From python-checkins at python.org Wed Jan 1 02:52:09 2014 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 1 Jan 2014 02:52:09 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMDU1?= =?utf-8?q?=3A_Fix_test=5Fshutil_under_Windows_with_symlink_privileges_hel?= =?utf-8?q?d=2E?= Message-ID: <3dvFk11T2Cz7Ll5@mail.python.org> http://hg.python.org/cpython/rev/0f888589dbcd changeset: 88239:0f888589dbcd branch: 3.3 parent: 88237:9c88280245e0 user: Antoine Pitrou date: Wed Jan 01 02:50:45 2014 +0100 summary: Issue #20055: Fix test_shutil under Windows with symlink privileges held. Patch by Vajrasky Kok. files: Lib/test/test_shutil.py | 32 +++++++++++++++++----------- Misc/NEWS | 3 ++ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -287,18 +287,20 @@ self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode) shutil.copymode(src, dst) self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode) - # follow src link - os.chmod(dst, stat.S_IRWXO) - shutil.copymode(src_link, dst) - self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode) - # follow dst link - os.chmod(dst, stat.S_IRWXO) - shutil.copymode(src, dst_link) - self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode) - # follow both links - os.chmod(dst, stat.S_IRWXO) - shutil.copymode(src_link, dst) - self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode) + # On Windows, os.chmod does not follow symlinks (issue #15411) + if os.name != 'nt': + # follow src link + os.chmod(dst, stat.S_IRWXO) + shutil.copymode(src_link, dst) + self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode) + # follow dst link + os.chmod(dst, stat.S_IRWXO) + shutil.copymode(src, dst_link) + self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode) + # follow both links + os.chmod(dst, stat.S_IRWXO) + shutil.copymode(src_link, dst_link) + self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode) @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod') @support.skip_unless_symlink @@ -1543,7 +1545,11 @@ dst_link = os.path.join(self.dst_dir, 'quux') shutil.move(dst, dst_link) self.assertTrue(os.path.islink(dst_link)) - self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link)) + # On Windows, os.path.realpath does not follow symlinks (issue #9949) + if os.name == 'nt': + self.assertEqual(os.path.realpath(src), os.readlink(dst_link)) + else: + self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link)) @support.skip_unless_symlink @mock_rename diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -197,6 +197,9 @@ Tests ----- +- Issue #20055: Fix test_shutil under Windows with symlink privileges held. + Patch by Vajrasky Kok. + - Issue #19938: Re-enabled test_bug_1333982 in test_dis, which had been disabled since 3.0 due to the changes in listcomp handling. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 1 02:52:11 2014 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 1 Jan 2014 02:52:11 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320055=3A_Fix_test=5Fshutil_under_Windows_with_s?= =?utf-8?q?ymlink_privileges_held=2E?= Message-ID: <3dvFk31J1tz7Lpw@mail.python.org> http://hg.python.org/cpython/rev/6fd3d473e1c2 changeset: 88240:6fd3d473e1c2 parent: 88238:b5f85b093252 parent: 88239:0f888589dbcd user: Antoine Pitrou date: Wed Jan 01 02:51:58 2014 +0100 summary: Issue #20055: Fix test_shutil under Windows with symlink privileges held. Patch by Vajrasky Kok. files: Lib/test/test_shutil.py | 32 +++++++++++++++++----------- Misc/NEWS | 3 ++ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -288,18 +288,20 @@ self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode) shutil.copymode(src, dst) self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode) - # follow src link - os.chmod(dst, stat.S_IRWXO) - shutil.copymode(src_link, dst) - self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode) - # follow dst link - os.chmod(dst, stat.S_IRWXO) - shutil.copymode(src, dst_link) - self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode) - # follow both links - os.chmod(dst, stat.S_IRWXO) - shutil.copymode(src_link, dst) - self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode) + # On Windows, os.chmod does not follow symlinks (issue #15411) + if os.name != 'nt': + # follow src link + os.chmod(dst, stat.S_IRWXO) + shutil.copymode(src_link, dst) + self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode) + # follow dst link + os.chmod(dst, stat.S_IRWXO) + shutil.copymode(src, dst_link) + self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode) + # follow both links + os.chmod(dst, stat.S_IRWXO) + shutil.copymode(src_link, dst_link) + self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode) @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod') @support.skip_unless_symlink @@ -1554,7 +1556,11 @@ dst_link = os.path.join(self.dst_dir, 'quux') shutil.move(dst, dst_link) self.assertTrue(os.path.islink(dst_link)) - self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link)) + # On Windows, os.path.realpath does not follow symlinks (issue #9949) + if os.name == 'nt': + self.assertEqual(os.path.realpath(src), os.readlink(dst_link)) + else: + self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link)) @support.skip_unless_symlink @mock_rename diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -267,6 +267,9 @@ Tests ----- +- Issue #20055: Fix test_shutil under Windows with symlink privileges held. + Patch by Vajrasky Kok. + - Issue #20070: Don't run test_urllib2net when network resources are not enabled. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 1 05:02:54 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 1 Jan 2014 05:02:54 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_update_copyrig?= =?utf-8?q?ht_year?= Message-ID: <3dvJct4vCGz7LjS@mail.python.org> http://hg.python.org/cpython/rev/8c276f37ba42 changeset: 88241:8c276f37ba42 branch: 3.3 parent: 88239:0f888589dbcd user: Benjamin Peterson date: Tue Dec 31 22:02:22 2013 -0600 summary: update copyright year files: Doc/README.txt | 2 +- Doc/copyright.rst | 2 +- Doc/license.rst | 2 +- LICENSE | 2 +- PC/python_nt.rc | 2 +- Python/getcopyright.c | 2 +- README | 4 ++-- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Doc/README.txt b/Doc/README.txt --- a/Doc/README.txt +++ b/Doc/README.txt @@ -135,7 +135,7 @@ as long as you don't change or remove the copyright notice: ---------------------------------------------------------------------- -Copyright (c) 2000-2013 Python Software Foundation. +Copyright (c) 2000-2014 Python Software Foundation. All rights reserved. Copyright (c) 2000 BeOpen.com. diff --git a/Doc/copyright.rst b/Doc/copyright.rst --- a/Doc/copyright.rst +++ b/Doc/copyright.rst @@ -4,7 +4,7 @@ Python and this documentation is: -Copyright ?? 2001-2013 Python Software Foundation. All rights reserved. +Copyright ?? 2001-2014 Python Software Foundation. All rights reserved. Copyright ?? 2000 BeOpen.com. All rights reserved. diff --git a/Doc/license.rst b/Doc/license.rst --- a/Doc/license.rst +++ b/Doc/license.rst @@ -84,7 +84,7 @@ analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python |release| alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of - copyright, i.e., "Copyright ?? 2001-2013 Python Software Foundation; All Rights + copyright, i.e., "Copyright ?? 2001-2014 Python Software Foundation; All Rights Reserved" are retained in Python |release| alone or in any derivative version prepared by Licensee. diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -74,7 +74,7 @@ distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -2011, 2012, 2013 Python Software Foundation; All Rights Reserved" are retained +2011, 2012, 2013, 2014 Python Software Foundation; All Rights Reserved" are retained in Python alone or in any derivative version prepared by Licensee. 3. In the event Licensee prepares a derivative work that is based on diff --git a/PC/python_nt.rc b/PC/python_nt.rc --- a/PC/python_nt.rc +++ b/PC/python_nt.rc @@ -61,7 +61,7 @@ VALUE "FileDescription", "Python Core\0" VALUE "FileVersion", PYTHON_VERSION VALUE "InternalName", "Python DLL\0" - VALUE "LegalCopyright", "Copyright ? 2001-2013 Python Software Foundation. Copyright ? 2000 BeOpen.com. Copyright ? 1995-2001 CNRI. Copyright ? 1991-1995 SMC.\0" + VALUE "LegalCopyright", "Copyright ? 2001-2014 Python Software Foundation. Copyright ? 2000 BeOpen.com. Copyright ? 1995-2001 CNRI. Copyright ? 1991-1995 SMC.\0" VALUE "OriginalFilename", PYTHON_DLL_NAME "\0" VALUE "ProductName", "Python\0" VALUE "ProductVersion", PYTHON_VERSION diff --git a/Python/getcopyright.c b/Python/getcopyright.c --- a/Python/getcopyright.c +++ b/Python/getcopyright.c @@ -4,7 +4,7 @@ static const char cprt[] = "\ -Copyright (c) 2001-2013 Python Software Foundation.\n\ +Copyright (c) 2001-2014 Python Software Foundation.\n\ All Rights Reserved.\n\ \n\ Copyright (c) 2000 BeOpen.com.\n\ diff --git a/README b/README --- a/README +++ b/README @@ -2,7 +2,7 @@ ============================ Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -2012, 2013 Python Software Foundation. All rights reserved. +2012, 2013, 2014 Python Software Foundation. All rights reserved. Python 3.x is a new version of the language, which is incompatible with the 2.x line of releases. The language is mostly the same, but many details, especially @@ -175,7 +175,7 @@ --------------------------------- Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -2012, 2013 Python Software Foundation. All rights reserved. +2012, 2013, 2014 Python Software Foundation. All rights reserved. Copyright (c) 2000 BeOpen.com. All rights reserved. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 1 05:02:56 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 1 Jan 2014 05:02:56 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3dvJcw12T9z7Lkg@mail.python.org> http://hg.python.org/cpython/rev/14133d998493 changeset: 88242:14133d998493 parent: 88240:6fd3d473e1c2 parent: 88241:8c276f37ba42 user: Benjamin Peterson date: Tue Dec 31 22:02:41 2013 -0600 summary: merge 3.3 files: Doc/README.txt | 2 +- Doc/copyright.rst | 2 +- Doc/license.rst | 2 +- LICENSE | 2 +- PC/python_nt.rc | 2 +- Python/getcopyright.c | 2 +- README | 4 ++-- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Doc/README.txt b/Doc/README.txt --- a/Doc/README.txt +++ b/Doc/README.txt @@ -136,7 +136,7 @@ as long as you don't change or remove the copyright notice: ---------------------------------------------------------------------- -Copyright (c) 2000-2013 Python Software Foundation. +Copyright (c) 2000-2014 Python Software Foundation. All rights reserved. Copyright (c) 2000 BeOpen.com. diff --git a/Doc/copyright.rst b/Doc/copyright.rst --- a/Doc/copyright.rst +++ b/Doc/copyright.rst @@ -4,7 +4,7 @@ Python and this documentation is: -Copyright ?? 2001-2013 Python Software Foundation. All rights reserved. +Copyright ?? 2001-2014 Python Software Foundation. All rights reserved. Copyright ?? 2000 BeOpen.com. All rights reserved. diff --git a/Doc/license.rst b/Doc/license.rst --- a/Doc/license.rst +++ b/Doc/license.rst @@ -84,7 +84,7 @@ analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python |release| alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of - copyright, i.e., "Copyright ?? 2001-2013 Python Software Foundation; All Rights + copyright, i.e., "Copyright ?? 2001-2014 Python Software Foundation; All Rights Reserved" are retained in Python |release| alone or in any derivative version prepared by Licensee. diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -74,7 +74,7 @@ distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -2011, 2012, 2013 Python Software Foundation; All Rights Reserved" are retained +2011, 2012, 2013, 2014 Python Software Foundation; All Rights Reserved" are retained in Python alone or in any derivative version prepared by Licensee. 3. In the event Licensee prepares a derivative work that is based on diff --git a/PC/python_nt.rc b/PC/python_nt.rc --- a/PC/python_nt.rc +++ b/PC/python_nt.rc @@ -61,7 +61,7 @@ VALUE "FileDescription", "Python Core\0" VALUE "FileVersion", PYTHON_VERSION VALUE "InternalName", "Python DLL\0" - VALUE "LegalCopyright", "Copyright ? 2001-2013 Python Software Foundation. Copyright ? 2000 BeOpen.com. Copyright ? 1995-2001 CNRI. Copyright ? 1991-1995 SMC.\0" + VALUE "LegalCopyright", "Copyright ? 2001-2014 Python Software Foundation. Copyright ? 2000 BeOpen.com. Copyright ? 1995-2001 CNRI. Copyright ? 1991-1995 SMC.\0" VALUE "OriginalFilename", PYTHON_DLL_NAME "\0" VALUE "ProductName", "Python\0" VALUE "ProductVersion", PYTHON_VERSION diff --git a/Python/getcopyright.c b/Python/getcopyright.c --- a/Python/getcopyright.c +++ b/Python/getcopyright.c @@ -4,7 +4,7 @@ static const char cprt[] = "\ -Copyright (c) 2001-2013 Python Software Foundation.\n\ +Copyright (c) 2001-2014 Python Software Foundation.\n\ All Rights Reserved.\n\ \n\ Copyright (c) 2000 BeOpen.com.\n\ diff --git a/README b/README --- a/README +++ b/README @@ -2,7 +2,7 @@ =================================== Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -2012, 2013 Python Software Foundation. All rights reserved. +2012, 2013, 2014 Python Software Foundation. All rights reserved. Python 3.x is a new version of the language, which is incompatible with the 2.x line of releases. The language is mostly the same, but many details, especially @@ -175,7 +175,7 @@ --------------------------------- Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -2012, 2013 Python Software Foundation. All rights reserved. +2012, 2013, 2014 Python Software Foundation. All rights reserved. Copyright (c) 2000 BeOpen.com. All rights reserved. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 1 05:05:18 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 1 Jan 2014 05:05:18 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_update_copyrig?= =?utf-8?q?ht_year?= Message-ID: <3dvJgf3MFdz7LjW@mail.python.org> http://hg.python.org/cpython/rev/72f323e8988b changeset: 88243:72f323e8988b branch: 2.7 parent: 88215:990d7647ea51 user: Benjamin Peterson date: Tue Dec 31 22:02:22 2013 -0600 summary: update copyright year files: Doc/README.txt | 2 +- Doc/copyright.rst | 2 +- Doc/license.rst | 2 +- LICENSE | 2 +- PC/python_nt.rc | 2 +- Python/getcopyright.c | 2 +- README | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Doc/README.txt b/Doc/README.txt --- a/Doc/README.txt +++ b/Doc/README.txt @@ -127,7 +127,7 @@ as long as you don't change or remove the copyright notice: ---------------------------------------------------------------------- -Copyright (c) 2000-2013 Python Software Foundation. +Copyright (c) 2000-2014 Python Software Foundation. All rights reserved. Copyright (c) 2000 BeOpen.com. diff --git a/Doc/copyright.rst b/Doc/copyright.rst --- a/Doc/copyright.rst +++ b/Doc/copyright.rst @@ -4,7 +4,7 @@ Python and this documentation is: -Copyright ?? 2001-2013 Python Software Foundation. All rights reserved. +Copyright ?? 2001-2014 Python Software Foundation. All rights reserved. Copyright ?? 2000 BeOpen.com. All rights reserved. diff --git a/Doc/license.rst b/Doc/license.rst --- a/Doc/license.rst +++ b/Doc/license.rst @@ -84,7 +84,7 @@ analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python |release| alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of - copyright, i.e., "Copyright ?? 2001-2013 Python Software Foundation; All Rights + copyright, i.e., "Copyright ?? 2001-2014 Python Software Foundation; All Rights Reserved" are retained in Python |release| alone or in any derivative version prepared by Licensee. diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -74,7 +74,7 @@ distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -2011, 2012, 2013 Python Software Foundation; All Rights Reserved" are retained +2011, 2012, 2013, 2014 Python Software Foundation; All Rights Reserved" are retained in Python alone or in any derivative version prepared by Licensee. 3. In the event Licensee prepares a derivative work that is based on diff --git a/PC/python_nt.rc b/PC/python_nt.rc --- a/PC/python_nt.rc +++ b/PC/python_nt.rc @@ -61,7 +61,7 @@ VALUE "FileDescription", "Python Core\0" VALUE "FileVersion", PYTHON_VERSION VALUE "InternalName", "Python DLL\0" - VALUE "LegalCopyright", "Copyright ? 2001-2008 Python Software Foundation. Copyright ? 2000 BeOpen.com. Copyright ? 1995-2001 CNRI. Copyright ? 1991-1995 SMC.\0" + VALUE "LegalCopyright", "Copyright ? 2001-2014 Python Software Foundation. Copyright ? 2000 BeOpen.com. Copyright ? 1995-2001 CNRI. Copyright ? 1991-1995 SMC.\0" VALUE "OriginalFilename", PYTHON_DLL_NAME "\0" VALUE "ProductName", "Python\0" VALUE "ProductVersion", PYTHON_VERSION diff --git a/Python/getcopyright.c b/Python/getcopyright.c --- a/Python/getcopyright.c +++ b/Python/getcopyright.c @@ -4,7 +4,7 @@ static char cprt[] = "\ -Copyright (c) 2001-2013 Python Software Foundation.\n\ +Copyright (c) 2001-2014 Python Software Foundation.\n\ All Rights Reserved.\n\ \n\ Copyright (c) 2000 BeOpen.com.\n\ diff --git a/README b/README --- a/README +++ b/README @@ -2,7 +2,7 @@ ============================ Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -2012, 2013 Python Software Foundation. All rights reserved. +2012, 2013, 2014 Python Software Foundation. All rights reserved. Copyright (c) 2000 BeOpen.com. All rights reserved. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed Jan 1 09:46:11 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 01 Jan 2014 09:46:11 +0100 Subject: [Python-checkins] Daily reference leaks (6fd3d473e1c2): sum=0 Message-ID: results for 6fd3d473e1c2 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog_CdVl_', '-x'] From python-checkins at python.org Wed Jan 1 22:06:29 2014 From: python-checkins at python.org (ned.deily) Date: Wed, 1 Jan 2014 22:06:29 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Update_copyrig?= =?utf-8?q?ht_dates_in_Mac_plists=2E?= Message-ID: <3dvlKx6cKjz7LjW@mail.python.org> http://hg.python.org/cpython/rev/aeb70f2f6f38 changeset: 88244:aeb70f2f6f38 branch: 2.7 user: Ned Deily date: Wed Jan 01 13:03:24 2014 -0800 summary: Update copyright dates in Mac plists. files: Mac/IDLE/Info.plist.in | 2 +- Mac/PythonLauncher/Info.plist.in | 2 +- Mac/Resources/app/Info.plist.in | 6 +++--- Mac/Resources/framework/Info.plist.in | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Mac/IDLE/Info.plist.in b/Mac/IDLE/Info.plist.in --- a/Mac/IDLE/Info.plist.in +++ b/Mac/IDLE/Info.plist.in @@ -36,7 +36,7 @@ CFBundleExecutable IDLE CFBundleGetInfoString - %VERSION%, ? 2001-2013 Python Software Foundation + %VERSION%, ? 2001-2014 Python Software Foundation CFBundleIconFile IDLE.icns CFBundleIdentifier diff --git a/Mac/PythonLauncher/Info.plist.in b/Mac/PythonLauncher/Info.plist.in --- a/Mac/PythonLauncher/Info.plist.in +++ b/Mac/PythonLauncher/Info.plist.in @@ -40,7 +40,7 @@ CFBundleExecutable PythonLauncher CFBundleGetInfoString - %VERSION%, ? 2001-2013 Python Software Foundation + %VERSION%, ? 2001-2014 Python Software Foundation CFBundleIconFile PythonLauncher.icns CFBundleIdentifier diff --git a/Mac/Resources/app/Info.plist.in b/Mac/Resources/app/Info.plist.in --- a/Mac/Resources/app/Info.plist.in +++ b/Mac/Resources/app/Info.plist.in @@ -20,7 +20,7 @@ CFBundleExecutable Python CFBundleGetInfoString - %version%, (c) 2004-2013 Python Software Foundation. + %version%, (c) 2004-2014 Python Software Foundation. CFBundleHelpBookFolder Documentation @@ -37,7 +37,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString - %version%, (c) 2004-2013 Python Software Foundation. + %version%, (c) 2004-2014 Python Software Foundation. CFBundleName Python CFBundlePackageType @@ -55,7 +55,7 @@ NSAppleScriptEnabled NSHumanReadableCopyright - (c) 2013 Python Software Foundation. + (c) 2014 Python Software Foundation. NSHighResolutionCapable diff --git a/Mac/Resources/framework/Info.plist.in b/Mac/Resources/framework/Info.plist.in --- a/Mac/Resources/framework/Info.plist.in +++ b/Mac/Resources/framework/Info.plist.in @@ -17,9 +17,9 @@ CFBundlePackageType FMWK CFBundleShortVersionString - %VERSION%, (c) 2004-2013 Python Software Foundation. + %VERSION%, (c) 2004-2014 Python Software Foundation. CFBundleLongVersionString - %VERSION%, (c) 2004-2013 Python Software Foundation. + %VERSION%, (c) 2004-2014 Python Software Foundation. CFBundleSignature ???? CFBundleVersion -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 1 22:06:31 2014 From: python-checkins at python.org (ned.deily) Date: Wed, 1 Jan 2014 22:06:31 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Update_copyrig?= =?utf-8?q?ht_dates_in_Mac_plists=2E?= Message-ID: <3dvlKz10Y3z7LjW@mail.python.org> http://hg.python.org/cpython/rev/6a1a1cf5a01b changeset: 88245:6a1a1cf5a01b branch: 3.3 parent: 88241:8c276f37ba42 user: Ned Deily date: Wed Jan 01 13:05:03 2014 -0800 summary: Update copyright dates in Mac plists. files: Mac/IDLE/IDLE.app/Contents/Info.plist | 2 +- Mac/PythonLauncher/Info.plist.in | 2 +- Mac/Resources/app/Info.plist.in | 6 +++--- Mac/Resources/framework/Info.plist.in | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Mac/IDLE/IDLE.app/Contents/Info.plist b/Mac/IDLE/IDLE.app/Contents/Info.plist --- a/Mac/IDLE/IDLE.app/Contents/Info.plist +++ b/Mac/IDLE/IDLE.app/Contents/Info.plist @@ -36,7 +36,7 @@ CFBundleExecutable IDLE CFBundleGetInfoString - %version%, ? 2001-2013 Python Software Foundation + %version%, ? 2001-2014 Python Software Foundation CFBundleIconFile IDLE.icns CFBundleIdentifier diff --git a/Mac/PythonLauncher/Info.plist.in b/Mac/PythonLauncher/Info.plist.in --- a/Mac/PythonLauncher/Info.plist.in +++ b/Mac/PythonLauncher/Info.plist.in @@ -40,7 +40,7 @@ CFBundleExecutable PythonLauncher CFBundleGetInfoString - %VERSION%, ? 2001-2013 Python Software Foundation + %VERSION%, ? 2001-2014 Python Software Foundation CFBundleIconFile PythonLauncher.icns CFBundleIdentifier diff --git a/Mac/Resources/app/Info.plist.in b/Mac/Resources/app/Info.plist.in --- a/Mac/Resources/app/Info.plist.in +++ b/Mac/Resources/app/Info.plist.in @@ -20,7 +20,7 @@ CFBundleExecutable Python CFBundleGetInfoString - %version%, (c) 2004-2013 Python Software Foundation. + %version%, (c) 2004-2014 Python Software Foundation. CFBundleHelpBookFolder Documentation @@ -37,7 +37,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString - %version%, (c) 2004-2013 Python Software Foundation. + %version%, (c) 2004-2014 Python Software Foundation. CFBundleName Python CFBundlePackageType @@ -55,7 +55,7 @@ NSAppleScriptEnabled NSHumanReadableCopyright - (c) 2013 Python Software Foundation. + (c) 2014 Python Software Foundation. NSHighResolutionCapable diff --git a/Mac/Resources/framework/Info.plist.in b/Mac/Resources/framework/Info.plist.in --- a/Mac/Resources/framework/Info.plist.in +++ b/Mac/Resources/framework/Info.plist.in @@ -17,9 +17,9 @@ CFBundlePackageType FMWK CFBundleShortVersionString - %VERSION%, (c) 2004-2013 Python Software Foundation. + %VERSION%, (c) 2004-2014 Python Software Foundation. CFBundleLongVersionString - %VERSION%, (c) 2004-2013 Python Software Foundation. + %VERSION%, (c) 2004-2014 Python Software Foundation. CFBundleSignature ???? CFBundleVersion -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 1 22:06:32 2014 From: python-checkins at python.org (ned.deily) Date: Wed, 1 Jan 2014 22:06:32 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Update_copyright_dates_in_Mac_plists=2E?= Message-ID: <3dvlL02TM6z7Lm0@mail.python.org> http://hg.python.org/cpython/rev/37582f4d90b5 changeset: 88246:37582f4d90b5 parent: 88242:14133d998493 parent: 88245:6a1a1cf5a01b user: Ned Deily date: Wed Jan 01 13:06:02 2014 -0800 summary: Update copyright dates in Mac plists. files: Mac/IDLE/IDLE.app/Contents/Info.plist | 2 +- Mac/PythonLauncher/Info.plist.in | 2 +- Mac/Resources/app/Info.plist.in | 6 +++--- Mac/Resources/framework/Info.plist.in | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Mac/IDLE/IDLE.app/Contents/Info.plist b/Mac/IDLE/IDLE.app/Contents/Info.plist --- a/Mac/IDLE/IDLE.app/Contents/Info.plist +++ b/Mac/IDLE/IDLE.app/Contents/Info.plist @@ -36,7 +36,7 @@ CFBundleExecutable IDLE CFBundleGetInfoString - %version%, ? 2001-2013 Python Software Foundation + %version%, ? 2001-2014 Python Software Foundation CFBundleIconFile IDLE.icns CFBundleIdentifier diff --git a/Mac/PythonLauncher/Info.plist.in b/Mac/PythonLauncher/Info.plist.in --- a/Mac/PythonLauncher/Info.plist.in +++ b/Mac/PythonLauncher/Info.plist.in @@ -40,7 +40,7 @@ CFBundleExecutable PythonLauncher CFBundleGetInfoString - %VERSION%, ? 2001-2013 Python Software Foundation + %VERSION%, ? 2001-2014 Python Software Foundation CFBundleIconFile PythonLauncher.icns CFBundleIdentifier diff --git a/Mac/Resources/app/Info.plist.in b/Mac/Resources/app/Info.plist.in --- a/Mac/Resources/app/Info.plist.in +++ b/Mac/Resources/app/Info.plist.in @@ -20,7 +20,7 @@ CFBundleExecutable Python CFBundleGetInfoString - %version%, (c) 2004-2013 Python Software Foundation. + %version%, (c) 2004-2014 Python Software Foundation. CFBundleHelpBookFolder Documentation @@ -37,7 +37,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString - %version%, (c) 2004-2013 Python Software Foundation. + %version%, (c) 2004-2014 Python Software Foundation. CFBundleName Python CFBundlePackageType @@ -55,7 +55,7 @@ NSAppleScriptEnabled NSHumanReadableCopyright - (c) 2013 Python Software Foundation. + (c) 2014 Python Software Foundation. NSHighResolutionCapable diff --git a/Mac/Resources/framework/Info.plist.in b/Mac/Resources/framework/Info.plist.in --- a/Mac/Resources/framework/Info.plist.in +++ b/Mac/Resources/framework/Info.plist.in @@ -17,9 +17,9 @@ CFBundlePackageType FMWK CFBundleShortVersionString - %VERSION%, (c) 2004-2013 Python Software Foundation. + %VERSION%, (c) 2004-2014 Python Software Foundation. CFBundleLongVersionString - %VERSION%, (c) 2004-2013 Python Software Foundation. + %VERSION%, (c) 2004-2014 Python Software Foundation. CFBundleSignature ???? CFBundleVersion -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu Jan 2 09:45:17 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 02 Jan 2014 09:45:17 +0100 Subject: [Python-checkins] Daily reference leaks (37582f4d90b5): sum=-4 Message-ID: results for 37582f4d90b5 on branch "default" -------------------------------------------- test_site leaked [0, -2, 0] references, sum=-2 test_site leaked [0, -2, 0] memory blocks, sum=-2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/refloghG1XVq', '-x'] From python-checkins at python.org Thu Jan 2 11:51:33 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 2 Jan 2014 11:51:33 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogcGFyc2VyOiBmaXgg?= =?utf-8?q?usage_of_Py=5FBuildValue=28=29_to_build_a_parser_error?= Message-ID: <3dw5dx45k8z7LjT@mail.python.org> http://hg.python.org/cpython/rev/91cb83f895cf changeset: 88247:91cb83f895cf branch: 3.3 parent: 88245:6a1a1cf5a01b user: Victor Stinner date: Thu Jan 02 11:49:27 2014 +0100 summary: parser: fix usage of Py_BuildValue() to build a parser error Fix typo: "os" format => "Os" files: Modules/parsermodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/parsermodule.c b/Modules/parsermodule.c --- a/Modules/parsermodule.c +++ b/Modules/parsermodule.c @@ -748,7 +748,7 @@ } } if (!ok) { - PyObject *err = Py_BuildValue("os", elem, + PyObject *err = Py_BuildValue("Os", elem, "Illegal node construct."); PyErr_SetObject(parser_error, err); Py_XDECREF(err); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 2 11:51:34 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 2 Jan 2014 11:51:34 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_=28Merge_3=2E3=29_parser=3A_fix_usage_of_Py=5FBuildValue?= =?utf-8?q?=28=29_to_build_a_parser_error?= Message-ID: <3dw5dy60v2z7Ljc@mail.python.org> http://hg.python.org/cpython/rev/cd952e92c180 changeset: 88248:cd952e92c180 parent: 88246:37582f4d90b5 parent: 88247:91cb83f895cf user: Victor Stinner date: Thu Jan 02 11:50:10 2014 +0100 summary: (Merge 3.3) parser: fix usage of Py_BuildValue() to build a parser error Fix typo: "os" format => "Os" files: Modules/parsermodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/parsermodule.c b/Modules/parsermodule.c --- a/Modules/parsermodule.c +++ b/Modules/parsermodule.c @@ -785,7 +785,7 @@ } } if (!ok) { - PyObject *err = Py_BuildValue("os", elem, + PyObject *err = Py_BuildValue("Os", elem, "Illegal node construct."); PyErr_SetObject(parser_error, err); Py_XDECREF(err); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 2 12:54:03 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 2 Jan 2014 12:54:03 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_threading=2ERLock=2E=5Facq?= =?utf-8?q?uire=5Frestore=28=29_now_raises_a_TypeError_instead_of_a?= Message-ID: <3dw7235gCHz7LjR@mail.python.org> http://hg.python.org/cpython/rev/9a61be172c23 changeset: 88249:9a61be172c23 user: Victor Stinner date: Thu Jan 02 12:47:24 2014 +0100 summary: threading.RLock._acquire_restore() now raises a TypeError instead of a SystemError when it is not called with 2 arguments files: Modules/_threadmodule.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -379,13 +379,13 @@ to be available for other threads."); static PyObject * -rlock_acquire_restore(rlockobject *self, PyObject *arg) +rlock_acquire_restore(rlockobject *self, PyObject *args) { long owner; unsigned long count; int r = 1; - if (!PyArg_ParseTuple(arg, "kl:_acquire_restore", &count, &owner)) + if (!PyArg_ParseTuple(args, "(kl):_acquire_restore", &count, &owner)) return NULL; if (!PyThread_acquire_lock(self->rlock_lock, 0)) { @@ -488,7 +488,7 @@ {"_is_owned", (PyCFunction)rlock_is_owned, METH_NOARGS, rlock_is_owned_doc}, {"_acquire_restore", (PyCFunction)rlock_acquire_restore, - METH_O, rlock_acquire_restore_doc}, + METH_VARARGS, rlock_acquire_restore_doc}, {"_release_save", (PyCFunction)rlock_release_save, METH_NOARGS, rlock_release_save_doc}, {"__enter__", (PyCFunction)rlock_acquire, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 2 12:54:05 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 2 Jan 2014 12:54:05 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4ODI5?= =?utf-8?q?=3A_Add_tests_for_the_csv_module_for_invalid_characters_=28deli?= =?utf-8?q?miter=2C?= Message-ID: <3dw7250HV0z7LjT@mail.python.org> http://hg.python.org/cpython/rev/0daf7f02c97f changeset: 88250:0daf7f02c97f branch: 3.3 parent: 88247:91cb83f895cf user: Victor Stinner date: Thu Jan 02 12:53:13 2014 +0100 summary: Issue #18829: Add tests for the csv module for invalid characters (delimiter, escapechar, quotechar) files: Lib/test/test_csv.py | 13 +++++++++++++ 1 files changed, 13 insertions(+), 0 deletions(-) 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 @@ -828,6 +828,19 @@ self.assertEqual(str(cm.exception), '"lineterminator" must be a string') + def test_invalid_chars(self): + def create_invalid(field_name, value): + class mydialect(csv.Dialect): + pass + setattr(mydialect, field_name, value) + d = mydialect() + + for field_name in ("delimiter", "escapechar", "quotechar"): + self.assertRaises(csv.Error, create_invalid, field_name, "") + self.assertRaises(csv.Error, create_invalid, field_name, "abc") + self.assertRaises(csv.Error, create_invalid, field_name, b'x') + self.assertRaises(csv.Error, create_invalid, field_name, 5) + class TestSniffer(unittest.TestCase): sample1 = """\ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 2 12:54:06 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 2 Jan 2014 12:54:06 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_=28Merge_3=2E3=29_Issue_=2318829=3A_Add_tests_for_the_cs?= =?utf-8?q?v_module_for_invalid_characters?= Message-ID: <3dw7261yf7z7LjZ@mail.python.org> http://hg.python.org/cpython/rev/ccb52323039f changeset: 88251:ccb52323039f parent: 88249:9a61be172c23 parent: 88250:0daf7f02c97f user: Victor Stinner date: Thu Jan 02 12:53:50 2014 +0100 summary: (Merge 3.3) Issue #18829: Add tests for the csv module for invalid characters (delimiter, escapechar, quotechar) files: Lib/test/test_csv.py | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-) 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 @@ -837,6 +837,20 @@ self.assertEqual(str(cm.exception), '"lineterminator" must be a string') + def test_invalid_chars(self): + def create_invalid(field_name, value): + class mydialect(csv.Dialect): + pass + setattr(mydialect, field_name, value) + d = mydialect() + + for field_name in ("delimiter", "escapechar", "quotechar"): + with self.subTest(field_name=field_name): + self.assertRaises(csv.Error, create_invalid, field_name, "") + self.assertRaises(csv.Error, create_invalid, field_name, "abc") + self.assertRaises(csv.Error, create_invalid, field_name, b'x') + self.assertRaises(csv.Error, create_invalid, field_name, 5) + class TestSniffer(unittest.TestCase): sample1 = """\ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 2 14:12:58 2014 From: python-checkins at python.org (martin.v.loewis) Date: Thu, 2 Jan 2014 14:12:58 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2319728=3A_Enable_p?= =?utf-8?q?ip_installation_by_default_on_Windows=2E?= Message-ID: <3dw8n61wFZz7LjS@mail.python.org> http://hg.python.org/cpython/rev/4c7b3e7fd4ca changeset: 88252:4c7b3e7fd4ca user: Martin v. L?wis date: Thu Jan 02 14:12:30 2014 +0100 summary: Issue #19728: Enable pip installation by default on Windows. files: Misc/NEWS | 2 ++ Tools/msi/msi.py | 21 +++++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -303,6 +303,8 @@ Build ----- +- Issue #19728: Enable pip installation by default on Windows. + - Issue #16136: Remove VMS support - Issue #18215: Add script Tools/ssl/test_multiple_versions.py to compile and diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py --- a/Tools/msi/msi.py +++ b/Tools/msi/msi.py @@ -422,7 +422,7 @@ compileargs = r'-Wi "[TARGETDIR]Lib\compileall.py" -f -x "bad_coding|badsyntax|site-packages|py2_|lib2to3\\tests|venv\\scripts" "[TARGETDIR]Lib"' lib2to3args = r'-c "import lib2to3.pygram, lib2to3.patcomp;lib2to3.patcomp.PatternCompiler()"' updatepipargs = r'-m ensurepip -U' - removepipargs = r'-m ensurepip -r' # does not yet work + removepipargs = r'-m ensurepip._uninstall' # See "CustomAction Table" add_data(db, "CustomAction", [ # msidbCustomActionTypeFirstSequence + msidbCustomActionTypeTextData + msidbCustomActionTypeProperty @@ -441,7 +441,7 @@ ("CompileGrammar", 18, "python.exe", lib2to3args), # msidbCustomActionTypeInScript (1024); run during actual installation ("UpdatePip", 18+1024, "python.exe", updatepipargs), - #("RemovePip", 18, "python.exe", removepipargs), + ("RemovePip", 18, "python.exe", removepipargs), ]) # UI Sequences, see "InstallUISequence Table", "Using a Sequence Table" @@ -480,10 +480,10 @@ ("UpdateEditIDLE", None, 1050), # run command if install state of pip changes to INSTALLSTATE_LOCAL # run after InstallFiles - ("UpdatePip", "&pip=3", 4001), + ("UpdatePip", "&pip_feature=3", 4001), # remove pip when state changes to INSTALLSTATE_ABSENT # run before RemoveFiles - #("RemovePip", "&pip=2", 3499), + ("RemovePip", "&pip_feature=2", 3499), ("CompilePyc", "COMPILEALL", 6800), ("CompilePyo", "COMPILEALL", 6801), ("CompileGrammar", "COMPILEALL", 6802), @@ -862,7 +862,7 @@ # Features that have no advertisement trigger (e.g. the test suite) # must not support advertisement global default_feature, tcltk, htmlfiles, tools, testsuite - global ext_feature, private_crt, prepend_path, update_pip + global ext_feature, private_crt, prepend_path, pip_feature default_feature = Feature(db, "DefaultFeature", "Python", "Python Interpreter and Libraries", 1, directory = "TARGETDIR") @@ -886,10 +886,10 @@ parent = default_feature, attributes=2) # pip installation isn't enabled by default until a clean uninstall procedure # becomes possible - update_pip = Feature(db, "pip", "pip", + pip_feature = Feature(db, "pip_feature", "pip", "Install (or upgrade from an earlier version) pip, " "a tool for installing and managing Python packages.", 11, - parent = default_feature, attributes=2|8, level=2) + parent = default_feature, attributes=2|8) testsuite = Feature(db, "Testsuite", "Test suite", "Python test suite (Lib/test/)", 13, parent = default_feature, attributes=2|8) @@ -1206,6 +1206,8 @@ "Documentation"), ("REGISTRY.path", msilib.gen_uuid(), "TARGETDIR", registry_component, None, None), + ("REGISTRY.ensurepip", msilib.gen_uuid(), "TARGETDIR", registry_component, "EnsurePipRun", + None), ("REGISTRY.def", msilib.gen_uuid(), "TARGETDIR", registry_component, None, None)] + tcldata) # See "FeatureComponents Table". @@ -1223,6 +1225,7 @@ [(default_feature.id, "REGISTRY"), (htmlfiles.id, "REGISTRY.doc"), (prepend_path.id, "REGISTRY.path"), + (pip_feature.id, "REGISTRY.ensurepip"), (ext_feature.id, "REGISTRY.def")] + tcldata ) @@ -1309,7 +1312,9 @@ "", r"[TARGETDIR]Python.exe", "REGISTRY.def"), ("DisplayIcon", -1, r"Software\Microsoft\Windows\CurrentVersion\Uninstall\%s" % product_code, - "DisplayIcon", "[TARGETDIR]python.exe", "REGISTRY") + "DisplayIcon", "[TARGETDIR]python.exe", "REGISTRY"), + # Fake registry entry to allow installer to track whether ensurepip has been run + ("EnsurePipRun", -1, prefix+r"\EnsurePipRun", "", "#1", "REGISTRY.ensurepip"), ]) # Shortcuts, see "Shortcut Table" add_data(db, "Directory", -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 2 15:33:47 2014 From: python-checkins at python.org (donald.stufft) Date: Thu, 2 Jan 2014 15:33:47 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Update_pip_to_the_released?= =?utf-8?q?_1=2E5?= Message-ID: <3dwBZM54QRz7LjN@mail.python.org> http://hg.python.org/cpython/rev/70fd3383bd31 changeset: 88253:70fd3383bd31 user: Donald Stufft date: Thu Jan 02 09:33:35 2014 -0500 summary: Update pip to the released 1.5 files: Lib/ensurepip/__init__.py | 10 +----- Lib/ensurepip/_bundled/pip-1.5-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/pip-1.5rc4-py2.py3-none-any.whl | Bin Lib/test/test_ensurepip.py | 16 +++++----- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -4,15 +4,13 @@ import sys import tempfile -# TODO: Remove the --pre flag when a pip 1.5 final copy is available - __all__ = ["version", "bootstrap"] _SETUPTOOLS_VERSION = "2.0.2" -_PIP_VERSION = "1.5rc4" +_PIP_VERSION = "1.5" # pip currently requires ssl support, so we try to provide a nicer # error message when that is missing (http://bugs.python.org/issue19744) @@ -102,11 +100,7 @@ additional_paths.append(os.path.join(tmpdir, wheel_name)) # Construct the arguments to be passed to the pip command - args = [ - "install", "--no-index", "--find-links", tmpdir, - # Temporary until pip 1.5 is final - "--pre", - ] + args = ["install", "--no-index", "--find-links", tmpdir] if root: args += ["--root", root] if upgrade: diff --git a/Lib/ensurepip/_bundled/pip-1.5-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-1.5-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..dd7ca2e634424d8f443cf82f7b92393410219748 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/pip-1.5rc4-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-1.5rc4-py2.py3-none-any.whl deleted file mode 100644 index 2a16332814c690b3fc6f040fc79709dfed2e5095..0000000000000000000000000000000000000000 GIT binary patch [stripped] diff --git a/Lib/test/test_ensurepip.py b/Lib/test/test_ensurepip.py --- a/Lib/test/test_ensurepip.py +++ b/Lib/test/test_ensurepip.py @@ -52,7 +52,7 @@ self.run_pip.assert_called_once_with( [ "install", "--no-index", "--find-links", - unittest.mock.ANY, "--pre", "setuptools", "pip", + unittest.mock.ANY, "setuptools", "pip", ], unittest.mock.ANY, ) @@ -67,7 +67,7 @@ self.run_pip.assert_called_once_with( [ "install", "--no-index", "--find-links", - unittest.mock.ANY, "--pre", "--root", "/foo/bar/", + unittest.mock.ANY, "--root", "/foo/bar/", "setuptools", "pip", ], unittest.mock.ANY, @@ -80,7 +80,7 @@ self.run_pip.assert_called_once_with( [ "install", "--no-index", "--find-links", - unittest.mock.ANY, "--pre", "--user", "setuptools", "pip", + unittest.mock.ANY, "--user", "setuptools", "pip", ], unittest.mock.ANY, ) @@ -92,7 +92,7 @@ self.run_pip.assert_called_once_with( [ "install", "--no-index", "--find-links", - unittest.mock.ANY, "--pre", "--upgrade", "setuptools", "pip", + unittest.mock.ANY, "--upgrade", "setuptools", "pip", ], unittest.mock.ANY, ) @@ -104,7 +104,7 @@ self.run_pip.assert_called_once_with( [ "install", "--no-index", "--find-links", - unittest.mock.ANY, "--pre", "-v", "setuptools", "pip", + unittest.mock.ANY, "-v", "setuptools", "pip", ], unittest.mock.ANY, ) @@ -116,7 +116,7 @@ self.run_pip.assert_called_once_with( [ "install", "--no-index", "--find-links", - unittest.mock.ANY, "--pre", "-vv", "setuptools", "pip", + unittest.mock.ANY, "-vv", "setuptools", "pip", ], unittest.mock.ANY, ) @@ -128,7 +128,7 @@ self.run_pip.assert_called_once_with( [ "install", "--no-index", "--find-links", - unittest.mock.ANY, "--pre", "-vvv", "setuptools", "pip", + unittest.mock.ANY, "-vvv", "setuptools", "pip", ], unittest.mock.ANY, ) @@ -286,7 +286,7 @@ self.run_pip.assert_called_once_with( [ "install", "--no-index", "--find-links", - unittest.mock.ANY, "--pre", "setuptools", "pip", + unittest.mock.ANY, "setuptools", "pip", ], unittest.mock.ANY, ) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 2 16:43:31 2014 From: python-checkins at python.org (zach.ware) Date: Thu, 2 Jan 2014 16:43:31 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMTAx?= =?utf-8?q?=3A_Allow_test=5Fmonotonic_to_pass_on_Windows_machines_on_which?= Message-ID: <3dwD6q4mRYz7LjS@mail.python.org> http://hg.python.org/cpython/rev/82df66a091da changeset: 88254:82df66a091da branch: 3.3 parent: 88250:0daf7f02c97f user: Zachary Ware date: Thu Jan 02 09:41:10 2014 -0600 summary: Issue #20101: Allow test_monotonic to pass on Windows machines on which time.get_clock_info('monotonic').resolution == 0.015600099999999999 This is just a workaround pending a real resolution to #20101. files: Lib/test/test_time.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -376,7 +376,8 @@ t2 = time.monotonic() dt = t2 - t1 self.assertGreater(t2, t1) - self.assertTrue(0.5 <= dt <= 1.0, dt) + # Issue #20101: On some Windows machines, dt may be slightly low + self.assertTrue(0.45 <= dt <= 1.0, dt) info = time.get_clock_info('monotonic') self.assertTrue(info.monotonic) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 2 16:43:32 2014 From: python-checkins at python.org (zach.ware) Date: Thu, 2 Jan 2014 16:43:32 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320101=3A_Merge_with_3=2E3?= Message-ID: <3dwD6r6Lbfz7LjS@mail.python.org> http://hg.python.org/cpython/rev/e2a1400b7db9 changeset: 88255:e2a1400b7db9 parent: 88253:70fd3383bd31 parent: 88254:82df66a091da user: Zachary Ware date: Thu Jan 02 09:43:09 2014 -0600 summary: Issue #20101: Merge with 3.3 files: Lib/test/test_time.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -384,7 +384,8 @@ t2 = time.monotonic() dt = t2 - t1 self.assertGreater(t2, t1) - self.assertTrue(0.5 <= dt <= 1.0, dt) + # Issue #20101: On some Windows machines, dt may be slightly low + self.assertTrue(0.45 <= dt <= 1.0, dt) # monotonic() is a monotonic but non adjustable clock info = time.get_clock_info('monotonic') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 2 19:27:06 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 2 Jan 2014 19:27:06 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_remove_bracket?= =?utf-8?q?s?= Message-ID: <3dwHlZ0KZQz7Ljy@mail.python.org> http://hg.python.org/cpython/rev/8083b8870686 changeset: 88256:8083b8870686 branch: 3.3 parent: 88254:82df66a091da user: Benjamin Peterson date: Thu Jan 02 12:22:30 2014 -0600 summary: remove brackets files: Doc/library/inspect.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -752,7 +752,7 @@ metatype is in use, cls will be the first element of the tuple. -.. function:: getcallargs(func[, *args][, **kwds]) +.. function:: getcallargs(func, *args, **kwds) Bind the *args* and *kwds* to the argument names of the Python function or method *func*, as if it was called with them. For bound methods, bind also the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 2 19:27:07 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 2 Jan 2014 19:27:07 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_avoid_paramete?= =?utf-8?q?r_name_clash_=28closes_=2320108=29?= Message-ID: <3dwHlb1qtGz7Ljw@mail.python.org> http://hg.python.org/cpython/rev/b0d472e3ff42 changeset: 88257:b0d472e3ff42 branch: 3.3 user: Benjamin Peterson date: Thu Jan 02 12:24:08 2014 -0600 summary: avoid parameter name clash (closes #20108) files: Lib/inspect.py | 4 +++- Misc/NEWS | 2 ++ 2 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -985,12 +985,14 @@ (f_name, sig, "s" if plural else "", given, kwonly_sig, "was" if given == 1 and not kwonly_given else "were")) -def getcallargs(func, *positional, **named): +def getcallargs(*func_and_positional, **named): """Get the mapping of arguments to values. A dict is returned, with keys the function argument names (including the names of the * and ** arguments, if any), and values the respective bound values from 'positional' and 'named'.""" + func = func_and_positional[0] + positional = func_and_positional[1:] spec = getfullargspec(func) args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = spec f_name = func.__name__ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -29,6 +29,8 @@ Library ------- +- Issue #20108: Avoid parameter name clash in inspect.getcallargs(). + - Issue #12692: Backport the fix for ResourceWarning in test_urllib2net. This also helps in closing the socket when Connection Close header is not sent. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 2 19:27:08 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 2 Jan 2014 19:27:08 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge_3=2E3_=28closes_=2320108=29?= Message-ID: <3dwHlc3TqFz7LkT@mail.python.org> http://hg.python.org/cpython/rev/c265675cd8e2 changeset: 88258:c265675cd8e2 parent: 88255:e2a1400b7db9 parent: 88257:b0d472e3ff42 user: Benjamin Peterson date: Thu Jan 02 12:26:50 2014 -0600 summary: merge 3.3 (closes #20108) files: Doc/library/inspect.rst | 2 +- Lib/inspect.py | 4 +++- Misc/NEWS | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -753,7 +753,7 @@ metatype is in use, cls will be the first element of the tuple. -.. function:: getcallargs(func[, *args][, **kwds]) +.. function:: getcallargs(func, *args, **kwds) Bind the *args* and *kwds* to the argument names of the Python function or method *func*, as if it was called with them. For bound methods, bind also the diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1087,12 +1087,14 @@ (f_name, sig, "s" if plural else "", given, kwonly_sig, "was" if given == 1 and not kwonly_given else "were")) -def getcallargs(func, *positional, **named): +def getcallargs(*func_and_positional, **named): """Get the mapping of arguments to values. A dict is returned, with keys the function argument names (including the names of the * and ** arguments, if any), and values the respective bound values from 'positional' and 'named'.""" + func = func_and_positional[0] + positional = func_and_positional[1:] spec = getfullargspec(func) args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = spec f_name = func.__name__ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -46,6 +46,8 @@ - Fix breakage in TestSuite.countTestCases() introduced by issue #11798. +- Issue #20108: Avoid parameter name clash in inspect.getcallargs(). + - Issue #19918: Fix PurePath.relative_to() under Windows. - Issue #19422: Explicitly disallow non-SOCK_STREAM sockets in the ssl -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 2 19:44:51 2014 From: python-checkins at python.org (r.david.murray) Date: Thu, 2 Jan 2014 19:44:51 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE3MjgyOiBEb2N1?= =?utf-8?q?ment_unittest=2Emain_defaultTest_argument=2E?= Message-ID: <3dwJ833cc5z7Ljh@mail.python.org> http://hg.python.org/cpython/rev/045e7a587f3c changeset: 88259:045e7a587f3c branch: 3.3 parent: 88257:b0d472e3ff42 user: R David Murray date: Thu Jan 02 13:37:26 2014 -0500 summary: #17282: Document unittest.main defaultTest argument. files: Doc/library/unittest.rst | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1801,6 +1801,10 @@ if __name__ == '__main__': unittest.main(verbosity=2) + The *defaultTest* argument is the name of the test to run if no test names + are specified via *argv*. If not specified or ``None`` and no test names are + provided via *argv*, all tests found in *module* are run. + The *argv* argument can be a list of options passed to the program, with the first element being the program name. If not specified or ``None``, the values of :data:`sys.argv` are used. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 2 19:44:52 2014 From: python-checkins at python.org (r.david.murray) Date: Thu, 2 Jan 2014 19:44:52 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE3MjgyOiBEb2N1?= =?utf-8?q?ment_unittest=2Emain_defaultTest_argument=2E?= Message-ID: <3dwJ845Y8rz7Ljk@mail.python.org> http://hg.python.org/cpython/rev/69b5f6924553 changeset: 88260:69b5f6924553 branch: 2.7 parent: 88244:aeb70f2f6f38 user: R David Murray date: Thu Jan 02 13:38:02 2014 -0500 summary: #17282: Document unittest.main defaultTest argument. files: Doc/library/unittest.rst | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1808,6 +1808,10 @@ if __name__ == '__main__': unittest.main(verbosity=2) + The *defaultTest* argument is the name of the test to run if no test names + are specified via *argv*. If not specified or ``None`` and no test names are + provided via *argv*, all tests found in *module* are run. + The *argv* argument can be a list of options passed to the program, with the first element being the program name. If not specified or ``None``, the values of :data:`sys.argv` are used. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 2 19:44:54 2014 From: python-checkins at python.org (r.david.murray) Date: Thu, 2 Jan 2014 19:44:54 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_and_update_=2317282=3A_Document_unittest=2Emain_de?= =?utf-8?q?faultTest_argument=2E?= Message-ID: <3dwJ860G3Tz7LkF@mail.python.org> http://hg.python.org/cpython/rev/1bbf8c263d3c changeset: 88261:1bbf8c263d3c parent: 88258:c265675cd8e2 parent: 88259:045e7a587f3c user: R David Murray date: Thu Jan 02 13:43:02 2014 -0500 summary: Merge and update #17282: Document unittest.main defaultTest argument. In 3.4 defaultTest can also be a list (see issue 15132). files: Doc/library/unittest.rst | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1966,6 +1966,11 @@ if __name__ == '__main__': unittest.main(verbosity=2) + The *defaultTest* argument is either the name of a single test or an + iterable of test names to run if no test names are specified via *argv*. If + not specified or ``None`` and no test names are provided via *argv*, all + tests found in *module* are run. + The *argv* argument can be a list of options passed to the program, with the first element being the program name. If not specified or ``None``, the values of :data:`sys.argv` are used. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 2 19:44:55 2014 From: python-checkins at python.org (r.david.murray) Date: Thu, 2 Jan 2014 19:44:55 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_sqlite3_uri_pa?= =?utf-8?q?rm=2C_unittest=2Emain_defaultTest=2C_ftplib=2ENetrc_deprecation?= Message-ID: <3dwJ871h9Hz7Lk3@mail.python.org> http://hg.python.org/cpython/rev/04af288c004c changeset: 88262:04af288c004c user: R David Murray date: Thu Jan 02 13:44:18 2014 -0500 summary: whatsnew: sqlite3 uri parm, unittest.main defaultTest, ftplib.Netrc deprecation files: Doc/whatsnew/3.4.rst | 17 +++++++++++++++++ Misc/NEWS | 2 +- 2 files changed, 18 insertions(+), 1 deletions(-) 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 @@ -915,6 +915,15 @@ during debugging, instead of integer "magic numbers". +sqlite3 +------- + +A new boolean parameter, *uri*, to the :func:`~sqlite3.connect` function can +be used to indicate that the *database* parameter is a ``uri`` (see +the `SQLite URI documentation `_). +(Contributed by poq in :issue:`13773`.) + + ssl --- @@ -998,6 +1007,10 @@ :meth:`~unittest.TestCase.subTest` context manager. (Contributed by Antoine Pitrou in :issue:`16997`.) +:func:`unittest.main` now also accepts an iterable of test names for +*defaultTest*, where previously it only accepted a single test name as a +string. (Contributed by Jyrki Pulliainen in :issue:`15132`.) + venv ---- @@ -1246,6 +1259,10 @@ * MD5 as default digestmod for :mod:`hmac` is deprecated. Python 3.6 will require an explicit digest name or constructor as *digestmod* argument. +* The internal ``Netrc`` class in the :mod:`ftplib` module has been documented + as deprecated in its docstring for quite some time. It now emits a + :exc:`DeprecationWarning` and will be removed completely in Python 3.5. + Deprecated Functions and Types in the C API ------------------------------------------- diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2439,7 +2439,7 @@ - Issue #4591: Uid and gid values larger than 2**31 are supported now. -- Issue #17141: random.vonmisesvariate() no more hangs for large kappas. +- Issue #17141: random.vonmisesvariate() no longer hangs for large kappas. - Issue #17149: Fix random.vonmisesvariate to always return results in [0, 2*math.pi]. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 2 23:48:39 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 2 Jan 2014 23:48:39 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_correct_word_f?= =?utf-8?q?or_=5F=5Fannotations=5F=5F_doc_=28closes_=2320110=29?= Message-ID: <3dwPYM3tZ2z7LjY@mail.python.org> http://hg.python.org/cpython/rev/203ca77ea819 changeset: 88263:203ca77ea819 branch: 3.3 parent: 88259:045e7a587f3c user: Benjamin Peterson date: Thu Jan 02 16:47:50 2014 -0600 summary: correct word for __annotations__ doc (closes #20110) Patch from Claudiu Popa. files: Doc/reference/datamodel.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -495,7 +495,7 @@ | :attr:`__annotations__` | A dict containing annotations | Writable | | | of parameters. The keys of | | | | the dict are the parameter | | - | | names, or ``'return'`` for | | + | | names, and ``'return'`` for | | | | the return annotation, if | | | | provided. | | +-------------------------+-------------------------------+-----------+ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 2 23:48:40 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 2 Jan 2014 23:48:40 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4zICgjMjAxMTAp?= Message-ID: <3dwPYN5T9Vz7LjY@mail.python.org> http://hg.python.org/cpython/rev/3e75f649e93b changeset: 88264:3e75f649e93b parent: 88262:04af288c004c parent: 88263:203ca77ea819 user: Benjamin Peterson date: Thu Jan 02 16:48:24 2014 -0600 summary: merge 3.3 (#20110) files: Doc/reference/datamodel.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -495,7 +495,7 @@ | :attr:`__annotations__` | A dict containing annotations | Writable | | | of parameters. The keys of | | | | the dict are the parameter | | - | | names, or ``'return'`` for | | + | | names, and ``'return'`` for | | | | the return annotation, if | | | | provided. | | +-------------------------+-------------------------------+-----------+ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 00:07:37 2014 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 3 Jan 2014 00:07:37 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320111=3A_pathlib?= =?utf-8?q?=2EPath=2Ewith=5Fsuffix=28=29_now_sanity_checks_the_given_suffi?= =?utf-8?q?x=2E?= Message-ID: <3dwPzF5BNsz7Ljh@mail.python.org> http://hg.python.org/cpython/rev/ef2b2ddd27c8 changeset: 88265:ef2b2ddd27c8 user: Antoine Pitrou date: Fri Jan 03 00:07:17 2014 +0100 summary: Issue #20111: pathlib.Path.with_suffix() now sanity checks the given suffix. files: Lib/pathlib.py | 6 ++++++ Lib/test/test_pathlib.py | 20 ++++++++++++++++++++ Misc/NEWS | 2 ++ 3 files changed, 28 insertions(+), 0 deletions(-) diff --git a/Lib/pathlib.py b/Lib/pathlib.py --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -755,6 +755,12 @@ def with_suffix(self, suffix): """Return a new path with the file suffix changed (or added, if none).""" # XXX if suffix is None, should the current suffix be removed? + drv, root, parts = self._flavour.parse_parts((suffix,)) + if drv or root or len(parts) != 1: + raise ValueError("Invalid suffix %r" % (suffix)) + suffix = parts[0] + if not suffix.startswith('.'): + raise ValueError("Invalid suffix %r" % (suffix)) name = self.name if not name: raise ValueError("%r has an empty name" % (self,)) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -528,9 +528,16 @@ self.assertEqual(P('/a/b').with_suffix('.gz'), P('/a/b.gz')) self.assertEqual(P('a/b.py').with_suffix('.gz'), P('a/b.gz')) self.assertEqual(P('/a/b.py').with_suffix('.gz'), P('/a/b.gz')) + # Path doesn't have a "filename" component self.assertRaises(ValueError, P('').with_suffix, '.gz') self.assertRaises(ValueError, P('.').with_suffix, '.gz') self.assertRaises(ValueError, P('/').with_suffix, '.gz') + # Invalid suffix + self.assertRaises(ValueError, P('a/b').with_suffix, 'gz') + self.assertRaises(ValueError, P('a/b').with_suffix, '/') + self.assertRaises(ValueError, P('a/b').with_suffix, '/.gz') + self.assertRaises(ValueError, P('a/b').with_suffix, 'c/d') + self.assertRaises(ValueError, P('a/b').with_suffix, '.c/.d') def test_relative_to_common(self): P = self.cls @@ -920,10 +927,23 @@ self.assertEqual(P('c:/a/b').with_suffix('.gz'), P('c:/a/b.gz')) self.assertEqual(P('c:a/b.py').with_suffix('.gz'), P('c:a/b.gz')) self.assertEqual(P('c:/a/b.py').with_suffix('.gz'), P('c:/a/b.gz')) + # Path doesn't have a "filename" component self.assertRaises(ValueError, P('').with_suffix, '.gz') self.assertRaises(ValueError, P('.').with_suffix, '.gz') self.assertRaises(ValueError, P('/').with_suffix, '.gz') self.assertRaises(ValueError, P('//My/Share').with_suffix, '.gz') + # Invalid suffix + self.assertRaises(ValueError, P('c:a/b').with_suffix, 'gz') + self.assertRaises(ValueError, P('c:a/b').with_suffix, '/') + self.assertRaises(ValueError, P('c:a/b').with_suffix, '\\') + self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c:') + self.assertRaises(ValueError, P('c:a/b').with_suffix, '/.gz') + self.assertRaises(ValueError, P('c:a/b').with_suffix, '\\.gz') + self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c:.gz') + self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c/d') + self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c\\d') + self.assertRaises(ValueError, P('c:a/b').with_suffix, '.c/d') + self.assertRaises(ValueError, P('c:a/b').with_suffix, '.c\\d') def test_relative_to(self): P = self.cls diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -44,6 +44,8 @@ Library ------- +- Issue #20111: pathlib.Path.with_suffix() now sanity checks the given suffix. + - Fix breakage in TestSuite.countTestCases() introduced by issue #11798. - Issue #20108: Avoid parameter name clash in inspect.getcallargs(). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 03:27:02 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 3 Jan 2014 03:27:02 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_make_PY34_symbo?= =?utf-8?q?l_private_=28rename_it_to_=5FPY34=29?= Message-ID: <3dwVPL5V0Yz7LjN@mail.python.org> http://hg.python.org/cpython/rev/584870f6d3d1 changeset: 88266:584870f6d3d1 user: Victor Stinner date: Thu Jan 02 18:41:34 2014 +0100 summary: asyncio: make PY34 symbol private (rename it to _PY34) files: Lib/asyncio/transports.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/asyncio/transports.py b/Lib/asyncio/transports.py --- a/Lib/asyncio/transports.py +++ b/Lib/asyncio/transports.py @@ -2,7 +2,7 @@ import sys -PY34 = sys.version_info >= (3, 4) +_PY34 = sys.version_info >= (3, 4) __all__ = ['BaseTransport', 'ReadTransport', 'WriteTransport', 'Transport', 'DatagramTransport', 'SubprocessTransport', @@ -94,7 +94,7 @@ The default implementation concatenates the arguments and calls write() on the result. """ - if not PY34: + if not _PY34: # In Python 3.3, bytes.join() doesn't handle memoryview. list_of_data = ( bytes(data) if isinstance(data, memoryview) else data -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 03:27:04 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 3 Jan 2014 03:27:04 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_audioop=3A_adpcm2lin=28=29?= =?utf-8?q?_and_lin2adpcm=28=29_now_raises_a_TypeError_instead_of_a?= Message-ID: <3dwVPN0Trkz7LjN@mail.python.org> http://hg.python.org/cpython/rev/dee33603a5fa changeset: 88267:dee33603a5fa user: Victor Stinner date: Fri Jan 03 03:26:47 2014 +0100 summary: audioop: adpcm2lin() and lin2adpcm() now raises a TypeError instead of a SystemError if the state type is invalid. files: Lib/test/test_audioop.py | 5 +++++ Modules/audioop.c | 6 ++++++ 2 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_audioop.py b/Lib/test/test_audioop.py --- a/Lib/test/test_audioop.py +++ b/Lib/test/test_audioop.py @@ -269,6 +269,11 @@ self.assertEqual(audioop.lin2adpcm(b'\0' * w * 10, w, None), (b'\0' * 5, (0, 0))) + def test_invalid_adpcm_state(self): + # state must be a tuple or None, not an integer + self.assertRaises(TypeError, audioop.adpcm2lin, b'\0', 1, 555) + self.assertRaises(TypeError, audioop.lin2adpcm, b'\0', 1, 555) + def test_lin2alaw(self): self.assertEqual(audioop.lin2alaw(datas[1], 1), b'\xd5\x87\xa4\x24\xaa\x2a\x5a') diff --git a/Modules/audioop.c b/Modules/audioop.c --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -1525,6 +1525,9 @@ /* First time, it seems. Set defaults */ valpred = 0; index = 0; + } else if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state must be a tuple or None"); + goto exit; } else if (!PyArg_ParseTuple(state, "ii", &valpred, &index)) goto exit; @@ -1631,6 +1634,9 @@ /* First time, it seems. Set defaults */ valpred = 0; index = 0; + } else if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state must be a tuple or None"); + goto exit; } else if (!PyArg_ParseTuple(state, "ii", &valpred, &index)) goto exit; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 05:20:49 2014 From: python-checkins at python.org (daniel.holth) Date: Fri, 3 Jan 2014 05:20:49 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318585=3A_speed_zi?= =?utf-8?q?pfile_import_by_only_generating_zipfile=2E=5FZipDecryptor_on?= Message-ID: <3dwXwd2kkbz7Lk4@mail.python.org> http://hg.python.org/cpython/rev/536a2cf5f1d2 changeset: 88268:536a2cf5f1d2 user: Daniel Holth date: Thu Jan 02 23:17:21 2014 -0500 summary: Issue #18585: speed zipfile import by only generating zipfile._ZipDecryptor on demand files: Lib/zipfile.py | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/zipfile.py b/Lib/zipfile.py --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -475,13 +475,15 @@ crc = ((crc >> 1) & 0x7FFFFFFF) table[i] = crc return table - crctable = _GenerateCRCTable() + crctable = None def _crc32(self, ch, crc): """Compute the CRC32 primitive on one byte.""" return ((crc >> 8) & 0xffffff) ^ self.crctable[(crc ^ ch) & 0xff] def __init__(self, pwd): + if _ZipDecrypter.crctable is None: + _ZipDecrypter.crctable = _ZipDecrypter._GenerateCRCTable() self.key0 = 305419896 self.key1 = 591751049 self.key2 = 878082192 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 06:31:31 2014 From: python-checkins at python.org (eric.snow) Date: Fri, 3 Jan 2014 06:31:31 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320097=3A_Fix_bad_?= =?utf-8?q?use_of_=22self=22_in_importlib=27s_WindowsRegistryFinder=2E?= Message-ID: <3dwZVC02V2z7LkF@mail.python.org> http://hg.python.org/cpython/rev/7dbb4c6cd30e changeset: 88269:7dbb4c6cd30e user: Eric Snow date: Thu Jan 02 22:25:00 2014 -0700 summary: Issue #20097: Fix bad use of "self" in importlib's WindowsRegistryFinder. files: Lib/importlib/_bootstrap.py | 2 +- Lib/test/test_importlib/test_windows.py | 29 + Misc/NEWS | 2 + Python/importlib.h | 3726 +++++----- 4 files changed, 1895 insertions(+), 1864 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -1406,7 +1406,7 @@ @classmethod def find_module(cls, fullname, path=None): """Find module named in the registry.""" - spec = self.find_spec(fullname, path) + spec = cls.find_spec(fullname, path) if spec is not None: return spec.loader else: diff --git a/Lib/test/test_importlib/test_windows.py b/Lib/test/test_importlib/test_windows.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_importlib/test_windows.py @@ -0,0 +1,29 @@ +from . import util +frozen_machinery, source_machinery = util.import_importlib('importlib.machinery') + +import sys +import unittest + + + at unittest.skipUnless(sys.platform.startswith('win'), 'requires Windows') +class WindowsRegistryFinderTests: + + # XXX Need a test that finds the spec via the registry. + + def test_find_spec_missing(self): + spec = self.machinery.WindowsRegistryFinder.find_spec('spam') + self.assertIs(spec, None) + + def test_find_module_missing(self): + loader = self.machinery.WindowsRegistryFinder.find_module('spam') + self.assertIs(loader, None) + + +class Frozen_WindowsRegistryFinderTests(WindowsRegistryFinderTests, + unittest.TestCase): + machinery = frozen_machinery + + +class Source_WindowsRegistryFinderTests(WindowsRegistryFinderTests, + unittest.TestCase): + machinery = source_machinery diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,8 @@ - Issue #19736: Add module-level statvfs constants defined for GNU/glibc based systems. +- Issue #20097: Fix bad use of "self" in importlib's WindowsRegistryFinder. + - Issue #19729: In str.format(), fix recursive expansion in format spec. - Issue #19638: Fix possible crash / undefined behaviour from huge (more than 2 diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Jan 3 09:49:44 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 03 Jan 2014 09:49:44 +0100 Subject: [Python-checkins] Daily reference leaks (dee33603a5fa): sum=3 Message-ID: results for dee33603a5fa on branch "default" -------------------------------------------- test_audioop leaked [1, 1, 1] references, sum=3 test_site leaked [-2, 2, 0] references, sum=0 test_site leaked [-2, 2, 0] memory blocks, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogrwKKjc', '-x'] From root at python.org Fri Jan 3 11:05:27 2014 From: root at python.org (Cron Daemon) Date: Fri, 03 Jan 2014 11:05:27 +0100 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: abort: error: Connection timed out From python-checkins at python.org Fri Jan 3 12:27:27 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 3 Jan 2014 12:27:27 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318294=3A_Fix_uint?= =?utf-8?q?=5Fconverter=28=29_in_zlibmodule=2Ec=2C_fix_the_=22=3E_UINT=5FM?= =?utf-8?q?AX=22_check?= Message-ID: <3dwkNv1GJ5z7LkC@mail.python.org> http://hg.python.org/cpython/rev/0cca6c5513d2 changeset: 88270:0cca6c5513d2 user: Victor Stinner date: Fri Jan 03 12:26:12 2014 +0100 summary: Issue #18294: Fix uint_converter() in zlibmodule.c, fix the "> UINT_MAX" check files: Modules/zlibmodule.c | 11 ++++++----- 1 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -329,11 +329,6 @@ uval = PyLong_AsUnsignedLong(obj); if (uval == (unsigned long)-1 && PyErr_Occurred()) return 0; - if (uval > UINT_MAX) { - PyErr_SetString(PyExc_OverflowError, - "Python int too large for C unsigned int"); - return 0; - } } else { if (val < 0) { @@ -344,6 +339,12 @@ uval = (unsigned long)val; } + if (uval > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large for C unsigned int"); + return 0; + } + *(unsigned int *)ptr = Py_SAFE_DOWNCAST(uval, unsigned long, unsigned int); return 1; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 13:01:01 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 3 Jan 2014 13:01:01 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_add_unicode=5Fchar=28=29_i?= =?utf-8?q?n_unicodeobject=2Ec_to_factorize_code?= Message-ID: <3dwl7d4x8cz7Ljs@mail.python.org> http://hg.python.org/cpython/rev/d453c95def31 changeset: 88271:d453c95def31 user: Victor Stinner date: Fri Jan 03 12:53:47 2014 +0100 summary: add unicode_char() in unicodeobject.c to factorize code files: Objects/unicodeobject.c | 86 ++++++++++------------------ 1 files changed, 31 insertions(+), 55 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1749,7 +1749,6 @@ } } - static PyObject* get_latin1_char(unsigned char ch) { @@ -1766,6 +1765,31 @@ return unicode; } +static PyObject* +unicode_char(Py_UCS4 ch) +{ + PyObject *unicode; + + assert(ch <= MAX_UNICODE); + + 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: + PyUnicode_2BYTE_DATA(unicode)[0] = (Py_UCS2)ch; + break; + default: + assert(PyUnicode_KIND(unicode) == PyUnicode_4BYTE_KIND); + PyUnicode_4BYTE_DATA(unicode)[0] = ch; + } + assert(_PyUnicode_CheckConsistency(unicode, 1)); + return unicode; +} + PyObject * PyUnicode_FromUnicode(const Py_UNICODE *u, Py_ssize_t size) { @@ -1964,22 +1988,8 @@ if (size == 0) _Py_RETURN_UNICODE_EMPTY(); assert(size > 0); - if (size == 1) { - Py_UCS4 ch = u[0]; - int kind; - void *data; - if (ch < 256) - return get_latin1_char((unsigned char)ch); - - res = PyUnicode_New(1, ch); - if (res == NULL) - return NULL; - kind = PyUnicode_KIND(res); - data = PyUnicode_DATA(res); - PyUnicode_WRITE(kind, data, 0, ch); - assert(_PyUnicode_CheckConsistency(res, 1)); - return res; - } + if (size == 1) + return unicode_char(u[0]); max_char = ucs2lib_find_max_char(u, u + size); res = PyUnicode_New(size, max_char); @@ -2004,22 +2014,8 @@ if (size == 0) _Py_RETURN_UNICODE_EMPTY(); assert(size > 0); - if (size == 1) { - Py_UCS4 ch = u[0]; - int kind; - void *data; - if (ch < 256) - return get_latin1_char((unsigned char)ch); - - res = PyUnicode_New(1, ch); - if (res == NULL) - return NULL; - kind = PyUnicode_KIND(res); - data = PyUnicode_DATA(res); - PyUnicode_WRITE(kind, data, 0, ch); - assert(_PyUnicode_CheckConsistency(res, 1)); - return res; - } + if (size == 1) + return unicode_char(u[0]); max_char = ucs4lib_find_max_char(u, u + size); res = PyUnicode_New(size, max_char); @@ -2887,17 +2883,7 @@ return NULL; } - if ((Py_UCS4)ordinal < 256) - return get_latin1_char((unsigned char)ordinal); - - v = PyUnicode_New(1, ordinal); - if (v == NULL) - return NULL; - kind = PyUnicode_KIND(v); - data = PyUnicode_DATA(v); - PyUnicode_WRITE(kind, data, 0, ordinal); - assert(_PyUnicode_CheckConsistency(v, 1)); - return v; + return unicode_char((Py_UCS4)ordinal); } PyObject * @@ -11354,17 +11340,7 @@ kind = PyUnicode_KIND(self); data = PyUnicode_DATA(self); ch = PyUnicode_READ(kind, data, index); - if (ch < 256) - return get_latin1_char(ch); - - res = PyUnicode_New(1, ch); - if (res == NULL) - return NULL; - kind = PyUnicode_KIND(res); - data = PyUnicode_DATA(res); - PyUnicode_WRITE(kind, data, 0, ch); - assert(_PyUnicode_CheckConsistency(res, 1)); - return res; + return unicode_char(ch); } /* Believe it or not, this produces the same value for ASCII strings -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 13:16:31 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 3 Jan 2014 13:16:31 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_unicode=5Fchar=28=29_uses_?= =?utf-8?q?get=5Flatin1=5Fchar=28=29_to_get_latin1_singleton_characters?= Message-ID: <3dwlTW2y2cz7Ljs@mail.python.org> http://hg.python.org/cpython/rev/fb8802277613 changeset: 88272:fb8802277613 user: Victor Stinner date: Fri Jan 03 13:16:00 2014 +0100 summary: unicode_char() uses get_latin1_char() to get latin1 singleton characters files: Objects/unicodeobject.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1772,6 +1772,9 @@ assert(ch <= MAX_UNICODE); + if (ch < 256) + return get_latin1_char(ch); + unicode = PyUnicode_New(1, ch); if (unicode == NULL) return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 14:11:02 2014 From: python-checkins at python.org (martin.v.loewis) Date: Fri, 3 Jan 2014 14:11:02 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_*_Issue_=2316113=3A_Remove?= =?utf-8?q?_sha3_module_again=2E?= Message-ID: <3dwmhQ5pZlz7LjV@mail.python.org> http://hg.python.org/cpython/rev/52350d325b41 changeset: 88273:52350d325b41 user: Martin v. L?wis date: Fri Jan 03 14:05:06 2014 +0100 summary: * Issue #16113: Remove sha3 module again. Patch by Christian Heimes, with modifications. files: Doc/library/hashlib.rst | 6 +- Doc/license.rst | 19 - Doc/whatsnew/3.4.rst | 8 - Lib/hashlib.py | 10 +- Lib/test/test_hashlib.py | 112 +- Makefile.pre.in | 1 - Misc/NEWS | 2 + Modules/_sha3/cleanup.py | 49 - Modules/_sha3/keccak/KeccakF-1600-32-rvk.macros | 555 ---- Modules/_sha3/keccak/KeccakF-1600-32-s1.macros | 1187 ---------- Modules/_sha3/keccak/KeccakF-1600-32-s2.macros | 1187 ---------- Modules/_sha3/keccak/KeccakF-1600-32.macros | 26 - Modules/_sha3/keccak/KeccakF-1600-64.macros | 728 ------ Modules/_sha3/keccak/KeccakF-1600-int-set.h | 6 - Modules/_sha3/keccak/KeccakF-1600-interface.h | 46 - Modules/_sha3/keccak/KeccakF-1600-opt32-settings.h | 6 - Modules/_sha3/keccak/KeccakF-1600-opt32.c | 524 ---- Modules/_sha3/keccak/KeccakF-1600-opt64-settings.h | 9 - Modules/_sha3/keccak/KeccakF-1600-opt64.c | 510 ---- Modules/_sha3/keccak/KeccakF-1600-simd128.macros | 651 ----- Modules/_sha3/keccak/KeccakF-1600-simd64.macros | 517 ---- Modules/_sha3/keccak/KeccakF-1600-unrolling.macros | 124 - Modules/_sha3/keccak/KeccakF-1600-xop.macros | 573 ---- Modules/_sha3/keccak/KeccakNISTInterface.c | 83 - Modules/_sha3/keccak/KeccakNISTInterface.h | 72 - Modules/_sha3/keccak/KeccakSponge.c | 266 -- Modules/_sha3/keccak/KeccakSponge.h | 76 - Modules/_sha3/keccak/brg_endian.h | 142 - Modules/_sha3/keccak/crypto_hash.h | 0 Modules/_sha3/sha3module.c | 593 ---- PC/VS9.0/_sha3.vcproj | 513 ---- PC/VS9.0/pcbuild.sln | 2 - PCbuild/_sha3.vcxproj | 218 - PCbuild/_sha3.vcxproj.filters | 13 - PCbuild/pcbuild.sln | 4 - PCbuild/readme.txt | 1 - Tools/msi/msi.py | 1 - setup.py | 9 - 38 files changed, 5 insertions(+), 8844 deletions(-) diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst --- a/Doc/library/hashlib.rst +++ b/Doc/library/hashlib.rst @@ -60,13 +60,9 @@ Constructors for hash algorithms that are always present in this module are :func:`md5`, :func:`sha1`, :func:`sha224`, :func:`sha256`, :func:`sha384`, -:func:`sha512`, :func:`sha3_224`, :func:`sha3_256`, :func:`sha3_384`, and -:func:`sha3_512`. Additional algorithms may also be available depending upon +and :func:`sha512`. Additional algorithms may also be available depending upon the OpenSSL library that Python uses on your platform. - .. versionchanged:: 3.4 - Added sha3 family of hash algorithms. - For example, to obtain the digest of the byte string ``b'Nobody inspects the spammish repetition'``:: diff --git a/Doc/license.rst b/Doc/license.rst --- a/Doc/license.rst +++ b/Doc/license.rst @@ -590,25 +590,6 @@ SUCH DAMAGE. -SHA-3 ------ - -The module :mod:`_sha3` and :mod:`hashlib` are using the reference -implementation of Keccak. The files at :file:`Modules/_sha3/keccak/` contain -the following note:: - - The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, - Micha?l Peeters and Gilles Van Assche. For more information, feedback or - questions, please refer to our website: http://keccak.noekeon.org/ - - Implementation by the designers, - hereby denoted as "the implementer". - - To the extent possible under law, the implementer has waived all copyright - and related or neighboring rights to the source code in this file. - http://creativecommons.org/publicdomain/zero/1.0/ - - SipHash24 --------- 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 @@ -123,8 +123,6 @@ * :ref:`Single-dispatch generic functions ` in :mod:`functools` (:pep:`443`). * New :mod:`pickle` :ref:`protocol 4 ` (:pep:`3154`). -* :ref:`SHA-3 (Keccak) support ` for :mod:`hashlib` - (:issue:`16113`). * :ref:`TLSv1.1 and TLSv1.2 support ` for :mod:`ssl` (:issue:`16692`). * :mod:`multiprocessing` now has :ref:`an option to avoid using os.fork @@ -667,12 +665,6 @@ New :func:`hashlib.pbkdf2_hmac` function. (Contributed by Christian Heimes in :issue:`18582`) -.. _whatsnew-sha3: - -New :ref:`hash algorithms ` ``sha3_224()``, ``sha3_256()``, -``sha3_384()``, and ``sha3_512()``. (Contributed by Christian Heimes in -:issue:`16113`.) - html ---- diff --git a/Lib/hashlib.py b/Lib/hashlib.py --- a/Lib/hashlib.py +++ b/Lib/hashlib.py @@ -54,8 +54,7 @@ # This tuple and __get_builtin_constructor() must be modified if a new # always available algorithm is added. -__always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', - 'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512') +__always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512') algorithms_guaranteed = set(__always_supported) algorithms_available = set(__always_supported) @@ -86,13 +85,6 @@ import _sha512 cache['SHA384'] = cache['sha384'] = _sha512.sha384 cache['SHA512'] = cache['sha512'] = _sha512.sha512 - elif name in {'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512', - 'SHA3_224', 'SHA3_256', 'SHA3_384', 'SHA3_512'}: - import _sha3 - cache['SHA3_224'] = cache['sha3_224'] = _sha3.sha3_224 - cache['SHA3_256'] = cache['sha3_256'] = _sha3.sha3_256 - cache['SHA3_384'] = cache['sha3_384'] = _sha3.sha3_384 - cache['SHA3_512'] = cache['sha3_512'] = _sha3.sha3_512 except ImportError: pass # no extension module, this hash is unsupported. diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -38,10 +38,7 @@ class HashLibTestCase(unittest.TestCase): supported_hash_names = ( 'md5', 'MD5', 'sha1', 'SHA1', 'sha224', 'SHA224', 'sha256', 'SHA256', - 'sha384', 'SHA384', 'sha512', 'SHA512', - 'sha3_224', 'sha3_256', 'sha3_384', - 'sha3_512', 'SHA3_224', 'SHA3_256', - 'SHA3_384', 'SHA3_512' ) + 'sha384', 'SHA384', 'sha512', 'SHA512') # Issue #14693: fallback modules are always compiled under POSIX _warn_on_extension_import = os.name == 'posix' or COMPILED_WITH_PYDEBUG @@ -102,12 +99,6 @@ if _sha512: add_builtin_constructor('sha384') add_builtin_constructor('sha512') - _sha3 = self._conditional_import_module('_sha3') - if _sha3: - add_builtin_constructor('sha3_224') - add_builtin_constructor('sha3_256') - add_builtin_constructor('sha3_384') - add_builtin_constructor('sha3_512') super(HashLibTestCase, self).__init__(*args, **kwargs) @@ -234,10 +225,6 @@ self.check_no_unicode('sha256') self.check_no_unicode('sha384') self.check_no_unicode('sha512') - self.check_no_unicode('sha3_224') - self.check_no_unicode('sha3_256') - self.check_no_unicode('sha3_384') - self.check_no_unicode('sha3_512') def check_blocksize_name(self, name, block_size=0, digest_size=0): constructors = self.constructors_to_test[name] @@ -257,10 +244,6 @@ self.check_blocksize_name('sha256', 64, 32) self.check_blocksize_name('sha384', 128, 48) self.check_blocksize_name('sha512', 128, 64) - self.check_blocksize_name('sha3_224', NotImplemented, 28) - self.check_blocksize_name('sha3_256', NotImplemented, 32) - self.check_blocksize_name('sha3_384', NotImplemented, 48) - self.check_blocksize_name('sha3_512', NotImplemented, 64) def test_case_md5_0(self): self.check('md5', b'', 'd41d8cd98f00b204e9800998ecf8427e') @@ -396,27 +379,6 @@ "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb"+ "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b") - # SHA-3 family - def test_case_sha3_224_0(self): - self.check('sha3_224', b"", - "F71837502BA8E10837BDD8D365ADB85591895602FC552B48B7390ABD") - - def test_case_sha3_224_1(self): - self.check('sha3_224', bytes.fromhex("CC"), - "A9CAB59EB40A10B246290F2D6086E32E3689FAF1D26B470C899F2802") - - def test_case_sha3_224_2(self): - self.check('sha3_224', bytes.fromhex("41FB"), - "615BA367AFDC35AAC397BC7EB5D58D106A734B24986D5D978FEFD62C") - - def test_case_sha3_224_3(self): - self.check('sha3_224', bytes.fromhex( - "433C5303131624C0021D868A30825475E8D0BD3052A022180398F4CA4423B9"+ - "8214B6BEAAC21C8807A2C33F8C93BD42B092CC1B06CEDF3224D5ED1EC29784"+ - "444F22E08A55AA58542B524B02CD3D5D5F6907AFE71C5D7462224A3F9D9E53"+ - "E7E0846DCBB4CE"), - "62B10F1B6236EBC2DA72957742A8D4E48E213B5F8934604BFD4D2C3A") - @bigmemtest(size=_4G + 5, memuse=1) def test_case_sha3_224_huge(self, size): if size == _4G + 5: @@ -426,78 +388,6 @@ except OverflowError: pass # 32-bit arch - - def test_case_sha3_256_0(self): - self.check('sha3_256', b"", - "C5D2460186F7233C927E7DB2DCC703C0E500B653CA82273B7BFAD8045D85A470") - - def test_case_sha3_256_1(self): - self.check('sha3_256', bytes.fromhex("CC"), - "EEAD6DBFC7340A56CAEDC044696A168870549A6A7F6F56961E84A54BD9970B8A") - - def test_case_sha3_256_2(self): - self.check('sha3_256', bytes.fromhex("41FB"), - "A8EACEDA4D47B3281A795AD9E1EA2122B407BAF9AABCB9E18B5717B7873537D2") - - def test_case_sha3_256_3(self): - self.check('sha3_256', bytes.fromhex( - "433C5303131624C0021D868A30825475E8D0BD3052A022180398F4CA4423B9"+ - "8214B6BEAAC21C8807A2C33F8C93BD42B092CC1B06CEDF3224D5ED1EC29784"+ - "444F22E08A55AA58542B524B02CD3D5D5F6907AFE71C5D7462224A3F9D9E53"+ - "E7E0846DCBB4CE"), - "CE87A5173BFFD92399221658F801D45C294D9006EE9F3F9D419C8D427748DC41") - - - def test_case_sha3_384_0(self): - self.check('sha3_384', b"", - "2C23146A63A29ACF99E73B88F8C24EAA7DC60AA771780CCC006AFBFA8FE2479B"+ - "2DD2B21362337441AC12B515911957FF") - - def test_case_sha3_384_1(self): - self.check('sha3_384', bytes.fromhex("CC"), - "1B84E62A46E5A201861754AF5DC95C4A1A69CAF4A796AE405680161E29572641"+ - "F5FA1E8641D7958336EE7B11C58F73E9") - - def test_case_sha3_384_2(self): - self.check('sha3_384', bytes.fromhex("41FB"), - "495CCE2714CD72C8C53C3363D22C58B55960FE26BE0BF3BBC7A3316DD563AD1D"+ - "B8410E75EEFEA655E39D4670EC0B1792") - - def test_case_sha3_384_3(self): - self.check('sha3_384', bytes.fromhex( - "433C5303131624C0021D868A30825475E8D0BD3052A022180398F4CA4423B9"+ - "8214B6BEAAC21C8807A2C33F8C93BD42B092CC1B06CEDF3224D5ED1EC29784"+ - "444F22E08A55AA58542B524B02CD3D5D5F6907AFE71C5D7462224A3F9D9E53"+ - "E7E0846DCBB4CE"), - "135114508DD63E279E709C26F7817C0482766CDE49132E3EDF2EEDD8996F4E35"+ - "96D184100B384868249F1D8B8FDAA2C9") - - - def test_case_sha3_512_0(self): - self.check('sha3_512', b"", - "0EAB42DE4C3CEB9235FC91ACFFE746B29C29A8C366B7C60E4E67C466F36A4304"+ - "C00FA9CAF9D87976BA469BCBE06713B435F091EF2769FB160CDAB33D3670680E") - - def test_case_sha3_512_1(self): - self.check('sha3_512', bytes.fromhex("CC"), - "8630C13CBD066EA74BBE7FE468FEC1DEE10EDC1254FB4C1B7C5FD69B646E4416"+ - "0B8CE01D05A0908CA790DFB080F4B513BC3B6225ECE7A810371441A5AC666EB9") - - def test_case_sha3_512_2(self): - self.check('sha3_512', bytes.fromhex("41FB"), - "551DA6236F8B96FCE9F97F1190E901324F0B45E06DBBB5CDB8355D6ED1DC34B3"+ - "F0EAE7DCB68622FF232FA3CECE0D4616CDEB3931F93803662A28DF1CD535B731") - - def test_case_sha3_512_3(self): - self.check('sha3_512', bytes.fromhex( - "433C5303131624C0021D868A30825475E8D0BD3052A022180398F4CA4423B9"+ - "8214B6BEAAC21C8807A2C33F8C93BD42B092CC1B06CEDF3224D5ED1EC29784"+ - "444F22E08A55AA58542B524B02CD3D5D5F6907AFE71C5D7462224A3F9D9E53"+ - "E7E0846DCBB4CE"), - "527D28E341E6B14F4684ADB4B824C496C6482E51149565D3D17226828884306B"+ - "51D6148A72622C2B75F5D3510B799D8BDC03EAEDE453676A6EC8FE03A1AD0EAB") - - def test_gil(self): # Check things work fine with an input larger than the size required # for multithreaded operation (which is hardwired to 2048). diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -501,7 +501,6 @@ : # remove 3rd party modules and system headers @lcov --remove $(COVERAGE_INFO) \ '*/Modules/_ctypes/libffi*/*' \ - '*/Modules/_sha3/keccak/*' \ '*/Modules/_decimal/libmpdec/*' \ '*/Modules/expat/*' \ '*/Modules/zlib/*' \ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -46,6 +46,8 @@ Library ------- +- Issue #16113: Remove sha3 module again. + - Issue #20111: pathlib.Path.with_suffix() now sanity checks the given suffix. - Fix breakage in TestSuite.countTestCases() introduced by issue #11798. diff --git a/Modules/_sha3/cleanup.py b/Modules/_sha3/cleanup.py deleted file mode 100755 --- a/Modules/_sha3/cleanup.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2012 Christian Heimes (christian at python.org) -# Licensed to PSF under a Contributor Agreement. -# -# cleanup Keccak sources - -import os -import re - -CPP1 = re.compile("^//(.*)") -CPP2 = re.compile("\ //(.*)") - -STATICS = ("void ", "int ", "HashReturn ", "const UINT64 ", "UINT16 ") - -HERE = os.path.dirname(os.path.abspath(__file__)) -KECCAK = os.path.join(HERE, "keccak") - -def getfiles(): - for name in os.listdir(KECCAK): - name = os.path.join(KECCAK, name) - if os.path.isfile(name): - yield name - -def cleanup(f): - buf = [] - for line in f: - # mark all functions and global data as static - if line.startswith(STATICS): - buf.append("static " + line) - continue - # remove UINT64 typedef, we have our own - if line.startswith("typedef unsigned long long int"): - buf.append("/* %s */\n" % line.strip()) - continue - # remove #include "brg_endian.h" - if "brg_endian.h" in line: - buf.append("/* %s */\n" % line.strip()) - continue - # transform C++ comments into ANSI C comments - line = CPP1.sub(r"/* \1 */", line) - line = CPP2.sub(r" /* \1 */", line) - buf.append(line) - return "".join(buf) - -for name in getfiles(): - with open(name) as f: - res = cleanup(f) - with open(name, "w") as f: - f.write(res) diff --git a/Modules/_sha3/keccak/KeccakF-1600-32-rvk.macros b/Modules/_sha3/keccak/KeccakF-1600-32-rvk.macros deleted file mode 100644 --- a/Modules/_sha3/keccak/KeccakF-1600-32-rvk.macros +++ /dev/null @@ -1,555 +0,0 @@ -/* -The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, -Micha?l Peeters and Gilles Van Assche. For more information, feedback or -questions, please refer to our website: http://keccak.noekeon.org/ - -Implementation by Ronny Van Keer, -hereby denoted as "the implementer". - -To the extent possible under law, the implementer has waived all copyright -and related or neighboring rights to the source code in this file. -http://creativecommons.org/publicdomain/zero/1.0/ -*/ - -static const UINT32 KeccakF1600RoundConstants_int2[2*24] = -{ - 0x00000001UL, 0x00000000UL, - 0x00000000UL, 0x00000089UL, - 0x00000000UL, 0x8000008bUL, - 0x00000000UL, 0x80008080UL, - 0x00000001UL, 0x0000008bUL, - 0x00000001UL, 0x00008000UL, - 0x00000001UL, 0x80008088UL, - 0x00000001UL, 0x80000082UL, - 0x00000000UL, 0x0000000bUL, - 0x00000000UL, 0x0000000aUL, - 0x00000001UL, 0x00008082UL, - 0x00000000UL, 0x00008003UL, - 0x00000001UL, 0x0000808bUL, - 0x00000001UL, 0x8000000bUL, - 0x00000001UL, 0x8000008aUL, - 0x00000001UL, 0x80000081UL, - 0x00000000UL, 0x80000081UL, - 0x00000000UL, 0x80000008UL, - 0x00000000UL, 0x00000083UL, - 0x00000000UL, 0x80008003UL, - 0x00000001UL, 0x80008088UL, - 0x00000000UL, 0x80000088UL, - 0x00000001UL, 0x00008000UL, - 0x00000000UL, 0x80008082UL -}; - -#undef rounds - -#define rounds \ -{ \ - UINT32 Da0, De0, Di0, Do0, Du0; \ - UINT32 Da1, De1, Di1, Do1, Du1; \ - UINT32 Ba, Be, Bi, Bo, Bu; \ - UINT32 Aba0, Abe0, Abi0, Abo0, Abu0; \ - UINT32 Aba1, Abe1, Abi1, Abo1, Abu1; \ - UINT32 Aga0, Age0, Agi0, Ago0, Agu0; \ - UINT32 Aga1, Age1, Agi1, Ago1, Agu1; \ - UINT32 Aka0, Ake0, Aki0, Ako0, Aku0; \ - UINT32 Aka1, Ake1, Aki1, Ako1, Aku1; \ - UINT32 Ama0, Ame0, Ami0, Amo0, Amu0; \ - UINT32 Ama1, Ame1, Ami1, Amo1, Amu1; \ - UINT32 Asa0, Ase0, Asi0, Aso0, Asu0; \ - UINT32 Asa1, Ase1, Asi1, Aso1, Asu1; \ - UINT32 Cw, Cx, Cy, Cz; \ - UINT32 Eba0, Ebe0, Ebi0, Ebo0, Ebu0; \ - UINT32 Eba1, Ebe1, Ebi1, Ebo1, Ebu1; \ - UINT32 Ega0, Ege0, Egi0, Ego0, Egu0; \ - UINT32 Ega1, Ege1, Egi1, Ego1, Egu1; \ - UINT32 Eka0, Eke0, Eki0, Eko0, Eku0; \ - UINT32 Eka1, Eke1, Eki1, Eko1, Eku1; \ - UINT32 Ema0, Eme0, Emi0, Emo0, Emu0; \ - UINT32 Ema1, Eme1, Emi1, Emo1, Emu1; \ - UINT32 Esa0, Ese0, Esi0, Eso0, Esu0; \ - UINT32 Esa1, Ese1, Esi1, Eso1, Esu1; \ - const UINT32 * pRoundConstants = KeccakF1600RoundConstants_int2; \ - UINT32 i; \ -\ - copyFromState(A, state) \ -\ - for( i = 12; i != 0; --i ) { \ - Cx = Abu0^Agu0^Aku0^Amu0^Asu0; \ - Du1 = Abe1^Age1^Ake1^Ame1^Ase1; \ - Da0 = Cx^ROL32(Du1, 1); \ - Cz = Abu1^Agu1^Aku1^Amu1^Asu1; \ - Du0 = Abe0^Age0^Ake0^Ame0^Ase0; \ - Da1 = Cz^Du0; \ -\ - Cw = Abi0^Agi0^Aki0^Ami0^Asi0; \ - Do0 = Cw^ROL32(Cz, 1); \ - Cy = Abi1^Agi1^Aki1^Ami1^Asi1; \ - Do1 = Cy^Cx; \ -\ - Cx = Aba0^Aga0^Aka0^Ama0^Asa0; \ - De0 = Cx^ROL32(Cy, 1); \ - Cz = Aba1^Aga1^Aka1^Ama1^Asa1; \ - De1 = Cz^Cw; \ -\ - Cy = Abo1^Ago1^Ako1^Amo1^Aso1; \ - Di0 = Du0^ROL32(Cy, 1); \ - Cw = Abo0^Ago0^Ako0^Amo0^Aso0; \ - Di1 = Du1^Cw; \ -\ - Du0 = Cw^ROL32(Cz, 1); \ - Du1 = Cy^Cx; \ -\ - Aba0 ^= Da0; \ - Ba = Aba0; \ - Age0 ^= De0; \ - Be = ROL32(Age0, 22); \ - Aki1 ^= Di1; \ - Bi = ROL32(Aki1, 22); \ - Amo1 ^= Do1; \ - Bo = ROL32(Amo1, 11); \ - Asu0 ^= Du0; \ - Bu = ROL32(Asu0, 7); \ - Eba0 = Ba ^((~Be)& Bi ) ^ *(pRoundConstants++); \ - Ebe0 = Be ^((~Bi)& Bo ); \ - Ebi0 = Bi ^((~Bo)& Bu ); \ - Ebo0 = Bo ^((~Bu)& Ba ); \ - Ebu0 = Bu ^((~Ba)& Be ); \ -\ - Abo0 ^= Do0; \ - Ba = ROL32(Abo0, 14); \ - Agu0 ^= Du0; \ - Be = ROL32(Agu0, 10); \ - Aka1 ^= Da1; \ - Bi = ROL32(Aka1, 2); \ - Ame1 ^= De1; \ - Bo = ROL32(Ame1, 23); \ - Asi1 ^= Di1; \ - Bu = ROL32(Asi1, 31); \ - Ega0 = Ba ^((~Be)& Bi ); \ - Ege0 = Be ^((~Bi)& Bo ); \ - Egi0 = Bi ^((~Bo)& Bu ); \ - Ego0 = Bo ^((~Bu)& Ba ); \ - Egu0 = Bu ^((~Ba)& Be ); \ -\ - Abe1 ^= De1; \ - Ba = ROL32(Abe1, 1); \ - Agi0 ^= Di0; \ - Be = ROL32(Agi0, 3); \ - Ako1 ^= Do1; \ - Bi = ROL32(Ako1, 13); \ - Amu0 ^= Du0; \ - Bo = ROL32(Amu0, 4); \ - Asa0 ^= Da0; \ - Bu = ROL32(Asa0, 9); \ - Eka0 = Ba ^((~Be)& Bi ); \ - Eke0 = Be ^((~Bi)& Bo ); \ - Eki0 = Bi ^((~Bo)& Bu ); \ - Eko0 = Bo ^((~Bu)& Ba ); \ - Eku0 = Bu ^((~Ba)& Be ); \ -\ - Abu1 ^= Du1; \ - Ba = ROL32(Abu1, 14); \ - Aga0 ^= Da0; \ - Be = ROL32(Aga0, 18); \ - Ake0 ^= De0; \ - Bi = ROL32(Ake0, 5); \ - Ami1 ^= Di1; \ - Bo = ROL32(Ami1, 8); \ - Aso0 ^= Do0; \ - Bu = ROL32(Aso0, 28); \ - Ema0 = Ba ^((~Be)& Bi ); \ - Eme0 = Be ^((~Bi)& Bo ); \ - Emi0 = Bi ^((~Bo)& Bu ); \ - Emo0 = Bo ^((~Bu)& Ba ); \ - Emu0 = Bu ^((~Ba)& Be ); \ -\ - Abi0 ^= Di0; \ - Ba = ROL32(Abi0, 31); \ - Ago1 ^= Do1; \ - Be = ROL32(Ago1, 28); \ - Aku1 ^= Du1; \ - Bi = ROL32(Aku1, 20); \ - Ama1 ^= Da1; \ - Bo = ROL32(Ama1, 21); \ - Ase0 ^= De0; \ - Bu = ROL32(Ase0, 1); \ - Esa0 = Ba ^((~Be)& Bi ); \ - Ese0 = Be ^((~Bi)& Bo ); \ - Esi0 = Bi ^((~Bo)& Bu ); \ - Eso0 = Bo ^((~Bu)& Ba ); \ - Esu0 = Bu ^((~Ba)& Be ); \ -\ - Aba1 ^= Da1; \ - Ba = Aba1; \ - Age1 ^= De1; \ - Be = ROL32(Age1, 22); \ - Aki0 ^= Di0; \ - Bi = ROL32(Aki0, 21); \ - Amo0 ^= Do0; \ - Bo = ROL32(Amo0, 10); \ - Asu1 ^= Du1; \ - Bu = ROL32(Asu1, 7); \ - Eba1 = Ba ^((~Be)& Bi ); \ - Eba1 ^= *(pRoundConstants++); \ - Ebe1 = Be ^((~Bi)& Bo ); \ - Ebi1 = Bi ^((~Bo)& Bu ); \ - Ebo1 = Bo ^((~Bu)& Ba ); \ - Ebu1 = Bu ^((~Ba)& Be ); \ -\ - Abo1 ^= Do1; \ - Ba = ROL32(Abo1, 14); \ - Agu1 ^= Du1; \ - Be = ROL32(Agu1, 10); \ - Aka0 ^= Da0; \ - Bi = ROL32(Aka0, 1); \ - Ame0 ^= De0; \ - Bo = ROL32(Ame0, 22); \ - Asi0 ^= Di0; \ - Bu = ROL32(Asi0, 30); \ - Ega1 = Ba ^((~Be)& Bi ); \ - Ege1 = Be ^((~Bi)& Bo ); \ - Egi1 = Bi ^((~Bo)& Bu ); \ - Ego1 = Bo ^((~Bu)& Ba ); \ - Egu1 = Bu ^((~Ba)& Be ); \ -\ - Abe0 ^= De0; \ - Ba = Abe0; \ - Agi1 ^= Di1; \ - Be = ROL32(Agi1, 3); \ - Ako0 ^= Do0; \ - Bi = ROL32(Ako0, 12); \ - Amu1 ^= Du1; \ - Bo = ROL32(Amu1, 4); \ - Asa1 ^= Da1; \ - Bu = ROL32(Asa1, 9); \ - Eka1 = Ba ^((~Be)& Bi ); \ - Eke1 = Be ^((~Bi)& Bo ); \ - Eki1 = Bi ^((~Bo)& Bu ); \ - Eko1 = Bo ^((~Bu)& Ba ); \ - Eku1 = Bu ^((~Ba)& Be ); \ -\ - Abu0 ^= Du0; \ - Ba = ROL32(Abu0, 13); \ - Aga1 ^= Da1; \ - Be = ROL32(Aga1, 18); \ - Ake1 ^= De1; \ - Bi = ROL32(Ake1, 5); \ - Ami0 ^= Di0; \ - Bo = ROL32(Ami0, 7); \ - Aso1 ^= Do1; \ - Bu = ROL32(Aso1, 28); \ - Ema1 = Ba ^((~Be)& Bi ); \ - Eme1 = Be ^((~Bi)& Bo ); \ - Emi1 = Bi ^((~Bo)& Bu ); \ - Emo1 = Bo ^((~Bu)& Ba ); \ - Emu1 = Bu ^((~Ba)& Be ); \ -\ - Abi1 ^= Di1; \ - Ba = ROL32(Abi1, 31); \ - Ago0 ^= Do0; \ - Be = ROL32(Ago0, 27); \ - Aku0 ^= Du0; \ - Bi = ROL32(Aku0, 19); \ - Ama0 ^= Da0; \ - Bo = ROL32(Ama0, 20); \ - Ase1 ^= De1; \ - Bu = ROL32(Ase1, 1); \ - Esa1 = Ba ^((~Be)& Bi ); \ - Ese1 = Be ^((~Bi)& Bo ); \ - Esi1 = Bi ^((~Bo)& Bu ); \ - Eso1 = Bo ^((~Bu)& Ba ); \ - Esu1 = Bu ^((~Ba)& Be ); \ -\ - Cx = Ebu0^Egu0^Eku0^Emu0^Esu0; \ - Du1 = Ebe1^Ege1^Eke1^Eme1^Ese1; \ - Da0 = Cx^ROL32(Du1, 1); \ - Cz = Ebu1^Egu1^Eku1^Emu1^Esu1; \ - Du0 = Ebe0^Ege0^Eke0^Eme0^Ese0; \ - Da1 = Cz^Du0; \ -\ - Cw = Ebi0^Egi0^Eki0^Emi0^Esi0; \ - Do0 = Cw^ROL32(Cz, 1); \ - Cy = Ebi1^Egi1^Eki1^Emi1^Esi1; \ - Do1 = Cy^Cx; \ -\ - Cx = Eba0^Ega0^Eka0^Ema0^Esa0; \ - De0 = Cx^ROL32(Cy, 1); \ - Cz = Eba1^Ega1^Eka1^Ema1^Esa1; \ - De1 = Cz^Cw; \ -\ - Cy = Ebo1^Ego1^Eko1^Emo1^Eso1; \ - Di0 = Du0^ROL32(Cy, 1); \ - Cw = Ebo0^Ego0^Eko0^Emo0^Eso0; \ - Di1 = Du1^Cw; \ -\ - Du0 = Cw^ROL32(Cz, 1); \ - Du1 = Cy^Cx; \ -\ - Eba0 ^= Da0; \ - Ba = Eba0; \ - Ege0 ^= De0; \ - Be = ROL32(Ege0, 22); \ - Eki1 ^= Di1; \ - Bi = ROL32(Eki1, 22); \ - Emo1 ^= Do1; \ - Bo = ROL32(Emo1, 11); \ - Esu0 ^= Du0; \ - Bu = ROL32(Esu0, 7); \ - Aba0 = Ba ^((~Be)& Bi ); \ - Aba0 ^= *(pRoundConstants++); \ - Abe0 = Be ^((~Bi)& Bo ); \ - Abi0 = Bi ^((~Bo)& Bu ); \ - Abo0 = Bo ^((~Bu)& Ba ); \ - Abu0 = Bu ^((~Ba)& Be ); \ -\ - Ebo0 ^= Do0; \ - Ba = ROL32(Ebo0, 14); \ - Egu0 ^= Du0; \ - Be = ROL32(Egu0, 10); \ - Eka1 ^= Da1; \ - Bi = ROL32(Eka1, 2); \ - Eme1 ^= De1; \ - Bo = ROL32(Eme1, 23); \ - Esi1 ^= Di1; \ - Bu = ROL32(Esi1, 31); \ - Aga0 = Ba ^((~Be)& Bi ); \ - Age0 = Be ^((~Bi)& Bo ); \ - Agi0 = Bi ^((~Bo)& Bu ); \ - Ago0 = Bo ^((~Bu)& Ba ); \ - Agu0 = Bu ^((~Ba)& Be ); \ -\ - Ebe1 ^= De1; \ - Ba = ROL32(Ebe1, 1); \ - Egi0 ^= Di0; \ - Be = ROL32(Egi0, 3); \ - Eko1 ^= Do1; \ - Bi = ROL32(Eko1, 13); \ - Emu0 ^= Du0; \ - Bo = ROL32(Emu0, 4); \ - Esa0 ^= Da0; \ - Bu = ROL32(Esa0, 9); \ - Aka0 = Ba ^((~Be)& Bi ); \ - Ake0 = Be ^((~Bi)& Bo ); \ - Aki0 = Bi ^((~Bo)& Bu ); \ - Ako0 = Bo ^((~Bu)& Ba ); \ - Aku0 = Bu ^((~Ba)& Be ); \ -\ - Ebu1 ^= Du1; \ - Ba = ROL32(Ebu1, 14); \ - Ega0 ^= Da0; \ - Be = ROL32(Ega0, 18); \ - Eke0 ^= De0; \ - Bi = ROL32(Eke0, 5); \ - Emi1 ^= Di1; \ - Bo = ROL32(Emi1, 8); \ - Eso0 ^= Do0; \ - Bu = ROL32(Eso0, 28); \ - Ama0 = Ba ^((~Be)& Bi ); \ - Ame0 = Be ^((~Bi)& Bo ); \ - Ami0 = Bi ^((~Bo)& Bu ); \ - Amo0 = Bo ^((~Bu)& Ba ); \ - Amu0 = Bu ^((~Ba)& Be ); \ -\ - Ebi0 ^= Di0; \ - Ba = ROL32(Ebi0, 31); \ - Ego1 ^= Do1; \ - Be = ROL32(Ego1, 28); \ - Eku1 ^= Du1; \ - Bi = ROL32(Eku1, 20); \ - Ema1 ^= Da1; \ - Bo = ROL32(Ema1, 21); \ - Ese0 ^= De0; \ - Bu = ROL32(Ese0, 1); \ - Asa0 = Ba ^((~Be)& Bi ); \ - Ase0 = Be ^((~Bi)& Bo ); \ - Asi0 = Bi ^((~Bo)& Bu ); \ - Aso0 = Bo ^((~Bu)& Ba ); \ - Asu0 = Bu ^((~Ba)& Be ); \ -\ - Eba1 ^= Da1; \ - Ba = Eba1; \ - Ege1 ^= De1; \ - Be = ROL32(Ege1, 22); \ - Eki0 ^= Di0; \ - Bi = ROL32(Eki0, 21); \ - Emo0 ^= Do0; \ - Bo = ROL32(Emo0, 10); \ - Esu1 ^= Du1; \ - Bu = ROL32(Esu1, 7); \ - Aba1 = Ba ^((~Be)& Bi ); \ - Aba1 ^= *(pRoundConstants++); \ - Abe1 = Be ^((~Bi)& Bo ); \ - Abi1 = Bi ^((~Bo)& Bu ); \ - Abo1 = Bo ^((~Bu)& Ba ); \ - Abu1 = Bu ^((~Ba)& Be ); \ -\ - Ebo1 ^= Do1; \ - Ba = ROL32(Ebo1, 14); \ - Egu1 ^= Du1; \ - Be = ROL32(Egu1, 10); \ - Eka0 ^= Da0; \ - Bi = ROL32(Eka0, 1); \ - Eme0 ^= De0; \ - Bo = ROL32(Eme0, 22); \ - Esi0 ^= Di0; \ - Bu = ROL32(Esi0, 30); \ - Aga1 = Ba ^((~Be)& Bi ); \ - Age1 = Be ^((~Bi)& Bo ); \ - Agi1 = Bi ^((~Bo)& Bu ); \ - Ago1 = Bo ^((~Bu)& Ba ); \ - Agu1 = Bu ^((~Ba)& Be ); \ -\ - Ebe0 ^= De0; \ - Ba = Ebe0; \ - Egi1 ^= Di1; \ - Be = ROL32(Egi1, 3); \ - Eko0 ^= Do0; \ - Bi = ROL32(Eko0, 12); \ - Emu1 ^= Du1; \ - Bo = ROL32(Emu1, 4); \ - Esa1 ^= Da1; \ - Bu = ROL32(Esa1, 9); \ - Aka1 = Ba ^((~Be)& Bi ); \ - Ake1 = Be ^((~Bi)& Bo ); \ - Aki1 = Bi ^((~Bo)& Bu ); \ - Ako1 = Bo ^((~Bu)& Ba ); \ - Aku1 = Bu ^((~Ba)& Be ); \ -\ - Ebu0 ^= Du0; \ - Ba = ROL32(Ebu0, 13); \ - Ega1 ^= Da1; \ - Be = ROL32(Ega1, 18); \ - Eke1 ^= De1; \ - Bi = ROL32(Eke1, 5); \ - Emi0 ^= Di0; \ - Bo = ROL32(Emi0, 7); \ - Eso1 ^= Do1; \ - Bu = ROL32(Eso1, 28); \ - Ama1 = Ba ^((~Be)& Bi ); \ - Ame1 = Be ^((~Bi)& Bo ); \ - Ami1 = Bi ^((~Bo)& Bu ); \ - Amo1 = Bo ^((~Bu)& Ba ); \ - Amu1 = Bu ^((~Ba)& Be ); \ -\ - Ebi1 ^= Di1; \ - Ba = ROL32(Ebi1, 31); \ - Ego0 ^= Do0; \ - Be = ROL32(Ego0, 27); \ - Eku0 ^= Du0; \ - Bi = ROL32(Eku0, 19); \ - Ema0 ^= Da0; \ - Bo = ROL32(Ema0, 20); \ - Ese1 ^= De1; \ - Bu = ROL32(Ese1, 1); \ - Asa1 = Ba ^((~Be)& Bi ); \ - Ase1 = Be ^((~Bi)& Bo ); \ - Asi1 = Bi ^((~Bo)& Bu ); \ - Aso1 = Bo ^((~Bu)& Ba ); \ - Asu1 = Bu ^((~Ba)& Be ); \ - } \ - copyToState(state, A) \ -} - -#define copyFromState(X, state) \ - X##ba0 = state[ 0]; \ - X##ba1 = state[ 1]; \ - X##be0 = state[ 2]; \ - X##be1 = state[ 3]; \ - X##bi0 = state[ 4]; \ - X##bi1 = state[ 5]; \ - X##bo0 = state[ 6]; \ - X##bo1 = state[ 7]; \ - X##bu0 = state[ 8]; \ - X##bu1 = state[ 9]; \ - X##ga0 = state[10]; \ - X##ga1 = state[11]; \ - X##ge0 = state[12]; \ - X##ge1 = state[13]; \ - X##gi0 = state[14]; \ - X##gi1 = state[15]; \ - X##go0 = state[16]; \ - X##go1 = state[17]; \ - X##gu0 = state[18]; \ - X##gu1 = state[19]; \ - X##ka0 = state[20]; \ - X##ka1 = state[21]; \ - X##ke0 = state[22]; \ - X##ke1 = state[23]; \ - X##ki0 = state[24]; \ - X##ki1 = state[25]; \ - X##ko0 = state[26]; \ - X##ko1 = state[27]; \ - X##ku0 = state[28]; \ - X##ku1 = state[29]; \ - X##ma0 = state[30]; \ - X##ma1 = state[31]; \ - X##me0 = state[32]; \ - X##me1 = state[33]; \ - X##mi0 = state[34]; \ - X##mi1 = state[35]; \ - X##mo0 = state[36]; \ - X##mo1 = state[37]; \ - X##mu0 = state[38]; \ - X##mu1 = state[39]; \ - X##sa0 = state[40]; \ - X##sa1 = state[41]; \ - X##se0 = state[42]; \ - X##se1 = state[43]; \ - X##si0 = state[44]; \ - X##si1 = state[45]; \ - X##so0 = state[46]; \ - X##so1 = state[47]; \ - X##su0 = state[48]; \ - X##su1 = state[49]; \ - -#define copyToState(state, X) \ - state[ 0] = X##ba0; \ - state[ 1] = X##ba1; \ - state[ 2] = X##be0; \ - state[ 3] = X##be1; \ - state[ 4] = X##bi0; \ - state[ 5] = X##bi1; \ - state[ 6] = X##bo0; \ - state[ 7] = X##bo1; \ - state[ 8] = X##bu0; \ - state[ 9] = X##bu1; \ - state[10] = X##ga0; \ - state[11] = X##ga1; \ - state[12] = X##ge0; \ - state[13] = X##ge1; \ - state[14] = X##gi0; \ - state[15] = X##gi1; \ - state[16] = X##go0; \ - state[17] = X##go1; \ - state[18] = X##gu0; \ - state[19] = X##gu1; \ - state[20] = X##ka0; \ - state[21] = X##ka1; \ - state[22] = X##ke0; \ - state[23] = X##ke1; \ - state[24] = X##ki0; \ - state[25] = X##ki1; \ - state[26] = X##ko0; \ - state[27] = X##ko1; \ - state[28] = X##ku0; \ - state[29] = X##ku1; \ - state[30] = X##ma0; \ - state[31] = X##ma1; \ - state[32] = X##me0; \ - state[33] = X##me1; \ - state[34] = X##mi0; \ - state[35] = X##mi1; \ - state[36] = X##mo0; \ - state[37] = X##mo1; \ - state[38] = X##mu0; \ - state[39] = X##mu1; \ - state[40] = X##sa0; \ - state[41] = X##sa1; \ - state[42] = X##se0; \ - state[43] = X##se1; \ - state[44] = X##si0; \ - state[45] = X##si1; \ - state[46] = X##so0; \ - state[47] = X##so1; \ - state[48] = X##su0; \ - state[49] = X##su1; \ - diff --git a/Modules/_sha3/keccak/KeccakF-1600-32-s1.macros b/Modules/_sha3/keccak/KeccakF-1600-32-s1.macros deleted file mode 100644 --- a/Modules/_sha3/keccak/KeccakF-1600-32-s1.macros +++ /dev/null @@ -1,1187 +0,0 @@ -/* -Code automatically generated by KeccakTools! - -The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, -Micha?l Peeters and Gilles Van Assche. For more information, feedback or -questions, please refer to our website: http://keccak.noekeon.org/ - -Implementation by the designers, -hereby denoted as "the implementer". - -To the extent possible under law, the implementer has waived all copyright -and related or neighboring rights to the source code in this file. -http://creativecommons.org/publicdomain/zero/1.0/ -*/ - -#define declareABCDE \ - UINT32 Aba0, Abe0, Abi0, Abo0, Abu0; \ - UINT32 Aba1, Abe1, Abi1, Abo1, Abu1; \ - UINT32 Aga0, Age0, Agi0, Ago0, Agu0; \ - UINT32 Aga1, Age1, Agi1, Ago1, Agu1; \ - UINT32 Aka0, Ake0, Aki0, Ako0, Aku0; \ - UINT32 Aka1, Ake1, Aki1, Ako1, Aku1; \ - UINT32 Ama0, Ame0, Ami0, Amo0, Amu0; \ - UINT32 Ama1, Ame1, Ami1, Amo1, Amu1; \ - UINT32 Asa0, Ase0, Asi0, Aso0, Asu0; \ - UINT32 Asa1, Ase1, Asi1, Aso1, Asu1; \ - UINT32 Bba0, Bbe0, Bbi0, Bbo0, Bbu0; \ - UINT32 Bba1, Bbe1, Bbi1, Bbo1, Bbu1; \ - UINT32 Bga0, Bge0, Bgi0, Bgo0, Bgu0; \ - UINT32 Bga1, Bge1, Bgi1, Bgo1, Bgu1; \ - UINT32 Bka0, Bke0, Bki0, Bko0, Bku0; \ - UINT32 Bka1, Bke1, Bki1, Bko1, Bku1; \ - UINT32 Bma0, Bme0, Bmi0, Bmo0, Bmu0; \ - UINT32 Bma1, Bme1, Bmi1, Bmo1, Bmu1; \ - UINT32 Bsa0, Bse0, Bsi0, Bso0, Bsu0; \ - UINT32 Bsa1, Bse1, Bsi1, Bso1, Bsu1; \ - UINT32 Ca0, Ce0, Ci0, Co0, Cu0; \ - UINT32 Ca1, Ce1, Ci1, Co1, Cu1; \ - UINT32 Da0, De0, Di0, Do0, Du0; \ - UINT32 Da1, De1, Di1, Do1, Du1; \ - UINT32 Eba0, Ebe0, Ebi0, Ebo0, Ebu0; \ - UINT32 Eba1, Ebe1, Ebi1, Ebo1, Ebu1; \ - UINT32 Ega0, Ege0, Egi0, Ego0, Egu0; \ - UINT32 Ega1, Ege1, Egi1, Ego1, Egu1; \ - UINT32 Eka0, Eke0, Eki0, Eko0, Eku0; \ - UINT32 Eka1, Eke1, Eki1, Eko1, Eku1; \ - UINT32 Ema0, Eme0, Emi0, Emo0, Emu0; \ - UINT32 Ema1, Eme1, Emi1, Emo1, Emu1; \ - UINT32 Esa0, Ese0, Esi0, Eso0, Esu0; \ - UINT32 Esa1, Ese1, Esi1, Eso1, Esu1; \ - -#define prepareTheta \ - Ca0 = Aba0^Aga0^Aka0^Ama0^Asa0; \ - Ca1 = Aba1^Aga1^Aka1^Ama1^Asa1; \ - Ce0 = Abe0^Age0^Ake0^Ame0^Ase0; \ - Ce1 = Abe1^Age1^Ake1^Ame1^Ase1; \ - Ci0 = Abi0^Agi0^Aki0^Ami0^Asi0; \ - Ci1 = Abi1^Agi1^Aki1^Ami1^Asi1; \ - Co0 = Abo0^Ago0^Ako0^Amo0^Aso0; \ - Co1 = Abo1^Ago1^Ako1^Amo1^Aso1; \ - Cu0 = Abu0^Agu0^Aku0^Amu0^Asu0; \ - Cu1 = Abu1^Agu1^Aku1^Amu1^Asu1; \ - -#ifdef UseBebigokimisa -/* --- Code for round, with prepare-theta (lane complementing pattern 'bebigokimisa') */ -/* --- using factor 2 interleaving, 64-bit lanes mapped to 32-bit words */ -#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ - Da0 = Cu0^ROL32(Ce1, 1); \ - Da1 = Cu1^Ce0; \ - De0 = Ca0^ROL32(Ci1, 1); \ - De1 = Ca1^Ci0; \ - Di0 = Ce0^ROL32(Co1, 1); \ - Di1 = Ce1^Co0; \ - Do0 = Ci0^ROL32(Cu1, 1); \ - Do1 = Ci1^Cu0; \ - Du0 = Co0^ROL32(Ca1, 1); \ - Du1 = Co1^Ca0; \ -\ - A##ba0 ^= Da0; \ - Bba0 = A##ba0; \ - A##ge0 ^= De0; \ - Bbe0 = ROL32(A##ge0, 22); \ - A##ki1 ^= Di1; \ - Bbi0 = ROL32(A##ki1, 22); \ - A##mo1 ^= Do1; \ - Bbo0 = ROL32(A##mo1, 11); \ - A##su0 ^= Du0; \ - Bbu0 = ROL32(A##su0, 7); \ - E##ba0 = Bba0 ^( Bbe0 | Bbi0 ); \ - E##ba0 ^= KeccakF1600RoundConstants_int2_0[i]; \ - Ca0 = E##ba0; \ - E##be0 = Bbe0 ^((~Bbi0)| Bbo0 ); \ - Ce0 = E##be0; \ - E##bi0 = Bbi0 ^( Bbo0 & Bbu0 ); \ - Ci0 = E##bi0; \ - E##bo0 = Bbo0 ^( Bbu0 | Bba0 ); \ - Co0 = E##bo0; \ - E##bu0 = Bbu0 ^( Bba0 & Bbe0 ); \ - Cu0 = E##bu0; \ -\ - A##ba1 ^= Da1; \ - Bba1 = A##ba1; \ - A##ge1 ^= De1; \ - Bbe1 = ROL32(A##ge1, 22); \ - A##ki0 ^= Di0; \ - Bbi1 = ROL32(A##ki0, 21); \ - A##mo0 ^= Do0; \ - Bbo1 = ROL32(A##mo0, 10); \ - A##su1 ^= Du1; \ - Bbu1 = ROL32(A##su1, 7); \ - E##ba1 = Bba1 ^( Bbe1 | Bbi1 ); \ - E##ba1 ^= KeccakF1600RoundConstants_int2_1[i]; \ - Ca1 = E##ba1; \ - E##be1 = Bbe1 ^((~Bbi1)| Bbo1 ); \ - Ce1 = E##be1; \ - E##bi1 = Bbi1 ^( Bbo1 & Bbu1 ); \ - Ci1 = E##bi1; \ - E##bo1 = Bbo1 ^( Bbu1 | Bba1 ); \ - Co1 = E##bo1; \ - E##bu1 = Bbu1 ^( Bba1 & Bbe1 ); \ - Cu1 = E##bu1; \ -\ - A##bo0 ^= Do0; \ - Bga0 = ROL32(A##bo0, 14); \ - A##gu0 ^= Du0; \ - Bge0 = ROL32(A##gu0, 10); \ - A##ka1 ^= Da1; \ - Bgi0 = ROL32(A##ka1, 2); \ - A##me1 ^= De1; \ - Bgo0 = ROL32(A##me1, 23); \ - A##si1 ^= Di1; \ - Bgu0 = ROL32(A##si1, 31); \ - E##ga0 = Bga0 ^( Bge0 | Bgi0 ); \ - Ca0 ^= E##ga0; \ - E##ge0 = Bge0 ^( Bgi0 & Bgo0 ); \ - Ce0 ^= E##ge0; \ - E##gi0 = Bgi0 ^( Bgo0 |(~Bgu0)); \ - Ci0 ^= E##gi0; \ - E##go0 = Bgo0 ^( Bgu0 | Bga0 ); \ - Co0 ^= E##go0; \ - E##gu0 = Bgu0 ^( Bga0 & Bge0 ); \ - Cu0 ^= E##gu0; \ -\ - A##bo1 ^= Do1; \ - Bga1 = ROL32(A##bo1, 14); \ - A##gu1 ^= Du1; \ - Bge1 = ROL32(A##gu1, 10); \ - A##ka0 ^= Da0; \ - Bgi1 = ROL32(A##ka0, 1); \ - A##me0 ^= De0; \ - Bgo1 = ROL32(A##me0, 22); \ - A##si0 ^= Di0; \ - Bgu1 = ROL32(A##si0, 30); \ - E##ga1 = Bga1 ^( Bge1 | Bgi1 ); \ - Ca1 ^= E##ga1; \ - E##ge1 = Bge1 ^( Bgi1 & Bgo1 ); \ - Ce1 ^= E##ge1; \ - E##gi1 = Bgi1 ^( Bgo1 |(~Bgu1)); \ - Ci1 ^= E##gi1; \ - E##go1 = Bgo1 ^( Bgu1 | Bga1 ); \ - Co1 ^= E##go1; \ - E##gu1 = Bgu1 ^( Bga1 & Bge1 ); \ - Cu1 ^= E##gu1; \ -\ - A##be1 ^= De1; \ - Bka0 = ROL32(A##be1, 1); \ - A##gi0 ^= Di0; \ - Bke0 = ROL32(A##gi0, 3); \ - A##ko1 ^= Do1; \ - Bki0 = ROL32(A##ko1, 13); \ - A##mu0 ^= Du0; \ - Bko0 = ROL32(A##mu0, 4); \ - A##sa0 ^= Da0; \ - Bku0 = ROL32(A##sa0, 9); \ - E##ka0 = Bka0 ^( Bke0 | Bki0 ); \ - Ca0 ^= E##ka0; \ - E##ke0 = Bke0 ^( Bki0 & Bko0 ); \ - Ce0 ^= E##ke0; \ - E##ki0 = Bki0 ^((~Bko0)& Bku0 ); \ - Ci0 ^= E##ki0; \ - E##ko0 = (~Bko0)^( Bku0 | Bka0 ); \ - Co0 ^= E##ko0; \ - E##ku0 = Bku0 ^( Bka0 & Bke0 ); \ - Cu0 ^= E##ku0; \ -\ - A##be0 ^= De0; \ - Bka1 = A##be0; \ - A##gi1 ^= Di1; \ - Bke1 = ROL32(A##gi1, 3); \ - A##ko0 ^= Do0; \ - Bki1 = ROL32(A##ko0, 12); \ - A##mu1 ^= Du1; \ - Bko1 = ROL32(A##mu1, 4); \ - A##sa1 ^= Da1; \ - Bku1 = ROL32(A##sa1, 9); \ - E##ka1 = Bka1 ^( Bke1 | Bki1 ); \ - Ca1 ^= E##ka1; \ - E##ke1 = Bke1 ^( Bki1 & Bko1 ); \ - Ce1 ^= E##ke1; \ - E##ki1 = Bki1 ^((~Bko1)& Bku1 ); \ - Ci1 ^= E##ki1; \ - E##ko1 = (~Bko1)^( Bku1 | Bka1 ); \ - Co1 ^= E##ko1; \ - E##ku1 = Bku1 ^( Bka1 & Bke1 ); \ - Cu1 ^= E##ku1; \ -\ - A##bu1 ^= Du1; \ - Bma0 = ROL32(A##bu1, 14); \ - A##ga0 ^= Da0; \ - Bme0 = ROL32(A##ga0, 18); \ - A##ke0 ^= De0; \ - Bmi0 = ROL32(A##ke0, 5); \ - A##mi1 ^= Di1; \ - Bmo0 = ROL32(A##mi1, 8); \ - A##so0 ^= Do0; \ - Bmu0 = ROL32(A##so0, 28); \ - E##ma0 = Bma0 ^( Bme0 & Bmi0 ); \ - Ca0 ^= E##ma0; \ - E##me0 = Bme0 ^( Bmi0 | Bmo0 ); \ - Ce0 ^= E##me0; \ - E##mi0 = Bmi0 ^((~Bmo0)| Bmu0 ); \ - Ci0 ^= E##mi0; \ - E##mo0 = (~Bmo0)^( Bmu0 & Bma0 ); \ - Co0 ^= E##mo0; \ - E##mu0 = Bmu0 ^( Bma0 | Bme0 ); \ - Cu0 ^= E##mu0; \ -\ - A##bu0 ^= Du0; \ - Bma1 = ROL32(A##bu0, 13); \ - A##ga1 ^= Da1; \ - Bme1 = ROL32(A##ga1, 18); \ - A##ke1 ^= De1; \ - Bmi1 = ROL32(A##ke1, 5); \ - A##mi0 ^= Di0; \ - Bmo1 = ROL32(A##mi0, 7); \ - A##so1 ^= Do1; \ - Bmu1 = ROL32(A##so1, 28); \ - E##ma1 = Bma1 ^( Bme1 & Bmi1 ); \ - Ca1 ^= E##ma1; \ - E##me1 = Bme1 ^( Bmi1 | Bmo1 ); \ - Ce1 ^= E##me1; \ - E##mi1 = Bmi1 ^((~Bmo1)| Bmu1 ); \ - Ci1 ^= E##mi1; \ - E##mo1 = (~Bmo1)^( Bmu1 & Bma1 ); \ - Co1 ^= E##mo1; \ - E##mu1 = Bmu1 ^( Bma1 | Bme1 ); \ - Cu1 ^= E##mu1; \ -\ - A##bi0 ^= Di0; \ - Bsa0 = ROL32(A##bi0, 31); \ - A##go1 ^= Do1; \ - Bse0 = ROL32(A##go1, 28); \ - A##ku1 ^= Du1; \ - Bsi0 = ROL32(A##ku1, 20); \ - A##ma1 ^= Da1; \ - Bso0 = ROL32(A##ma1, 21); \ - A##se0 ^= De0; \ - Bsu0 = ROL32(A##se0, 1); \ - E##sa0 = Bsa0 ^((~Bse0)& Bsi0 ); \ - Ca0 ^= E##sa0; \ - E##se0 = (~Bse0)^( Bsi0 | Bso0 ); \ - Ce0 ^= E##se0; \ - E##si0 = Bsi0 ^( Bso0 & Bsu0 ); \ - Ci0 ^= E##si0; \ - E##so0 = Bso0 ^( Bsu0 | Bsa0 ); \ - Co0 ^= E##so0; \ - E##su0 = Bsu0 ^( Bsa0 & Bse0 ); \ - Cu0 ^= E##su0; \ -\ - A##bi1 ^= Di1; \ - Bsa1 = ROL32(A##bi1, 31); \ - A##go0 ^= Do0; \ - Bse1 = ROL32(A##go0, 27); \ - A##ku0 ^= Du0; \ - Bsi1 = ROL32(A##ku0, 19); \ - A##ma0 ^= Da0; \ - Bso1 = ROL32(A##ma0, 20); \ - A##se1 ^= De1; \ - Bsu1 = ROL32(A##se1, 1); \ - E##sa1 = Bsa1 ^((~Bse1)& Bsi1 ); \ - Ca1 ^= E##sa1; \ - E##se1 = (~Bse1)^( Bsi1 | Bso1 ); \ - Ce1 ^= E##se1; \ - E##si1 = Bsi1 ^( Bso1 & Bsu1 ); \ - Ci1 ^= E##si1; \ - E##so1 = Bso1 ^( Bsu1 | Bsa1 ); \ - Co1 ^= E##so1; \ - E##su1 = Bsu1 ^( Bsa1 & Bse1 ); \ - Cu1 ^= E##su1; \ -\ - -/* --- Code for round (lane complementing pattern 'bebigokimisa') */ -/* --- using factor 2 interleaving, 64-bit lanes mapped to 32-bit words */ -#define thetaRhoPiChiIota(i, A, E) \ - Da0 = Cu0^ROL32(Ce1, 1); \ - Da1 = Cu1^Ce0; \ - De0 = Ca0^ROL32(Ci1, 1); \ - De1 = Ca1^Ci0; \ - Di0 = Ce0^ROL32(Co1, 1); \ - Di1 = Ce1^Co0; \ - Do0 = Ci0^ROL32(Cu1, 1); \ - Do1 = Ci1^Cu0; \ - Du0 = Co0^ROL32(Ca1, 1); \ - Du1 = Co1^Ca0; \ -\ - A##ba0 ^= Da0; \ - Bba0 = A##ba0; \ - A##ge0 ^= De0; \ - Bbe0 = ROL32(A##ge0, 22); \ - A##ki1 ^= Di1; \ - Bbi0 = ROL32(A##ki1, 22); \ - A##mo1 ^= Do1; \ - Bbo0 = ROL32(A##mo1, 11); \ - A##su0 ^= Du0; \ - Bbu0 = ROL32(A##su0, 7); \ - E##ba0 = Bba0 ^( Bbe0 | Bbi0 ); \ - E##ba0 ^= KeccakF1600RoundConstants_int2_0[i]; \ - E##be0 = Bbe0 ^((~Bbi0)| Bbo0 ); \ - E##bi0 = Bbi0 ^( Bbo0 & Bbu0 ); \ - E##bo0 = Bbo0 ^( Bbu0 | Bba0 ); \ - E##bu0 = Bbu0 ^( Bba0 & Bbe0 ); \ -\ - A##ba1 ^= Da1; \ - Bba1 = A##ba1; \ - A##ge1 ^= De1; \ - Bbe1 = ROL32(A##ge1, 22); \ - A##ki0 ^= Di0; \ - Bbi1 = ROL32(A##ki0, 21); \ - A##mo0 ^= Do0; \ - Bbo1 = ROL32(A##mo0, 10); \ - A##su1 ^= Du1; \ - Bbu1 = ROL32(A##su1, 7); \ - E##ba1 = Bba1 ^( Bbe1 | Bbi1 ); \ - E##ba1 ^= KeccakF1600RoundConstants_int2_1[i]; \ - E##be1 = Bbe1 ^((~Bbi1)| Bbo1 ); \ - E##bi1 = Bbi1 ^( Bbo1 & Bbu1 ); \ - E##bo1 = Bbo1 ^( Bbu1 | Bba1 ); \ - E##bu1 = Bbu1 ^( Bba1 & Bbe1 ); \ -\ - A##bo0 ^= Do0; \ - Bga0 = ROL32(A##bo0, 14); \ - A##gu0 ^= Du0; \ - Bge0 = ROL32(A##gu0, 10); \ - A##ka1 ^= Da1; \ - Bgi0 = ROL32(A##ka1, 2); \ - A##me1 ^= De1; \ - Bgo0 = ROL32(A##me1, 23); \ - A##si1 ^= Di1; \ - Bgu0 = ROL32(A##si1, 31); \ - E##ga0 = Bga0 ^( Bge0 | Bgi0 ); \ - E##ge0 = Bge0 ^( Bgi0 & Bgo0 ); \ - E##gi0 = Bgi0 ^( Bgo0 |(~Bgu0)); \ - E##go0 = Bgo0 ^( Bgu0 | Bga0 ); \ - E##gu0 = Bgu0 ^( Bga0 & Bge0 ); \ -\ - A##bo1 ^= Do1; \ - Bga1 = ROL32(A##bo1, 14); \ - A##gu1 ^= Du1; \ - Bge1 = ROL32(A##gu1, 10); \ - A##ka0 ^= Da0; \ - Bgi1 = ROL32(A##ka0, 1); \ - A##me0 ^= De0; \ - Bgo1 = ROL32(A##me0, 22); \ - A##si0 ^= Di0; \ - Bgu1 = ROL32(A##si0, 30); \ - E##ga1 = Bga1 ^( Bge1 | Bgi1 ); \ - E##ge1 = Bge1 ^( Bgi1 & Bgo1 ); \ - E##gi1 = Bgi1 ^( Bgo1 |(~Bgu1)); \ - E##go1 = Bgo1 ^( Bgu1 | Bga1 ); \ - E##gu1 = Bgu1 ^( Bga1 & Bge1 ); \ -\ - A##be1 ^= De1; \ - Bka0 = ROL32(A##be1, 1); \ - A##gi0 ^= Di0; \ - Bke0 = ROL32(A##gi0, 3); \ - A##ko1 ^= Do1; \ - Bki0 = ROL32(A##ko1, 13); \ - A##mu0 ^= Du0; \ - Bko0 = ROL32(A##mu0, 4); \ - A##sa0 ^= Da0; \ - Bku0 = ROL32(A##sa0, 9); \ - E##ka0 = Bka0 ^( Bke0 | Bki0 ); \ - E##ke0 = Bke0 ^( Bki0 & Bko0 ); \ - E##ki0 = Bki0 ^((~Bko0)& Bku0 ); \ - E##ko0 = (~Bko0)^( Bku0 | Bka0 ); \ - E##ku0 = Bku0 ^( Bka0 & Bke0 ); \ -\ - A##be0 ^= De0; \ - Bka1 = A##be0; \ - A##gi1 ^= Di1; \ - Bke1 = ROL32(A##gi1, 3); \ - A##ko0 ^= Do0; \ - Bki1 = ROL32(A##ko0, 12); \ - A##mu1 ^= Du1; \ - Bko1 = ROL32(A##mu1, 4); \ - A##sa1 ^= Da1; \ - Bku1 = ROL32(A##sa1, 9); \ - E##ka1 = Bka1 ^( Bke1 | Bki1 ); \ - E##ke1 = Bke1 ^( Bki1 & Bko1 ); \ - E##ki1 = Bki1 ^((~Bko1)& Bku1 ); \ - E##ko1 = (~Bko1)^( Bku1 | Bka1 ); \ - E##ku1 = Bku1 ^( Bka1 & Bke1 ); \ -\ - A##bu1 ^= Du1; \ - Bma0 = ROL32(A##bu1, 14); \ - A##ga0 ^= Da0; \ - Bme0 = ROL32(A##ga0, 18); \ - A##ke0 ^= De0; \ - Bmi0 = ROL32(A##ke0, 5); \ - A##mi1 ^= Di1; \ - Bmo0 = ROL32(A##mi1, 8); \ - A##so0 ^= Do0; \ - Bmu0 = ROL32(A##so0, 28); \ - E##ma0 = Bma0 ^( Bme0 & Bmi0 ); \ - E##me0 = Bme0 ^( Bmi0 | Bmo0 ); \ - E##mi0 = Bmi0 ^((~Bmo0)| Bmu0 ); \ - E##mo0 = (~Bmo0)^( Bmu0 & Bma0 ); \ - E##mu0 = Bmu0 ^( Bma0 | Bme0 ); \ -\ - A##bu0 ^= Du0; \ - Bma1 = ROL32(A##bu0, 13); \ - A##ga1 ^= Da1; \ - Bme1 = ROL32(A##ga1, 18); \ - A##ke1 ^= De1; \ - Bmi1 = ROL32(A##ke1, 5); \ - A##mi0 ^= Di0; \ - Bmo1 = ROL32(A##mi0, 7); \ - A##so1 ^= Do1; \ - Bmu1 = ROL32(A##so1, 28); \ - E##ma1 = Bma1 ^( Bme1 & Bmi1 ); \ - E##me1 = Bme1 ^( Bmi1 | Bmo1 ); \ - E##mi1 = Bmi1 ^((~Bmo1)| Bmu1 ); \ - E##mo1 = (~Bmo1)^( Bmu1 & Bma1 ); \ - E##mu1 = Bmu1 ^( Bma1 | Bme1 ); \ -\ - A##bi0 ^= Di0; \ - Bsa0 = ROL32(A##bi0, 31); \ - A##go1 ^= Do1; \ - Bse0 = ROL32(A##go1, 28); \ - A##ku1 ^= Du1; \ - Bsi0 = ROL32(A##ku1, 20); \ - A##ma1 ^= Da1; \ - Bso0 = ROL32(A##ma1, 21); \ - A##se0 ^= De0; \ - Bsu0 = ROL32(A##se0, 1); \ - E##sa0 = Bsa0 ^((~Bse0)& Bsi0 ); \ - E##se0 = (~Bse0)^( Bsi0 | Bso0 ); \ - E##si0 = Bsi0 ^( Bso0 & Bsu0 ); \ - E##so0 = Bso0 ^( Bsu0 | Bsa0 ); \ - E##su0 = Bsu0 ^( Bsa0 & Bse0 ); \ -\ - A##bi1 ^= Di1; \ - Bsa1 = ROL32(A##bi1, 31); \ - A##go0 ^= Do0; \ - Bse1 = ROL32(A##go0, 27); \ - A##ku0 ^= Du0; \ - Bsi1 = ROL32(A##ku0, 19); \ - A##ma0 ^= Da0; \ - Bso1 = ROL32(A##ma0, 20); \ - A##se1 ^= De1; \ - Bsu1 = ROL32(A##se1, 1); \ - E##sa1 = Bsa1 ^((~Bse1)& Bsi1 ); \ - E##se1 = (~Bse1)^( Bsi1 | Bso1 ); \ - E##si1 = Bsi1 ^( Bso1 & Bsu1 ); \ - E##so1 = Bso1 ^( Bsu1 | Bsa1 ); \ - E##su1 = Bsu1 ^( Bsa1 & Bse1 ); \ -\ - -#else /* UseBebigokimisa */ -/* --- Code for round, with prepare-theta */ -/* --- using factor 2 interleaving, 64-bit lanes mapped to 32-bit words */ -#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ - Da0 = Cu0^ROL32(Ce1, 1); \ - Da1 = Cu1^Ce0; \ - De0 = Ca0^ROL32(Ci1, 1); \ - De1 = Ca1^Ci0; \ - Di0 = Ce0^ROL32(Co1, 1); \ - Di1 = Ce1^Co0; \ - Do0 = Ci0^ROL32(Cu1, 1); \ - Do1 = Ci1^Cu0; \ - Du0 = Co0^ROL32(Ca1, 1); \ - Du1 = Co1^Ca0; \ -\ - A##ba0 ^= Da0; \ - Bba0 = A##ba0; \ - A##ge0 ^= De0; \ - Bbe0 = ROL32(A##ge0, 22); \ - A##ki1 ^= Di1; \ - Bbi0 = ROL32(A##ki1, 22); \ - A##mo1 ^= Do1; \ - Bbo0 = ROL32(A##mo1, 11); \ - A##su0 ^= Du0; \ - Bbu0 = ROL32(A##su0, 7); \ - E##ba0 = Bba0 ^((~Bbe0)& Bbi0 ); \ - E##ba0 ^= KeccakF1600RoundConstants_int2_0[i]; \ - Ca0 = E##ba0; \ - E##be0 = Bbe0 ^((~Bbi0)& Bbo0 ); \ - Ce0 = E##be0; \ - E##bi0 = Bbi0 ^((~Bbo0)& Bbu0 ); \ - Ci0 = E##bi0; \ - E##bo0 = Bbo0 ^((~Bbu0)& Bba0 ); \ - Co0 = E##bo0; \ - E##bu0 = Bbu0 ^((~Bba0)& Bbe0 ); \ - Cu0 = E##bu0; \ -\ - A##ba1 ^= Da1; \ - Bba1 = A##ba1; \ - A##ge1 ^= De1; \ - Bbe1 = ROL32(A##ge1, 22); \ - A##ki0 ^= Di0; \ - Bbi1 = ROL32(A##ki0, 21); \ - A##mo0 ^= Do0; \ - Bbo1 = ROL32(A##mo0, 10); \ - A##su1 ^= Du1; \ - Bbu1 = ROL32(A##su1, 7); \ - E##ba1 = Bba1 ^((~Bbe1)& Bbi1 ); \ - E##ba1 ^= KeccakF1600RoundConstants_int2_1[i]; \ - Ca1 = E##ba1; \ - E##be1 = Bbe1 ^((~Bbi1)& Bbo1 ); \ - Ce1 = E##be1; \ - E##bi1 = Bbi1 ^((~Bbo1)& Bbu1 ); \ - Ci1 = E##bi1; \ - E##bo1 = Bbo1 ^((~Bbu1)& Bba1 ); \ - Co1 = E##bo1; \ - E##bu1 = Bbu1 ^((~Bba1)& Bbe1 ); \ - Cu1 = E##bu1; \ -\ - A##bo0 ^= Do0; \ - Bga0 = ROL32(A##bo0, 14); \ - A##gu0 ^= Du0; \ - Bge0 = ROL32(A##gu0, 10); \ - A##ka1 ^= Da1; \ - Bgi0 = ROL32(A##ka1, 2); \ - A##me1 ^= De1; \ - Bgo0 = ROL32(A##me1, 23); \ - A##si1 ^= Di1; \ - Bgu0 = ROL32(A##si1, 31); \ - E##ga0 = Bga0 ^((~Bge0)& Bgi0 ); \ - Ca0 ^= E##ga0; \ - E##ge0 = Bge0 ^((~Bgi0)& Bgo0 ); \ - Ce0 ^= E##ge0; \ - E##gi0 = Bgi0 ^((~Bgo0)& Bgu0 ); \ - Ci0 ^= E##gi0; \ - E##go0 = Bgo0 ^((~Bgu0)& Bga0 ); \ - Co0 ^= E##go0; \ - E##gu0 = Bgu0 ^((~Bga0)& Bge0 ); \ - Cu0 ^= E##gu0; \ -\ - A##bo1 ^= Do1; \ - Bga1 = ROL32(A##bo1, 14); \ - A##gu1 ^= Du1; \ - Bge1 = ROL32(A##gu1, 10); \ - A##ka0 ^= Da0; \ - Bgi1 = ROL32(A##ka0, 1); \ - A##me0 ^= De0; \ - Bgo1 = ROL32(A##me0, 22); \ - A##si0 ^= Di0; \ - Bgu1 = ROL32(A##si0, 30); \ - E##ga1 = Bga1 ^((~Bge1)& Bgi1 ); \ - Ca1 ^= E##ga1; \ - E##ge1 = Bge1 ^((~Bgi1)& Bgo1 ); \ - Ce1 ^= E##ge1; \ - E##gi1 = Bgi1 ^((~Bgo1)& Bgu1 ); \ - Ci1 ^= E##gi1; \ - E##go1 = Bgo1 ^((~Bgu1)& Bga1 ); \ - Co1 ^= E##go1; \ - E##gu1 = Bgu1 ^((~Bga1)& Bge1 ); \ - Cu1 ^= E##gu1; \ -\ - A##be1 ^= De1; \ - Bka0 = ROL32(A##be1, 1); \ - A##gi0 ^= Di0; \ - Bke0 = ROL32(A##gi0, 3); \ - A##ko1 ^= Do1; \ - Bki0 = ROL32(A##ko1, 13); \ - A##mu0 ^= Du0; \ - Bko0 = ROL32(A##mu0, 4); \ - A##sa0 ^= Da0; \ - Bku0 = ROL32(A##sa0, 9); \ - E##ka0 = Bka0 ^((~Bke0)& Bki0 ); \ - Ca0 ^= E##ka0; \ - E##ke0 = Bke0 ^((~Bki0)& Bko0 ); \ - Ce0 ^= E##ke0; \ - E##ki0 = Bki0 ^((~Bko0)& Bku0 ); \ - Ci0 ^= E##ki0; \ - E##ko0 = Bko0 ^((~Bku0)& Bka0 ); \ - Co0 ^= E##ko0; \ - E##ku0 = Bku0 ^((~Bka0)& Bke0 ); \ - Cu0 ^= E##ku0; \ -\ - A##be0 ^= De0; \ - Bka1 = A##be0; \ - A##gi1 ^= Di1; \ - Bke1 = ROL32(A##gi1, 3); \ - A##ko0 ^= Do0; \ - Bki1 = ROL32(A##ko0, 12); \ - A##mu1 ^= Du1; \ - Bko1 = ROL32(A##mu1, 4); \ - A##sa1 ^= Da1; \ - Bku1 = ROL32(A##sa1, 9); \ - E##ka1 = Bka1 ^((~Bke1)& Bki1 ); \ - Ca1 ^= E##ka1; \ - E##ke1 = Bke1 ^((~Bki1)& Bko1 ); \ - Ce1 ^= E##ke1; \ - E##ki1 = Bki1 ^((~Bko1)& Bku1 ); \ - Ci1 ^= E##ki1; \ - E##ko1 = Bko1 ^((~Bku1)& Bka1 ); \ - Co1 ^= E##ko1; \ - E##ku1 = Bku1 ^((~Bka1)& Bke1 ); \ - Cu1 ^= E##ku1; \ -\ - A##bu1 ^= Du1; \ - Bma0 = ROL32(A##bu1, 14); \ - A##ga0 ^= Da0; \ - Bme0 = ROL32(A##ga0, 18); \ - A##ke0 ^= De0; \ - Bmi0 = ROL32(A##ke0, 5); \ - A##mi1 ^= Di1; \ - Bmo0 = ROL32(A##mi1, 8); \ - A##so0 ^= Do0; \ - Bmu0 = ROL32(A##so0, 28); \ - E##ma0 = Bma0 ^((~Bme0)& Bmi0 ); \ - Ca0 ^= E##ma0; \ - E##me0 = Bme0 ^((~Bmi0)& Bmo0 ); \ - Ce0 ^= E##me0; \ - E##mi0 = Bmi0 ^((~Bmo0)& Bmu0 ); \ - Ci0 ^= E##mi0; \ - E##mo0 = Bmo0 ^((~Bmu0)& Bma0 ); \ - Co0 ^= E##mo0; \ - E##mu0 = Bmu0 ^((~Bma0)& Bme0 ); \ - Cu0 ^= E##mu0; \ -\ - A##bu0 ^= Du0; \ - Bma1 = ROL32(A##bu0, 13); \ - A##ga1 ^= Da1; \ - Bme1 = ROL32(A##ga1, 18); \ - A##ke1 ^= De1; \ - Bmi1 = ROL32(A##ke1, 5); \ - A##mi0 ^= Di0; \ - Bmo1 = ROL32(A##mi0, 7); \ - A##so1 ^= Do1; \ - Bmu1 = ROL32(A##so1, 28); \ - E##ma1 = Bma1 ^((~Bme1)& Bmi1 ); \ - Ca1 ^= E##ma1; \ - E##me1 = Bme1 ^((~Bmi1)& Bmo1 ); \ - Ce1 ^= E##me1; \ - E##mi1 = Bmi1 ^((~Bmo1)& Bmu1 ); \ - Ci1 ^= E##mi1; \ - E##mo1 = Bmo1 ^((~Bmu1)& Bma1 ); \ - Co1 ^= E##mo1; \ - E##mu1 = Bmu1 ^((~Bma1)& Bme1 ); \ - Cu1 ^= E##mu1; \ -\ - A##bi0 ^= Di0; \ - Bsa0 = ROL32(A##bi0, 31); \ - A##go1 ^= Do1; \ - Bse0 = ROL32(A##go1, 28); \ - A##ku1 ^= Du1; \ - Bsi0 = ROL32(A##ku1, 20); \ - A##ma1 ^= Da1; \ - Bso0 = ROL32(A##ma1, 21); \ - A##se0 ^= De0; \ - Bsu0 = ROL32(A##se0, 1); \ - E##sa0 = Bsa0 ^((~Bse0)& Bsi0 ); \ - Ca0 ^= E##sa0; \ - E##se0 = Bse0 ^((~Bsi0)& Bso0 ); \ - Ce0 ^= E##se0; \ - E##si0 = Bsi0 ^((~Bso0)& Bsu0 ); \ - Ci0 ^= E##si0; \ - E##so0 = Bso0 ^((~Bsu0)& Bsa0 ); \ - Co0 ^= E##so0; \ - E##su0 = Bsu0 ^((~Bsa0)& Bse0 ); \ - Cu0 ^= E##su0; \ -\ - A##bi1 ^= Di1; \ - Bsa1 = ROL32(A##bi1, 31); \ - A##go0 ^= Do0; \ - Bse1 = ROL32(A##go0, 27); \ - A##ku0 ^= Du0; \ - Bsi1 = ROL32(A##ku0, 19); \ - A##ma0 ^= Da0; \ - Bso1 = ROL32(A##ma0, 20); \ - A##se1 ^= De1; \ - Bsu1 = ROL32(A##se1, 1); \ - E##sa1 = Bsa1 ^((~Bse1)& Bsi1 ); \ - Ca1 ^= E##sa1; \ - E##se1 = Bse1 ^((~Bsi1)& Bso1 ); \ - Ce1 ^= E##se1; \ - E##si1 = Bsi1 ^((~Bso1)& Bsu1 ); \ - Ci1 ^= E##si1; \ - E##so1 = Bso1 ^((~Bsu1)& Bsa1 ); \ - Co1 ^= E##so1; \ - E##su1 = Bsu1 ^((~Bsa1)& Bse1 ); \ - Cu1 ^= E##su1; \ -\ - -/* --- Code for round */ -/* --- using factor 2 interleaving, 64-bit lanes mapped to 32-bit words */ -#define thetaRhoPiChiIota(i, A, E) \ - Da0 = Cu0^ROL32(Ce1, 1); \ - Da1 = Cu1^Ce0; \ - De0 = Ca0^ROL32(Ci1, 1); \ - De1 = Ca1^Ci0; \ - Di0 = Ce0^ROL32(Co1, 1); \ - Di1 = Ce1^Co0; \ - Do0 = Ci0^ROL32(Cu1, 1); \ - Do1 = Ci1^Cu0; \ - Du0 = Co0^ROL32(Ca1, 1); \ - Du1 = Co1^Ca0; \ -\ - A##ba0 ^= Da0; \ - Bba0 = A##ba0; \ - A##ge0 ^= De0; \ - Bbe0 = ROL32(A##ge0, 22); \ - A##ki1 ^= Di1; \ - Bbi0 = ROL32(A##ki1, 22); \ - A##mo1 ^= Do1; \ - Bbo0 = ROL32(A##mo1, 11); \ - A##su0 ^= Du0; \ - Bbu0 = ROL32(A##su0, 7); \ - E##ba0 = Bba0 ^((~Bbe0)& Bbi0 ); \ - E##ba0 ^= KeccakF1600RoundConstants_int2_0[i]; \ - E##be0 = Bbe0 ^((~Bbi0)& Bbo0 ); \ - E##bi0 = Bbi0 ^((~Bbo0)& Bbu0 ); \ - E##bo0 = Bbo0 ^((~Bbu0)& Bba0 ); \ - E##bu0 = Bbu0 ^((~Bba0)& Bbe0 ); \ -\ - A##ba1 ^= Da1; \ - Bba1 = A##ba1; \ - A##ge1 ^= De1; \ - Bbe1 = ROL32(A##ge1, 22); \ - A##ki0 ^= Di0; \ - Bbi1 = ROL32(A##ki0, 21); \ - A##mo0 ^= Do0; \ - Bbo1 = ROL32(A##mo0, 10); \ - A##su1 ^= Du1; \ - Bbu1 = ROL32(A##su1, 7); \ - E##ba1 = Bba1 ^((~Bbe1)& Bbi1 ); \ - E##ba1 ^= KeccakF1600RoundConstants_int2_1[i]; \ - E##be1 = Bbe1 ^((~Bbi1)& Bbo1 ); \ - E##bi1 = Bbi1 ^((~Bbo1)& Bbu1 ); \ - E##bo1 = Bbo1 ^((~Bbu1)& Bba1 ); \ - E##bu1 = Bbu1 ^((~Bba1)& Bbe1 ); \ -\ - A##bo0 ^= Do0; \ - Bga0 = ROL32(A##bo0, 14); \ - A##gu0 ^= Du0; \ - Bge0 = ROL32(A##gu0, 10); \ - A##ka1 ^= Da1; \ - Bgi0 = ROL32(A##ka1, 2); \ - A##me1 ^= De1; \ - Bgo0 = ROL32(A##me1, 23); \ - A##si1 ^= Di1; \ - Bgu0 = ROL32(A##si1, 31); \ - E##ga0 = Bga0 ^((~Bge0)& Bgi0 ); \ - E##ge0 = Bge0 ^((~Bgi0)& Bgo0 ); \ - E##gi0 = Bgi0 ^((~Bgo0)& Bgu0 ); \ - E##go0 = Bgo0 ^((~Bgu0)& Bga0 ); \ - E##gu0 = Bgu0 ^((~Bga0)& Bge0 ); \ -\ - A##bo1 ^= Do1; \ - Bga1 = ROL32(A##bo1, 14); \ - A##gu1 ^= Du1; \ - Bge1 = ROL32(A##gu1, 10); \ - A##ka0 ^= Da0; \ - Bgi1 = ROL32(A##ka0, 1); \ - A##me0 ^= De0; \ - Bgo1 = ROL32(A##me0, 22); \ - A##si0 ^= Di0; \ - Bgu1 = ROL32(A##si0, 30); \ - E##ga1 = Bga1 ^((~Bge1)& Bgi1 ); \ - E##ge1 = Bge1 ^((~Bgi1)& Bgo1 ); \ - E##gi1 = Bgi1 ^((~Bgo1)& Bgu1 ); \ - E##go1 = Bgo1 ^((~Bgu1)& Bga1 ); \ - E##gu1 = Bgu1 ^((~Bga1)& Bge1 ); \ -\ - A##be1 ^= De1; \ - Bka0 = ROL32(A##be1, 1); \ - A##gi0 ^= Di0; \ - Bke0 = ROL32(A##gi0, 3); \ - A##ko1 ^= Do1; \ - Bki0 = ROL32(A##ko1, 13); \ - A##mu0 ^= Du0; \ - Bko0 = ROL32(A##mu0, 4); \ - A##sa0 ^= Da0; \ - Bku0 = ROL32(A##sa0, 9); \ - E##ka0 = Bka0 ^((~Bke0)& Bki0 ); \ - E##ke0 = Bke0 ^((~Bki0)& Bko0 ); \ - E##ki0 = Bki0 ^((~Bko0)& Bku0 ); \ - E##ko0 = Bko0 ^((~Bku0)& Bka0 ); \ - E##ku0 = Bku0 ^((~Bka0)& Bke0 ); \ -\ - A##be0 ^= De0; \ - Bka1 = A##be0; \ - A##gi1 ^= Di1; \ - Bke1 = ROL32(A##gi1, 3); \ - A##ko0 ^= Do0; \ - Bki1 = ROL32(A##ko0, 12); \ - A##mu1 ^= Du1; \ - Bko1 = ROL32(A##mu1, 4); \ - A##sa1 ^= Da1; \ - Bku1 = ROL32(A##sa1, 9); \ - E##ka1 = Bka1 ^((~Bke1)& Bki1 ); \ - E##ke1 = Bke1 ^((~Bki1)& Bko1 ); \ - E##ki1 = Bki1 ^((~Bko1)& Bku1 ); \ - E##ko1 = Bko1 ^((~Bku1)& Bka1 ); \ - E##ku1 = Bku1 ^((~Bka1)& Bke1 ); \ -\ - A##bu1 ^= Du1; \ - Bma0 = ROL32(A##bu1, 14); \ - A##ga0 ^= Da0; \ - Bme0 = ROL32(A##ga0, 18); \ - A##ke0 ^= De0; \ - Bmi0 = ROL32(A##ke0, 5); \ - A##mi1 ^= Di1; \ - Bmo0 = ROL32(A##mi1, 8); \ - A##so0 ^= Do0; \ - Bmu0 = ROL32(A##so0, 28); \ - E##ma0 = Bma0 ^((~Bme0)& Bmi0 ); \ - E##me0 = Bme0 ^((~Bmi0)& Bmo0 ); \ - E##mi0 = Bmi0 ^((~Bmo0)& Bmu0 ); \ - E##mo0 = Bmo0 ^((~Bmu0)& Bma0 ); \ - E##mu0 = Bmu0 ^((~Bma0)& Bme0 ); \ -\ - A##bu0 ^= Du0; \ - Bma1 = ROL32(A##bu0, 13); \ - A##ga1 ^= Da1; \ - Bme1 = ROL32(A##ga1, 18); \ - A##ke1 ^= De1; \ - Bmi1 = ROL32(A##ke1, 5); \ - A##mi0 ^= Di0; \ - Bmo1 = ROL32(A##mi0, 7); \ - A##so1 ^= Do1; \ - Bmu1 = ROL32(A##so1, 28); \ - E##ma1 = Bma1 ^((~Bme1)& Bmi1 ); \ - E##me1 = Bme1 ^((~Bmi1)& Bmo1 ); \ - E##mi1 = Bmi1 ^((~Bmo1)& Bmu1 ); \ - E##mo1 = Bmo1 ^((~Bmu1)& Bma1 ); \ - E##mu1 = Bmu1 ^((~Bma1)& Bme1 ); \ -\ - A##bi0 ^= Di0; \ - Bsa0 = ROL32(A##bi0, 31); \ - A##go1 ^= Do1; \ - Bse0 = ROL32(A##go1, 28); \ - A##ku1 ^= Du1; \ - Bsi0 = ROL32(A##ku1, 20); \ - A##ma1 ^= Da1; \ - Bso0 = ROL32(A##ma1, 21); \ - A##se0 ^= De0; \ - Bsu0 = ROL32(A##se0, 1); \ - E##sa0 = Bsa0 ^((~Bse0)& Bsi0 ); \ - E##se0 = Bse0 ^((~Bsi0)& Bso0 ); \ - E##si0 = Bsi0 ^((~Bso0)& Bsu0 ); \ - E##so0 = Bso0 ^((~Bsu0)& Bsa0 ); \ - E##su0 = Bsu0 ^((~Bsa0)& Bse0 ); \ -\ - A##bi1 ^= Di1; \ - Bsa1 = ROL32(A##bi1, 31); \ - A##go0 ^= Do0; \ - Bse1 = ROL32(A##go0, 27); \ - A##ku0 ^= Du0; \ - Bsi1 = ROL32(A##ku0, 19); \ - A##ma0 ^= Da0; \ - Bso1 = ROL32(A##ma0, 20); \ - A##se1 ^= De1; \ - Bsu1 = ROL32(A##se1, 1); \ - E##sa1 = Bsa1 ^((~Bse1)& Bsi1 ); \ - E##se1 = Bse1 ^((~Bsi1)& Bso1 ); \ - E##si1 = Bsi1 ^((~Bso1)& Bsu1 ); \ - E##so1 = Bso1 ^((~Bsu1)& Bsa1 ); \ - E##su1 = Bsu1 ^((~Bsa1)& Bse1 ); \ -\ - -#endif /* UseBebigokimisa */ - -const UINT32 KeccakF1600RoundConstants_int2_0[24] = { - 0x00000001UL, - 0x00000000UL, - 0x00000000UL, - 0x00000000UL, - 0x00000001UL, - 0x00000001UL, - 0x00000001UL, - 0x00000001UL, - 0x00000000UL, - 0x00000000UL, - 0x00000001UL, - 0x00000000UL, - 0x00000001UL, - 0x00000001UL, - 0x00000001UL, - 0x00000001UL, - 0x00000000UL, - 0x00000000UL, - 0x00000000UL, - 0x00000000UL, - 0x00000001UL, - 0x00000000UL, - 0x00000001UL, - 0x00000000UL }; - -const UINT32 KeccakF1600RoundConstants_int2_1[24] = { - 0x00000000UL, - 0x00000089UL, - 0x8000008bUL, - 0x80008080UL, - 0x0000008bUL, - 0x00008000UL, - 0x80008088UL, - 0x80000082UL, - 0x0000000bUL, - 0x0000000aUL, - 0x00008082UL, - 0x00008003UL, - 0x0000808bUL, - 0x8000000bUL, - 0x8000008aUL, - 0x80000081UL, - 0x80000081UL, - 0x80000008UL, - 0x00000083UL, - 0x80008003UL, - 0x80008088UL, - 0x80000088UL, - 0x00008000UL, - 0x80008082UL }; - -#define copyFromStateAndXor1024bits(X, state, input) \ - X##ba0 = state[ 0]^input[ 0]; \ - X##ba1 = state[ 1]^input[ 1]; \ - X##be0 = state[ 2]^input[ 2]; \ - X##be1 = state[ 3]^input[ 3]; \ - X##bi0 = state[ 4]^input[ 4]; \ - X##bi1 = state[ 5]^input[ 5]; \ - X##bo0 = state[ 6]^input[ 6]; \ - X##bo1 = state[ 7]^input[ 7]; \ - X##bu0 = state[ 8]^input[ 8]; \ - X##bu1 = state[ 9]^input[ 9]; \ - X##ga0 = state[10]^input[10]; \ - X##ga1 = state[11]^input[11]; \ - X##ge0 = state[12]^input[12]; \ - X##ge1 = state[13]^input[13]; \ - X##gi0 = state[14]^input[14]; \ - X##gi1 = state[15]^input[15]; \ - X##go0 = state[16]^input[16]; \ - X##go1 = state[17]^input[17]; \ - X##gu0 = state[18]^input[18]; \ - X##gu1 = state[19]^input[19]; \ - X##ka0 = state[20]^input[20]; \ - X##ka1 = state[21]^input[21]; \ - X##ke0 = state[22]^input[22]; \ - X##ke1 = state[23]^input[23]; \ - X##ki0 = state[24]^input[24]; \ - X##ki1 = state[25]^input[25]; \ - X##ko0 = state[26]^input[26]; \ - X##ko1 = state[27]^input[27]; \ - X##ku0 = state[28]^input[28]; \ - X##ku1 = state[29]^input[29]; \ - X##ma0 = state[30]^input[30]; \ - X##ma1 = state[31]^input[31]; \ - X##me0 = state[32]; \ - X##me1 = state[33]; \ - X##mi0 = state[34]; \ - X##mi1 = state[35]; \ - X##mo0 = state[36]; \ - X##mo1 = state[37]; \ - X##mu0 = state[38]; \ - X##mu1 = state[39]; \ - X##sa0 = state[40]; \ - X##sa1 = state[41]; \ - X##se0 = state[42]; \ - X##se1 = state[43]; \ - X##si0 = state[44]; \ - X##si1 = state[45]; \ - X##so0 = state[46]; \ - X##so1 = state[47]; \ - X##su0 = state[48]; \ - X##su1 = state[49]; \ - -#define copyFromStateAndXor1088bits(X, state, input) \ - X##ba0 = state[ 0]^input[ 0]; \ - X##ba1 = state[ 1]^input[ 1]; \ - X##be0 = state[ 2]^input[ 2]; \ - X##be1 = state[ 3]^input[ 3]; \ - X##bi0 = state[ 4]^input[ 4]; \ - X##bi1 = state[ 5]^input[ 5]; \ - X##bo0 = state[ 6]^input[ 6]; \ - X##bo1 = state[ 7]^input[ 7]; \ - X##bu0 = state[ 8]^input[ 8]; \ - X##bu1 = state[ 9]^input[ 9]; \ - X##ga0 = state[10]^input[10]; \ - X##ga1 = state[11]^input[11]; \ - X##ge0 = state[12]^input[12]; \ - X##ge1 = state[13]^input[13]; \ - X##gi0 = state[14]^input[14]; \ - X##gi1 = state[15]^input[15]; \ - X##go0 = state[16]^input[16]; \ - X##go1 = state[17]^input[17]; \ - X##gu0 = state[18]^input[18]; \ - X##gu1 = state[19]^input[19]; \ - X##ka0 = state[20]^input[20]; \ - X##ka1 = state[21]^input[21]; \ - X##ke0 = state[22]^input[22]; \ - X##ke1 = state[23]^input[23]; \ - X##ki0 = state[24]^input[24]; \ - X##ki1 = state[25]^input[25]; \ - X##ko0 = state[26]^input[26]; \ - X##ko1 = state[27]^input[27]; \ - X##ku0 = state[28]^input[28]; \ - X##ku1 = state[29]^input[29]; \ - X##ma0 = state[30]^input[30]; \ - X##ma1 = state[31]^input[31]; \ - X##me0 = state[32]^input[32]; \ - X##me1 = state[33]^input[33]; \ - X##mi0 = state[34]; \ - X##mi1 = state[35]; \ - X##mo0 = state[36]; \ - X##mo1 = state[37]; \ - X##mu0 = state[38]; \ - X##mu1 = state[39]; \ - X##sa0 = state[40]; \ - X##sa1 = state[41]; \ - X##se0 = state[42]; \ - X##se1 = state[43]; \ - X##si0 = state[44]; \ - X##si1 = state[45]; \ - X##so0 = state[46]; \ - X##so1 = state[47]; \ - X##su0 = state[48]; \ - X##su1 = state[49]; \ - -#define copyFromState(X, state) \ - X##ba0 = state[ 0]; \ - X##ba1 = state[ 1]; \ - X##be0 = state[ 2]; \ - X##be1 = state[ 3]; \ - X##bi0 = state[ 4]; \ - X##bi1 = state[ 5]; \ - X##bo0 = state[ 6]; \ - X##bo1 = state[ 7]; \ - X##bu0 = state[ 8]; \ - X##bu1 = state[ 9]; \ - X##ga0 = state[10]; \ - X##ga1 = state[11]; \ - X##ge0 = state[12]; \ - X##ge1 = state[13]; \ - X##gi0 = state[14]; \ - X##gi1 = state[15]; \ - X##go0 = state[16]; \ - X##go1 = state[17]; \ - X##gu0 = state[18]; \ - X##gu1 = state[19]; \ - X##ka0 = state[20]; \ - X##ka1 = state[21]; \ - X##ke0 = state[22]; \ - X##ke1 = state[23]; \ - X##ki0 = state[24]; \ - X##ki1 = state[25]; \ - X##ko0 = state[26]; \ - X##ko1 = state[27]; \ - X##ku0 = state[28]; \ - X##ku1 = state[29]; \ - X##ma0 = state[30]; \ - X##ma1 = state[31]; \ - X##me0 = state[32]; \ - X##me1 = state[33]; \ - X##mi0 = state[34]; \ - X##mi1 = state[35]; \ - X##mo0 = state[36]; \ - X##mo1 = state[37]; \ - X##mu0 = state[38]; \ - X##mu1 = state[39]; \ - X##sa0 = state[40]; \ - X##sa1 = state[41]; \ - X##se0 = state[42]; \ - X##se1 = state[43]; \ - X##si0 = state[44]; \ - X##si1 = state[45]; \ - X##so0 = state[46]; \ - X##so1 = state[47]; \ - X##su0 = state[48]; \ - X##su1 = state[49]; \ - -#define copyToState(state, X) \ - state[ 0] = X##ba0; \ - state[ 1] = X##ba1; \ - state[ 2] = X##be0; \ - state[ 3] = X##be1; \ - state[ 4] = X##bi0; \ - state[ 5] = X##bi1; \ - state[ 6] = X##bo0; \ - state[ 7] = X##bo1; \ - state[ 8] = X##bu0; \ - state[ 9] = X##bu1; \ - state[10] = X##ga0; \ - state[11] = X##ga1; \ - state[12] = X##ge0; \ - state[13] = X##ge1; \ - state[14] = X##gi0; \ - state[15] = X##gi1; \ - state[16] = X##go0; \ - state[17] = X##go1; \ - state[18] = X##gu0; \ - state[19] = X##gu1; \ - state[20] = X##ka0; \ - state[21] = X##ka1; \ - state[22] = X##ke0; \ - state[23] = X##ke1; \ - state[24] = X##ki0; \ - state[25] = X##ki1; \ - state[26] = X##ko0; \ - state[27] = X##ko1; \ - state[28] = X##ku0; \ - state[29] = X##ku1; \ - state[30] = X##ma0; \ - state[31] = X##ma1; \ - state[32] = X##me0; \ - state[33] = X##me1; \ - state[34] = X##mi0; \ - state[35] = X##mi1; \ - state[36] = X##mo0; \ - state[37] = X##mo1; \ - state[38] = X##mu0; \ - state[39] = X##mu1; \ - state[40] = X##sa0; \ - state[41] = X##sa1; \ - state[42] = X##se0; \ - state[43] = X##se1; \ - state[44] = X##si0; \ - state[45] = X##si1; \ - state[46] = X##so0; \ - state[47] = X##so1; \ - state[48] = X##su0; \ - state[49] = X##su1; \ - -#define copyStateVariables(X, Y) \ - X##ba0 = Y##ba0; \ - X##ba1 = Y##ba1; \ - X##be0 = Y##be0; \ - X##be1 = Y##be1; \ - X##bi0 = Y##bi0; \ - X##bi1 = Y##bi1; \ - X##bo0 = Y##bo0; \ - X##bo1 = Y##bo1; \ - X##bu0 = Y##bu0; \ - X##bu1 = Y##bu1; \ - X##ga0 = Y##ga0; \ - X##ga1 = Y##ga1; \ - X##ge0 = Y##ge0; \ - X##ge1 = Y##ge1; \ - X##gi0 = Y##gi0; \ - X##gi1 = Y##gi1; \ - X##go0 = Y##go0; \ - X##go1 = Y##go1; \ - X##gu0 = Y##gu0; \ - X##gu1 = Y##gu1; \ - X##ka0 = Y##ka0; \ - X##ka1 = Y##ka1; \ - X##ke0 = Y##ke0; \ - X##ke1 = Y##ke1; \ - X##ki0 = Y##ki0; \ - X##ki1 = Y##ki1; \ - X##ko0 = Y##ko0; \ - X##ko1 = Y##ko1; \ - X##ku0 = Y##ku0; \ - X##ku1 = Y##ku1; \ - X##ma0 = Y##ma0; \ - X##ma1 = Y##ma1; \ - X##me0 = Y##me0; \ - X##me1 = Y##me1; \ - X##mi0 = Y##mi0; \ - X##mi1 = Y##mi1; \ - X##mo0 = Y##mo0; \ - X##mo1 = Y##mo1; \ - X##mu0 = Y##mu0; \ - X##mu1 = Y##mu1; \ - X##sa0 = Y##sa0; \ - X##sa1 = Y##sa1; \ - X##se0 = Y##se0; \ - X##se1 = Y##se1; \ - X##si0 = Y##si0; \ - X##si1 = Y##si1; \ - X##so0 = Y##so0; \ - X##so1 = Y##so1; \ - X##su0 = Y##su0; \ - X##su1 = Y##su1; \ - diff --git a/Modules/_sha3/keccak/KeccakF-1600-32-s2.macros b/Modules/_sha3/keccak/KeccakF-1600-32-s2.macros deleted file mode 100644 --- a/Modules/_sha3/keccak/KeccakF-1600-32-s2.macros +++ /dev/null @@ -1,1187 +0,0 @@ -/* -Code automatically generated by KeccakTools! - -The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, -Micha?l Peeters and Gilles Van Assche. For more information, feedback or -questions, please refer to our website: http://keccak.noekeon.org/ - -Implementation by the designers, -hereby denoted as "the implementer". - -To the extent possible under law, the implementer has waived all copyright -and related or neighboring rights to the source code in this file. -http://creativecommons.org/publicdomain/zero/1.0/ -*/ - -#define declareABCDE \ - UINT32 Aba0, Abe0, Abi0, Abo0, Abu0; \ - UINT32 Aba1, Abe1, Abi1, Abo1, Abu1; \ - UINT32 Aga0, Age0, Agi0, Ago0, Agu0; \ - UINT32 Aga1, Age1, Agi1, Ago1, Agu1; \ - UINT32 Aka0, Ake0, Aki0, Ako0, Aku0; \ - UINT32 Aka1, Ake1, Aki1, Ako1, Aku1; \ - UINT32 Ama0, Ame0, Ami0, Amo0, Amu0; \ - UINT32 Ama1, Ame1, Ami1, Amo1, Amu1; \ - UINT32 Asa0, Ase0, Asi0, Aso0, Asu0; \ - UINT32 Asa1, Ase1, Asi1, Aso1, Asu1; \ - UINT32 Bba0, Bbe0, Bbi0, Bbo0, Bbu0; \ - UINT32 Bba1, Bbe1, Bbi1, Bbo1, Bbu1; \ - UINT32 Bga0, Bge0, Bgi0, Bgo0, Bgu0; \ - UINT32 Bga1, Bge1, Bgi1, Bgo1, Bgu1; \ - UINT32 Bka0, Bke0, Bki0, Bko0, Bku0; \ - UINT32 Bka1, Bke1, Bki1, Bko1, Bku1; \ - UINT32 Bma0, Bme0, Bmi0, Bmo0, Bmu0; \ - UINT32 Bma1, Bme1, Bmi1, Bmo1, Bmu1; \ - UINT32 Bsa0, Bse0, Bsi0, Bso0, Bsu0; \ - UINT32 Bsa1, Bse1, Bsi1, Bso1, Bsu1; \ - UINT32 Ca0, Ce0, Ci0, Co0, Cu0; \ - UINT32 Ca1, Ce1, Ci1, Co1, Cu1; \ - UINT32 Da0, De0, Di0, Do0, Du0; \ - UINT32 Da1, De1, Di1, Do1, Du1; \ - UINT32 Eba0, Ebe0, Ebi0, Ebo0, Ebu0; \ - UINT32 Eba1, Ebe1, Ebi1, Ebo1, Ebu1; \ - UINT32 Ega0, Ege0, Egi0, Ego0, Egu0; \ - UINT32 Ega1, Ege1, Egi1, Ego1, Egu1; \ - UINT32 Eka0, Eke0, Eki0, Eko0, Eku0; \ - UINT32 Eka1, Eke1, Eki1, Eko1, Eku1; \ - UINT32 Ema0, Eme0, Emi0, Emo0, Emu0; \ - UINT32 Ema1, Eme1, Emi1, Emo1, Emu1; \ - UINT32 Esa0, Ese0, Esi0, Eso0, Esu0; \ - UINT32 Esa1, Ese1, Esi1, Eso1, Esu1; \ - -#define prepareTheta \ - Ca0 = Aba0^Aga0^Aka0^Ama0^Asa0; \ - Ca1 = Aba1^Aga1^Aka1^Ama1^Asa1; \ - Ce0 = Abe0^Age0^Ake0^Ame0^Ase0; \ - Ce1 = Abe1^Age1^Ake1^Ame1^Ase1; \ - Ci0 = Abi0^Agi0^Aki0^Ami0^Asi0; \ - Ci1 = Abi1^Agi1^Aki1^Ami1^Asi1; \ - Co0 = Abo0^Ago0^Ako0^Amo0^Aso0; \ - Co1 = Abo1^Ago1^Ako1^Amo1^Aso1; \ - Cu0 = Abu0^Agu0^Aku0^Amu0^Asu0; \ - Cu1 = Abu1^Agu1^Aku1^Amu1^Asu1; \ - -#ifdef UseBebigokimisa -/* --- Code for round, with prepare-theta (lane complementing pattern 'bebigokimisa') */ -/* --- using factor 2 interleaving, 64-bit lanes mapped to 32-bit words */ -#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ - Da0 = Cu0^ROL32(Ce1, 1); \ - Da1 = Cu1^Ce0; \ - De0 = Ca0^ROL32(Ci1, 1); \ - De1 = Ca1^Ci0; \ - Di0 = Ce0^ROL32(Co1, 1); \ - Di1 = Ce1^Co0; \ - Do0 = Ci0^ROL32(Cu1, 1); \ - Do1 = Ci1^Cu0; \ - Du0 = Co0^ROL32(Ca1, 1); \ - Du1 = Co1^Ca0; \ -\ - A##ba0 ^= Da0; \ - Bba0 = A##ba0; \ - A##ge0 ^= De0; \ - Bbe0 = ROL32(A##ge0, 22); \ - A##ki1 ^= Di1; \ - Bbi0 = ROL32(A##ki1, 22); \ - E##ba0 = Bba0 ^( Bbe0 | Bbi0 ); \ - E##ba0 ^= KeccakF1600RoundConstants_int2_0[i]; \ - Ca0 = E##ba0; \ - A##mo1 ^= Do1; \ - Bbo0 = ROL32(A##mo1, 11); \ - E##be0 = Bbe0 ^((~Bbi0)| Bbo0 ); \ - Ce0 = E##be0; \ - A##su0 ^= Du0; \ - Bbu0 = ROL32(A##su0, 7); \ - E##bi0 = Bbi0 ^( Bbo0 & Bbu0 ); \ - Ci0 = E##bi0; \ - E##bo0 = Bbo0 ^( Bbu0 | Bba0 ); \ - Co0 = E##bo0; \ - E##bu0 = Bbu0 ^( Bba0 & Bbe0 ); \ - Cu0 = E##bu0; \ -\ - A##ba1 ^= Da1; \ - Bba1 = A##ba1; \ - A##ge1 ^= De1; \ - Bbe1 = ROL32(A##ge1, 22); \ - A##ki0 ^= Di0; \ - Bbi1 = ROL32(A##ki0, 21); \ - E##ba1 = Bba1 ^( Bbe1 | Bbi1 ); \ - E##ba1 ^= KeccakF1600RoundConstants_int2_1[i]; \ - Ca1 = E##ba1; \ - A##mo0 ^= Do0; \ - Bbo1 = ROL32(A##mo0, 10); \ - E##be1 = Bbe1 ^((~Bbi1)| Bbo1 ); \ - Ce1 = E##be1; \ - A##su1 ^= Du1; \ - Bbu1 = ROL32(A##su1, 7); \ - E##bi1 = Bbi1 ^( Bbo1 & Bbu1 ); \ - Ci1 = E##bi1; \ - E##bo1 = Bbo1 ^( Bbu1 | Bba1 ); \ - Co1 = E##bo1; \ - E##bu1 = Bbu1 ^( Bba1 & Bbe1 ); \ - Cu1 = E##bu1; \ -\ - A##bo0 ^= Do0; \ - Bga0 = ROL32(A##bo0, 14); \ - A##gu0 ^= Du0; \ - Bge0 = ROL32(A##gu0, 10); \ - A##ka1 ^= Da1; \ - Bgi0 = ROL32(A##ka1, 2); \ - E##ga0 = Bga0 ^( Bge0 | Bgi0 ); \ - Ca0 ^= E##ga0; \ - A##me1 ^= De1; \ - Bgo0 = ROL32(A##me1, 23); \ - E##ge0 = Bge0 ^( Bgi0 & Bgo0 ); \ - Ce0 ^= E##ge0; \ - A##si1 ^= Di1; \ - Bgu0 = ROL32(A##si1, 31); \ - E##gi0 = Bgi0 ^( Bgo0 |(~Bgu0)); \ - Ci0 ^= E##gi0; \ - E##go0 = Bgo0 ^( Bgu0 | Bga0 ); \ - Co0 ^= E##go0; \ - E##gu0 = Bgu0 ^( Bga0 & Bge0 ); \ - Cu0 ^= E##gu0; \ -\ - A##bo1 ^= Do1; \ - Bga1 = ROL32(A##bo1, 14); \ - A##gu1 ^= Du1; \ - Bge1 = ROL32(A##gu1, 10); \ - A##ka0 ^= Da0; \ - Bgi1 = ROL32(A##ka0, 1); \ - E##ga1 = Bga1 ^( Bge1 | Bgi1 ); \ - Ca1 ^= E##ga1; \ - A##me0 ^= De0; \ - Bgo1 = ROL32(A##me0, 22); \ - E##ge1 = Bge1 ^( Bgi1 & Bgo1 ); \ - Ce1 ^= E##ge1; \ - A##si0 ^= Di0; \ - Bgu1 = ROL32(A##si0, 30); \ - E##gi1 = Bgi1 ^( Bgo1 |(~Bgu1)); \ - Ci1 ^= E##gi1; \ - E##go1 = Bgo1 ^( Bgu1 | Bga1 ); \ - Co1 ^= E##go1; \ - E##gu1 = Bgu1 ^( Bga1 & Bge1 ); \ - Cu1 ^= E##gu1; \ -\ - A##be1 ^= De1; \ - Bka0 = ROL32(A##be1, 1); \ - A##gi0 ^= Di0; \ - Bke0 = ROL32(A##gi0, 3); \ - A##ko1 ^= Do1; \ - Bki0 = ROL32(A##ko1, 13); \ - E##ka0 = Bka0 ^( Bke0 | Bki0 ); \ - Ca0 ^= E##ka0; \ - A##mu0 ^= Du0; \ - Bko0 = ROL32(A##mu0, 4); \ - E##ke0 = Bke0 ^( Bki0 & Bko0 ); \ - Ce0 ^= E##ke0; \ - A##sa0 ^= Da0; \ - Bku0 = ROL32(A##sa0, 9); \ - E##ki0 = Bki0 ^((~Bko0)& Bku0 ); \ - Ci0 ^= E##ki0; \ - E##ko0 = (~Bko0)^( Bku0 | Bka0 ); \ - Co0 ^= E##ko0; \ - E##ku0 = Bku0 ^( Bka0 & Bke0 ); \ - Cu0 ^= E##ku0; \ -\ - A##be0 ^= De0; \ - Bka1 = A##be0; \ - A##gi1 ^= Di1; \ - Bke1 = ROL32(A##gi1, 3); \ - A##ko0 ^= Do0; \ - Bki1 = ROL32(A##ko0, 12); \ - E##ka1 = Bka1 ^( Bke1 | Bki1 ); \ - Ca1 ^= E##ka1; \ - A##mu1 ^= Du1; \ - Bko1 = ROL32(A##mu1, 4); \ - E##ke1 = Bke1 ^( Bki1 & Bko1 ); \ - Ce1 ^= E##ke1; \ - A##sa1 ^= Da1; \ - Bku1 = ROL32(A##sa1, 9); \ - E##ki1 = Bki1 ^((~Bko1)& Bku1 ); \ - Ci1 ^= E##ki1; \ - E##ko1 = (~Bko1)^( Bku1 | Bka1 ); \ - Co1 ^= E##ko1; \ - E##ku1 = Bku1 ^( Bka1 & Bke1 ); \ - Cu1 ^= E##ku1; \ -\ - A##bu1 ^= Du1; \ - Bma0 = ROL32(A##bu1, 14); \ - A##ga0 ^= Da0; \ - Bme0 = ROL32(A##ga0, 18); \ - A##ke0 ^= De0; \ - Bmi0 = ROL32(A##ke0, 5); \ - E##ma0 = Bma0 ^( Bme0 & Bmi0 ); \ - Ca0 ^= E##ma0; \ - A##mi1 ^= Di1; \ - Bmo0 = ROL32(A##mi1, 8); \ - E##me0 = Bme0 ^( Bmi0 | Bmo0 ); \ - Ce0 ^= E##me0; \ - A##so0 ^= Do0; \ - Bmu0 = ROL32(A##so0, 28); \ - E##mi0 = Bmi0 ^((~Bmo0)| Bmu0 ); \ - Ci0 ^= E##mi0; \ - E##mo0 = (~Bmo0)^( Bmu0 & Bma0 ); \ - Co0 ^= E##mo0; \ - E##mu0 = Bmu0 ^( Bma0 | Bme0 ); \ - Cu0 ^= E##mu0; \ -\ - A##bu0 ^= Du0; \ - Bma1 = ROL32(A##bu0, 13); \ - A##ga1 ^= Da1; \ - Bme1 = ROL32(A##ga1, 18); \ - A##ke1 ^= De1; \ - Bmi1 = ROL32(A##ke1, 5); \ - E##ma1 = Bma1 ^( Bme1 & Bmi1 ); \ - Ca1 ^= E##ma1; \ - A##mi0 ^= Di0; \ - Bmo1 = ROL32(A##mi0, 7); \ - E##me1 = Bme1 ^( Bmi1 | Bmo1 ); \ - Ce1 ^= E##me1; \ - A##so1 ^= Do1; \ - Bmu1 = ROL32(A##so1, 28); \ - E##mi1 = Bmi1 ^((~Bmo1)| Bmu1 ); \ - Ci1 ^= E##mi1; \ - E##mo1 = (~Bmo1)^( Bmu1 & Bma1 ); \ - Co1 ^= E##mo1; \ - E##mu1 = Bmu1 ^( Bma1 | Bme1 ); \ - Cu1 ^= E##mu1; \ -\ - A##bi0 ^= Di0; \ - Bsa0 = ROL32(A##bi0, 31); \ - A##go1 ^= Do1; \ - Bse0 = ROL32(A##go1, 28); \ - A##ku1 ^= Du1; \ - Bsi0 = ROL32(A##ku1, 20); \ - E##sa0 = Bsa0 ^((~Bse0)& Bsi0 ); \ - Ca0 ^= E##sa0; \ - A##ma1 ^= Da1; \ - Bso0 = ROL32(A##ma1, 21); \ - E##se0 = (~Bse0)^( Bsi0 | Bso0 ); \ - Ce0 ^= E##se0; \ - A##se0 ^= De0; \ - Bsu0 = ROL32(A##se0, 1); \ - E##si0 = Bsi0 ^( Bso0 & Bsu0 ); \ - Ci0 ^= E##si0; \ - E##so0 = Bso0 ^( Bsu0 | Bsa0 ); \ - Co0 ^= E##so0; \ - E##su0 = Bsu0 ^( Bsa0 & Bse0 ); \ - Cu0 ^= E##su0; \ -\ - A##bi1 ^= Di1; \ - Bsa1 = ROL32(A##bi1, 31); \ - A##go0 ^= Do0; \ - Bse1 = ROL32(A##go0, 27); \ - A##ku0 ^= Du0; \ - Bsi1 = ROL32(A##ku0, 19); \ - E##sa1 = Bsa1 ^((~Bse1)& Bsi1 ); \ - Ca1 ^= E##sa1; \ - A##ma0 ^= Da0; \ - Bso1 = ROL32(A##ma0, 20); \ - E##se1 = (~Bse1)^( Bsi1 | Bso1 ); \ - Ce1 ^= E##se1; \ - A##se1 ^= De1; \ - Bsu1 = ROL32(A##se1, 1); \ - E##si1 = Bsi1 ^( Bso1 & Bsu1 ); \ - Ci1 ^= E##si1; \ - E##so1 = Bso1 ^( Bsu1 | Bsa1 ); \ - Co1 ^= E##so1; \ - E##su1 = Bsu1 ^( Bsa1 & Bse1 ); \ - Cu1 ^= E##su1; \ -\ - -/* --- Code for round (lane complementing pattern 'bebigokimisa') */ -/* --- using factor 2 interleaving, 64-bit lanes mapped to 32-bit words */ -#define thetaRhoPiChiIota(i, A, E) \ - Da0 = Cu0^ROL32(Ce1, 1); \ - Da1 = Cu1^Ce0; \ - De0 = Ca0^ROL32(Ci1, 1); \ - De1 = Ca1^Ci0; \ - Di0 = Ce0^ROL32(Co1, 1); \ - Di1 = Ce1^Co0; \ - Do0 = Ci0^ROL32(Cu1, 1); \ - Do1 = Ci1^Cu0; \ - Du0 = Co0^ROL32(Ca1, 1); \ - Du1 = Co1^Ca0; \ -\ - A##ba0 ^= Da0; \ - Bba0 = A##ba0; \ - A##ge0 ^= De0; \ - Bbe0 = ROL32(A##ge0, 22); \ - A##ki1 ^= Di1; \ - Bbi0 = ROL32(A##ki1, 22); \ - E##ba0 = Bba0 ^( Bbe0 | Bbi0 ); \ - E##ba0 ^= KeccakF1600RoundConstants_int2_0[i]; \ - A##mo1 ^= Do1; \ - Bbo0 = ROL32(A##mo1, 11); \ - E##be0 = Bbe0 ^((~Bbi0)| Bbo0 ); \ - A##su0 ^= Du0; \ - Bbu0 = ROL32(A##su0, 7); \ - E##bi0 = Bbi0 ^( Bbo0 & Bbu0 ); \ - E##bo0 = Bbo0 ^( Bbu0 | Bba0 ); \ - E##bu0 = Bbu0 ^( Bba0 & Bbe0 ); \ -\ - A##ba1 ^= Da1; \ - Bba1 = A##ba1; \ - A##ge1 ^= De1; \ - Bbe1 = ROL32(A##ge1, 22); \ - A##ki0 ^= Di0; \ - Bbi1 = ROL32(A##ki0, 21); \ - E##ba1 = Bba1 ^( Bbe1 | Bbi1 ); \ - E##ba1 ^= KeccakF1600RoundConstants_int2_1[i]; \ - A##mo0 ^= Do0; \ - Bbo1 = ROL32(A##mo0, 10); \ - E##be1 = Bbe1 ^((~Bbi1)| Bbo1 ); \ - A##su1 ^= Du1; \ - Bbu1 = ROL32(A##su1, 7); \ - E##bi1 = Bbi1 ^( Bbo1 & Bbu1 ); \ - E##bo1 = Bbo1 ^( Bbu1 | Bba1 ); \ - E##bu1 = Bbu1 ^( Bba1 & Bbe1 ); \ -\ - A##bo0 ^= Do0; \ - Bga0 = ROL32(A##bo0, 14); \ - A##gu0 ^= Du0; \ - Bge0 = ROL32(A##gu0, 10); \ - A##ka1 ^= Da1; \ - Bgi0 = ROL32(A##ka1, 2); \ - E##ga0 = Bga0 ^( Bge0 | Bgi0 ); \ - A##me1 ^= De1; \ - Bgo0 = ROL32(A##me1, 23); \ - E##ge0 = Bge0 ^( Bgi0 & Bgo0 ); \ - A##si1 ^= Di1; \ - Bgu0 = ROL32(A##si1, 31); \ - E##gi0 = Bgi0 ^( Bgo0 |(~Bgu0)); \ - E##go0 = Bgo0 ^( Bgu0 | Bga0 ); \ - E##gu0 = Bgu0 ^( Bga0 & Bge0 ); \ -\ - A##bo1 ^= Do1; \ - Bga1 = ROL32(A##bo1, 14); \ - A##gu1 ^= Du1; \ - Bge1 = ROL32(A##gu1, 10); \ - A##ka0 ^= Da0; \ - Bgi1 = ROL32(A##ka0, 1); \ - E##ga1 = Bga1 ^( Bge1 | Bgi1 ); \ - A##me0 ^= De0; \ - Bgo1 = ROL32(A##me0, 22); \ - E##ge1 = Bge1 ^( Bgi1 & Bgo1 ); \ - A##si0 ^= Di0; \ - Bgu1 = ROL32(A##si0, 30); \ - E##gi1 = Bgi1 ^( Bgo1 |(~Bgu1)); \ - E##go1 = Bgo1 ^( Bgu1 | Bga1 ); \ - E##gu1 = Bgu1 ^( Bga1 & Bge1 ); \ -\ - A##be1 ^= De1; \ - Bka0 = ROL32(A##be1, 1); \ - A##gi0 ^= Di0; \ - Bke0 = ROL32(A##gi0, 3); \ - A##ko1 ^= Do1; \ - Bki0 = ROL32(A##ko1, 13); \ - E##ka0 = Bka0 ^( Bke0 | Bki0 ); \ - A##mu0 ^= Du0; \ - Bko0 = ROL32(A##mu0, 4); \ - E##ke0 = Bke0 ^( Bki0 & Bko0 ); \ - A##sa0 ^= Da0; \ - Bku0 = ROL32(A##sa0, 9); \ - E##ki0 = Bki0 ^((~Bko0)& Bku0 ); \ - E##ko0 = (~Bko0)^( Bku0 | Bka0 ); \ - E##ku0 = Bku0 ^( Bka0 & Bke0 ); \ -\ - A##be0 ^= De0; \ - Bka1 = A##be0; \ - A##gi1 ^= Di1; \ - Bke1 = ROL32(A##gi1, 3); \ - A##ko0 ^= Do0; \ - Bki1 = ROL32(A##ko0, 12); \ - E##ka1 = Bka1 ^( Bke1 | Bki1 ); \ - A##mu1 ^= Du1; \ - Bko1 = ROL32(A##mu1, 4); \ - E##ke1 = Bke1 ^( Bki1 & Bko1 ); \ - A##sa1 ^= Da1; \ - Bku1 = ROL32(A##sa1, 9); \ - E##ki1 = Bki1 ^((~Bko1)& Bku1 ); \ - E##ko1 = (~Bko1)^( Bku1 | Bka1 ); \ - E##ku1 = Bku1 ^( Bka1 & Bke1 ); \ -\ - A##bu1 ^= Du1; \ - Bma0 = ROL32(A##bu1, 14); \ - A##ga0 ^= Da0; \ - Bme0 = ROL32(A##ga0, 18); \ - A##ke0 ^= De0; \ - Bmi0 = ROL32(A##ke0, 5); \ - E##ma0 = Bma0 ^( Bme0 & Bmi0 ); \ - A##mi1 ^= Di1; \ - Bmo0 = ROL32(A##mi1, 8); \ - E##me0 = Bme0 ^( Bmi0 | Bmo0 ); \ - A##so0 ^= Do0; \ - Bmu0 = ROL32(A##so0, 28); \ - E##mi0 = Bmi0 ^((~Bmo0)| Bmu0 ); \ - E##mo0 = (~Bmo0)^( Bmu0 & Bma0 ); \ - E##mu0 = Bmu0 ^( Bma0 | Bme0 ); \ -\ - A##bu0 ^= Du0; \ - Bma1 = ROL32(A##bu0, 13); \ - A##ga1 ^= Da1; \ - Bme1 = ROL32(A##ga1, 18); \ - A##ke1 ^= De1; \ - Bmi1 = ROL32(A##ke1, 5); \ - E##ma1 = Bma1 ^( Bme1 & Bmi1 ); \ - A##mi0 ^= Di0; \ - Bmo1 = ROL32(A##mi0, 7); \ - E##me1 = Bme1 ^( Bmi1 | Bmo1 ); \ - A##so1 ^= Do1; \ - Bmu1 = ROL32(A##so1, 28); \ - E##mi1 = Bmi1 ^((~Bmo1)| Bmu1 ); \ - E##mo1 = (~Bmo1)^( Bmu1 & Bma1 ); \ - E##mu1 = Bmu1 ^( Bma1 | Bme1 ); \ -\ - A##bi0 ^= Di0; \ - Bsa0 = ROL32(A##bi0, 31); \ - A##go1 ^= Do1; \ - Bse0 = ROL32(A##go1, 28); \ - A##ku1 ^= Du1; \ - Bsi0 = ROL32(A##ku1, 20); \ - E##sa0 = Bsa0 ^((~Bse0)& Bsi0 ); \ - A##ma1 ^= Da1; \ - Bso0 = ROL32(A##ma1, 21); \ - E##se0 = (~Bse0)^( Bsi0 | Bso0 ); \ - A##se0 ^= De0; \ - Bsu0 = ROL32(A##se0, 1); \ - E##si0 = Bsi0 ^( Bso0 & Bsu0 ); \ - E##so0 = Bso0 ^( Bsu0 | Bsa0 ); \ - E##su0 = Bsu0 ^( Bsa0 & Bse0 ); \ -\ - A##bi1 ^= Di1; \ - Bsa1 = ROL32(A##bi1, 31); \ - A##go0 ^= Do0; \ - Bse1 = ROL32(A##go0, 27); \ - A##ku0 ^= Du0; \ - Bsi1 = ROL32(A##ku0, 19); \ - E##sa1 = Bsa1 ^((~Bse1)& Bsi1 ); \ - A##ma0 ^= Da0; \ - Bso1 = ROL32(A##ma0, 20); \ - E##se1 = (~Bse1)^( Bsi1 | Bso1 ); \ - A##se1 ^= De1; \ - Bsu1 = ROL32(A##se1, 1); \ - E##si1 = Bsi1 ^( Bso1 & Bsu1 ); \ - E##so1 = Bso1 ^( Bsu1 | Bsa1 ); \ - E##su1 = Bsu1 ^( Bsa1 & Bse1 ); \ -\ - -#else /* UseBebigokimisa */ -/* --- Code for round, with prepare-theta */ -/* --- using factor 2 interleaving, 64-bit lanes mapped to 32-bit words */ -#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ - Da0 = Cu0^ROL32(Ce1, 1); \ - Da1 = Cu1^Ce0; \ - De0 = Ca0^ROL32(Ci1, 1); \ - De1 = Ca1^Ci0; \ - Di0 = Ce0^ROL32(Co1, 1); \ - Di1 = Ce1^Co0; \ - Do0 = Ci0^ROL32(Cu1, 1); \ - Do1 = Ci1^Cu0; \ - Du0 = Co0^ROL32(Ca1, 1); \ - Du1 = Co1^Ca0; \ -\ - A##ba0 ^= Da0; \ - Bba0 = A##ba0; \ - A##ge0 ^= De0; \ - Bbe0 = ROL32(A##ge0, 22); \ - A##ki1 ^= Di1; \ - Bbi0 = ROL32(A##ki1, 22); \ - E##ba0 = Bba0 ^((~Bbe0)& Bbi0 ); \ - E##ba0 ^= KeccakF1600RoundConstants_int2_0[i]; \ - Ca0 = E##ba0; \ - A##mo1 ^= Do1; \ - Bbo0 = ROL32(A##mo1, 11); \ - E##be0 = Bbe0 ^((~Bbi0)& Bbo0 ); \ - Ce0 = E##be0; \ - A##su0 ^= Du0; \ - Bbu0 = ROL32(A##su0, 7); \ - E##bi0 = Bbi0 ^((~Bbo0)& Bbu0 ); \ - Ci0 = E##bi0; \ - E##bo0 = Bbo0 ^((~Bbu0)& Bba0 ); \ - Co0 = E##bo0; \ - E##bu0 = Bbu0 ^((~Bba0)& Bbe0 ); \ - Cu0 = E##bu0; \ -\ - A##ba1 ^= Da1; \ - Bba1 = A##ba1; \ - A##ge1 ^= De1; \ - Bbe1 = ROL32(A##ge1, 22); \ - A##ki0 ^= Di0; \ - Bbi1 = ROL32(A##ki0, 21); \ - E##ba1 = Bba1 ^((~Bbe1)& Bbi1 ); \ - E##ba1 ^= KeccakF1600RoundConstants_int2_1[i]; \ - Ca1 = E##ba1; \ - A##mo0 ^= Do0; \ - Bbo1 = ROL32(A##mo0, 10); \ - E##be1 = Bbe1 ^((~Bbi1)& Bbo1 ); \ - Ce1 = E##be1; \ - A##su1 ^= Du1; \ - Bbu1 = ROL32(A##su1, 7); \ - E##bi1 = Bbi1 ^((~Bbo1)& Bbu1 ); \ - Ci1 = E##bi1; \ - E##bo1 = Bbo1 ^((~Bbu1)& Bba1 ); \ - Co1 = E##bo1; \ - E##bu1 = Bbu1 ^((~Bba1)& Bbe1 ); \ - Cu1 = E##bu1; \ -\ - A##bo0 ^= Do0; \ - Bga0 = ROL32(A##bo0, 14); \ - A##gu0 ^= Du0; \ - Bge0 = ROL32(A##gu0, 10); \ - A##ka1 ^= Da1; \ - Bgi0 = ROL32(A##ka1, 2); \ - E##ga0 = Bga0 ^((~Bge0)& Bgi0 ); \ - Ca0 ^= E##ga0; \ - A##me1 ^= De1; \ - Bgo0 = ROL32(A##me1, 23); \ - E##ge0 = Bge0 ^((~Bgi0)& Bgo0 ); \ - Ce0 ^= E##ge0; \ - A##si1 ^= Di1; \ - Bgu0 = ROL32(A##si1, 31); \ - E##gi0 = Bgi0 ^((~Bgo0)& Bgu0 ); \ - Ci0 ^= E##gi0; \ - E##go0 = Bgo0 ^((~Bgu0)& Bga0 ); \ - Co0 ^= E##go0; \ - E##gu0 = Bgu0 ^((~Bga0)& Bge0 ); \ - Cu0 ^= E##gu0; \ -\ - A##bo1 ^= Do1; \ - Bga1 = ROL32(A##bo1, 14); \ - A##gu1 ^= Du1; \ - Bge1 = ROL32(A##gu1, 10); \ - A##ka0 ^= Da0; \ - Bgi1 = ROL32(A##ka0, 1); \ - E##ga1 = Bga1 ^((~Bge1)& Bgi1 ); \ - Ca1 ^= E##ga1; \ - A##me0 ^= De0; \ - Bgo1 = ROL32(A##me0, 22); \ - E##ge1 = Bge1 ^((~Bgi1)& Bgo1 ); \ - Ce1 ^= E##ge1; \ - A##si0 ^= Di0; \ - Bgu1 = ROL32(A##si0, 30); \ - E##gi1 = Bgi1 ^((~Bgo1)& Bgu1 ); \ - Ci1 ^= E##gi1; \ - E##go1 = Bgo1 ^((~Bgu1)& Bga1 ); \ - Co1 ^= E##go1; \ - E##gu1 = Bgu1 ^((~Bga1)& Bge1 ); \ - Cu1 ^= E##gu1; \ -\ - A##be1 ^= De1; \ - Bka0 = ROL32(A##be1, 1); \ - A##gi0 ^= Di0; \ - Bke0 = ROL32(A##gi0, 3); \ - A##ko1 ^= Do1; \ - Bki0 = ROL32(A##ko1, 13); \ - E##ka0 = Bka0 ^((~Bke0)& Bki0 ); \ - Ca0 ^= E##ka0; \ - A##mu0 ^= Du0; \ - Bko0 = ROL32(A##mu0, 4); \ - E##ke0 = Bke0 ^((~Bki0)& Bko0 ); \ - Ce0 ^= E##ke0; \ - A##sa0 ^= Da0; \ - Bku0 = ROL32(A##sa0, 9); \ - E##ki0 = Bki0 ^((~Bko0)& Bku0 ); \ - Ci0 ^= E##ki0; \ - E##ko0 = Bko0 ^((~Bku0)& Bka0 ); \ - Co0 ^= E##ko0; \ - E##ku0 = Bku0 ^((~Bka0)& Bke0 ); \ - Cu0 ^= E##ku0; \ -\ - A##be0 ^= De0; \ - Bka1 = A##be0; \ - A##gi1 ^= Di1; \ - Bke1 = ROL32(A##gi1, 3); \ - A##ko0 ^= Do0; \ - Bki1 = ROL32(A##ko0, 12); \ - E##ka1 = Bka1 ^((~Bke1)& Bki1 ); \ - Ca1 ^= E##ka1; \ - A##mu1 ^= Du1; \ - Bko1 = ROL32(A##mu1, 4); \ - E##ke1 = Bke1 ^((~Bki1)& Bko1 ); \ - Ce1 ^= E##ke1; \ - A##sa1 ^= Da1; \ - Bku1 = ROL32(A##sa1, 9); \ - E##ki1 = Bki1 ^((~Bko1)& Bku1 ); \ - Ci1 ^= E##ki1; \ - E##ko1 = Bko1 ^((~Bku1)& Bka1 ); \ - Co1 ^= E##ko1; \ - E##ku1 = Bku1 ^((~Bka1)& Bke1 ); \ - Cu1 ^= E##ku1; \ -\ - A##bu1 ^= Du1; \ - Bma0 = ROL32(A##bu1, 14); \ - A##ga0 ^= Da0; \ - Bme0 = ROL32(A##ga0, 18); \ - A##ke0 ^= De0; \ - Bmi0 = ROL32(A##ke0, 5); \ - E##ma0 = Bma0 ^((~Bme0)& Bmi0 ); \ - Ca0 ^= E##ma0; \ - A##mi1 ^= Di1; \ - Bmo0 = ROL32(A##mi1, 8); \ - E##me0 = Bme0 ^((~Bmi0)& Bmo0 ); \ - Ce0 ^= E##me0; \ - A##so0 ^= Do0; \ - Bmu0 = ROL32(A##so0, 28); \ - E##mi0 = Bmi0 ^((~Bmo0)& Bmu0 ); \ - Ci0 ^= E##mi0; \ - E##mo0 = Bmo0 ^((~Bmu0)& Bma0 ); \ - Co0 ^= E##mo0; \ - E##mu0 = Bmu0 ^((~Bma0)& Bme0 ); \ - Cu0 ^= E##mu0; \ -\ - A##bu0 ^= Du0; \ - Bma1 = ROL32(A##bu0, 13); \ - A##ga1 ^= Da1; \ - Bme1 = ROL32(A##ga1, 18); \ - A##ke1 ^= De1; \ - Bmi1 = ROL32(A##ke1, 5); \ - E##ma1 = Bma1 ^((~Bme1)& Bmi1 ); \ - Ca1 ^= E##ma1; \ - A##mi0 ^= Di0; \ - Bmo1 = ROL32(A##mi0, 7); \ - E##me1 = Bme1 ^((~Bmi1)& Bmo1 ); \ - Ce1 ^= E##me1; \ - A##so1 ^= Do1; \ - Bmu1 = ROL32(A##so1, 28); \ - E##mi1 = Bmi1 ^((~Bmo1)& Bmu1 ); \ - Ci1 ^= E##mi1; \ - E##mo1 = Bmo1 ^((~Bmu1)& Bma1 ); \ - Co1 ^= E##mo1; \ - E##mu1 = Bmu1 ^((~Bma1)& Bme1 ); \ - Cu1 ^= E##mu1; \ -\ - A##bi0 ^= Di0; \ - Bsa0 = ROL32(A##bi0, 31); \ - A##go1 ^= Do1; \ - Bse0 = ROL32(A##go1, 28); \ - A##ku1 ^= Du1; \ - Bsi0 = ROL32(A##ku1, 20); \ - E##sa0 = Bsa0 ^((~Bse0)& Bsi0 ); \ - Ca0 ^= E##sa0; \ - A##ma1 ^= Da1; \ - Bso0 = ROL32(A##ma1, 21); \ - E##se0 = Bse0 ^((~Bsi0)& Bso0 ); \ - Ce0 ^= E##se0; \ - A##se0 ^= De0; \ - Bsu0 = ROL32(A##se0, 1); \ - E##si0 = Bsi0 ^((~Bso0)& Bsu0 ); \ - Ci0 ^= E##si0; \ - E##so0 = Bso0 ^((~Bsu0)& Bsa0 ); \ - Co0 ^= E##so0; \ - E##su0 = Bsu0 ^((~Bsa0)& Bse0 ); \ - Cu0 ^= E##su0; \ -\ - A##bi1 ^= Di1; \ - Bsa1 = ROL32(A##bi1, 31); \ - A##go0 ^= Do0; \ - Bse1 = ROL32(A##go0, 27); \ - A##ku0 ^= Du0; \ - Bsi1 = ROL32(A##ku0, 19); \ - E##sa1 = Bsa1 ^((~Bse1)& Bsi1 ); \ - Ca1 ^= E##sa1; \ - A##ma0 ^= Da0; \ - Bso1 = ROL32(A##ma0, 20); \ - E##se1 = Bse1 ^((~Bsi1)& Bso1 ); \ - Ce1 ^= E##se1; \ - A##se1 ^= De1; \ - Bsu1 = ROL32(A##se1, 1); \ - E##si1 = Bsi1 ^((~Bso1)& Bsu1 ); \ - Ci1 ^= E##si1; \ - E##so1 = Bso1 ^((~Bsu1)& Bsa1 ); \ - Co1 ^= E##so1; \ - E##su1 = Bsu1 ^((~Bsa1)& Bse1 ); \ - Cu1 ^= E##su1; \ -\ - -/* --- Code for round */ -/* --- using factor 2 interleaving, 64-bit lanes mapped to 32-bit words */ -#define thetaRhoPiChiIota(i, A, E) \ - Da0 = Cu0^ROL32(Ce1, 1); \ - Da1 = Cu1^Ce0; \ - De0 = Ca0^ROL32(Ci1, 1); \ - De1 = Ca1^Ci0; \ - Di0 = Ce0^ROL32(Co1, 1); \ - Di1 = Ce1^Co0; \ - Do0 = Ci0^ROL32(Cu1, 1); \ - Do1 = Ci1^Cu0; \ - Du0 = Co0^ROL32(Ca1, 1); \ - Du1 = Co1^Ca0; \ -\ - A##ba0 ^= Da0; \ - Bba0 = A##ba0; \ - A##ge0 ^= De0; \ - Bbe0 = ROL32(A##ge0, 22); \ - A##ki1 ^= Di1; \ - Bbi0 = ROL32(A##ki1, 22); \ - E##ba0 = Bba0 ^((~Bbe0)& Bbi0 ); \ - E##ba0 ^= KeccakF1600RoundConstants_int2_0[i]; \ - A##mo1 ^= Do1; \ - Bbo0 = ROL32(A##mo1, 11); \ - E##be0 = Bbe0 ^((~Bbi0)& Bbo0 ); \ - A##su0 ^= Du0; \ - Bbu0 = ROL32(A##su0, 7); \ - E##bi0 = Bbi0 ^((~Bbo0)& Bbu0 ); \ - E##bo0 = Bbo0 ^((~Bbu0)& Bba0 ); \ - E##bu0 = Bbu0 ^((~Bba0)& Bbe0 ); \ -\ - A##ba1 ^= Da1; \ - Bba1 = A##ba1; \ - A##ge1 ^= De1; \ - Bbe1 = ROL32(A##ge1, 22); \ - A##ki0 ^= Di0; \ - Bbi1 = ROL32(A##ki0, 21); \ - E##ba1 = Bba1 ^((~Bbe1)& Bbi1 ); \ - E##ba1 ^= KeccakF1600RoundConstants_int2_1[i]; \ - A##mo0 ^= Do0; \ - Bbo1 = ROL32(A##mo0, 10); \ - E##be1 = Bbe1 ^((~Bbi1)& Bbo1 ); \ - A##su1 ^= Du1; \ - Bbu1 = ROL32(A##su1, 7); \ - E##bi1 = Bbi1 ^((~Bbo1)& Bbu1 ); \ - E##bo1 = Bbo1 ^((~Bbu1)& Bba1 ); \ - E##bu1 = Bbu1 ^((~Bba1)& Bbe1 ); \ -\ - A##bo0 ^= Do0; \ - Bga0 = ROL32(A##bo0, 14); \ - A##gu0 ^= Du0; \ - Bge0 = ROL32(A##gu0, 10); \ - A##ka1 ^= Da1; \ - Bgi0 = ROL32(A##ka1, 2); \ - E##ga0 = Bga0 ^((~Bge0)& Bgi0 ); \ - A##me1 ^= De1; \ - Bgo0 = ROL32(A##me1, 23); \ - E##ge0 = Bge0 ^((~Bgi0)& Bgo0 ); \ - A##si1 ^= Di1; \ - Bgu0 = ROL32(A##si1, 31); \ - E##gi0 = Bgi0 ^((~Bgo0)& Bgu0 ); \ - E##go0 = Bgo0 ^((~Bgu0)& Bga0 ); \ - E##gu0 = Bgu0 ^((~Bga0)& Bge0 ); \ -\ - A##bo1 ^= Do1; \ - Bga1 = ROL32(A##bo1, 14); \ - A##gu1 ^= Du1; \ - Bge1 = ROL32(A##gu1, 10); \ - A##ka0 ^= Da0; \ - Bgi1 = ROL32(A##ka0, 1); \ - E##ga1 = Bga1 ^((~Bge1)& Bgi1 ); \ - A##me0 ^= De0; \ - Bgo1 = ROL32(A##me0, 22); \ - E##ge1 = Bge1 ^((~Bgi1)& Bgo1 ); \ - A##si0 ^= Di0; \ - Bgu1 = ROL32(A##si0, 30); \ - E##gi1 = Bgi1 ^((~Bgo1)& Bgu1 ); \ - E##go1 = Bgo1 ^((~Bgu1)& Bga1 ); \ - E##gu1 = Bgu1 ^((~Bga1)& Bge1 ); \ -\ - A##be1 ^= De1; \ - Bka0 = ROL32(A##be1, 1); \ - A##gi0 ^= Di0; \ - Bke0 = ROL32(A##gi0, 3); \ - A##ko1 ^= Do1; \ - Bki0 = ROL32(A##ko1, 13); \ - E##ka0 = Bka0 ^((~Bke0)& Bki0 ); \ - A##mu0 ^= Du0; \ - Bko0 = ROL32(A##mu0, 4); \ - E##ke0 = Bke0 ^((~Bki0)& Bko0 ); \ - A##sa0 ^= Da0; \ - Bku0 = ROL32(A##sa0, 9); \ - E##ki0 = Bki0 ^((~Bko0)& Bku0 ); \ - E##ko0 = Bko0 ^((~Bku0)& Bka0 ); \ - E##ku0 = Bku0 ^((~Bka0)& Bke0 ); \ -\ - A##be0 ^= De0; \ - Bka1 = A##be0; \ - A##gi1 ^= Di1; \ - Bke1 = ROL32(A##gi1, 3); \ - A##ko0 ^= Do0; \ - Bki1 = ROL32(A##ko0, 12); \ - E##ka1 = Bka1 ^((~Bke1)& Bki1 ); \ - A##mu1 ^= Du1; \ - Bko1 = ROL32(A##mu1, 4); \ - E##ke1 = Bke1 ^((~Bki1)& Bko1 ); \ - A##sa1 ^= Da1; \ - Bku1 = ROL32(A##sa1, 9); \ - E##ki1 = Bki1 ^((~Bko1)& Bku1 ); \ - E##ko1 = Bko1 ^((~Bku1)& Bka1 ); \ - E##ku1 = Bku1 ^((~Bka1)& Bke1 ); \ -\ - A##bu1 ^= Du1; \ - Bma0 = ROL32(A##bu1, 14); \ - A##ga0 ^= Da0; \ - Bme0 = ROL32(A##ga0, 18); \ - A##ke0 ^= De0; \ - Bmi0 = ROL32(A##ke0, 5); \ - E##ma0 = Bma0 ^((~Bme0)& Bmi0 ); \ - A##mi1 ^= Di1; \ - Bmo0 = ROL32(A##mi1, 8); \ - E##me0 = Bme0 ^((~Bmi0)& Bmo0 ); \ - A##so0 ^= Do0; \ - Bmu0 = ROL32(A##so0, 28); \ - E##mi0 = Bmi0 ^((~Bmo0)& Bmu0 ); \ - E##mo0 = Bmo0 ^((~Bmu0)& Bma0 ); \ - E##mu0 = Bmu0 ^((~Bma0)& Bme0 ); \ -\ - A##bu0 ^= Du0; \ - Bma1 = ROL32(A##bu0, 13); \ - A##ga1 ^= Da1; \ - Bme1 = ROL32(A##ga1, 18); \ - A##ke1 ^= De1; \ - Bmi1 = ROL32(A##ke1, 5); \ - E##ma1 = Bma1 ^((~Bme1)& Bmi1 ); \ - A##mi0 ^= Di0; \ - Bmo1 = ROL32(A##mi0, 7); \ - E##me1 = Bme1 ^((~Bmi1)& Bmo1 ); \ - A##so1 ^= Do1; \ - Bmu1 = ROL32(A##so1, 28); \ - E##mi1 = Bmi1 ^((~Bmo1)& Bmu1 ); \ - E##mo1 = Bmo1 ^((~Bmu1)& Bma1 ); \ - E##mu1 = Bmu1 ^((~Bma1)& Bme1 ); \ -\ - A##bi0 ^= Di0; \ - Bsa0 = ROL32(A##bi0, 31); \ - A##go1 ^= Do1; \ - Bse0 = ROL32(A##go1, 28); \ - A##ku1 ^= Du1; \ - Bsi0 = ROL32(A##ku1, 20); \ - E##sa0 = Bsa0 ^((~Bse0)& Bsi0 ); \ - A##ma1 ^= Da1; \ - Bso0 = ROL32(A##ma1, 21); \ - E##se0 = Bse0 ^((~Bsi0)& Bso0 ); \ - A##se0 ^= De0; \ - Bsu0 = ROL32(A##se0, 1); \ - E##si0 = Bsi0 ^((~Bso0)& Bsu0 ); \ - E##so0 = Bso0 ^((~Bsu0)& Bsa0 ); \ - E##su0 = Bsu0 ^((~Bsa0)& Bse0 ); \ -\ - A##bi1 ^= Di1; \ - Bsa1 = ROL32(A##bi1, 31); \ - A##go0 ^= Do0; \ - Bse1 = ROL32(A##go0, 27); \ - A##ku0 ^= Du0; \ - Bsi1 = ROL32(A##ku0, 19); \ - E##sa1 = Bsa1 ^((~Bse1)& Bsi1 ); \ - A##ma0 ^= Da0; \ - Bso1 = ROL32(A##ma0, 20); \ - E##se1 = Bse1 ^((~Bsi1)& Bso1 ); \ - A##se1 ^= De1; \ - Bsu1 = ROL32(A##se1, 1); \ - E##si1 = Bsi1 ^((~Bso1)& Bsu1 ); \ - E##so1 = Bso1 ^((~Bsu1)& Bsa1 ); \ - E##su1 = Bsu1 ^((~Bsa1)& Bse1 ); \ -\ - -#endif /* UseBebigokimisa */ - -const UINT32 KeccakF1600RoundConstants_int2_0[24] = { - 0x00000001UL, - 0x00000000UL, - 0x00000000UL, - 0x00000000UL, - 0x00000001UL, - 0x00000001UL, - 0x00000001UL, - 0x00000001UL, - 0x00000000UL, - 0x00000000UL, - 0x00000001UL, - 0x00000000UL, - 0x00000001UL, - 0x00000001UL, - 0x00000001UL, - 0x00000001UL, - 0x00000000UL, - 0x00000000UL, - 0x00000000UL, - 0x00000000UL, - 0x00000001UL, - 0x00000000UL, - 0x00000001UL, - 0x00000000UL }; - -const UINT32 KeccakF1600RoundConstants_int2_1[24] = { - 0x00000000UL, - 0x00000089UL, - 0x8000008bUL, - 0x80008080UL, - 0x0000008bUL, - 0x00008000UL, - 0x80008088UL, - 0x80000082UL, - 0x0000000bUL, - 0x0000000aUL, - 0x00008082UL, - 0x00008003UL, - 0x0000808bUL, - 0x8000000bUL, - 0x8000008aUL, - 0x80000081UL, - 0x80000081UL, - 0x80000008UL, - 0x00000083UL, - 0x80008003UL, - 0x80008088UL, - 0x80000088UL, - 0x00008000UL, - 0x80008082UL }; - -#define copyFromStateAndXor1024bits(X, state, input) \ - X##ba0 = state[ 0]^input[ 0]; \ - X##ba1 = state[ 1]^input[ 1]; \ - X##be0 = state[ 2]^input[ 2]; \ - X##be1 = state[ 3]^input[ 3]; \ - X##bi0 = state[ 4]^input[ 4]; \ - X##bi1 = state[ 5]^input[ 5]; \ - X##bo0 = state[ 6]^input[ 6]; \ - X##bo1 = state[ 7]^input[ 7]; \ - X##bu0 = state[ 8]^input[ 8]; \ - X##bu1 = state[ 9]^input[ 9]; \ - X##ga0 = state[10]^input[10]; \ - X##ga1 = state[11]^input[11]; \ - X##ge0 = state[12]^input[12]; \ - X##ge1 = state[13]^input[13]; \ - X##gi0 = state[14]^input[14]; \ - X##gi1 = state[15]^input[15]; \ - X##go0 = state[16]^input[16]; \ - X##go1 = state[17]^input[17]; \ - X##gu0 = state[18]^input[18]; \ - X##gu1 = state[19]^input[19]; \ - X##ka0 = state[20]^input[20]; \ - X##ka1 = state[21]^input[21]; \ - X##ke0 = state[22]^input[22]; \ - X##ke1 = state[23]^input[23]; \ - X##ki0 = state[24]^input[24]; \ - X##ki1 = state[25]^input[25]; \ - X##ko0 = state[26]^input[26]; \ - X##ko1 = state[27]^input[27]; \ - X##ku0 = state[28]^input[28]; \ - X##ku1 = state[29]^input[29]; \ - X##ma0 = state[30]^input[30]; \ - X##ma1 = state[31]^input[31]; \ - X##me0 = state[32]; \ - X##me1 = state[33]; \ - X##mi0 = state[34]; \ - X##mi1 = state[35]; \ - X##mo0 = state[36]; \ - X##mo1 = state[37]; \ - X##mu0 = state[38]; \ - X##mu1 = state[39]; \ - X##sa0 = state[40]; \ - X##sa1 = state[41]; \ - X##se0 = state[42]; \ - X##se1 = state[43]; \ - X##si0 = state[44]; \ - X##si1 = state[45]; \ - X##so0 = state[46]; \ - X##so1 = state[47]; \ - X##su0 = state[48]; \ - X##su1 = state[49]; \ - -#define copyFromStateAndXor1088bits(X, state, input) \ - X##ba0 = state[ 0]^input[ 0]; \ - X##ba1 = state[ 1]^input[ 1]; \ - X##be0 = state[ 2]^input[ 2]; \ - X##be1 = state[ 3]^input[ 3]; \ - X##bi0 = state[ 4]^input[ 4]; \ - X##bi1 = state[ 5]^input[ 5]; \ - X##bo0 = state[ 6]^input[ 6]; \ - X##bo1 = state[ 7]^input[ 7]; \ - X##bu0 = state[ 8]^input[ 8]; \ - X##bu1 = state[ 9]^input[ 9]; \ - X##ga0 = state[10]^input[10]; \ - X##ga1 = state[11]^input[11]; \ - X##ge0 = state[12]^input[12]; \ - X##ge1 = state[13]^input[13]; \ - X##gi0 = state[14]^input[14]; \ - X##gi1 = state[15]^input[15]; \ - X##go0 = state[16]^input[16]; \ - X##go1 = state[17]^input[17]; \ - X##gu0 = state[18]^input[18]; \ - X##gu1 = state[19]^input[19]; \ - X##ka0 = state[20]^input[20]; \ - X##ka1 = state[21]^input[21]; \ - X##ke0 = state[22]^input[22]; \ - X##ke1 = state[23]^input[23]; \ - X##ki0 = state[24]^input[24]; \ - X##ki1 = state[25]^input[25]; \ - X##ko0 = state[26]^input[26]; \ - X##ko1 = state[27]^input[27]; \ - X##ku0 = state[28]^input[28]; \ - X##ku1 = state[29]^input[29]; \ - X##ma0 = state[30]^input[30]; \ - X##ma1 = state[31]^input[31]; \ - X##me0 = state[32]^input[32]; \ - X##me1 = state[33]^input[33]; \ - X##mi0 = state[34]; \ - X##mi1 = state[35]; \ - X##mo0 = state[36]; \ - X##mo1 = state[37]; \ - X##mu0 = state[38]; \ - X##mu1 = state[39]; \ - X##sa0 = state[40]; \ - X##sa1 = state[41]; \ - X##se0 = state[42]; \ - X##se1 = state[43]; \ - X##si0 = state[44]; \ - X##si1 = state[45]; \ - X##so0 = state[46]; \ - X##so1 = state[47]; \ - X##su0 = state[48]; \ - X##su1 = state[49]; \ - -#define copyFromState(X, state) \ - X##ba0 = state[ 0]; \ - X##ba1 = state[ 1]; \ - X##be0 = state[ 2]; \ - X##be1 = state[ 3]; \ - X##bi0 = state[ 4]; \ - X##bi1 = state[ 5]; \ - X##bo0 = state[ 6]; \ - X##bo1 = state[ 7]; \ - X##bu0 = state[ 8]; \ - X##bu1 = state[ 9]; \ - X##ga0 = state[10]; \ - X##ga1 = state[11]; \ - X##ge0 = state[12]; \ - X##ge1 = state[13]; \ - X##gi0 = state[14]; \ - X##gi1 = state[15]; \ - X##go0 = state[16]; \ - X##go1 = state[17]; \ - X##gu0 = state[18]; \ - X##gu1 = state[19]; \ - X##ka0 = state[20]; \ - X##ka1 = state[21]; \ - X##ke0 = state[22]; \ - X##ke1 = state[23]; \ - X##ki0 = state[24]; \ - X##ki1 = state[25]; \ - X##ko0 = state[26]; \ - X##ko1 = state[27]; \ - X##ku0 = state[28]; \ - X##ku1 = state[29]; \ - X##ma0 = state[30]; \ - X##ma1 = state[31]; \ - X##me0 = state[32]; \ - X##me1 = state[33]; \ - X##mi0 = state[34]; \ - X##mi1 = state[35]; \ - X##mo0 = state[36]; \ - X##mo1 = state[37]; \ - X##mu0 = state[38]; \ - X##mu1 = state[39]; \ - X##sa0 = state[40]; \ - X##sa1 = state[41]; \ - X##se0 = state[42]; \ - X##se1 = state[43]; \ - X##si0 = state[44]; \ - X##si1 = state[45]; \ - X##so0 = state[46]; \ - X##so1 = state[47]; \ - X##su0 = state[48]; \ - X##su1 = state[49]; \ - -#define copyToState(state, X) \ - state[ 0] = X##ba0; \ - state[ 1] = X##ba1; \ - state[ 2] = X##be0; \ - state[ 3] = X##be1; \ - state[ 4] = X##bi0; \ - state[ 5] = X##bi1; \ - state[ 6] = X##bo0; \ - state[ 7] = X##bo1; \ - state[ 8] = X##bu0; \ - state[ 9] = X##bu1; \ - state[10] = X##ga0; \ - state[11] = X##ga1; \ - state[12] = X##ge0; \ - state[13] = X##ge1; \ - state[14] = X##gi0; \ - state[15] = X##gi1; \ - state[16] = X##go0; \ - state[17] = X##go1; \ - state[18] = X##gu0; \ - state[19] = X##gu1; \ - state[20] = X##ka0; \ - state[21] = X##ka1; \ - state[22] = X##ke0; \ - state[23] = X##ke1; \ - state[24] = X##ki0; \ - state[25] = X##ki1; \ - state[26] = X##ko0; \ - state[27] = X##ko1; \ - state[28] = X##ku0; \ - state[29] = X##ku1; \ - state[30] = X##ma0; \ - state[31] = X##ma1; \ - state[32] = X##me0; \ - state[33] = X##me1; \ - state[34] = X##mi0; \ - state[35] = X##mi1; \ - state[36] = X##mo0; \ - state[37] = X##mo1; \ - state[38] = X##mu0; \ - state[39] = X##mu1; \ - state[40] = X##sa0; \ - state[41] = X##sa1; \ - state[42] = X##se0; \ - state[43] = X##se1; \ - state[44] = X##si0; \ - state[45] = X##si1; \ - state[46] = X##so0; \ - state[47] = X##so1; \ - state[48] = X##su0; \ - state[49] = X##su1; \ - -#define copyStateVariables(X, Y) \ - X##ba0 = Y##ba0; \ - X##ba1 = Y##ba1; \ - X##be0 = Y##be0; \ - X##be1 = Y##be1; \ - X##bi0 = Y##bi0; \ - X##bi1 = Y##bi1; \ - X##bo0 = Y##bo0; \ - X##bo1 = Y##bo1; \ - X##bu0 = Y##bu0; \ - X##bu1 = Y##bu1; \ - X##ga0 = Y##ga0; \ - X##ga1 = Y##ga1; \ - X##ge0 = Y##ge0; \ - X##ge1 = Y##ge1; \ - X##gi0 = Y##gi0; \ - X##gi1 = Y##gi1; \ - X##go0 = Y##go0; \ - X##go1 = Y##go1; \ - X##gu0 = Y##gu0; \ - X##gu1 = Y##gu1; \ - X##ka0 = Y##ka0; \ - X##ka1 = Y##ka1; \ - X##ke0 = Y##ke0; \ - X##ke1 = Y##ke1; \ - X##ki0 = Y##ki0; \ - X##ki1 = Y##ki1; \ - X##ko0 = Y##ko0; \ - X##ko1 = Y##ko1; \ - X##ku0 = Y##ku0; \ - X##ku1 = Y##ku1; \ - X##ma0 = Y##ma0; \ - X##ma1 = Y##ma1; \ - X##me0 = Y##me0; \ - X##me1 = Y##me1; \ - X##mi0 = Y##mi0; \ - X##mi1 = Y##mi1; \ - X##mo0 = Y##mo0; \ - X##mo1 = Y##mo1; \ - X##mu0 = Y##mu0; \ - X##mu1 = Y##mu1; \ - X##sa0 = Y##sa0; \ - X##sa1 = Y##sa1; \ - X##se0 = Y##se0; \ - X##se1 = Y##se1; \ - X##si0 = Y##si0; \ - X##si1 = Y##si1; \ - X##so0 = Y##so0; \ - X##so1 = Y##so1; \ - X##su0 = Y##su0; \ - X##su1 = Y##su1; \ - diff --git a/Modules/_sha3/keccak/KeccakF-1600-32.macros b/Modules/_sha3/keccak/KeccakF-1600-32.macros deleted file mode 100644 --- a/Modules/_sha3/keccak/KeccakF-1600-32.macros +++ /dev/null @@ -1,26 +0,0 @@ -/* -The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, -Micha?l Peeters and Gilles Van Assche. For more information, feedback or -questions, please refer to our website: http://keccak.noekeon.org/ - -Implementation by the designers, -hereby denoted as "the implementer". - -To the extent possible under law, the implementer has waived all copyright -and related or neighboring rights to the source code in this file. -http://creativecommons.org/publicdomain/zero/1.0/ -*/ - -#ifdef UseSchedule - #if (UseSchedule == 1) - #include "KeccakF-1600-32-s1.macros" - #elif (UseSchedule == 2) - #include "KeccakF-1600-32-s2.macros" - #elif (UseSchedule == 3) - #include "KeccakF-1600-32-rvk.macros" - #else - #error "This schedule is not supported." - #endif -#else - #include "KeccakF-1600-32-s1.macros" -#endif diff --git a/Modules/_sha3/keccak/KeccakF-1600-64.macros b/Modules/_sha3/keccak/KeccakF-1600-64.macros deleted file mode 100644 --- a/Modules/_sha3/keccak/KeccakF-1600-64.macros +++ /dev/null @@ -1,728 +0,0 @@ -/* -Code automatically generated by KeccakTools! - -The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, -Micha?l Peeters and Gilles Van Assche. For more information, feedback or -questions, please refer to our website: http://keccak.noekeon.org/ - -Implementation by the designers, -hereby denoted as "the implementer". - -To the extent possible under law, the implementer has waived all copyright -and related or neighboring rights to the source code in this file. -http://creativecommons.org/publicdomain/zero/1.0/ -*/ - -#define declareABCDE \ - UINT64 Aba, Abe, Abi, Abo, Abu; \ - UINT64 Aga, Age, Agi, Ago, Agu; \ - UINT64 Aka, Ake, Aki, Ako, Aku; \ - UINT64 Ama, Ame, Ami, Amo, Amu; \ - UINT64 Asa, Ase, Asi, Aso, Asu; \ - UINT64 Bba, Bbe, Bbi, Bbo, Bbu; \ - UINT64 Bga, Bge, Bgi, Bgo, Bgu; \ - UINT64 Bka, Bke, Bki, Bko, Bku; \ - UINT64 Bma, Bme, Bmi, Bmo, Bmu; \ - UINT64 Bsa, Bse, Bsi, Bso, Bsu; \ - UINT64 Ca, Ce, Ci, Co, Cu; \ - UINT64 Da, De, Di, Do, Du; \ - UINT64 Eba, Ebe, Ebi, Ebo, Ebu; \ - UINT64 Ega, Ege, Egi, Ego, Egu; \ - UINT64 Eka, Eke, Eki, Eko, Eku; \ - UINT64 Ema, Eme, Emi, Emo, Emu; \ - UINT64 Esa, Ese, Esi, Eso, Esu; \ - -#define prepareTheta \ - Ca = Aba^Aga^Aka^Ama^Asa; \ - Ce = Abe^Age^Ake^Ame^Ase; \ - Ci = Abi^Agi^Aki^Ami^Asi; \ - Co = Abo^Ago^Ako^Amo^Aso; \ - Cu = Abu^Agu^Aku^Amu^Asu; \ - -#ifdef UseBebigokimisa -/* --- Code for round, with prepare-theta (lane complementing pattern 'bebigokimisa') */ -/* --- 64-bit lanes mapped to 64-bit words */ -#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ - Da = Cu^ROL64(Ce, 1); \ - De = Ca^ROL64(Ci, 1); \ - Di = Ce^ROL64(Co, 1); \ - Do = Ci^ROL64(Cu, 1); \ - Du = Co^ROL64(Ca, 1); \ -\ - A##ba ^= Da; \ - Bba = A##ba; \ - A##ge ^= De; \ - Bbe = ROL64(A##ge, 44); \ - A##ki ^= Di; \ - Bbi = ROL64(A##ki, 43); \ - A##mo ^= Do; \ - Bbo = ROL64(A##mo, 21); \ - A##su ^= Du; \ - Bbu = ROL64(A##su, 14); \ - E##ba = Bba ^( Bbe | Bbi ); \ - E##ba ^= KeccakF1600RoundConstants[i]; \ - Ca = E##ba; \ - E##be = Bbe ^((~Bbi)| Bbo ); \ - Ce = E##be; \ - E##bi = Bbi ^( Bbo & Bbu ); \ - Ci = E##bi; \ - E##bo = Bbo ^( Bbu | Bba ); \ - Co = E##bo; \ - E##bu = Bbu ^( Bba & Bbe ); \ - Cu = E##bu; \ -\ - A##bo ^= Do; \ - Bga = ROL64(A##bo, 28); \ - A##gu ^= Du; \ - Bge = ROL64(A##gu, 20); \ - A##ka ^= Da; \ - Bgi = ROL64(A##ka, 3); \ - A##me ^= De; \ - Bgo = ROL64(A##me, 45); \ - A##si ^= Di; \ - Bgu = ROL64(A##si, 61); \ - E##ga = Bga ^( Bge | Bgi ); \ - Ca ^= E##ga; \ - E##ge = Bge ^( Bgi & Bgo ); \ - Ce ^= E##ge; \ - E##gi = Bgi ^( Bgo |(~Bgu)); \ - Ci ^= E##gi; \ - E##go = Bgo ^( Bgu | Bga ); \ - Co ^= E##go; \ - E##gu = Bgu ^( Bga & Bge ); \ - Cu ^= E##gu; \ -\ - A##be ^= De; \ - Bka = ROL64(A##be, 1); \ - A##gi ^= Di; \ - Bke = ROL64(A##gi, 6); \ - A##ko ^= Do; \ - Bki = ROL64(A##ko, 25); \ - A##mu ^= Du; \ - Bko = ROL64(A##mu, 8); \ - A##sa ^= Da; \ - Bku = ROL64(A##sa, 18); \ - E##ka = Bka ^( Bke | Bki ); \ - Ca ^= E##ka; \ - E##ke = Bke ^( Bki & Bko ); \ - Ce ^= E##ke; \ - E##ki = Bki ^((~Bko)& Bku ); \ - Ci ^= E##ki; \ - E##ko = (~Bko)^( Bku | Bka ); \ - Co ^= E##ko; \ - E##ku = Bku ^( Bka & Bke ); \ - Cu ^= E##ku; \ -\ - A##bu ^= Du; \ - Bma = ROL64(A##bu, 27); \ - A##ga ^= Da; \ - Bme = ROL64(A##ga, 36); \ - A##ke ^= De; \ - Bmi = ROL64(A##ke, 10); \ - A##mi ^= Di; \ - Bmo = ROL64(A##mi, 15); \ - A##so ^= Do; \ - Bmu = ROL64(A##so, 56); \ - E##ma = Bma ^( Bme & Bmi ); \ - Ca ^= E##ma; \ - E##me = Bme ^( Bmi | Bmo ); \ - Ce ^= E##me; \ - E##mi = Bmi ^((~Bmo)| Bmu ); \ - Ci ^= E##mi; \ - E##mo = (~Bmo)^( Bmu & Bma ); \ - Co ^= E##mo; \ - E##mu = Bmu ^( Bma | Bme ); \ - Cu ^= E##mu; \ -\ - A##bi ^= Di; \ - Bsa = ROL64(A##bi, 62); \ - A##go ^= Do; \ - Bse = ROL64(A##go, 55); \ - A##ku ^= Du; \ - Bsi = ROL64(A##ku, 39); \ - A##ma ^= Da; \ - Bso = ROL64(A##ma, 41); \ - A##se ^= De; \ - Bsu = ROL64(A##se, 2); \ - E##sa = Bsa ^((~Bse)& Bsi ); \ - Ca ^= E##sa; \ - E##se = (~Bse)^( Bsi | Bso ); \ - Ce ^= E##se; \ - E##si = Bsi ^( Bso & Bsu ); \ - Ci ^= E##si; \ - E##so = Bso ^( Bsu | Bsa ); \ - Co ^= E##so; \ - E##su = Bsu ^( Bsa & Bse ); \ - Cu ^= E##su; \ -\ - -/* --- Code for round (lane complementing pattern 'bebigokimisa') */ -/* --- 64-bit lanes mapped to 64-bit words */ -#define thetaRhoPiChiIota(i, A, E) \ - Da = Cu^ROL64(Ce, 1); \ - De = Ca^ROL64(Ci, 1); \ - Di = Ce^ROL64(Co, 1); \ - Do = Ci^ROL64(Cu, 1); \ - Du = Co^ROL64(Ca, 1); \ -\ - A##ba ^= Da; \ - Bba = A##ba; \ - A##ge ^= De; \ - Bbe = ROL64(A##ge, 44); \ - A##ki ^= Di; \ - Bbi = ROL64(A##ki, 43); \ - A##mo ^= Do; \ - Bbo = ROL64(A##mo, 21); \ - A##su ^= Du; \ - Bbu = ROL64(A##su, 14); \ - E##ba = Bba ^( Bbe | Bbi ); \ - E##ba ^= KeccakF1600RoundConstants[i]; \ - E##be = Bbe ^((~Bbi)| Bbo ); \ - E##bi = Bbi ^( Bbo & Bbu ); \ - E##bo = Bbo ^( Bbu | Bba ); \ - E##bu = Bbu ^( Bba & Bbe ); \ -\ - A##bo ^= Do; \ - Bga = ROL64(A##bo, 28); \ - A##gu ^= Du; \ - Bge = ROL64(A##gu, 20); \ - A##ka ^= Da; \ - Bgi = ROL64(A##ka, 3); \ - A##me ^= De; \ - Bgo = ROL64(A##me, 45); \ - A##si ^= Di; \ - Bgu = ROL64(A##si, 61); \ - E##ga = Bga ^( Bge | Bgi ); \ - E##ge = Bge ^( Bgi & Bgo ); \ - E##gi = Bgi ^( Bgo |(~Bgu)); \ - E##go = Bgo ^( Bgu | Bga ); \ - E##gu = Bgu ^( Bga & Bge ); \ -\ - A##be ^= De; \ - Bka = ROL64(A##be, 1); \ - A##gi ^= Di; \ - Bke = ROL64(A##gi, 6); \ - A##ko ^= Do; \ - Bki = ROL64(A##ko, 25); \ - A##mu ^= Du; \ - Bko = ROL64(A##mu, 8); \ - A##sa ^= Da; \ - Bku = ROL64(A##sa, 18); \ - E##ka = Bka ^( Bke | Bki ); \ - E##ke = Bke ^( Bki & Bko ); \ - E##ki = Bki ^((~Bko)& Bku ); \ - E##ko = (~Bko)^( Bku | Bka ); \ - E##ku = Bku ^( Bka & Bke ); \ -\ - A##bu ^= Du; \ - Bma = ROL64(A##bu, 27); \ - A##ga ^= Da; \ - Bme = ROL64(A##ga, 36); \ - A##ke ^= De; \ - Bmi = ROL64(A##ke, 10); \ - A##mi ^= Di; \ - Bmo = ROL64(A##mi, 15); \ - A##so ^= Do; \ - Bmu = ROL64(A##so, 56); \ - E##ma = Bma ^( Bme & Bmi ); \ - E##me = Bme ^( Bmi | Bmo ); \ - E##mi = Bmi ^((~Bmo)| Bmu ); \ - E##mo = (~Bmo)^( Bmu & Bma ); \ - E##mu = Bmu ^( Bma | Bme ); \ -\ - A##bi ^= Di; \ - Bsa = ROL64(A##bi, 62); \ - A##go ^= Do; \ - Bse = ROL64(A##go, 55); \ - A##ku ^= Du; \ - Bsi = ROL64(A##ku, 39); \ - A##ma ^= Da; \ - Bso = ROL64(A##ma, 41); \ - A##se ^= De; \ - Bsu = ROL64(A##se, 2); \ - E##sa = Bsa ^((~Bse)& Bsi ); \ - E##se = (~Bse)^( Bsi | Bso ); \ - E##si = Bsi ^( Bso & Bsu ); \ - E##so = Bso ^( Bsu | Bsa ); \ - E##su = Bsu ^( Bsa & Bse ); \ -\ - -#else /* UseBebigokimisa */ -/* --- Code for round, with prepare-theta */ -/* --- 64-bit lanes mapped to 64-bit words */ -#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ - Da = Cu^ROL64(Ce, 1); \ - De = Ca^ROL64(Ci, 1); \ - Di = Ce^ROL64(Co, 1); \ - Do = Ci^ROL64(Cu, 1); \ - Du = Co^ROL64(Ca, 1); \ -\ - A##ba ^= Da; \ - Bba = A##ba; \ - A##ge ^= De; \ - Bbe = ROL64(A##ge, 44); \ - A##ki ^= Di; \ - Bbi = ROL64(A##ki, 43); \ - A##mo ^= Do; \ - Bbo = ROL64(A##mo, 21); \ - A##su ^= Du; \ - Bbu = ROL64(A##su, 14); \ - E##ba = Bba ^((~Bbe)& Bbi ); \ - E##ba ^= KeccakF1600RoundConstants[i]; \ - Ca = E##ba; \ - E##be = Bbe ^((~Bbi)& Bbo ); \ - Ce = E##be; \ - E##bi = Bbi ^((~Bbo)& Bbu ); \ - Ci = E##bi; \ - E##bo = Bbo ^((~Bbu)& Bba ); \ - Co = E##bo; \ - E##bu = Bbu ^((~Bba)& Bbe ); \ - Cu = E##bu; \ -\ - A##bo ^= Do; \ - Bga = ROL64(A##bo, 28); \ - A##gu ^= Du; \ - Bge = ROL64(A##gu, 20); \ - A##ka ^= Da; \ - Bgi = ROL64(A##ka, 3); \ - A##me ^= De; \ - Bgo = ROL64(A##me, 45); \ - A##si ^= Di; \ - Bgu = ROL64(A##si, 61); \ - E##ga = Bga ^((~Bge)& Bgi ); \ - Ca ^= E##ga; \ - E##ge = Bge ^((~Bgi)& Bgo ); \ - Ce ^= E##ge; \ - E##gi = Bgi ^((~Bgo)& Bgu ); \ - Ci ^= E##gi; \ - E##go = Bgo ^((~Bgu)& Bga ); \ - Co ^= E##go; \ - E##gu = Bgu ^((~Bga)& Bge ); \ - Cu ^= E##gu; \ -\ - A##be ^= De; \ - Bka = ROL64(A##be, 1); \ - A##gi ^= Di; \ - Bke = ROL64(A##gi, 6); \ - A##ko ^= Do; \ - Bki = ROL64(A##ko, 25); \ - A##mu ^= Du; \ - Bko = ROL64(A##mu, 8); \ - A##sa ^= Da; \ - Bku = ROL64(A##sa, 18); \ - E##ka = Bka ^((~Bke)& Bki ); \ - Ca ^= E##ka; \ - E##ke = Bke ^((~Bki)& Bko ); \ - Ce ^= E##ke; \ - E##ki = Bki ^((~Bko)& Bku ); \ - Ci ^= E##ki; \ - E##ko = Bko ^((~Bku)& Bka ); \ - Co ^= E##ko; \ - E##ku = Bku ^((~Bka)& Bke ); \ - Cu ^= E##ku; \ -\ - A##bu ^= Du; \ - Bma = ROL64(A##bu, 27); \ - A##ga ^= Da; \ - Bme = ROL64(A##ga, 36); \ - A##ke ^= De; \ - Bmi = ROL64(A##ke, 10); \ - A##mi ^= Di; \ - Bmo = ROL64(A##mi, 15); \ - A##so ^= Do; \ - Bmu = ROL64(A##so, 56); \ - E##ma = Bma ^((~Bme)& Bmi ); \ - Ca ^= E##ma; \ - E##me = Bme ^((~Bmi)& Bmo ); \ - Ce ^= E##me; \ - E##mi = Bmi ^((~Bmo)& Bmu ); \ - Ci ^= E##mi; \ - E##mo = Bmo ^((~Bmu)& Bma ); \ - Co ^= E##mo; \ - E##mu = Bmu ^((~Bma)& Bme ); \ - Cu ^= E##mu; \ -\ - A##bi ^= Di; \ - Bsa = ROL64(A##bi, 62); \ - A##go ^= Do; \ - Bse = ROL64(A##go, 55); \ - A##ku ^= Du; \ - Bsi = ROL64(A##ku, 39); \ - A##ma ^= Da; \ - Bso = ROL64(A##ma, 41); \ - A##se ^= De; \ - Bsu = ROL64(A##se, 2); \ - E##sa = Bsa ^((~Bse)& Bsi ); \ - Ca ^= E##sa; \ - E##se = Bse ^((~Bsi)& Bso ); \ - Ce ^= E##se; \ - E##si = Bsi ^((~Bso)& Bsu ); \ - Ci ^= E##si; \ - E##so = Bso ^((~Bsu)& Bsa ); \ - Co ^= E##so; \ - E##su = Bsu ^((~Bsa)& Bse ); \ - Cu ^= E##su; \ -\ - -/* --- Code for round */ -/* --- 64-bit lanes mapped to 64-bit words */ -#define thetaRhoPiChiIota(i, A, E) \ - Da = Cu^ROL64(Ce, 1); \ - De = Ca^ROL64(Ci, 1); \ - Di = Ce^ROL64(Co, 1); \ - Do = Ci^ROL64(Cu, 1); \ - Du = Co^ROL64(Ca, 1); \ -\ - A##ba ^= Da; \ - Bba = A##ba; \ - A##ge ^= De; \ - Bbe = ROL64(A##ge, 44); \ - A##ki ^= Di; \ - Bbi = ROL64(A##ki, 43); \ - A##mo ^= Do; \ - Bbo = ROL64(A##mo, 21); \ - A##su ^= Du; \ - Bbu = ROL64(A##su, 14); \ - E##ba = Bba ^((~Bbe)& Bbi ); \ - E##ba ^= KeccakF1600RoundConstants[i]; \ - E##be = Bbe ^((~Bbi)& Bbo ); \ - E##bi = Bbi ^((~Bbo)& Bbu ); \ - E##bo = Bbo ^((~Bbu)& Bba ); \ - E##bu = Bbu ^((~Bba)& Bbe ); \ -\ - A##bo ^= Do; \ - Bga = ROL64(A##bo, 28); \ - A##gu ^= Du; \ - Bge = ROL64(A##gu, 20); \ - A##ka ^= Da; \ - Bgi = ROL64(A##ka, 3); \ - A##me ^= De; \ - Bgo = ROL64(A##me, 45); \ - A##si ^= Di; \ - Bgu = ROL64(A##si, 61); \ - E##ga = Bga ^((~Bge)& Bgi ); \ - E##ge = Bge ^((~Bgi)& Bgo ); \ - E##gi = Bgi ^((~Bgo)& Bgu ); \ - E##go = Bgo ^((~Bgu)& Bga ); \ - E##gu = Bgu ^((~Bga)& Bge ); \ -\ - A##be ^= De; \ - Bka = ROL64(A##be, 1); \ - A##gi ^= Di; \ - Bke = ROL64(A##gi, 6); \ - A##ko ^= Do; \ - Bki = ROL64(A##ko, 25); \ - A##mu ^= Du; \ - Bko = ROL64(A##mu, 8); \ - A##sa ^= Da; \ - Bku = ROL64(A##sa, 18); \ - E##ka = Bka ^((~Bke)& Bki ); \ - E##ke = Bke ^((~Bki)& Bko ); \ - E##ki = Bki ^((~Bko)& Bku ); \ - E##ko = Bko ^((~Bku)& Bka ); \ - E##ku = Bku ^((~Bka)& Bke ); \ -\ - A##bu ^= Du; \ - Bma = ROL64(A##bu, 27); \ - A##ga ^= Da; \ - Bme = ROL64(A##ga, 36); \ - A##ke ^= De; \ - Bmi = ROL64(A##ke, 10); \ - A##mi ^= Di; \ - Bmo = ROL64(A##mi, 15); \ - A##so ^= Do; \ - Bmu = ROL64(A##so, 56); \ - E##ma = Bma ^((~Bme)& Bmi ); \ - E##me = Bme ^((~Bmi)& Bmo ); \ - E##mi = Bmi ^((~Bmo)& Bmu ); \ - E##mo = Bmo ^((~Bmu)& Bma ); \ - E##mu = Bmu ^((~Bma)& Bme ); \ -\ - A##bi ^= Di; \ - Bsa = ROL64(A##bi, 62); \ - A##go ^= Do; \ - Bse = ROL64(A##go, 55); \ - A##ku ^= Du; \ - Bsi = ROL64(A##ku, 39); \ - A##ma ^= Da; \ - Bso = ROL64(A##ma, 41); \ - A##se ^= De; \ - Bsu = ROL64(A##se, 2); \ - E##sa = Bsa ^((~Bse)& Bsi ); \ - E##se = Bse ^((~Bsi)& Bso ); \ - E##si = Bsi ^((~Bso)& Bsu ); \ - E##so = Bso ^((~Bsu)& Bsa ); \ - E##su = Bsu ^((~Bsa)& Bse ); \ -\ - -#endif /* UseBebigokimisa */ - -static const UINT64 KeccakF1600RoundConstants[24] = { - 0x0000000000000001ULL, - 0x0000000000008082ULL, - 0x800000000000808aULL, - 0x8000000080008000ULL, - 0x000000000000808bULL, - 0x0000000080000001ULL, - 0x8000000080008081ULL, - 0x8000000000008009ULL, - 0x000000000000008aULL, - 0x0000000000000088ULL, - 0x0000000080008009ULL, - 0x000000008000000aULL, - 0x000000008000808bULL, - 0x800000000000008bULL, - 0x8000000000008089ULL, - 0x8000000000008003ULL, - 0x8000000000008002ULL, - 0x8000000000000080ULL, - 0x000000000000800aULL, - 0x800000008000000aULL, - 0x8000000080008081ULL, - 0x8000000000008080ULL, - 0x0000000080000001ULL, - 0x8000000080008008ULL }; - -#define copyFromStateAndXor576bits(X, state, input) \ - X##ba = state[ 0]^input[ 0]; \ - X##be = state[ 1]^input[ 1]; \ - X##bi = state[ 2]^input[ 2]; \ - X##bo = state[ 3]^input[ 3]; \ - X##bu = state[ 4]^input[ 4]; \ - X##ga = state[ 5]^input[ 5]; \ - X##ge = state[ 6]^input[ 6]; \ - X##gi = state[ 7]^input[ 7]; \ - X##go = state[ 8]^input[ 8]; \ - X##gu = state[ 9]; \ - X##ka = state[10]; \ - X##ke = state[11]; \ - X##ki = state[12]; \ - X##ko = state[13]; \ - X##ku = state[14]; \ - X##ma = state[15]; \ - X##me = state[16]; \ - X##mi = state[17]; \ - X##mo = state[18]; \ - X##mu = state[19]; \ - X##sa = state[20]; \ - X##se = state[21]; \ - X##si = state[22]; \ - X##so = state[23]; \ - X##su = state[24]; \ - -#define copyFromStateAndXor832bits(X, state, input) \ - X##ba = state[ 0]^input[ 0]; \ - X##be = state[ 1]^input[ 1]; \ - X##bi = state[ 2]^input[ 2]; \ - X##bo = state[ 3]^input[ 3]; \ - X##bu = state[ 4]^input[ 4]; \ - X##ga = state[ 5]^input[ 5]; \ - X##ge = state[ 6]^input[ 6]; \ - X##gi = state[ 7]^input[ 7]; \ - X##go = state[ 8]^input[ 8]; \ - X##gu = state[ 9]^input[ 9]; \ - X##ka = state[10]^input[10]; \ - X##ke = state[11]^input[11]; \ - X##ki = state[12]^input[12]; \ - X##ko = state[13]; \ - X##ku = state[14]; \ - X##ma = state[15]; \ - X##me = state[16]; \ - X##mi = state[17]; \ - X##mo = state[18]; \ - X##mu = state[19]; \ - X##sa = state[20]; \ - X##se = state[21]; \ - X##si = state[22]; \ - X##so = state[23]; \ - X##su = state[24]; \ - -#define copyFromStateAndXor1024bits(X, state, input) \ - X##ba = state[ 0]^input[ 0]; \ - X##be = state[ 1]^input[ 1]; \ - X##bi = state[ 2]^input[ 2]; \ - X##bo = state[ 3]^input[ 3]; \ - X##bu = state[ 4]^input[ 4]; \ - X##ga = state[ 5]^input[ 5]; \ - X##ge = state[ 6]^input[ 6]; \ - X##gi = state[ 7]^input[ 7]; \ - X##go = state[ 8]^input[ 8]; \ - X##gu = state[ 9]^input[ 9]; \ - X##ka = state[10]^input[10]; \ - X##ke = state[11]^input[11]; \ - X##ki = state[12]^input[12]; \ - X##ko = state[13]^input[13]; \ - X##ku = state[14]^input[14]; \ - X##ma = state[15]^input[15]; \ - X##me = state[16]; \ - X##mi = state[17]; \ - X##mo = state[18]; \ - X##mu = state[19]; \ - X##sa = state[20]; \ - X##se = state[21]; \ - X##si = state[22]; \ - X##so = state[23]; \ - X##su = state[24]; \ - -#define copyFromStateAndXor1088bits(X, state, input) \ - X##ba = state[ 0]^input[ 0]; \ - X##be = state[ 1]^input[ 1]; \ - X##bi = state[ 2]^input[ 2]; \ - X##bo = state[ 3]^input[ 3]; \ - X##bu = state[ 4]^input[ 4]; \ - X##ga = state[ 5]^input[ 5]; \ - X##ge = state[ 6]^input[ 6]; \ - X##gi = state[ 7]^input[ 7]; \ - X##go = state[ 8]^input[ 8]; \ - X##gu = state[ 9]^input[ 9]; \ - X##ka = state[10]^input[10]; \ - X##ke = state[11]^input[11]; \ - X##ki = state[12]^input[12]; \ - X##ko = state[13]^input[13]; \ - X##ku = state[14]^input[14]; \ - X##ma = state[15]^input[15]; \ - X##me = state[16]^input[16]; \ - X##mi = state[17]; \ - X##mo = state[18]; \ - X##mu = state[19]; \ - X##sa = state[20]; \ - X##se = state[21]; \ - X##si = state[22]; \ - X##so = state[23]; \ - X##su = state[24]; \ - -#define copyFromStateAndXor1152bits(X, state, input) \ - X##ba = state[ 0]^input[ 0]; \ - X##be = state[ 1]^input[ 1]; \ - X##bi = state[ 2]^input[ 2]; \ - X##bo = state[ 3]^input[ 3]; \ - X##bu = state[ 4]^input[ 4]; \ - X##ga = state[ 5]^input[ 5]; \ - X##ge = state[ 6]^input[ 6]; \ - X##gi = state[ 7]^input[ 7]; \ - X##go = state[ 8]^input[ 8]; \ - X##gu = state[ 9]^input[ 9]; \ - X##ka = state[10]^input[10]; \ - X##ke = state[11]^input[11]; \ - X##ki = state[12]^input[12]; \ - X##ko = state[13]^input[13]; \ - X##ku = state[14]^input[14]; \ - X##ma = state[15]^input[15]; \ - X##me = state[16]^input[16]; \ - X##mi = state[17]^input[17]; \ - X##mo = state[18]; \ - X##mu = state[19]; \ - X##sa = state[20]; \ - X##se = state[21]; \ - X##si = state[22]; \ - X##so = state[23]; \ - X##su = state[24]; \ - -#define copyFromStateAndXor1344bits(X, state, input) \ - X##ba = state[ 0]^input[ 0]; \ - X##be = state[ 1]^input[ 1]; \ - X##bi = state[ 2]^input[ 2]; \ - X##bo = state[ 3]^input[ 3]; \ - X##bu = state[ 4]^input[ 4]; \ - X##ga = state[ 5]^input[ 5]; \ - X##ge = state[ 6]^input[ 6]; \ - X##gi = state[ 7]^input[ 7]; \ - X##go = state[ 8]^input[ 8]; \ - X##gu = state[ 9]^input[ 9]; \ - X##ka = state[10]^input[10]; \ - X##ke = state[11]^input[11]; \ - X##ki = state[12]^input[12]; \ - X##ko = state[13]^input[13]; \ - X##ku = state[14]^input[14]; \ - X##ma = state[15]^input[15]; \ - X##me = state[16]^input[16]; \ - X##mi = state[17]^input[17]; \ - X##mo = state[18]^input[18]; \ - X##mu = state[19]^input[19]; \ - X##sa = state[20]^input[20]; \ - X##se = state[21]; \ - X##si = state[22]; \ - X##so = state[23]; \ - X##su = state[24]; \ - -#define copyFromState(X, state) \ - X##ba = state[ 0]; \ - X##be = state[ 1]; \ - X##bi = state[ 2]; \ - X##bo = state[ 3]; \ - X##bu = state[ 4]; \ - X##ga = state[ 5]; \ - X##ge = state[ 6]; \ - X##gi = state[ 7]; \ - X##go = state[ 8]; \ - X##gu = state[ 9]; \ - X##ka = state[10]; \ - X##ke = state[11]; \ - X##ki = state[12]; \ - X##ko = state[13]; \ - X##ku = state[14]; \ - X##ma = state[15]; \ - X##me = state[16]; \ - X##mi = state[17]; \ - X##mo = state[18]; \ - X##mu = state[19]; \ - X##sa = state[20]; \ - X##se = state[21]; \ - X##si = state[22]; \ - X##so = state[23]; \ - X##su = state[24]; \ - -#define copyToState(state, X) \ - state[ 0] = X##ba; \ - state[ 1] = X##be; \ - state[ 2] = X##bi; \ - state[ 3] = X##bo; \ - state[ 4] = X##bu; \ - state[ 5] = X##ga; \ - state[ 6] = X##ge; \ - state[ 7] = X##gi; \ - state[ 8] = X##go; \ - state[ 9] = X##gu; \ - state[10] = X##ka; \ - state[11] = X##ke; \ - state[12] = X##ki; \ - state[13] = X##ko; \ - state[14] = X##ku; \ - state[15] = X##ma; \ - state[16] = X##me; \ - state[17] = X##mi; \ - state[18] = X##mo; \ - state[19] = X##mu; \ - state[20] = X##sa; \ - state[21] = X##se; \ - state[22] = X##si; \ - state[23] = X##so; \ - state[24] = X##su; \ - -#define copyStateVariables(X, Y) \ - X##ba = Y##ba; \ - X##be = Y##be; \ - X##bi = Y##bi; \ - X##bo = Y##bo; \ - X##bu = Y##bu; \ - X##ga = Y##ga; \ - X##ge = Y##ge; \ - X##gi = Y##gi; \ - X##go = Y##go; \ - X##gu = Y##gu; \ - X##ka = Y##ka; \ - X##ke = Y##ke; \ - X##ki = Y##ki; \ - X##ko = Y##ko; \ - X##ku = Y##ku; \ - X##ma = Y##ma; \ - X##me = Y##me; \ - X##mi = Y##mi; \ - X##mo = Y##mo; \ - X##mu = Y##mu; \ - X##sa = Y##sa; \ - X##se = Y##se; \ - X##si = Y##si; \ - X##so = Y##so; \ - X##su = Y##su; \ - diff --git a/Modules/_sha3/keccak/KeccakF-1600-int-set.h b/Modules/_sha3/keccak/KeccakF-1600-int-set.h deleted file mode 100644 --- a/Modules/_sha3/keccak/KeccakF-1600-int-set.h +++ /dev/null @@ -1,6 +0,0 @@ -#define ProvideFast576 -#define ProvideFast832 -#define ProvideFast1024 -#define ProvideFast1088 -#define ProvideFast1152 -#define ProvideFast1344 diff --git a/Modules/_sha3/keccak/KeccakF-1600-interface.h b/Modules/_sha3/keccak/KeccakF-1600-interface.h deleted file mode 100644 --- a/Modules/_sha3/keccak/KeccakF-1600-interface.h +++ /dev/null @@ -1,46 +0,0 @@ -/* -The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, -Micha?l Peeters and Gilles Van Assche. For more information, feedback or -questions, please refer to our website: http://keccak.noekeon.org/ - -Implementation by the designers, -hereby denoted as "the implementer". - -To the extent possible under law, the implementer has waived all copyright -and related or neighboring rights to the source code in this file. -http://creativecommons.org/publicdomain/zero/1.0/ -*/ - -#ifndef _KeccakPermutationInterface_h_ -#define _KeccakPermutationInterface_h_ - -#include "KeccakF-1600-int-set.h" - -static void KeccakInitialize( void ); -static void KeccakInitializeState(unsigned char *state); -static void KeccakPermutation(unsigned char *state); -#ifdef ProvideFast576 -static void KeccakAbsorb576bits(unsigned char *state, const unsigned char *data); -#endif -#ifdef ProvideFast832 -static void KeccakAbsorb832bits(unsigned char *state, const unsigned char *data); -#endif -#ifdef ProvideFast1024 -static void KeccakAbsorb1024bits(unsigned char *state, const unsigned char *data); -#endif -#ifdef ProvideFast1088 -static void KeccakAbsorb1088bits(unsigned char *state, const unsigned char *data); -#endif -#ifdef ProvideFast1152 -static void KeccakAbsorb1152bits(unsigned char *state, const unsigned char *data); -#endif -#ifdef ProvideFast1344 -static void KeccakAbsorb1344bits(unsigned char *state, const unsigned char *data); -#endif -static void KeccakAbsorb(unsigned char *state, const unsigned char *data, unsigned int laneCount); -#ifdef ProvideFast1024 -static void KeccakExtract1024bits(const unsigned char *state, unsigned char *data); -#endif -static void KeccakExtract(const unsigned char *state, unsigned char *data, unsigned int laneCount); - -#endif diff --git a/Modules/_sha3/keccak/KeccakF-1600-opt32-settings.h b/Modules/_sha3/keccak/KeccakF-1600-opt32-settings.h deleted file mode 100644 --- a/Modules/_sha3/keccak/KeccakF-1600-opt32-settings.h +++ /dev/null @@ -1,6 +0,0 @@ -/* -#define Unrolling 2 -#define UseBebigokimisa -#define UseInterleaveTables -#define UseSchedule 3 -*/ diff --git a/Modules/_sha3/keccak/KeccakF-1600-opt32.c b/Modules/_sha3/keccak/KeccakF-1600-opt32.c deleted file mode 100644 --- a/Modules/_sha3/keccak/KeccakF-1600-opt32.c +++ /dev/null @@ -1,524 +0,0 @@ -/* -The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, -Micha?l Peeters and Gilles Van Assche. For more information, feedback or -questions, please refer to our website: http://keccak.noekeon.org/ - -Implementation by the designers, -hereby denoted as "the implementer". - -To the extent possible under law, the implementer has waived all copyright -and related or neighboring rights to the source code in this file. -http://creativecommons.org/publicdomain/zero/1.0/ -*/ - -#include -/* #include "brg_endian.h" */ -#include "KeccakF-1600-opt32-settings.h" -#include "KeccakF-1600-interface.h" - -typedef unsigned char UINT8; -typedef unsigned short UINT16; -typedef unsigned int UINT32; -/* typedef unsigned long long int UINT64; */ - -#ifdef UseInterleaveTables -static int interleaveTablesBuilt = 0; -static UINT16 interleaveTable[65536]; -static UINT16 deinterleaveTable[65536]; - -static void buildInterleaveTables() -{ - UINT32 i, j; - UINT16 x; - - if (!interleaveTablesBuilt) { - for(i=0; i<65536; i++) { - x = 0; - for(j=0; j<16; j++) { - if (i & (1 << j)) - x |= (1 << (j/2 + 8*(j%2))); - } - interleaveTable[i] = x; - deinterleaveTable[x] = (UINT16)i; - } - interleaveTablesBuilt = 1; - } -} - -#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN) - -#define xor2bytesIntoInterleavedWords(even, odd, source, j) \ - i##j = interleaveTable[((const UINT16*)source)[j]]; \ - ((UINT8*)even)[j] ^= i##j & 0xFF; \ - ((UINT8*)odd)[j] ^= i##j >> 8; - -#define setInterleavedWordsInto2bytes(dest, even, odd, j) \ - d##j = deinterleaveTable[((even >> (j*8)) & 0xFF) ^ (((odd >> (j*8)) & 0xFF) << 8)]; \ - ((UINT16*)dest)[j] = d##j; - -#else /* (PLATFORM_BYTE_ORDER == IS_BIG_ENDIAN) */ - -#define xor2bytesIntoInterleavedWords(even, odd, source, j) \ - i##j = interleaveTable[source[2*j] ^ ((UINT16)source[2*j+1] << 8)]; \ - *even ^= (i##j & 0xFF) << (j*8); \ - *odd ^= ((i##j >> 8) & 0xFF) << (j*8); - -#define setInterleavedWordsInto2bytes(dest, even, odd, j) \ - d##j = deinterleaveTable[((even >> (j*8)) & 0xFF) ^ (((odd >> (j*8)) & 0xFF) << 8)]; \ - dest[2*j] = d##j & 0xFF; \ - dest[2*j+1] = d##j >> 8; - -#endif /* Endianness */ - -static void xor8bytesIntoInterleavedWords(UINT32 *even, UINT32 *odd, const UINT8* source) -{ - UINT16 i0, i1, i2, i3; - - xor2bytesIntoInterleavedWords(even, odd, source, 0) - xor2bytesIntoInterleavedWords(even, odd, source, 1) - xor2bytesIntoInterleavedWords(even, odd, source, 2) - xor2bytesIntoInterleavedWords(even, odd, source, 3) -} - -#define xorLanesIntoState(laneCount, state, input) \ - { \ - int i; \ - for(i=0; i<(laneCount); i++) \ - xor8bytesIntoInterleavedWords(state+i*2, state+i*2+1, input+i*8); \ - } - -static void setInterleavedWordsInto8bytes(UINT8* dest, UINT32 even, UINT32 odd) -{ - UINT16 d0, d1, d2, d3; - - setInterleavedWordsInto2bytes(dest, even, odd, 0) - setInterleavedWordsInto2bytes(dest, even, odd, 1) - setInterleavedWordsInto2bytes(dest, even, odd, 2) - setInterleavedWordsInto2bytes(dest, even, odd, 3) -} - -#define extractLanes(laneCount, state, data) \ - { \ - int i; \ - for(i=0; i<(laneCount); i++) \ - setInterleavedWordsInto8bytes(data+i*8, ((UINT32*)state)[i*2], ((UINT32*)state)[i*2+1]); \ - } - -#else /* No interleaving tables */ - -#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN) - -/* Credit: Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */ -#define xorInterleavedLE(rateInLanes, state, input) \ - { \ - const UINT32 * pI = (const UINT32 *)input; \ - UINT32 * pS = state; \ - UINT32 t, x0, x1; \ - int i; \ - for (i = (rateInLanes)-1; i >= 0; --i) \ - { \ - x0 = *(pI++); \ - t = (x0 ^ (x0 >> 1)) & 0x22222222UL; x0 = x0 ^ t ^ (t << 1); \ - t = (x0 ^ (x0 >> 2)) & 0x0C0C0C0CUL; x0 = x0 ^ t ^ (t << 2); \ - t = (x0 ^ (x0 >> 4)) & 0x00F000F0UL; x0 = x0 ^ t ^ (t << 4); \ - t = (x0 ^ (x0 >> 8)) & 0x0000FF00UL; x0 = x0 ^ t ^ (t << 8); \ - x1 = *(pI++); \ - t = (x1 ^ (x1 >> 1)) & 0x22222222UL; x1 = x1 ^ t ^ (t << 1); \ - t = (x1 ^ (x1 >> 2)) & 0x0C0C0C0CUL; x1 = x1 ^ t ^ (t << 2); \ - t = (x1 ^ (x1 >> 4)) & 0x00F000F0UL; x1 = x1 ^ t ^ (t << 4); \ - t = (x1 ^ (x1 >> 8)) & 0x0000FF00UL; x1 = x1 ^ t ^ (t << 8); \ - *(pS++) ^= (UINT16)x0 | (x1 << 16); \ - *(pS++) ^= (x0 >> 16) | (x1 & 0xFFFF0000); \ - } \ - } - -#define xorLanesIntoState(laneCount, state, input) \ - xorInterleavedLE(laneCount, state, input) - -#else /* (PLATFORM_BYTE_ORDER == IS_BIG_ENDIAN) */ - -/* Credit: Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */ -UINT64 toInterleaving(UINT64 x) -{ - UINT64 t; - - t = (x ^ (x >> 1)) & 0x2222222222222222ULL; x = x ^ t ^ (t << 1); - t = (x ^ (x >> 2)) & 0x0C0C0C0C0C0C0C0CULL; x = x ^ t ^ (t << 2); - t = (x ^ (x >> 4)) & 0x00F000F000F000F0ULL; x = x ^ t ^ (t << 4); - t = (x ^ (x >> 8)) & 0x0000FF000000FF00ULL; x = x ^ t ^ (t << 8); - t = (x ^ (x >> 16)) & 0x00000000FFFF0000ULL; x = x ^ t ^ (t << 16); - - return x; -} - -static void xor8bytesIntoInterleavedWords(UINT32* evenAndOdd, const UINT8* source) -{ - /* This can be optimized */ - UINT64 sourceWord = - (UINT64)source[0] - ^ (((UINT64)source[1]) << 8) - ^ (((UINT64)source[2]) << 16) - ^ (((UINT64)source[3]) << 24) - ^ (((UINT64)source[4]) << 32) - ^ (((UINT64)source[5]) << 40) - ^ (((UINT64)source[6]) << 48) - ^ (((UINT64)source[7]) << 56); - UINT64 evenAndOddWord = toInterleaving(sourceWord); - evenAndOdd[0] ^= (UINT32)evenAndOddWord; - evenAndOdd[1] ^= (UINT32)(evenAndOddWord >> 32); -} - -#define xorLanesIntoState(laneCount, state, input) \ - { \ - int i; \ - for(i=0; i<(laneCount); i++) \ - xor8bytesIntoInterleavedWords(state+i*2, input+i*8); \ - } - -#endif /* Endianness */ - -/* Credit: Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */ -UINT64 fromInterleaving(UINT64 x) -{ - UINT64 t; - - t = (x ^ (x >> 16)) & 0x00000000FFFF0000ULL; x = x ^ t ^ (t << 16); - t = (x ^ (x >> 8)) & 0x0000FF000000FF00ULL; x = x ^ t ^ (t << 8); - t = (x ^ (x >> 4)) & 0x00F000F000F000F0ULL; x = x ^ t ^ (t << 4); - t = (x ^ (x >> 2)) & 0x0C0C0C0C0C0C0C0CULL; x = x ^ t ^ (t << 2); - t = (x ^ (x >> 1)) & 0x2222222222222222ULL; x = x ^ t ^ (t << 1); - - return x; -} - -static void setInterleavedWordsInto8bytes(UINT8* dest, UINT32* evenAndOdd) -{ -#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN) - ((UINT64*)dest)[0] = fromInterleaving(*(UINT64*)evenAndOdd); -#else /* (PLATFORM_BYTE_ORDER == IS_BIG_ENDIAN) */ - /* This can be optimized */ - UINT64 evenAndOddWord = (UINT64)evenAndOdd[0] ^ ((UINT64)evenAndOdd[1] << 32); - UINT64 destWord = fromInterleaving(evenAndOddWord); - dest[0] = destWord & 0xFF; - dest[1] = (destWord >> 8) & 0xFF; - dest[2] = (destWord >> 16) & 0xFF; - dest[3] = (destWord >> 24) & 0xFF; - dest[4] = (destWord >> 32) & 0xFF; - dest[5] = (destWord >> 40) & 0xFF; - dest[6] = (destWord >> 48) & 0xFF; - dest[7] = (destWord >> 56) & 0xFF; -#endif /* Endianness */ -} - -#define extractLanes(laneCount, state, data) \ - { \ - unsigned int i; \ - for(i=0; i<(laneCount); i++) \ - setInterleavedWordsInto8bytes(data+i*8, (UINT32*)state+i*2); \ - } - -#endif /* With or without interleaving tables */ - -#if defined(_MSC_VER) -#define ROL32(a, offset) _rotl(a, offset) -#elif (defined (__arm__) && defined(__ARMCC_VERSION)) -#define ROL32(a, offset) __ror(a, 32-(offset)) -#else -#define ROL32(a, offset) ((((UINT32)a) << (offset)) ^ (((UINT32)a) >> (32-(offset)))) -#endif - -#include "KeccakF-1600-unrolling.macros" -#include "KeccakF-1600-32.macros" - -#if (UseSchedule == 3) - -#ifdef UseBebigokimisa -#error "No lane complementing with schedule 3." -#endif - -#if (Unrolling != 2) -#error "Only unrolling 2 is supported by schedule 3." -#endif - -static void KeccakPermutationOnWords(UINT32 *state) -{ - rounds -} - -static void KeccakPermutationOnWordsAfterXoring(UINT32 *state, const UINT8 *input, unsigned int laneCount) -{ - xorLanesIntoState(laneCount, state, input) - rounds -} - -#ifdef ProvideFast576 -static void KeccakPermutationOnWordsAfterXoring576bits(UINT32 *state, const UINT8 *input) -{ - xorLanesIntoState(9, state, input) - rounds -} -#endif - -#ifdef ProvideFast832 -static void KeccakPermutationOnWordsAfterXoring832bits(UINT32 *state, const UINT8 *input) -{ - xorLanesIntoState(13, state, input) - rounds -} -#endif - -#ifdef ProvideFast1024 -static void KeccakPermutationOnWordsAfterXoring1024bits(UINT32 *state, const UINT8 *input) -{ - xorLanesIntoState(16, state, input) - rounds -} -#endif - -#ifdef ProvideFast1088 -static void KeccakPermutationOnWordsAfterXoring1088bits(UINT32 *state, const UINT8 *input) -{ - xorLanesIntoState(17, state, input) - rounds -} -#endif - -#ifdef ProvideFast1152 -static void KeccakPermutationOnWordsAfterXoring1152bits(UINT32 *state, const UINT8 *input) -{ - xorLanesIntoState(18, state, input) - rounds -} -#endif - -#ifdef ProvideFast1344 -static void KeccakPermutationOnWordsAfterXoring1344bits(UINT32 *state, const UINT8 *input) -{ - xorLanesIntoState(21, state, input) - rounds -} -#endif - -#else /* (Schedule != 3) */ - -static void KeccakPermutationOnWords(UINT32 *state) -{ - declareABCDE -#if (Unrolling != 24) - unsigned int i; -#endif - - copyFromState(A, state) - rounds -} - -static void KeccakPermutationOnWordsAfterXoring(UINT32 *state, const UINT8 *input, unsigned int laneCount) -{ - declareABCDE - unsigned int i; - - xorLanesIntoState(laneCount, state, input) - copyFromState(A, state) - rounds -} - -#ifdef ProvideFast576 -static void KeccakPermutationOnWordsAfterXoring576bits(UINT32 *state, const UINT8 *input) -{ - declareABCDE - unsigned int i; - - xorLanesIntoState(9, state, input) - copyFromState(A, state) - rounds -} -#endif - -#ifdef ProvideFast832 -static void KeccakPermutationOnWordsAfterXoring832bits(UINT32 *state, const UINT8 *input) -{ - declareABCDE - unsigned int i; - - xorLanesIntoState(13, state, input) - copyFromState(A, state) - rounds -} -#endif - -#ifdef ProvideFast1024 -static void KeccakPermutationOnWordsAfterXoring1024bits(UINT32 *state, const UINT8 *input) -{ - declareABCDE - unsigned int i; - - xorLanesIntoState(16, state, input) - copyFromState(A, state) - rounds -} -#endif - -#ifdef ProvideFast1088 -static void KeccakPermutationOnWordsAfterXoring1088bits(UINT32 *state, const UINT8 *input) -{ - declareABCDE - unsigned int i; - - xorLanesIntoState(17, state, input) - copyFromState(A, state) - rounds -} -#endif - -#ifdef ProvideFast1152 -static void KeccakPermutationOnWordsAfterXoring1152bits(UINT32 *state, const UINT8 *input) -{ - declareABCDE - unsigned int i; - - xorLanesIntoState(18, state, input) - copyFromState(A, state) - rounds -} -#endif - -#ifdef ProvideFast1344 -static void KeccakPermutationOnWordsAfterXoring1344bits(UINT32 *state, const UINT8 *input) -{ - declareABCDE - unsigned int i; - - xorLanesIntoState(21, state, input) - copyFromState(A, state) - rounds -} -#endif - -#endif - -static void KeccakInitialize() -{ -#ifdef UseInterleaveTables - buildInterleaveTables(); -#endif -} - -static void KeccakInitializeState(unsigned char *state) -{ - memset(state, 0, 200); -#ifdef UseBebigokimisa - ((UINT32*)state)[ 2] = ~(UINT32)0; - ((UINT32*)state)[ 3] = ~(UINT32)0; - ((UINT32*)state)[ 4] = ~(UINT32)0; - ((UINT32*)state)[ 5] = ~(UINT32)0; - ((UINT32*)state)[16] = ~(UINT32)0; - ((UINT32*)state)[17] = ~(UINT32)0; - ((UINT32*)state)[24] = ~(UINT32)0; - ((UINT32*)state)[25] = ~(UINT32)0; - ((UINT32*)state)[34] = ~(UINT32)0; - ((UINT32*)state)[35] = ~(UINT32)0; - ((UINT32*)state)[40] = ~(UINT32)0; - ((UINT32*)state)[41] = ~(UINT32)0; -#endif -} - -static void KeccakPermutation(unsigned char *state) -{ - /* We assume the state is always stored as interleaved 32-bit words */ - KeccakPermutationOnWords((UINT32*)state); -} - -#ifdef ProvideFast576 -static void KeccakAbsorb576bits(unsigned char *state, const unsigned char *data) -{ - KeccakPermutationOnWordsAfterXoring576bits((UINT32*)state, data); -} -#endif - -#ifdef ProvideFast832 -static void KeccakAbsorb832bits(unsigned char *state, const unsigned char *data) -{ - KeccakPermutationOnWordsAfterXoring832bits((UINT32*)state, data); -} -#endif - -#ifdef ProvideFast1024 -static void KeccakAbsorb1024bits(unsigned char *state, const unsigned char *data) -{ - KeccakPermutationOnWordsAfterXoring1024bits((UINT32*)state, data); -} -#endif - -#ifdef ProvideFast1088 -static void KeccakAbsorb1088bits(unsigned char *state, const unsigned char *data) -{ - KeccakPermutationOnWordsAfterXoring1088bits((UINT32*)state, data); -} -#endif - -#ifdef ProvideFast1152 -static void KeccakAbsorb1152bits(unsigned char *state, const unsigned char *data) -{ - KeccakPermutationOnWordsAfterXoring1152bits((UINT32*)state, data); -} -#endif - -#ifdef ProvideFast1344 -static void KeccakAbsorb1344bits(unsigned char *state, const unsigned char *data) -{ - KeccakPermutationOnWordsAfterXoring1344bits((UINT32*)state, data); -} -#endif - -static void KeccakAbsorb(unsigned char *state, const unsigned char *data, unsigned int laneCount) -{ - KeccakPermutationOnWordsAfterXoring((UINT32*)state, data, laneCount); -} - -#ifdef ProvideFast1024 -static void KeccakExtract1024bits(const unsigned char *state, unsigned char *data) -{ - extractLanes(16, state, data) -#ifdef UseBebigokimisa - ((UINT32*)data)[ 2] = ~((UINT32*)data)[ 2]; - ((UINT32*)data)[ 3] = ~((UINT32*)data)[ 3]; - ((UINT32*)data)[ 4] = ~((UINT32*)data)[ 4]; - ((UINT32*)data)[ 5] = ~((UINT32*)data)[ 5]; - ((UINT32*)data)[16] = ~((UINT32*)data)[16]; - ((UINT32*)data)[17] = ~((UINT32*)data)[17]; - ((UINT32*)data)[24] = ~((UINT32*)data)[24]; - ((UINT32*)data)[25] = ~((UINT32*)data)[25]; -#endif -} -#endif - -static void KeccakExtract(const unsigned char *state, unsigned char *data, unsigned int laneCount) -{ - extractLanes(laneCount, state, data) -#ifdef UseBebigokimisa - if (laneCount > 1) { - ((UINT32*)data)[ 2] = ~((UINT32*)data)[ 2]; - ((UINT32*)data)[ 3] = ~((UINT32*)data)[ 3]; - if (laneCount > 2) { - ((UINT32*)data)[ 4] = ~((UINT32*)data)[ 4]; - ((UINT32*)data)[ 5] = ~((UINT32*)data)[ 5]; - if (laneCount > 8) { - ((UINT32*)data)[16] = ~((UINT32*)data)[16]; - ((UINT32*)data)[17] = ~((UINT32*)data)[17]; - if (laneCount > 12) { - ((UINT32*)data)[24] = ~((UINT32*)data)[24]; - ((UINT32*)data)[25] = ~((UINT32*)data)[25]; - if (laneCount > 17) { - ((UINT32*)data)[34] = ~((UINT32*)data)[34]; - ((UINT32*)data)[35] = ~((UINT32*)data)[35]; - if (laneCount > 20) { - ((UINT32*)data)[40] = ~((UINT32*)data)[40]; - ((UINT32*)data)[41] = ~((UINT32*)data)[41]; - } - } - } - } - } - } -#endif -} diff --git a/Modules/_sha3/keccak/KeccakF-1600-opt64-settings.h b/Modules/_sha3/keccak/KeccakF-1600-opt64-settings.h deleted file mode 100644 --- a/Modules/_sha3/keccak/KeccakF-1600-opt64-settings.h +++ /dev/null @@ -1,9 +0,0 @@ -/* -#define Unrolling 24 -#define UseBebigokimisa -#define UseSSE -#define UseOnlySIMD64 -#define UseMMX -#define UseSHLD -#define UseXOP -*/ diff --git a/Modules/_sha3/keccak/KeccakF-1600-opt64.c b/Modules/_sha3/keccak/KeccakF-1600-opt64.c deleted file mode 100644 --- a/Modules/_sha3/keccak/KeccakF-1600-opt64.c +++ /dev/null @@ -1,510 +0,0 @@ -/* -The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, -Micha?l Peeters and Gilles Van Assche. For more information, feedback or -questions, please refer to our website: http://keccak.noekeon.org/ - -Implementation by the designers, -hereby denoted as "the implementer". - -To the extent possible under law, the implementer has waived all copyright -and related or neighboring rights to the source code in this file. -http://creativecommons.org/publicdomain/zero/1.0/ -*/ - -#include -/* #include "brg_endian.h" */ -#include "KeccakF-1600-opt64-settings.h" -#include "KeccakF-1600-interface.h" - -typedef unsigned char UINT8; -/* typedef unsigned long long int UINT64; */ - -#if defined(__GNUC__) -#define ALIGN __attribute__ ((aligned(32))) -#elif defined(_MSC_VER) -#define ALIGN __declspec(align(32)) -#else -#define ALIGN -#endif - -#if defined(UseSSE) - #include - typedef __m128i V64; - typedef __m128i V128; - typedef union { - V128 v128; - UINT64 v64[2]; - } V6464; - - #define ANDnu64(a, b) _mm_andnot_si128(a, b) - #define LOAD64(a) _mm_loadl_epi64((const V64 *)&(a)) - #define CONST64(a) _mm_loadl_epi64((const V64 *)&(a)) - #define ROL64(a, o) _mm_or_si128(_mm_slli_epi64(a, o), _mm_srli_epi64(a, 64-(o))) - #define STORE64(a, b) _mm_storel_epi64((V64 *)&(a), b) - #define XOR64(a, b) _mm_xor_si128(a, b) - #define XOReq64(a, b) a = _mm_xor_si128(a, b) - #define SHUFFLEBYTES128(a, b) _mm_shuffle_epi8(a, b) - - #define ANDnu128(a, b) _mm_andnot_si128(a, b) - #define LOAD6464(a, b) _mm_set_epi64((__m64)(a), (__m64)(b)) - #define CONST128(a) _mm_load_si128((const V128 *)&(a)) - #define LOAD128(a) _mm_load_si128((const V128 *)&(a)) - #define LOAD128u(a) _mm_loadu_si128((const V128 *)&(a)) - #define ROL64in128(a, o) _mm_or_si128(_mm_slli_epi64(a, o), _mm_srli_epi64(a, 64-(o))) - #define STORE128(a, b) _mm_store_si128((V128 *)&(a), b) - #define XOR128(a, b) _mm_xor_si128(a, b) - #define XOReq128(a, b) a = _mm_xor_si128(a, b) - #define GET64LOLO(a, b) _mm_unpacklo_epi64(a, b) - #define GET64HIHI(a, b) _mm_unpackhi_epi64(a, b) - #define COPY64HI2LO(a) _mm_shuffle_epi32(a, 0xEE) - #define COPY64LO2HI(a) _mm_shuffle_epi32(a, 0x44) - #define ZERO128() _mm_setzero_si128() - - #ifdef UseOnlySIMD64 - #include "KeccakF-1600-simd64.macros" - #else -ALIGN const UINT64 rho8_56[2] = {0x0605040302010007, 0x080F0E0D0C0B0A09}; - #include "KeccakF-1600-simd128.macros" - #endif - - #ifdef UseBebigokimisa - #error "UseBebigokimisa cannot be used in combination with UseSSE" - #endif -#elif defined(UseXOP) - #include - typedef __m128i V64; - typedef __m128i V128; - - #define LOAD64(a) _mm_loadl_epi64((const V64 *)&(a)) - #define CONST64(a) _mm_loadl_epi64((const V64 *)&(a)) - #define STORE64(a, b) _mm_storel_epi64((V64 *)&(a), b) - #define XOR64(a, b) _mm_xor_si128(a, b) - #define XOReq64(a, b) a = _mm_xor_si128(a, b) - - #define ANDnu128(a, b) _mm_andnot_si128(a, b) - #define LOAD6464(a, b) _mm_set_epi64((__m64)(a), (__m64)(b)) - #define CONST128(a) _mm_load_si128((const V128 *)&(a)) - #define LOAD128(a) _mm_load_si128((const V128 *)&(a)) - #define LOAD128u(a) _mm_loadu_si128((const V128 *)&(a)) - #define STORE128(a, b) _mm_store_si128((V128 *)&(a), b) - #define XOR128(a, b) _mm_xor_si128(a, b) - #define XOReq128(a, b) a = _mm_xor_si128(a, b) - #define ZERO128() _mm_setzero_si128() - - #define SWAP64(a) _mm_shuffle_epi32(a, 0x4E) - #define GET64LOLO(a, b) _mm_unpacklo_epi64(a, b) - #define GET64HIHI(a, b) _mm_unpackhi_epi64(a, b) - #define GET64LOHI(a, b) ((__m128i)_mm_blend_pd((__m128d)a, (__m128d)b, 2)) - #define GET64HILO(a, b) SWAP64(GET64LOHI(b, a)) - #define COPY64HI2LO(a) _mm_shuffle_epi32(a, 0xEE) - #define COPY64LO2HI(a) _mm_shuffle_epi32(a, 0x44) - - #define ROL6464same(a, o) _mm_roti_epi64(a, o) - #define ROL6464(a, r1, r2) _mm_rot_epi64(a, CONST128( rot_##r1##_##r2 )) -ALIGN const UINT64 rot_0_20[2] = { 0, 20}; -ALIGN const UINT64 rot_44_3[2] = {44, 3}; -ALIGN const UINT64 rot_43_45[2] = {43, 45}; -ALIGN const UINT64 rot_21_61[2] = {21, 61}; -ALIGN const UINT64 rot_14_28[2] = {14, 28}; -ALIGN const UINT64 rot_1_36[2] = { 1, 36}; -ALIGN const UINT64 rot_6_10[2] = { 6, 10}; -ALIGN const UINT64 rot_25_15[2] = {25, 15}; -ALIGN const UINT64 rot_8_56[2] = { 8, 56}; -ALIGN const UINT64 rot_18_27[2] = {18, 27}; -ALIGN const UINT64 rot_62_55[2] = {62, 55}; -ALIGN const UINT64 rot_39_41[2] = {39, 41}; - -#if defined(UseSimulatedXOP) - /* For debugging purposes, when XOP is not available */ - #undef ROL6464 - #undef ROL6464same - #define ROL6464same(a, o) _mm_or_si128(_mm_slli_epi64(a, o), _mm_srli_epi64(a, 64-(o))) - V128 ROL6464(V128 a, int r0, int r1) - { - V128 a0 = ROL64(a, r0); - V128 a1 = COPY64HI2LO(ROL64(a, r1)); - return GET64LOLO(a0, a1); - } -#endif - - #include "KeccakF-1600-xop.macros" - - #ifdef UseBebigokimisa - #error "UseBebigokimisa cannot be used in combination with UseXOP" - #endif -#elif defined(UseMMX) - #include - typedef __m64 V64; - #define ANDnu64(a, b) _mm_andnot_si64(a, b) - - #if (defined(_MSC_VER) || defined (__INTEL_COMPILER)) - #define LOAD64(a) *(V64*)&(a) - #define CONST64(a) *(V64*)&(a) - #define STORE64(a, b) *(V64*)&(a) = b - #else - #define LOAD64(a) (V64)a - #define CONST64(a) (V64)a - #define STORE64(a, b) a = (UINT64)b - #endif - #define ROL64(a, o) _mm_or_si64(_mm_slli_si64(a, o), _mm_srli_si64(a, 64-(o))) - #define XOR64(a, b) _mm_xor_si64(a, b) - #define XOReq64(a, b) a = _mm_xor_si64(a, b) - - #include "KeccakF-1600-simd64.macros" - - #ifdef UseBebigokimisa - #error "UseBebigokimisa cannot be used in combination with UseMMX" - #endif -#else - #if defined(_MSC_VER) - #define ROL64(a, offset) _rotl64(a, offset) - #elif defined(UseSHLD) - #define ROL64(x,N) ({ \ - register UINT64 __out; \ - register UINT64 __in = x; \ - __asm__ ("shld %2,%0,%0" : "=r"(__out) : "0"(__in), "i"(N)); \ - __out; \ - }) - #else - #define ROL64(a, offset) ((((UINT64)a) << offset) ^ (((UINT64)a) >> (64-offset))) - #endif - - #include "KeccakF-1600-64.macros" -#endif - -#include "KeccakF-1600-unrolling.macros" - -static void KeccakPermutationOnWords(UINT64 *state) -{ - declareABCDE -#if (Unrolling != 24) - unsigned int i; -#endif - - copyFromState(A, state) - rounds -#if defined(UseMMX) - _mm_empty(); -#endif -} - -static void KeccakPermutationOnWordsAfterXoring(UINT64 *state, const UINT64 *input, unsigned int laneCount) -{ - declareABCDE -#if (Unrolling != 24) - unsigned int i; -#endif - unsigned int j; - - for(j=0; j> (8*i)) & 0xFF; -} -#endif - - -#ifdef ProvideFast1024 -static void KeccakExtract1024bits(const unsigned char *state, unsigned char *data) -{ -#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN) - memcpy(data, state, 128); -#else - unsigned int i; - - for(i=0; i<16; i++) - fromWordToBytes(data+(i*8), ((const UINT64*)state)[i]); -#endif -#ifdef UseBebigokimisa - ((UINT64*)data)[ 1] = ~((UINT64*)data)[ 1]; - ((UINT64*)data)[ 2] = ~((UINT64*)data)[ 2]; - ((UINT64*)data)[ 8] = ~((UINT64*)data)[ 8]; - ((UINT64*)data)[12] = ~((UINT64*)data)[12]; -#endif -} -#endif - -static void KeccakExtract(const unsigned char *state, unsigned char *data, unsigned int laneCount) -{ -#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN) - memcpy(data, state, laneCount*8); -#else - unsigned int i; - - for(i=0; i 1) { - ((UINT64*)data)[ 1] = ~((UINT64*)data)[ 1]; - if (laneCount > 2) { - ((UINT64*)data)[ 2] = ~((UINT64*)data)[ 2]; - if (laneCount > 8) { - ((UINT64*)data)[ 8] = ~((UINT64*)data)[ 8]; - if (laneCount > 12) { - ((UINT64*)data)[12] = ~((UINT64*)data)[12]; - if (laneCount > 17) { - ((UINT64*)data)[17] = ~((UINT64*)data)[17]; - if (laneCount > 20) { - ((UINT64*)data)[20] = ~((UINT64*)data)[20]; - } - } - } - } - } - } -#endif -} diff --git a/Modules/_sha3/keccak/KeccakF-1600-simd128.macros b/Modules/_sha3/keccak/KeccakF-1600-simd128.macros deleted file mode 100644 --- a/Modules/_sha3/keccak/KeccakF-1600-simd128.macros +++ /dev/null @@ -1,651 +0,0 @@ -/* -The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, -Micha?l Peeters and Gilles Van Assche. For more information, feedback or -questions, please refer to our website: http://keccak.noekeon.org/ - -Implementation by the designers, -hereby denoted as "the implementer". - -To the extent possible under law, the implementer has waived all copyright -and related or neighboring rights to the source code in this file. -http://creativecommons.org/publicdomain/zero/1.0/ -*/ - -#define declareABCDE \ - V6464 Abage, Abegi, Abigo, Abogu, Abuga; \ - V6464 Akame, Akemi, Akimo, Akomu, Akuma; \ - V6464 Abae, Abio, Agae, Agio, Akae, Akio, Amae, Amio, Asae, Asio; \ - V64 Aba, Abe, Abi, Abo, Abu; \ - V64 Aga, Age, Agi, Ago, Agu; \ - V64 Aka, Ake, Aki, Ako, Aku; \ - V64 Ama, Ame, Ami, Amo, Amu; \ - V64 Asa, Ase, Asi, Aso, Asu; \ - V128 Bbage, Bbegi, Bbigo, Bbogu, Bbuga; \ - V128 Bkame, Bkemi, Bkimo, Bkomu, Bkuma; \ - V64 Bba, Bbe, Bbi, Bbo, Bbu; \ - V64 Bga, Bge, Bgi, Bgo, Bgu; \ - V64 Bka, Bke, Bki, Bko, Bku; \ - V64 Bma, Bme, Bmi, Bmo, Bmu; \ - V64 Bsa, Bse, Bsi, Bso, Bsu; \ - V128 Cae, Cei, Cio, Cou, Cua, Dei, Dou; \ - V64 Ca, Ce, Ci, Co, Cu; \ - V64 Da, De, Di, Do, Du; \ - V6464 Ebage, Ebegi, Ebigo, Ebogu, Ebuga; \ - V6464 Ekame, Ekemi, Ekimo, Ekomu, Ekuma; \ - V64 Eba, Ebe, Ebi, Ebo, Ebu; \ - V64 Ega, Ege, Egi, Ego, Egu; \ - V64 Eka, Eke, Eki, Eko, Eku; \ - V64 Ema, Eme, Emi, Emo, Emu; \ - V64 Esa, Ese, Esi, Eso, Esu; \ - V128 Zero; - -#define prepareTheta - -#define computeD \ - Cua = GET64LOLO(Cu, Cae); \ - Dei = XOR128(Cae, ROL64in128(Cio, 1)); \ - Dou = XOR128(Cio, ROL64in128(Cua, 1)); \ - Da = XOR64(Cu, ROL64in128(COPY64HI2LO(Cae), 1)); \ - De = Dei; \ - Di = COPY64HI2LO(Dei); \ - Do = Dou; \ - Du = COPY64HI2LO(Dou); - -/* --- Theta Rho Pi Chi Iota Prepare-theta */ -/* --- 64-bit lanes mapped to 64-bit and 128-bit words */ -#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ - computeD \ - \ - A##ba = LOAD64(A##bage.v64[0]); \ - XOReq64(A##ba, Da); \ - Bba = A##ba; \ - XOReq64(A##gu, Du); \ - Bge = ROL64(A##gu, 20); \ - Bbage = GET64LOLO(Bba, Bge); \ - A##ge = LOAD64(A##bage.v64[1]); \ - XOReq64(A##ge, De); \ - Bbe = ROL64(A##ge, 44); \ - A##ka = LOAD64(A##kame.v64[0]); \ - XOReq64(A##ka, Da); \ - Bgi = ROL64(A##ka, 3); \ - Bbegi = GET64LOLO(Bbe, Bgi); \ - XOReq64(A##ki, Di); \ - Bbi = ROL64(A##ki, 43); \ - A##me = LOAD64(A##kame.v64[1]); \ - XOReq64(A##me, De); \ - Bgo = ROL64(A##me, 45); \ - Bbigo = GET64LOLO(Bbi, Bgo); \ - E##bage.v128 = XOR128(Bbage, ANDnu128(Bbegi, Bbigo)); \ - XOReq128(E##bage.v128, CONST64(KeccakF1600RoundConstants[i])); \ - Cae = E##bage.v128; \ - XOReq64(A##mo, Do); \ - Bbo = ROL64(A##mo, 21); \ - XOReq64(A##si, Di); \ - Bgu = ROL64(A##si, 61); \ - Bbogu = GET64LOLO(Bbo, Bgu); \ - E##begi.v128 = XOR128(Bbegi, ANDnu128(Bbigo, Bbogu)); \ - Cei = E##begi.v128; \ - XOReq64(A##su, Du); \ - Bbu = ROL64(A##su, 14); \ - XOReq64(A##bo, Do); \ - Bga = ROL64(A##bo, 28); \ - Bbuga = GET64LOLO(Bbu, Bga); \ - E##bigo.v128 = XOR128(Bbigo, ANDnu128(Bbogu, Bbuga)); \ - E##bi = E##bigo.v128; \ - E##go = GET64HIHI(E##bigo.v128, E##bigo.v128); \ - Cio = E##bigo.v128; \ - E##bogu.v128 = XOR128(Bbogu, ANDnu128(Bbuga, Bbage)); \ - E##bo = E##bogu.v128; \ - E##gu = GET64HIHI(E##bogu.v128, E##bogu.v128); \ - Cou = E##bogu.v128; \ - E##buga.v128 = XOR128(Bbuga, ANDnu128(Bbage, Bbegi)); \ - E##bu = E##buga.v128; \ - E##ga = GET64HIHI(E##buga.v128, E##buga.v128); \ - Cua = E##buga.v128; \ -\ - A##be = LOAD64(A##begi.v64[0]); \ - XOReq64(A##be, De); \ - Bka = ROL64(A##be, 1); \ - XOReq64(A##ga, Da); \ - Bme = ROL64(A##ga, 36); \ - Bkame = GET64LOLO(Bka, Bme); \ - A##gi = LOAD64(A##begi.v64[1]); \ - XOReq64(A##gi, Di); \ - Bke = ROL64(A##gi, 6); \ - A##ke = LOAD64(A##kemi.v64[0]); \ - XOReq64(A##ke, De); \ - Bmi = ROL64(A##ke, 10); \ - Bkemi = GET64LOLO(Bke, Bmi); \ - XOReq64(A##ko, Do); \ - Bki = ROL64(A##ko, 25); \ - A##mi = LOAD64(A##kemi.v64[1]); \ - XOReq64(A##mi, Di); \ - Bmo = ROL64(A##mi, 15); \ - Bkimo = GET64LOLO(Bki, Bmo); \ - E##kame.v128 = XOR128(Bkame, ANDnu128(Bkemi, Bkimo)); \ - XOReq128(Cae, E##kame.v128); \ - Bkomu = GET64LOLO(XOR64(A##mu, Du), XOR64(A##so, Do)); \ - Bkomu = SHUFFLEBYTES128(Bkomu, CONST128(rho8_56)); \ - E##kemi.v128 = XOR128(Bkemi, ANDnu128(Bkimo, Bkomu)); \ - XOReq128(Cei, E##kemi.v128); \ - XOReq64(A##sa, Da); \ - Bku = ROL64(A##sa, 18); \ - XOReq64(A##bu, Du); \ - Bma = ROL64(A##bu, 27); \ - Bkuma = GET64LOLO(Bku, Bma); \ - E##kimo.v128 = XOR128(Bkimo, ANDnu128(Bkomu, Bkuma)); \ - E##ki = E##kimo.v128; \ - E##mo = GET64HIHI(E##kimo.v128, E##kimo.v128); \ - XOReq128(Cio, E##kimo.v128); \ - E##komu.v128 = XOR128(Bkomu, ANDnu128(Bkuma, Bkame)); \ - E##ko = E##komu.v128; \ - E##mu = GET64HIHI(E##komu.v128, E##komu.v128); \ - XOReq128(Cou, E##komu.v128); \ - E##kuma.v128 = XOR128(Bkuma, ANDnu128(Bkame, Bkemi)); \ - E##ku = E##kuma.v128; \ - E##ma = GET64HIHI(E##kuma.v128, E##kuma.v128); \ - XOReq128(Cua, E##kuma.v128); \ -\ - XOReq64(A##bi, Di); \ - Bsa = ROL64(A##bi, 62); \ - XOReq64(A##go, Do); \ - Bse = ROL64(A##go, 55); \ - XOReq64(A##ku, Du); \ - Bsi = ROL64(A##ku, 39); \ - E##sa = XOR64(Bsa, ANDnu64(Bse, Bsi)); \ - Ca = E##sa; \ - XOReq64(A##ma, Da); \ - Bso = ROL64(A##ma, 41); \ - E##se = XOR64(Bse, ANDnu64(Bsi, Bso)); \ - Ce = E##se; \ - XOReq128(Cae, GET64LOLO(Ca, Ce)); \ - XOReq64(A##se, De); \ - Bsu = ROL64(A##se, 2); \ - E##si = XOR64(Bsi, ANDnu64(Bso, Bsu)); \ - Ci = E##si; \ - E##so = XOR64(Bso, ANDnu64(Bsu, Bsa)); \ - Co = E##so; \ - XOReq128(Cio, GET64LOLO(Ci, Co)); \ - E##su = XOR64(Bsu, ANDnu64(Bsa, Bse)); \ - Cu = E##su; \ -\ - Zero = ZERO128(); \ - XOReq128(Cae, GET64HIHI(Cua, Zero)); \ - XOReq128(Cae, GET64LOLO(Zero, Cei)); \ - XOReq128(Cio, GET64HIHI(Cei, Zero)); \ - XOReq128(Cio, GET64LOLO(Zero, Cou)); \ - XOReq128(Cua, GET64HIHI(Cou, Zero)); \ - XOReq64(Cu, Cua); \ - -/* --- Theta Rho Pi Chi Iota */ -/* --- 64-bit lanes mapped to 64-bit and 128-bit words */ -#define thetaRhoPiChiIota(i, A, E) thetaRhoPiChiIotaPrepareTheta(i, A, E) - -static const UINT64 KeccakF1600RoundConstants[24] = { - 0x0000000000000001ULL, - 0x0000000000008082ULL, - 0x800000000000808aULL, - 0x8000000080008000ULL, - 0x000000000000808bULL, - 0x0000000080000001ULL, - 0x8000000080008081ULL, - 0x8000000000008009ULL, - 0x000000000000008aULL, - 0x0000000000000088ULL, - 0x0000000080008009ULL, - 0x000000008000000aULL, - 0x000000008000808bULL, - 0x800000000000008bULL, - 0x8000000000008089ULL, - 0x8000000000008003ULL, - 0x8000000000008002ULL, - 0x8000000000000080ULL, - 0x000000000000800aULL, - 0x800000008000000aULL, - 0x8000000080008081ULL, - 0x8000000000008080ULL, - 0x0000000080000001ULL, - 0x8000000080008008ULL }; - -#define copyFromStateAndXor576bits(X, state, input) \ - X##bae.v128 = XOR128(LOAD128(state[ 0]), LOAD128u(input[ 0])); \ - X##ba = X##bae.v128; \ - X##be = GET64HIHI(X##bae.v128, X##bae.v128); \ - Cae = X##bae.v128; \ - X##bio.v128 = XOR128(LOAD128(state[ 2]), LOAD128u(input[ 2])); \ - X##bi = X##bio.v128; \ - X##bo = GET64HIHI(X##bio.v128, X##bio.v128); \ - Cio = X##bio.v128; \ - X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ - Cu = X##bu; \ - X##gae.v128 = XOR128(LOAD128u(state[ 5]), LOAD128u(input[ 5])); \ - X##ga = X##gae.v128; \ - X##ge = GET64HIHI(X##gae.v128, X##gae.v128); \ - X##bage.v128 = GET64LOLO(X##ba, X##ge); \ - XOReq128(Cae, X##gae.v128); \ - X##gio.v128 = XOR128(LOAD128u(state[ 7]), LOAD128u(input[ 7])); \ - X##gi = X##gio.v128; \ - X##begi.v128 = GET64LOLO(X##be, X##gi); \ - X##go = GET64HIHI(X##gio.v128, X##gio.v128); \ - XOReq128(Cio, X##gio.v128); \ - X##gu = LOAD64(state[ 9]); \ - XOReq64(Cu, X##gu); \ - X##kae.v128 = LOAD128(state[10]); \ - X##ka = X##kae.v128; \ - X##ke = GET64HIHI(X##kae.v128, X##kae.v128); \ - XOReq128(Cae, X##kae.v128); \ - X##kio.v128 = LOAD128(state[12]); \ - X##ki = X##kio.v128; \ - X##ko = GET64HIHI(X##kio.v128, X##kio.v128); \ - XOReq128(Cio, X##kio.v128); \ - X##ku = LOAD64(state[14]); \ - XOReq64(Cu, X##ku); \ - X##mae.v128 = LOAD128u(state[15]); \ - X##ma = X##mae.v128; \ - X##me = GET64HIHI(X##mae.v128, X##mae.v128); \ - X##kame.v128 = GET64LOLO(X##ka, X##me); \ - XOReq128(Cae, X##mae.v128); \ - X##mio.v128 = LOAD128u(state[17]); \ - X##mi = X##mio.v128; \ - X##kemi.v128 = GET64LOLO(X##ke, X##mi); \ - X##mo = GET64HIHI(X##mio.v128, X##mio.v128); \ - XOReq128(Cio, X##mio.v128); \ - X##mu = LOAD64(state[19]); \ - XOReq64(Cu, X##mu); \ - X##sae.v128 = LOAD128(state[20]); \ - X##sa = X##sae.v128; \ - X##se = GET64HIHI(X##sae.v128, X##sae.v128); \ - XOReq128(Cae, X##sae.v128); \ - X##sio.v128 = LOAD128(state[22]); \ - X##si = X##sio.v128; \ - X##so = GET64HIHI(X##sio.v128, X##sio.v128); \ - XOReq128(Cio, X##sio.v128); \ - X##su = LOAD64(state[24]); \ - XOReq64(Cu, X##su); \ - -#define copyFromStateAndXor832bits(X, state, input) \ - X##bae.v128 = XOR128(LOAD128(state[ 0]), LOAD128u(input[ 0])); \ - X##ba = X##bae.v128; \ - X##be = GET64HIHI(X##bae.v128, X##bae.v128); \ - Cae = X##bae.v128; \ - X##bio.v128 = XOR128(LOAD128(state[ 2]), LOAD128u(input[ 2])); \ - X##bi = X##bio.v128; \ - X##bo = GET64HIHI(X##bio.v128, X##bio.v128); \ - Cio = X##bio.v128; \ - X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ - Cu = X##bu; \ - X##gae.v128 = XOR128(LOAD128u(state[ 5]), LOAD128u(input[ 5])); \ - X##ga = X##gae.v128; \ - X##ge = GET64HIHI(X##gae.v128, X##gae.v128); \ - X##bage.v128 = GET64LOLO(X##ba, X##ge); \ - XOReq128(Cae, X##gae.v128); \ - X##gio.v128 = XOR128(LOAD128u(state[ 7]), LOAD128u(input[ 7])); \ - X##gi = X##gio.v128; \ - X##begi.v128 = GET64LOLO(X##be, X##gi); \ - X##go = GET64HIHI(X##gio.v128, X##gio.v128); \ - XOReq128(Cio, X##gio.v128); \ - X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ - XOReq64(Cu, X##gu); \ - X##kae.v128 = XOR128(LOAD128(state[10]), LOAD128u(input[10])); \ - X##ka = X##kae.v128; \ - X##ke = GET64HIHI(X##kae.v128, X##kae.v128); \ - XOReq128(Cae, X##kae.v128); \ - X##kio.v128 = XOR128(LOAD128(state[12]), LOAD64(input[12])); \ - X##ki = X##kio.v128; \ - X##ko = GET64HIHI(X##kio.v128, X##kio.v128); \ - XOReq128(Cio, X##kio.v128); \ - X##ku = LOAD64(state[14]); \ - XOReq64(Cu, X##ku); \ - X##mae.v128 = LOAD128u(state[15]); \ - X##ma = X##mae.v128; \ - X##me = GET64HIHI(X##mae.v128, X##mae.v128); \ - X##kame.v128 = GET64LOLO(X##ka, X##me); \ - XOReq128(Cae, X##mae.v128); \ - X##mio.v128 = LOAD128u(state[17]); \ - X##mi = X##mio.v128; \ - X##kemi.v128 = GET64LOLO(X##ke, X##mi); \ - X##mo = GET64HIHI(X##mio.v128, X##mio.v128); \ - XOReq128(Cio, X##mio.v128); \ - X##mu = LOAD64(state[19]); \ - XOReq64(Cu, X##mu); \ - X##sae.v128 = LOAD128(state[20]); \ - X##sa = X##sae.v128; \ - X##se = GET64HIHI(X##sae.v128, X##sae.v128); \ - XOReq128(Cae, X##sae.v128); \ - X##sio.v128 = LOAD128(state[22]); \ - X##si = X##sio.v128; \ - X##so = GET64HIHI(X##sio.v128, X##sio.v128); \ - XOReq128(Cio, X##sio.v128); \ - X##su = LOAD64(state[24]); \ - XOReq64(Cu, X##su); \ - -#define copyFromStateAndXor1024bits(X, state, input) \ - X##bae.v128 = XOR128(LOAD128(state[ 0]), LOAD128u(input[ 0])); \ - X##ba = X##bae.v128; \ - X##be = GET64HIHI(X##bae.v128, X##bae.v128); \ - Cae = X##bae.v128; \ - X##bio.v128 = XOR128(LOAD128(state[ 2]), LOAD128u(input[ 2])); \ - X##bi = X##bio.v128; \ - X##bo = GET64HIHI(X##bio.v128, X##bio.v128); \ - Cio = X##bio.v128; \ - X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ - Cu = X##bu; \ - X##gae.v128 = XOR128(LOAD128u(state[ 5]), LOAD128u(input[ 5])); \ - X##ga = X##gae.v128; \ - X##ge = GET64HIHI(X##gae.v128, X##gae.v128); \ - X##bage.v128 = GET64LOLO(X##ba, X##ge); \ - XOReq128(Cae, X##gae.v128); \ - X##gio.v128 = XOR128(LOAD128u(state[ 7]), LOAD128u(input[ 7])); \ - X##gi = X##gio.v128; \ - X##begi.v128 = GET64LOLO(X##be, X##gi); \ - X##go = GET64HIHI(X##gio.v128, X##gio.v128); \ - XOReq128(Cio, X##gio.v128); \ - X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ - XOReq64(Cu, X##gu); \ - X##kae.v128 = XOR128(LOAD128(state[10]), LOAD128u(input[10])); \ - X##ka = X##kae.v128; \ - X##ke = GET64HIHI(X##kae.v128, X##kae.v128); \ - XOReq128(Cae, X##kae.v128); \ - X##kio.v128 = XOR128(LOAD128(state[12]), LOAD128u(input[12])); \ - X##ki = X##kio.v128; \ - X##ko = GET64HIHI(X##kio.v128, X##kio.v128); \ - XOReq128(Cio, X##kio.v128); \ - X##ku = XOR64(LOAD64(state[14]), LOAD64(input[14])); \ - XOReq64(Cu, X##ku); \ - X##mae.v128 = XOR128(LOAD128u(state[15]), LOAD64(input[15])); \ - X##ma = X##mae.v128; \ - X##me = GET64HIHI(X##mae.v128, X##mae.v128); \ - X##kame.v128 = GET64LOLO(X##ka, X##me); \ - XOReq128(Cae, X##mae.v128); \ - X##mio.v128 = LOAD128u(state[17]); \ - X##mi = X##mio.v128; \ - X##kemi.v128 = GET64LOLO(X##ke, X##mi); \ - X##mo = GET64HIHI(X##mio.v128, X##mio.v128); \ - XOReq128(Cio, X##mio.v128); \ - X##mu = LOAD64(state[19]); \ - XOReq64(Cu, X##mu); \ - X##sae.v128 = LOAD128(state[20]); \ - X##sa = X##sae.v128; \ - X##se = GET64HIHI(X##sae.v128, X##sae.v128); \ - XOReq128(Cae, X##sae.v128); \ - X##sio.v128 = LOAD128(state[22]); \ - X##si = X##sio.v128; \ - X##so = GET64HIHI(X##sio.v128, X##sio.v128); \ - XOReq128(Cio, X##sio.v128); \ - X##su = LOAD64(state[24]); \ - XOReq64(Cu, X##su); \ - -#define copyFromStateAndXor1088bits(X, state, input) \ - X##bae.v128 = XOR128(LOAD128(state[ 0]), LOAD128u(input[ 0])); \ - X##ba = X##bae.v128; \ - X##be = GET64HIHI(X##bae.v128, X##bae.v128); \ - Cae = X##bae.v128; \ - X##bio.v128 = XOR128(LOAD128(state[ 2]), LOAD128u(input[ 2])); \ - X##bi = X##bio.v128; \ - X##bo = GET64HIHI(X##bio.v128, X##bio.v128); \ - Cio = X##bio.v128; \ - X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ - Cu = X##bu; \ - X##gae.v128 = XOR128(LOAD128u(state[ 5]), LOAD128u(input[ 5])); \ - X##ga = X##gae.v128; \ - X##ge = GET64HIHI(X##gae.v128, X##gae.v128); \ - X##bage.v128 = GET64LOLO(X##ba, X##ge); \ - XOReq128(Cae, X##gae.v128); \ - X##gio.v128 = XOR128(LOAD128u(state[ 7]), LOAD128u(input[ 7])); \ - X##gi = X##gio.v128; \ - X##begi.v128 = GET64LOLO(X##be, X##gi); \ - X##go = GET64HIHI(X##gio.v128, X##gio.v128); \ - XOReq128(Cio, X##gio.v128); \ - X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ - XOReq64(Cu, X##gu); \ - X##kae.v128 = XOR128(LOAD128(state[10]), LOAD128u(input[10])); \ - X##ka = X##kae.v128; \ - X##ke = GET64HIHI(X##kae.v128, X##kae.v128); \ - XOReq128(Cae, X##kae.v128); \ - X##kio.v128 = XOR128(LOAD128(state[12]), LOAD128u(input[12])); \ - X##ki = X##kio.v128; \ - X##ko = GET64HIHI(X##kio.v128, X##kio.v128); \ - XOReq128(Cio, X##kio.v128); \ - X##ku = XOR64(LOAD64(state[14]), LOAD64(input[14])); \ - XOReq64(Cu, X##ku); \ - X##mae.v128 = XOR128(LOAD128u(state[15]), LOAD128u(input[15])); \ - X##ma = X##mae.v128; \ - X##me = GET64HIHI(X##mae.v128, X##mae.v128); \ - X##kame.v128 = GET64LOLO(X##ka, X##me); \ - XOReq128(Cae, X##mae.v128); \ - X##mio.v128 = LOAD128u(state[17]); \ - X##mi = X##mio.v128; \ - X##kemi.v128 = GET64LOLO(X##ke, X##mi); \ - X##mo = GET64HIHI(X##mio.v128, X##mio.v128); \ - XOReq128(Cio, X##mio.v128); \ - X##mu = LOAD64(state[19]); \ - XOReq64(Cu, X##mu); \ - X##sae.v128 = LOAD128(state[20]); \ - X##sa = X##sae.v128; \ - X##se = GET64HIHI(X##sae.v128, X##sae.v128); \ - XOReq128(Cae, X##sae.v128); \ - X##sio.v128 = LOAD128(state[22]); \ - X##si = X##sio.v128; \ - X##so = GET64HIHI(X##sio.v128, X##sio.v128); \ - XOReq128(Cio, X##sio.v128); \ - X##su = LOAD64(state[24]); \ - XOReq64(Cu, X##su); \ - -#define copyFromStateAndXor1152bits(X, state, input) \ - X##bae.v128 = XOR128(LOAD128(state[ 0]), LOAD128u(input[ 0])); \ - X##ba = X##bae.v128; \ - X##be = GET64HIHI(X##bae.v128, X##bae.v128); \ - Cae = X##bae.v128; \ - X##bio.v128 = XOR128(LOAD128(state[ 2]), LOAD128u(input[ 2])); \ - X##bi = X##bio.v128; \ - X##bo = GET64HIHI(X##bio.v128, X##bio.v128); \ - Cio = X##bio.v128; \ - X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ - Cu = X##bu; \ - X##gae.v128 = XOR128(LOAD128u(state[ 5]), LOAD128u(input[ 5])); \ - X##ga = X##gae.v128; \ - X##ge = GET64HIHI(X##gae.v128, X##gae.v128); \ - X##bage.v128 = GET64LOLO(X##ba, X##ge); \ - XOReq128(Cae, X##gae.v128); \ - X##gio.v128 = XOR128(LOAD128u(state[ 7]), LOAD128u(input[ 7])); \ - X##gi = X##gio.v128; \ - X##begi.v128 = GET64LOLO(X##be, X##gi); \ - X##go = GET64HIHI(X##gio.v128, X##gio.v128); \ - XOReq128(Cio, X##gio.v128); \ - X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ - XOReq64(Cu, X##gu); \ - X##kae.v128 = XOR128(LOAD128(state[10]), LOAD128u(input[10])); \ - X##ka = X##kae.v128; \ - X##ke = GET64HIHI(X##kae.v128, X##kae.v128); \ - XOReq128(Cae, X##kae.v128); \ - X##kio.v128 = XOR128(LOAD128(state[12]), LOAD128u(input[12])); \ - X##ki = X##kio.v128; \ - X##ko = GET64HIHI(X##kio.v128, X##kio.v128); \ - XOReq128(Cio, X##kio.v128); \ - X##ku = XOR64(LOAD64(state[14]), LOAD64(input[14])); \ - XOReq64(Cu, X##ku); \ - X##mae.v128 = XOR128(LOAD128u(state[15]), LOAD128u(input[15])); \ - X##ma = X##mae.v128; \ - X##me = GET64HIHI(X##mae.v128, X##mae.v128); \ - X##kame.v128 = GET64LOLO(X##ka, X##me); \ - XOReq128(Cae, X##mae.v128); \ - X##mio.v128 = XOR128(LOAD128u(state[17]), LOAD64(input[17])); \ - X##mi = X##mio.v128; \ - X##kemi.v128 = GET64LOLO(X##ke, X##mi); \ - X##mo = GET64HIHI(X##mio.v128, X##mio.v128); \ - XOReq128(Cio, X##mio.v128); \ - X##mu = LOAD64(state[19]); \ - XOReq64(Cu, X##mu); \ - X##sae.v128 = LOAD128(state[20]); \ - X##sa = X##sae.v128; \ - X##se = GET64HIHI(X##sae.v128, X##sae.v128); \ - XOReq128(Cae, X##sae.v128); \ - X##sio.v128 = LOAD128(state[22]); \ - X##si = X##sio.v128; \ - X##so = GET64HIHI(X##sio.v128, X##sio.v128); \ - XOReq128(Cio, X##sio.v128); \ - X##su = LOAD64(state[24]); \ - XOReq64(Cu, X##su); \ - -#define copyFromStateAndXor1344bits(X, state, input) \ - X##bae.v128 = XOR128(LOAD128(state[ 0]), LOAD128u(input[ 0])); \ - X##ba = X##bae.v128; \ - X##be = GET64HIHI(X##bae.v128, X##bae.v128); \ - Cae = X##bae.v128; \ - X##bio.v128 = XOR128(LOAD128(state[ 2]), LOAD128u(input[ 2])); \ - X##bi = X##bio.v128; \ - X##bo = GET64HIHI(X##bio.v128, X##bio.v128); \ - Cio = X##bio.v128; \ - X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ - Cu = X##bu; \ - X##gae.v128 = XOR128(LOAD128u(state[ 5]), LOAD128u(input[ 5])); \ - X##ga = X##gae.v128; \ - X##ge = GET64HIHI(X##gae.v128, X##gae.v128); \ - X##bage.v128 = GET64LOLO(X##ba, X##ge); \ - XOReq128(Cae, X##gae.v128); \ - X##gio.v128 = XOR128(LOAD128u(state[ 7]), LOAD128u(input[ 7])); \ - X##gi = X##gio.v128; \ - X##begi.v128 = GET64LOLO(X##be, X##gi); \ - X##go = GET64HIHI(X##gio.v128, X##gio.v128); \ - XOReq128(Cio, X##gio.v128); \ - X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ - XOReq64(Cu, X##gu); \ - X##kae.v128 = XOR128(LOAD128(state[10]), LOAD128u(input[10])); \ - X##ka = X##kae.v128; \ - X##ke = GET64HIHI(X##kae.v128, X##kae.v128); \ - XOReq128(Cae, X##kae.v128); \ - X##kio.v128 = XOR128(LOAD128(state[12]), LOAD128u(input[12])); \ - X##ki = X##kio.v128; \ - X##ko = GET64HIHI(X##kio.v128, X##kio.v128); \ - XOReq128(Cio, X##kio.v128); \ - X##ku = XOR64(LOAD64(state[14]), LOAD64(input[14])); \ - XOReq64(Cu, X##ku); \ - X##mae.v128 = XOR128(LOAD128u(state[15]), LOAD128u(input[15])); \ - X##ma = X##mae.v128; \ - X##me = GET64HIHI(X##mae.v128, X##mae.v128); \ - X##kame.v128 = GET64LOLO(X##ka, X##me); \ - XOReq128(Cae, X##mae.v128); \ - X##mio.v128 = XOR128(LOAD128u(state[17]), LOAD128u(input[17])); \ - X##mi = X##mio.v128; \ - X##kemi.v128 = GET64LOLO(X##ke, X##mi); \ - X##mo = GET64HIHI(X##mio.v128, X##mio.v128); \ - XOReq128(Cio, X##mio.v128); \ - X##mu = XOR64(LOAD64(state[19]), LOAD64(input[19])); \ - XOReq64(Cu, X##mu); \ - X##sae.v128 = XOR128(LOAD128(state[20]), LOAD64(input[20])); \ - X##sa = X##sae.v128; \ - X##se = GET64HIHI(X##sae.v128, X##sae.v128); \ - XOReq128(Cae, X##sae.v128); \ - X##sio.v128 = LOAD128(state[22]); \ - X##si = X##sio.v128; \ - X##so = GET64HIHI(X##sio.v128, X##sio.v128); \ - XOReq128(Cio, X##sio.v128); \ - X##su = LOAD64(state[24]); \ - XOReq64(Cu, X##su); \ - -#define copyFromState(X, state) \ - X##bae.v128 = LOAD128(state[ 0]); \ - X##ba = X##bae.v128; \ - X##be = GET64HIHI(X##bae.v128, X##bae.v128); \ - Cae = X##bae.v128; \ - X##bio.v128 = LOAD128(state[ 2]); \ - X##bi = X##bio.v128; \ - X##bo = GET64HIHI(X##bio.v128, X##bio.v128); \ - Cio = X##bio.v128; \ - X##bu = LOAD64(state[ 4]); \ - Cu = X##bu; \ - X##gae.v128 = LOAD128u(state[ 5]); \ - X##ga = X##gae.v128; \ - X##ge = GET64HIHI(X##gae.v128, X##gae.v128); \ - X##bage.v128 = GET64LOLO(X##ba, X##ge); \ - XOReq128(Cae, X##gae.v128); \ - X##gio.v128 = LOAD128u(state[ 7]); \ - X##gi = X##gio.v128; \ - X##begi.v128 = GET64LOLO(X##be, X##gi); \ - X##go = GET64HIHI(X##gio.v128, X##gio.v128); \ - XOReq128(Cio, X##gio.v128); \ - X##gu = LOAD64(state[ 9]); \ - XOReq64(Cu, X##gu); \ - X##kae.v128 = LOAD128(state[10]); \ - X##ka = X##kae.v128; \ - X##ke = GET64HIHI(X##kae.v128, X##kae.v128); \ - XOReq128(Cae, X##kae.v128); \ - X##kio.v128 = LOAD128(state[12]); \ - X##ki = X##kio.v128; \ - X##ko = GET64HIHI(X##kio.v128, X##kio.v128); \ - XOReq128(Cio, X##kio.v128); \ - X##ku = LOAD64(state[14]); \ - XOReq64(Cu, X##ku); \ - X##mae.v128 = LOAD128u(state[15]); \ - X##ma = X##mae.v128; \ - X##me = GET64HIHI(X##mae.v128, X##mae.v128); \ - X##kame.v128 = GET64LOLO(X##ka, X##me); \ - XOReq128(Cae, X##mae.v128); \ - X##mio.v128 = LOAD128u(state[17]); \ - X##mi = X##mio.v128; \ - X##kemi.v128 = GET64LOLO(X##ke, X##mi); \ - X##mo = GET64HIHI(X##mio.v128, X##mio.v128); \ - XOReq128(Cio, X##mio.v128); \ - X##mu = LOAD64(state[19]); \ - XOReq64(Cu, X##mu); \ - X##sae.v128 = LOAD128(state[20]); \ - X##sa = X##sae.v128; \ - X##se = GET64HIHI(X##sae.v128, X##sae.v128); \ - XOReq128(Cae, X##sae.v128); \ - X##sio.v128 = LOAD128(state[22]); \ - X##si = X##sio.v128; \ - X##so = GET64HIHI(X##sio.v128, X##sio.v128); \ - XOReq128(Cio, X##sio.v128); \ - X##su = LOAD64(state[24]); \ - XOReq64(Cu, X##su); \ - -#define copyToState(state, X) \ - state[ 0] = A##bage.v64[0]; \ - state[ 1] = A##begi.v64[0]; \ - STORE64(state[ 2], X##bi); \ - STORE64(state[ 3], X##bo); \ - STORE64(state[ 4], X##bu); \ - STORE64(state[ 5], X##ga); \ - state[ 6] = A##bage.v64[1]; \ - state[ 7] = A##begi.v64[1]; \ - STORE64(state[ 8], X##go); \ - STORE64(state[ 9], X##gu); \ - state[10] = X##kame.v64[0]; \ - state[11] = X##kemi.v64[0]; \ - STORE64(state[12], X##ki); \ - STORE64(state[13], X##ko); \ - STORE64(state[14], X##ku); \ - STORE64(state[15], X##ma); \ - state[16] = X##kame.v64[1]; \ - state[17] = X##kemi.v64[1]; \ - STORE64(state[18], X##mo); \ - STORE64(state[19], X##mu); \ - STORE64(state[20], X##sa); \ - STORE64(state[21], X##se); \ - STORE64(state[22], X##si); \ - STORE64(state[23], X##so); \ - STORE64(state[24], X##su); \ - -#define copyStateVariables(X, Y) \ - X##bage = Y##bage; \ - X##begi = Y##begi; \ - X##bi = Y##bi; \ - X##bo = Y##bo; \ - X##bu = Y##bu; \ - X##ga = Y##ga; \ - X##go = Y##go; \ - X##gu = Y##gu; \ - X##kame = Y##kame; \ - X##kemi = Y##kemi; \ - X##ki = Y##ki; \ - X##ko = Y##ko; \ - X##ku = Y##ku; \ - X##ma = Y##ma; \ - X##mo = Y##mo; \ - X##mu = Y##mu; \ - X##sa = Y##sa; \ - X##se = Y##se; \ - X##si = Y##si; \ - X##so = Y##so; \ - X##su = Y##su; \ - diff --git a/Modules/_sha3/keccak/KeccakF-1600-simd64.macros b/Modules/_sha3/keccak/KeccakF-1600-simd64.macros deleted file mode 100644 --- a/Modules/_sha3/keccak/KeccakF-1600-simd64.macros +++ /dev/null @@ -1,517 +0,0 @@ -/* -Code automatically generated by KeccakTools! - -The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, -Micha?l Peeters and Gilles Van Assche. For more information, feedback or -questions, please refer to our website: http://keccak.noekeon.org/ - -Implementation by the designers, -hereby denoted as "the implementer". - -To the extent possible under law, the implementer has waived all copyright -and related or neighboring rights to the source code in this file. -http://creativecommons.org/publicdomain/zero/1.0/ -*/ - -#define declareABCDE \ - V64 Aba, Abe, Abi, Abo, Abu; \ - V64 Aga, Age, Agi, Ago, Agu; \ - V64 Aka, Ake, Aki, Ako, Aku; \ - V64 Ama, Ame, Ami, Amo, Amu; \ - V64 Asa, Ase, Asi, Aso, Asu; \ - V64 Bba, Bbe, Bbi, Bbo, Bbu; \ - V64 Bga, Bge, Bgi, Bgo, Bgu; \ - V64 Bka, Bke, Bki, Bko, Bku; \ - V64 Bma, Bme, Bmi, Bmo, Bmu; \ - V64 Bsa, Bse, Bsi, Bso, Bsu; \ - V64 Ca, Ce, Ci, Co, Cu; \ - V64 Da, De, Di, Do, Du; \ - V64 Eba, Ebe, Ebi, Ebo, Ebu; \ - V64 Ega, Ege, Egi, Ego, Egu; \ - V64 Eka, Eke, Eki, Eko, Eku; \ - V64 Ema, Eme, Emi, Emo, Emu; \ - V64 Esa, Ese, Esi, Eso, Esu; \ - -#define prepareTheta \ - Ca = XOR64(Aba, XOR64(Aga, XOR64(Aka, XOR64(Ama, Asa)))); \ - Ce = XOR64(Abe, XOR64(Age, XOR64(Ake, XOR64(Ame, Ase)))); \ - Ci = XOR64(Abi, XOR64(Agi, XOR64(Aki, XOR64(Ami, Asi)))); \ - Co = XOR64(Abo, XOR64(Ago, XOR64(Ako, XOR64(Amo, Aso)))); \ - Cu = XOR64(Abu, XOR64(Agu, XOR64(Aku, XOR64(Amu, Asu)))); \ - -/* --- Code for round, with prepare-theta */ -/* --- 64-bit lanes mapped to 64-bit words */ -#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ - Da = XOR64(Cu, ROL64(Ce, 1)); \ - De = XOR64(Ca, ROL64(Ci, 1)); \ - Di = XOR64(Ce, ROL64(Co, 1)); \ - Do = XOR64(Ci, ROL64(Cu, 1)); \ - Du = XOR64(Co, ROL64(Ca, 1)); \ -\ - XOReq64(A##ba, Da); \ - Bba = A##ba; \ - XOReq64(A##ge, De); \ - Bbe = ROL64(A##ge, 44); \ - XOReq64(A##ki, Di); \ - Bbi = ROL64(A##ki, 43); \ - E##ba = XOR64(Bba, ANDnu64(Bbe, Bbi)); \ - XOReq64(E##ba, CONST64(KeccakF1600RoundConstants[i])); \ - Ca = E##ba; \ - XOReq64(A##mo, Do); \ - Bbo = ROL64(A##mo, 21); \ - E##be = XOR64(Bbe, ANDnu64(Bbi, Bbo)); \ - Ce = E##be; \ - XOReq64(A##su, Du); \ - Bbu = ROL64(A##su, 14); \ - E##bi = XOR64(Bbi, ANDnu64(Bbo, Bbu)); \ - Ci = E##bi; \ - E##bo = XOR64(Bbo, ANDnu64(Bbu, Bba)); \ - Co = E##bo; \ - E##bu = XOR64(Bbu, ANDnu64(Bba, Bbe)); \ - Cu = E##bu; \ -\ - XOReq64(A##bo, Do); \ - Bga = ROL64(A##bo, 28); \ - XOReq64(A##gu, Du); \ - Bge = ROL64(A##gu, 20); \ - XOReq64(A##ka, Da); \ - Bgi = ROL64(A##ka, 3); \ - E##ga = XOR64(Bga, ANDnu64(Bge, Bgi)); \ - XOReq64(Ca, E##ga); \ - XOReq64(A##me, De); \ - Bgo = ROL64(A##me, 45); \ - E##ge = XOR64(Bge, ANDnu64(Bgi, Bgo)); \ - XOReq64(Ce, E##ge); \ - XOReq64(A##si, Di); \ - Bgu = ROL64(A##si, 61); \ - E##gi = XOR64(Bgi, ANDnu64(Bgo, Bgu)); \ - XOReq64(Ci, E##gi); \ - E##go = XOR64(Bgo, ANDnu64(Bgu, Bga)); \ - XOReq64(Co, E##go); \ - E##gu = XOR64(Bgu, ANDnu64(Bga, Bge)); \ - XOReq64(Cu, E##gu); \ -\ - XOReq64(A##be, De); \ - Bka = ROL64(A##be, 1); \ - XOReq64(A##gi, Di); \ - Bke = ROL64(A##gi, 6); \ - XOReq64(A##ko, Do); \ - Bki = ROL64(A##ko, 25); \ - E##ka = XOR64(Bka, ANDnu64(Bke, Bki)); \ - XOReq64(Ca, E##ka); \ - XOReq64(A##mu, Du); \ - Bko = ROL64(A##mu, 8); \ - E##ke = XOR64(Bke, ANDnu64(Bki, Bko)); \ - XOReq64(Ce, E##ke); \ - XOReq64(A##sa, Da); \ - Bku = ROL64(A##sa, 18); \ - E##ki = XOR64(Bki, ANDnu64(Bko, Bku)); \ - XOReq64(Ci, E##ki); \ - E##ko = XOR64(Bko, ANDnu64(Bku, Bka)); \ - XOReq64(Co, E##ko); \ - E##ku = XOR64(Bku, ANDnu64(Bka, Bke)); \ - XOReq64(Cu, E##ku); \ -\ - XOReq64(A##bu, Du); \ - Bma = ROL64(A##bu, 27); \ - XOReq64(A##ga, Da); \ - Bme = ROL64(A##ga, 36); \ - XOReq64(A##ke, De); \ - Bmi = ROL64(A##ke, 10); \ - E##ma = XOR64(Bma, ANDnu64(Bme, Bmi)); \ - XOReq64(Ca, E##ma); \ - XOReq64(A##mi, Di); \ - Bmo = ROL64(A##mi, 15); \ - E##me = XOR64(Bme, ANDnu64(Bmi, Bmo)); \ - XOReq64(Ce, E##me); \ - XOReq64(A##so, Do); \ - Bmu = ROL64(A##so, 56); \ - E##mi = XOR64(Bmi, ANDnu64(Bmo, Bmu)); \ - XOReq64(Ci, E##mi); \ - E##mo = XOR64(Bmo, ANDnu64(Bmu, Bma)); \ - XOReq64(Co, E##mo); \ - E##mu = XOR64(Bmu, ANDnu64(Bma, Bme)); \ - XOReq64(Cu, E##mu); \ -\ - XOReq64(A##bi, Di); \ - Bsa = ROL64(A##bi, 62); \ - XOReq64(A##go, Do); \ - Bse = ROL64(A##go, 55); \ - XOReq64(A##ku, Du); \ - Bsi = ROL64(A##ku, 39); \ - E##sa = XOR64(Bsa, ANDnu64(Bse, Bsi)); \ - XOReq64(Ca, E##sa); \ - XOReq64(A##ma, Da); \ - Bso = ROL64(A##ma, 41); \ - E##se = XOR64(Bse, ANDnu64(Bsi, Bso)); \ - XOReq64(Ce, E##se); \ - XOReq64(A##se, De); \ - Bsu = ROL64(A##se, 2); \ - E##si = XOR64(Bsi, ANDnu64(Bso, Bsu)); \ - XOReq64(Ci, E##si); \ - E##so = XOR64(Bso, ANDnu64(Bsu, Bsa)); \ - XOReq64(Co, E##so); \ - E##su = XOR64(Bsu, ANDnu64(Bsa, Bse)); \ - XOReq64(Cu, E##su); \ -\ - -/* --- Code for round */ -/* --- 64-bit lanes mapped to 64-bit words */ -#define thetaRhoPiChiIota(i, A, E) \ - Da = XOR64(Cu, ROL64(Ce, 1)); \ - De = XOR64(Ca, ROL64(Ci, 1)); \ - Di = XOR64(Ce, ROL64(Co, 1)); \ - Do = XOR64(Ci, ROL64(Cu, 1)); \ - Du = XOR64(Co, ROL64(Ca, 1)); \ -\ - XOReq64(A##ba, Da); \ - Bba = A##ba; \ - XOReq64(A##ge, De); \ - Bbe = ROL64(A##ge, 44); \ - XOReq64(A##ki, Di); \ - Bbi = ROL64(A##ki, 43); \ - E##ba = XOR64(Bba, ANDnu64(Bbe, Bbi)); \ - XOReq64(E##ba, CONST64(KeccakF1600RoundConstants[i])); \ - XOReq64(A##mo, Do); \ - Bbo = ROL64(A##mo, 21); \ - E##be = XOR64(Bbe, ANDnu64(Bbi, Bbo)); \ - XOReq64(A##su, Du); \ - Bbu = ROL64(A##su, 14); \ - E##bi = XOR64(Bbi, ANDnu64(Bbo, Bbu)); \ - E##bo = XOR64(Bbo, ANDnu64(Bbu, Bba)); \ - E##bu = XOR64(Bbu, ANDnu64(Bba, Bbe)); \ -\ - XOReq64(A##bo, Do); \ - Bga = ROL64(A##bo, 28); \ - XOReq64(A##gu, Du); \ - Bge = ROL64(A##gu, 20); \ - XOReq64(A##ka, Da); \ - Bgi = ROL64(A##ka, 3); \ - E##ga = XOR64(Bga, ANDnu64(Bge, Bgi)); \ - XOReq64(A##me, De); \ - Bgo = ROL64(A##me, 45); \ - E##ge = XOR64(Bge, ANDnu64(Bgi, Bgo)); \ - XOReq64(A##si, Di); \ - Bgu = ROL64(A##si, 61); \ - E##gi = XOR64(Bgi, ANDnu64(Bgo, Bgu)); \ - E##go = XOR64(Bgo, ANDnu64(Bgu, Bga)); \ - E##gu = XOR64(Bgu, ANDnu64(Bga, Bge)); \ -\ - XOReq64(A##be, De); \ - Bka = ROL64(A##be, 1); \ - XOReq64(A##gi, Di); \ - Bke = ROL64(A##gi, 6); \ - XOReq64(A##ko, Do); \ - Bki = ROL64(A##ko, 25); \ - E##ka = XOR64(Bka, ANDnu64(Bke, Bki)); \ - XOReq64(A##mu, Du); \ - Bko = ROL64(A##mu, 8); \ - E##ke = XOR64(Bke, ANDnu64(Bki, Bko)); \ - XOReq64(A##sa, Da); \ - Bku = ROL64(A##sa, 18); \ - E##ki = XOR64(Bki, ANDnu64(Bko, Bku)); \ - E##ko = XOR64(Bko, ANDnu64(Bku, Bka)); \ - E##ku = XOR64(Bku, ANDnu64(Bka, Bke)); \ -\ - XOReq64(A##bu, Du); \ - Bma = ROL64(A##bu, 27); \ - XOReq64(A##ga, Da); \ - Bme = ROL64(A##ga, 36); \ - XOReq64(A##ke, De); \ - Bmi = ROL64(A##ke, 10); \ - E##ma = XOR64(Bma, ANDnu64(Bme, Bmi)); \ - XOReq64(A##mi, Di); \ - Bmo = ROL64(A##mi, 15); \ - E##me = XOR64(Bme, ANDnu64(Bmi, Bmo)); \ - XOReq64(A##so, Do); \ - Bmu = ROL64(A##so, 56); \ - E##mi = XOR64(Bmi, ANDnu64(Bmo, Bmu)); \ - E##mo = XOR64(Bmo, ANDnu64(Bmu, Bma)); \ - E##mu = XOR64(Bmu, ANDnu64(Bma, Bme)); \ -\ - XOReq64(A##bi, Di); \ - Bsa = ROL64(A##bi, 62); \ - XOReq64(A##go, Do); \ - Bse = ROL64(A##go, 55); \ - XOReq64(A##ku, Du); \ - Bsi = ROL64(A##ku, 39); \ - E##sa = XOR64(Bsa, ANDnu64(Bse, Bsi)); \ - XOReq64(A##ma, Da); \ - Bso = ROL64(A##ma, 41); \ - E##se = XOR64(Bse, ANDnu64(Bsi, Bso)); \ - XOReq64(A##se, De); \ - Bsu = ROL64(A##se, 2); \ - E##si = XOR64(Bsi, ANDnu64(Bso, Bsu)); \ - E##so = XOR64(Bso, ANDnu64(Bsu, Bsa)); \ - E##su = XOR64(Bsu, ANDnu64(Bsa, Bse)); \ -\ - -static const UINT64 KeccakF1600RoundConstants[24] = { - 0x0000000000000001ULL, - 0x0000000000008082ULL, - 0x800000000000808aULL, - 0x8000000080008000ULL, - 0x000000000000808bULL, - 0x0000000080000001ULL, - 0x8000000080008081ULL, - 0x8000000000008009ULL, - 0x000000000000008aULL, - 0x0000000000000088ULL, - 0x0000000080008009ULL, - 0x000000008000000aULL, - 0x000000008000808bULL, - 0x800000000000008bULL, - 0x8000000000008089ULL, - 0x8000000000008003ULL, - 0x8000000000008002ULL, - 0x8000000000000080ULL, - 0x000000000000800aULL, - 0x800000008000000aULL, - 0x8000000080008081ULL, - 0x8000000000008080ULL, - 0x0000000080000001ULL, - 0x8000000080008008ULL }; - -#define copyFromStateAndXor576bits(X, state, input) \ - X##ba = XOR64(LOAD64(state[ 0]), LOAD64(input[ 0])); \ - X##be = XOR64(LOAD64(state[ 1]), LOAD64(input[ 1])); \ - X##bi = XOR64(LOAD64(state[ 2]), LOAD64(input[ 2])); \ - X##bo = XOR64(LOAD64(state[ 3]), LOAD64(input[ 3])); \ - X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ - X##ga = XOR64(LOAD64(state[ 5]), LOAD64(input[ 5])); \ - X##ge = XOR64(LOAD64(state[ 6]), LOAD64(input[ 6])); \ - X##gi = XOR64(LOAD64(state[ 7]), LOAD64(input[ 7])); \ - X##go = XOR64(LOAD64(state[ 8]), LOAD64(input[ 8])); \ - X##gu = LOAD64(state[ 9]); \ - X##ka = LOAD64(state[10]); \ - X##ke = LOAD64(state[11]); \ - X##ki = LOAD64(state[12]); \ - X##ko = LOAD64(state[13]); \ - X##ku = LOAD64(state[14]); \ - X##ma = LOAD64(state[15]); \ - X##me = LOAD64(state[16]); \ - X##mi = LOAD64(state[17]); \ - X##mo = LOAD64(state[18]); \ - X##mu = LOAD64(state[19]); \ - X##sa = LOAD64(state[20]); \ - X##se = LOAD64(state[21]); \ - X##si = LOAD64(state[22]); \ - X##so = LOAD64(state[23]); \ - X##su = LOAD64(state[24]); \ - -#define copyFromStateAndXor832bits(X, state, input) \ - X##ba = XOR64(LOAD64(state[ 0]), LOAD64(input[ 0])); \ - X##be = XOR64(LOAD64(state[ 1]), LOAD64(input[ 1])); \ - X##bi = XOR64(LOAD64(state[ 2]), LOAD64(input[ 2])); \ - X##bo = XOR64(LOAD64(state[ 3]), LOAD64(input[ 3])); \ - X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ - X##ga = XOR64(LOAD64(state[ 5]), LOAD64(input[ 5])); \ - X##ge = XOR64(LOAD64(state[ 6]), LOAD64(input[ 6])); \ - X##gi = XOR64(LOAD64(state[ 7]), LOAD64(input[ 7])); \ - X##go = XOR64(LOAD64(state[ 8]), LOAD64(input[ 8])); \ - X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ - X##ka = XOR64(LOAD64(state[10]), LOAD64(input[10])); \ - X##ke = XOR64(LOAD64(state[11]), LOAD64(input[11])); \ - X##ki = XOR64(LOAD64(state[12]), LOAD64(input[12])); \ - X##ko = LOAD64(state[13]); \ - X##ku = LOAD64(state[14]); \ - X##ma = LOAD64(state[15]); \ - X##me = LOAD64(state[16]); \ - X##mi = LOAD64(state[17]); \ - X##mo = LOAD64(state[18]); \ - X##mu = LOAD64(state[19]); \ - X##sa = LOAD64(state[20]); \ - X##se = LOAD64(state[21]); \ - X##si = LOAD64(state[22]); \ - X##so = LOAD64(state[23]); \ - X##su = LOAD64(state[24]); \ - -#define copyFromStateAndXor1024bits(X, state, input) \ - X##ba = XOR64(LOAD64(state[ 0]), LOAD64(input[ 0])); \ - X##be = XOR64(LOAD64(state[ 1]), LOAD64(input[ 1])); \ - X##bi = XOR64(LOAD64(state[ 2]), LOAD64(input[ 2])); \ - X##bo = XOR64(LOAD64(state[ 3]), LOAD64(input[ 3])); \ - X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ - X##ga = XOR64(LOAD64(state[ 5]), LOAD64(input[ 5])); \ - X##ge = XOR64(LOAD64(state[ 6]), LOAD64(input[ 6])); \ - X##gi = XOR64(LOAD64(state[ 7]), LOAD64(input[ 7])); \ - X##go = XOR64(LOAD64(state[ 8]), LOAD64(input[ 8])); \ - X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ - X##ka = XOR64(LOAD64(state[10]), LOAD64(input[10])); \ - X##ke = XOR64(LOAD64(state[11]), LOAD64(input[11])); \ - X##ki = XOR64(LOAD64(state[12]), LOAD64(input[12])); \ - X##ko = XOR64(LOAD64(state[13]), LOAD64(input[13])); \ - X##ku = XOR64(LOAD64(state[14]), LOAD64(input[14])); \ - X##ma = XOR64(LOAD64(state[15]), LOAD64(input[15])); \ - X##me = LOAD64(state[16]); \ - X##mi = LOAD64(state[17]); \ - X##mo = LOAD64(state[18]); \ - X##mu = LOAD64(state[19]); \ - X##sa = LOAD64(state[20]); \ - X##se = LOAD64(state[21]); \ - X##si = LOAD64(state[22]); \ - X##so = LOAD64(state[23]); \ - X##su = LOAD64(state[24]); \ - -#define copyFromStateAndXor1088bits(X, state, input) \ - X##ba = XOR64(LOAD64(state[ 0]), LOAD64(input[ 0])); \ - X##be = XOR64(LOAD64(state[ 1]), LOAD64(input[ 1])); \ - X##bi = XOR64(LOAD64(state[ 2]), LOAD64(input[ 2])); \ - X##bo = XOR64(LOAD64(state[ 3]), LOAD64(input[ 3])); \ - X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ - X##ga = XOR64(LOAD64(state[ 5]), LOAD64(input[ 5])); \ - X##ge = XOR64(LOAD64(state[ 6]), LOAD64(input[ 6])); \ - X##gi = XOR64(LOAD64(state[ 7]), LOAD64(input[ 7])); \ - X##go = XOR64(LOAD64(state[ 8]), LOAD64(input[ 8])); \ - X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ - X##ka = XOR64(LOAD64(state[10]), LOAD64(input[10])); \ - X##ke = XOR64(LOAD64(state[11]), LOAD64(input[11])); \ - X##ki = XOR64(LOAD64(state[12]), LOAD64(input[12])); \ - X##ko = XOR64(LOAD64(state[13]), LOAD64(input[13])); \ - X##ku = XOR64(LOAD64(state[14]), LOAD64(input[14])); \ - X##ma = XOR64(LOAD64(state[15]), LOAD64(input[15])); \ - X##me = XOR64(LOAD64(state[16]), LOAD64(input[16])); \ - X##mi = LOAD64(state[17]); \ - X##mo = LOAD64(state[18]); \ - X##mu = LOAD64(state[19]); \ - X##sa = LOAD64(state[20]); \ - X##se = LOAD64(state[21]); \ - X##si = LOAD64(state[22]); \ - X##so = LOAD64(state[23]); \ - X##su = LOAD64(state[24]); \ - -#define copyFromStateAndXor1152bits(X, state, input) \ - X##ba = XOR64(LOAD64(state[ 0]), LOAD64(input[ 0])); \ - X##be = XOR64(LOAD64(state[ 1]), LOAD64(input[ 1])); \ - X##bi = XOR64(LOAD64(state[ 2]), LOAD64(input[ 2])); \ - X##bo = XOR64(LOAD64(state[ 3]), LOAD64(input[ 3])); \ - X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ - X##ga = XOR64(LOAD64(state[ 5]), LOAD64(input[ 5])); \ - X##ge = XOR64(LOAD64(state[ 6]), LOAD64(input[ 6])); \ - X##gi = XOR64(LOAD64(state[ 7]), LOAD64(input[ 7])); \ - X##go = XOR64(LOAD64(state[ 8]), LOAD64(input[ 8])); \ - X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ - X##ka = XOR64(LOAD64(state[10]), LOAD64(input[10])); \ - X##ke = XOR64(LOAD64(state[11]), LOAD64(input[11])); \ - X##ki = XOR64(LOAD64(state[12]), LOAD64(input[12])); \ - X##ko = XOR64(LOAD64(state[13]), LOAD64(input[13])); \ - X##ku = XOR64(LOAD64(state[14]), LOAD64(input[14])); \ - X##ma = XOR64(LOAD64(state[15]), LOAD64(input[15])); \ - X##me = XOR64(LOAD64(state[16]), LOAD64(input[16])); \ - X##mi = XOR64(LOAD64(state[17]), LOAD64(input[17])); \ - X##mo = LOAD64(state[18]); \ - X##mu = LOAD64(state[19]); \ - X##sa = LOAD64(state[20]); \ - X##se = LOAD64(state[21]); \ - X##si = LOAD64(state[22]); \ - X##so = LOAD64(state[23]); \ - X##su = LOAD64(state[24]); \ - -#define copyFromStateAndXor1344bits(X, state, input) \ - X##ba = XOR64(LOAD64(state[ 0]), LOAD64(input[ 0])); \ - X##be = XOR64(LOAD64(state[ 1]), LOAD64(input[ 1])); \ - X##bi = XOR64(LOAD64(state[ 2]), LOAD64(input[ 2])); \ - X##bo = XOR64(LOAD64(state[ 3]), LOAD64(input[ 3])); \ - X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ - X##ga = XOR64(LOAD64(state[ 5]), LOAD64(input[ 5])); \ - X##ge = XOR64(LOAD64(state[ 6]), LOAD64(input[ 6])); \ - X##gi = XOR64(LOAD64(state[ 7]), LOAD64(input[ 7])); \ - X##go = XOR64(LOAD64(state[ 8]), LOAD64(input[ 8])); \ - X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ - X##ka = XOR64(LOAD64(state[10]), LOAD64(input[10])); \ - X##ke = XOR64(LOAD64(state[11]), LOAD64(input[11])); \ - X##ki = XOR64(LOAD64(state[12]), LOAD64(input[12])); \ - X##ko = XOR64(LOAD64(state[13]), LOAD64(input[13])); \ - X##ku = XOR64(LOAD64(state[14]), LOAD64(input[14])); \ - X##ma = XOR64(LOAD64(state[15]), LOAD64(input[15])); \ - X##me = XOR64(LOAD64(state[16]), LOAD64(input[16])); \ - X##mi = XOR64(LOAD64(state[17]), LOAD64(input[17])); \ - X##mo = XOR64(LOAD64(state[18]), LOAD64(input[18])); \ - X##mu = XOR64(LOAD64(state[19]), LOAD64(input[19])); \ - X##sa = XOR64(LOAD64(state[20]), LOAD64(input[20])); \ - X##se = LOAD64(state[21]); \ - X##si = LOAD64(state[22]); \ - X##so = LOAD64(state[23]); \ - X##su = LOAD64(state[24]); \ - -#define copyFromState(X, state) \ - X##ba = LOAD64(state[ 0]); \ - X##be = LOAD64(state[ 1]); \ - X##bi = LOAD64(state[ 2]); \ - X##bo = LOAD64(state[ 3]); \ - X##bu = LOAD64(state[ 4]); \ - X##ga = LOAD64(state[ 5]); \ - X##ge = LOAD64(state[ 6]); \ - X##gi = LOAD64(state[ 7]); \ - X##go = LOAD64(state[ 8]); \ - X##gu = LOAD64(state[ 9]); \ - X##ka = LOAD64(state[10]); \ - X##ke = LOAD64(state[11]); \ - X##ki = LOAD64(state[12]); \ - X##ko = LOAD64(state[13]); \ - X##ku = LOAD64(state[14]); \ - X##ma = LOAD64(state[15]); \ - X##me = LOAD64(state[16]); \ - X##mi = LOAD64(state[17]); \ - X##mo = LOAD64(state[18]); \ - X##mu = LOAD64(state[19]); \ - X##sa = LOAD64(state[20]); \ - X##se = LOAD64(state[21]); \ - X##si = LOAD64(state[22]); \ - X##so = LOAD64(state[23]); \ - X##su = LOAD64(state[24]); \ - -#define copyToState(state, X) \ - STORE64(state[ 0], X##ba); \ - STORE64(state[ 1], X##be); \ - STORE64(state[ 2], X##bi); \ - STORE64(state[ 3], X##bo); \ - STORE64(state[ 4], X##bu); \ - STORE64(state[ 5], X##ga); \ - STORE64(state[ 6], X##ge); \ - STORE64(state[ 7], X##gi); \ - STORE64(state[ 8], X##go); \ - STORE64(state[ 9], X##gu); \ - STORE64(state[10], X##ka); \ - STORE64(state[11], X##ke); \ - STORE64(state[12], X##ki); \ - STORE64(state[13], X##ko); \ - STORE64(state[14], X##ku); \ - STORE64(state[15], X##ma); \ - STORE64(state[16], X##me); \ - STORE64(state[17], X##mi); \ - STORE64(state[18], X##mo); \ - STORE64(state[19], X##mu); \ - STORE64(state[20], X##sa); \ - STORE64(state[21], X##se); \ - STORE64(state[22], X##si); \ - STORE64(state[23], X##so); \ - STORE64(state[24], X##su); \ - -#define copyStateVariables(X, Y) \ - X##ba = Y##ba; \ - X##be = Y##be; \ - X##bi = Y##bi; \ - X##bo = Y##bo; \ - X##bu = Y##bu; \ - X##ga = Y##ga; \ - X##ge = Y##ge; \ - X##gi = Y##gi; \ - X##go = Y##go; \ - X##gu = Y##gu; \ - X##ka = Y##ka; \ - X##ke = Y##ke; \ - X##ki = Y##ki; \ - X##ko = Y##ko; \ - X##ku = Y##ku; \ - X##ma = Y##ma; \ - X##me = Y##me; \ - X##mi = Y##mi; \ - X##mo = Y##mo; \ - X##mu = Y##mu; \ - X##sa = Y##sa; \ - X##se = Y##se; \ - X##si = Y##si; \ - X##so = Y##so; \ - X##su = Y##su; \ - diff --git a/Modules/_sha3/keccak/KeccakF-1600-unrolling.macros b/Modules/_sha3/keccak/KeccakF-1600-unrolling.macros deleted file mode 100644 --- a/Modules/_sha3/keccak/KeccakF-1600-unrolling.macros +++ /dev/null @@ -1,124 +0,0 @@ -/* -The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, -Micha?l Peeters and Gilles Van Assche. For more information, feedback or -questions, please refer to our website: http://keccak.noekeon.org/ - -Implementation by the designers, -hereby denoted as "the implementer". - -To the extent possible under law, the implementer has waived all copyright -and related or neighboring rights to the source code in this file. -http://creativecommons.org/publicdomain/zero/1.0/ -*/ - -#if (Unrolling == 24) -#define rounds \ - prepareTheta \ - thetaRhoPiChiIotaPrepareTheta( 0, A, E) \ - thetaRhoPiChiIotaPrepareTheta( 1, E, A) \ - thetaRhoPiChiIotaPrepareTheta( 2, A, E) \ - thetaRhoPiChiIotaPrepareTheta( 3, E, A) \ - thetaRhoPiChiIotaPrepareTheta( 4, A, E) \ - thetaRhoPiChiIotaPrepareTheta( 5, E, A) \ - thetaRhoPiChiIotaPrepareTheta( 6, A, E) \ - thetaRhoPiChiIotaPrepareTheta( 7, E, A) \ - thetaRhoPiChiIotaPrepareTheta( 8, A, E) \ - thetaRhoPiChiIotaPrepareTheta( 9, E, A) \ - thetaRhoPiChiIotaPrepareTheta(10, A, E) \ - thetaRhoPiChiIotaPrepareTheta(11, E, A) \ - thetaRhoPiChiIotaPrepareTheta(12, A, E) \ - thetaRhoPiChiIotaPrepareTheta(13, E, A) \ - thetaRhoPiChiIotaPrepareTheta(14, A, E) \ - thetaRhoPiChiIotaPrepareTheta(15, E, A) \ - thetaRhoPiChiIotaPrepareTheta(16, A, E) \ - thetaRhoPiChiIotaPrepareTheta(17, E, A) \ - thetaRhoPiChiIotaPrepareTheta(18, A, E) \ - thetaRhoPiChiIotaPrepareTheta(19, E, A) \ - thetaRhoPiChiIotaPrepareTheta(20, A, E) \ - thetaRhoPiChiIotaPrepareTheta(21, E, A) \ - thetaRhoPiChiIotaPrepareTheta(22, A, E) \ - thetaRhoPiChiIota(23, E, A) \ - copyToState(state, A) -#elif (Unrolling == 12) -#define rounds \ - prepareTheta \ - for(i=0; i<24; i+=12) { \ - thetaRhoPiChiIotaPrepareTheta(i , A, E) \ - thetaRhoPiChiIotaPrepareTheta(i+ 1, E, A) \ - thetaRhoPiChiIotaPrepareTheta(i+ 2, A, E) \ - thetaRhoPiChiIotaPrepareTheta(i+ 3, E, A) \ - thetaRhoPiChiIotaPrepareTheta(i+ 4, A, E) \ - thetaRhoPiChiIotaPrepareTheta(i+ 5, E, A) \ - thetaRhoPiChiIotaPrepareTheta(i+ 6, A, E) \ - thetaRhoPiChiIotaPrepareTheta(i+ 7, E, A) \ - thetaRhoPiChiIotaPrepareTheta(i+ 8, A, E) \ - thetaRhoPiChiIotaPrepareTheta(i+ 9, E, A) \ - thetaRhoPiChiIotaPrepareTheta(i+10, A, E) \ - thetaRhoPiChiIotaPrepareTheta(i+11, E, A) \ - } \ - copyToState(state, A) -#elif (Unrolling == 8) -#define rounds \ - prepareTheta \ - for(i=0; i<24; i+=8) { \ - thetaRhoPiChiIotaPrepareTheta(i , A, E) \ - thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ - thetaRhoPiChiIotaPrepareTheta(i+2, A, E) \ - thetaRhoPiChiIotaPrepareTheta(i+3, E, A) \ - thetaRhoPiChiIotaPrepareTheta(i+4, A, E) \ - thetaRhoPiChiIotaPrepareTheta(i+5, E, A) \ - thetaRhoPiChiIotaPrepareTheta(i+6, A, E) \ - thetaRhoPiChiIotaPrepareTheta(i+7, E, A) \ - } \ - copyToState(state, A) -#elif (Unrolling == 6) -#define rounds \ - prepareTheta \ - for(i=0; i<24; i+=6) { \ - thetaRhoPiChiIotaPrepareTheta(i , A, E) \ - thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ - thetaRhoPiChiIotaPrepareTheta(i+2, A, E) \ - thetaRhoPiChiIotaPrepareTheta(i+3, E, A) \ - thetaRhoPiChiIotaPrepareTheta(i+4, A, E) \ - thetaRhoPiChiIotaPrepareTheta(i+5, E, A) \ - } \ - copyToState(state, A) -#elif (Unrolling == 4) -#define rounds \ - prepareTheta \ - for(i=0; i<24; i+=4) { \ - thetaRhoPiChiIotaPrepareTheta(i , A, E) \ - thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ - thetaRhoPiChiIotaPrepareTheta(i+2, A, E) \ - thetaRhoPiChiIotaPrepareTheta(i+3, E, A) \ - } \ - copyToState(state, A) -#elif (Unrolling == 3) -#define rounds \ - prepareTheta \ - for(i=0; i<24; i+=3) { \ - thetaRhoPiChiIotaPrepareTheta(i , A, E) \ - thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ - thetaRhoPiChiIotaPrepareTheta(i+2, A, E) \ - copyStateVariables(A, E) \ - } \ - copyToState(state, A) -#elif (Unrolling == 2) -#define rounds \ - prepareTheta \ - for(i=0; i<24; i+=2) { \ - thetaRhoPiChiIotaPrepareTheta(i , A, E) \ - thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ - } \ - copyToState(state, A) -#elif (Unrolling == 1) -#define rounds \ - prepareTheta \ - for(i=0; i<24; i++) { \ - thetaRhoPiChiIotaPrepareTheta(i , A, E) \ - copyStateVariables(A, E) \ - } \ - copyToState(state, A) -#else -#error "Unrolling is not correctly specified!" -#endif diff --git a/Modules/_sha3/keccak/KeccakF-1600-xop.macros b/Modules/_sha3/keccak/KeccakF-1600-xop.macros deleted file mode 100644 --- a/Modules/_sha3/keccak/KeccakF-1600-xop.macros +++ /dev/null @@ -1,573 +0,0 @@ -/* -The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, -Micha?l Peeters and Gilles Van Assche. For more information, feedback or -questions, please refer to our website: http://keccak.noekeon.org/ - -Implementation by the designers, -hereby denoted as "the implementer". - -To the extent possible under law, the implementer has waived all copyright -and related or neighboring rights to the source code in this file. -http://creativecommons.org/publicdomain/zero/1.0/ -*/ - -#define declareABCDE \ - V128 Abage, Abegi, Abigo, Abogu, Abuga; \ - V128 Akame, Akemi, Akimo, Akomu, Akuma; \ - V128 Abae, Abio, Agae, Agio, Akae, Akio, Amae, Amio; \ - V64 Aba, Abe, Abi, Abo, Abu; \ - V64 Aga, Age, Agi, Ago, Agu; \ - V64 Aka, Ake, Aki, Ako, Aku; \ - V64 Ama, Ame, Ami, Amo, Amu; \ - V128 Asase, Asiso; \ - V64 Asu; \ - V128 Bbage, Bbegi, Bbigo, Bbogu, Bbuga; \ - V128 Bkame, Bkemi, Bkimo, Bkomu, Bkuma; \ - V128 Bsase, Bsesi, Bsiso, Bsosu, Bsusa; \ - V128 Cae, Cei, Cio, Cou, Cua; \ - V128 Dau, Dea, Die, Doi, Duo; \ - V128 Dua, Dae, Dei, Dio, Dou; \ - V128 Ebage, Ebegi, Ebigo, Ebogu, Ebuga; \ - V128 Ekame, Ekemi, Ekimo, Ekomu, Ekuma; \ - V128 Esase, Esiso; \ - V64 Esu; \ - V128 Zero; - -#define prepareTheta - -#define computeD \ - Cua = GET64LOLO(Cua, Cae); \ - Dei = XOR128(Cae, ROL6464same(Cio, 1)); \ - Dou = XOR128(Cio, ROL6464same(Cua, 1)); \ - Cei = GET64HILO(Cae, Cio); \ - Dae = XOR128(Cua, ROL6464same(Cei, 1)); \ - Dau = GET64LOHI(Dae, Dou); \ - Dea = SWAP64(Dae); \ - Die = SWAP64(Dei); \ - Doi = GET64LOLO(Dou, Die); \ - Duo = SWAP64(Dou); - -/* --- Theta Rho Pi Chi Iota Prepare-theta */ -/* --- 64-bit lanes mapped to 64-bit and 128-bit words */ -#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ - computeD \ - \ - Bbage = XOR128(GET64LOHI(A##bage, A##bogu), Dau); \ - Bbage = ROL6464(Bbage, 0, 20); \ - Bbegi = XOR128(GET64HILO(A##bage, A##kame), Dea); \ - Bbegi = ROL6464(Bbegi, 44, 3); \ - Bbigo = XOR128(GET64LOHI(A##kimo, A##kame), Die); \ - Bbigo = ROL6464(Bbigo, 43, 45); \ - E##bage = XOR128(Bbage, ANDnu128(Bbegi, Bbigo)); \ - XOReq128(E##bage, CONST64(KeccakF1600RoundConstants[i])); \ - Cae = E##bage; \ - Bbogu = XOR128(GET64HILO(A##kimo, A##siso), Doi); \ - Bbogu = ROL6464(Bbogu, 21, 61); \ - E##begi = XOR128(Bbegi, ANDnu128(Bbigo, Bbogu)); \ - Cei = E##begi; \ - Bbuga = XOR128(GET64LOLO(A##su, A##bogu), Duo); \ - Bbuga = ROL6464(Bbuga, 14, 28); \ - E##bigo = XOR128(Bbigo, ANDnu128(Bbogu, Bbuga)); \ - Cio = E##bigo; \ - E##bogu = XOR128(Bbogu, ANDnu128(Bbuga, Bbage)); \ - Cou = E##bogu; \ - E##buga = XOR128(Bbuga, ANDnu128(Bbage, Bbegi)); \ - Cua = E##buga; \ -\ - Bkame = XOR128(GET64LOHI(A##begi, A##buga), Dea); \ - Bkame = ROL6464(Bkame, 1, 36); \ - Bkemi = XOR128(GET64HILO(A##begi, A##kemi), Die); \ - Bkemi = ROL6464(Bkemi, 6, 10); \ - Bkimo = XOR128(GET64LOHI(A##komu, A##kemi), Doi); \ - Bkimo = ROL6464(Bkimo, 25, 15); \ - E##kame = XOR128(Bkame, ANDnu128(Bkemi, Bkimo)); \ - XOReq128(Cae, E##kame); \ - Bkomu = XOR128(GET64HIHI(A##komu, A##siso), Duo); \ - Bkomu = ROL6464(Bkomu, 8, 56); \ - E##kemi = XOR128(Bkemi, ANDnu128(Bkimo, Bkomu)); \ - XOReq128(Cei, E##kemi); \ - Bkuma = XOR128(GET64LOLO(A##sase, A##buga), Dau); \ - Bkuma = ROL6464(Bkuma, 18, 27); \ - E##kimo = XOR128(Bkimo, ANDnu128(Bkomu, Bkuma)); \ - XOReq128(Cio, E##kimo); \ - E##komu = XOR128(Bkomu, ANDnu128(Bkuma, Bkame)); \ - XOReq128(Cou, E##komu); \ - E##kuma = XOR128(Bkuma, ANDnu128(Bkame, Bkemi)); \ - XOReq128(Cua, E##kuma); \ -\ - Bsase = XOR128(A##bigo, SWAP64(Doi)); \ - Bsase = ROL6464(Bsase, 62, 55); \ - Bsiso = XOR128(A##kuma, SWAP64(Dau)); \ - Bsiso = ROL6464(Bsiso, 39, 41); \ - Bsusa = XOR64(COPY64HI2LO(A##sase), Dei); \ - Bsusa = ROL6464same(Bsusa, 2); \ - Bsusa = GET64LOLO(Bsusa, Bsase); \ - Bsesi = GET64HILO(Bsase, Bsiso); \ - Bsosu = GET64HILO(Bsiso, Bsusa); \ - E##sase = XOR128(Bsase, ANDnu128(Bsesi, Bsiso)); \ - XOReq128(Cae, E##sase); \ - E##siso = XOR128(Bsiso, ANDnu128(Bsosu, Bsusa)); \ - XOReq128(Cio, E##siso); \ - E##su = GET64LOLO(XOR128(Bsusa, ANDnu128(Bsase, Bsesi)), Zero); \ - XOReq128(Cua, E##su); \ -\ - Zero = ZERO128(); \ - XOReq128(Cae, GET64HIHI(Cua, Zero)); \ - XOReq128(Cae, GET64LOLO(Zero, Cei)); \ - XOReq128(Cio, GET64HIHI(Cei, Zero)); \ - XOReq128(Cio, GET64LOLO(Zero, Cou)); \ - XOReq128(Cua, GET64HIHI(Cou, Zero)); \ - -/* --- Theta Rho Pi Chi Iota */ -/* --- 64-bit lanes mapped to 64-bit and 128-bit words */ -#define thetaRhoPiChiIota(i, A, E) thetaRhoPiChiIotaPrepareTheta(i, A, E) - -static const UINT64 KeccakF1600RoundConstants[24] = { - 0x0000000000000001ULL, - 0x0000000000008082ULL, - 0x800000000000808aULL, - 0x8000000080008000ULL, - 0x000000000000808bULL, - 0x0000000080000001ULL, - 0x8000000080008081ULL, - 0x8000000000008009ULL, - 0x000000000000008aULL, - 0x0000000000000088ULL, - 0x0000000080008009ULL, - 0x000000008000000aULL, - 0x000000008000808bULL, - 0x800000000000008bULL, - 0x8000000000008089ULL, - 0x8000000000008003ULL, - 0x8000000000008002ULL, - 0x8000000000000080ULL, - 0x000000000000800aULL, - 0x800000008000000aULL, - 0x8000000080008081ULL, - 0x8000000000008080ULL, - 0x0000000080000001ULL, - 0x8000000080008008ULL }; - -#define copyFromStateAndXor576bits(X, state, input) \ - X##bae = XOR128(LOAD128(state[ 0]), LOAD128u(input[ 0])); \ - X##ba = X##bae; \ - X##be = GET64HIHI(X##bae, X##bae); \ - Cae = X##bae; \ - X##bio = XOR128(LOAD128(state[ 2]), LOAD128u(input[ 2])); \ - X##bi = X##bio; \ - X##bo = GET64HIHI(X##bio, X##bio); \ - Cio = X##bio; \ - X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ - Cua = X##bu; \ - X##gae = XOR128(LOAD128u(state[ 5]), LOAD128u(input[ 5])); \ - X##ga = X##gae; \ - X##buga = GET64LOLO(X##bu, X##ga); \ - X##ge = GET64HIHI(X##gae, X##gae); \ - X##bage = GET64LOLO(X##ba, X##ge); \ - XOReq128(Cae, X##gae); \ - X##gio = XOR128(LOAD128u(state[ 7]), LOAD128u(input[ 7])); \ - X##gi = X##gio; \ - X##begi = GET64LOLO(X##be, X##gi); \ - X##go = GET64HIHI(X##gio, X##gio); \ - X##bigo = GET64LOLO(X##bi, X##go); \ - XOReq128(Cio, X##gio); \ - X##gu = LOAD64(state[ 9]); \ - X##bogu = GET64LOLO(X##bo, X##gu); \ - XOReq64(Cua, X##gu); \ - X##kae = LOAD128(state[10]); \ - X##ka = X##kae; \ - X##ke = GET64HIHI(X##kae, X##kae); \ - XOReq128(Cae, X##kae); \ - X##kio = LOAD128(state[12]); \ - X##ki = X##kio; \ - X##ko = GET64HIHI(X##kio, X##kio); \ - XOReq128(Cio, X##kio); \ - X##kuma = LOAD128(state[14]); \ - XOReq64(Cua, X##kuma); \ - X##me = LOAD64(state[16]); \ - X##kame = GET64LOLO(X##ka, X##me); \ - XOReq128(Cae, GET64HIHI(X##kuma, X##kame)); \ - X##mio = LOAD128u(state[17]); \ - X##mi = X##mio; \ - X##kemi = GET64LOLO(X##ke, X##mi); \ - X##mo = GET64HIHI(X##mio, X##mio); \ - X##kimo = GET64LOLO(X##ki, X##mo); \ - XOReq128(Cio, X##mio); \ - X##mu = LOAD64(state[19]); \ - X##komu = GET64LOLO(X##ko, X##mu); \ - XOReq64(Cua, X##mu); \ - X##sase = LOAD128(state[20]); \ - XOReq128(Cae, X##sase); \ - X##siso = LOAD128(state[22]); \ - XOReq128(Cio, X##siso); \ - X##su = LOAD64(state[24]); \ - XOReq64(Cua, X##su); \ - -#define copyFromStateAndXor832bits(X, state, input) \ - X##bae = XOR128(LOAD128(state[ 0]), LOAD128u(input[ 0])); \ - X##ba = X##bae; \ - X##be = GET64HIHI(X##bae, X##bae); \ - Cae = X##bae; \ - X##bio = XOR128(LOAD128(state[ 2]), LOAD128u(input[ 2])); \ - X##bi = X##bio; \ - X##bo = GET64HIHI(X##bio, X##bio); \ - Cio = X##bio; \ - X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ - Cua = X##bu; \ - X##gae = XOR128(LOAD128u(state[ 5]), LOAD128u(input[ 5])); \ - X##ga = X##gae; \ - X##buga = GET64LOLO(X##bu, X##ga); \ - X##ge = GET64HIHI(X##gae, X##gae); \ - X##bage = GET64LOLO(X##ba, X##ge); \ - XOReq128(Cae, X##gae); \ - X##gio = XOR128(LOAD128u(state[ 7]), LOAD128u(input[ 7])); \ - X##gi = X##gio; \ - X##begi = GET64LOLO(X##be, X##gi); \ - X##go = GET64HIHI(X##gio, X##gio); \ - X##bigo = GET64LOLO(X##bi, X##go); \ - XOReq128(Cio, X##gio); \ - X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ - X##bogu = GET64LOLO(X##bo, X##gu); \ - XOReq64(Cua, X##gu); \ - X##kae = XOR128(LOAD128(state[10]), LOAD128u(input[10])); \ - X##ka = X##kae; \ - X##ke = GET64HIHI(X##kae, X##kae); \ - XOReq128(Cae, X##kae); \ - X##kio = XOR128(LOAD128(state[12]), LOAD64(input[12])); \ - X##ki = X##kio; \ - X##ko = GET64HIHI(X##kio, X##kio); \ - XOReq128(Cio, X##kio); \ - X##kuma = LOAD128(state[14]); \ - XOReq64(Cua, X##kuma); \ - X##me = LOAD64(state[16]); \ - X##kame = GET64LOLO(X##ka, X##me); \ - XOReq128(Cae, GET64HIHI(X##kuma, X##kame)); \ - X##mio = LOAD128u(state[17]); \ - X##mi = X##mio; \ - X##kemi = GET64LOLO(X##ke, X##mi); \ - X##mo = GET64HIHI(X##mio, X##mio); \ - X##kimo = GET64LOLO(X##ki, X##mo); \ - XOReq128(Cio, X##mio); \ - X##mu = LOAD64(state[19]); \ - X##komu = GET64LOLO(X##ko, X##mu); \ - XOReq64(Cua, X##mu); \ - X##sase = LOAD128(state[20]); \ - XOReq128(Cae, X##sase); \ - X##siso = LOAD128(state[22]); \ - XOReq128(Cio, X##siso); \ - X##su = LOAD64(state[24]); \ - XOReq64(Cua, X##su); \ - -#define copyFromStateAndXor1024bits(X, state, input) \ - X##bae = XOR128(LOAD128(state[ 0]), LOAD128u(input[ 0])); \ - X##ba = X##bae; \ - X##be = GET64HIHI(X##bae, X##bae); \ - Cae = X##bae; \ - X##bio = XOR128(LOAD128(state[ 2]), LOAD128u(input[ 2])); \ - X##bi = X##bio; \ - X##bo = GET64HIHI(X##bio, X##bio); \ - Cio = X##bio; \ - X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ - Cua = X##bu; \ - X##gae = XOR128(LOAD128u(state[ 5]), LOAD128u(input[ 5])); \ - X##ga = X##gae; \ - X##buga = GET64LOLO(X##bu, X##ga); \ - X##ge = GET64HIHI(X##gae, X##gae); \ - X##bage = GET64LOLO(X##ba, X##ge); \ - XOReq128(Cae, X##gae); \ - X##gio = XOR128(LOAD128u(state[ 7]), LOAD128u(input[ 7])); \ - X##gi = X##gio; \ - X##begi = GET64LOLO(X##be, X##gi); \ - X##go = GET64HIHI(X##gio, X##gio); \ - X##bigo = GET64LOLO(X##bi, X##go); \ - XOReq128(Cio, X##gio); \ - X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ - X##bogu = GET64LOLO(X##bo, X##gu); \ - XOReq64(Cua, X##gu); \ - X##kae = XOR128(LOAD128(state[10]), LOAD128u(input[10])); \ - X##ka = X##kae; \ - X##ke = GET64HIHI(X##kae, X##kae); \ - XOReq128(Cae, X##kae); \ - X##kio = XOR128(LOAD128(state[12]), LOAD128u(input[12])); \ - X##ki = X##kio; \ - X##ko = GET64HIHI(X##kio, X##kio); \ - XOReq128(Cio, X##kio); \ - X##kuma = XOR128(LOAD128(state[14]), LOAD128(input[14])); \ - XOReq64(Cua, X##kuma); \ - X##me = LOAD64(state[16]); \ - X##kame = GET64LOLO(X##ka, X##me); \ - XOReq128(Cae, GET64HIHI(X##kuma, X##kame)); \ - X##mio = LOAD128u(state[17]); \ - X##mi = X##mio; \ - X##kemi = GET64LOLO(X##ke, X##mi); \ - X##mo = GET64HIHI(X##mio, X##mio); \ - X##kimo = GET64LOLO(X##ki, X##mo); \ - XOReq128(Cio, X##mio); \ - X##mu = LOAD64(state[19]); \ - X##komu = GET64LOLO(X##ko, X##mu); \ - XOReq64(Cua, X##mu); \ - X##sase = LOAD128(state[20]); \ - XOReq128(Cae, X##sase); \ - X##siso = LOAD128(state[22]); \ - XOReq128(Cio, X##siso); \ - X##su = LOAD64(state[24]); \ - XOReq64(Cua, X##su); \ - -#define copyFromStateAndXor1088bits(X, state, input) \ - X##bae = XOR128(LOAD128(state[ 0]), LOAD128u(input[ 0])); \ - X##ba = X##bae; \ - X##be = GET64HIHI(X##bae, X##bae); \ - Cae = X##bae; \ - X##bio = XOR128(LOAD128(state[ 2]), LOAD128u(input[ 2])); \ - X##bi = X##bio; \ - X##bo = GET64HIHI(X##bio, X##bio); \ - Cio = X##bio; \ - X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ - Cua = X##bu; \ - X##gae = XOR128(LOAD128u(state[ 5]), LOAD128u(input[ 5])); \ - X##ga = X##gae; \ - X##buga = GET64LOLO(X##bu, X##ga); \ - X##ge = GET64HIHI(X##gae, X##gae); \ - X##bage = GET64LOLO(X##ba, X##ge); \ - XOReq128(Cae, X##gae); \ - X##gio = XOR128(LOAD128u(state[ 7]), LOAD128u(input[ 7])); \ - X##gi = X##gio; \ - X##begi = GET64LOLO(X##be, X##gi); \ - X##go = GET64HIHI(X##gio, X##gio); \ - X##bigo = GET64LOLO(X##bi, X##go); \ - XOReq128(Cio, X##gio); \ - X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ - X##bogu = GET64LOLO(X##bo, X##gu); \ - XOReq64(Cua, X##gu); \ - X##kae = XOR128(LOAD128(state[10]), LOAD128u(input[10])); \ - X##ka = X##kae; \ - X##ke = GET64HIHI(X##kae, X##kae); \ - XOReq128(Cae, X##kae); \ - X##kio = XOR128(LOAD128(state[12]), LOAD128u(input[12])); \ - X##ki = X##kio; \ - X##ko = GET64HIHI(X##kio, X##kio); \ - XOReq128(Cio, X##kio); \ - X##kuma = XOR128(LOAD128(state[14]), LOAD128(input[14])); \ - XOReq64(Cua, X##kuma); \ - X##me = XOR64(LOAD64(state[16]), LOAD64(input[16])); \ - X##kame = GET64LOLO(X##ka, X##me); \ - XOReq128(Cae, GET64HIHI(X##kuma, X##kame)); \ - X##mio = LOAD128u(state[17]); \ - X##mi = X##mio; \ - X##kemi = GET64LOLO(X##ke, X##mi); \ - X##mo = GET64HIHI(X##mio, X##mio); \ - X##kimo = GET64LOLO(X##ki, X##mo); \ - XOReq128(Cio, X##mio); \ - X##mu = LOAD64(state[19]); \ - X##komu = GET64LOLO(X##ko, X##mu); \ - XOReq64(Cua, X##mu); \ - X##sase = LOAD128(state[20]); \ - XOReq128(Cae, X##sase); \ - X##siso = LOAD128(state[22]); \ - XOReq128(Cio, X##siso); \ - X##su = LOAD64(state[24]); \ - XOReq64(Cua, X##su); \ - -#define copyFromStateAndXor1152bits(X, state, input) \ - X##bae = XOR128(LOAD128(state[ 0]), LOAD128u(input[ 0])); \ - X##ba = X##bae; \ - X##be = GET64HIHI(X##bae, X##bae); \ - Cae = X##bae; \ - X##bio = XOR128(LOAD128(state[ 2]), LOAD128u(input[ 2])); \ - X##bi = X##bio; \ - X##bo = GET64HIHI(X##bio, X##bio); \ - Cio = X##bio; \ - X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ - Cua = X##bu; \ - X##gae = XOR128(LOAD128u(state[ 5]), LOAD128u(input[ 5])); \ - X##ga = X##gae; \ - X##buga = GET64LOLO(X##bu, X##ga); \ - X##ge = GET64HIHI(X##gae, X##gae); \ - X##bage = GET64LOLO(X##ba, X##ge); \ - XOReq128(Cae, X##gae); \ - X##gio = XOR128(LOAD128u(state[ 7]), LOAD128u(input[ 7])); \ - X##gi = X##gio; \ - X##begi = GET64LOLO(X##be, X##gi); \ - X##go = GET64HIHI(X##gio, X##gio); \ - X##bigo = GET64LOLO(X##bi, X##go); \ - XOReq128(Cio, X##gio); \ - X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ - X##bogu = GET64LOLO(X##bo, X##gu); \ - XOReq64(Cua, X##gu); \ - X##kae = XOR128(LOAD128(state[10]), LOAD128u(input[10])); \ - X##ka = X##kae; \ - X##ke = GET64HIHI(X##kae, X##kae); \ - XOReq128(Cae, X##kae); \ - X##kio = XOR128(LOAD128(state[12]), LOAD128u(input[12])); \ - X##ki = X##kio; \ - X##ko = GET64HIHI(X##kio, X##kio); \ - XOReq128(Cio, X##kio); \ - X##kuma = XOR128(LOAD128(state[14]), LOAD128(input[14])); \ - XOReq64(Cua, X##kuma); \ - X##me = XOR64(LOAD64(state[16]), LOAD64(input[16])); \ - X##kame = GET64LOLO(X##ka, X##me); \ - XOReq128(Cae, GET64HIHI(X##kuma, X##kame)); \ - X##mio = XOR128(LOAD128u(state[17]), LOAD64(input[17])); \ - X##mi = X##mio; \ - X##kemi = GET64LOLO(X##ke, X##mi); \ - X##mo = GET64HIHI(X##mio, X##mio); \ - X##kimo = GET64LOLO(X##ki, X##mo); \ - XOReq128(Cio, X##mio); \ - X##mu = LOAD64(state[19]); \ - X##komu = GET64LOLO(X##ko, X##mu); \ - XOReq64(Cua, X##mu); \ - X##sase = LOAD128(state[20]); \ - XOReq128(Cae, X##sase); \ - X##siso = LOAD128(state[22]); \ - XOReq128(Cio, X##siso); \ - X##su = LOAD64(state[24]); \ - XOReq64(Cua, X##su); \ - -#define copyFromStateAndXor1344bits(X, state, input) \ - X##bae = XOR128(LOAD128(state[ 0]), LOAD128u(input[ 0])); \ - X##ba = X##bae; \ - X##be = GET64HIHI(X##bae, X##bae); \ - Cae = X##bae; \ - X##bio = XOR128(LOAD128(state[ 2]), LOAD128u(input[ 2])); \ - X##bi = X##bio; \ - X##bo = GET64HIHI(X##bio, X##bio); \ - Cio = X##bio; \ - X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ - Cua = X##bu; \ - X##gae = XOR128(LOAD128u(state[ 5]), LOAD128u(input[ 5])); \ - X##ga = X##gae; \ - X##buga = GET64LOLO(X##bu, X##ga); \ - X##ge = GET64HIHI(X##gae, X##gae); \ - X##bage = GET64LOLO(X##ba, X##ge); \ - XOReq128(Cae, X##gae); \ - X##gio = XOR128(LOAD128u(state[ 7]), LOAD128u(input[ 7])); \ - X##gi = X##gio; \ - X##begi = GET64LOLO(X##be, X##gi); \ - X##go = GET64HIHI(X##gio, X##gio); \ - X##bigo = GET64LOLO(X##bi, X##go); \ - XOReq128(Cio, X##gio); \ - X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ - X##bogu = GET64LOLO(X##bo, X##gu); \ - XOReq64(Cua, X##gu); \ - X##kae = XOR128(LOAD128(state[10]), LOAD128u(input[10])); \ - X##ka = X##kae; \ - X##ke = GET64HIHI(X##kae, X##kae); \ - XOReq128(Cae, X##kae); \ - X##kio = XOR128(LOAD128(state[12]), LOAD128u(input[12])); \ - X##ki = X##kio; \ - X##ko = GET64HIHI(X##kio, X##kio); \ - XOReq128(Cio, X##kio); \ - X##kuma = XOR128(LOAD128(state[14]), LOAD128(input[14])); \ - XOReq64(Cua, X##kuma); \ - X##me = XOR64(LOAD64(state[16]), LOAD64(input[16])); \ - X##kame = GET64LOLO(X##ka, X##me); \ - XOReq128(Cae, GET64HIHI(X##kuma, X##kame)); \ - X##mio = XOR128(LOAD128u(state[17]), LOAD128u(input[17])); \ - X##mi = X##mio; \ - X##kemi = GET64LOLO(X##ke, X##mi); \ - X##mo = GET64HIHI(X##mio, X##mio); \ - X##kimo = GET64LOLO(X##ki, X##mo); \ - XOReq128(Cio, X##mio); \ - X##mu = XOR64(LOAD64(state[19]), LOAD64(input[19])); \ - X##komu = GET64LOLO(X##ko, X##mu); \ - XOReq64(Cua, X##mu); \ - X##sase = XOR128(LOAD128(state[20]), LOAD64(input[20])); \ - XOReq128(Cae, X##sase); \ - X##siso = LOAD128(state[22]); \ - XOReq128(Cio, X##siso); \ - X##su = LOAD64(state[24]); \ - XOReq64(Cua, X##su); \ - -#define copyFromState(X, state) \ - X##bae = LOAD128(state[ 0]); \ - X##ba = X##bae; \ - X##be = GET64HIHI(X##bae, X##bae); \ - Cae = X##bae; \ - X##bio = LOAD128(state[ 2]); \ - X##bi = X##bio; \ - X##bo = GET64HIHI(X##bio, X##bio); \ - Cio = X##bio; \ - X##bu = LOAD64(state[ 4]); \ - Cua = X##bu; \ - X##gae = LOAD128u(state[ 5]); \ - X##ga = X##gae; \ - X##buga = GET64LOLO(X##bu, X##ga); \ - X##ge = GET64HIHI(X##gae, X##gae); \ - X##bage = GET64LOLO(X##ba, X##ge); \ - XOReq128(Cae, X##gae); \ - X##gio = LOAD128u(state[ 7]); \ - X##gi = X##gio; \ - X##begi = GET64LOLO(X##be, X##gi); \ - X##go = GET64HIHI(X##gio, X##gio); \ - X##bigo = GET64LOLO(X##bi, X##go); \ - XOReq128(Cio, X##gio); \ - X##gu = LOAD64(state[ 9]); \ - X##bogu = GET64LOLO(X##bo, X##gu); \ - XOReq64(Cua, X##gu); \ - X##kae = LOAD128(state[10]); \ - X##ka = X##kae; \ - X##ke = GET64HIHI(X##kae, X##kae); \ - XOReq128(Cae, X##kae); \ - X##kio = LOAD128(state[12]); \ - X##ki = X##kio; \ - X##ko = GET64HIHI(X##kio, X##kio); \ - XOReq128(Cio, X##kio); \ - X##kuma = LOAD128(state[14]); \ - XOReq64(Cua, X##kuma); \ - X##me = LOAD64(state[16]); \ - X##kame = GET64LOLO(X##ka, X##me); \ - XOReq128(Cae, GET64HIHI(X##kuma, X##kame)); \ - X##mio = LOAD128u(state[17]); \ - X##mi = X##mio; \ - X##kemi = GET64LOLO(X##ke, X##mi); \ - X##mo = GET64HIHI(X##mio, X##mio); \ - X##kimo = GET64LOLO(X##ki, X##mo); \ - XOReq128(Cio, X##mio); \ - X##mu = LOAD64(state[19]); \ - X##komu = GET64LOLO(X##ko, X##mu); \ - XOReq64(Cua, X##mu); \ - X##sase = LOAD128(state[20]); \ - XOReq128(Cae, X##sase); \ - X##siso = LOAD128(state[22]); \ - XOReq128(Cio, X##siso); \ - X##su = LOAD64(state[24]); \ - XOReq64(Cua, X##su); \ - -#define copyToState(state, X) \ - STORE64(state[ 0], X##bage); \ - STORE64(state[ 1], X##begi); \ - STORE64(state[ 2], X##bigo); \ - STORE64(state[ 3], X##bogu); \ - STORE128(state[ 4], X##buga); \ - STORE64(state[ 6], COPY64HI2LO(X##bage)); \ - STORE64(state[ 7], COPY64HI2LO(X##begi)); \ - STORE64(state[ 8], COPY64HI2LO(X##bigo)); \ - STORE64(state[ 9], COPY64HI2LO(X##bogu)); \ - STORE64(state[10], X##kame); \ - STORE64(state[11], X##kemi); \ - STORE64(state[12], X##kimo); \ - STORE64(state[13], X##komu); \ - STORE128(state[14], X##kuma); \ - STORE64(state[16], COPY64HI2LO(X##kame)); \ - STORE64(state[17], COPY64HI2LO(X##kemi)); \ - STORE64(state[18], COPY64HI2LO(X##kimo)); \ - STORE64(state[19], COPY64HI2LO(X##komu)); \ - STORE128(state[20], X##sase); \ - STORE128(state[22], X##siso); \ - STORE64(state[24], X##su); \ - -#define copyStateVariables(X, Y) \ - X##bage = Y##bage; \ - X##begi = Y##begi; \ - X##bigo = Y##bigo; \ - X##bogu = Y##bogu; \ - X##buga = Y##buga; \ - X##kame = Y##kame; \ - X##kemi = Y##kemi; \ - X##kimo = Y##kimo; \ - X##komu = Y##komu; \ - X##kuma = Y##kuma; \ - X##sase = Y##sase; \ - X##siso = Y##siso; \ - X##su = Y##su; \ - diff --git a/Modules/_sha3/keccak/KeccakNISTInterface.c b/Modules/_sha3/keccak/KeccakNISTInterface.c deleted file mode 100644 --- a/Modules/_sha3/keccak/KeccakNISTInterface.c +++ /dev/null @@ -1,83 +0,0 @@ -/* -The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, -Micha?l Peeters and Gilles Van Assche. For more information, feedback or -questions, please refer to our website: http://keccak.noekeon.org/ - -Implementation by the designers, -hereby denoted as "the implementer". - -To the extent possible under law, the implementer has waived all copyright -and related or neighboring rights to the source code in this file. -http://creativecommons.org/publicdomain/zero/1.0/ -*/ - -#include -#include "KeccakNISTInterface.h" -#include "KeccakF-1600-interface.h" - -static HashReturn Init(hashState *state, int hashbitlen) -{ - switch(hashbitlen) { - case 0: /* Default parameters, arbitrary length output */ - InitSponge((spongeState*)state, 1024, 576); - break; - case 224: - InitSponge((spongeState*)state, 1152, 448); - break; - case 256: - InitSponge((spongeState*)state, 1088, 512); - break; - case 384: - InitSponge((spongeState*)state, 832, 768); - break; - case 512: - InitSponge((spongeState*)state, 576, 1024); - break; - default: - return BAD_HASHLEN; - } - state->fixedOutputLength = hashbitlen; - return SUCCESS; -} - -static HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen) -{ - if ((databitlen % 8) == 0) - return Absorb((spongeState*)state, data, databitlen); - else { - HashReturn ret = Absorb((spongeState*)state, data, databitlen - (databitlen % 8)); - if (ret == SUCCESS) { - unsigned char lastByte; - /* Align the last partial byte to the least significant bits */ - lastByte = data[databitlen/8] >> (8 - (databitlen % 8)); - return Absorb((spongeState*)state, &lastByte, databitlen % 8); - } - else - return ret; - } -} - -static HashReturn Final(hashState *state, BitSequence *hashval) -{ - return Squeeze(state, hashval, state->fixedOutputLength); -} - -/* -static HashReturn Hash(int hashbitlen, const BitSequence *data, DataLength databitlen, BitSequence *hashval) -{ - hashState state; - HashReturn result; - - if ((hashbitlen != 224) && (hashbitlen != 256) && (hashbitlen != 384) && (hashbitlen != 512)) - return BAD_HASHLEN; * Only the four fixed output lengths available through this API * - result = Init(&state, hashbitlen); - if (result != SUCCESS) - return result; - result = Update(&state, data, databitlen); - if (result != SUCCESS) - return result; - result = Final(&state, hashval); - return result; -} -*/ - diff --git a/Modules/_sha3/keccak/KeccakNISTInterface.h b/Modules/_sha3/keccak/KeccakNISTInterface.h deleted file mode 100644 --- a/Modules/_sha3/keccak/KeccakNISTInterface.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, -Micha?l Peeters and Gilles Van Assche. For more information, feedback or -questions, please refer to our website: http://keccak.noekeon.org/ - -Implementation by the designers, -hereby denoted as "the implementer". - -To the extent possible under law, the implementer has waived all copyright -and related or neighboring rights to the source code in this file. -http://creativecommons.org/publicdomain/zero/1.0/ -*/ - -#ifndef _KeccakNISTInterface_h_ -#define _KeccakNISTInterface_h_ - -#include "KeccakSponge.h" - -typedef unsigned char BitSequence; -typedef unsigned long long DataLength; -typedef enum { SUCCESS = 0, FAIL = 1, BAD_HASHLEN = 2 } HashReturn; - -typedef spongeState hashState; - -/** - * Function to initialize the state of the Keccak[r, c] sponge function. - * The rate r and capacity c values are determined from @a hashbitlen. - * @param state Pointer to the state of the sponge function to be initialized. - * @param hashbitlen The desired number of output bits, - * or 0 for Keccak[] with default parameters - * and arbitrarily-long output. - * @pre The value of hashbitlen must be one of 0, 224, 256, 384 and 512. - * @return SUCCESS if successful, BAD_HASHLEN if the value of hashbitlen is incorrect. - */ -static HashReturn Init(hashState *state, int hashbitlen); -/** - * Function to give input data for the sponge function to absorb. - * @param state Pointer to the state of the sponge function initialized by Init(). - * @param data Pointer to the input data. - * When @a databitLen is not a multiple of 8, the last bits of data must be - * in the most significant bits of the last byte. - * @param databitLen The number of input bits provided in the input data. - * @pre In the previous call to Absorb(), databitLen was a multiple of 8. - * @return SUCCESS if successful, FAIL otherwise. - */ -static HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen); -/** - * Function to squeeze output data from the sponge function. - * If @a hashbitlen was not 0 in the call to Init(), the number of output bits is equal to @a hashbitlen. - * If @a hashbitlen was 0 in the call to Init(), the output bits must be extracted using the Squeeze() function. - * @param state Pointer to the state of the sponge function initialized by Init(). - * @param hashval Pointer to the buffer where to store the output data. - * @return SUCCESS if successful, FAIL otherwise. - */ -static HashReturn Final(hashState *state, BitSequence *hashval); -/** - * Function to compute a hash using the Keccak[r, c] sponge function. - * The rate r and capacity c values are determined from @a hashbitlen. - * @param hashbitlen The desired number of output bits. - * @param data Pointer to the input data. - * When @a databitLen is not a multiple of 8, the last bits of data must be - * in the most significant bits of the last byte. - * @param databitLen The number of input bits provided in the input data. - * @param hashval Pointer to the buffer where to store the output data. - * @pre The value of hashbitlen must be one of 224, 256, 384 and 512. - * @return SUCCESS if successful, BAD_HASHLEN if the value of hashbitlen is incorrect. - */ -/* -static HashReturn Hash(int hashbitlen, const BitSequence *data, DataLength databitlen, BitSequence *hashval); -*/ - -#endif diff --git a/Modules/_sha3/keccak/KeccakSponge.c b/Modules/_sha3/keccak/KeccakSponge.c deleted file mode 100644 --- a/Modules/_sha3/keccak/KeccakSponge.c +++ /dev/null @@ -1,266 +0,0 @@ -/* -The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, -Micha?l Peeters and Gilles Van Assche. For more information, feedback or -questions, please refer to our website: http://keccak.noekeon.org/ - -Implementation by the designers, -hereby denoted as "the implementer". - -To the extent possible under law, the implementer has waived all copyright -and related or neighboring rights to the source code in this file. -http://creativecommons.org/publicdomain/zero/1.0/ -*/ - -#include -#include "KeccakSponge.h" -#include "KeccakF-1600-interface.h" -#ifdef KeccakReference -#include "displayIntermediateValues.h" -#endif - -static int InitSponge(spongeState *state, unsigned int rate, unsigned int capacity) -{ - if (rate+capacity != 1600) - return 1; - if ((rate <= 0) || (rate >= 1600) || ((rate % 64) != 0)) - return 1; - KeccakInitialize(); - state->rate = rate; - state->capacity = capacity; - state->fixedOutputLength = 0; - KeccakInitializeState(state->state); - memset(state->dataQueue, 0, KeccakMaximumRateInBytes); - state->bitsInQueue = 0; - state->squeezing = 0; - state->bitsAvailableForSqueezing = 0; - - return 0; -} - -static void AbsorbQueue(spongeState *state) -{ - /* state->bitsInQueue is assumed to be equal to state->rate */ - #ifdef KeccakReference - displayBytes(1, "Block to be absorbed", state->dataQueue, state->rate/8); - #endif -#ifdef ProvideFast576 - if (state->rate == 576) - KeccakAbsorb576bits(state->state, state->dataQueue); - else -#endif -#ifdef ProvideFast832 - if (state->rate == 832) - KeccakAbsorb832bits(state->state, state->dataQueue); - else -#endif -#ifdef ProvideFast1024 - if (state->rate == 1024) - KeccakAbsorb1024bits(state->state, state->dataQueue); - else -#endif -#ifdef ProvideFast1088 - if (state->rate == 1088) - KeccakAbsorb1088bits(state->state, state->dataQueue); - else -#endif -#ifdef ProvideFast1152 - if (state->rate == 1152) - KeccakAbsorb1152bits(state->state, state->dataQueue); - else -#endif -#ifdef ProvideFast1344 - if (state->rate == 1344) - KeccakAbsorb1344bits(state->state, state->dataQueue); - else -#endif - KeccakAbsorb(state->state, state->dataQueue, state->rate/64); - state->bitsInQueue = 0; -} - -static int Absorb(spongeState *state, const unsigned char *data, unsigned long long databitlen) -{ - unsigned long long i, j, wholeBlocks; - unsigned int partialBlock, partialByte; - const unsigned char *curData; - - if ((state->bitsInQueue % 8) != 0) - return 1; /* Only the last call may contain a partial byte */ - if (state->squeezing) - return 1; /* Too late for additional input */ - - i = 0; - while(i < databitlen) { - if ((state->bitsInQueue == 0) && (databitlen >= state->rate) && (i <= (databitlen-state->rate))) { - wholeBlocks = (databitlen-i)/state->rate; - curData = data+i/8; -#ifdef ProvideFast576 - if (state->rate == 576) { - for(j=0; jrate/8); - #endif - KeccakAbsorb576bits(state->state, curData); - } - } - else -#endif -#ifdef ProvideFast832 - if (state->rate == 832) { - for(j=0; jrate/8); - #endif - KeccakAbsorb832bits(state->state, curData); - } - } - else -#endif -#ifdef ProvideFast1024 - if (state->rate == 1024) { - for(j=0; jrate/8); - #endif - KeccakAbsorb1024bits(state->state, curData); - } - } - else -#endif -#ifdef ProvideFast1088 - if (state->rate == 1088) { - for(j=0; jrate/8); - #endif - KeccakAbsorb1088bits(state->state, curData); - } - } - else -#endif -#ifdef ProvideFast1152 - if (state->rate == 1152) { - for(j=0; jrate/8); - #endif - KeccakAbsorb1152bits(state->state, curData); - } - } - else -#endif -#ifdef ProvideFast1344 - if (state->rate == 1344) { - for(j=0; jrate/8); - #endif - KeccakAbsorb1344bits(state->state, curData); - } - } - else -#endif - { - for(j=0; jrate/8) { - #ifdef KeccakReference - displayBytes(1, "Block to be absorbed", curData, state->rate/8); - #endif - KeccakAbsorb(state->state, curData, state->rate/64); - } - } - i += wholeBlocks*state->rate; - } - else { - partialBlock = (unsigned int)(databitlen - i); - if (partialBlock+state->bitsInQueue > state->rate) - partialBlock = state->rate-state->bitsInQueue; - partialByte = partialBlock % 8; - partialBlock -= partialByte; - memcpy(state->dataQueue+state->bitsInQueue/8, data+i/8, partialBlock/8); - state->bitsInQueue += partialBlock; - i += partialBlock; - if (state->bitsInQueue == state->rate) - AbsorbQueue(state); - if (partialByte > 0) { - unsigned char mask = (1 << partialByte)-1; - state->dataQueue[state->bitsInQueue/8] = data[i/8] & mask; - state->bitsInQueue += partialByte; - i += partialByte; - } - } - } - return 0; -} - -static void PadAndSwitchToSqueezingPhase(spongeState *state) -{ - /* Note: the bits are numbered from 0=LSB to 7=MSB */ - if (state->bitsInQueue + 1 == state->rate) { - state->dataQueue[state->bitsInQueue/8 ] |= 1 << (state->bitsInQueue % 8); - AbsorbQueue(state); - memset(state->dataQueue, 0, state->rate/8); - } - else { - memset(state->dataQueue + (state->bitsInQueue+7)/8, 0, state->rate/8 - (state->bitsInQueue+7)/8); - state->dataQueue[state->bitsInQueue/8 ] |= 1 << (state->bitsInQueue % 8); - } - state->dataQueue[(state->rate-1)/8] |= 1 << ((state->rate-1) % 8); - AbsorbQueue(state); - - #ifdef KeccakReference - displayText(1, "--- Switching to squeezing phase ---"); - #endif -#ifdef ProvideFast1024 - if (state->rate == 1024) { - KeccakExtract1024bits(state->state, state->dataQueue); - state->bitsAvailableForSqueezing = 1024; - } - else -#endif - { - KeccakExtract(state->state, state->dataQueue, state->rate/64); - state->bitsAvailableForSqueezing = state->rate; - } - #ifdef KeccakReference - displayBytes(1, "Block available for squeezing", state->dataQueue, state->bitsAvailableForSqueezing/8); - #endif - state->squeezing = 1; -} - -static int Squeeze(spongeState *state, unsigned char *output, unsigned long long outputLength) -{ - unsigned long long i; - unsigned int partialBlock; - - if (!state->squeezing) - PadAndSwitchToSqueezingPhase(state); - if ((outputLength % 8) != 0) - return 1; /* Only multiple of 8 bits are allowed, truncation can be done at user level */ - - i = 0; - while(i < outputLength) { - if (state->bitsAvailableForSqueezing == 0) { - KeccakPermutation(state->state); -#ifdef ProvideFast1024 - if (state->rate == 1024) { - KeccakExtract1024bits(state->state, state->dataQueue); - state->bitsAvailableForSqueezing = 1024; - } - else -#endif - { - KeccakExtract(state->state, state->dataQueue, state->rate/64); - state->bitsAvailableForSqueezing = state->rate; - } - #ifdef KeccakReference - displayBytes(1, "Block available for squeezing", state->dataQueue, state->bitsAvailableForSqueezing/8); - #endif - } - partialBlock = state->bitsAvailableForSqueezing; - if ((unsigned long long)partialBlock > outputLength - i) - partialBlock = (unsigned int)(outputLength - i); - memcpy(output+i/8, state->dataQueue+(state->rate-state->bitsAvailableForSqueezing)/8, partialBlock/8); - state->bitsAvailableForSqueezing -= partialBlock; - i += partialBlock; - } - return 0; -} diff --git a/Modules/_sha3/keccak/KeccakSponge.h b/Modules/_sha3/keccak/KeccakSponge.h deleted file mode 100644 --- a/Modules/_sha3/keccak/KeccakSponge.h +++ /dev/null @@ -1,76 +0,0 @@ -/* -The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, -Micha?l Peeters and Gilles Van Assche. For more information, feedback or -questions, please refer to our website: http://keccak.noekeon.org/ - -Implementation by the designers, -hereby denoted as "the implementer". - -To the extent possible under law, the implementer has waived all copyright -and related or neighboring rights to the source code in this file. -http://creativecommons.org/publicdomain/zero/1.0/ -*/ - -#ifndef _KeccakSponge_h_ -#define _KeccakSponge_h_ - -#define KeccakPermutationSize 1600 -#define KeccakPermutationSizeInBytes (KeccakPermutationSize/8) -#define KeccakMaximumRate 1536 -#define KeccakMaximumRateInBytes (KeccakMaximumRate/8) - -#if defined(__GNUC__) -#define ALIGN __attribute__ ((aligned(32))) -#elif defined(_MSC_VER) -#define ALIGN __declspec(align(32)) -#else -#define ALIGN -#endif - -ALIGN typedef struct spongeStateStruct { - ALIGN unsigned char state[KeccakPermutationSizeInBytes]; - ALIGN unsigned char dataQueue[KeccakMaximumRateInBytes]; - unsigned int rate; - unsigned int capacity; - unsigned int bitsInQueue; - unsigned int fixedOutputLength; - int squeezing; - unsigned int bitsAvailableForSqueezing; -} spongeState; - -/** - * Function to initialize the state of the Keccak[r, c] sponge function. - * The sponge function is set to the absorbing phase. - * @param state Pointer to the state of the sponge function to be initialized. - * @param rate The value of the rate r. - * @param capacity The value of the capacity c. - * @pre One must have r+c=1600 and the rate a multiple of 64 bits in this implementation. - * @return Zero if successful, 1 otherwise. - */ -static int InitSponge(spongeState *state, unsigned int rate, unsigned int capacity); -/** - * Function to give input data for the sponge function to absorb. - * @param state Pointer to the state of the sponge function initialized by InitSponge(). - * @param data Pointer to the input data. - * When @a databitLen is not a multiple of 8, the last bits of data must be - * in the least significant bits of the last byte. - * @param databitLen The number of input bits provided in the input data. - * @pre In the previous call to Absorb(), databitLen was a multiple of 8. - * @pre The sponge function must be in the absorbing phase, - * i.e., Squeeze() must not have been called before. - * @return Zero if successful, 1 otherwise. - */ -static int Absorb(spongeState *state, const unsigned char *data, unsigned long long databitlen); -/** - * Function to squeeze output data from the sponge function. - * If the sponge function was in the absorbing phase, this function - * switches it to the squeezing phase. - * @param state Pointer to the state of the sponge function initialized by InitSponge(). - * @param output Pointer to the buffer where to store the output data. - * @param outputLength The number of output bits desired. - * It must be a multiple of 8. - * @return Zero if successful, 1 otherwise. - */ -static int Squeeze(spongeState *state, unsigned char *output, unsigned long long outputLength); - -#endif diff --git a/Modules/_sha3/keccak/brg_endian.h b/Modules/_sha3/keccak/brg_endian.h deleted file mode 100755 --- a/Modules/_sha3/keccak/brg_endian.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - --------------------------------------------------------------------------- - Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. - - LICENSE TERMS - - The redistribution and use of this software (with or without changes) - is allowed without the payment of fees or royalties provided that: - - 1. source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - 2. binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation; - - 3. the name of the copyright holder is not used to endorse products - built using this software without specific written permission. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and/or fitness for purpose. - --------------------------------------------------------------------------- - Issue Date: 20/12/2007 - Changes for ARM 9/9/2010 -*/ - -#ifndef _BRG_ENDIAN_H -#define _BRG_ENDIAN_H - -#define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ -#define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ - -#if 0 -/* Include files where endian defines and byteswap functions may reside */ -#if defined( __sun ) -# include -#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ ) -# include -#elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \ - defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ ) -# include -#elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ ) -# if !defined( __MINGW32__ ) && !defined( _AIX ) -# include -# if !defined( __BEOS__ ) -# include -# endif -# endif -#endif -#endif - -/* Now attempt to set the define for platform byte order using any */ -/* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */ -/* seem to encompass most endian symbol definitions */ - -#if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN ) -# if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -# elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -# endif -#elif defined( BIG_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#elif defined( LITTLE_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#endif - -#if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN ) -# if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -# elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -# endif -#elif defined( _BIG_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#elif defined( _LITTLE_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#endif - -#if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN ) -# if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -# elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -# endif -#elif defined( __BIG_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#elif defined( __LITTLE_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#endif - -#if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ ) -# if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__ -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -# elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__ -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -# endif -#elif defined( __BIG_ENDIAN__ ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#elif defined( __LITTLE_ENDIAN__ ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#endif - -/* if the platform byte order could not be determined, then try to */ -/* set this define using common machine defines */ -#if !defined(PLATFORM_BYTE_ORDER) - -#if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \ - defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \ - defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \ - defined( vax ) || defined( vms ) || defined( VMS ) || \ - defined( __VMS ) || defined( _M_X64 ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN - -#elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \ - defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \ - defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \ - defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \ - defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \ - defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \ - defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN - -#elif defined(__arm__) -# ifdef __BIG_ENDIAN -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -# else -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -# endif -#elif 1 /* **** EDIT HERE IF NECESSARY **** */ -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#elif 0 /* **** EDIT HERE IF NECESSARY **** */ -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#else -# error Please edit lines 132 or 134 in brg_endian.h to set the platform byte order -#endif - -#endif - -#endif diff --git a/Modules/_sha3/keccak/crypto_hash.h b/Modules/_sha3/keccak/crypto_hash.h deleted file mode 100644 diff --git a/Modules/_sha3/sha3module.c b/Modules/_sha3/sha3module.c deleted file mode 100644 --- a/Modules/_sha3/sha3module.c +++ /dev/null @@ -1,593 +0,0 @@ -/* SHA3 module - * - * This module provides an interface to the SHA3 algorithm - * - * See below for information about the original code this module was - * based upon. Additional work performed by: - * - * Andrew Kuchling (amk at amk.ca) - * Greg Stein (gstein at lyra.org) - * Trevor Perrin (trevp at trevp.net) - * Gregory P. Smith (greg at krypto.org) - * - * Copyright (C) 2012 Christian Heimes (christian at python.org) - * Licensed to PSF under a Contributor Agreement. - * - */ - -#include "Python.h" -#include "../hashlib.h" - -/* ************************************************************************** - * SHA-3 (Keccak) - * - * The code is based on KeccakReferenceAndOptimized-3.2.zip from 29 May 2012. - * - * The reference implementation is altered in this points: - * - C++ comments are converted to ANSI C comments. - * - All functions and globals are declared static. - * - The typedef for UINT64 is commented out. - * - KeccakF-1600-opt[32|64]-settings.h are commented out - * - Some unused functions are commented out to silence compiler warnings. - * - * In order to avoid name clashes with other software I have to declare all - * Keccak functions and global data as static. The C code is directly - * included into this file in order to access the static functions. - * - * Keccak can be tuned with several paramenters. I try to explain all options - * as far as I understand them. The reference implementation also contains - * assembler code for ARM platforms (NEON instructions). - * - * Common - * ====== - * - * Options: - * UseBebigokimisa, Unrolling - * - * - Unrolling: loop unrolling (24, 12, 8, 6, 4, 3, 2, 1) - * - UseBebigokimisa: lane complementing - * - * 64bit platforms - * =============== - * - * Additional options: - * UseSSE, UseOnlySIMD64, UseMMX, UseXOP, UseSHLD - * - * Optimized instructions (disabled by default): - * - UseSSE: use Stream SIMD extensions - * o UseOnlySIMD64: limit to 64bit instructions, otherwise 128bit - * o w/o UseOnlySIMD64: requires compiler agument -mssse3 or -mtune - * - UseMMX: use 64bit MMX instructions - * - UseXOP: use AMD's eXtended Operations (128bit SSE extension) - * - * Other: - * - Unrolling: default 24 - * - UseBebigokimisa: default 1 - * - * When neither UseSSE, UseMMX nor UseXOP is configured, ROL64 (rotate left - * 64) is implemented as: - * - Windows: _rotl64() - * - UseSHLD: use shld (shift left) asm optimization - * - otherwise: shift and xor - * - * UseBebigokimisa can't be used in combination with UseSSE, UseMMX or - * UseXOP. UseOnlySIMD64 has no effect unless UseSSE is specified. - * - * Tests have shown that UseSSE + UseOnlySIMD64 is about three to four - * times SLOWER than UseBebigokimisa. UseSSE and UseMMX are about two times - * slower. (tested by CH and AP) - * - * 32bit platforms - * =============== - * - * Additional options: - * UseInterleaveTables, UseSchedule - * - * - Unrolling: default 2 - * - UseBebigokimisa: default n/a - * - UseSchedule: ???, (1, 2, 3; default 3) - * - UseInterleaveTables: use two 64k lookup tables for (de)interleaving - * default: n/a - * - * schedules: - * - 3: no UseBebigokimisa, Unrolling must be 2 - * - 2 + 1: ??? - * - * *************************************************************************/ - -#ifdef __sparc - /* opt64 uses un-aligned memory access that causes a BUS error with msg - * 'invalid address alignment' on SPARC. */ - #define KeccakOpt 32 -#elif SIZEOF_VOID_P == 8 && defined(PY_UINT64_T) - /* opt64 works only for 64bit platforms with unsigned int64 */ - #define KeccakOpt 64 -#else - /* opt32 is used for the remaining 32 and 64bit platforms */ - #define KeccakOpt 32 -#endif - -#if KeccakOpt == 64 && defined(PY_UINT64_T) - /* 64bit platforms with unsigned int64 */ - #define Unrolling 24 - #define UseBebigokimisa - typedef PY_UINT64_T UINT64; -#elif KeccakOpt == 32 && defined(PY_UINT64_T) - /* 32bit platforms with unsigned int64 */ - #define Unrolling 2 - #define UseSchedule 3 - typedef PY_UINT64_T UINT64; -#else - /* 32 or 64bit platforms without unsigned int64 */ - #define Unrolling 2 - #define UseSchedule 3 - #define UseInterleaveTables -#endif - -/* replacement for brg_endian.h */ -#define IS_BIG_ENDIAN 4321 -#define IS_LITTLE_ENDIAN 1234 -#if PY_BIG_ENDIAN -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#else -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#endif - -/* inline all Keccak dependencies */ -#include "keccak/KeccakNISTInterface.h" -#include "keccak/KeccakNISTInterface.c" -#include "keccak/KeccakSponge.c" -#if KeccakOpt == 64 - #include "keccak/KeccakF-1600-opt64.c" -#elif KeccakOpt == 32 - #include "keccak/KeccakF-1600-opt32.c" -#endif - -/* #define SHA3_BLOCKSIZE 200 // 1600 bits */ -#define SHA3_MAX_DIGESTSIZE 64 /* 512 bits */ -#define SHA3_state hashState -#define SHA3_init Init -#define SHA3_process Update -#define SHA3_done Final -#define SHA3_copystate(dest, src) memcpy(&(dest), &(src), sizeof(SHA3_state)) -#define SHA3_clearstate(state) memset(&(state), 0, sizeof(SHA3_state)) - -/* The structure for storing SHA3 info */ - -typedef struct { - PyObject_HEAD - int hashbitlen; - SHA3_state hash_state; -#ifdef WITH_THREAD - PyThread_type_lock lock; -#endif - -} SHA3object; - -static PyTypeObject SHA3type; - - -static SHA3object * -newSHA3object(int hashbitlen) -{ - SHA3object *newobj; - - /* check hashbitlen */ - switch(hashbitlen) { - /* supported hash length */ - case 224: - break; - case 256: - break; - case 384: - break; - case 512: - break; - case 0: - /* arbitrarily-long output isn't supported by this module */ - default: - /* everything else is an error */ - PyErr_SetString(PyExc_ValueError, - "hashbitlen must be one of 224, 256, 384 or 512."); - return NULL; - } - newobj = (SHA3object *)PyObject_New(SHA3object, &SHA3type); - if (newobj == NULL) { - return NULL; - } - newobj->hashbitlen = hashbitlen; -#ifdef WITH_THREAD - newobj->lock = NULL; -#endif - return newobj; -} - - -/* Internal methods for a hash object */ - -static void -SHA3_dealloc(SHA3object *self) -{ - SHA3_clearstate(self->hash_state); -#ifdef WITH_THREAD - if (self->lock) { - PyThread_free_lock(self->lock); - } -#endif - PyObject_Del(self); -} - - -/* External methods for a hash object */ - -PyDoc_STRVAR(SHA3_copy__doc__, "Return a copy of the hash object."); - -static PyObject * -SHA3_copy(SHA3object *self, PyObject *unused) -{ - SHA3object *newobj; - - if ((newobj = newSHA3object(self->hashbitlen)) == NULL) { - return NULL; - } - ENTER_HASHLIB(self); - SHA3_copystate(newobj->hash_state, self->hash_state); - LEAVE_HASHLIB(self); - return (PyObject *)newobj; -} - - -PyDoc_STRVAR(SHA3_digest__doc__, -"Return the digest value as a string of binary data."); - -static PyObject * -SHA3_digest(SHA3object *self, PyObject *unused) -{ - unsigned char digest[SHA3_MAX_DIGESTSIZE]; - SHA3_state temp; - HashReturn res; - - ENTER_HASHLIB(self); - SHA3_copystate(temp, self->hash_state); - LEAVE_HASHLIB(self); - res = SHA3_done(&temp, digest); - SHA3_clearstate(temp); - if (res != SUCCESS) { - PyErr_SetString(PyExc_RuntimeError, "internal error in SHA3 Final()"); - return NULL; - } - return PyBytes_FromStringAndSize((const char *)digest, - self->hashbitlen / 8); -} - - -PyDoc_STRVAR(SHA3_hexdigest__doc__, -"Return the digest value as a string of hexadecimal digits."); - -static PyObject * -SHA3_hexdigest(SHA3object *self, PyObject *unused) -{ - unsigned char digest[SHA3_MAX_DIGESTSIZE]; - SHA3_state temp; - HashReturn res; - PyObject *retval; - Py_UCS1 *hex_digest; - int digestlen, i, j; - - /* Get the raw (binary) digest value */ - ENTER_HASHLIB(self); - SHA3_copystate(temp, self->hash_state); - LEAVE_HASHLIB(self); - res = SHA3_done(&temp, digest); - SHA3_clearstate(temp); - if (res != SUCCESS) { - PyErr_SetString(PyExc_RuntimeError, "internal error in SHA3 Final()"); - return NULL; - } - - /* Create a new string */ - digestlen = self->hashbitlen / 8; - retval = PyUnicode_New(digestlen * 2, 127); - if (!retval) - return NULL; - hex_digest = PyUnicode_1BYTE_DATA(retval); - - /* Make hex version of the digest */ - for(i=j=0; i < digestlen; i++) { - unsigned char c; - c = (digest[i] >> 4) & 0xf; - hex_digest[j++] = Py_hexdigits[c]; - c = (digest[i] & 0xf); - hex_digest[j++] = Py_hexdigits[c]; - } -#ifdef Py_DEBUG - assert(_PyUnicode_CheckConsistency(retval, 1)); -#endif - return retval; -} - -PyDoc_STRVAR(SHA3_update__doc__, -"Update this hash object's state with the provided string."); - -static PyObject * -SHA3_update(SHA3object *self, PyObject *args) -{ - PyObject *obj; - Py_buffer buf; - HashReturn res; - - if (!PyArg_ParseTuple(args, "O:update", &obj)) - return NULL; - - GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - - /* add new data, the function takes the length in bits not bytes */ -#ifdef WITH_THREAD - if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { - self->lock = PyThread_allocate_lock(); - } - /* Once a lock exists all code paths must be synchronized. We have to - * release the GIL even for small buffers as acquiring the lock may take - * an unlimited amount of time when another thread updates this object - * with lots of data. */ - if (self->lock) { - Py_BEGIN_ALLOW_THREADS - PyThread_acquire_lock(self->lock, 1); - res = SHA3_process(&self->hash_state, buf.buf, buf.len * 8); - PyThread_release_lock(self->lock); - Py_END_ALLOW_THREADS - } - else { - res = SHA3_process(&self->hash_state, buf.buf, buf.len * 8); - } -#else - res = SHA3_process(&self->hash_state, buf.buf, buf.len * 8); -#endif - LEAVE_HASHLIB(self); - - if (res != SUCCESS) { - PyBuffer_Release(&buf); - PyErr_SetString(PyExc_RuntimeError, - "internal error in SHA3 Update()"); - return NULL; - } - - PyBuffer_Release(&buf); - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef SHA3_methods[] = { - {"copy", (PyCFunction)SHA3_copy, METH_NOARGS, - SHA3_copy__doc__}, - {"digest", (PyCFunction)SHA3_digest, METH_NOARGS, - SHA3_digest__doc__}, - {"hexdigest", (PyCFunction)SHA3_hexdigest, METH_NOARGS, - SHA3_hexdigest__doc__}, - {"update", (PyCFunction)SHA3_update, METH_VARARGS, - SHA3_update__doc__}, - {NULL, NULL} /* sentinel */ -}; - -static PyObject * -SHA3_get_block_size(SHA3object *self, void *closure) -{ - /* HMAC-SHA3 hasn't been specified yet and no official test vectors are - * available. Thus block_size returns NotImplemented to prevent people - * from using SHA3 with the hmac module. - */ - Py_RETURN_NOTIMPLEMENTED; -} - -static PyObject * -SHA3_get_name(SHA3object *self, void *closure) -{ - return PyUnicode_FromFormat("sha3_%i", self->hashbitlen); -} - -static PyObject * -SHA3_get_digest_size(SHA3object *self, void *closure) -{ - return PyLong_FromLong(self->hashbitlen / 8); -} - - -static PyGetSetDef SHA3_getseters[] = { - {"block_size", (getter)SHA3_get_block_size, NULL, NULL, NULL}, - {"name", (getter)SHA3_get_name, NULL, NULL, NULL}, - {"digest_size", (getter)SHA3_get_digest_size, NULL, NULL, NULL}, - {NULL} /* Sentinel */ -}; - -static PyTypeObject SHA3type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_sha3.SHA3", /* tp_name */ - sizeof(SHA3object), /* tp_size */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)SHA3_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - SHA3_methods, /* tp_methods */ - NULL, /* tp_members */ - SHA3_getseters, /* tp_getset */ -}; - - -/* constructor helper */ -static PyObject * -SHA3_factory(PyObject *args, PyObject *kwdict, const char *fmt, - int hashbitlen) -{ - SHA3object *newobj = NULL; - static char *kwlist[] = {"string", NULL}; - PyObject *data_obj = NULL; - Py_buffer buf; - HashReturn res; - - if (!PyArg_ParseTupleAndKeywords(args, kwdict, fmt, kwlist, - &data_obj)) { - return NULL; - } - - if (data_obj) - GET_BUFFER_VIEW_OR_ERROUT(data_obj, &buf); - - if ((newobj = newSHA3object(hashbitlen)) == NULL) { - goto error; - } - - if (SHA3_init(&newobj->hash_state, hashbitlen) != SUCCESS) { - PyErr_SetString(PyExc_RuntimeError, - "internal error in SHA3 Update()"); - goto error; - } - - if (data_obj) { -#ifdef WITH_THREAD - if (buf.len >= HASHLIB_GIL_MINSIZE) { - /* invariant: New objects can't be accessed by other code yet, - * thus it's safe to release the GIL without locking the object. - */ - Py_BEGIN_ALLOW_THREADS - res = SHA3_process(&newobj->hash_state, buf.buf, buf.len * 8); - Py_END_ALLOW_THREADS - } - else { - res = SHA3_process(&newobj->hash_state, buf.buf, buf.len * 8); - } -#else - res = SHA3_process(&newobj->hash_state, buf.buf, buf.len * 8); -#endif - if (res != SUCCESS) { - PyErr_SetString(PyExc_RuntimeError, - "internal error in SHA3 Update()"); - goto error; - } - PyBuffer_Release(&buf); - } - - return (PyObject *)newobj; - - error: - if (newobj) { - SHA3_dealloc(newobj); - } - if (data_obj) { - PyBuffer_Release(&buf); - } - return NULL; - -} - -PyDoc_STRVAR(sha3_224__doc__, -"sha3_224([string]) -> SHA3 object\n\ -\n\ -Return a new SHA3 hash object with a hashbit length of 28 bytes."); - -static PyObject * -sha3_224(PyObject *self, PyObject *args, PyObject *kwdict) -{ - return SHA3_factory(args, kwdict, "|O:sha3_224", 224); -} - - -PyDoc_STRVAR(sha3_256__doc__, -"sha3_256([string]) -> SHA3 object\n\ -\n\ -Return a new SHA3 hash object with a hashbit length of 32 bytes."); - -static PyObject * -sha3_256(PyObject *self, PyObject *args, PyObject *kwdict) -{ - return SHA3_factory(args, kwdict, "|O:sha3_256", 256); -} - -PyDoc_STRVAR(sha3_384__doc__, -"sha3_384([string]) -> SHA3 object\n\ -\n\ -Return a new SHA3 hash object with a hashbit length of 48 bytes."); - -static PyObject * -sha3_384(PyObject *self, PyObject *args, PyObject *kwdict) -{ - return SHA3_factory(args, kwdict, "|O:sha3_384", 384); -} - -PyDoc_STRVAR(sha3_512__doc__, -"sha3_512([string]) -> SHA3 object\n\ -\n\ -Return a new SHA3 hash object with a hashbit length of 64 bytes."); - -static PyObject * -sha3_512(PyObject *self, PyObject *args, PyObject *kwdict) -{ - return SHA3_factory(args, kwdict, "|O:sha3_512", 512); -} - - -/* List of functions exported by this module */ -static struct PyMethodDef SHA3_functions[] = { - {"sha3_224", (PyCFunction)sha3_224, METH_VARARGS|METH_KEYWORDS, - sha3_224__doc__}, - {"sha3_256", (PyCFunction)sha3_256, METH_VARARGS|METH_KEYWORDS, - sha3_256__doc__}, - {"sha3_384", (PyCFunction)sha3_384, METH_VARARGS|METH_KEYWORDS, - sha3_384__doc__}, - {"sha3_512", (PyCFunction)sha3_512, METH_VARARGS|METH_KEYWORDS, - sha3_512__doc__}, - {NULL, NULL} /* Sentinel */ -}; - - -/* Initialize this module. */ -static struct PyModuleDef _SHA3module = { - PyModuleDef_HEAD_INIT, - "_sha3", - NULL, - -1, - SHA3_functions, - NULL, - NULL, - NULL, - NULL -}; - -PyMODINIT_FUNC -PyInit__sha3(void) -{ - PyObject *m; - - Py_TYPE(&SHA3type) = &PyType_Type; - if (PyType_Ready(&SHA3type) < 0) { - return NULL; - } - - m = PyModule_Create(&_SHA3module); - if (m == NULL) - return NULL; - - Py_INCREF((PyObject *)&SHA3type); - PyModule_AddObject(m, "SHA3Type", (PyObject *)&SHA3type); - return m; -} diff --git a/PC/VS9.0/_sha3.vcproj b/PC/VS9.0/_sha3.vcproj deleted file mode 100644 --- a/PC/VS9.0/_sha3.vcproj +++ /dev/null @@ -1,513 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/PC/VS9.0/pcbuild.sln b/PC/VS9.0/pcbuild.sln --- a/PC/VS9.0/pcbuild.sln +++ b/PC/VS9.0/pcbuild.sln @@ -152,8 +152,6 @@ {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_sha3", "_sha3.vcproj", "{04F37400-883C-42D7-AE28-6CF9953BF975}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 diff --git a/PCbuild/_sha3.vcxproj b/PCbuild/_sha3.vcxproj deleted file mode 100644 --- a/PCbuild/_sha3.vcxproj +++ /dev/null @@ -1,218 +0,0 @@ -? - - - - Debug - Win32 - - - Debug - x64 - - - PGInstrument - Win32 - - - PGInstrument - x64 - - - PGUpdate - Win32 - - - PGUpdate - x64 - - - Release - Win32 - - - Release - x64 - - - - {254A0C05-6696-4B08-8CB2-EF7D533AEE01} - _sha3 - Win32Proj - - - - DynamicLibrary - NotSet - true - - - DynamicLibrary - NotSet - true - - - DynamicLibrary - NotSet - true - - - DynamicLibrary - NotSet - - - DynamicLibrary - NotSet - true - - - DynamicLibrary - NotSet - true - - - DynamicLibrary - NotSet - true - - - DynamicLibrary - NotSet - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - - - - %(AdditionalDependencies) - - - - - X64 - - - %(AdditionalDependencies) - - - - - %(AdditionalDependencies) - - - - - X64 - - - %(AdditionalDependencies) - - - - - %(AdditionalDependencies) - - - - - X64 - - - %(AdditionalDependencies) - MachineX64 - - - - - %(AdditionalDependencies) - - - - - X64 - - - %(AdditionalDependencies) - MachineX64 - - - - - {cf7ac3d1-e2df-41d2-bea6-1e2556cdea26} - false - - - - - - - - - \ No newline at end of file diff --git a/PCbuild/_sha3.vcxproj.filters b/PCbuild/_sha3.vcxproj.filters deleted file mode 100644 --- a/PCbuild/_sha3.vcxproj.filters +++ /dev/null @@ -1,13 +0,0 @@ -? - - - - {f1f1fd19-4f85-4a56-be41-af14f0bc2a9c} - - - - - Source Files - - - \ No newline at end of file diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -74,10 +74,6 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_freeze_importlib", "_freeze_importlib.vcxproj", "{19C0C13F-47CA-4432-AFF3-799A296A4DDC}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_sha3", "_sha3.vcxproj", "{254A0C05-6696-4B08-8CB2-EF7D533AEE01}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_overlapped", "_overlapped.vcxproj", "{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_testembed", "_testembed.vcxproj", "{6DAC66D9-E703-4624-BE03-49112AB5AA62}" EndProject Global diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -140,7 +140,6 @@ _msi _multiprocessing _overlapped -_sha3 _socket _testcapi _testbuffer diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py --- a/Tools/msi/msi.py +++ b/Tools/msi/msi.py @@ -100,7 +100,6 @@ '_lzma.pyd', '_decimal.pyd', '_testbuffer.pyd', - '_sha3.pyd', '_testimportmultiple.pyd', '_overlapped.pyd', ] diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -827,15 +827,6 @@ exts.append( Extension('_sha1', ['sha1module.c'], depends=['hashlib.h']) ) - # SHA-3 (Keccak) module - sha3_depends = ['hashlib.h'] - keccak = os.path.join(os.getcwd(), srcdir, 'Modules', '_sha3', - 'keccak') - for pattern in ('*.c', '*.h', '*.macros'): - sha3_depends.extend(glob(os.path.join(keccak, pattern))) - exts.append(Extension("_sha3", ["_sha3/sha3module.c"], - depends=sha3_depends)) - # Modules that provide persistent dictionary-like semantics. You will # probably want to arrange for at least one of them to be available on # your machine, though none are defined by default because of library -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 15:53:42 2014 From: python-checkins at python.org (martin.v.loewis) Date: Fri, 3 Jan 2014 15:53:42 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Revert_accidental_deletion?= =?utf-8?q?_of_=5Foverlapped=2E?= Message-ID: <3dwpyt4r87z7Ljw@mail.python.org> http://hg.python.org/cpython/rev/8a3718f31188 changeset: 88274:8a3718f31188 user: Martin v. L?wis date: Fri Jan 03 15:53:20 2014 +0100 summary: Revert accidental deletion of _overlapped. files: PCbuild/pcbuild.sln | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -74,6 +74,8 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_freeze_importlib", "_freeze_importlib.vcxproj", "{19C0C13F-47CA-4432-AFF3-799A296A4DDC}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_overlapped", "_overlapped.vcxproj", "{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_testembed", "_testembed.vcxproj", "{6DAC66D9-E703-4624-BE03-49112AB5AA62}" EndProject Global -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 17:40:10 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 3 Jan 2014 17:40:10 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Remove_now_unused_variable?= =?utf-8?q?s?= Message-ID: <3dwsKk6ZWGz7Ljf@mail.python.org> http://hg.python.org/cpython/rev/85006a6136bf changeset: 88275:85006a6136bf user: Victor Stinner date: Fri Jan 03 17:39:40 2014 +0100 summary: Remove now unused variables files: Objects/unicodeobject.c | 5 ----- 1 files changed, 0 insertions(+), 5 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -2876,10 +2876,6 @@ PyObject * PyUnicode_FromOrdinal(int ordinal) { - PyObject *v; - void *data; - int kind; - if (ordinal < 0 || ordinal > MAX_UNICODE) { PyErr_SetString(PyExc_ValueError, "chr() arg not in range(0x110000)"); @@ -11330,7 +11326,6 @@ void *data; enum PyUnicode_Kind kind; Py_UCS4 ch; - PyObject *res; if (!PyUnicode_Check(self) || PyUnicode_READY(self) == -1) { PyErr_BadArgument(); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 17:42:29 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 3 Jan 2014 17:42:29 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Remove_deadcode_=28HASH_ma?= =?utf-8?q?cro_is_no_more_defined=29?= Message-ID: <3dwsNP4wg1z7LjR@mail.python.org> http://hg.python.org/cpython/rev/14a2324e82e4 changeset: 88276:14a2324e82e4 user: Victor Stinner date: Fri Jan 03 17:42:18 2014 +0100 summary: Remove deadcode (HASH macro is no more defined) 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 @@ -11370,7 +11370,6 @@ _PyUnicode_HASH(self) = x; return x; } -#undef HASH PyDoc_STRVAR(index__doc__, "S.index(sub[, start[, end]]) -> int\n\ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 19:04:58 2014 From: python-checkins at python.org (r.david.murray) Date: Fri, 3 Jan 2014 19:04:58 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_http=2Eserver_?= =?utf-8?q?send=5Ferror_explain_parameter=2E?= Message-ID: <3dwvCZ6zMHzQnV@mail.python.org> http://hg.python.org/cpython/rev/8ade807624a5 changeset: 88277:8ade807624a5 user: R David Murray date: Fri Jan 03 13:03:00 2014 -0500 summary: whatsnew: http.server send_error explain parameter. Also rewrote the send_error description for clarity and correct English. files: Doc/library/http.server.rst | 15 +++++++++------ Doc/whatsnew/3.4.rst | 12 ++++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) 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 @@ -116,7 +116,7 @@ HTTP error code value. *message* should be a string containing a (detailed) error message of what occurred, and *explain* should be an explanation of the error code number. Default *message* and *explain* - values can found in the *responses* class variable. + values can found in the :attr:`responses` class variable. .. attribute:: error_content_type @@ -173,11 +173,14 @@ .. method:: send_error(code, message=None, explain=None) Sends and logs a complete error reply to the client. The numeric *code* - specifies the HTTP error code, with *message* as optional, more specific - text, usually referring to short message response. The *explain* - argument can be used to send a detailed information about the error in - response content body. A complete set of headers is sent, followed by - text composed using the :attr:`error_message_format` class variable. + specifies the HTTP error code, with *message* as an optional, short, human + readable description of the error. The *explain* argument can be used to + provide more detailed information about the error; it will be formatted + using the :attr:`error_message_format` class variable and emitted, after + a complete set of headers, as the response body. The :attr:`responses` + class variable holds the default values for *message* and *explain* that + will be used if no value is provided; for unknown codes the default value + for both is the string ``???``. .. versionchanged:: 3.4 The error response includes a Content-Length header. 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 @@ -684,6 +684,18 @@ (Contributed by Ezio Melotti in :issue:`15114`) +http +---- + +:meth:`~http.server.BaseHTTPRequestHandler.send_error` now accepts an +optional additional *exaplain* parameter which can be used to provide an +extended error description, overriding the hardcoded default if there is one. +This extended error description will be formatted using the +:attr:`~http.server.HTTP.error_message_format` attribute and sent as the body +of the error response. (Contributed by Karl Cow in :issue:`12921`.) + + + importlib --------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 19:05:00 2014 From: python-checkins at python.org (r.david.murray) Date: Fri, 3 Jan 2014 19:05:00 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_unittest_impor?= =?utf-8?q?t_time_SkipTest_reported_as_skip_not_error=2E?= Message-ID: <3dwvCc1gyczQnV@mail.python.org> http://hg.python.org/cpython/rev/22235c8e0a33 changeset: 88278:22235c8e0a33 user: R David Murray date: Fri Jan 03 13:03:36 2014 -0500 summary: whatsnew: unittest import time SkipTest reported as skip not error. files: Doc/library/unittest.rst | 5 +++-- Doc/whatsnew/3.4.rst | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -559,8 +559,9 @@ Usually you can use :meth:`TestCase.skipTest` or one of the skipping decorators instead of raising this directly. -Skipped tests will not have :meth:`setUp` or :meth:`tearDown` run around them. -Skipped classes will not have :meth:`setUpClass` or :meth:`tearDownClass` run. +Skipped tests will not have :meth:`~TestCase.setUp` or :meth:`~TestCase.tearDown` run around them. +Skipped classes will not have :meth:`~TestCase.setUpClass` or :meth:`~TestCase.tearDownClass` run. +Skipped modules will not have :func:`setUpModule` or :func:`tearDownModule` run. .. _subtests: 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 @@ -1015,6 +1015,10 @@ *defaultTest*, where previously it only accepted a single test name as a string. (Contributed by Jyrki Pulliainen in :issue:`15132`.) +If :class:`~unittest.SkipTest` is raised during test discovery (that is, at the +module level in the test file), it is now reported as a skip instead of an +error. (Contributed by Zach Ware in :issue:`16935`.) + venv ---- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 19:05:01 2014 From: python-checkins at python.org (r.david.murray) Date: Fri, 3 Jan 2014 19:05:01 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_deprecation_of?= =?utf-8?q?_HTTPConnection=27s_strict_parameter=2E?= Message-ID: <3dwvCd39HQz7LlG@mail.python.org> http://hg.python.org/cpython/rev/5ff4f2be7d8a changeset: 88279:5ff4f2be7d8a user: R David Murray date: Fri Jan 03 13:04:25 2014 -0500 summary: whatsnew: deprecation of HTTPConnection's strict parameter. files: Doc/library/http.client.rst | 12 ++++++------ Doc/whatsnew/3.4.rst | 5 ++++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -52,8 +52,8 @@ *source_address* was added. .. versionchanged:: 3.4 - The *strict* parameter is removed. HTTP 0.9-style "Simple Responses" are - not supported. + The *strict* parameter was removed. HTTP 0.9-style "Simple Responses" are + not longer supported. .. class:: HTTPSConnection(host, port=None, key_file=None, \ @@ -90,8 +90,8 @@ if :data:`ssl.HAS_SNI` is true). .. versionchanged:: 3.4 - The *strict* parameter is removed. HTTP 0.9-style "Simple Responses" are - not supported anymore. + The *strict* parameter was removed. HTTP 0.9-style "Simple Responses" are + no longer supported. .. class:: HTTPResponse(sock, debuglevel=0, method=None, url=None) @@ -100,8 +100,8 @@ instantiated directly by user. .. versionchanged:: 3.4 - The *strict* parameter is removed. HTTP 0.9 style "Simple Responses" are - not supported anymore. + The *strict* parameter was removed. HTTP 0.9 style "Simple Responses" are + no longer supported. The following exceptions are raised as appropriate: 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 @@ -1303,7 +1303,7 @@ * The unmaintained ``Misc/TextMate`` and ``Misc/vim`` directories have been removed (see the `devguide `_ - for what to use instead). + for suggestions on what to use instead). * The ``SO`` makefile macro is removed (it was replaced by the ``SHLIB_SUFFIX`` and ``EXT_SUFFIX`` macros) (:issue:`16754`). @@ -1314,6 +1314,9 @@ * ``PyLoader`` and ``PyPycLoader`` have been removed from :mod:`importlib`. (Contributed by Taras Lyapun in :issue:`15641`.) +* The *strict* argument to :class:`~http.client.HTTPConnection` has been + removed. HTTP 0.9-style "Simple Responses" are no longer supported. + Porting to Python 3.4 ===================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 20:00:28 2014 From: python-checkins at python.org (r.david.murray) Date: Fri, 3 Jan 2014 20:00:28 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_closes_16039?= =?utf-8?q?=3A_CVE-2013-1752=3A_limit_line_length_in_imaplib_readline_call?= =?utf-8?q?s=2E?= Message-ID: <3dwwRc4B3Kz7Ljg@mail.python.org> http://hg.python.org/cpython/rev/dd906f4ab923 changeset: 88280:dd906f4ab923 branch: 2.7 parent: 88260:69b5f6924553 user: R David Murray date: Fri Jan 03 13:59:22 2014 -0500 summary: closes 16039: CVE-2013-1752: limit line length in imaplib readline calls. files: Lib/imaplib.py | 14 +++++++++++++- Lib/test/test_imaplib.py | 10 ++++++++++ Misc/NEWS | 3 +++ 3 files changed, 26 insertions(+), 1 deletions(-) diff --git a/Lib/imaplib.py b/Lib/imaplib.py --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -35,6 +35,15 @@ IMAP4_SSL_PORT = 993 AllowedVersions = ('IMAP4REV1', 'IMAP4') # Most recent first +# Maximal line length when calling readline(). This is to prevent +# reading arbitrary length lines. RFC 3501 and 2060 (IMAP 4rev1) +# don't specify a line length. RFC 2683 however suggests limiting client +# command lines to 1000 octets and server command lines to 8000 octets. +# We have selected 10000 for some extra margin and since that is supposedly +# also what UW and Panda IMAP does. +_MAXLINE = 10000 + + # Commands Commands = { @@ -237,7 +246,10 @@ def readline(self): """Read line from remote.""" - return self.file.readline() + line = self.file.readline(_MAXLINE + 1) + if len(line) > _MAXLINE: + raise self.error("got more than %d bytes" % _MAXLINE) + return line def send(self, data): diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -165,6 +165,16 @@ self.imap_class, *server.server_address) + def test_linetoolong(self): + class TooLongHandler(SimpleIMAPHandler): + def handle(self): + # Send a very long response line + self.wfile.write('* OK ' + imaplib._MAXLINE*'x' + '\r\n') + + with self.reaped_server(TooLongHandler) as server: + self.assertRaises(imaplib.IMAP4.error, + self.imap_class, *server.server_address) + class ThreadedNetworkedTests(BaseThreadedNetworkedTests): server_class = SocketServer.TCPServer diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,9 @@ Library ------- +- Issue #16039: CVE-2013-1752: Change use of readline in imaplib module to + limit line length. Patch by Emil Lind. + - Issue #19422: Explicitly disallow non-SOCK_STREAM sockets in the ssl module, rather than silently let them emit clear text data. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 20:14:08 2014 From: python-checkins at python.org (r.david.murray) Date: Fri, 3 Jan 2014 20:14:08 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_porting_note_f?= =?utf-8?q?or_HTTP=5BS=5DConnection_strict_parameter_removal=2E?= Message-ID: <3dwwlN2kqwz7Ljw@mail.python.org> http://hg.python.org/cpython/rev/f9bb9c11363a changeset: 88281:f9bb9c11363a parent: 88279:5ff4f2be7d8a user: R David Murray date: Fri Jan 03 14:06:01 2014 -0500 summary: whatsnew: porting note for HTTP[S]Connection strict parameter removal. It was discussed in issue #17460 whether or not to make the remaining arguments keyword only so that things would fail noisily if someone was still using positional parameters, but no decision was made and we are now well past the Beta API change deadline. files: Doc/whatsnew/3.4.rst | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) 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 @@ -1314,8 +1314,9 @@ * ``PyLoader`` and ``PyPycLoader`` have been removed from :mod:`importlib`. (Contributed by Taras Lyapun in :issue:`15641`.) -* The *strict* argument to :class:`~http.client.HTTPConnection` has been - removed. HTTP 0.9-style "Simple Responses" are no longer supported. +* The *strict* argument to :class:`~http.client.HTTPConnection` and + :class:`~http.client.HTTPSConnection` has been removed. HTTP 0.9-style + "Simple Responses" are no longer supported. Porting to Python 3.4 @@ -1383,6 +1384,12 @@ ``-m`` with the interpreter (this does not influence when the path to a file is specified on the command-line). +* The removal of the *strict* argument to :class:`~http.client.HTTPConnection` + and :class:`~http.client.HTTPSConnection` changes the meaning of the + remaining arguments if you are specifying them positionally rather than by + keyword. If you've been paying attention to deprecation warnings your code + should already be specifying any additional arguments via keywords. + Changes in the C API -------------------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 21:37:15 2014 From: python-checkins at python.org (martin.v.loewis) Date: Fri, 3 Jan 2014 21:37:15 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2319526=3A_Exclude_?= =?utf-8?q?all_new_API_from_the_stable_ABI=2E?= Message-ID: <3dwybH4bS2z7Lk1@mail.python.org> http://hg.python.org/cpython/rev/15bad3abfac9 changeset: 88282:15bad3abfac9 user: Martin v. L?wis date: Fri Jan 03 21:36:49 2014 +0100 summary: Issue #19526: Exclude all new API from the stable ABI. files: Include/abstract.h | 2 +- Include/codecs.h | 2 +- Include/dictobject.h | 2 ++ Include/fileutils.h | 4 ++++ Include/object.h | 2 ++ Include/pyerrors.h | 6 ++++++ Include/pyhash.h | 2 ++ Include/pymem.h | 4 ++++ Include/pystate.h | 2 ++ Include/pythonrun.h | 2 ++ Include/sysmodule.h | 2 ++ Include/unicodeobject.h | 2 ++ Include/warnings.h | 4 ++++ Misc/NEWS | 3 +++ 14 files changed, 37 insertions(+), 2 deletions(-) diff --git a/Include/abstract.h b/Include/abstract.h --- a/Include/abstract.h +++ b/Include/abstract.h @@ -409,8 +409,8 @@ #ifndef Py_LIMITED_API PyAPI_FUNC(int) _PyObject_HasLen(PyObject *o); + PyAPI_FUNC(Py_ssize_t) PyObject_LengthHint(PyObject *o, Py_ssize_t); #endif -PyAPI_FUNC(Py_ssize_t) PyObject_LengthHint(PyObject *o, Py_ssize_t); /* Guess the size of object o using len(o) or o.__length_hint__(). diff --git a/Include/codecs.h b/Include/codecs.h --- a/Include/codecs.h +++ b/Include/codecs.h @@ -94,7 +94,7 @@ const char *errors ); -#ifndef PY_LIMITED_API +#ifndef Py_LIMITED_API /* Text codec specific encoding and decoding API. Checks the encoding against a list of codecs which do not diff --git a/Include/dictobject.h b/Include/dictobject.h --- a/Include/dictobject.h +++ b/Include/dictobject.h @@ -53,8 +53,10 @@ PyAPI_FUNC(PyObject *) PyDict_GetItemWithError(PyObject *mp, PyObject *key); PyAPI_FUNC(PyObject *) _PyDict_GetItemIdWithError(PyObject *dp, struct _Py_Identifier *key); +#ifndef Py_LIMITED_API PyAPI_FUNC(PyObject *) PyDict_SetDefault( PyObject *mp, PyObject *key, PyObject *defaultobj); +#endif PyAPI_FUNC(int) PyDict_SetItem(PyObject *mp, PyObject *key, PyObject *item); PyAPI_FUNC(int) PyDict_DelItem(PyObject *mp, PyObject *key); PyAPI_FUNC(void) PyDict_Clear(PyObject *mp); diff --git a/Include/fileutils.h b/Include/fileutils.h --- a/Include/fileutils.h +++ b/Include/fileutils.h @@ -27,9 +27,11 @@ struct stat *statbuf); #endif +#ifndef Py_LIMITED_API PyAPI_FUNC(int) _Py_open( const char *pathname, int flags); +#endif PyAPI_FUNC(FILE *) _Py_wfopen( const wchar_t *path, @@ -61,12 +63,14 @@ wchar_t *buf, size_t size); +#ifndef Py_LIMITED_API PyAPI_FUNC(int) _Py_get_inheritable(int fd); PyAPI_FUNC(int) _Py_set_inheritable(int fd, int inheritable, int *atomic_flag_works); PyAPI_FUNC(int) _Py_dup(int fd); +#endif #ifdef __cplusplus } diff --git a/Include/object.h b/Include/object.h --- a/Include/object.h +++ b/Include/object.h @@ -533,8 +533,10 @@ PyAPI_FUNC(int) PyCallable_Check(PyObject *); PyAPI_FUNC(void) PyObject_ClearWeakRefs(PyObject *); +#ifndef Py_LIMITED_API PyAPI_FUNC(void) PyObject_CallFinalizer(PyObject *); PyAPI_FUNC(int) PyObject_CallFinalizerFromDealloc(PyObject *); +#endif /* Same as PyObject_Generic{Get,Set}Attr, but passing the attributes dict as the last parameter. */ diff --git a/Include/pyerrors.h b/Include/pyerrors.h --- a/Include/pyerrors.h +++ b/Include/pyerrors.h @@ -75,7 +75,9 @@ PyAPI_FUNC(void) PyErr_SetNone(PyObject *); PyAPI_FUNC(void) PyErr_SetObject(PyObject *, PyObject *); +#ifndef Py_LIMITED_API PyAPI_FUNC(void) _PyErr_SetKeyError(PyObject *); +#endif PyAPI_FUNC(void) PyErr_SetString( PyObject *exception, const char *string /* decoded from utf-8 */ @@ -321,16 +323,20 @@ const char *filename, /* decoded from the filesystem encoding */ int lineno, int col_offset); +#ifndef Py_LIMITED_API PyAPI_FUNC(void) PyErr_SyntaxLocationObject( PyObject *filename, int lineno, int col_offset); +#endif PyAPI_FUNC(PyObject *) PyErr_ProgramText( const char *filename, /* decoded from the filesystem encoding */ int lineno); +#ifndef Py_LIMITED_API PyAPI_FUNC(PyObject *) PyErr_ProgramTextObject( PyObject *filename, int lineno); +#endif /* The following functions are used to create and modify unicode exceptions from C */ diff --git a/Include/pyhash.h b/Include/pyhash.h --- a/Include/pyhash.h +++ b/Include/pyhash.h @@ -50,6 +50,7 @@ * (*) The siphash member may not be available on 32 bit platforms without * an unsigned int64 data type. */ +#ifndef Py_LIMITED_API typedef union { /* ensure 24 bytes */ unsigned char uc[24]; @@ -76,6 +77,7 @@ } expat; } _Py_HashSecret_t; PyAPI_DATA(_Py_HashSecret_t) _Py_HashSecret; +#endif #ifdef Py_DEBUG PyAPI_DATA(int) _Py_HashSecret_Initialized; diff --git a/Include/pymem.h b/Include/pymem.h --- a/Include/pymem.h +++ b/Include/pymem.h @@ -11,9 +11,11 @@ extern "C" { #endif +#ifndef Py_LIMITED_API PyAPI_FUNC(void *) PyMem_RawMalloc(size_t size); PyAPI_FUNC(void *) PyMem_RawRealloc(void *ptr, size_t new_size); PyAPI_FUNC(void) PyMem_RawFree(void *ptr); +#endif /* BEWARE: @@ -58,8 +60,10 @@ PyAPI_FUNC(void *) PyMem_Realloc(void *ptr, size_t new_size); PyAPI_FUNC(void) PyMem_Free(void *ptr); +#ifndef Py_LIMITED_API PyAPI_FUNC(char *) _PyMem_RawStrdup(const char *str); PyAPI_FUNC(char *) _PyMem_Strdup(const char *str); +#endif /* Macros. */ diff --git a/Include/pystate.h b/Include/pystate.h --- a/Include/pystate.h +++ b/Include/pystate.h @@ -236,7 +236,9 @@ /* Helper/diagnostic function - return 1 if the current thread * currently holds the GIL, 0 otherwise */ +#ifndef Py_LIMITED_API PyAPI_FUNC(int) PyGILState_Check(void); +#endif #endif /* #ifdef WITH_THREAD */ diff --git a/Include/pythonrun.h b/Include/pythonrun.h --- a/Include/pythonrun.h +++ b/Include/pythonrun.h @@ -155,10 +155,12 @@ const char *str, const char *filename, /* decoded from the filesystem encoding */ int start); +#ifndef Py_LIMITED_API PyAPI_FUNC(struct symtable *) Py_SymtableStringObject( const char *str, PyObject *filename, int start); +#endif PyAPI_FUNC(void) PyErr_Print(void); PyAPI_FUNC(void) PyErr_PrintEx(int); diff --git a/Include/sysmodule.h b/Include/sysmodule.h --- a/Include/sysmodule.h +++ b/Include/sysmodule.h @@ -8,7 +8,9 @@ #endif PyAPI_FUNC(PyObject *) PySys_GetObject(const char *); +#ifndef Py_LIMITED_API PyAPI_FUNC(PyObject *) _PySys_GetObjectId(_Py_Identifier *key); +#endif PyAPI_FUNC(int) PySys_SetObject(const char *, PyObject *); PyAPI_FUNC(int) _PySys_SetObjectId(_Py_Identifier *key, PyObject *); diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -2004,10 +2004,12 @@ PyObject *right /* Right string */ ); +#ifndef Py_LIMITED_API PyAPI_FUNC(int) _PyUnicode_CompareWithId( PyObject *left, /* Left string */ _Py_Identifier *right /* Right identifier */ ); +#endif PyAPI_FUNC(int) PyUnicode_CompareWithASCIIString( PyObject *left, diff --git a/Include/warnings.h b/Include/warnings.h --- a/Include/warnings.h +++ b/Include/warnings.h @@ -17,6 +17,7 @@ Py_ssize_t stack_level, const char *format, /* ASCII-encoded string */ ...); +#ifndef Py_LIMITED_API PyAPI_FUNC(int) PyErr_WarnExplicitObject( PyObject *category, PyObject *message, @@ -24,6 +25,7 @@ int lineno, PyObject *module, PyObject *registry); +#endif PyAPI_FUNC(int) PyErr_WarnExplicit( PyObject *category, const char *message, /* UTF-8 encoded string */ @@ -32,11 +34,13 @@ const char *module, /* UTF-8 encoded string */ PyObject *registry); +#ifndef Py_LIMITED_API PyAPI_FUNC(int) PyErr_WarnExplicitFormat(PyObject *category, const char *filename, int lineno, const char *module, PyObject *registry, const char *format, ...); +#endif /* DEPRECATED: Use PyErr_WarnEx() instead. */ #ifndef Py_LIMITED_API diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #19526: Exclude all new API from the stable ABI. Exceptions can be + made if a need is demonstrated. + - Issue #19969: PyBytes_FromFormatV() now raises an OverflowError if "%c" argument is not in range [0; 255]. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 21:53:50 2014 From: python-checkins at python.org (r.david.murray) Date: Fri, 3 Jan 2014 21:53:50 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_unittest_disco?= =?utf-8?q?very_sorting=2C_urlllib_Request_getter/setter_removals=2E?= Message-ID: <3dwyyQ5SwBz7Lk1@mail.python.org> http://hg.python.org/cpython/rev/4799400c09aa changeset: 88283:4799400c09aa user: R David Murray date: Fri Jan 03 15:46:24 2014 -0500 summary: whatsnew: unittest discovery sorting, urlllib Request getter/setter removals. files: Doc/whatsnew/3.4.rst | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-) 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 @@ -1019,6 +1019,10 @@ module level in the test file), it is now reported as a skip instead of an error. (Contributed by Zach Ware in :issue:`16935`.) +:meth:`~unittest.TestLoader.discover` now sorts the discovered files to provide +consistent test ordering. (Contributed by Martin Melin and Jeff Ramnani in +:issue:`16709`.) + venv ---- @@ -1318,6 +1322,11 @@ :class:`~http.client.HTTPSConnection` has been removed. HTTP 0.9-style "Simple Responses" are no longer supported. +* The deprecated :mod:`urllib.request.Request` getter and setter methods + ``add_data``, ``has_data``, ``get_data``, ``get_type``, ``get_host``, + ``get_selector``, ``set_proxy``, ``get_origin_req_host``, and + ``is_unverifiable`` have been removed (use direct attribute access instead). + Porting to Python 3.4 ===================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 21:53:52 2014 From: python-checkins at python.org (r.david.murray) Date: Fri, 3 Jan 2014 21:53:52 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_make_bullet_li?= =?utf-8?q?st_presentation_style_consistent=2E?= Message-ID: <3dwyyS0Gsyz7Lk1@mail.python.org> http://hg.python.org/cpython/rev/ae69ebd41807 changeset: 88284:ae69ebd41807 user: R David Murray date: Fri Jan 03 15:52:22 2014 -0500 summary: whatsnew: make bullet list presentation style consistent. files: Doc/whatsnew/3.4.rst | 39 ++++++++++++++++++------------- 1 files changed, 22 insertions(+), 17 deletions(-) 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 @@ -1213,24 +1213,20 @@ probe now checks a series of consecutive, adjacent key/hash pairs before continuing to make random probes through the hash table. This exploits cache locality to make collision resolution less expensive. - The collision resolution scheme can be described as a hybrid of linear probing and open addressing. The number of additional linear probes defaults to nine. This can be changed at compile-time by defining LINEAR_PROBES to be any value. Set LINEAR_PROBES=0 to turn-off - linear probing entirely. - - (Contributed by Raymond Hettinger in :issue:`18771`.) + linear probing entirely. (Contributed by Raymond Hettinger in + :issue:`18771`.) * The interpreter starts about 30% faster. A couple of measures lead to the speedup. The interpreter loads fewer modules on startup, e.g. the :mod:`re`, :mod:`collections` and :mod:`locale` modules and their dependencies are no longer imported by default. The marshal module has been improved to load - compiled Python code faster. - - (Contributed by Antoine Pitrou, Christian Heimes and Victor Stinner in - :issue:`19219`, :issue:`19218`, :issue:`19209`, :issue:`19205` and - :issue:`9548`) + compiled Python code faster. (Contributed by Antoine Pitrou, Christian + Heimes and Victor Stinner in :issue:`19219`, :issue:`19218`, :issue:`19209`, + :issue:`19205` and :issue:`9548`) * :class:`bz2.BZ2File` is now as fast or faster than the Python2 version for most cases. :class:`lzma.LZMAFile` has also been optimized. (Contributed by @@ -1292,18 +1288,27 @@ exists, is deprecated (:issue:`19375`). + Removed ======= + +Operating Systems No Longer Supported +------------------------------------- + +Support for the following operating systems has been removed from the source +and build tools: + +* OS/2 (:issue:`16135`). +* Windows 2000 (changeset e52df05b496a). +* VMS (:issue:`16136`). + + +API and Feature Removals +------------------------ + The following obsolete and previously deprecated APIs and features have been -removed in Python 3.4: - -* Support for the following operating systems has been removed from the source - and build tools: - - * OS/2 (:issue:`16135`). - * Windows 2000 (changeset e52df05b496a). - * VMS (:issue:`16136`). +removed: * The unmaintained ``Misc/TextMate`` and ``Misc/vim`` directories have been removed (see the `devguide `_ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 23:27:33 2014 From: python-checkins at python.org (r.david.murray) Date: Fri, 3 Jan 2014 23:27:33 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_consistently_u?= =?utf-8?q?se_3_blanks_between_major_sections=2E_2_for_minor=2E?= Message-ID: <3dx12Y0hR4z7Llh@mail.python.org> http://hg.python.org/cpython/rev/48bd7ec44bbc changeset: 88285:48bd7ec44bbc user: R David Murray date: Fri Jan 03 16:15:45 2014 -0500 summary: whatsnew: consistently use 3 blanks between major sections. 2 for minor. files: Doc/whatsnew/3.4.rst | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) 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 @@ -78,6 +78,7 @@ :pep:`429` -- Python 3.4 Release Schedule + Summary -- Release Highlights ============================= @@ -149,6 +150,7 @@ porting issues. + New Expected Features for Python Implementations ================================================ @@ -341,6 +343,7 @@ :issue:`12892`. + New Modules =========== @@ -469,6 +472,7 @@ PEP written and implemented by Victor Stinner + Improved Modules ================ @@ -486,7 +490,6 @@ (Contributed by Bruno Dupuis in :issue:`16049`.) - aifc ---- @@ -1078,6 +1081,7 @@ (Contributed by Christian Tismer in :issue:`19274`.) + CPython Implementation Changes ============================== @@ -1176,6 +1180,7 @@ interpreter is not available (for example, in cross compilation scenarios). + Other Improvements ================== @@ -1204,6 +1209,7 @@ :issue:`13390`). + Significant Optimizations ========================= @@ -1236,6 +1242,7 @@ common use case). (Contributed by Serhiy Storchaka in :issue:`16674`). + Deprecated ========== @@ -1333,6 +1340,7 @@ ``is_unverifiable`` have been removed (use direct attribute access instead). + Porting to Python 3.4 ===================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 3 23:27:34 2014 From: python-checkins at python.org (r.david.murray) Date: Fri, 3 Jan 2014 23:27:34 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE2MDM5LyMyMDEx?= =?utf-8?q?8=3A_temporarily_skip_failing_imaplib_SSL_test=2E?= Message-ID: <3dx12Z2P2zz7Llh@mail.python.org> http://hg.python.org/cpython/rev/d7ae948d9eee changeset: 88286:d7ae948d9eee branch: 2.7 parent: 88280:dd906f4ab923 user: R David Murray date: Fri Jan 03 17:26:21 2014 -0500 summary: #16039/#20118: temporarily skip failing imaplib SSL test. The fix the test is testing prevents a DOS attack, and the failure mode will also prevent the DOS attack, so for now skip the test. Either the test or the code does need fixing, however. files: Lib/test/test_imaplib.py | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -187,6 +187,9 @@ server_class = SecureTCPServer imap_class = IMAP4_SSL + def test_linetoolong(self): + raise unittest.SkipTest("test is not reliable on 2.7; see issue 20118") + class RemoteIMAPTest(unittest.TestCase): host = 'cyrus.andrew.cmu.edu' -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Jan 4 09:45:07 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 04 Jan 2014 09:45:07 +0100 Subject: [Python-checkins] Daily reference leaks (48bd7ec44bbc): sum=3 Message-ID: results for 48bd7ec44bbc on branch "default" -------------------------------------------- test_audioop leaked [1, 1, 1] references, sum=3 test_site leaked [0, 2, -2] references, sum=0 test_site leaked [0, 2, -2] memory blocks, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogMqNuQa', '-x'] From python-checkins at python.org Sat Jan 4 10:06:42 2014 From: python-checkins at python.org (martin.v.loewis) Date: Sat, 4 Jan 2014 10:06:42 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3NDMy?= =?utf-8?q?=3A_Drop_UCS2_from_names_of_Unicode_functions_in_python3=2Edef?= =?utf-8?q?=2E?= Message-ID: <3dxHD2452qz7Ljk@mail.python.org> http://hg.python.org/cpython/rev/ea0aa3e32ab5 changeset: 88287:ea0aa3e32ab5 branch: 3.3 parent: 88263:203ca77ea819 user: Martin v. L?wis date: Sat Jan 04 10:01:42 2014 +0100 summary: Issue #17432: Drop UCS2 from names of Unicode functions in python3.def. files: Misc/NEWS | 2 + PC/python3.def | 124 ++++++++++++++++++------------------ 2 files changed, 64 insertions(+), 62 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #17432: Drop UCS2 from names of Unicode functions in python3.def. + - Issue #19969: PyBytes_FromFormatV() now raises an OverflowError if "%c" argument is not in range [0; 255]. diff --git a/PC/python3.def b/PC/python3.def --- a/PC/python3.def +++ b/PC/python3.def @@ -547,68 +547,68 @@ PyUnicodeTranslateError_SetEnd=python33.PyUnicodeTranslateError_SetEnd PyUnicodeTranslateError_SetReason=python33.PyUnicodeTranslateError_SetReason PyUnicodeTranslateError_SetStart=python33.PyUnicodeTranslateError_SetStart - PyUnicode_Append=python33.PyUnicodeUCS2_Append - PyUnicode_AppendAndDel=python33.PyUnicodeUCS2_AppendAndDel - PyUnicode_AsASCIIString=python33.PyUnicodeUCS2_AsASCIIString - PyUnicode_AsCharmapString=python33.PyUnicodeUCS2_AsCharmapString - PyUnicode_AsDecodedObject=python33.PyUnicodeUCS2_AsDecodedObject - PyUnicode_AsDecodedUnicode=python33.PyUnicodeUCS2_AsDecodedUnicode - PyUnicode_AsEncodedObject=python33.PyUnicodeUCS2_AsEncodedObject - PyUnicode_AsEncodedString=python33.PyUnicodeUCS2_AsEncodedString - PyUnicode_AsEncodedUnicode=python33.PyUnicodeUCS2_AsEncodedUnicode - PyUnicode_AsLatin1String=python33.PyUnicodeUCS2_AsLatin1String - PyUnicode_AsRawUnicodeEscapeString=python33.PyUnicodeUCS2_AsRawUnicodeEscapeString - PyUnicode_AsUTF16String=python33.PyUnicodeUCS2_AsUTF16String - PyUnicode_AsUTF32String=python33.PyUnicodeUCS2_AsUTF32String - PyUnicode_AsUTF8String=python33.PyUnicodeUCS2_AsUTF8String - PyUnicode_AsUnicodeEscapeString=python33.PyUnicodeUCS2_AsUnicodeEscapeString - PyUnicode_AsWideChar=python33.PyUnicodeUCS2_AsWideChar - PyUnicode_ClearFreelist=python33.PyUnicodeUCS2_ClearFreelist - PyUnicode_Compare=python33.PyUnicodeUCS2_Compare - PyUnicode_Concat=python33.PyUnicodeUCS2_Concat - PyUnicode_Contains=python33.PyUnicodeUCS2_Contains - PyUnicode_Count=python33.PyUnicodeUCS2_Count - PyUnicode_Decode=python33.PyUnicodeUCS2_Decode - PyUnicode_DecodeASCII=python33.PyUnicodeUCS2_DecodeASCII - PyUnicode_DecodeCharmap=python33.PyUnicodeUCS2_DecodeCharmap - PyUnicode_DecodeFSDefault=python33.PyUnicodeUCS2_DecodeFSDefault - PyUnicode_DecodeFSDefaultAndSize=python33.PyUnicodeUCS2_DecodeFSDefaultAndSize - PyUnicode_DecodeLatin1=python33.PyUnicodeUCS2_DecodeLatin1 - PyUnicode_DecodeRawUnicodeEscape=python33.PyUnicodeUCS2_DecodeRawUnicodeEscape - PyUnicode_DecodeUTF16=python33.PyUnicodeUCS2_DecodeUTF16 - PyUnicode_DecodeUTF16Stateful=python33.PyUnicodeUCS2_DecodeUTF16Stateful - PyUnicode_DecodeUTF32=python33.PyUnicodeUCS2_DecodeUTF32 - PyUnicode_DecodeUTF32Stateful=python33.PyUnicodeUCS2_DecodeUTF32Stateful - PyUnicode_DecodeUTF8=python33.PyUnicodeUCS2_DecodeUTF8 - PyUnicode_DecodeUTF8Stateful=python33.PyUnicodeUCS2_DecodeUTF8Stateful - PyUnicode_DecodeUnicodeEscape=python33.PyUnicodeUCS2_DecodeUnicodeEscape - PyUnicode_FSConverter=python33.PyUnicodeUCS2_FSConverter - PyUnicode_FSDecoder=python33.PyUnicodeUCS2_FSDecoder - PyUnicode_Find=python33.PyUnicodeUCS2_Find - PyUnicode_Format=python33.PyUnicodeUCS2_Format - PyUnicode_FromEncodedObject=python33.PyUnicodeUCS2_FromEncodedObject - PyUnicode_FromFormat=python33.PyUnicodeUCS2_FromFormat - PyUnicode_FromFormatV=python33.PyUnicodeUCS2_FromFormatV - PyUnicode_FromObject=python33.PyUnicodeUCS2_FromObject - PyUnicode_FromOrdinal=python33.PyUnicodeUCS2_FromOrdinal - PyUnicode_FromString=python33.PyUnicodeUCS2_FromString - PyUnicode_FromStringAndSize=python33.PyUnicodeUCS2_FromStringAndSize - PyUnicode_FromWideChar=python33.PyUnicodeUCS2_FromWideChar - PyUnicode_GetDefaultEncoding=python33.PyUnicodeUCS2_GetDefaultEncoding - PyUnicode_GetSize=python33.PyUnicodeUCS2_GetSize - PyUnicode_IsIdentifier=python33.PyUnicodeUCS2_IsIdentifier - PyUnicode_Join=python33.PyUnicodeUCS2_Join - PyUnicode_Partition=python33.PyUnicodeUCS2_Partition - PyUnicode_RPartition=python33.PyUnicodeUCS2_RPartition - PyUnicode_RSplit=python33.PyUnicodeUCS2_RSplit - PyUnicode_Replace=python33.PyUnicodeUCS2_Replace - PyUnicode_Resize=python33.PyUnicodeUCS2_Resize - PyUnicode_RichCompare=python33.PyUnicodeUCS2_RichCompare - PyUnicode_SetDefaultEncoding=python33.PyUnicodeUCS2_SetDefaultEncoding - PyUnicode_Split=python33.PyUnicodeUCS2_Split - PyUnicode_Splitlines=python33.PyUnicodeUCS2_Splitlines - PyUnicode_Tailmatch=python33.PyUnicodeUCS2_Tailmatch - PyUnicode_Translate=python33.PyUnicodeUCS2_Translate + PyUnicode_Append=python33.PyUnicode_Append + PyUnicode_AppendAndDel=python33.PyUnicode_AppendAndDel + PyUnicode_AsASCIIString=python33.PyUnicode_AsASCIIString + PyUnicode_AsCharmapString=python33.PyUnicode_AsCharmapString + PyUnicode_AsDecodedObject=python33.PyUnicode_AsDecodedObject + PyUnicode_AsDecodedUnicode=python33.PyUnicode_AsDecodedUnicode + PyUnicode_AsEncodedObject=python33.PyUnicode_AsEncodedObject + PyUnicode_AsEncodedString=python33.PyUnicode_AsEncodedString + PyUnicode_AsEncodedUnicode=python33.PyUnicode_AsEncodedUnicode + PyUnicode_AsLatin1String=python33.PyUnicode_AsLatin1String + PyUnicode_AsRawUnicodeEscapeString=python33.PyUnicode_AsRawUnicodeEscapeString + PyUnicode_AsUTF16String=python33.PyUnicode_AsUTF16String + PyUnicode_AsUTF32String=python33.PyUnicode_AsUTF32String + PyUnicode_AsUTF8String=python33.PyUnicode_AsUTF8String + PyUnicode_AsUnicodeEscapeString=python33.PyUnicode_AsUnicodeEscapeString + PyUnicode_AsWideChar=python33.PyUnicode_AsWideChar + PyUnicode_ClearFreelist=python33.PyUnicode_ClearFreelist + PyUnicode_Compare=python33.PyUnicode_Compare + PyUnicode_Concat=python33.PyUnicode_Concat + PyUnicode_Contains=python33.PyUnicode_Contains + PyUnicode_Count=python33.PyUnicode_Count + PyUnicode_Decode=python33.PyUnicode_Decode + PyUnicode_DecodeASCII=python33.PyUnicode_DecodeASCII + PyUnicode_DecodeCharmap=python33.PyUnicode_DecodeCharmap + PyUnicode_DecodeFSDefault=python33.PyUnicode_DecodeFSDefault + PyUnicode_DecodeFSDefaultAndSize=python33.PyUnicode_DecodeFSDefaultAndSize + PyUnicode_DecodeLatin1=python33.PyUnicode_DecodeLatin1 + PyUnicode_DecodeRawUnicodeEscape=python33.PyUnicode_DecodeRawUnicodeEscape + PyUnicode_DecodeUTF16=python33.PyUnicode_DecodeUTF16 + PyUnicode_DecodeUTF16Stateful=python33.PyUnicode_DecodeUTF16Stateful + PyUnicode_DecodeUTF32=python33.PyUnicode_DecodeUTF32 + PyUnicode_DecodeUTF32Stateful=python33.PyUnicode_DecodeUTF32Stateful + PyUnicode_DecodeUTF8=python33.PyUnicode_DecodeUTF8 + PyUnicode_DecodeUTF8Stateful=python33.PyUnicode_DecodeUTF8Stateful + PyUnicode_DecodeUnicodeEscape=python33.PyUnicode_DecodeUnicodeEscape + PyUnicode_FSConverter=python33.PyUnicode_FSConverter + PyUnicode_FSDecoder=python33.PyUnicode_FSDecoder + PyUnicode_Find=python33.PyUnicode_Find + PyUnicode_Format=python33.PyUnicode_Format + PyUnicode_FromEncodedObject=python33.PyUnicode_FromEncodedObject + PyUnicode_FromFormat=python33.PyUnicode_FromFormat + PyUnicode_FromFormatV=python33.PyUnicode_FromFormatV + PyUnicode_FromObject=python33.PyUnicode_FromObject + PyUnicode_FromOrdinal=python33.PyUnicode_FromOrdinal + PyUnicode_FromString=python33.PyUnicode_FromString + PyUnicode_FromStringAndSize=python33.PyUnicode_FromStringAndSize + PyUnicode_FromWideChar=python33.PyUnicode_FromWideChar + PyUnicode_GetDefaultEncoding=python33.PyUnicode_GetDefaultEncoding + PyUnicode_GetSize=python33.PyUnicode_GetSize + PyUnicode_IsIdentifier=python33.PyUnicode_IsIdentifier + PyUnicode_Join=python33.PyUnicode_Join + PyUnicode_Partition=python33.PyUnicode_Partition + PyUnicode_RPartition=python33.PyUnicode_RPartition + PyUnicode_RSplit=python33.PyUnicode_RSplit + PyUnicode_Replace=python33.PyUnicode_Replace + PyUnicode_Resize=python33.PyUnicode_Resize + PyUnicode_RichCompare=python33.PyUnicode_RichCompare + PyUnicode_SetDefaultEncoding=python33.PyUnicode_SetDefaultEncoding + PyUnicode_Split=python33.PyUnicode_Split + PyUnicode_Splitlines=python33.PyUnicode_Splitlines + PyUnicode_Tailmatch=python33.PyUnicode_Tailmatch + PyUnicode_Translate=python33.PyUnicode_Translate PyUnicode_BuildEncodingMap=python33.PyUnicode_BuildEncodingMap PyUnicode_CompareWithASCIIString=python33.PyUnicode_CompareWithASCIIString PyUnicode_DecodeUTF7=python33.PyUnicode_DecodeUTF7 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 4 10:06:43 2014 From: python-checkins at python.org (martin.v.loewis) Date: Sat, 4 Jan 2014 10:06:43 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E3=3A_Issue_=2317432=3A_Drop_UCS2_from_nam?= =?utf-8?q?es_of_Unicode_functions_in?= Message-ID: <3dxHD36rk9z7Lkf@mail.python.org> http://hg.python.org/cpython/rev/0ea09c824d9b changeset: 88288:0ea09c824d9b parent: 88285:48bd7ec44bbc parent: 88287:ea0aa3e32ab5 user: Martin v. L?wis date: Sat Jan 04 10:06:28 2014 +0100 summary: Merge with 3.3: Issue #17432: Drop UCS2 from names of Unicode functions in python3.def. files: Misc/NEWS | 2 + PC/python3.def | 124 ++++++++++++++++++------------------ 2 files changed, 64 insertions(+), 62 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #17432: Drop UCS2 from names of Unicode functions in python3.def. + - Issue #19526: Exclude all new API from the stable ABI. Exceptions can be made if a need is demonstrated. diff --git a/PC/python3.def b/PC/python3.def --- a/PC/python3.def +++ b/PC/python3.def @@ -548,68 +548,68 @@ PyUnicodeTranslateError_SetEnd=python34.PyUnicodeTranslateError_SetEnd PyUnicodeTranslateError_SetReason=python34.PyUnicodeTranslateError_SetReason PyUnicodeTranslateError_SetStart=python34.PyUnicodeTranslateError_SetStart - PyUnicode_Append=python34.PyUnicodeUCS2_Append - PyUnicode_AppendAndDel=python34.PyUnicodeUCS2_AppendAndDel - PyUnicode_AsASCIIString=python34.PyUnicodeUCS2_AsASCIIString - PyUnicode_AsCharmapString=python34.PyUnicodeUCS2_AsCharmapString - PyUnicode_AsDecodedObject=python34.PyUnicodeUCS2_AsDecodedObject - PyUnicode_AsDecodedUnicode=python34.PyUnicodeUCS2_AsDecodedUnicode - PyUnicode_AsEncodedObject=python34.PyUnicodeUCS2_AsEncodedObject - PyUnicode_AsEncodedString=python34.PyUnicodeUCS2_AsEncodedString - PyUnicode_AsEncodedUnicode=python34.PyUnicodeUCS2_AsEncodedUnicode - PyUnicode_AsLatin1String=python34.PyUnicodeUCS2_AsLatin1String - PyUnicode_AsRawUnicodeEscapeString=python34.PyUnicodeUCS2_AsRawUnicodeEscapeString - PyUnicode_AsUTF16String=python34.PyUnicodeUCS2_AsUTF16String - PyUnicode_AsUTF32String=python34.PyUnicodeUCS2_AsUTF32String - PyUnicode_AsUTF8String=python34.PyUnicodeUCS2_AsUTF8String - PyUnicode_AsUnicodeEscapeString=python34.PyUnicodeUCS2_AsUnicodeEscapeString - PyUnicode_AsWideChar=python34.PyUnicodeUCS2_AsWideChar - PyUnicode_ClearFreelist=python34.PyUnicodeUCS2_ClearFreelist - PyUnicode_Compare=python34.PyUnicodeUCS2_Compare - PyUnicode_Concat=python34.PyUnicodeUCS2_Concat - PyUnicode_Contains=python34.PyUnicodeUCS2_Contains - PyUnicode_Count=python34.PyUnicodeUCS2_Count - PyUnicode_Decode=python34.PyUnicodeUCS2_Decode - PyUnicode_DecodeASCII=python34.PyUnicodeUCS2_DecodeASCII - PyUnicode_DecodeCharmap=python34.PyUnicodeUCS2_DecodeCharmap - PyUnicode_DecodeFSDefault=python34.PyUnicodeUCS2_DecodeFSDefault - PyUnicode_DecodeFSDefaultAndSize=python34.PyUnicodeUCS2_DecodeFSDefaultAndSize - PyUnicode_DecodeLatin1=python34.PyUnicodeUCS2_DecodeLatin1 - PyUnicode_DecodeRawUnicodeEscape=python34.PyUnicodeUCS2_DecodeRawUnicodeEscape - PyUnicode_DecodeUTF16=python34.PyUnicodeUCS2_DecodeUTF16 - PyUnicode_DecodeUTF16Stateful=python34.PyUnicodeUCS2_DecodeUTF16Stateful - PyUnicode_DecodeUTF32=python34.PyUnicodeUCS2_DecodeUTF32 - PyUnicode_DecodeUTF32Stateful=python34.PyUnicodeUCS2_DecodeUTF32Stateful - PyUnicode_DecodeUTF8=python34.PyUnicodeUCS2_DecodeUTF8 - PyUnicode_DecodeUTF8Stateful=python34.PyUnicodeUCS2_DecodeUTF8Stateful - PyUnicode_DecodeUnicodeEscape=python34.PyUnicodeUCS2_DecodeUnicodeEscape - PyUnicode_FSConverter=python34.PyUnicodeUCS2_FSConverter - PyUnicode_FSDecoder=python34.PyUnicodeUCS2_FSDecoder - PyUnicode_Find=python34.PyUnicodeUCS2_Find - PyUnicode_Format=python34.PyUnicodeUCS2_Format - PyUnicode_FromEncodedObject=python34.PyUnicodeUCS2_FromEncodedObject - PyUnicode_FromFormat=python34.PyUnicodeUCS2_FromFormat - PyUnicode_FromFormatV=python34.PyUnicodeUCS2_FromFormatV - PyUnicode_FromObject=python34.PyUnicodeUCS2_FromObject - PyUnicode_FromOrdinal=python34.PyUnicodeUCS2_FromOrdinal - PyUnicode_FromString=python34.PyUnicodeUCS2_FromString - PyUnicode_FromStringAndSize=python34.PyUnicodeUCS2_FromStringAndSize - PyUnicode_FromWideChar=python34.PyUnicodeUCS2_FromWideChar - PyUnicode_GetDefaultEncoding=python34.PyUnicodeUCS2_GetDefaultEncoding - PyUnicode_GetSize=python34.PyUnicodeUCS2_GetSize - PyUnicode_IsIdentifier=python34.PyUnicodeUCS2_IsIdentifier - PyUnicode_Join=python34.PyUnicodeUCS2_Join - PyUnicode_Partition=python34.PyUnicodeUCS2_Partition - PyUnicode_RPartition=python34.PyUnicodeUCS2_RPartition - PyUnicode_RSplit=python34.PyUnicodeUCS2_RSplit - PyUnicode_Replace=python34.PyUnicodeUCS2_Replace - PyUnicode_Resize=python34.PyUnicodeUCS2_Resize - PyUnicode_RichCompare=python34.PyUnicodeUCS2_RichCompare - PyUnicode_SetDefaultEncoding=python34.PyUnicodeUCS2_SetDefaultEncoding - PyUnicode_Split=python34.PyUnicodeUCS2_Split - PyUnicode_Splitlines=python34.PyUnicodeUCS2_Splitlines - PyUnicode_Tailmatch=python34.PyUnicodeUCS2_Tailmatch - PyUnicode_Translate=python34.PyUnicodeUCS2_Translate + PyUnicode_Append=python34.PyUnicode_Append + PyUnicode_AppendAndDel=python34.PyUnicode_AppendAndDel + PyUnicode_AsASCIIString=python34.PyUnicode_AsASCIIString + PyUnicode_AsCharmapString=python34.PyUnicode_AsCharmapString + PyUnicode_AsDecodedObject=python34.PyUnicode_AsDecodedObject + PyUnicode_AsDecodedUnicode=python34.PyUnicode_AsDecodedUnicode + PyUnicode_AsEncodedObject=python34.PyUnicode_AsEncodedObject + PyUnicode_AsEncodedString=python34.PyUnicode_AsEncodedString + PyUnicode_AsEncodedUnicode=python34.PyUnicode_AsEncodedUnicode + PyUnicode_AsLatin1String=python34.PyUnicode_AsLatin1String + PyUnicode_AsRawUnicodeEscapeString=python34.PyUnicode_AsRawUnicodeEscapeString + PyUnicode_AsUTF16String=python34.PyUnicode_AsUTF16String + PyUnicode_AsUTF32String=python34.PyUnicode_AsUTF32String + PyUnicode_AsUTF8String=python34.PyUnicode_AsUTF8String + PyUnicode_AsUnicodeEscapeString=python34.PyUnicode_AsUnicodeEscapeString + PyUnicode_AsWideChar=python34.PyUnicode_AsWideChar + PyUnicode_ClearFreelist=python34.PyUnicode_ClearFreelist + PyUnicode_Compare=python34.PyUnicode_Compare + PyUnicode_Concat=python34.PyUnicode_Concat + PyUnicode_Contains=python34.PyUnicode_Contains + PyUnicode_Count=python34.PyUnicode_Count + PyUnicode_Decode=python34.PyUnicode_Decode + PyUnicode_DecodeASCII=python34.PyUnicode_DecodeASCII + PyUnicode_DecodeCharmap=python34.PyUnicode_DecodeCharmap + PyUnicode_DecodeFSDefault=python34.PyUnicode_DecodeFSDefault + PyUnicode_DecodeFSDefaultAndSize=python34.PyUnicode_DecodeFSDefaultAndSize + PyUnicode_DecodeLatin1=python34.PyUnicode_DecodeLatin1 + PyUnicode_DecodeRawUnicodeEscape=python34.PyUnicode_DecodeRawUnicodeEscape + PyUnicode_DecodeUTF16=python34.PyUnicode_DecodeUTF16 + PyUnicode_DecodeUTF16Stateful=python34.PyUnicode_DecodeUTF16Stateful + PyUnicode_DecodeUTF32=python34.PyUnicode_DecodeUTF32 + PyUnicode_DecodeUTF32Stateful=python34.PyUnicode_DecodeUTF32Stateful + PyUnicode_DecodeUTF8=python34.PyUnicode_DecodeUTF8 + PyUnicode_DecodeUTF8Stateful=python34.PyUnicode_DecodeUTF8Stateful + PyUnicode_DecodeUnicodeEscape=python34.PyUnicode_DecodeUnicodeEscape + PyUnicode_FSConverter=python34.PyUnicode_FSConverter + PyUnicode_FSDecoder=python34.PyUnicode_FSDecoder + PyUnicode_Find=python34.PyUnicode_Find + PyUnicode_Format=python34.PyUnicode_Format + PyUnicode_FromEncodedObject=python34.PyUnicode_FromEncodedObject + PyUnicode_FromFormat=python34.PyUnicode_FromFormat + PyUnicode_FromFormatV=python34.PyUnicode_FromFormatV + PyUnicode_FromObject=python34.PyUnicode_FromObject + PyUnicode_FromOrdinal=python34.PyUnicode_FromOrdinal + PyUnicode_FromString=python34.PyUnicode_FromString + PyUnicode_FromStringAndSize=python34.PyUnicode_FromStringAndSize + PyUnicode_FromWideChar=python34.PyUnicode_FromWideChar + PyUnicode_GetDefaultEncoding=python34.PyUnicode_GetDefaultEncoding + PyUnicode_GetSize=python34.PyUnicode_GetSize + PyUnicode_IsIdentifier=python34.PyUnicode_IsIdentifier + PyUnicode_Join=python34.PyUnicode_Join + PyUnicode_Partition=python34.PyUnicode_Partition + PyUnicode_RPartition=python34.PyUnicode_RPartition + PyUnicode_RSplit=python34.PyUnicode_RSplit + PyUnicode_Replace=python34.PyUnicode_Replace + PyUnicode_Resize=python34.PyUnicode_Resize + PyUnicode_RichCompare=python34.PyUnicode_RichCompare + PyUnicode_SetDefaultEncoding=python34.PyUnicode_SetDefaultEncoding + PyUnicode_Split=python34.PyUnicode_Split + PyUnicode_Splitlines=python34.PyUnicode_Splitlines + PyUnicode_Tailmatch=python34.PyUnicode_Tailmatch + PyUnicode_Translate=python34.PyUnicode_Translate PyUnicode_BuildEncodingMap=python34.PyUnicode_BuildEncodingMap PyUnicode_CompareWithASCIIString=python34.PyUnicode_CompareWithASCIIString PyUnicode_DecodeUTF7=python34.PyUnicode_DecodeUTF7 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 4 11:21:30 2014 From: python-checkins at python.org (martin.v.loewis) Date: Sat, 4 Jan 2014 11:21:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Regenerate_pyt?= =?utf-8?q?hon34stub=2Edef=2E?= Message-ID: <3dxJtL1jy4z7LlX@mail.python.org> http://hg.python.org/cpython/rev/1819fee1c20f changeset: 88289:1819fee1c20f branch: 3.3 parent: 88287:ea0aa3e32ab5 user: Martin v. L?wis date: Sat Jan 04 11:20:45 2014 +0100 summary: Regenerate python34stub.def. files: PC/python33stub.def | 124 ++++++++++++++++---------------- 1 files changed, 62 insertions(+), 62 deletions(-) diff --git a/PC/python33stub.def b/PC/python33stub.def --- a/PC/python33stub.def +++ b/PC/python33stub.def @@ -546,68 +546,68 @@ PyUnicodeTranslateError_SetEnd PyUnicodeTranslateError_SetReason PyUnicodeTranslateError_SetStart -PyUnicodeUCS2_Append -PyUnicodeUCS2_AppendAndDel -PyUnicodeUCS2_AsASCIIString -PyUnicodeUCS2_AsCharmapString -PyUnicodeUCS2_AsDecodedObject -PyUnicodeUCS2_AsDecodedUnicode -PyUnicodeUCS2_AsEncodedObject -PyUnicodeUCS2_AsEncodedString -PyUnicodeUCS2_AsEncodedUnicode -PyUnicodeUCS2_AsLatin1String -PyUnicodeUCS2_AsRawUnicodeEscapeString -PyUnicodeUCS2_AsUTF16String -PyUnicodeUCS2_AsUTF32String -PyUnicodeUCS2_AsUTF8String -PyUnicodeUCS2_AsUnicodeEscapeString -PyUnicodeUCS2_AsWideChar -PyUnicodeUCS2_ClearFreelist -PyUnicodeUCS2_Compare -PyUnicodeUCS2_Concat -PyUnicodeUCS2_Contains -PyUnicodeUCS2_Count -PyUnicodeUCS2_Decode -PyUnicodeUCS2_DecodeASCII -PyUnicodeUCS2_DecodeCharmap -PyUnicodeUCS2_DecodeFSDefault -PyUnicodeUCS2_DecodeFSDefaultAndSize -PyUnicodeUCS2_DecodeLatin1 -PyUnicodeUCS2_DecodeRawUnicodeEscape -PyUnicodeUCS2_DecodeUTF16 -PyUnicodeUCS2_DecodeUTF16Stateful -PyUnicodeUCS2_DecodeUTF32 -PyUnicodeUCS2_DecodeUTF32Stateful -PyUnicodeUCS2_DecodeUTF8 -PyUnicodeUCS2_DecodeUTF8Stateful -PyUnicodeUCS2_DecodeUnicodeEscape -PyUnicodeUCS2_FSConverter -PyUnicodeUCS2_FSDecoder -PyUnicodeUCS2_Find -PyUnicodeUCS2_Format -PyUnicodeUCS2_FromEncodedObject -PyUnicodeUCS2_FromFormat -PyUnicodeUCS2_FromFormatV -PyUnicodeUCS2_FromObject -PyUnicodeUCS2_FromOrdinal -PyUnicodeUCS2_FromString -PyUnicodeUCS2_FromStringAndSize -PyUnicodeUCS2_FromWideChar -PyUnicodeUCS2_GetDefaultEncoding -PyUnicodeUCS2_GetSize -PyUnicodeUCS2_IsIdentifier -PyUnicodeUCS2_Join -PyUnicodeUCS2_Partition -PyUnicodeUCS2_RPartition -PyUnicodeUCS2_RSplit -PyUnicodeUCS2_Replace -PyUnicodeUCS2_Resize -PyUnicodeUCS2_RichCompare -PyUnicodeUCS2_SetDefaultEncoding -PyUnicodeUCS2_Split -PyUnicodeUCS2_Splitlines -PyUnicodeUCS2_Tailmatch -PyUnicodeUCS2_Translate +PyUnicode_Append +PyUnicode_AppendAndDel +PyUnicode_AsASCIIString +PyUnicode_AsCharmapString +PyUnicode_AsDecodedObject +PyUnicode_AsDecodedUnicode +PyUnicode_AsEncodedObject +PyUnicode_AsEncodedString +PyUnicode_AsEncodedUnicode +PyUnicode_AsLatin1String +PyUnicode_AsRawUnicodeEscapeString +PyUnicode_AsUTF16String +PyUnicode_AsUTF32String +PyUnicode_AsUTF8String +PyUnicode_AsUnicodeEscapeString +PyUnicode_AsWideChar +PyUnicode_ClearFreelist +PyUnicode_Compare +PyUnicode_Concat +PyUnicode_Contains +PyUnicode_Count +PyUnicode_Decode +PyUnicode_DecodeASCII +PyUnicode_DecodeCharmap +PyUnicode_DecodeFSDefault +PyUnicode_DecodeFSDefaultAndSize +PyUnicode_DecodeLatin1 +PyUnicode_DecodeRawUnicodeEscape +PyUnicode_DecodeUTF16 +PyUnicode_DecodeUTF16Stateful +PyUnicode_DecodeUTF32 +PyUnicode_DecodeUTF32Stateful +PyUnicode_DecodeUTF8 +PyUnicode_DecodeUTF8Stateful +PyUnicode_DecodeUnicodeEscape +PyUnicode_FSConverter +PyUnicode_FSDecoder +PyUnicode_Find +PyUnicode_Format +PyUnicode_FromEncodedObject +PyUnicode_FromFormat +PyUnicode_FromFormatV +PyUnicode_FromObject +PyUnicode_FromOrdinal +PyUnicode_FromString +PyUnicode_FromStringAndSize +PyUnicode_FromWideChar +PyUnicode_GetDefaultEncoding +PyUnicode_GetSize +PyUnicode_IsIdentifier +PyUnicode_Join +PyUnicode_Partition +PyUnicode_RPartition +PyUnicode_RSplit +PyUnicode_Replace +PyUnicode_Resize +PyUnicode_RichCompare +PyUnicode_SetDefaultEncoding +PyUnicode_Split +PyUnicode_Splitlines +PyUnicode_Tailmatch +PyUnicode_Translate PyUnicode_BuildEncodingMap PyUnicode_CompareWithASCIIString PyUnicode_DecodeUTF7 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 4 11:21:31 2014 From: python-checkins at python.org (martin.v.loewis) Date: Sat, 4 Jan 2014 11:21:31 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy4z?= Message-ID: <3dxJtM4Ygsz7Lkx@mail.python.org> http://hg.python.org/cpython/rev/7ce112a25402 changeset: 88290:7ce112a25402 parent: 88288:0ea09c824d9b parent: 88289:1819fee1c20f user: Martin v. L?wis date: Sat Jan 04 11:21:15 2014 +0100 summary: Merge 3.3 files: PC/python34stub.def | 124 ++++++++++++++++---------------- 1 files changed, 62 insertions(+), 62 deletions(-) diff --git a/PC/python34stub.def b/PC/python34stub.def --- a/PC/python34stub.def +++ b/PC/python34stub.def @@ -547,68 +547,68 @@ PyUnicodeTranslateError_SetEnd PyUnicodeTranslateError_SetReason PyUnicodeTranslateError_SetStart -PyUnicodeUCS2_Append -PyUnicodeUCS2_AppendAndDel -PyUnicodeUCS2_AsASCIIString -PyUnicodeUCS2_AsCharmapString -PyUnicodeUCS2_AsDecodedObject -PyUnicodeUCS2_AsDecodedUnicode -PyUnicodeUCS2_AsEncodedObject -PyUnicodeUCS2_AsEncodedString -PyUnicodeUCS2_AsEncodedUnicode -PyUnicodeUCS2_AsLatin1String -PyUnicodeUCS2_AsRawUnicodeEscapeString -PyUnicodeUCS2_AsUTF16String -PyUnicodeUCS2_AsUTF32String -PyUnicodeUCS2_AsUTF8String -PyUnicodeUCS2_AsUnicodeEscapeString -PyUnicodeUCS2_AsWideChar -PyUnicodeUCS2_ClearFreelist -PyUnicodeUCS2_Compare -PyUnicodeUCS2_Concat -PyUnicodeUCS2_Contains -PyUnicodeUCS2_Count -PyUnicodeUCS2_Decode -PyUnicodeUCS2_DecodeASCII -PyUnicodeUCS2_DecodeCharmap -PyUnicodeUCS2_DecodeFSDefault -PyUnicodeUCS2_DecodeFSDefaultAndSize -PyUnicodeUCS2_DecodeLatin1 -PyUnicodeUCS2_DecodeRawUnicodeEscape -PyUnicodeUCS2_DecodeUTF16 -PyUnicodeUCS2_DecodeUTF16Stateful -PyUnicodeUCS2_DecodeUTF32 -PyUnicodeUCS2_DecodeUTF32Stateful -PyUnicodeUCS2_DecodeUTF8 -PyUnicodeUCS2_DecodeUTF8Stateful -PyUnicodeUCS2_DecodeUnicodeEscape -PyUnicodeUCS2_FSConverter -PyUnicodeUCS2_FSDecoder -PyUnicodeUCS2_Find -PyUnicodeUCS2_Format -PyUnicodeUCS2_FromEncodedObject -PyUnicodeUCS2_FromFormat -PyUnicodeUCS2_FromFormatV -PyUnicodeUCS2_FromObject -PyUnicodeUCS2_FromOrdinal -PyUnicodeUCS2_FromString -PyUnicodeUCS2_FromStringAndSize -PyUnicodeUCS2_FromWideChar -PyUnicodeUCS2_GetDefaultEncoding -PyUnicodeUCS2_GetSize -PyUnicodeUCS2_IsIdentifier -PyUnicodeUCS2_Join -PyUnicodeUCS2_Partition -PyUnicodeUCS2_RPartition -PyUnicodeUCS2_RSplit -PyUnicodeUCS2_Replace -PyUnicodeUCS2_Resize -PyUnicodeUCS2_RichCompare -PyUnicodeUCS2_SetDefaultEncoding -PyUnicodeUCS2_Split -PyUnicodeUCS2_Splitlines -PyUnicodeUCS2_Tailmatch -PyUnicodeUCS2_Translate +PyUnicode_Append +PyUnicode_AppendAndDel +PyUnicode_AsASCIIString +PyUnicode_AsCharmapString +PyUnicode_AsDecodedObject +PyUnicode_AsDecodedUnicode +PyUnicode_AsEncodedObject +PyUnicode_AsEncodedString +PyUnicode_AsEncodedUnicode +PyUnicode_AsLatin1String +PyUnicode_AsRawUnicodeEscapeString +PyUnicode_AsUTF16String +PyUnicode_AsUTF32String +PyUnicode_AsUTF8String +PyUnicode_AsUnicodeEscapeString +PyUnicode_AsWideChar +PyUnicode_ClearFreelist +PyUnicode_Compare +PyUnicode_Concat +PyUnicode_Contains +PyUnicode_Count +PyUnicode_Decode +PyUnicode_DecodeASCII +PyUnicode_DecodeCharmap +PyUnicode_DecodeFSDefault +PyUnicode_DecodeFSDefaultAndSize +PyUnicode_DecodeLatin1 +PyUnicode_DecodeRawUnicodeEscape +PyUnicode_DecodeUTF16 +PyUnicode_DecodeUTF16Stateful +PyUnicode_DecodeUTF32 +PyUnicode_DecodeUTF32Stateful +PyUnicode_DecodeUTF8 +PyUnicode_DecodeUTF8Stateful +PyUnicode_DecodeUnicodeEscape +PyUnicode_FSConverter +PyUnicode_FSDecoder +PyUnicode_Find +PyUnicode_Format +PyUnicode_FromEncodedObject +PyUnicode_FromFormat +PyUnicode_FromFormatV +PyUnicode_FromObject +PyUnicode_FromOrdinal +PyUnicode_FromString +PyUnicode_FromStringAndSize +PyUnicode_FromWideChar +PyUnicode_GetDefaultEncoding +PyUnicode_GetSize +PyUnicode_IsIdentifier +PyUnicode_Join +PyUnicode_Partition +PyUnicode_RPartition +PyUnicode_RSplit +PyUnicode_Replace +PyUnicode_Resize +PyUnicode_RichCompare +PyUnicode_SetDefaultEncoding +PyUnicode_Split +PyUnicode_Splitlines +PyUnicode_Tailmatch +PyUnicode_Translate PyUnicode_BuildEncodingMap PyUnicode_CompareWithASCIIString PyUnicode_DecodeUTF7 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 4 11:26:04 2014 From: python-checkins at python.org (martin.v.loewis) Date: Sat, 4 Jan 2014 11:26:04 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Drop_reference_to_pythonco?= =?utf-8?q?re=2C_to_avoid_linking_python34=2Edll?= Message-ID: <3dxJzc406Wz7LjZ@mail.python.org> http://hg.python.org/cpython/rev/e36018357fd1 changeset: 88291:e36018357fd1 user: Martin v. L?wis date: Sat Jan 04 11:25:35 2014 +0100 summary: Drop reference to pythoncore, to avoid linking python34.dll files: PCbuild/xxlimited.vcxproj | 5 ----- 1 files changed, 0 insertions(+), 5 deletions(-) diff --git a/PCbuild/xxlimited.vcxproj b/PCbuild/xxlimited.vcxproj --- a/PCbuild/xxlimited.vcxproj +++ b/PCbuild/xxlimited.vcxproj @@ -183,11 +183,6 @@ - - - {cf7ac3d1-e2df-41d2-bea6-1e2556cdea26} - - -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 4 13:07:39 2014 From: python-checkins at python.org (stefan.krah) Date: Sat, 4 Jan 2014 13:07:39 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Whitespace=2E?= Message-ID: <3dxMDq0pljz7LjZ@mail.python.org> http://hg.python.org/cpython/rev/28337a8fb502 changeset: 88292:28337a8fb502 branch: 3.3 parent: 88289:1819fee1c20f user: Stefan Krah date: Sat Jan 04 13:03:48 2014 +0100 summary: Whitespace. files: Modules/_decimal/libmpdec/mpdecimal.h | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/_decimal/libmpdec/mpdecimal.h b/Modules/_decimal/libmpdec/mpdecimal.h --- a/Modules/_decimal/libmpdec/mpdecimal.h +++ b/Modules/_decimal/libmpdec/mpdecimal.h @@ -406,7 +406,7 @@ mpd_ssize_t mpd_to_eng_size(char **res, const mpd_t *dec, int fmt); int mpd_validate_lconv(mpd_spec_t *spec); int mpd_parse_fmt_str(mpd_spec_t *spec, const char *fmt, int caps); -char * mpd_qformat_spec(const mpd_t *dec, const mpd_spec_t *spec, const mpd_context_t *ctx, uint32_t *status); +char *mpd_qformat_spec(const mpd_t *dec, const mpd_spec_t *spec, const mpd_context_t *ctx, uint32_t *status); char *mpd_qformat(const mpd_t *dec, const char *fmt, const mpd_context_t *ctx, uint32_t *status); #define MPD_NUM_FLAGS 15 @@ -465,7 +465,7 @@ int mpd_qcheck_nans(mpd_t *nanresult, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); void mpd_qfinalize(mpd_t *result, const mpd_context_t *ctx, uint32_t *status); -const char * mpd_class(const mpd_t *a, const mpd_context_t *ctx); +const char *mpd_class(const mpd_t *a, const mpd_context_t *ctx); int mpd_qcopy(mpd_t *result, const mpd_t *a, uint32_t *status); mpd_t *mpd_qncopy(const mpd_t *a); @@ -579,7 +579,7 @@ /* Signalling functions */ /******************************************************************************/ -char * mpd_format(const mpd_t *dec, const char *fmt, mpd_context_t *ctx); +char *mpd_format(const mpd_t *dec, const char *fmt, mpd_context_t *ctx); void mpd_import_u16(mpd_t *result, const uint16_t *srcdata, size_t srclen, uint8_t srcsign, uint32_t base, mpd_context_t *ctx); void mpd_import_u32(mpd_t *result, const uint32_t *srcdata, size_t srclen, uint8_t srcsign, uint32_t base, mpd_context_t *ctx); size_t mpd_export_u16(uint16_t **rdata, size_t rlen, uint32_t base, const mpd_t *src, mpd_context_t *ctx); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 4 13:07:40 2014 From: python-checkins at python.org (stefan.krah) Date: Sat, 4 Jan 2014 13:07:40 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgZnJvbSAzLjMu?= Message-ID: <3dxMDr2fKfz7LjZ@mail.python.org> http://hg.python.org/cpython/rev/1f02dc050855 changeset: 88293:1f02dc050855 parent: 88291:e36018357fd1 parent: 88292:28337a8fb502 user: Stefan Krah date: Sat Jan 04 13:06:59 2014 +0100 summary: Merge from 3.3. files: Modules/_decimal/libmpdec/mpdecimal.h | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/_decimal/libmpdec/mpdecimal.h b/Modules/_decimal/libmpdec/mpdecimal.h --- a/Modules/_decimal/libmpdec/mpdecimal.h +++ b/Modules/_decimal/libmpdec/mpdecimal.h @@ -406,7 +406,7 @@ mpd_ssize_t mpd_to_eng_size(char **res, const mpd_t *dec, int fmt); int mpd_validate_lconv(mpd_spec_t *spec); int mpd_parse_fmt_str(mpd_spec_t *spec, const char *fmt, int caps); -char * mpd_qformat_spec(const mpd_t *dec, const mpd_spec_t *spec, const mpd_context_t *ctx, uint32_t *status); +char *mpd_qformat_spec(const mpd_t *dec, const mpd_spec_t *spec, const mpd_context_t *ctx, uint32_t *status); char *mpd_qformat(const mpd_t *dec, const char *fmt, const mpd_context_t *ctx, uint32_t *status); #define MPD_NUM_FLAGS 15 @@ -465,7 +465,7 @@ int mpd_qcheck_nans(mpd_t *nanresult, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status); void mpd_qfinalize(mpd_t *result, const mpd_context_t *ctx, uint32_t *status); -const char * mpd_class(const mpd_t *a, const mpd_context_t *ctx); +const char *mpd_class(const mpd_t *a, const mpd_context_t *ctx); int mpd_qcopy(mpd_t *result, const mpd_t *a, uint32_t *status); mpd_t *mpd_qncopy(const mpd_t *a); @@ -579,7 +579,7 @@ /* Signalling functions */ /******************************************************************************/ -char * mpd_format(const mpd_t *dec, const char *fmt, mpd_context_t *ctx); +char *mpd_format(const mpd_t *dec, const char *fmt, mpd_context_t *ctx); void mpd_import_u16(mpd_t *result, const uint16_t *srcdata, size_t srclen, uint8_t srcsign, uint32_t base, mpd_context_t *ctx); void mpd_import_u32(mpd_t *result, const uint32_t *srcdata, size_t srclen, uint8_t srcsign, uint32_t base, mpd_context_t *ctx); size_t mpd_export_u16(uint16_t **rdata, size_t rlen, uint32_t base, const mpd_t *src, mpd_context_t *ctx); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 4 18:26:01 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 4 Jan 2014 18:26:01 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315027=3A_Rewrite_?= =?utf-8?q?the_UTF-32_encoder=2E__It_is_now_1=2E6x_to_3=2E5x_faster=2E?= Message-ID: <3dxVJ90mFrz7Ljs@mail.python.org> http://hg.python.org/cpython/rev/b72c5573c5e7 changeset: 88294:b72c5573c5e7 user: Serhiy Storchaka date: Sat Jan 04 19:25:37 2014 +0200 summary: Issue #15027: Rewrite the UTF-32 encoder. It is now 1.6x to 3.5x faster. files: Doc/whatsnew/3.4.rst | 4 +- Misc/NEWS | 2 + Objects/stringlib/codecs.h | 87 +++++++++++++++++++ Objects/unicodeobject.c | 110 ++++++++++-------------- 4 files changed, 137 insertions(+), 66 deletions(-) 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 @@ -1213,7 +1213,9 @@ Significant Optimizations ========================= -* The UTF-32 decoder is now 3x to 4x faster. +* The UTF-32 decoder is now 3x to 4x faster. The UTF-32 encoder is now 1.6x + to 3.5x faster. (Contributed by Serhiy Storchaka in :issue:`14625` and + :issue:`15027`.) * The cost of hash collisions for sets is now reduced. Each hash table probe now checks a series of consecutive, adjacent key/hash pairs before diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #15027: Rewrite the UTF-32 encoder. It is now 1.6x to 3.5x faster. + - Issue #17432: Drop UCS2 from names of Unicode functions in python3.def. - Issue #19526: Exclude all new API from the stable ABI. Exceptions can be diff --git a/Objects/stringlib/codecs.h b/Objects/stringlib/codecs.h --- a/Objects/stringlib/codecs.h +++ b/Objects/stringlib/codecs.h @@ -718,6 +718,93 @@ return len - (end - in + 1); #endif } + +#if STRINGLIB_SIZEOF_CHAR == 1 +# define SWAB4(CH, tmp) ((CH) << 24) /* high bytes are zero */ +#elif STRINGLIB_SIZEOF_CHAR == 2 +# define SWAB4(CH, tmp) (tmp = (CH), \ + ((tmp & 0x00FFu) << 24) + ((tmp & 0xFF00u) << 8)) + /* high bytes are zero */ +#else +# define SWAB4(CH, tmp) (tmp = (CH), \ + tmp = ((tmp & 0x00FF00FFu) << 8) + ((tmp >> 8) & 0x00FF00FFu), \ + ((tmp & 0x0000FFFFu) << 16) + ((tmp >> 16) & 0x0000FFFFu)) +#endif +Py_LOCAL_INLINE(Py_ssize_t) +STRINGLIB(utf32_encode)(const STRINGLIB_CHAR *in, + Py_ssize_t len, + PY_UINT32_T **outptr, + int native_ordering) +{ + PY_UINT32_T *out = *outptr; + const STRINGLIB_CHAR *end = in + len; + if (native_ordering) { + const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4); + while (in < unrolled_end) { +#if STRINGLIB_SIZEOF_CHAR > 1 + /* check if any character is a surrogate character */ + if (((in[0] ^ 0xd800) & + (in[1] ^ 0xd800) & + (in[2] ^ 0xd800) & + (in[3] ^ 0xd800) & 0xf800) == 0) + break; +#endif + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; + in += 4; out += 4; + } + while (in < end) { + Py_UCS4 ch; + ch = *in++; +#if STRINGLIB_SIZEOF_CHAR > 1 + if (Py_UNICODE_IS_SURROGATE(ch)) { + /* reject surrogate characters (U+DC800-U+DFFF) */ + goto fail; + } +#endif + *out++ = ch; + } + } else { + const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4); + while (in < unrolled_end) { +#if STRINGLIB_SIZEOF_CHAR > 1 + Py_UCS4 ch1, ch2, ch3, ch4; + /* check if any character is a surrogate character */ + if (((in[0] ^ 0xd800) & + (in[1] ^ 0xd800) & + (in[2] ^ 0xd800) & + (in[3] ^ 0xd800) & 0xf800) == 0) + break; +#endif + out[0] = SWAB4(in[0], ch1); + out[1] = SWAB4(in[1], ch2); + out[2] = SWAB4(in[2], ch3); + out[3] = SWAB4(in[3], ch4); + in += 4; out += 4; + } + while (in < end) { + Py_UCS4 ch = *in++; +#if STRINGLIB_SIZEOF_CHAR > 1 + if (Py_UNICODE_IS_SURROGATE(ch)) { + /* reject surrogate characters (U+DC800-U+DFFF) */ + goto fail; + } +#endif + *out++ = SWAB4(ch, ch); + } + } + *outptr = out; + return len; +#if STRINGLIB_SIZEOF_CHAR > 1 + fail: + *outptr = out; + return len - (end - in + 1); +#endif +} +#undef SWAB4 + #endif #endif /* STRINGLIB_IS_UNICODE */ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -5085,32 +5085,22 @@ const char *errors, int byteorder) { - int kind; - void *data; + enum PyUnicode_Kind kind; + const void *data; Py_ssize_t len; PyObject *v; - unsigned char *p; - Py_ssize_t nsize, i; - /* Offsets from p for storing byte pairs in the right order. */ + PY_UINT32_T *out; #if PY_LITTLE_ENDIAN - int iorder[] = {0, 1, 2, 3}; + int native_ordering = byteorder <= 0; #else - int iorder[] = {3, 2, 1, 0}; + int native_ordering = byteorder >= 0; #endif const char *encoding; + Py_ssize_t nsize, pos; PyObject *errorHandler = NULL; PyObject *exc = NULL; PyObject *rep = NULL; -#define STORECHAR(CH) \ - do { \ - p[iorder[3]] = ((CH) >> 24) & 0xff; \ - p[iorder[2]] = ((CH) >> 16) & 0xff; \ - p[iorder[1]] = ((CH) >> 8) & 0xff; \ - p[iorder[0]] = (CH) & 0xff; \ - p += 4; \ - } while(0) - if (!PyUnicode_Check(str)) { PyErr_BadArgument(); return NULL; @@ -5121,59 +5111,53 @@ data = PyUnicode_DATA(str); len = PyUnicode_GET_LENGTH(str); + if (len > PY_SSIZE_T_MAX / 4 - (byteorder == 0)) + return PyErr_NoMemory(); nsize = len + (byteorder == 0); - if (nsize > PY_SSIZE_T_MAX / 4) - return PyErr_NoMemory(); v = PyBytes_FromStringAndSize(NULL, nsize * 4); if (v == NULL) return NULL; - p = (unsigned char *)PyBytes_AS_STRING(v); + /* output buffer is 4-bytes aligned */ + assert(_Py_IS_ALIGNED(PyBytes_AS_STRING(v), 4)); + out = (PY_UINT32_T *)PyBytes_AS_STRING(v); if (byteorder == 0) - STORECHAR(0xFEFF); + *out++ = 0xFEFF; if (len == 0) - return v; - - if (byteorder == -1) { - /* force LE */ - iorder[0] = 0; - iorder[1] = 1; - iorder[2] = 2; - iorder[3] = 3; + goto done; + + if (byteorder == -1) encoding = "utf-32-le"; - } - else if (byteorder == 1) { - /* force BE */ - iorder[0] = 3; - iorder[1] = 2; - iorder[2] = 1; - iorder[3] = 0; + else if (byteorder == 1) encoding = "utf-32-be"; - } else encoding = "utf-32"; if (kind == PyUnicode_1BYTE_KIND) { - for (i = 0; i < len; i++) - STORECHAR(PyUnicode_READ(kind, data, i)); - return v; - } - - for (i = 0; i < len;) { + ucs1lib_utf32_encode((const Py_UCS1 *)data, len, &out, native_ordering); + goto done; + } + + pos = 0; + while (pos < len) { Py_ssize_t repsize, moreunits; - Py_UCS4 ch = PyUnicode_READ(kind, data, i); - i++; - assert(ch <= MAX_UNICODE); - if (!Py_UNICODE_IS_SURROGATE(ch)) { - STORECHAR(ch); - continue; - } + + if (kind == PyUnicode_2BYTE_KIND) { + pos += ucs2lib_utf32_encode((const Py_UCS2 *)data + pos, len - pos, + &out, native_ordering); + } + else { + assert(kind == PyUnicode_4BYTE_KIND); + pos += ucs4lib_utf32_encode((const Py_UCS4 *)data + pos, len - pos, + &out, native_ordering); + } + if (pos == len) + break; rep = unicode_encode_call_errorhandler( errors, &errorHandler, encoding, "surrogates not allowed", - str, &exc, i-1, i, &i); - + str, &exc, pos, pos + 1, &pos); if (!rep) goto error; @@ -5181,7 +5165,7 @@ repsize = PyBytes_GET_SIZE(rep); if (repsize & 3) { raise_encode_exception(&exc, encoding, - str, i - 1, i, + str, pos - 1, pos, "surrogates not allowed"); goto error; } @@ -5194,7 +5178,7 @@ moreunits = repsize = PyUnicode_GET_LENGTH(rep); if (!PyUnicode_IS_ASCII(rep)) { raise_encode_exception(&exc, encoding, - str, i - 1, i, + str, pos - 1, pos, "surrogates not allowed"); goto error; } @@ -5202,7 +5186,7 @@ /* four bytes are reserved for each surrogate */ if (moreunits > 1) { - Py_ssize_t outpos = p - (unsigned char*) PyBytes_AS_STRING(v); + Py_ssize_t outpos = out - (PY_UINT32_T*) PyBytes_AS_STRING(v); Py_ssize_t morebytes = 4 * (moreunits - 1); if (PyBytes_GET_SIZE(v) > PY_SSIZE_T_MAX - morebytes) { /* integer overflow */ @@ -5211,20 +5195,16 @@ } if (_PyBytes_Resize(&v, PyBytes_GET_SIZE(v) + morebytes) < 0) goto error; - p = (unsigned char*) PyBytes_AS_STRING(v) + outpos; + out = (PY_UINT32_T*) PyBytes_AS_STRING(v) + outpos; } if (PyBytes_Check(rep)) { - Py_MEMCPY(p, PyBytes_AS_STRING(rep), repsize); - p += repsize; + Py_MEMCPY(out, PyBytes_AS_STRING(rep), repsize); + out += moreunits; } else /* rep is unicode */ { - const Py_UCS1 *repdata; assert(PyUnicode_KIND(rep) == PyUnicode_1BYTE_KIND); - repdata = PyUnicode_1BYTE_DATA(rep); - while (repsize--) { - Py_UCS4 ch = *repdata++; - STORECHAR(ch); - } + ucs1lib_utf32_encode(PyUnicode_1BYTE_DATA(rep), repsize, + &out, native_ordering); } Py_CLEAR(rep); @@ -5233,11 +5213,12 @@ /* Cut back to size actually needed. This is necessary for, for example, encoding of a string containing isolated surrogates and the 'ignore' handler is used. */ - nsize = p - (unsigned char*) PyBytes_AS_STRING(v); + nsize = (unsigned char*) out - (unsigned char*) PyBytes_AS_STRING(v); if (nsize != PyBytes_GET_SIZE(v)) _PyBytes_Resize(&v, nsize); Py_XDECREF(errorHandler); Py_XDECREF(exc); + done: return v; error: Py_XDECREF(rep); @@ -5245,7 +5226,6 @@ Py_XDECREF(exc); Py_XDECREF(v); return NULL; -#undef STORECHAR } PyObject * -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 4 20:09:30 2014 From: python-checkins at python.org (larry.hastings) Date: Sat, 4 Jan 2014 20:09:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2319976=3A_Argument?= =?utf-8?q?_Clinic_METH=5FNOARGS_functions_now_always?= Message-ID: <3dxXbZ30w6z7Ljs@mail.python.org> http://hg.python.org/cpython/rev/c4ababa110a2 changeset: 88295:c4ababa110a2 user: Larry Hastings date: Sat Jan 04 11:09:09 2014 -0800 summary: Issue #19976: Argument Clinic METH_NOARGS functions now always take two parameters. files: Include/pymacro.h | 6 + Misc/NEWS | 5 + Modules/_pickle.c | 140 +++++++++++++++++++++++++--- Modules/zlibmodule.c | 17 +++- Tools/clinic/clinic.py | 13 +-- 5 files changed, 150 insertions(+), 31 deletions(-) diff --git a/Include/pymacro.h b/Include/pymacro.h --- a/Include/pymacro.h +++ b/Include/pymacro.h @@ -69,4 +69,10 @@ /* Check if pointer "p" is aligned to "a"-bytes boundary. */ #define _Py_IS_ALIGNED(p, a) (!((Py_uintptr_t)(p) & (Py_uintptr_t)((a) - 1))) +#ifdef __GNUC__ +#define Py_UNUSED(name) _unused_ ## name __attribute__((unused)) +#else +#define Py_UNUSED(name) _unused_ ## name +#endif + #endif /* Py_PYMACRO_H */ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -342,6 +342,11 @@ - Issue #19795: Improved markup of True/False constants. +Tools/Demos +----------- + +- Issue #19976: Argument Clinic METH_NOARGS functions now always + take two parameters. What's New in Python 3.4.0 Beta 1? ================================== diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -3901,8 +3901,21 @@ {"clear_memo", (PyCFunction)_pickle_Pickler_clear_memo, METH_NOARGS, _pickle_Pickler_clear_memo__doc__}, static PyObject * -_pickle_Pickler_clear_memo(PicklerObject *self) -/*[clinic checksum: 9c32be7e7a17ff82a81aae409d0d4f469033a5b2]*/ +_pickle_Pickler_clear_memo_impl(PicklerObject *self); + +static PyObject * +_pickle_Pickler_clear_memo(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + return_value = _pickle_Pickler_clear_memo_impl((PicklerObject *)self); + + return return_value; +} + +static PyObject * +_pickle_Pickler_clear_memo_impl(PicklerObject *self) +/*[clinic checksum: 0574593b102fffb8e781d7bb9b536ceffc525ac1]*/ { if (self->memo) PyMemoTable_Clear(self->memo); @@ -4176,8 +4189,21 @@ {"clear", (PyCFunction)_pickle_PicklerMemoProxy_clear, METH_NOARGS, _pickle_PicklerMemoProxy_clear__doc__}, static PyObject * -_pickle_PicklerMemoProxy_clear(PicklerMemoProxyObject *self) -/*[clinic checksum: 507f13938721992e175a3e58b5ad02620045a1cc]*/ +_pickle_PicklerMemoProxy_clear_impl(PicklerMemoProxyObject *self); + +static PyObject * +_pickle_PicklerMemoProxy_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + return_value = _pickle_PicklerMemoProxy_clear_impl((PicklerMemoProxyObject *)self); + + return return_value; +} + +static PyObject * +_pickle_PicklerMemoProxy_clear_impl(PicklerMemoProxyObject *self) +/*[clinic checksum: c6ca252530ccb3ea2f4b33507b51b183f23b24c7]*/ { if (self->pickler->memo) PyMemoTable_Clear(self->pickler->memo); @@ -4200,8 +4226,21 @@ {"copy", (PyCFunction)_pickle_PicklerMemoProxy_copy, METH_NOARGS, _pickle_PicklerMemoProxy_copy__doc__}, static PyObject * -_pickle_PicklerMemoProxy_copy(PicklerMemoProxyObject *self) -/*[clinic checksum: 73a5117ab354290ebdbe07bd0bf7232d0936a69d]*/ +_pickle_PicklerMemoProxy_copy_impl(PicklerMemoProxyObject *self); + +static PyObject * +_pickle_PicklerMemoProxy_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + return_value = _pickle_PicklerMemoProxy_copy_impl((PicklerMemoProxyObject *)self); + + return return_value; +} + +static PyObject * +_pickle_PicklerMemoProxy_copy_impl(PicklerMemoProxyObject *self) +/*[clinic checksum: 808c4d5a37359ed5fb2efe81dbe5ff480719f470]*/ { Py_ssize_t i; PyMemoTable *memo; @@ -4254,11 +4293,24 @@ {"__reduce__", (PyCFunction)_pickle_PicklerMemoProxy___reduce__, METH_NOARGS, _pickle_PicklerMemoProxy___reduce____doc__}, static PyObject * -_pickle_PicklerMemoProxy___reduce__(PicklerMemoProxyObject *self) -/*[clinic checksum: 40f0bf7a9b161e77130674f0481bda0a0184dcce]*/ +_pickle_PicklerMemoProxy___reduce___impl(PicklerMemoProxyObject *self); + +static PyObject * +_pickle_PicklerMemoProxy___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + return_value = _pickle_PicklerMemoProxy___reduce___impl((PicklerMemoProxyObject *)self); + + return return_value; +} + +static PyObject * +_pickle_PicklerMemoProxy___reduce___impl(PicklerMemoProxyObject *self) +/*[clinic checksum: 2293152bdf53951a012d430767b608f5fb4213b5]*/ { PyObject *reduce_value, *dict_args; - PyObject *contents = _pickle_PicklerMemoProxy_copy(self); + PyObject *contents = _pickle_PicklerMemoProxy_copy_impl(self); if (contents == NULL) return NULL; @@ -6288,8 +6340,21 @@ {"load", (PyCFunction)_pickle_Unpickler_load, METH_NOARGS, _pickle_Unpickler_load__doc__}, static PyObject * -_pickle_Unpickler_load(PyObject *self) -/*[clinic checksum: c2ae1263f0dd000f34ccf0fe59d7c544464babc4]*/ +_pickle_Unpickler_load_impl(PyObject *self); + +static PyObject * +_pickle_Unpickler_load(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + return_value = _pickle_Unpickler_load_impl(self); + + return return_value; +} + +static PyObject * +_pickle_Unpickler_load_impl(PyObject *self) +/*[clinic checksum: 55f35fcaf034817e75c355ec50b7878577355899]*/ { UnpicklerObject *unpickler = (UnpicklerObject*)self; @@ -6688,8 +6753,21 @@ {"clear", (PyCFunction)_pickle_UnpicklerMemoProxy_clear, METH_NOARGS, _pickle_UnpicklerMemoProxy_clear__doc__}, static PyObject * -_pickle_UnpicklerMemoProxy_clear(UnpicklerMemoProxyObject *self) -/*[clinic checksum: 46fecf4e33c0c873124f845edf6cc3a2e9864bd5]*/ +_pickle_UnpicklerMemoProxy_clear_impl(UnpicklerMemoProxyObject *self); + +static PyObject * +_pickle_UnpicklerMemoProxy_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + return_value = _pickle_UnpicklerMemoProxy_clear_impl((UnpicklerMemoProxyObject *)self); + + return return_value; +} + +static PyObject * +_pickle_UnpicklerMemoProxy_clear_impl(UnpicklerMemoProxyObject *self) +/*[clinic checksum: e0f99c26d48444a3f58f598bec3190c66595fce7]*/ { _Unpickler_MemoCleanup(self->unpickler); self->unpickler->memo = _Unpickler_NewMemo(self->unpickler->memo_size); @@ -6714,8 +6792,21 @@ {"copy", (PyCFunction)_pickle_UnpicklerMemoProxy_copy, METH_NOARGS, _pickle_UnpicklerMemoProxy_copy__doc__}, static PyObject * -_pickle_UnpicklerMemoProxy_copy(UnpicklerMemoProxyObject *self) -/*[clinic checksum: f8856c4e8a33540886dfbb245f286af3008fa0ad]*/ +_pickle_UnpicklerMemoProxy_copy_impl(UnpicklerMemoProxyObject *self); + +static PyObject * +_pickle_UnpicklerMemoProxy_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + return_value = _pickle_UnpicklerMemoProxy_copy_impl((UnpicklerMemoProxyObject *)self); + + return return_value; +} + +static PyObject * +_pickle_UnpicklerMemoProxy_copy_impl(UnpicklerMemoProxyObject *self) +/*[clinic checksum: 8c0ab91c0b694ea71a1774650898a760d1ab4765]*/ { Py_ssize_t i; PyObject *new_memo = PyDict_New(); @@ -6761,12 +6852,25 @@ {"__reduce__", (PyCFunction)_pickle_UnpicklerMemoProxy___reduce__, METH_NOARGS, _pickle_UnpicklerMemoProxy___reduce____doc__}, static PyObject * -_pickle_UnpicklerMemoProxy___reduce__(UnpicklerMemoProxyObject *self) -/*[clinic checksum: ab5516a77659144e1191c7dd70a0c6c7455660bc]*/ +_pickle_UnpicklerMemoProxy___reduce___impl(UnpicklerMemoProxyObject *self); + +static PyObject * +_pickle_UnpicklerMemoProxy___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + return_value = _pickle_UnpicklerMemoProxy___reduce___impl((UnpicklerMemoProxyObject *)self); + + return return_value; +} + +static PyObject * +_pickle_UnpicklerMemoProxy___reduce___impl(UnpicklerMemoProxyObject *self) +/*[clinic checksum: 4ee76a65511291f0de2e9e63db395d2e5d6d8df6]*/ { PyObject *reduce_value; PyObject *constructor_args; - PyObject *contents = _pickle_UnpicklerMemoProxy_copy(self); + PyObject *contents = _pickle_UnpicklerMemoProxy_copy_impl(self); if (contents == NULL) return NULL; diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -1045,8 +1045,21 @@ {"copy", (PyCFunction)zlib_Compress_copy, METH_NOARGS, zlib_Compress_copy__doc__}, static PyObject * -zlib_Compress_copy(compobject *self) -/*[clinic checksum: 0b37c07f8f27deb7d4769951fbecf600a1006ef8]*/ +zlib_Compress_copy_impl(compobject *self); + +static PyObject * +zlib_Compress_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + return_value = zlib_Compress_copy_impl((compobject *)self); + + return return_value; +} + +static PyObject * +zlib_Compress_copy_impl(compobject *self) +/*[clinic checksum: 2f454ee15be3bc53cfb4e845c3f891f68be4c8e4]*/ { compobject *retval = NULL; int err; diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -400,19 +400,13 @@ {{"{name}", (PyCFunction){c_basename}, {methoddef_flags}, {c_basename}__doc__}}, """.replace('{methoddef_flags}', flags) - def meth_noargs_pyobject_template(self, methoddef_flags=""): - return self.template_base("METH_NOARGS", methoddef_flags) + """ -static PyObject * -{c_basename}({impl_parameters}) -""" - def meth_noargs_template(self, methoddef_flags=""): return self.template_base("METH_NOARGS", methoddef_flags) + """ static {impl_return_type} {impl_prototype}; static PyObject * -{c_basename}({self_type}{self_name}) +{c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored)) {{ PyObject *return_value = NULL; {declarations} @@ -713,10 +707,7 @@ f.return_converter.type == 'PyObject *') if not parameters: - if default_return_converter: - template = self.meth_noargs_pyobject_template(f.methoddef_flags) - else: - template = self.meth_noargs_template(f.methoddef_flags) + template = self.meth_noargs_template(f.methoddef_flags) elif (len(parameters) == 1 and parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY and not converters[0].is_optional() and -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 4 21:45:13 2014 From: python-checkins at python.org (larry.hastings) Date: Sat, 4 Jan 2014 21:45:13 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2319659=3A_Added_do?= =?utf-8?q?cumentation_for_Argument_Clinic=2E?= Message-ID: <3dxZk10Zt0z7Lmp@mail.python.org> http://hg.python.org/cpython/rev/e2280bf5c263 changeset: 88296:e2280bf5c263 user: Larry Hastings date: Sat Jan 04 12:44:57 2014 -0800 summary: Issue #19659: Added documentation for Argument Clinic. files: Doc/howto/clinic.rst | 900 +++++++++++++++++++++++++++++ Doc/howto/index.rst | 1 + Misc/NEWS | 2 + Modules/zlibmodule.c | 7 +- Tools/clinic/clinic.py | 56 +- 5 files changed, 955 insertions(+), 11 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst new file mode 100644 --- /dev/null +++ b/Doc/howto/clinic.rst @@ -0,0 +1,900 @@ +====================== +Argument Clinic How-To +====================== + +:author: Larry Hastings + + +.. topic:: Abstract + + Argument Clinic is a preprocessor for CPython C files. + Its purpose is to automate all the boilerplate involved + with writing argument parsing code for "builtins". + This document shows you how to convert your first C + function to work with Argument Clinic, and then introduces + some advanced topics on Argument Clinic usage. + + Argument Clinic is currently considered an internal + tool for the CPython code tree. Its use is not supported + for files outside the CPython code tree, and no guarantees + are made regarding backwards compatibility for future + versions. In other words: if you maintain an external C + extension for CPython, you're welcome to experiment with + Argument Clinic in your own code. But the version of Argument + Clinic that ships with CPython 3.5 *could* be totally + incompatible and break all your code. + +======================== +Basic Concepts And Usage +======================== + +Argument Clinic ships with CPython. You can find it in ``Tools/clinic/clinic.py``. +If you run that script, specifying a C file as an argument:: + + % python3 Tools/clinic/clinic.py foo.c + +Argument Clinic will scan over the file looking for lines that +look exactly like this:: + + /*[clinic] + +When it finds one, it reads everything up to a line that looks +like this:: + + [clinic]*/ + +Everything in between these two lines is input for Argument Clinic. +All of these lines, including the beginning and ending comment +lines, are collectively called an Argument Clinic "input block", +or "block" for short. + +When Argument Clinic parses one of these blocks, it +generates output. This output is rewritten into the C file +immediately after the block, followed by a comment containing a checksum. +The resulting Argument Clinic block looks like this:: + + /*[clinic] + ... clinic input goes here ... + [clinic]*/ + ... clinic output goes here ... + /*[clinic checksum:...]*/ + +If you run Argument Clinic on the same file a second time, Argument Clinic +will discard the old output and write out the new output with a fresh checksum +line. However, if the input hasn't changed, the output won't change either. + +You should never modify the output portion of an Argument Clinic block. Instead, +change the input until it produces the output you want. (That's the purpose of the +checksum--to detect and warn you in case someone accidentally modifies the output.) + +For the sake of clarity, here's the terminology we'll use with Argument Clinic: + +* The first line of the comment (``/*[clinic]``) is the *start line*. +* The last line of the initial comment (``[clinic]*/``) is the *end line*. +* The last line (``/*[clinic checksum:...]*/``) is the *checksum line*. +* In between the start line and the end line is the *input*. +* In between the end line and the checksum line is the *output*. +* All the text collectively, from the start line to the checksum line inclusively, + is the *block*. (A block that hasn't been successfully processed by Argument + Clinic yet doesn't have output or a checksum line, but it's still considered + a block.) + + +============================== +Converting Your First Function +============================== + +The best way to get a sense of how Argument Clinic works is to +convert a function to work with it. Let's dive in! + +0. Make sure you're working with a freshly updated trunk. + +1. Find a Python builtin that calls either ``PyArg_ParseTuple()`` + or ``PyArg_ParseTupleAndKeywords()``, and hasn't been converted yet. + For my example I'm using ``pickle.Pickler.dump()``. + +2. If the call to the ``PyArg_Parse`` function uses any of the + following format units:: + + O& + O! + es + es# + et + et# + + or if it has multiple calls to ``PyArg_ParseTuple()``, + you should choose a different function. Argument Clinic *does* + support all of these scenarios. But these are advanced + topics--let's do something simpler for your first function. + +3. Add the following boilerplate above the function, creating our block:: + + /*[clinic] + [clinic]*/ + +4. Cut the docstring and paste it in between the ``[clinic]`` lines, + removing all the junk that makes it a properly quoted C string. + When you're done you should have just the text, based at the left + margin, with no line wider than 80 characters. + (Argument Clinic will preserve indents inside the docstring.) + + Sample:: + + /*[clinic] + Write a pickled representation of obj to the open file. + [clinic]*/ + +5. If your docstring doesn't have a "summary" line, Argument Clinic will + complain. So let's make sure it has one. The "summary" line should + be a paragraph consisting of a single 80-column line + at the beginning of the docstring. + + (Our docstring consists solely of the summary line, so the sample + code doesn't have to change for this step.) + +6. Above the docstring, enter the name of the function, followed + by a blank line. This should be the Python name of the function, + and should be the full dotted path + to the function--it should start with the name of the module, + include any sub-modules, and if the function is a method on + a class it should include the class name too. + + Sample:: + + /*[clinic] + pickle.Pickler.dump + + Write a pickled representation of obj to the open file. + [clinic]*/ + +7. If this is the first time that module or class has been used with Argument + Clinic in this C file, + you must declare the module and/or class. Proper Argument Clinic hygiene + prefers declaring these in a separate block somewhere near the + top of the C file, in the same way that include files and statics go at + the top. (In our sample code we'll just show the two blocks next to + each other.) + + Sample:: + + /*[clinic] + module pickle + class pickle.Pickler + [clinic]*/ + + /*[clinic] + pickle.Pickler.dump + + Write a pickled representation of obj to the open file. + [clinic]*/ + + +8. Declare each of the parameters to the function. Each parameter + should get its own line. All the parameter lines should be + indented from the function name and the docstring. + + The general form of these parameter lines is as follows:: + + name_of_parameter: converter + + If the parameter has a default value, add that after the + converter:: + + name_of_parameter: converter = default_value + + Add a blank line below the parameters. + + What's a "converter"? It establishes both the type + of the variable used in C, and the method to convert the Python + value into a C value at runtime. + For now you're going to use what's called a "legacy converter"--a + convenience syntax intended to make porting old code into Argument + Clinic easier. + + For each parameter, copy the "format unit" for that + parameter from the ``PyArg_Parse()`` format argument and + specify *that* as its converter, as a quoted + string. ("format unit" is the formal name for the one-to-three + character substring of the ``format`` parameter that tells + the argument parsing function what the type of the variable + is and how to convert it.) + + For multicharacter format units like ``z#``, use the + entire two-or-three character string. + + Sample:: + + /*[clinic] + module pickle + class pickle.Pickler + [clinic]*/ + + /*[clinic] + pickle.Pickler.dump + + obj: 'O' + + Write a pickled representation of obj to the open file. + [clinic]*/ + +9. If your function has ``|`` in the format string, meaning some + parameters have default values, you can ignore it. Argument + Clinic infers which parameters are optional based on whether + or not they have default values. + + If your function has ``$`` in the format string, meaning it + takes keyword-only arguments, specify ``*`` on a line by + itself before the first keyword-only argument, indented the + same as the parameter lines. + + (``pickle.Pickler.dump`` has neither, so our sample is unchanged.) + + +10. If the existing C function uses ``PyArg_ParseTuple()`` + (instead of ``PyArg_ParseTupleAndKeywords()``), then all its + arguments are positional-only. + + To mark all parameters as positional-only in Argument Clinic, + add a ``/`` on a line by itself after the last parameter, + indented the same as the parameter lines. + + Sample:: + + /*[clinic] + module pickle + class pickle.Pickler + [clinic]*/ + + /*[clinic] + pickle.Pickler.dump + + obj: 'O' + / + + Write a pickled representation of obj to the open file. + [clinic]*/ + +11. It's helpful to write a per-parameter docstring, indented + another level past the parameter declaration. But per-parameter + docstrings are optional; you can skip this step if you prefer. + + Here's how per-parameter docstrings work. The first line + of the per-parameter docstring must be indented further than the + parameter definition. This left margin establishes the left margin + for the whole per-parameter docstring; all the text you write will + be outdented by this amount. You can write as much as you like, + across multiple lines if you wish. + + Sample:: + + /*[clinic] + module pickle + class pickle.Pickler + [clinic]*/ + + /*[clinic] + pickle.Pickler.dump + + obj: 'O' + The object to be pickled. + / + + Write a pickled representation of obj to the open file. + [clinic]*/ + +12. Save and close the file, then run ``Tools/clinic/clinic.py`` on it. + With luck everything worked and your block now has output! Reopen + the file in your text editor to see:: + + /*[clinic] + module pickle + class pickle.Pickler + [clinic]*/ + /*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + + /*[clinic] + pickle.Pickler.dump + + obj: 'O' + The object to be pickled. + / + + Write a pickled representation of obj to the open file. + [clinic]*/ + + PyDoc_STRVAR(pickle_Pickler_dump__doc__, + "Write a pickled representation of obj to the open file.\n" + "\n" + ... + static PyObject * + pickle_Pickler_dump_impl(PyObject *self, PyObject *obj) + /*[clinic checksum: 3bd30745bf206a48f8b576a1da3d90f55a0a4187]*/ + +13. Double-check that the argument-parsing code Argument Clinic generated + looks basically the same as the existing code. + + First, ensure both places use the same argument-parsing function. + The existing code must call either + ``PyArg_ParseTuple()`` or ``PyArg_ParseTupleAndKeywords()``; + ensure that the code generated by Argument Clinic calls the + same function. + + Second, the format string passed in to ``PyArg_ParseTuple()`` or + ``PyArg_ParseTupleAndKeywords()`` should be *exactly* the same + as the hand-written one in the existing function. + + Well, there's one way that Argument Clinic's output is permitted + to be different. Argument Clinic always generates a format string + ending with ``:`` followed by the name of the function. If the + format string originally ended with ``;`` (to specify usage help), + this is harmless--don't worry about this difference. + + Apart from that, if either of these things differ in *any way*, + fix your input to Argument Clinic and rerun ``Tools/clinic/clinic.py`` + until they are the same. + + +14. Notice that the last line of its output is the declaration + of your "impl" function. This is where the builtin's implementation goes. + Delete the existing prototype of the function you're modifying, but leave + the opening curly brace. Now delete its argument parsing code and the + declarations of all the variables it dumps the arguments into. + Notice how the Python arguments are now arguments to this impl function; + if the implementation used different names for these variables, fix it. + The result should be a function that handles just the implementation + of the Python function without any argument-parsing code. + + Sample:: + + /*[clinic] + module pickle + class pickle.Pickler + [clinic]*/ + /*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + + /*[clinic] + pickle.Pickler.dump + + obj: 'O' + The object to be pickled. + / + + Write a pickled representation of obj to the open file. + [clinic]*/ + + PyDoc_STRVAR(pickle_Pickler_dump__doc__, + "Write a pickled representation of obj to the open file.\n" + "\n" + ... + static PyObject * + pickle_Pickler_dump_impl(PyObject *self, PyObject *obj) + /*[clinic checksum: 3bd30745bf206a48f8b576a1da3d90f55a0a4187]*/ + { + /* Check whether the Pickler was initialized correctly (issue3664). + Developers often forget to call __init__() in their subclasses, which + would trigger a segfault without this check. */ + if (self->write == NULL) { + PyErr_Format(PicklingError, + "Pickler.__init__() was not called by %s.__init__()", + Py_TYPE(self)->tp_name); + return NULL; + } + + if (_Pickler_ClearBuffer(self) < 0) + return NULL; + + ... + +15. Compile and run the relevant portions of the regression-test suite. + This change should not introduce any new compile-time warnings or errors, + and there should be no externally-visible change to Python's behavior. + + Well, except for one difference: ``inspect.signature()`` run on your function + should now provide a valid signature! + + Congratulations, you've ported your first function to work with Argument Clinic! + +=============== +Advanced Topics +=============== + + +Renaming the C functions generated by Argument Clinic +----------------------------------------------------- + +Argument Clinic automatically names the functions it generates for you. +Occasionally this may cause a problem, if the generated name collides with +the name of an existing C function. There's an easy solution: you can explicitly +specify the base name to use for the C functions. Just add the keyword ``"as"`` +to your function declaration line, followed by the function name you wish to use. +Argument Clinic will use the function name you use for the base (generated) function, +and then add ``"_impl"`` to the end for the name of the impl function. + +For example, if we wanted to rename the C function names generated for +``pickle.Pickler.dump``, it'd look like this:: + + /*[clinic] + pickle.Pickler.dump as pickler_dumper + + ... + +The base function would now be named ``pickler_dumper()``, +and the impl function would be named ``pickler_dumper_impl()``. + + +Optional Groups +--------------- + +Some legacy functions have a tricky approach to parsing their arguments: +they count the number of positional arguments, then use a ``switch`` statement +to call one of several different ``PyArg_ParseTuple()`` calls depending on +how many positional arguments there are. (These functions cannot accept +keyword-only arguments.) This approach was used to simulate optional +arguments back before ``PyArg_ParseTupleAndKeywords()`` was created. + +Functions using this approach can often be converted to +use ``PyArg_ParseTupleAndKeywords()``, optional arguments, and default values. +But it's not always possible, because some of these legacy functions have +behaviors ``PyArg_ParseTupleAndKeywords()`` can't directly support. +The most obvious example is the builtin function ``range()``, which has +an optional argument on the *left* side of its required argument! +Another example is ``curses.window.addch()``, which has a group of two +arguments that must always be specified together. (The arguments are +called ``x`` and ``y``; if you call the function passing in ``x``, +you must also pass in ``y``--and if you don't pass in ``x`` you may not +pass in ``y`` either.) + +For the sake of backwards compatibility, Argument Clinic supports this +alternate approach to parsing, using what are called *optional groups*. +Optional groups are groups of arguments that can only be specified together. +They can be to the left or the right of the required arguments. They +can *only* be used with positional-only parameters. + +To specify an optional group, add a ``[`` on a line by itself before +the parameters you wish to be +in a group together, and a ``]`` on a line by itself after the +parameters. As an example, here's how ``curses.window.addch`` +uses optional groups to make the first two parameters and the last +parameter optional:: + + /*[clinic] + + curses.window.addch + + [ + x: int + X-coordinate. + y: int + Y-coordinate. + ] + + ch: object + Character to add. + + [ + attr: long + Attributes for the character. + ] + / + + ... + + +Notes: + +* For every optional group, one additional parameter will be passed into the + impl function representing the group. The parameter will be an int, and it will + be named ``group_{direction}_{number}``, + where ``{direction}`` is either ``right`` or ``left`` depending on whether the group + is before or after the required parameters, and ``{number}`` is a monotonically + increasing number (starting at 1) indicating how far away the group is from + the required parameters. When the impl is called, this parameter will be set + to zero if this group was unused, and set to non-zero if this group was used. + (By used or unused, I mean whether or not the parameters received arguments + in this invocation.) + +* If there are no required arguments, the optional groups will behave + as if they are to the right of the required arguments. + +* In the case of ambiguity, the argument parsing code + favors parameters on the left (before the required parameters). + +* Optional groups are *only* intended for legacy code. Please do not + use optional groups for new code. + + +Using real Argument Clinic converters, instead of "legacy converters" +--------------------------------------------------------------------- + +To save time, and to minimize how much you need to learn +to achieve your first port to Argument Clinic, the walkthrough above tells +you to use the "legacy converters". "Legacy converters" are a convenience, +designed explicitly to make porting existing code to Argument Clinic +easier. And to be clear, their use is entirely acceptable when porting +code for Python 3.4. + +However, in the long term we probably want all our blocks to +use Argument Clinic's real syntax for converters. Why? A couple +reasons: + +* The proper converters are far easier to read and clearer in their intent. +* There are some format units that are unsupported as "legacy converters", + because they require arguments, and the legacy converter syntax doesn't + support specifying arguments. +* In the future we may have a new argument parsing library that isn't + restricted to what ``PyArg_ParseTuple()`` supports. + +So if you want +to go that extra effort, you should consider using normal +converters instead of the legacy converters. + +In a nutshell, the syntax for Argument Clinic (non-legacy) converters +looks like a Python function call. However, if there are no explicit +arguments to the function (all functions take their default values), +you may omit the parentheses. Thus ``bool`` and ``bool()`` are exactly +the same. All parameters to Argument Clinic converters are keyword-only. + +All Argument Clinic converters accept the following arguments: + +``doc_default`` + If the parameter takes a default value, normally this value is also + provided in the ``inspect.Signature`` metadata, and displayed in the + docstring. ``doc_default`` lets you override the value used in these + two places: pass in a string representing the Python value you wish + to use in these two contexts. + +``required`` + If a parameter takes a default value, Argument Clinic infers that the + parameter is optional. However, you may want a parameter to take a + default value in C, but not behave in Python as if the parameter is + optional. Passing in ``required=True`` to a converter tells Argument + Clinic that this parameter is not optional, even if it has a default + value. + +``annotation`` + The annotation value for this parameter. Not currently supported, + because PEP 8 mandates that the Python library may not use + annotations. + +Below is a table showing the mapping of legacy converters into real +Argument Clinic converters. On the left is the legacy converter, +on the right is the text you'd replace it with. + +========= ================================================================================= +``'B'`` ``byte(bitwise=True)`` +``'b'`` ``byte`` +``'c'`` ``char`` +``'C'`` ``int(types='str')`` +``'d'`` ``double`` +``'D'`` ``Py_complex`` +``'es#'`` ``str(encoding='name_of_encoding', length=True, zeroes=True)`` +``'es'`` ``str(encoding='name_of_encoding')`` +``'et#'`` ``str(encoding='name_of_encoding', types='bytes bytearray str', length=True)`` +``'et'`` ``str(encoding='name_of_encoding', types='bytes bytearray str')`` +``'f'`` ``float`` +``'h'`` ``short`` +``'H'`` ``unsigned_short`` +``'i'`` ``int`` +``'I'`` ``unsigned_int`` +``'K'`` ``unsigned_PY_LONG_LONG`` +``'L'`` ``PY_LONG_LONG`` +``'n'`` ``Py_ssize_t`` +``'O!'`` ``object(type='name_of_Python_type')`` +``'O&'`` ``object(converter='name_of_c_function')`` +``'O'`` ``object`` +``'p'`` ``bool`` +``'s#'`` ``str(length=True)`` +``'S'`` ``PyBytesObject`` +``'s'`` ``str`` +``'s*'`` ``Py_buffer(types='str bytes bytearray buffer')`` +``'u#'`` ``Py_UNICODE(length=True)`` +``'u'`` ``Py_UNICODE`` +``'U'`` ``unicode`` +``'w*'`` ``Py_buffer(types='bytearray rwbuffer')`` +``'y#'`` ``str(type='bytes', length=True)`` +``'Y'`` ``PyByteArrayObject`` +``'y'`` ``str(type='bytes')`` +``'y*'`` ``Py_buffer`` +``'Z#'`` ``Py_UNICODE(nullable=True, length=True)`` +``'z#'`` ``str(nullable=True, length=True)`` +``'Z'`` ``Py_UNICODE(nullable=True)`` +``'z'`` ``str(nullable=True)`` +``'z*'`` ``Py_buffer(types='str bytes bytearray buffer', nullable=True)`` +========= ================================================================================= + +As an example, here's our sample ``pickle.Pickler.dump`` using the proper +converter:: + + /*[clinic] + pickle.Pickler.dump + + obj: object + The object to be pickled. + / + + Write a pickled representation of obj to the open file. + [clinic]*/ + +Argument Clinic will show you all the converters it has +available. For each converter it'll show you all the parameters +it accepts, along with the default value for each parameter. +Just run ``Tools/clinic/clinic.py --converters`` to see the full list. + + +Advanced converters +------------------- + +Remeber those format units you skipped for your first +time because they were advanced? Here's how to handle those too. + +The trick is, all those format units take arguments--either +conversion functions, or types, or strings specifying an encoding. +(But "legacy converters" don't support arguments. That's why we +skipped them for your first function.) The argument you specified +to the format unit is now an argument to the converter; this +argument is either ``converter`` (for ``O&``), ``type`` (for ``O!``), +or ``encoding`` (for all the format units that start with ``e``). + +Note that ``object()`` must explicitly support each Python type you specify +for the ``type`` argument. Currently it only supports ``str``. It should be +easy to add more, just edit ``Tools/clinic/clinic.py``, search for ``O!`` in +the text, and add more entries to the dict mapping types to strings just above it. + +Note also that this approach takes away some possible flexibility for the format +units starting with ``e``. It used to be possible to decide at runtime what +encoding string to pass in to ``PyArg_ParseTuple()``. But now this string must +be hard-coded at compile-time. This limitation is deliberate; it made supporting +this format unit much easier, and may allow for future compile-time optimizations. +This restriction does not seem unreasonable; CPython itself always passes in static +hard-coded strings when using format units starting with ``e``. + + +Using a return converter +------------------------ + +By default the impl function Argument Clinic generates for you returns ``PyObject *``. +But your C function often computes some C type, then converts it into the ``PyObject *`` +at the last moment. Argument Clinic handles converting your inputs from Python types +into native C types--why not have it convert your return value from a native C type +into a Python type too? + +That's what a "return converter" does. It changes your impl function to return +some C type, then adds code to the generated (non-impl) function to handle converting +that value into the appropriate ``PyObject *``. + +The syntax for return converters is similar to that of parameter converters. +You specify the return converter like it was a return annotation on the +function itself. Return converters behave much the same as parameter converters; +they take arguments, the arguments are all keyword-only, and if you're not changing +any of the default arguments you can omit the parentheses. + +(If you use both ``"as"`` *and* a return converter for your function, +the ``"as"`` should come before the return converter.) + +There's one additional complication when using return converters: how do you +indicate an error has occured? Normally, a function returns a valid (non-``NULL``) +pointer for success, and ``NULL`` for failure. But if you use an integer return converter, +all integers are valid. How can Argument Clinic detect an error? Its solution: each return +converter implicitly looks for a special value that indicates an error. If you return +that value, and an error has been set (``PyErr_Occurred()`` returns a true +value), then the generated code will propogate the error. Otherwise it will +encode the value you return like normal. + +Currently Argument Clinic supports only a few return converters:: + + int + long + Py_ssize_t + DecodeFSDefault + +None of these take parameters. For the first three, return -1 to indicate +error. For ``DecodeFSDefault``, the return type is ``char *``; return a NULL +pointer to indicate an error. + +Calling Python code +------------------- + +The rest of the advanced topics require you to write Python code +which lives inside your C file and modifies Argument Clinic at +runtime. This is simple; you simply define a Python block. + +A Python block uses different delimiter lines than an Argument +Clinic function block. It looks like this:: + + /*[python] + # python code goes here + [python]*/ + +All the code inside the Python block is executed at the +time it's parsed. All text written to stdout inside the block +is redirected into the "output" after the block. + +As an example, here's a Python block that adds a static integer +variable to the C code:: + + /*[python] + print('static int __ignored_unused_variable__ = 0;') + [python]*/ + static int __ignored_unused_variable__ = 0; + /*[python checksum:...]*/ + + +Using a "self converter" +------------------------ + +Argument Clinic automatically adds a "self" parameter for you +using a default converter. However, you can override +Argument Clinic's converter and specify one yourself. +Just add your own ``self`` parameter as the first parameter in a +block, and ensure that its converter is an instance of +``self_converter`` or a subclass thereof. + +What's the point? This lets you automatically cast ``self`` +from ``PyObject *`` to a custom type. + +How do you specify the custom type you want to cast ``self`` to? +If you only have one or two functions with the same type for ``self``, +you can directly use Argument Clinic's existing ``self`` converter, +passing in the type you want to use as the ``type`` parameter:: + + /*[clinic] + + _pickle.Pickler.dump + + self: self(type="PicklerObject *") + obj: object + / + + Write a pickled representation of the given object to the open file. + [clinic]*/ + +On the other hand, if you have a lot of functions that will use the same +type for ``self``, it's best to create your own converter, subclassing +``self_converter`` but overwriting the ``type`` member:: + + /*[clinic] + class PicklerObject_converter(self_converter): + type = "PicklerObject *" + [clinic]*/ + + /*[clinic] + + _pickle.Pickler.dump + + self: PicklerObject + obj: object + / + + Write a pickled representation of the given object to the open file. + [clinic]*/ + + + +Writing a custom converter +-------------------------- + +As we hinted at in the previous section... you can write your own converters! +A converter is simply a Python class that inherits from ``CConverter``. +The main purpose of a custom converter is if you have a parameter using +the ``O&`` format unit--parsing this parameter means calling +a ``PyArg_ParseTuple()`` "converter function". + +Your converter class should be named ``*something*_converter``. +If the name follows this convention, then your converter class +will be automatically registered with Argument Clinic; its name +will be the name of your class with the ``_converter`` suffix +stripped off. (This is done automatically for you with a metaclass.) + +You shouldn't subclass ``CConverter.__init__``. Instead, you should +write a ``converter_init()`` function. ``converter_init()`` +always accepts a ``self`` parameter; after that, all additional +parameters *must* be keyword-only. Any arguments passed in to +the converter in Argument Clinic will be passed along to your +``converter_init()``. + +There are some additional members of ``CConverter`` you may wish +to specify in your subclass. Here's the current list: + +``type`` + The C type to use for this variable. + ``type`` should be a Python string specifying the type, e.g. ``int``. + If this is a pointer type, the type string should end with ``' *'``. + +``default`` + The Python default value for this parameter, as a Python value. + Or the magic value ``unspecified`` if there is no default. + +``doc_default`` + ``default`` as it should appear in the documentation, + as a string. + Or ``None`` if there is no default. + This string, when run through ``eval()``, should produce + a Python value. + +``py_default`` + ``default`` as it should appear in Python code, + as a string. + Or ``None`` if there is no default. + +``c_default`` + ``default`` as it should appear in C code, + as a string. + Or ``None`` if there is no default. + +``c_ignored_default`` + The default value used to initialize the C variable when + there is no default, but not specifying a default may + result in an "uninitialized variable" warning. This is + easily happen when using option groups--although + properly-written code won't actually use the variable, + the variable does get passed in to the _impl, and the + C compiler will complain about the "use" of the uninitialized + value. This value should be a string. + +``converter`` + The name of the C converter function, as a string. + +``impl_by_reference`` + A boolean value. If true, + Argument Clinic will add a ``&`` in front of the name of + the variable when passing it into the impl function. + +``parse_by_reference`` + A boolean value. If true, + Argument Clinic will add a ``&`` in front of the name of + the variable when passing it into ``PyArg_ParseTuple()``. + + +Here's the simplest example of a custom converter, from ``Modules/zlibmodule.c``:: + + /*[python] + + class uint_converter(CConverter): + type = 'unsigned int' + converter = 'uint_converter' + + [python]*/ + /*[python checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + +This block adds a ``uint`` converter to Argument Clinic. Parameters +declared as ``uint`` will be declared as type ``unsigned int``, and will +be parsed by calling the ``uint_converter`` converter function in C. +``uint`` variables automatically support default values. + +More sophisticated custom converters can insert custom C code to +handle initialization and cleanup. +You can see more examples of custom converters in the CPython +source tree; grep the C files for the string ``CConverter``. + +Writing a custom return converter +--------------------------------- + +Writing a custom return converter is much like writing +a custom converter. Except it's much simpler, because return +converters are themselves much simpler. + +Return converters must subclass ``CReturnConverter``. +There are no examples yet of custom return converters, +because they are not widely used yet. If you wish to +write your own return converter, please read ``Tools/clinic/clinic.py``, +specifically the implementation of ``CReturnConverter`` and +all its subclasses. + + +Using Argument Clinic in Python files +------------------------------------- + +It's actually possible to use Argument Clinic to preprocess Python files. +There's no point to using Argument Clinic blocks, of course, as the output +wouldn't make any sense to the Python interpreter. But using Argument Clinic +to run Python blocks lets you use Python as a Python preprocessor! + +Since Python comments are different from C comments, Argument Clinic +blocks embedded in Python files look slightly different. They look like this:: + + #/*[python] + #print("def foo(): pass") + #[python]*/ + def foo(): pass + #/*[python checksum:...]*/ diff --git a/Doc/howto/index.rst b/Doc/howto/index.rst --- a/Doc/howto/index.rst +++ b/Doc/howto/index.rst @@ -28,4 +28,5 @@ webservers.rst argparse.rst ipaddress.rst + clinic.rst diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -345,6 +345,8 @@ Tools/Demos ----------- +- Issue #19659: Added documentation for Argument Clinic. + - Issue #19976: Argument Clinic METH_NOARGS functions now always take two parameters. diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -312,9 +312,6 @@ type = 'unsigned int' converter = 'uint_converter' -class compobject_converter(self_converter): - type = "compobject *" - [python]*/ /*[python checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ @@ -750,7 +747,7 @@ zlib.Decompress.decompress - self: compobject + self: self(type="compobject *") data: Py_buffer The binary data to decompress. @@ -1032,7 +1029,7 @@ /*[clinic] zlib.Compress.copy - self: compobject + self: self(type="compobject *") Return a copy of the compression object. [clinic]*/ diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1296,11 +1296,13 @@ must be keyword-only. """ + # The C type to use for this variable. + # 'type' should be a Python string specifying the type, e.g. "int". + # If this is a pointer type, the type string should end with ' *'. type = None - format_unit = 'O&' # The Python default value for this parameter, as a Python value. - # Or "unspecified" if there is no default. + # Or the magic value "unspecified" if there is no default. default = unspecified # "default" as it should appear in the documentation, as a string. @@ -1330,9 +1332,32 @@ # (If this is not None, format_unit must be 'O&'.) converter = None + # Should Argument Clinic add a '&' before the name of + # the variable when passing it into the _impl function? + impl_by_reference = False + + # Should Argument Clinic add a '&' before the name of + # the variable when passing it into PyArg_ParseTuple (AndKeywords)? + parse_by_reference = True + + ############################################################# + ############################################################# + ## You shouldn't need to read anything below this point to ## + ## write your own converter functions. ## + ############################################################# + ############################################################# + + # The "format unit" to specify for this variable when + # parsing arguments using PyArg_ParseTuple (AndKeywords). + # Custom converters should always use the default value of 'O&'. + format_unit = 'O&' + + # What encoding do we want for this variable? Only used + # by format units starting with 'e'. encoding = None - impl_by_reference = False - parse_by_reference = True + + # Do we want an adjacent '_length' variable for this variable? + # Only used by format units ending with '#'. length = False def __init__(self, name, function, default=unspecified, *, doc_default=None, required=False, annotation=unspecified, **kwargs): @@ -1751,7 +1776,7 @@ this is the default converter used for "self". """ type = "PyObject *" - def converter_init(self): + def converter_init(self, *, type=None): f = self.function if f.kind == CALLABLE: if f.cls: @@ -1766,6 +1791,9 @@ self.name = "cls" self.type = "PyTypeObject *" + if type: + self.type = type + def render(self, parameter, data): fail("render() should never be called on self_converter instances") @@ -1787,7 +1815,13 @@ class CReturnConverter(metaclass=CReturnConverterAutoRegister): + # The C type to use for this variable. + # 'type' should be a Python string specifying the type, e.g. "int". + # If this is a pointer type, the type string should end with ' *'. type = 'PyObject *' + + # The Python default value for this parameter, as a Python value. + # Or the magic value "unspecified" if there is no default. default = None def __init__(self, *, doc_default=None, **kwargs): @@ -1826,6 +1860,16 @@ add_c_return_converter(CReturnConverter, 'object') +class NoneType_return_converter(CReturnConverter): + def render(self, function, data): + self.declare(data) + data.return_conversion.append(''' +if (_return_value != Py_None) + goto exit; +return_value = Py_None; +Py_INCREF(Py_None); +'''.strip()) + class int_return_converter(CReturnConverter): type = 'int' @@ -2680,7 +2724,7 @@ # print(" ", short_name + "".join(parameters)) print() - print("All converters also accept (doc_default=None, required=False).") + print("All converters also accept (doc_default=None, required=False, annotation=None).") print("All return converters also accept (doc_default=None).") sys.exit(0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 4 21:51:12 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 4 Jan 2014 21:51:12 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Reverted_changeset_b72c557?= =?utf-8?b?M2M1ZTcgKGlzc3VlICMxNTAyNyku?= Message-ID: <3dxZrw3vC4z7LjS@mail.python.org> http://hg.python.org/cpython/rev/1e345924f7ea changeset: 88297:1e345924f7ea parent: 88295:c4ababa110a2 user: Serhiy Storchaka date: Sat Jan 04 22:44:01 2014 +0200 summary: Reverted changeset b72c5573c5e7 (issue #15027). files: Doc/whatsnew/3.4.rst | 4 +- Misc/NEWS | 2 - Objects/stringlib/codecs.h | 87 ------------------- Objects/unicodeobject.c | 110 ++++++++++++++---------- 4 files changed, 66 insertions(+), 137 deletions(-) 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 @@ -1213,9 +1213,7 @@ Significant Optimizations ========================= -* The UTF-32 decoder is now 3x to 4x faster. The UTF-32 encoder is now 1.6x - to 3.5x faster. (Contributed by Serhiy Storchaka in :issue:`14625` and - :issue:`15027`.) +* The UTF-32 decoder is now 3x to 4x faster. * The cost of hash collisions for sets is now reduced. Each hash table probe now checks a series of consecutive, adjacent key/hash pairs before diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,8 +10,6 @@ Core and Builtins ----------------- -- Issue #15027: Rewrite the UTF-32 encoder. It is now 1.6x to 3.5x faster. - - Issue #17432: Drop UCS2 from names of Unicode functions in python3.def. - Issue #19526: Exclude all new API from the stable ABI. Exceptions can be diff --git a/Objects/stringlib/codecs.h b/Objects/stringlib/codecs.h --- a/Objects/stringlib/codecs.h +++ b/Objects/stringlib/codecs.h @@ -718,93 +718,6 @@ return len - (end - in + 1); #endif } - -#if STRINGLIB_SIZEOF_CHAR == 1 -# define SWAB4(CH, tmp) ((CH) << 24) /* high bytes are zero */ -#elif STRINGLIB_SIZEOF_CHAR == 2 -# define SWAB4(CH, tmp) (tmp = (CH), \ - ((tmp & 0x00FFu) << 24) + ((tmp & 0xFF00u) << 8)) - /* high bytes are zero */ -#else -# define SWAB4(CH, tmp) (tmp = (CH), \ - tmp = ((tmp & 0x00FF00FFu) << 8) + ((tmp >> 8) & 0x00FF00FFu), \ - ((tmp & 0x0000FFFFu) << 16) + ((tmp >> 16) & 0x0000FFFFu)) -#endif -Py_LOCAL_INLINE(Py_ssize_t) -STRINGLIB(utf32_encode)(const STRINGLIB_CHAR *in, - Py_ssize_t len, - PY_UINT32_T **outptr, - int native_ordering) -{ - PY_UINT32_T *out = *outptr; - const STRINGLIB_CHAR *end = in + len; - if (native_ordering) { - const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4); - while (in < unrolled_end) { -#if STRINGLIB_SIZEOF_CHAR > 1 - /* check if any character is a surrogate character */ - if (((in[0] ^ 0xd800) & - (in[1] ^ 0xd800) & - (in[2] ^ 0xd800) & - (in[3] ^ 0xd800) & 0xf800) == 0) - break; -#endif - out[0] = in[0]; - out[1] = in[1]; - out[2] = in[2]; - out[3] = in[3]; - in += 4; out += 4; - } - while (in < end) { - Py_UCS4 ch; - ch = *in++; -#if STRINGLIB_SIZEOF_CHAR > 1 - if (Py_UNICODE_IS_SURROGATE(ch)) { - /* reject surrogate characters (U+DC800-U+DFFF) */ - goto fail; - } -#endif - *out++ = ch; - } - } else { - const STRINGLIB_CHAR *unrolled_end = in + _Py_SIZE_ROUND_DOWN(len, 4); - while (in < unrolled_end) { -#if STRINGLIB_SIZEOF_CHAR > 1 - Py_UCS4 ch1, ch2, ch3, ch4; - /* check if any character is a surrogate character */ - if (((in[0] ^ 0xd800) & - (in[1] ^ 0xd800) & - (in[2] ^ 0xd800) & - (in[3] ^ 0xd800) & 0xf800) == 0) - break; -#endif - out[0] = SWAB4(in[0], ch1); - out[1] = SWAB4(in[1], ch2); - out[2] = SWAB4(in[2], ch3); - out[3] = SWAB4(in[3], ch4); - in += 4; out += 4; - } - while (in < end) { - Py_UCS4 ch = *in++; -#if STRINGLIB_SIZEOF_CHAR > 1 - if (Py_UNICODE_IS_SURROGATE(ch)) { - /* reject surrogate characters (U+DC800-U+DFFF) */ - goto fail; - } -#endif - *out++ = SWAB4(ch, ch); - } - } - *outptr = out; - return len; -#if STRINGLIB_SIZEOF_CHAR > 1 - fail: - *outptr = out; - return len - (end - in + 1); -#endif -} -#undef SWAB4 - #endif #endif /* STRINGLIB_IS_UNICODE */ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -5085,22 +5085,32 @@ const char *errors, int byteorder) { - enum PyUnicode_Kind kind; - const void *data; + int kind; + void *data; Py_ssize_t len; PyObject *v; - PY_UINT32_T *out; + unsigned char *p; + Py_ssize_t nsize, i; + /* Offsets from p for storing byte pairs in the right order. */ #if PY_LITTLE_ENDIAN - int native_ordering = byteorder <= 0; + int iorder[] = {0, 1, 2, 3}; #else - int native_ordering = byteorder >= 0; + int iorder[] = {3, 2, 1, 0}; #endif const char *encoding; - Py_ssize_t nsize, pos; PyObject *errorHandler = NULL; PyObject *exc = NULL; PyObject *rep = NULL; +#define STORECHAR(CH) \ + do { \ + p[iorder[3]] = ((CH) >> 24) & 0xff; \ + p[iorder[2]] = ((CH) >> 16) & 0xff; \ + p[iorder[1]] = ((CH) >> 8) & 0xff; \ + p[iorder[0]] = (CH) & 0xff; \ + p += 4; \ + } while(0) + if (!PyUnicode_Check(str)) { PyErr_BadArgument(); return NULL; @@ -5111,53 +5121,59 @@ data = PyUnicode_DATA(str); len = PyUnicode_GET_LENGTH(str); - if (len > PY_SSIZE_T_MAX / 4 - (byteorder == 0)) + nsize = len + (byteorder == 0); + if (nsize > PY_SSIZE_T_MAX / 4) return PyErr_NoMemory(); - nsize = len + (byteorder == 0); v = PyBytes_FromStringAndSize(NULL, nsize * 4); if (v == NULL) return NULL; - /* output buffer is 4-bytes aligned */ - assert(_Py_IS_ALIGNED(PyBytes_AS_STRING(v), 4)); - out = (PY_UINT32_T *)PyBytes_AS_STRING(v); + p = (unsigned char *)PyBytes_AS_STRING(v); if (byteorder == 0) - *out++ = 0xFEFF; + STORECHAR(0xFEFF); if (len == 0) - goto done; - - if (byteorder == -1) + return v; + + if (byteorder == -1) { + /* force LE */ + iorder[0] = 0; + iorder[1] = 1; + iorder[2] = 2; + iorder[3] = 3; encoding = "utf-32-le"; - else if (byteorder == 1) + } + else if (byteorder == 1) { + /* force BE */ + iorder[0] = 3; + iorder[1] = 2; + iorder[2] = 1; + iorder[3] = 0; encoding = "utf-32-be"; + } else encoding = "utf-32"; if (kind == PyUnicode_1BYTE_KIND) { - ucs1lib_utf32_encode((const Py_UCS1 *)data, len, &out, native_ordering); - goto done; - } - - pos = 0; - while (pos < len) { + for (i = 0; i < len; i++) + STORECHAR(PyUnicode_READ(kind, data, i)); + return v; + } + + for (i = 0; i < len;) { Py_ssize_t repsize, moreunits; - - if (kind == PyUnicode_2BYTE_KIND) { - pos += ucs2lib_utf32_encode((const Py_UCS2 *)data + pos, len - pos, - &out, native_ordering); - } - else { - assert(kind == PyUnicode_4BYTE_KIND); - pos += ucs4lib_utf32_encode((const Py_UCS4 *)data + pos, len - pos, - &out, native_ordering); - } - if (pos == len) - break; + Py_UCS4 ch = PyUnicode_READ(kind, data, i); + i++; + assert(ch <= MAX_UNICODE); + if (!Py_UNICODE_IS_SURROGATE(ch)) { + STORECHAR(ch); + continue; + } rep = unicode_encode_call_errorhandler( errors, &errorHandler, encoding, "surrogates not allowed", - str, &exc, pos, pos + 1, &pos); + str, &exc, i-1, i, &i); + if (!rep) goto error; @@ -5165,7 +5181,7 @@ repsize = PyBytes_GET_SIZE(rep); if (repsize & 3) { raise_encode_exception(&exc, encoding, - str, pos - 1, pos, + str, i - 1, i, "surrogates not allowed"); goto error; } @@ -5178,7 +5194,7 @@ moreunits = repsize = PyUnicode_GET_LENGTH(rep); if (!PyUnicode_IS_ASCII(rep)) { raise_encode_exception(&exc, encoding, - str, pos - 1, pos, + str, i - 1, i, "surrogates not allowed"); goto error; } @@ -5186,7 +5202,7 @@ /* four bytes are reserved for each surrogate */ if (moreunits > 1) { - Py_ssize_t outpos = out - (PY_UINT32_T*) PyBytes_AS_STRING(v); + Py_ssize_t outpos = p - (unsigned char*) PyBytes_AS_STRING(v); Py_ssize_t morebytes = 4 * (moreunits - 1); if (PyBytes_GET_SIZE(v) > PY_SSIZE_T_MAX - morebytes) { /* integer overflow */ @@ -5195,16 +5211,20 @@ } if (_PyBytes_Resize(&v, PyBytes_GET_SIZE(v) + morebytes) < 0) goto error; - out = (PY_UINT32_T*) PyBytes_AS_STRING(v) + outpos; + p = (unsigned char*) PyBytes_AS_STRING(v) + outpos; } if (PyBytes_Check(rep)) { - Py_MEMCPY(out, PyBytes_AS_STRING(rep), repsize); - out += moreunits; + Py_MEMCPY(p, PyBytes_AS_STRING(rep), repsize); + p += repsize; } else /* rep is unicode */ { + const Py_UCS1 *repdata; assert(PyUnicode_KIND(rep) == PyUnicode_1BYTE_KIND); - ucs1lib_utf32_encode(PyUnicode_1BYTE_DATA(rep), repsize, - &out, native_ordering); + repdata = PyUnicode_1BYTE_DATA(rep); + while (repsize--) { + Py_UCS4 ch = *repdata++; + STORECHAR(ch); + } } Py_CLEAR(rep); @@ -5213,12 +5233,11 @@ /* Cut back to size actually needed. This is necessary for, for example, encoding of a string containing isolated surrogates and the 'ignore' handler is used. */ - nsize = (unsigned char*) out - (unsigned char*) PyBytes_AS_STRING(v); + nsize = p - (unsigned char*) PyBytes_AS_STRING(v); if (nsize != PyBytes_GET_SIZE(v)) _PyBytes_Resize(&v, nsize); Py_XDECREF(errorHandler); Py_XDECREF(exc); - done: return v; error: Py_XDECREF(rep); @@ -5226,6 +5245,7 @@ Py_XDECREF(exc); Py_XDECREF(v); return NULL; +#undef STORECHAR } PyObject * -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 4 21:51:14 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 4 Jan 2014 21:51:14 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_heads?= Message-ID: <3dxZry1Y1wz7LmR@mail.python.org> http://hg.python.org/cpython/rev/0a306e5ce5aa changeset: 88298:0a306e5ce5aa parent: 88297:1e345924f7ea parent: 88296:e2280bf5c263 user: Serhiy Storchaka date: Sat Jan 04 22:49:40 2014 +0200 summary: Merge heads files: Doc/howto/clinic.rst | 900 +++++++++++++++++++++++++++++ Doc/howto/index.rst | 1 + Misc/NEWS | 2 + Modules/zlibmodule.c | 7 +- Tools/clinic/clinic.py | 56 +- 5 files changed, 955 insertions(+), 11 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst new file mode 100644 --- /dev/null +++ b/Doc/howto/clinic.rst @@ -0,0 +1,900 @@ +====================== +Argument Clinic How-To +====================== + +:author: Larry Hastings + + +.. topic:: Abstract + + Argument Clinic is a preprocessor for CPython C files. + Its purpose is to automate all the boilerplate involved + with writing argument parsing code for "builtins". + This document shows you how to convert your first C + function to work with Argument Clinic, and then introduces + some advanced topics on Argument Clinic usage. + + Argument Clinic is currently considered an internal + tool for the CPython code tree. Its use is not supported + for files outside the CPython code tree, and no guarantees + are made regarding backwards compatibility for future + versions. In other words: if you maintain an external C + extension for CPython, you're welcome to experiment with + Argument Clinic in your own code. But the version of Argument + Clinic that ships with CPython 3.5 *could* be totally + incompatible and break all your code. + +======================== +Basic Concepts And Usage +======================== + +Argument Clinic ships with CPython. You can find it in ``Tools/clinic/clinic.py``. +If you run that script, specifying a C file as an argument:: + + % python3 Tools/clinic/clinic.py foo.c + +Argument Clinic will scan over the file looking for lines that +look exactly like this:: + + /*[clinic] + +When it finds one, it reads everything up to a line that looks +like this:: + + [clinic]*/ + +Everything in between these two lines is input for Argument Clinic. +All of these lines, including the beginning and ending comment +lines, are collectively called an Argument Clinic "input block", +or "block" for short. + +When Argument Clinic parses one of these blocks, it +generates output. This output is rewritten into the C file +immediately after the block, followed by a comment containing a checksum. +The resulting Argument Clinic block looks like this:: + + /*[clinic] + ... clinic input goes here ... + [clinic]*/ + ... clinic output goes here ... + /*[clinic checksum:...]*/ + +If you run Argument Clinic on the same file a second time, Argument Clinic +will discard the old output and write out the new output with a fresh checksum +line. However, if the input hasn't changed, the output won't change either. + +You should never modify the output portion of an Argument Clinic block. Instead, +change the input until it produces the output you want. (That's the purpose of the +checksum--to detect and warn you in case someone accidentally modifies the output.) + +For the sake of clarity, here's the terminology we'll use with Argument Clinic: + +* The first line of the comment (``/*[clinic]``) is the *start line*. +* The last line of the initial comment (``[clinic]*/``) is the *end line*. +* The last line (``/*[clinic checksum:...]*/``) is the *checksum line*. +* In between the start line and the end line is the *input*. +* In between the end line and the checksum line is the *output*. +* All the text collectively, from the start line to the checksum line inclusively, + is the *block*. (A block that hasn't been successfully processed by Argument + Clinic yet doesn't have output or a checksum line, but it's still considered + a block.) + + +============================== +Converting Your First Function +============================== + +The best way to get a sense of how Argument Clinic works is to +convert a function to work with it. Let's dive in! + +0. Make sure you're working with a freshly updated trunk. + +1. Find a Python builtin that calls either ``PyArg_ParseTuple()`` + or ``PyArg_ParseTupleAndKeywords()``, and hasn't been converted yet. + For my example I'm using ``pickle.Pickler.dump()``. + +2. If the call to the ``PyArg_Parse`` function uses any of the + following format units:: + + O& + O! + es + es# + et + et# + + or if it has multiple calls to ``PyArg_ParseTuple()``, + you should choose a different function. Argument Clinic *does* + support all of these scenarios. But these are advanced + topics--let's do something simpler for your first function. + +3. Add the following boilerplate above the function, creating our block:: + + /*[clinic] + [clinic]*/ + +4. Cut the docstring and paste it in between the ``[clinic]`` lines, + removing all the junk that makes it a properly quoted C string. + When you're done you should have just the text, based at the left + margin, with no line wider than 80 characters. + (Argument Clinic will preserve indents inside the docstring.) + + Sample:: + + /*[clinic] + Write a pickled representation of obj to the open file. + [clinic]*/ + +5. If your docstring doesn't have a "summary" line, Argument Clinic will + complain. So let's make sure it has one. The "summary" line should + be a paragraph consisting of a single 80-column line + at the beginning of the docstring. + + (Our docstring consists solely of the summary line, so the sample + code doesn't have to change for this step.) + +6. Above the docstring, enter the name of the function, followed + by a blank line. This should be the Python name of the function, + and should be the full dotted path + to the function--it should start with the name of the module, + include any sub-modules, and if the function is a method on + a class it should include the class name too. + + Sample:: + + /*[clinic] + pickle.Pickler.dump + + Write a pickled representation of obj to the open file. + [clinic]*/ + +7. If this is the first time that module or class has been used with Argument + Clinic in this C file, + you must declare the module and/or class. Proper Argument Clinic hygiene + prefers declaring these in a separate block somewhere near the + top of the C file, in the same way that include files and statics go at + the top. (In our sample code we'll just show the two blocks next to + each other.) + + Sample:: + + /*[clinic] + module pickle + class pickle.Pickler + [clinic]*/ + + /*[clinic] + pickle.Pickler.dump + + Write a pickled representation of obj to the open file. + [clinic]*/ + + +8. Declare each of the parameters to the function. Each parameter + should get its own line. All the parameter lines should be + indented from the function name and the docstring. + + The general form of these parameter lines is as follows:: + + name_of_parameter: converter + + If the parameter has a default value, add that after the + converter:: + + name_of_parameter: converter = default_value + + Add a blank line below the parameters. + + What's a "converter"? It establishes both the type + of the variable used in C, and the method to convert the Python + value into a C value at runtime. + For now you're going to use what's called a "legacy converter"--a + convenience syntax intended to make porting old code into Argument + Clinic easier. + + For each parameter, copy the "format unit" for that + parameter from the ``PyArg_Parse()`` format argument and + specify *that* as its converter, as a quoted + string. ("format unit" is the formal name for the one-to-three + character substring of the ``format`` parameter that tells + the argument parsing function what the type of the variable + is and how to convert it.) + + For multicharacter format units like ``z#``, use the + entire two-or-three character string. + + Sample:: + + /*[clinic] + module pickle + class pickle.Pickler + [clinic]*/ + + /*[clinic] + pickle.Pickler.dump + + obj: 'O' + + Write a pickled representation of obj to the open file. + [clinic]*/ + +9. If your function has ``|`` in the format string, meaning some + parameters have default values, you can ignore it. Argument + Clinic infers which parameters are optional based on whether + or not they have default values. + + If your function has ``$`` in the format string, meaning it + takes keyword-only arguments, specify ``*`` on a line by + itself before the first keyword-only argument, indented the + same as the parameter lines. + + (``pickle.Pickler.dump`` has neither, so our sample is unchanged.) + + +10. If the existing C function uses ``PyArg_ParseTuple()`` + (instead of ``PyArg_ParseTupleAndKeywords()``), then all its + arguments are positional-only. + + To mark all parameters as positional-only in Argument Clinic, + add a ``/`` on a line by itself after the last parameter, + indented the same as the parameter lines. + + Sample:: + + /*[clinic] + module pickle + class pickle.Pickler + [clinic]*/ + + /*[clinic] + pickle.Pickler.dump + + obj: 'O' + / + + Write a pickled representation of obj to the open file. + [clinic]*/ + +11. It's helpful to write a per-parameter docstring, indented + another level past the parameter declaration. But per-parameter + docstrings are optional; you can skip this step if you prefer. + + Here's how per-parameter docstrings work. The first line + of the per-parameter docstring must be indented further than the + parameter definition. This left margin establishes the left margin + for the whole per-parameter docstring; all the text you write will + be outdented by this amount. You can write as much as you like, + across multiple lines if you wish. + + Sample:: + + /*[clinic] + module pickle + class pickle.Pickler + [clinic]*/ + + /*[clinic] + pickle.Pickler.dump + + obj: 'O' + The object to be pickled. + / + + Write a pickled representation of obj to the open file. + [clinic]*/ + +12. Save and close the file, then run ``Tools/clinic/clinic.py`` on it. + With luck everything worked and your block now has output! Reopen + the file in your text editor to see:: + + /*[clinic] + module pickle + class pickle.Pickler + [clinic]*/ + /*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + + /*[clinic] + pickle.Pickler.dump + + obj: 'O' + The object to be pickled. + / + + Write a pickled representation of obj to the open file. + [clinic]*/ + + PyDoc_STRVAR(pickle_Pickler_dump__doc__, + "Write a pickled representation of obj to the open file.\n" + "\n" + ... + static PyObject * + pickle_Pickler_dump_impl(PyObject *self, PyObject *obj) + /*[clinic checksum: 3bd30745bf206a48f8b576a1da3d90f55a0a4187]*/ + +13. Double-check that the argument-parsing code Argument Clinic generated + looks basically the same as the existing code. + + First, ensure both places use the same argument-parsing function. + The existing code must call either + ``PyArg_ParseTuple()`` or ``PyArg_ParseTupleAndKeywords()``; + ensure that the code generated by Argument Clinic calls the + same function. + + Second, the format string passed in to ``PyArg_ParseTuple()`` or + ``PyArg_ParseTupleAndKeywords()`` should be *exactly* the same + as the hand-written one in the existing function. + + Well, there's one way that Argument Clinic's output is permitted + to be different. Argument Clinic always generates a format string + ending with ``:`` followed by the name of the function. If the + format string originally ended with ``;`` (to specify usage help), + this is harmless--don't worry about this difference. + + Apart from that, if either of these things differ in *any way*, + fix your input to Argument Clinic and rerun ``Tools/clinic/clinic.py`` + until they are the same. + + +14. Notice that the last line of its output is the declaration + of your "impl" function. This is where the builtin's implementation goes. + Delete the existing prototype of the function you're modifying, but leave + the opening curly brace. Now delete its argument parsing code and the + declarations of all the variables it dumps the arguments into. + Notice how the Python arguments are now arguments to this impl function; + if the implementation used different names for these variables, fix it. + The result should be a function that handles just the implementation + of the Python function without any argument-parsing code. + + Sample:: + + /*[clinic] + module pickle + class pickle.Pickler + [clinic]*/ + /*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + + /*[clinic] + pickle.Pickler.dump + + obj: 'O' + The object to be pickled. + / + + Write a pickled representation of obj to the open file. + [clinic]*/ + + PyDoc_STRVAR(pickle_Pickler_dump__doc__, + "Write a pickled representation of obj to the open file.\n" + "\n" + ... + static PyObject * + pickle_Pickler_dump_impl(PyObject *self, PyObject *obj) + /*[clinic checksum: 3bd30745bf206a48f8b576a1da3d90f55a0a4187]*/ + { + /* Check whether the Pickler was initialized correctly (issue3664). + Developers often forget to call __init__() in their subclasses, which + would trigger a segfault without this check. */ + if (self->write == NULL) { + PyErr_Format(PicklingError, + "Pickler.__init__() was not called by %s.__init__()", + Py_TYPE(self)->tp_name); + return NULL; + } + + if (_Pickler_ClearBuffer(self) < 0) + return NULL; + + ... + +15. Compile and run the relevant portions of the regression-test suite. + This change should not introduce any new compile-time warnings or errors, + and there should be no externally-visible change to Python's behavior. + + Well, except for one difference: ``inspect.signature()`` run on your function + should now provide a valid signature! + + Congratulations, you've ported your first function to work with Argument Clinic! + +=============== +Advanced Topics +=============== + + +Renaming the C functions generated by Argument Clinic +----------------------------------------------------- + +Argument Clinic automatically names the functions it generates for you. +Occasionally this may cause a problem, if the generated name collides with +the name of an existing C function. There's an easy solution: you can explicitly +specify the base name to use for the C functions. Just add the keyword ``"as"`` +to your function declaration line, followed by the function name you wish to use. +Argument Clinic will use the function name you use for the base (generated) function, +and then add ``"_impl"`` to the end for the name of the impl function. + +For example, if we wanted to rename the C function names generated for +``pickle.Pickler.dump``, it'd look like this:: + + /*[clinic] + pickle.Pickler.dump as pickler_dumper + + ... + +The base function would now be named ``pickler_dumper()``, +and the impl function would be named ``pickler_dumper_impl()``. + + +Optional Groups +--------------- + +Some legacy functions have a tricky approach to parsing their arguments: +they count the number of positional arguments, then use a ``switch`` statement +to call one of several different ``PyArg_ParseTuple()`` calls depending on +how many positional arguments there are. (These functions cannot accept +keyword-only arguments.) This approach was used to simulate optional +arguments back before ``PyArg_ParseTupleAndKeywords()`` was created. + +Functions using this approach can often be converted to +use ``PyArg_ParseTupleAndKeywords()``, optional arguments, and default values. +But it's not always possible, because some of these legacy functions have +behaviors ``PyArg_ParseTupleAndKeywords()`` can't directly support. +The most obvious example is the builtin function ``range()``, which has +an optional argument on the *left* side of its required argument! +Another example is ``curses.window.addch()``, which has a group of two +arguments that must always be specified together. (The arguments are +called ``x`` and ``y``; if you call the function passing in ``x``, +you must also pass in ``y``--and if you don't pass in ``x`` you may not +pass in ``y`` either.) + +For the sake of backwards compatibility, Argument Clinic supports this +alternate approach to parsing, using what are called *optional groups*. +Optional groups are groups of arguments that can only be specified together. +They can be to the left or the right of the required arguments. They +can *only* be used with positional-only parameters. + +To specify an optional group, add a ``[`` on a line by itself before +the parameters you wish to be +in a group together, and a ``]`` on a line by itself after the +parameters. As an example, here's how ``curses.window.addch`` +uses optional groups to make the first two parameters and the last +parameter optional:: + + /*[clinic] + + curses.window.addch + + [ + x: int + X-coordinate. + y: int + Y-coordinate. + ] + + ch: object + Character to add. + + [ + attr: long + Attributes for the character. + ] + / + + ... + + +Notes: + +* For every optional group, one additional parameter will be passed into the + impl function representing the group. The parameter will be an int, and it will + be named ``group_{direction}_{number}``, + where ``{direction}`` is either ``right`` or ``left`` depending on whether the group + is before or after the required parameters, and ``{number}`` is a monotonically + increasing number (starting at 1) indicating how far away the group is from + the required parameters. When the impl is called, this parameter will be set + to zero if this group was unused, and set to non-zero if this group was used. + (By used or unused, I mean whether or not the parameters received arguments + in this invocation.) + +* If there are no required arguments, the optional groups will behave + as if they are to the right of the required arguments. + +* In the case of ambiguity, the argument parsing code + favors parameters on the left (before the required parameters). + +* Optional groups are *only* intended for legacy code. Please do not + use optional groups for new code. + + +Using real Argument Clinic converters, instead of "legacy converters" +--------------------------------------------------------------------- + +To save time, and to minimize how much you need to learn +to achieve your first port to Argument Clinic, the walkthrough above tells +you to use the "legacy converters". "Legacy converters" are a convenience, +designed explicitly to make porting existing code to Argument Clinic +easier. And to be clear, their use is entirely acceptable when porting +code for Python 3.4. + +However, in the long term we probably want all our blocks to +use Argument Clinic's real syntax for converters. Why? A couple +reasons: + +* The proper converters are far easier to read and clearer in their intent. +* There are some format units that are unsupported as "legacy converters", + because they require arguments, and the legacy converter syntax doesn't + support specifying arguments. +* In the future we may have a new argument parsing library that isn't + restricted to what ``PyArg_ParseTuple()`` supports. + +So if you want +to go that extra effort, you should consider using normal +converters instead of the legacy converters. + +In a nutshell, the syntax for Argument Clinic (non-legacy) converters +looks like a Python function call. However, if there are no explicit +arguments to the function (all functions take their default values), +you may omit the parentheses. Thus ``bool`` and ``bool()`` are exactly +the same. All parameters to Argument Clinic converters are keyword-only. + +All Argument Clinic converters accept the following arguments: + +``doc_default`` + If the parameter takes a default value, normally this value is also + provided in the ``inspect.Signature`` metadata, and displayed in the + docstring. ``doc_default`` lets you override the value used in these + two places: pass in a string representing the Python value you wish + to use in these two contexts. + +``required`` + If a parameter takes a default value, Argument Clinic infers that the + parameter is optional. However, you may want a parameter to take a + default value in C, but not behave in Python as if the parameter is + optional. Passing in ``required=True`` to a converter tells Argument + Clinic that this parameter is not optional, even if it has a default + value. + +``annotation`` + The annotation value for this parameter. Not currently supported, + because PEP 8 mandates that the Python library may not use + annotations. + +Below is a table showing the mapping of legacy converters into real +Argument Clinic converters. On the left is the legacy converter, +on the right is the text you'd replace it with. + +========= ================================================================================= +``'B'`` ``byte(bitwise=True)`` +``'b'`` ``byte`` +``'c'`` ``char`` +``'C'`` ``int(types='str')`` +``'d'`` ``double`` +``'D'`` ``Py_complex`` +``'es#'`` ``str(encoding='name_of_encoding', length=True, zeroes=True)`` +``'es'`` ``str(encoding='name_of_encoding')`` +``'et#'`` ``str(encoding='name_of_encoding', types='bytes bytearray str', length=True)`` +``'et'`` ``str(encoding='name_of_encoding', types='bytes bytearray str')`` +``'f'`` ``float`` +``'h'`` ``short`` +``'H'`` ``unsigned_short`` +``'i'`` ``int`` +``'I'`` ``unsigned_int`` +``'K'`` ``unsigned_PY_LONG_LONG`` +``'L'`` ``PY_LONG_LONG`` +``'n'`` ``Py_ssize_t`` +``'O!'`` ``object(type='name_of_Python_type')`` +``'O&'`` ``object(converter='name_of_c_function')`` +``'O'`` ``object`` +``'p'`` ``bool`` +``'s#'`` ``str(length=True)`` +``'S'`` ``PyBytesObject`` +``'s'`` ``str`` +``'s*'`` ``Py_buffer(types='str bytes bytearray buffer')`` +``'u#'`` ``Py_UNICODE(length=True)`` +``'u'`` ``Py_UNICODE`` +``'U'`` ``unicode`` +``'w*'`` ``Py_buffer(types='bytearray rwbuffer')`` +``'y#'`` ``str(type='bytes', length=True)`` +``'Y'`` ``PyByteArrayObject`` +``'y'`` ``str(type='bytes')`` +``'y*'`` ``Py_buffer`` +``'Z#'`` ``Py_UNICODE(nullable=True, length=True)`` +``'z#'`` ``str(nullable=True, length=True)`` +``'Z'`` ``Py_UNICODE(nullable=True)`` +``'z'`` ``str(nullable=True)`` +``'z*'`` ``Py_buffer(types='str bytes bytearray buffer', nullable=True)`` +========= ================================================================================= + +As an example, here's our sample ``pickle.Pickler.dump`` using the proper +converter:: + + /*[clinic] + pickle.Pickler.dump + + obj: object + The object to be pickled. + / + + Write a pickled representation of obj to the open file. + [clinic]*/ + +Argument Clinic will show you all the converters it has +available. For each converter it'll show you all the parameters +it accepts, along with the default value for each parameter. +Just run ``Tools/clinic/clinic.py --converters`` to see the full list. + + +Advanced converters +------------------- + +Remeber those format units you skipped for your first +time because they were advanced? Here's how to handle those too. + +The trick is, all those format units take arguments--either +conversion functions, or types, or strings specifying an encoding. +(But "legacy converters" don't support arguments. That's why we +skipped them for your first function.) The argument you specified +to the format unit is now an argument to the converter; this +argument is either ``converter`` (for ``O&``), ``type`` (for ``O!``), +or ``encoding`` (for all the format units that start with ``e``). + +Note that ``object()`` must explicitly support each Python type you specify +for the ``type`` argument. Currently it only supports ``str``. It should be +easy to add more, just edit ``Tools/clinic/clinic.py``, search for ``O!`` in +the text, and add more entries to the dict mapping types to strings just above it. + +Note also that this approach takes away some possible flexibility for the format +units starting with ``e``. It used to be possible to decide at runtime what +encoding string to pass in to ``PyArg_ParseTuple()``. But now this string must +be hard-coded at compile-time. This limitation is deliberate; it made supporting +this format unit much easier, and may allow for future compile-time optimizations. +This restriction does not seem unreasonable; CPython itself always passes in static +hard-coded strings when using format units starting with ``e``. + + +Using a return converter +------------------------ + +By default the impl function Argument Clinic generates for you returns ``PyObject *``. +But your C function often computes some C type, then converts it into the ``PyObject *`` +at the last moment. Argument Clinic handles converting your inputs from Python types +into native C types--why not have it convert your return value from a native C type +into a Python type too? + +That's what a "return converter" does. It changes your impl function to return +some C type, then adds code to the generated (non-impl) function to handle converting +that value into the appropriate ``PyObject *``. + +The syntax for return converters is similar to that of parameter converters. +You specify the return converter like it was a return annotation on the +function itself. Return converters behave much the same as parameter converters; +they take arguments, the arguments are all keyword-only, and if you're not changing +any of the default arguments you can omit the parentheses. + +(If you use both ``"as"`` *and* a return converter for your function, +the ``"as"`` should come before the return converter.) + +There's one additional complication when using return converters: how do you +indicate an error has occured? Normally, a function returns a valid (non-``NULL``) +pointer for success, and ``NULL`` for failure. But if you use an integer return converter, +all integers are valid. How can Argument Clinic detect an error? Its solution: each return +converter implicitly looks for a special value that indicates an error. If you return +that value, and an error has been set (``PyErr_Occurred()`` returns a true +value), then the generated code will propogate the error. Otherwise it will +encode the value you return like normal. + +Currently Argument Clinic supports only a few return converters:: + + int + long + Py_ssize_t + DecodeFSDefault + +None of these take parameters. For the first three, return -1 to indicate +error. For ``DecodeFSDefault``, the return type is ``char *``; return a NULL +pointer to indicate an error. + +Calling Python code +------------------- + +The rest of the advanced topics require you to write Python code +which lives inside your C file and modifies Argument Clinic at +runtime. This is simple; you simply define a Python block. + +A Python block uses different delimiter lines than an Argument +Clinic function block. It looks like this:: + + /*[python] + # python code goes here + [python]*/ + +All the code inside the Python block is executed at the +time it's parsed. All text written to stdout inside the block +is redirected into the "output" after the block. + +As an example, here's a Python block that adds a static integer +variable to the C code:: + + /*[python] + print('static int __ignored_unused_variable__ = 0;') + [python]*/ + static int __ignored_unused_variable__ = 0; + /*[python checksum:...]*/ + + +Using a "self converter" +------------------------ + +Argument Clinic automatically adds a "self" parameter for you +using a default converter. However, you can override +Argument Clinic's converter and specify one yourself. +Just add your own ``self`` parameter as the first parameter in a +block, and ensure that its converter is an instance of +``self_converter`` or a subclass thereof. + +What's the point? This lets you automatically cast ``self`` +from ``PyObject *`` to a custom type. + +How do you specify the custom type you want to cast ``self`` to? +If you only have one or two functions with the same type for ``self``, +you can directly use Argument Clinic's existing ``self`` converter, +passing in the type you want to use as the ``type`` parameter:: + + /*[clinic] + + _pickle.Pickler.dump + + self: self(type="PicklerObject *") + obj: object + / + + Write a pickled representation of the given object to the open file. + [clinic]*/ + +On the other hand, if you have a lot of functions that will use the same +type for ``self``, it's best to create your own converter, subclassing +``self_converter`` but overwriting the ``type`` member:: + + /*[clinic] + class PicklerObject_converter(self_converter): + type = "PicklerObject *" + [clinic]*/ + + /*[clinic] + + _pickle.Pickler.dump + + self: PicklerObject + obj: object + / + + Write a pickled representation of the given object to the open file. + [clinic]*/ + + + +Writing a custom converter +-------------------------- + +As we hinted at in the previous section... you can write your own converters! +A converter is simply a Python class that inherits from ``CConverter``. +The main purpose of a custom converter is if you have a parameter using +the ``O&`` format unit--parsing this parameter means calling +a ``PyArg_ParseTuple()`` "converter function". + +Your converter class should be named ``*something*_converter``. +If the name follows this convention, then your converter class +will be automatically registered with Argument Clinic; its name +will be the name of your class with the ``_converter`` suffix +stripped off. (This is done automatically for you with a metaclass.) + +You shouldn't subclass ``CConverter.__init__``. Instead, you should +write a ``converter_init()`` function. ``converter_init()`` +always accepts a ``self`` parameter; after that, all additional +parameters *must* be keyword-only. Any arguments passed in to +the converter in Argument Clinic will be passed along to your +``converter_init()``. + +There are some additional members of ``CConverter`` you may wish +to specify in your subclass. Here's the current list: + +``type`` + The C type to use for this variable. + ``type`` should be a Python string specifying the type, e.g. ``int``. + If this is a pointer type, the type string should end with ``' *'``. + +``default`` + The Python default value for this parameter, as a Python value. + Or the magic value ``unspecified`` if there is no default. + +``doc_default`` + ``default`` as it should appear in the documentation, + as a string. + Or ``None`` if there is no default. + This string, when run through ``eval()``, should produce + a Python value. + +``py_default`` + ``default`` as it should appear in Python code, + as a string. + Or ``None`` if there is no default. + +``c_default`` + ``default`` as it should appear in C code, + as a string. + Or ``None`` if there is no default. + +``c_ignored_default`` + The default value used to initialize the C variable when + there is no default, but not specifying a default may + result in an "uninitialized variable" warning. This is + easily happen when using option groups--although + properly-written code won't actually use the variable, + the variable does get passed in to the _impl, and the + C compiler will complain about the "use" of the uninitialized + value. This value should be a string. + +``converter`` + The name of the C converter function, as a string. + +``impl_by_reference`` + A boolean value. If true, + Argument Clinic will add a ``&`` in front of the name of + the variable when passing it into the impl function. + +``parse_by_reference`` + A boolean value. If true, + Argument Clinic will add a ``&`` in front of the name of + the variable when passing it into ``PyArg_ParseTuple()``. + + +Here's the simplest example of a custom converter, from ``Modules/zlibmodule.c``:: + + /*[python] + + class uint_converter(CConverter): + type = 'unsigned int' + converter = 'uint_converter' + + [python]*/ + /*[python checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + +This block adds a ``uint`` converter to Argument Clinic. Parameters +declared as ``uint`` will be declared as type ``unsigned int``, and will +be parsed by calling the ``uint_converter`` converter function in C. +``uint`` variables automatically support default values. + +More sophisticated custom converters can insert custom C code to +handle initialization and cleanup. +You can see more examples of custom converters in the CPython +source tree; grep the C files for the string ``CConverter``. + +Writing a custom return converter +--------------------------------- + +Writing a custom return converter is much like writing +a custom converter. Except it's much simpler, because return +converters are themselves much simpler. + +Return converters must subclass ``CReturnConverter``. +There are no examples yet of custom return converters, +because they are not widely used yet. If you wish to +write your own return converter, please read ``Tools/clinic/clinic.py``, +specifically the implementation of ``CReturnConverter`` and +all its subclasses. + + +Using Argument Clinic in Python files +------------------------------------- + +It's actually possible to use Argument Clinic to preprocess Python files. +There's no point to using Argument Clinic blocks, of course, as the output +wouldn't make any sense to the Python interpreter. But using Argument Clinic +to run Python blocks lets you use Python as a Python preprocessor! + +Since Python comments are different from C comments, Argument Clinic +blocks embedded in Python files look slightly different. They look like this:: + + #/*[python] + #print("def foo(): pass") + #[python]*/ + def foo(): pass + #/*[python checksum:...]*/ diff --git a/Doc/howto/index.rst b/Doc/howto/index.rst --- a/Doc/howto/index.rst +++ b/Doc/howto/index.rst @@ -28,4 +28,5 @@ webservers.rst argparse.rst ipaddress.rst + clinic.rst diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -343,6 +343,8 @@ Tools/Demos ----------- +- Issue #19659: Added documentation for Argument Clinic. + - Issue #19976: Argument Clinic METH_NOARGS functions now always take two parameters. diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -312,9 +312,6 @@ type = 'unsigned int' converter = 'uint_converter' -class compobject_converter(self_converter): - type = "compobject *" - [python]*/ /*[python checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ @@ -750,7 +747,7 @@ zlib.Decompress.decompress - self: compobject + self: self(type="compobject *") data: Py_buffer The binary data to decompress. @@ -1032,7 +1029,7 @@ /*[clinic] zlib.Compress.copy - self: compobject + self: self(type="compobject *") Return a copy of the compression object. [clinic]*/ diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1296,11 +1296,13 @@ must be keyword-only. """ + # The C type to use for this variable. + # 'type' should be a Python string specifying the type, e.g. "int". + # If this is a pointer type, the type string should end with ' *'. type = None - format_unit = 'O&' # The Python default value for this parameter, as a Python value. - # Or "unspecified" if there is no default. + # Or the magic value "unspecified" if there is no default. default = unspecified # "default" as it should appear in the documentation, as a string. @@ -1330,9 +1332,32 @@ # (If this is not None, format_unit must be 'O&'.) converter = None + # Should Argument Clinic add a '&' before the name of + # the variable when passing it into the _impl function? + impl_by_reference = False + + # Should Argument Clinic add a '&' before the name of + # the variable when passing it into PyArg_ParseTuple (AndKeywords)? + parse_by_reference = True + + ############################################################# + ############################################################# + ## You shouldn't need to read anything below this point to ## + ## write your own converter functions. ## + ############################################################# + ############################################################# + + # The "format unit" to specify for this variable when + # parsing arguments using PyArg_ParseTuple (AndKeywords). + # Custom converters should always use the default value of 'O&'. + format_unit = 'O&' + + # What encoding do we want for this variable? Only used + # by format units starting with 'e'. encoding = None - impl_by_reference = False - parse_by_reference = True + + # Do we want an adjacent '_length' variable for this variable? + # Only used by format units ending with '#'. length = False def __init__(self, name, function, default=unspecified, *, doc_default=None, required=False, annotation=unspecified, **kwargs): @@ -1751,7 +1776,7 @@ this is the default converter used for "self". """ type = "PyObject *" - def converter_init(self): + def converter_init(self, *, type=None): f = self.function if f.kind == CALLABLE: if f.cls: @@ -1766,6 +1791,9 @@ self.name = "cls" self.type = "PyTypeObject *" + if type: + self.type = type + def render(self, parameter, data): fail("render() should never be called on self_converter instances") @@ -1787,7 +1815,13 @@ class CReturnConverter(metaclass=CReturnConverterAutoRegister): + # The C type to use for this variable. + # 'type' should be a Python string specifying the type, e.g. "int". + # If this is a pointer type, the type string should end with ' *'. type = 'PyObject *' + + # The Python default value for this parameter, as a Python value. + # Or the magic value "unspecified" if there is no default. default = None def __init__(self, *, doc_default=None, **kwargs): @@ -1826,6 +1860,16 @@ add_c_return_converter(CReturnConverter, 'object') +class NoneType_return_converter(CReturnConverter): + def render(self, function, data): + self.declare(data) + data.return_conversion.append(''' +if (_return_value != Py_None) + goto exit; +return_value = Py_None; +Py_INCREF(Py_None); +'''.strip()) + class int_return_converter(CReturnConverter): type = 'int' @@ -2680,7 +2724,7 @@ # print(" ", short_name + "".join(parameters)) print() - print("All converters also accept (doc_default=None, required=False).") + print("All converters also accept (doc_default=None, required=False, annotation=None).") print("All return converters also accept (doc_default=None).") sys.exit(0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 4 23:13:51 2014 From: python-checkins at python.org (eric.snow) Date: Sat, 4 Jan 2014 23:13:51 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2319927=3A_Add_=5F?= =?utf-8?q?=5Feq=5F=5F_to_path-based_loaders_in_importlib=2E?= Message-ID: <3dxchH3dVxz7LmP@mail.python.org> http://hg.python.org/cpython/rev/a72a0e4dad20 changeset: 88299:a72a0e4dad20 user: Eric Snow date: Sat Jan 04 15:06:49 2014 -0700 summary: Issue #19927: Add __eq__ to path-based loaders in importlib. files: Lib/importlib/_bootstrap.py | 14 + Lib/test/test_importlib/extension/test_loader.py | 9 + Lib/test/test_importlib/source/test_file_loader.py | 13 + Lib/test/test_importlib/test_api.py | 3 +- Misc/NEWS | 2 + Python/importlib.h | 1278 +++++---- 6 files changed, 698 insertions(+), 621 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -1559,6 +1559,13 @@ self.name = fullname self.path = path + def __eq__(self, other): + return (self.__class__ == other.__class__ and + self.__dict__ == other.__dict__) + + def __hash__(self): + return hash(self.name) ^ hash(self.path) + @_check_name def load_module(self, fullname): """Load a module from a file.""" @@ -1653,6 +1660,13 @@ self.name = name self.path = path + def __eq__(self, other): + return (self.__class__ == other.__class__ and + self.__dict__ == other.__dict__) + + def __hash__(self): + return hash(self.name) ^ hash(self.path) + @_check_name def load_module(self, fullname): """Load an extension module.""" diff --git a/Lib/test/test_importlib/extension/test_loader.py b/Lib/test/test_importlib/extension/test_loader.py --- a/Lib/test/test_importlib/extension/test_loader.py +++ b/Lib/test/test_importlib/extension/test_loader.py @@ -28,6 +28,15 @@ with self.assertRaises(ImportError): self.load_module('XXX') + def test_equality(self): + other = self.machinery.ExtensionFileLoader(ext_util.NAME, + ext_util.FILEPATH) + self.assertEqual(self.loader, other) + + def test_inequality(self): + other = self.machinery.ExtensionFileLoader('_' + ext_util.NAME, + ext_util.FILEPATH) + self.assertNotEqual(self.loader, other) def test_module(self): with util.uncache(ext_util.NAME): diff --git a/Lib/test/test_importlib/source/test_file_loader.py b/Lib/test/test_importlib/source/test_file_loader.py --- a/Lib/test/test_importlib/source/test_file_loader.py +++ b/Lib/test/test_importlib/source/test_file_loader.py @@ -27,6 +27,11 @@ """ + def setUp(self): + self.name = 'spam' + self.filepath = os.path.join('ham', self.name + '.py') + self.loader = self.machinery.SourceFileLoader(self.name, self.filepath) + def test_load_module_API(self): class Tester(self.abc.FileLoader): def get_source(self, _): return 'attr = 42' @@ -53,6 +58,14 @@ with self.assertRaises(ImportError): loader.get_filename(name + 'XXX') + def test_equality(self): + other = self.machinery.SourceFileLoader(self.name, self.filepath) + self.assertEqual(self.loader, other) + + def test_inequality(self): + other = self.machinery.SourceFileLoader('_' + self.name, self.filepath) + self.assertNotEqual(self.loader, other) + # [basic] def test_module(self): with source_util.create_modules('_temp') as mapping: diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py --- a/Lib/test/test_importlib/test_api.py +++ b/Lib/test/test_importlib/test_api.py @@ -288,8 +288,7 @@ self.assertNotIn(name, sorted(sys.modules)) # Ensure successive calls behave the same. spec_again = self.init.find_spec(fullname, [pkg_dir]) - # XXX Once #19927 is resolved, uncomment this line. - #self.assertEqual(spec_again, spec) + self.assertEqual(spec_again, spec) def test_find_submodule_missing_path(self): name = 'spam' diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -203,6 +203,8 @@ no exception detail exists (no colon following the exception's name, or a colon does follow but no text follows the colon). +- Issue #19927: Add __eq__ to path-based loaders in importlib. + - Issue #19827: On UNIX, setblocking() and settimeout() methods of socket.socket can now avoid a second syscall if the ioctl() function can be used, or if the non-blocking flag of the socket is unchanged. diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 4 23:13:52 2014 From: python-checkins at python.org (eric.snow) Date: Sat, 4 Jan 2014 23:13:52 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2319713=3A_Move_awa?= =?utf-8?q?y_from_using_find=5Fmodule/load=5Fmodule=2E?= Message-ID: <3dxchJ5XcSz7LmX@mail.python.org> http://hg.python.org/cpython/rev/a18c1a4cf30a changeset: 88300:a18c1a4cf30a user: Eric Snow date: Sat Jan 04 15:09:28 2014 -0700 summary: Issue #19713: Move away from using find_module/load_module. files: Lib/test/test_tools.py | 9 +++++---- Misc/NEWS | 2 ++ setup.py | 6 +++++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_tools.py b/Lib/test/test_tools.py --- a/Lib/test/test_tools.py +++ b/Lib/test/test_tools.py @@ -6,6 +6,7 @@ import os import sys +import importlib._bootstrap import importlib.machinery import unittest from unittest import mock @@ -405,8 +406,8 @@ @classmethod def setUpClass(self): path = os.path.join(scriptsdir, 'pdeps.py') - loader = importlib.machinery.SourceFileLoader('pdeps', path) - self.pdeps = loader.load_module() + spec = importlib.util.spec_from_file_location('pdeps', path) + self.pdeps = importlib._bootstrap._SpecMethods(spec).load() @classmethod def tearDownClass(self): @@ -430,8 +431,8 @@ def setUp(self): path = os.path.join(scriptsdir, 'gprof2html.py') - loader = importlib.machinery.SourceFileLoader('gprof2html', path) - self.gprof = loader.load_module() + spec = importlib.util.spec_from_file_location('gprof2html', path) + self.gprof = importlib._bootstrap._SpecMethods(spec).load() oldargv = sys.argv def fixup(): sys.argv = oldargv diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -255,6 +255,8 @@ - Issue #6477: Added support for pickling the types of built-in singletons (i.e., Ellipsis, NotImplemented, None). +- Issue #19713: Move away from using find_module/load_module. + - Issue #19851: Fixed a regression in reloading sub-modules. - ssl.create_default_context() sets OP_NO_COMPRESSION to prevent CRIME. diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -3,6 +3,8 @@ import sys, os, importlib.machinery, re, optparse from glob import glob +import importlib._bootstrap +import importlib.util import sysconfig from distutils import log @@ -327,8 +329,10 @@ return loader = importlib.machinery.ExtensionFileLoader(ext.name, ext_filename) + spec = importlib.util.spec_from_file_location(ext.name, ext_filename, + loader=loader) try: - loader.load_module() + importlib._bootstrap._SpecMethods(spec).load() except ImportError as why: self.failed.append(ext.name) self.announce('*** WARNING: renaming "%s" since importing it' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 4 23:13:54 2014 From: python-checkins at python.org (eric.snow) Date: Sat, 4 Jan 2014 23:13:54 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2319708=3A_Update_p?= =?utf-8?q?kgutil_to_use_the_new_importer_APIs=2E?= Message-ID: <3dxchL1VN3z7Lmr@mail.python.org> http://hg.python.org/cpython/rev/acebe574ab08 changeset: 88301:acebe574ab08 user: Eric Snow date: Sat Jan 04 15:09:53 2014 -0700 summary: Issue #19708: Update pkgutil to use the new importer APIs. files: Lib/pkgutil.py | 20 ++++++++++++++++++-- Lib/test/test_pkgutil.py | 25 ++++++++++++------------- Misc/NEWS | 2 ++ 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py --- a/Lib/pkgutil.py +++ b/Lib/pkgutil.py @@ -16,6 +16,21 @@ 'ImpImporter', 'ImpLoader', 'read_code', 'extend_path', ] + +def _get_spec(finder, name): + """Return the finder-specific module spec.""" + # Works with legacy finders. + try: + find_spec = finder.find_spec + except AttributeError: + loader = finder.find_module(name) + if loader is None: + return None + return importlib.util.spec_from_loader(name, loader) + else: + return find_spec(name) + + def read_code(stream): # This helper is needed in order for the PEP 302 emulation to # correctly handle compiled files @@ -326,9 +341,10 @@ self.source = self._get_delegate().get_source() return self.source - def _get_delegate(self): - return ImpImporter(self.filename).find_module('__init__') + finder = ImpImporter(self.filename) + spec = _get_spec(finder, '__init__') + return spec.loader def get_filename(self, fullname=None): fullname = self._fix_name(fullname) diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py --- a/Lib/test/test_pkgutil.py +++ b/Lib/test/test_pkgutil.py @@ -2,6 +2,7 @@ import unittest import sys import importlib +from importlib.util import spec_from_file_location import pkgutil import os import os.path @@ -103,23 +104,20 @@ class PkgutilPEP302Tests(unittest.TestCase): class MyTestLoader(object): - def load_module(self, fullname): - # Create an empty module - mod = sys.modules.setdefault(fullname, types.ModuleType(fullname)) - mod.__file__ = "<%s>" % self.__class__.__name__ - mod.__loader__ = self - # Make it a package - mod.__path__ = [] + def exec_module(self, mod): # Count how many times the module is reloaded - mod.__dict__['loads'] = mod.__dict__.get('loads',0) + 1 - return mod + mod.__dict__['loads'] = mod.__dict__.get('loads', 0) + 1 def get_data(self, path): return "Hello, world!" class MyTestImporter(object): - def find_module(self, fullname, path=None): - return PkgutilPEP302Tests.MyTestLoader() + def find_spec(self, fullname, path=None, target=None): + loader = PkgutilPEP302Tests.MyTestLoader() + return spec_from_file_location(fullname, + '<%s>' % loader.__class__.__name__, + loader=loader, + submodule_search_locations=[]) def setUp(self): sys.meta_path.insert(0, self.MyTestImporter()) @@ -210,7 +208,8 @@ importers = list(iter_importers(fullname)) expected_importer = get_importer(pathitem) for finder in importers: - loader = finder.find_module(fullname) + spec = pkgutil._get_spec(finder, fullname) + loader = spec.loader try: loader = loader.loader except AttributeError: @@ -221,7 +220,7 @@ self.assertEqual(finder, expected_importer) self.assertIsInstance(loader, importlib.machinery.SourceFileLoader) - self.assertIsNone(finder.find_module(pkgname)) + self.assertIsNone(pkgutil._get_spec(finder, pkgname)) with self.assertRaises(ImportError): list(iter_importers('invalid.module')) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -257,6 +257,8 @@ - Issue #19713: Move away from using find_module/load_module. +- Issue #19708: Update pkgutil to use the new importer APIs. + - Issue #19851: Fixed a regression in reloading sub-modules. - ssl.create_default_context() sets OP_NO_COMPRESSION to prevent CRIME. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 5 00:29:40 2014 From: python-checkins at python.org (r.david.murray) Date: Sun, 5 Jan 2014 00:29:40 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_Mock_mock=5Fop?= =?utf-8?q?en_readline=28s=29=3B_expand_description_of_subtests_feature=2E?= Message-ID: <3dxfMm3Qrxz7LnN@mail.python.org> http://hg.python.org/cpython/rev/28f7e08a6a87 changeset: 88302:28f7e08a6a87 user: R David Murray date: Fri Jan 03 23:31:54 2014 -0500 summary: whatsnew: Mock mock_open readline(s); expand description of subtests feature. files: Doc/whatsnew/3.4.rst | 26 ++++++++++++++++++++++---- 1 files changed, 22 insertions(+), 4 deletions(-) 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 @@ -759,6 +759,9 @@ or name, instead of only by position. (Contributed by Antoine Pitrou in :issue:`17015`.) +:func:`~mock.mock_open` objects now have ``readline`` and ``readlines`` +methods. (Contributed by Toshio Kuratomi in :issue:`17467`.) + multiprocessing --------------- @@ -1010,11 +1013,26 @@ unittest -------- -Support for easy dynamically-generated subtests using the -:meth:`~unittest.TestCase.subTest` context manager. -(Contributed by Antoine Pitrou in :issue:`16997`.) +The :class:`~unittest.TestCase` class has a new method, +:meth:`~unittest.TestCase.subTest`, that produces a context manager whose +:keyword:`with` block becomes a "sub-test". This context manager allows a test +method to dynamically generate subtests by, say, calling the ``subTest`` +context manager inside a loop. A single test method can thereby produce an +indefinite number of separately-identified and separately-counted tests, all of +which will run even if one or more of them fail. For example:: -:func:`unittest.main` now also accepts an iterable of test names for + class NumbersTest(unittest.TestCase): + def test_even(self): + for i in range(6): + with self.subTest(i=1): + self.assertEqual(i % 2, 0) + +will result in six subtests, each identified in the unittest verbose output +with a label consisting of the variable name ``i`` and a particular value for +that variable (``i=0``, ``i=1``, etc). See :ref:`subtests` for the full +version of this example. (Contributed by Antoine Pitrou in :issue:`16997`.) + +:func:`unittest.main` now accepts an iterable of test names for *defaultTest*, where previously it only accepted a single test name as a string. (Contributed by Jyrki Pulliainen in :issue:`15132`.) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 5 00:29:41 2014 From: python-checkins at python.org (r.david.murray) Date: Sun, 5 Jan 2014 00:29:41 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_ppring_string_?= =?utf-8?q?wrapping=2C_string_pickling_optimization=2E?= Message-ID: <3dxfMn5Kfgz7LnJ@mail.python.org> http://hg.python.org/cpython/rev/d0c710d34927 changeset: 88303:d0c710d34927 user: R David Murray date: Sat Jan 04 17:11:23 2014 -0500 summary: whatsnew: ppring string wrapping, string pickling optimization. Also clarify some NEWS entries. files: Doc/whatsnew/3.4.rst | 7 +++++++ Misc/NEWS | 12 ++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) 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 @@ -847,6 +847,9 @@ The :mod:`pprint` module now supports *compact* mode for formatting long sequences (:issue:`19132`). +Long strings are now wrapped using Python's normal line continuation +syntax (Contributed by Antoine Pitrou in :issue:`17150`.) + pty --- @@ -1259,6 +1262,10 @@ * :func:`random.getrandbits` is 20%-40% faster for small integers (the most common use case). (Contributed by Serhiy Storchaka in :issue:`16674`). +* By taking advantage of the new storage format for strings, pickling of + strings is now significantly faster. (Contributed by Victor Stinner and + Antoine Pitrou in :issue:`15596`.) + Deprecated diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2282,7 +2282,7 @@ - Issue #15596: Faster pickling of unicode strings. -- Issue #17572: Avoid chained exceptions while passing bad directives to +- Issue #17572: Avoid chained exceptions when passing bad directives to time.strptime(). Initial patch by Claudiu Popa. - Issue #17435: threading.Timer's __init__ method no longer uses mutable @@ -2291,7 +2291,7 @@ - Issue #17526: fix an IndexError raised while passing code without filename to inspect.findsource(). Initial patch by Tyler Doyle. -- Issue #17540: Added style to formatter configuration by dict. +- Issue #17540: Added style parameter to logging formatter configuration by dict. - Issue #16692: The ssl module now supports TLS 1.1 and TLS 1.2. Initial patch by Michele Orr?. @@ -2312,10 +2312,10 @@ - Issue #17521: Corrected non-enabling of logger following two calls to fileConfig(). -- Issue #17508: Corrected MemoryHandler configuration in dictConfig() where - the target handler wasn't configured first. - -- Issue #17209: curses.window.get_wch() now handles correctly KeyboardInterrupt +- Issue #17508: Corrected logging MemoryHandler configuration in dictConfig() + where the target handler wasn't configured first. + +- Issue #17209: curses.window.get_wch() now correctly handles KeyboardInterrupt (CTRL+c). - Issue #5713: smtplib now handles 421 (closing connection) error codes when -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 5 00:29:43 2014 From: python-checkins at python.org (r.david.murray) Date: Sun, 5 Jan 2014 00:29:43 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_from_=5F=5Ffut?= =?utf-8?q?ure=5F=5F_string_exception=2C_attribute_UTF-32_decoder_speedup?= =?utf-8?q?=2E?= Message-ID: <3dxfMq05SBz7Lmw@mail.python.org> http://hg.python.org/cpython/rev/87decd548a56 changeset: 88304:87decd548a56 user: R David Murray date: Sat Jan 04 18:07:20 2014 -0500 summary: whatsnew: from __future__ string exception, attribute UTF-32 decoder speedup. And more news entry clarifications. files: Doc/whatsnew/3.4.rst | 9 ++++++++- Misc/NEWS | 8 ++++---- 2 files changed, 12 insertions(+), 5 deletions(-) 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 @@ -1234,7 +1234,8 @@ Significant Optimizations ========================= -* The UTF-32 decoder is now 3x to 4x faster. +* The UTF-32 decoder is now 3x to 4x faster. (Contributed by Serhiy Storchaka + in :issue:`14625`.) * The cost of hash collisions for sets is now reduced. Each hash table probe now checks a series of consecutive, adjacent key/hash pairs before @@ -1437,6 +1438,12 @@ keyword. If you've been paying attention to deprecation warnings your code should already be specifying any additional arguments via keywords. +* Strings between ``from __future__ import ...`` statements now *always* raise + a :exc:`SyntaxError`. Previously if there was no leading docstring, an + interstitial string would sometimes be ignored. This brings CPython into + compliance with the language spec; Jython and PyPy already were. + (:issue:`17434`). + Changes in the C API -------------------- diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2243,10 +2243,10 @@ calls. - Issue #17566: Make importlib.abc.Loader.module_repr() optional instead of an - abstractmethod and raising NotImplementedError so as to be ignored by default. - -- Issue #17678: Remove the use of deprecated method in http/cookiejar.py. - Changing the usage of get_origin_req_host() to origin_req_host. + abstractmethod; now it raises NotImplementedError so as to be ignored by default. + +- Issue #17678: Remove the use of deprecated method in http/cookiejar.py by + changing the call to get_origin_req_host() to origin_req_host. - Issue #17666: Fix reading gzip files with an extra field. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 5 02:33:03 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 5 Jan 2014 02:33:03 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_fix_release_date?= Message-ID: <3dxj6713q6z7LkS@mail.python.org> http://hg.python.org/peps/rev/3143c88f23ce changeset: 5335:3143c88f23ce user: Benjamin Peterson date: Sat Jan 04 19:32:54 2014 -0600 summary: fix release date files: pep-0373.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0373.txt b/pep-0373.txt --- a/pep-0373.txt +++ b/pep-0373.txt @@ -71,7 +71,7 @@ - 2.7.4 2013-04-06 - 2.7.5 2013-05-12 - 2.7.6rc1 2013-10-26 -- 2.7.6 2012-11-10 +- 2.7.6 2013-11-10 Possible features for 2.7 -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Jan 5 03:18:29 2014 From: python-checkins at python.org (r.david.murray) Date: Sun, 5 Jan 2014 03:18:29 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_logging_TimedR?= =?utf-8?q?otatingFileHandler_atTime_parameter=2E?= Message-ID: <3dxk6Y17sDz7Ljm@mail.python.org> http://hg.python.org/cpython/rev/1eb10bbebe79 changeset: 88305:1eb10bbebe79 user: R David Murray date: Sat Jan 04 18:55:01 2014 -0500 summary: whatsnew: logging TimedRotatingFileHandler atTime parameter. files: Doc/whatsnew/3.4.rst | 8 ++++++++ Misc/NEWS | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) 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 @@ -730,6 +730,14 @@ :issue:`19030`) +logging +------- + +The :class:`~logging.handlers.TimedRotatingFileHandler` has a new *atTime* +parameter that can be used to specify the time of day when rollover should +happen. (Contributed by Ronald Oussoren in :issue:`9556`.) + + .. _whatsnew-marshal-3: marshal diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2226,8 +2226,8 @@ - Issue #16658: add missing return to HTTPConnection.send() Patch by Jeff Knupp. -- Issue #9556: Allowed specifying a time-of-day for a TimedRotatingFileHandler - to rotate. +- Issue #9556: the logging package now allows specifying a time-of-day for a + TimedRotatingFileHandler to rotate. - Issue #14971: unittest test discovery no longer gets confused when a function has a different __name__ than its name in the TestCase class dictionary. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 5 03:18:30 2014 From: python-checkins at python.org (r.david.murray) Date: Sun, 5 Jan 2014 03:18:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_removal_of_TYP?= =?utf-8?q?E=5FINT64_from_marshal=2E?= Message-ID: <3dxk6Z2zz1z7Lms@mail.python.org> http://hg.python.org/cpython/rev/6d72617cae64 changeset: 88306:6d72617cae64 user: R David Murray date: Sat Jan 04 21:17:52 2014 -0500 summary: whatsnew: removal of TYPE_INT64 from marshal. Also update news entry for SMTPException; when I changed it from IOError to OSError I forgot to update the news item. files: Doc/whatsnew/3.4.rst | 3 +++ Misc/NEWS | 2 +- 2 files changed, 4 insertions(+), 1 deletions(-) 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 @@ -1373,6 +1373,9 @@ ``get_selector``, ``set_proxy``, ``get_origin_req_host``, and ``is_unverifiable`` have been removed (use direct attribute access instead). +* Support for loading the deprecated ``TYPE_INT64`` has been removed from + :mod:`marshal`. (Contributed by Dan Riti in :issue:`15480`.) + Porting to Python 3.4 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2218,7 +2218,7 @@ - Issue #15480: Remove the deprecated and unused TYPE_INT64 code from marshal. Initial patch by Daniel Riti. -- Issue #2118: SMTPException is now a subclass of IOError. +- Issue #2118: SMTPException is now a subclass of OSError. - Issue #17016: Get rid of possible pointer wraparounds and integer overflows in the re module. Patch by Nickolai Zeldovich. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 5 04:58:40 2014 From: python-checkins at python.org (eric.snow) Date: Sun, 5 Jan 2014 04:58:40 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_20123=3A_Fix_pydoc?= =?utf-8?b?LnN5bm9wc2lzKCkgZm9yICJiaW5hcnkiIG1vZHVsZXMu?= Message-ID: <3dxmL81pS9z7Lp4@mail.python.org> http://hg.python.org/cpython/rev/d6c3fb8d5f84 changeset: 88307:d6c3fb8d5f84 user: Eric Snow date: Sat Jan 04 20:38:11 2014 -0700 summary: Issue 20123: Fix pydoc.synopsis() for "binary" modules. Also add missing tests to test_pydoc. files: Lib/pydoc.py | 46 +++++++++++++------------- Lib/test/test_pydoc.py | 52 ++++++++++++++++++++++++++++++ Misc/NEWS | 2 + 3 files changed, 77 insertions(+), 23 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -225,34 +225,34 @@ mtime = os.stat(filename).st_mtime lastupdate, result = cache.get(filename, (None, None)) if lastupdate is None or lastupdate < mtime: - try: - file = tokenize.open(filename) - except OSError: - # module can't be opened, so skip it - return None - binary_suffixes = importlib.machinery.BYTECODE_SUFFIXES[:] - binary_suffixes += importlib.machinery.EXTENSION_SUFFIXES[:] - if any(filename.endswith(x) for x in binary_suffixes): - # binary modules have to be imported - file.close() - if any(filename.endswith(x) for x in - importlib.machinery.BYTECODE_SUFFIXES): - loader = importlib.machinery.SourcelessFileLoader('__temp__', - filename) - else: - loader = importlib.machinery.ExtensionFileLoader('__temp__', - filename) + # Look for binary suffixes first, falling back to source. + if filename.endswith(tuple(importlib.machinery.BYTECODE_SUFFIXES)): + loader_cls = importlib.machinery.SourcelessFileLoader + elif filename.endswith(tuple(importlib.machinery.EXTENSION_SUFFIXES)): + loader_cls = importlib.machinery.ExtensionFileLoader + else: + loader_cls = None + # Now handle the choice. + if loader_cls is None: + # Must be a source file. + try: + file = tokenize.open(filename) + except OSError: + # module can't be opened, so skip it + return None + # text modules can be directly examined + with file: + result = source_synopsis(file) + else: + # Must be a binary module, which has to be imported. + loader = loader_cls('__temp__', filename) try: module = loader.load_module('__temp__') except: return None + del sys.modules['__temp__'] result = (module.__doc__ or '').splitlines()[0] - del sys.modules['__temp__'] - else: - # text modules can be directly examined - result = source_synopsis(file) - file.close() - + # Cache the result. cache[filename] = (mtime, result) return result 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 @@ -487,6 +487,13 @@ synopsis = pydoc.synopsis(TESTFN, {}) self.assertEqual(synopsis, 'line 1: h\xe9') + def test_synopsis_sourceless(self): + expected = os.__doc__.splitlines()[0] + filename = os.__cached__ + synopsis = pydoc.synopsis(filename) + + self.assertEqual(synopsis, expected) + def test_splitdoc_with_description(self): example_string = "I Am A Doc\n\n\nHere is my description" self.assertEqual(pydoc.splitdoc(example_string), @@ -600,6 +607,50 @@ self.assertEqual(out.getvalue(), '') self.assertEqual(err.getvalue(), '') + def test_modules(self): + # See Helper.listmodules(). + num_header_lines = 2 + num_module_lines_min = 5 # Playing it safe. + num_footer_lines = 3 + expected = num_header_lines + num_module_lines_min + num_footer_lines + + output = StringIO() + helper = pydoc.Helper(output=output) + helper('modules') + result = output.getvalue().strip() + num_lines = len(result.splitlines()) + + self.assertGreaterEqual(num_lines, expected) + + def test_modules_search(self): + # See Helper.listmodules(). + expected = 'pydoc - ' + + output = StringIO() + helper = pydoc.Helper(output=output) + with captured_stdout() as help_io: + helper('modules pydoc') + result = help_io.getvalue() + + self.assertIn(expected, result) + + def test_modules_search_builtin(self): + expected = 'gc - ' + + output = StringIO() + helper = pydoc.Helper(output=output) + with captured_stdout() as help_io: + helper('modules garbage') + result = help_io.getvalue() + + self.assertTrue(result.startswith(expected)) + + def test_importfile(self): + loaded_pydoc = pydoc.importfile(pydoc.__file__) + + self.assertEqual(loaded_pydoc.__name__, 'pydoc') + self.assertEqual(loaded_pydoc.__file__, pydoc.__file__) + class TestDescriptions(unittest.TestCase): @@ -827,6 +878,7 @@ print_diffs(expected_text, result) self.fail("outputs are not equal, see diff above") + @reap_threads def test_main(): try: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -221,6 +221,8 @@ - Issue #19782: imaplib now supports SSLContext.check_hostname and server name indication for TLS/SSL connections. +- Issue 20123: Fix pydoc.synopsis() for "binary" modules. + - Issue #19834: Support unpickling of exceptions pickled by Python 2. - Issue #19781: ftplib now supports SSLContext.check_hostname and server name -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 5 05:54:24 2014 From: python-checkins at python.org (r.david.murray) Date: Sun, 5 Jan 2014 05:54:24 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_XMLPullParser?= =?utf-8?q?=2C_plus_some_doc_updates=2E?= Message-ID: <3dxnZS1P8vz7Lmc@mail.python.org> http://hg.python.org/cpython/rev/069f88f4935f changeset: 88308:069f88f4935f user: R David Murray date: Sat Jan 04 23:52:50 2014 -0500 summary: whatsnew: XMLPullParser, plus some doc updates. I was confused by the text saying that read_events "iterated", since it actually returns an iterator (that's what a generator does) that the caller must then iterate. So I tidied up the language. I'm not sure what the sentence "Events provided in a previous call to read_events() will not be yielded again." is trying to convey, so I didn't try to fix that. Also fixed a couple more news items. files: Doc/library/xml.etree.elementtree.rst | 23 +++++++++----- Doc/whatsnew/3.4.rst | 7 ++- Lib/xml/etree/ElementTree.py | 2 +- Misc/NEWS | 12 +++--- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -105,12 +105,15 @@ >>> root[0][1].text '2008' + +.. _elementtree-pull-parsing: + Pull API for non-blocking parsing ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Most parsing functions provided by this module require to read the whole -document at once before returning any result. It is possible to use a -:class:`XMLParser` and feed data into it incrementally, but it's a push API that +Most parsing functions provided by this module require the whole document +to be read at once before returning any result. It is possible to use an +:class:`XMLParser` and feed data into it incrementally, but it is a push API that calls methods on a callback target, which is too low-level and inconvenient for most needs. Sometimes what the user really wants is to be able to parse XML incrementally, without blocking operations, while enjoying the convenience of @@ -119,7 +122,7 @@ The most powerful tool for doing this is :class:`XMLPullParser`. It does not require a blocking read to obtain the XML data, and is instead fed with data incrementally with :meth:`XMLPullParser.feed` calls. To get the parsed XML -elements, call :meth:`XMLPullParser.read_events`. Here's an example:: +elements, call :meth:`XMLPullParser.read_events`. Here is an example:: >>> parser = ET.XMLPullParser(['start', 'end']) >>> parser.feed('sometext') @@ -1038,15 +1041,17 @@ .. method:: read_events() - Iterate over the events which have been encountered in the data fed to the - parser. This method yields ``(event, elem)`` pairs, where *event* is a + Return an iterator over the events which have been encountered in the + data fed to the + parser. The iterator yields ``(event, elem)`` pairs, where *event* is a string representing the type of event (e.g. ``"end"``) and *elem* is the encountered :class:`Element` object. Events provided in a previous call to :meth:`read_events` will not be - yielded again. As events are consumed from the internal queue only as - they are retrieved from the iterator, multiple readers calling - :meth:`read_events` in parallel will have unpredictable results. + yielded again. Events are consumed from the internal queue only when + they are retrieved from the iterator, so multiple readers iterating in + parallel over iterators obtained from :meth:`read_events` will have + unpredictable results. .. note:: 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 @@ -1088,9 +1088,10 @@ xml.etree --------- -Add an event-driven parser for non-blocking applications, -:class:`~xml.etree.ElementTree.XMLPullParser`. -(Contributed by Antoine Pitrou in :issue:`17741`.) +A new parser, :class:`~xml.etree.ElementTree.XMLPullParser`, allows a +non-blocking applications to parse XML documents. An example can be +seen at :ref:`elementtree-pull-parsing`. (Contributed by Antoine +Pitrou in :issue:`17741`.) The :mod:`xml.etree.ElementTree` :func:`~xml.etree.ElementTree.tostring` and :func:`~xml.etree.ElementTree.tostringlist` functions, and the diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -1251,7 +1251,7 @@ self._close_and_return_root() def read_events(self): - """Iterate over currently available (event, elem) pairs. + """Return an iterator over currently available (event, elem) pairs. Events are consumed from the internal event queue as they are retrieved from the iterator. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2193,14 +2193,14 @@ - Issue #17555: Fix ForkAwareThreadLock so that size of after fork registry does not grow exponentially with generation of process. -- Issue #17707: multiprocessing.Queue's get() method does not block for short - timeouts. - -- Isuse #17720: Fix the Python implementation of pickle.Unpickler to correctly +- Issue #17707: fix regression in multiprocessing.Queue's get() method where + it did not block for short timeouts. + +- Issue #17720: Fix the Python implementation of pickle.Unpickler to correctly process the APPENDS opcode when it is used on non-list objects. -- Issue #17012: shutil.which() no longer fallbacks to the PATH environment - variable if empty path argument is specified. Patch by Serhiy Storchaka. +- Issue #17012: shutil.which() no longer falls back to the PATH environment + variable if an empty path argument is specified. Patch by Serhiy Storchaka. - Issue #17710: Fix pickle raising a SystemError on bogus input. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 5 06:05:38 2014 From: python-checkins at python.org (eric.snow) Date: Sun, 5 Jan 2014 06:05:38 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_20123=3A_try_using_a?= =?utf-8?q?_different_builtin_module_in_a_pydoc_test=2E?= Message-ID: <3dxnqQ0dBBz7Lmc@mail.python.org> http://hg.python.org/cpython/rev/ff3be21338d5 changeset: 88309:ff3be21338d5 user: Eric Snow date: Sat Jan 04 21:56:07 2014 -0700 summary: Issue 20123: try using a different builtin module in a pydoc test. The test is failing on one of the stable FreeBSD buildbots. It seems unlikely that the gc module would not be available, so switching to _imp may not fix the problem. files: Lib/test/test_pydoc.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -635,12 +635,12 @@ self.assertIn(expected, result) def test_modules_search_builtin(self): - expected = 'gc - ' + expected = '_imp - ' output = StringIO() helper = pydoc.Helper(output=output) with captured_stdout() as help_io: - helper('modules garbage') + helper('modules low-level') result = help_io.getvalue() self.assertTrue(result.startswith(expected)) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 5 06:30:32 2014 From: python-checkins at python.org (r.david.murray) Date: Sun, 5 Jan 2014 06:30:32 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_news_entry_to_use_upda?= =?utf-8?q?ted_name_for_XMLPullParser=2E?= Message-ID: <3dxpN85g7JzPVW@mail.python.org> http://hg.python.org/cpython/rev/2d876843b52c changeset: 88310:2d876843b52c user: R David Murray date: Sun Jan 05 00:30:03 2014 -0500 summary: Fix news entry to use updated name for XMLPullParser. files: Misc/NEWS | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2187,8 +2187,8 @@ - Issue #11182: remove the unused and undocumented pydoc.Scanner class. Patch by Martin Morrison. -- Issue #17741: Add ElementTree.IncrementalParser, an event-driven parser - for non-blocking applications. +- Issue #17741: Add ElementTree.XMLPullParser, an event-driven parser for + non-blocking applications. - Issue #17555: Fix ForkAwareThreadLock so that size of after fork registry does not grow exponentially with generation of process. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 5 07:06:11 2014 From: python-checkins at python.org (eric.snow) Date: Sun, 5 Jan 2014 07:06:11 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_20123=3A_Disable_a_p?= =?utf-8?q?roblematic_test=2E?= Message-ID: <3dxq9H4zTCz7Lmb@mail.python.org> http://hg.python.org/cpython/rev/efcf163d04f5 changeset: 88311:efcf163d04f5 user: Eric Snow date: Sat Jan 04 23:04:27 2014 -0700 summary: Issue 20123: Disable a problematic test. files: Lib/test/test_pydoc.py | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -634,13 +634,14 @@ self.assertIn(expected, result) + @unittest.skip('some buildbots are not cooperating (#20123)') def test_modules_search_builtin(self): - expected = '_imp - ' + expected = 'gc - ' output = StringIO() helper = pydoc.Helper(output=output) with captured_stdout() as help_io: - helper('modules low-level') + helper('modules garbage') result = help_io.getvalue() self.assertTrue(result.startswith(expected)) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun Jan 5 09:46:13 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 05 Jan 2014 09:46:13 +0100 Subject: [Python-checkins] Daily reference leaks (6d72617cae64): sum=11 Message-ID: results for 6d72617cae64 on branch "default" -------------------------------------------- test_asyncio leaked [0, 0, 4] memory blocks, sum=4 test_audioop leaked [1, 1, 1] references, sum=3 test_site leaked [0, 0, 2] references, sum=2 test_site leaked [0, 0, 2] memory blocks, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/refloggDBTf7', '-x'] From python-checkins at python.org Sun Jan 5 11:50:58 2014 From: python-checkins at python.org (larry.hastings) Date: Sun, 5 Jan 2014 11:50:58 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Argument_Clinic=3A_fixed_t?= =?utf-8?q?est_suite=2C_improved_howto=2E?= Message-ID: <3dxxTt3yjyz7Ljd@mail.python.org> http://hg.python.org/cpython/rev/172a6bfdd91b changeset: 88312:172a6bfdd91b user: Larry Hastings date: Sun Jan 05 02:50:45 2014 -0800 summary: Argument Clinic: fixed test suite, improved howto. files: Doc/howto/clinic.rst | 241 +++++++++++++++-------- Tools/clinic/clinic.py | 9 +- Tools/clinic/clinic_test.py | 24 +- 3 files changed, 173 insertions(+), 101 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -14,21 +14,20 @@ function to work with Argument Clinic, and then introduces some advanced topics on Argument Clinic usage. - Argument Clinic is currently considered an internal - tool for the CPython code tree. Its use is not supported - for files outside the CPython code tree, and no guarantees - are made regarding backwards compatibility for future - versions. In other words: if you maintain an external C - extension for CPython, you're welcome to experiment with - Argument Clinic in your own code. But the version of Argument - Clinic that ships with CPython 3.5 *could* be totally - incompatible and break all your code. + Currently Argument Clinic is considered internal-only + for CPython. Its use is not supported for files outside + CPython, and no guarantees are made regarding backwards + compatibility for future versions. In other words: if you + maintain an external C extension for CPython, you're welcome + to experiment with Argument Clinic in your own code. But the + version of Argument Clinic that ships with CPython 3.5 *could* + be totally incompatible and break all your code. ======================== Basic Concepts And Usage ======================== -Argument Clinic ships with CPython. You can find it in ``Tools/clinic/clinic.py``. +Argument Clinic ships with CPython; you'll find it in ``Tools/clinic/clinic.py``. If you run that script, specifying a C file as an argument:: % python3 Tools/clinic/clinic.py foo.c @@ -45,13 +44,12 @@ Everything in between these two lines is input for Argument Clinic. All of these lines, including the beginning and ending comment -lines, are collectively called an Argument Clinic "input block", -or "block" for short. +lines, are collectively called an Argument Clinic "block". When Argument Clinic parses one of these blocks, it generates output. This output is rewritten into the C file immediately after the block, followed by a comment containing a checksum. -The resulting Argument Clinic block looks like this:: +The Argument Clinic block now looks like this:: /*[clinic] ... clinic input goes here ... @@ -65,7 +63,8 @@ You should never modify the output portion of an Argument Clinic block. Instead, change the input until it produces the output you want. (That's the purpose of the -checksum--to detect and warn you in case someone accidentally modifies the output.) +checksum--to detect if someone changed the output, as these edits would be lost +the next time Argument Clinic writes out fresh output.) For the sake of clarity, here's the terminology we'll use with Argument Clinic: @@ -87,10 +86,12 @@ The best way to get a sense of how Argument Clinic works is to convert a function to work with it. Let's dive in! -0. Make sure you're working with a freshly updated trunk. +0. Make sure you're working with a freshly updated checkout + of the CPython trunk. -1. Find a Python builtin that calls either ``PyArg_ParseTuple()`` - or ``PyArg_ParseTupleAndKeywords()``, and hasn't been converted yet. +1. Find a Python builtin that calls either :c:func:`PyArg_ParseTuple` + or :c:func:`PyArg_ParseTupleAndKeywords`, and hasn't been converted + to work with Argument Clinic yet. For my example I'm using ``pickle.Pickler.dump()``. 2. If the call to the ``PyArg_Parse`` function uses any of the @@ -103,7 +104,7 @@ et et# - or if it has multiple calls to ``PyArg_ParseTuple()``, + or if it has multiple calls to :c:func:`PyArg_ParseTuple`, you should choose a different function. Argument Clinic *does* support all of these scenarios. But these are advanced topics--let's do something simpler for your first function. @@ -130,7 +131,7 @@ be a paragraph consisting of a single 80-column line at the beginning of the docstring. - (Our docstring consists solely of the summary line, so the sample + (Our example docstring consists solely of a summary line, so the sample code doesn't have to change for this step.) 6. Above the docstring, enter the name of the function, followed @@ -198,7 +199,8 @@ string. ("format unit" is the formal name for the one-to-three character substring of the ``format`` parameter that tells the argument parsing function what the type of the variable - is and how to convert it.) + is and how to convert it. For more on format units please + see :ref:`arg-parsing`.) For multicharacter format units like ``z#``, use the entire two-or-three character string. @@ -231,14 +233,18 @@ (``pickle.Pickler.dump`` has neither, so our sample is unchanged.) -10. If the existing C function uses ``PyArg_ParseTuple()`` - (instead of ``PyArg_ParseTupleAndKeywords()``), then all its +10. If the existing C function calls :c:func:`PyArg_ParseTuple` + (as opposed to :c:func:`PyArg_ParseTupleAndKeywords`), then all its arguments are positional-only. To mark all parameters as positional-only in Argument Clinic, add a ``/`` on a line by itself after the last parameter, indented the same as the parameter lines. + Currently this is all-or-nothing; either all parameters are + positional-only, or none of them are. (In the future Argument + Clinic may relax this restriction.) + Sample:: /*[clinic] @@ -255,16 +261,16 @@ Write a pickled representation of obj to the open file. [clinic]*/ -11. It's helpful to write a per-parameter docstring, indented - another level past the parameter declaration. But per-parameter - docstrings are optional; you can skip this step if you prefer. +11. It's helpful to write a per-parameter docstring for each parameter. + But per-parameter docstrings are optional; you can skip this step + if you prefer. - Here's how per-parameter docstrings work. The first line + Here's how to add a per-parameter docstring. The first line of the per-parameter docstring must be indented further than the - parameter definition. This left margin establishes the left margin - for the whole per-parameter docstring; all the text you write will - be outdented by this amount. You can write as much as you like, - across multiple lines if you wish. + parameter definition. The left margin of this first line establishes + the left margin for the whole per-parameter docstring; all the text + you write will be outdented by this amount. You can write as much + text as you like, across multiple lines if you wish. Sample:: @@ -311,28 +317,47 @@ pickle_Pickler_dump_impl(PyObject *self, PyObject *obj) /*[clinic checksum: 3bd30745bf206a48f8b576a1da3d90f55a0a4187]*/ + Obviously, if Argument Clinic didn't produce any output, it's because + it found an error in your input. Keep fixing your errors and retrying + until Argument Clinic processes your file without complaint. + 13. Double-check that the argument-parsing code Argument Clinic generated looks basically the same as the existing code. First, ensure both places use the same argument-parsing function. The existing code must call either - ``PyArg_ParseTuple()`` or ``PyArg_ParseTupleAndKeywords()``; + :c:func:`PyArg_ParseTuple` or :c:func:`PyArg_ParseTupleAndKeywords`; ensure that the code generated by Argument Clinic calls the - same function. + *exact* same function. - Second, the format string passed in to ``PyArg_ParseTuple()`` or - ``PyArg_ParseTupleAndKeywords()`` should be *exactly* the same - as the hand-written one in the existing function. + Second, the format string passed in to :c:func:`PyArg_ParseTuple` or + :c:func:`PyArg_ParseTupleAndKeywords` should be *exactly* the same + as the hand-written one in the existing function, up to the colon + or semi-colon. - Well, there's one way that Argument Clinic's output is permitted - to be different. Argument Clinic always generates a format string - ending with ``:`` followed by the name of the function. If the - format string originally ended with ``;`` (to specify usage help), - this is harmless--don't worry about this difference. + (Argument Clinic always generates its format strings + with a ``:`` followed by the name of the function. If the + existing code's format string ends with ``;``, to provide + usage help, this change is harmless--don't worry about it.) - Apart from that, if either of these things differ in *any way*, - fix your input to Argument Clinic and rerun ``Tools/clinic/clinic.py`` - until they are the same. + Third, for parameters whose format units require two arguments + (like a length variable, or an encoding string, or a pointer + to a conversion function), ensure that the second argument is + *exactly* the same between the two invocations. + + Fourth, inside the output portion of the block you'll find a preprocessor + macro defining the appropriate static :c:type:`PyMethodDef` structure for + this builtin:: + + #define _PICKLE_PICKLER_DUMP_METHODDEF \ + {"dump", (PyCFunction)_pickle_Pickler_dump, METH_O, _pickle_Pickler_dump__doc__}, + + This static structure should be *exactly* the same as the existing static + :c:type:`PyMethodDef` structure for this builtin. + + If any of these items differ in *any way*, + adjust your Argument Clinic function specification and rerun + ``Tools/clinic/clinic.py`` until they *are* the same. 14. Notice that the last line of its output is the declaration @@ -342,8 +367,19 @@ declarations of all the variables it dumps the arguments into. Notice how the Python arguments are now arguments to this impl function; if the implementation used different names for these variables, fix it. - The result should be a function that handles just the implementation - of the Python function without any argument-parsing code. + + Let's reiterate, just because it's kind of weird. Your code should now + look like this:: + + static return_type + your_function_impl(...) + /*[clinic checksum: ...]*/ + { + ... + + Argument Clinic generated the checksum line and the function prototype just + above it. You should write the opening (and closing) curly braces for the + function, and the implementation inside. Sample:: @@ -386,7 +422,27 @@ ... -15. Compile and run the relevant portions of the regression-test suite. +15. Remember the macro with the :c:type:`PyMethodDef` structure for this + function? Find the existing :c:type:`PyMethodDef` structure for this + function and replace it with a reference to the macro. (If the builtin + is at module scope, this will probably be very near the end of the file; + if the builtin is a class method, this will probably be below but relatively + near to the implementation.) + + Note that the body of the macro contains a trailing comma. So when you + replace the existing static :c:type:`PyMethodDef` structure with the macro, + *don't* add a comma to the end. + + Sample:: + + static struct PyMethodDef Pickler_methods[] = { + _PICKLE_PICKLER_DUMP_METHODDEF + _PICKLE_PICKLER_CLEAR_MEMO_METHODDEF + {NULL, NULL} /* sentinel */ + }; + + +16. Compile, then run the relevant portions of the regression-test suite. This change should not introduce any new compile-time warnings or errors, and there should be no externally-visible change to Python's behavior. @@ -405,11 +461,11 @@ Argument Clinic automatically names the functions it generates for you. Occasionally this may cause a problem, if the generated name collides with -the name of an existing C function. There's an easy solution: you can explicitly -specify the base name to use for the C functions. Just add the keyword ``"as"`` +the name of an existing C function. There's an easy solution: override the names +used for the C functions. Just add the keyword ``"as"`` to your function declaration line, followed by the function name you wish to use. -Argument Clinic will use the function name you use for the base (generated) function, -and then add ``"_impl"`` to the end for the name of the impl function. +Argument Clinic will use that function name for the base (generated) function, +then add ``"_impl"`` to the end and use that for the name of the impl function. For example, if we wanted to rename the C function names generated for ``pickle.Pickler.dump``, it'd look like this:: @@ -420,7 +476,7 @@ ... The base function would now be named ``pickler_dumper()``, -and the impl function would be named ``pickler_dumper_impl()``. +and the impl function would now be named ``pickler_dumper_impl()``. Optional Groups @@ -428,15 +484,15 @@ Some legacy functions have a tricky approach to parsing their arguments: they count the number of positional arguments, then use a ``switch`` statement -to call one of several different ``PyArg_ParseTuple()`` calls depending on +to call one of several different :c:func:`PyArg_ParseTuple` calls depending on how many positional arguments there are. (These functions cannot accept keyword-only arguments.) This approach was used to simulate optional -arguments back before ``PyArg_ParseTupleAndKeywords()`` was created. +arguments back before :c:func:`PyArg_ParseTupleAndKeywords` was created. -Functions using this approach can often be converted to -use ``PyArg_ParseTupleAndKeywords()``, optional arguments, and default values. -But it's not always possible, because some of these legacy functions have -behaviors ``PyArg_ParseTupleAndKeywords()`` can't directly support. +While functions using this approach can often be converted to +use :c:func:`PyArg_ParseTupleAndKeywords`, optional arguments, and default values, +it's not always possible. Some of these legacy functions have +behaviors :c:func:`PyArg_ParseTupleAndKeywords` doesn't directly support. The most obvious example is the builtin function ``range()``, which has an optional argument on the *left* side of its required argument! Another example is ``curses.window.addch()``, which has a group of two @@ -445,16 +501,17 @@ you must also pass in ``y``--and if you don't pass in ``x`` you may not pass in ``y`` either.) -For the sake of backwards compatibility, Argument Clinic supports this -alternate approach to parsing, using what are called *optional groups*. -Optional groups are groups of arguments that can only be specified together. +In any case, the goal of Argument Clinic is to support argument parsing +for all existing CPython builtins without changing their semantics. +Therefore Argument Clinic supports +this alternate approach to parsing, using what are called *optional groups*. +Optional groups are groups of arguments that must all be passed in together. They can be to the left or the right of the required arguments. They can *only* be used with positional-only parameters. To specify an optional group, add a ``[`` on a line by itself before -the parameters you wish to be -in a group together, and a ``]`` on a line by itself after the -parameters. As an example, here's how ``curses.window.addch`` +the parameters you wish to group together, and a ``]`` on a line by itself +after these parameters. As an example, here's how ``curses.window.addch`` uses optional groups to make the first two parameters and the last parameter optional:: @@ -484,8 +541,8 @@ Notes: * For every optional group, one additional parameter will be passed into the - impl function representing the group. The parameter will be an int, and it will - be named ``group_{direction}_{number}``, + impl function representing the group. The parameter will be an int named + ``group_{direction}_{number}``, where ``{direction}`` is either ``right`` or ``left`` depending on whether the group is before or after the required parameters, and ``{number}`` is a monotonically increasing number (starting at 1) indicating how far away the group is from @@ -495,11 +552,13 @@ in this invocation.) * If there are no required arguments, the optional groups will behave - as if they are to the right of the required arguments. + as if they're to the right of the required arguments. * In the case of ambiguity, the argument parsing code favors parameters on the left (before the required parameters). +* Optional groups can only contain positional-only parameters. + * Optional groups are *only* intended for legacy code. Please do not use optional groups for new code. @@ -509,7 +568,7 @@ To save time, and to minimize how much you need to learn to achieve your first port to Argument Clinic, the walkthrough above tells -you to use the "legacy converters". "Legacy converters" are a convenience, +you to use "legacy converters". "Legacy converters" are a convenience, designed explicitly to make porting existing code to Argument Clinic easier. And to be clear, their use is entirely acceptable when porting code for Python 3.4. @@ -523,18 +582,19 @@ because they require arguments, and the legacy converter syntax doesn't support specifying arguments. * In the future we may have a new argument parsing library that isn't - restricted to what ``PyArg_ParseTuple()`` supports. + restricted to what :c:func:`PyArg_ParseTuple` supports; this flexibility + won't be available to parameters using legacy converters. -So if you want -to go that extra effort, you should consider using normal -converters instead of the legacy converters. +Therefore, if you don't mind a little extra effort, you should consider +using normal converters instead of legacy converters. In a nutshell, the syntax for Argument Clinic (non-legacy) converters looks like a Python function call. However, if there are no explicit arguments to the function (all functions take their default values), you may omit the parentheses. Thus ``bool`` and ``bool()`` are exactly -the same. All parameters to Argument Clinic converters are keyword-only. +the same converters. +All arguments to Argument Clinic converters are keyword-only. All Argument Clinic converters accept the following arguments: ``doc_default`` @@ -643,11 +703,11 @@ Note also that this approach takes away some possible flexibility for the format units starting with ``e``. It used to be possible to decide at runtime what -encoding string to pass in to ``PyArg_ParseTuple()``. But now this string must +encoding string to pass in to :c:func:`PyArg_ParseTuple`. But now this string must be hard-coded at compile-time. This limitation is deliberate; it made supporting this format unit much easier, and may allow for future compile-time optimizations. This restriction does not seem unreasonable; CPython itself always passes in static -hard-coded strings when using format units starting with ``e``. +hard-coded encoding strings for parameters whose format units start with ``e``. Using a return converter @@ -692,12 +752,17 @@ error. For ``DecodeFSDefault``, the return type is ``char *``; return a NULL pointer to indicate an error. +To see all the return converters Argument Clinic supports, along with +their parameters (if any), +just run ``Tools/clinic/clinic.py --converters`` for the full list. + + Calling Python code ------------------- The rest of the advanced topics require you to write Python code -which lives inside your C file and modifies Argument Clinic at -runtime. This is simple; you simply define a Python block. +which lives inside your C file and modifies Argument Clinic's +runtime state. This is simple: you simply define a Python block. A Python block uses different delimiter lines than an Argument Clinic function block. It looks like this:: @@ -778,13 +843,13 @@ A converter is simply a Python class that inherits from ``CConverter``. The main purpose of a custom converter is if you have a parameter using the ``O&`` format unit--parsing this parameter means calling -a ``PyArg_ParseTuple()`` "converter function". +a :c:func:`PyArg_ParseTuple` "converter function". Your converter class should be named ``*something*_converter``. If the name follows this convention, then your converter class will be automatically registered with Argument Clinic; its name will be the name of your class with the ``_converter`` suffix -stripped off. (This is done automatically for you with a metaclass.) +stripped off. (This is accomplished with a metaclass.) You shouldn't subclass ``CConverter.__init__``. Instead, you should write a ``converter_init()`` function. ``converter_init()`` @@ -825,12 +890,13 @@ ``c_ignored_default`` The default value used to initialize the C variable when there is no default, but not specifying a default may - result in an "uninitialized variable" warning. This is + result in an "uninitialized variable" warning. This can easily happen when using option groups--although - properly-written code won't actually use the variable, - the variable does get passed in to the _impl, and the - C compiler will complain about the "use" of the uninitialized - value. This value should be a string. + properly-written code will never actually use this value, + the variable does get passed in to the impl, and the + C compiler will complain about the "use" of the + uninitialized value. This value should always be a + non-empty string. ``converter`` The name of the C converter function, as a string. @@ -843,7 +909,7 @@ ``parse_by_reference`` A boolean value. If true, Argument Clinic will add a ``&`` in front of the name of - the variable when passing it into ``PyArg_ParseTuple()``. + the variable when passing it into :c:func:`PyArg_ParseTuple`. Here's the simplest example of a custom converter, from ``Modules/zlibmodule.c``:: @@ -857,9 +923,10 @@ [python]*/ /*[python checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ -This block adds a ``uint`` converter to Argument Clinic. Parameters +This block adds a converter to Argument Clinic named ``uint``. Parameters declared as ``uint`` will be declared as type ``unsigned int``, and will -be parsed by calling the ``uint_converter`` converter function in C. +be parsed by the ``'O&'`` format unit, which will call the ``uint_converter`` +converter function. ``uint`` variables automatically support default values. More sophisticated custom converters can insert custom C code to @@ -871,7 +938,7 @@ --------------------------------- Writing a custom return converter is much like writing -a custom converter. Except it's much simpler, because return +a custom converter. Except it's somewhat simpler, because return converters are themselves much simpler. Return converters must subclass ``CReturnConverter``. diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -997,7 +997,8 @@ # "languages" maps the name of the language ("C", "Python"). # "extensions" maps the file extension ("c", "py"). languages = { 'C': CLanguage, 'Python': PythonLanguage } -extensions = { 'c': CLanguage, 'h': CLanguage, 'py': PythonLanguage } +extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() } +extensions['py'] = PythonLanguage # maps strings to callables. @@ -2430,9 +2431,6 @@ # the final stanza of the DSL is the docstring. def state_function_docstring(self, line): - if not self.function.self_converter: - self.function.self_converter = self_converter("self", self.function) - if self.group: fail("Function " + self.function.name + " has a ] without a matching [.") @@ -2604,6 +2602,9 @@ if not self.function: return + if not self.function.self_converter: + self.function.self_converter = self_converter("self", self.function) + if self.keyword_only: values = self.function.parameters.values() if not values: diff --git a/Tools/clinic/clinic_test.py b/Tools/clinic/clinic_test.py --- a/Tools/clinic/clinic_test.py +++ b/Tools/clinic/clinic_test.py @@ -296,9 +296,9 @@ Perform a stat system call on the given path.""") self.assertEqual(""" +stat(path) Perform a stat system call on the given path. -os.stat(path) path Path to be examined """.strip(), function.docstring) @@ -316,9 +316,9 @@ Okay, we're done here. """) self.assertEqual(""" +bar(x, y) This is the documentation for foo. -foo.bar(x, y) x Documentation for x. @@ -356,7 +356,7 @@ def test_left_group(self): function = self.parse_function(""" module curses -curses.window.addch +curses.addch [ y: int Y-coordinate. @@ -380,7 +380,9 @@ self.assertEqual(p.group, group) self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY) self.assertEqual(function.docstring.strip(), """ -curses.window.addch([y, x,] ch, [attr]) +addch([y, x,] ch, [attr]) + + y Y-coordinate. x @@ -394,7 +396,7 @@ def test_nested_groups(self): function = self.parse_function(""" module curses -curses.window.imaginary +curses.imaginary [ [ y1: int @@ -439,7 +441,9 @@ self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY) self.assertEqual(function.docstring.strip(), """ -curses.window.imaginary([[y1, y2,] x1, x2,] ch, [attr1, attr2, attr3, [attr4, attr5, attr6]]) +imaginary([[y1, y2,] x1, x2,] ch, [attr1, attr2, attr3, [attr4, attr5, attr6]]) + + y1 Y-coordinate. y2 @@ -557,7 +561,7 @@ Docstring """) - self.assertEqual("Docstring\n\nfoo.bar()", function.docstring) + self.assertEqual("bar()\nDocstring", function.docstring) self.assertEqual(0, len(function.parameters)) def test_illegal_module_line(self): @@ -652,9 +656,9 @@ Not at column 0! """) self.assertEqual(""" +bar(x, *, y) Not at column 0! -foo.bar(x, *, y) x Nested docstring here, goeth. """.strip(), function.docstring) @@ -666,7 +670,7 @@ path: str This/used to break Clinic! """) - self.assertEqual("This/used to break Clinic!\n\nos.stat(path)", function.docstring) + self.assertEqual("stat(path)\nThis/used to break Clinic!", function.docstring) def test_directive(self): c = FakeClinic() @@ -692,7 +696,7 @@ def parse_function(self, text): block = self.parse(text) s = block.signatures - assert len(s) == 2 + self.assertEqual(len(s), 2) assert isinstance(s[0], clinic.Module) assert isinstance(s[1], clinic.Function) return s[1] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 5 15:50:40 2014 From: python-checkins at python.org (ethan.furman) Date: Sun, 5 Jan 2014 15:50:40 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbjogSXNzdWUxOTk5NTogJW8sICV4?= =?utf-8?q?=2C_=25X_now_only_accept_ints?= Message-ID: <3dy2pS1Bh2z7Lpy@mail.python.org> http://hg.python.org/cpython/rev/2f81f0e331f6 changeset: 88313:2f81f0e331f6 user: Ethan Furman date: Sun Jan 05 06:50:30 2014 -0800 summary: Issue19995: %o, %x, %X now only accept ints files: Doc/reference/datamodel.rst | 14 +++++++-- Lib/tarfile.py | 2 +- Lib/test/test_format.py | 5 --- Lib/test/test_unicode.py | 29 ++++++++++++++++++++ Misc/NEWS | 4 ++ Objects/unicodeobject.c | 35 +++++++++++++++++++----- 6 files changed, 72 insertions(+), 17 deletions(-) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -2080,9 +2080,17 @@ .. method:: object.__index__(self) - Called to implement :func:`operator.index`. Also called whenever Python needs - an integer object (such as in slicing, or in the built-in :func:`bin`, - :func:`hex` and :func:`oct` functions). Must return an integer. + Called to implement :func:`operator.index`, and whenever Python needs to + losslessly convert the numeric object to an integer object (such as in + slicing, or in the built-in :func:`bin`, :func:`hex` and :func:`oct` + functions). Presence of this method indicates that the numeric object is + an integer type. Must return an integer. + + .. note:: + + When :meth:`__index__` is defined, :meth:`__int__` should also be defined, + and both shuld return the same value, in order to have a coherent integer + type class. .. _context-managers: diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -196,7 +196,7 @@ # A 0o200 byte indicates a positive number, a 0o377 byte a negative # number. if 0 <= n < 8 ** (digits - 1): - s = bytes("%0*o" % (digits - 1, n), "ascii") + NUL + s = bytes("%0*o" % (digits - 1, int(n)), "ascii") + NUL elif format == GNU_FORMAT and -256 ** (digits - 1) <= n < 256 ** (digits - 1): if n >= 0: s = bytearray([0o200]) diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py --- a/Lib/test/test_format.py +++ b/Lib/test/test_format.py @@ -142,7 +142,6 @@ testformat("%#+027.23X", big, "+0X0001234567890ABCDEF12345") # same, except no 0 flag testformat("%#+27.23X", big, " +0X001234567890ABCDEF12345") - testformat("%x", float(big), "123456_______________", 6) big = 0o12345670123456701234567012345670 # 32 octal digits testformat("%o", big, "12345670123456701234567012345670") testformat("%o", -big, "-12345670123456701234567012345670") @@ -182,7 +181,6 @@ testformat("%034.33o", big, "0012345670123456701234567012345670") # base marker shouldn't change that testformat("%0#34.33o", big, "0o012345670123456701234567012345670") - testformat("%o", float(big), "123456__________________________", 6) # Some small ints, in both Python int and flavors). testformat("%d", 42, "42") testformat("%d", -42, "-42") @@ -193,7 +191,6 @@ testformat("%#x", 1, "0x1") testformat("%#X", 1, "0X1") testformat("%#X", 1, "0X1") - testformat("%#x", 1.0, "0x1") testformat("%#o", 1, "0o1") testformat("%#o", 1, "0o1") testformat("%#o", 0, "0o0") @@ -210,12 +207,10 @@ testformat("%x", -0x42, "-42") testformat("%x", 0x42, "42") testformat("%x", -0x42, "-42") - testformat("%x", float(0x42), "42") testformat("%o", 0o42, "42") testformat("%o", -0o42, "-42") testformat("%o", 0o42, "42") testformat("%o", -0o42, "-42") - testformat("%o", float(0o42), "42") testformat("%r", "\u0378", "'\\u0378'") # non printable testformat("%a", "\u0378", "'\\u0378'") # non printable testformat("%r", "\u0374", "'\u0374'") # printable 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 @@ -1126,6 +1126,35 @@ self.assertEqual('%.1s' % "a\xe9\u20ac", 'a') self.assertEqual('%.2s' % "a\xe9\u20ac", 'a\xe9') + #issue 19995 + class PsuedoInt: + def __init__(self, value): + self.value = int(value) + def __int__(self): + return self.value + def __index__(self): + return self.value + class PsuedoFloat: + def __init__(self, value): + self.value = float(value) + def __int__(self): + return int(self.value) + pi = PsuedoFloat(3.1415) + letter_m = PsuedoInt(109) + self.assertEquals('%x' % 42, '2a') + self.assertEquals('%X' % 15, 'F') + self.assertEquals('%o' % 9, '11') + self.assertEquals('%c' % 109, 'm') + self.assertEquals('%x' % letter_m, '6d') + self.assertEquals('%X' % letter_m, '6D') + self.assertEquals('%o' % letter_m, '155') + self.assertEquals('%c' % letter_m, 'm') + self.assertRaises(TypeError, '%x'.__mod__, pi) + self.assertRaises(TypeError, '%x'.__mod__, 3.14) + self.assertRaises(TypeError, '%X'.__mod__, 2.11) + self.assertRaises(TypeError, '%o'.__mod__, 1.79) + self.assertRaises(TypeError, '%c'.__mod__, pi) + def test_formatting_with_enum(self): # issue18780 import enum diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,10 @@ - Issue #19969: PyBytes_FromFormatV() now raises an OverflowError if "%c" argument is not in range [0; 255]. +- Issue #19995: %c, %o, %x, and %X now raise TypeError on non-integer input; + reworded docs to clarify that an integer type should define both __int__ + and __index__. + - Issue #19787: PyThread_set_key_value() now always set the value. In Python 3.3, the function did nothing if the key already exists (if the current value is a non-NULL pointer). diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13988,7 +13988,7 @@ return result; } -/* Format an integer. +/* Format an integer or a float as an integer. * Return 1 if the number has been formatted into the writer, * 0 if the number has been formatted into *p_output * -1 and raise an exception on error */ @@ -14005,11 +14005,19 @@ goto wrongtype; if (!PyLong_Check(v)) { - iobj = PyNumber_Long(v); - if (iobj == NULL) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) - goto wrongtype; - return -1; + if (type == 'o' || type == 'x' || type == 'X') { + iobj = PyNumber_Index(v); + if (iobj == NULL) { + return -1; + } + } + else { + iobj = PyNumber_Long(v); + if (iobj == NULL ) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + goto wrongtype; + return -1; + } } assert(PyLong_Check(iobj)); } @@ -14079,8 +14087,18 @@ goto onError; } else { + PyObject *iobj; + long x; + /* make sure number is a type of integer */ + if (!PyLong_Check(v)) { + iobj = PyNumber_Index(v); + if (iobj == NULL) { + goto onError; + } + v = iobj; + Py_DECREF(iobj); + } /* Integer input truncated to a character */ - long x; x = PyLong_AsLong(v); if (x == -1 && PyErr_Occurred()) goto onError; @@ -14282,7 +14300,8 @@ /* Format one argument. Supported conversion specifiers: - "s", "r", "a": any type - - "i", "d", "u", "o", "x", "X": int + - "i", "d", "u": int or float + - "o", "x", "X": int - "e", "E", "f", "F", "g", "G": float - "c": int or str (1 character) -- Repository URL: http://hg.python.org/cpython From root at python.org Sun Jan 5 16:55:23 2014 From: root at python.org (Cron Daemon) Date: Sun, 05 Jan 2014 16:55:23 +0100 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: abort: error: Connection timed out From root at python.org Sun Jan 5 17:00:24 2014 From: root at python.org (Cron Daemon) Date: Sun, 05 Jan 2014 17:00:24 +0100 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: abort: error: Connection timed out From python-checkins at python.org Sun Jan 5 21:00:37 2014 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 5 Jan 2014 21:00:37 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_comments_to_frozenset?= =?utf-8?b?X2hhc2goKS4=?= Message-ID: <3dy9h56lFnz7LqG@mail.python.org> http://hg.python.org/cpython/rev/247f12fecf2b changeset: 88314:247f12fecf2b user: Raymond Hettinger date: Sun Jan 05 12:00:31 2014 -0800 summary: Add comments to frozenset_hash(). Also, provide a minor hint to the compiler on how to group the xors. files: Objects/setobject.c | 15 ++++++++++++++- 1 files changed, 14 insertions(+), 1 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -738,6 +738,17 @@ static Py_hash_t frozenset_hash(PyObject *self) { + /* Most of the constants in this hash algorithm are randomly choosen + large primes with "interesting bit patterns" and that passed + tests for good collision statistics on a variety of problematic + datasets such as: + + ps = [] + for r in range(21): + ps += itertools.combinations(range(20), r) + num_distinct_hashes = len({hash(frozenset(s)) for s in ps}) + + */ PySetObject *so = (PySetObject *)self; Py_uhash_t h, hash = 1927868237UL; setentry *entry; @@ -754,8 +765,10 @@ hashes so that many distinct combinations collapse to only a handful of distinct hash values. */ h = entry->hash; - hash ^= (h ^ (h << 16) ^ 89869747UL) * 3644798167UL; + hash ^= ((h ^ 89869747UL) ^ (h << 16)) * 3644798167UL; } + /* Make the final result spread-out in a different pattern + than the algorithem for tuples or other python objects. */ hash = hash * 69069U + 907133923UL; if (hash == -1) hash = 590923713UL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 5 21:39:41 2014 From: python-checkins at python.org (r.david.murray) Date: Sun, 5 Jan 2014 21:39:41 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzEwNjU5ODY6IE1h?= =?utf-8?q?ke_pydoc_handle_unicode_strings=2E?= Message-ID: <3dyBY915mFz7LjP@mail.python.org> http://hg.python.org/cpython/rev/bf077fc97fdd changeset: 88315:bf077fc97fdd branch: 2.7 parent: 88286:d7ae948d9eee user: R David Murray date: Sun Jan 05 12:35:59 2014 -0500 summary: #1065986: Make pydoc handle unicode strings. Patch by Akira Kitada. files: Lib/pydoc.py | 58 ++++++++++++++---- Lib/test/test_pydoc.py | 91 ++++++++++++++++++++++++++++++ Misc/NEWS | 2 + 3 files changed, 137 insertions(+), 14 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -81,6 +81,7 @@ def getdoc(object): """Get the doc string or comments for an object.""" result = inspect.getdoc(object) or inspect.getcomments(object) + result = _encode(result) return result and re.sub('^ *\n', '', rstrip(result)) or '' def splitdoc(doc): @@ -182,6 +183,34 @@ return name, kind, cls, value return map(fixup, inspect.classify_class_attrs(object)) +# ----------------------------------------------------- Unicode support helpers + +try: + _unicode = unicode +except NameError: + # If Python is built without Unicode support, the unicode type + # will not exist. Fake one that nothing will match, and make + # the _encode function that do nothing. + class _unicode(object): + pass + _encoding = 'ascii' + def _encode(text, encoding='ascii'): + return text +else: + import locale + _encoding = locale.getpreferredencoding() + + def _encode(text, encoding=None): + if isinstance(text, unicode): + return text.encode(encoding or _encoding, 'xmlcharrefreplace') + else: + return text + +def _binstr(obj): + # Ensure that we have an encoded (binary) string representation of obj, + # even if it is a unicode string. + return obj.encode(_encoding) if isinstance(obj, _unicode) else str(obj) + # ----------------------------------------------------- module manipulation def ispackage(path): @@ -424,12 +453,13 @@ def page(self, title, contents): """Format an HTML page.""" - return ''' + return _encode(''' Python: %s + %s -''' % (title, contents) +''' % (title, contents), 'ascii') def heading(self, title, fgcol, bgcol, extras=''): """Format a page heading.""" @@ -606,12 +636,12 @@ filelink = '(built-in)' info = [] if hasattr(object, '__version__'): - version = str(object.__version__) + version = _binstr(object.__version__) if version[:11] == '$' + 'Revision: ' and version[-1:] == '$': version = strip(version[11:-1]) info.append('version %s' % self.escape(version)) if hasattr(object, '__date__'): - info.append(self.escape(str(object.__date__))) + info.append(self.escape(_binstr(object.__date__))) if info: head = head + ' (%s)' % join(info, ', ') docloc = self.getdocloc(object) @@ -694,11 +724,11 @@ result = result + self.bigsection( 'Data', '#ffffff', '#55aa55', join(contents, '
\n')) if hasattr(object, '__author__'): - contents = self.markup(str(object.__author__), self.preformat) + contents = self.markup(_binstr(object.__author__), self.preformat) result = result + self.bigsection( 'Author', '#ffffff', '#7799ee', contents) if hasattr(object, '__credits__'): - contents = self.markup(str(object.__credits__), self.preformat) + contents = self.markup(_binstr(object.__credits__), self.preformat) result = result + self.bigsection( 'Credits', '#ffffff', '#7799ee', contents) @@ -1116,16 +1146,16 @@ result = result + self.section('DATA', join(contents, '\n')) if hasattr(object, '__version__'): - version = str(object.__version__) + version = _binstr(object.__version__) if version[:11] == '$' + 'Revision: ' and version[-1:] == '$': version = strip(version[11:-1]) result = result + self.section('VERSION', version) if hasattr(object, '__date__'): - result = result + self.section('DATE', str(object.__date__)) + result = result + self.section('DATE', _binstr(object.__date__)) if hasattr(object, '__author__'): - result = result + self.section('AUTHOR', str(object.__author__)) + result = result + self.section('AUTHOR', _binstr(object.__author__)) if hasattr(object, '__credits__'): - result = result + self.section('CREDITS', str(object.__credits__)) + result = result + self.section('CREDITS', _binstr(object.__credits__)) return result def docclass(self, object, name=None, mod=None, *ignored): @@ -1375,7 +1405,7 @@ """Page through text by feeding it to another program.""" pipe = os.popen(cmd, 'w') try: - pipe.write(text) + pipe.write(_encode(text)) pipe.close() except IOError: pass # Ignore broken pipes caused by quitting the pager program. @@ -1385,7 +1415,7 @@ import tempfile filename = tempfile.mktemp() file = open(filename, 'w') - file.write(text) + file.write(_encode(text)) file.close() try: os.system(cmd + ' "' + filename + '"') @@ -1394,7 +1424,7 @@ def ttypager(text): """Page through text on a text terminal.""" - lines = split(plain(text), '\n') + lines = plain(_encode(plain(text), getattr(sys.stdout, 'encoding', _encoding))).split('\n') try: import tty fd = sys.stdin.fileno() @@ -1432,7 +1462,7 @@ def plainpager(text): """Simply print unformatted text. This is the ultimate fallback.""" - sys.stdout.write(plain(text)) + sys.stdout.write(_encode(plain(text), getattr(sys.stdout, 'encoding', _encoding))) def describe(thing): """Produce a short description of the given thing.""" 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 @@ -10,6 +10,7 @@ import pkgutil import unittest import xml.etree +import types import test.test_support from collections import namedtuple from test.script_helper import assert_python_ok @@ -428,6 +429,95 @@ self.assertIn('_asdict', helptext) + at unittest.skipUnless(test.test_support.have_unicode, + "test requires unicode support") +class TestUnicode(unittest.TestCase): + + def setUp(self): + # Better not to use unicode escapes in literals, lest the + # parser choke on it if Python has been built without + # unicode support. + self.Q = types.ModuleType( + 'Q', 'Rational numbers: \xe2\x84\x9a'.decode('utf8')) + self.Q.__version__ = '\xe2\x84\x9a'.decode('utf8') + self.Q.__date__ = '\xe2\x84\x9a'.decode('utf8') + self.Q.__author__ = '\xe2\x84\x9a'.decode('utf8') + self.Q.__credits__ = '\xe2\x84\x9a'.decode('utf8') + + self.assertIsInstance(self.Q.__doc__, unicode) + + def test_render_doc(self): + # render_doc is robust against unicode in docstrings + doc = pydoc.render_doc(self.Q) + self.assertIsInstance(doc, str) + + def test_encode(self): + # _encode is robust against characters out the specified encoding + self.assertEqual(pydoc._encode(self.Q.__doc__, 'ascii'), 'Rational numbers: ℚ') + + def test_pipepager(self): + # pipepager does not choke on unicode + doc = pydoc.render_doc(self.Q) + + saved, os.popen = os.popen, open + try: + with test.test_support.temp_cwd(): + pydoc.pipepager(doc, 'pipe') + self.assertEqual(open('pipe').read(), pydoc._encode(doc)) + finally: + os.popen = saved + + def test_tempfilepager(self): + # tempfilepager does not choke on unicode + doc = pydoc.render_doc(self.Q) + + output = {} + def mock_system(cmd): + import ast + output['content'] = open(ast.literal_eval(cmd.strip())).read() + saved, os.system = os.system, mock_system + try: + pydoc.tempfilepager(doc, '') + self.assertEqual(output['content'], pydoc._encode(doc)) + finally: + os.system = saved + + def test_plainpager(self): + # plainpager does not choke on unicode + doc = pydoc.render_doc(self.Q) + + # Note: captured_stdout is too permissive when it comes to + # unicode, and using it here would make the test always + # pass. + with test.test_support.temp_cwd(): + with open('output', 'w') as f: + saved, sys.stdout = sys.stdout, f + try: + pydoc.plainpager(doc) + finally: + sys.stdout = saved + self.assertIn('Rational numbers:', open('output').read()) + + def test_ttypager(self): + # ttypager does not choke on unicode + doc = pydoc.render_doc(self.Q) + # Test ttypager + with test.test_support.temp_cwd(), test.test_support.captured_stdin(): + with open('output', 'w') as f: + saved, sys.stdout = sys.stdout, f + try: + pydoc.ttypager(doc) + finally: + sys.stdout = saved + self.assertIn('Rational numbers:', open('output').read()) + + def test_htmlpage(self): + # html.page does not choke on unicode + with test.test_support.temp_cwd(): + with captured_stdout() as output: + pydoc.writedoc(self.Q) + self.assertEqual(output.getvalue(), 'wrote Q.html\n') + class TestHelper(unittest.TestCase): def test_keywords(self): self.assertEqual(sorted(pydoc.Helper.keywords), @@ -456,6 +546,7 @@ test.test_support.run_unittest(PydocDocTest, PydocImportTest, TestDescriptions, + TestUnicode, TestHelper) finally: reap_children() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,8 @@ Library ------- +- Issue #1065986: pydoc can now handle unicode strings. + - Issue #16039: CVE-2013-1752: Change use of readline in imaplib module to limit line length. Patch by Emil Lind. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 5 23:14:27 2014 From: python-checkins at python.org (r.david.murray) Date: Sun, 5 Jan 2014 23:14:27 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzEwNjU5ODY6IGFk?= =?utf-8?q?d_missing_error_handler_in_pydoc_unicode_fix=2E?= Message-ID: <3dyDfW5wYtz7Lr2@mail.python.org> http://hg.python.org/cpython/rev/e57660acc6d4 changeset: 88316:e57660acc6d4 branch: 2.7 user: R David Murray date: Sun Jan 05 17:14:08 2014 -0500 summary: #1065986: add missing error handler in pydoc unicode fix. files: Lib/pydoc.py | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -209,7 +209,9 @@ def _binstr(obj): # Ensure that we have an encoded (binary) string representation of obj, # even if it is a unicode string. - return obj.encode(_encoding) if isinstance(obj, _unicode) else str(obj) + if isinstance(obj, _unicode): + return obj.encode(_encoding, 'xmlcharrefreplace') + return str(obj) # ----------------------------------------------------- module manipulation -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon Jan 6 09:47:25 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 06 Jan 2014 09:47:25 +0100 Subject: [Python-checkins] Daily reference leaks (247f12fecf2b): sum=3 Message-ID: results for 247f12fecf2b on branch "default" -------------------------------------------- test_audioop leaked [1, 1, 1] references, sum=3 test_site leaked [2, -2, 0] references, sum=0 test_site leaked [2, -2, 0] memory blocks, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogU8DXuf', '-x'] From python-checkins at python.org Mon Jan 6 11:53:12 2014 From: python-checkins at python.org (victor.stinner) Date: Mon, 6 Jan 2014 11:53:12 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Rename_pep-0466/_to_pep-0446/?= Message-ID: <3dyYV04lk1z7Ljw@mail.python.org> http://hg.python.org/peps/rev/caedc2aa99b6 changeset: 5336:caedc2aa99b6 user: Victor Stinner date: Mon Jan 06 11:53:05 2014 +0100 summary: Rename pep-0466/ to pep-0446/ files: pep-0466/test_cloexec.py | 0 1 files changed, 0 insertions(+), 0 deletions(-) diff --git a/pep-0466/test_cloexec.py b/pep-0446/test_cloexec.py rename from pep-0466/test_cloexec.py rename to pep-0446/test_cloexec.py -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jan 6 14:19:10 2014 From: python-checkins at python.org (victor.stinner) Date: Mon, 6 Jan 2014 14:19:10 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Create_PEP_460_=22Add_bytes_?= =?utf-8?q?=25_args_and_bytes=2Eformat=28args=29_to_Python_3=2E5=22?= Message-ID: <3dyckQ324Hz7LjN@mail.python.org> http://hg.python.org/peps/rev/7a92360bbdff changeset: 5337:7a92360bbdff user: Victor Stinner date: Mon Jan 06 14:01:09 2014 +0100 summary: Create PEP 460 "Add bytes % args and bytes.format(args) to Python 3.5" files: pep-0460.txt | 175 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 175 insertions(+), 0 deletions(-) diff --git a/pep-0460.txt b/pep-0460.txt new file mode 100644 --- /dev/null +++ b/pep-0460.txt @@ -0,0 +1,175 @@ +PEP: 460 +Title: Add bytes % args and bytes.format(args) to Python 3.5 +Version: $Revision$ +Last-Modified: $Date$ +Author: Victor Stinner +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 6-Jan-2014 +Python-Version: 3.5 + + +Abstract +======== + +Add ``bytes % args`` operator and ``bytes.format(args)`` method to +Python 3.5. + + +Rationale +========= + +``bytes % args`` and ``bytes.format(args)`` have been removed in Python +2. This operator and this method are requested by Mercurial and Twisted +developers to ease porting their project on Python 3. + +Python 3 suggests to format text first and then encode to bytes. In +some cases, it does not make sense because arguments are bytes strings. +Typical usage is a network protocol which is binary, since data are +send to and received from sockets. For example, SMTP, SIP, HTTP, IMAP, +POP, FTP are ASCII commands interspersed with binary data. + +Using multiple ``bytes + bytes`` instructions is inefficient because it +requires temporary buffers and copies which are slow and waste memory. +Python 3.3 optimizes ``str2 += str2`` but not ``bytes2 += bytes1``. + +``bytes % args`` and ``bytes.format(args)`` were asked since 2008, even +before the first release of Python 3.0 (see issue #3982). + +``struct.pack()`` is incomplete. For example, a number cannot be +formatted as decimal and it does not support padding bytes string. + +Mercurial 2.8 still supports Python 2.4. + + +Needed and excluded features +============================ + +Needed features + +* Bytes strings: bytes, bytearray and memoryview types +* Format integer numbers as decimal +* Padding with spaces and null bytes +* "%s" should use the buffer protocol, not str() + +The feature set is minimal to keep the implementation as simple as +possible to limit the cost of the implementation. ``str % args`` and +``str.format(args)`` are already complex and difficult to maintain, the +code is heavily optimized. + +Excluded features: + +* no implicit conversion from Unicode to bytes (ex: encode to ASCII or + to Latin1) +* Locale support (``{!n}`` format for numbers). Locales are related to + text and usually to an encoding. +* ``repr()``, ``ascii()``: ``%r``, ``{!r}``, ``%a`` and ``{!a}`` + formats. ``repr()`` and ``ascii()`` are used to debug, the output is + displayed a terminal or a graphical widget. They are more related to + text. +* Attribute access: ``{obj.attr}`` +* Indexing: ``{dict[key]}`` +* Features of struct.pack(). For example, format a number as 32 bit unsigned + integer in network endian. The ``struct.pack()`` can be used to prepare + arguments, the implementation should be kept simple. +* Features of int.to_bytes(). +* Features of ctypes. +* New format protocol like a new ``__bformat__()`` method. Since the +* list of + supported types is short, there is no need to add a new protocol. + Other types must be explicitly casted. +* Alternate format for integer. For example, ``'{|#x}'.format(0x123)`` + to get ``0x123``. It is more related to debug, and the prefix can be + easily be written in the format string (ex: ``0x%x``). +* Relation with format() and the __format__() protocol. bytes.format() + and str.format() are unrelated. + +Unknown: + +* Format integer to hexadecimal? ``%x`` and ``%X`` +* Format integer to octal? ``%o`` +* Format integer to binary? ``{!b}`` +* Alignment? +* Truncating? Truncate or raise an error? +* format keywords? ``b'{arg}'.format(arg=5)`` +* ``str % dict`` ? ``b'%(arg)s' % {'arg': 5)`` +* Floating point number? +* ``%i``, ``%u`` and ``%d`` formats for integer numbers? +* Signed number? ``%+i`` and ``%-i`` + + +bytes % args +============ + +Formatters: + +* ``"%c"``: one byte +* ``"%s"``: integer or bytes strings +* ``"%20s"`` pads to 20 bytes with spaces (``b' '``) +* ``"%020s"`` pads to 20 bytes with zeros (``b'0'``) +* ``"%\020s"`` pads to 20 bytes with null bytes (``b'\0'``) + + +bytes.format(args) +================== + +Formatters: + +* ``"{!c}"``: one byte +* ``"{!s}"``: integer or bytes strings +* ``"{!.20s}"`` pads to 20 bytes with spaces (``b' '``) +* ``"{!.020s}"`` pads to 20 bytes with zeros (``b'0'``) +* ``"{!\020s}"`` pads to 20 bytes with null bytes (``b'\0'``) + + +Examples +======== + +* ``b'a%sc%s' % (b'b', 4)`` gives ``b'abc4'`` +* ``b'a{}c{}'.format(b'b', 4)`` gives ``b'abc4'`` +* ``b'%c'`` % 88`` gives ``b'X``' +* ``b'%%'`` gives ``b'%'`` + + +Criticisms +========== + +* The development cost and maintenance cost. +* In 3.3 encoding to ascii or latin1 is as fast as memcpy +* Developers must work around the lack of bytes%args and + bytes.format(args) anyway to support Python 3.0-3.4 +* bytes.join() is consistently faster than format to join bytes strings. +* Formatting functions can be implemented in a third party module + + +References +========== + +* `Issue #3982: support .format for bytes + `_ +* `Mercurial project + `_ +* `Twisted project + `_ +* `Documentation of Python 2 formatting (str % args) + `_ +* `Documentation of Python 2 formatting (str.format) + `_ + +Copyright +========= + +This document has been placed in the public domain. + + + +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + coding: utf-8 + End: + -- Repository URL: http://hg.python.org/peps From ncoghlan at gmail.com Mon Jan 6 16:22:21 2014 From: ncoghlan at gmail.com (Nick Coghlan) Date: Tue, 7 Jan 2014 01:22:21 +1000 Subject: [Python-checkins] cpython: whatsnew: XMLPullParser, plus some doc updates. In-Reply-To: <3dxnZS1P8vz7Lmc@mail.python.org> References: <3dxnZS1P8vz7Lmc@mail.python.org> Message-ID: On 5 Jan 2014 12:54, "r.david.murray" wrote: > > http://hg.python.org/cpython/rev/069f88f4935f > changeset: 88308:069f88f4935f > user: R David Murray > date: Sat Jan 04 23:52:50 2014 -0500 > summary: > whatsnew: XMLPullParser, plus some doc updates. > > I was confused by the text saying that read_events "iterated", since it > actually returns an iterator (that's what a generator does) that the > caller must then iterate. So I tidied up the language. I'm not sure > what the sentence "Events provided in a previous call to read_events() > will not be yielded again." is trying to convey, so I didn't try to fix that. It's a mutating API - once the events have been retrieved, that's it, they're gone from the internal state. Suggestions for wording improvements welcome :) Cheers, Nick. > > Also fixed a couple more news items. > > files: > Doc/library/xml.etree.elementtree.rst | 23 +++++++++----- > Doc/whatsnew/3.4.rst | 7 ++- > Lib/xml/etree/ElementTree.py | 2 +- > Misc/NEWS | 12 +++--- > 4 files changed, 25 insertions(+), 19 deletions(-) > > > diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst > --- a/Doc/library/xml.etree.elementtree.rst > +++ b/Doc/library/xml.etree.elementtree.rst > @@ -105,12 +105,15 @@ > >>> root[0][1].text > '2008' > > + > +.. _elementtree-pull-parsing: > + > Pull API for non-blocking parsing > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > > -Most parsing functions provided by this module require to read the whole > -document at once before returning any result. It is possible to use a > -:class:`XMLParser` and feed data into it incrementally, but it's a push API that > +Most parsing functions provided by this module require the whole document > +to be read at once before returning any result. It is possible to use an > +:class:`XMLParser` and feed data into it incrementally, but it is a push API that > calls methods on a callback target, which is too low-level and inconvenient for > most needs. Sometimes what the user really wants is to be able to parse XML > incrementally, without blocking operations, while enjoying the convenience of > @@ -119,7 +122,7 @@ > The most powerful tool for doing this is :class:`XMLPullParser`. It does not > require a blocking read to obtain the XML data, and is instead fed with data > incrementally with :meth:`XMLPullParser.feed` calls. To get the parsed XML > -elements, call :meth:`XMLPullParser.read_events`. Here's an example:: > +elements, call :meth:`XMLPullParser.read_events`. Here is an example:: > > >>> parser = ET.XMLPullParser(['start', 'end']) > >>> parser.feed('sometext') > @@ -1038,15 +1041,17 @@ > > .. method:: read_events() > > - Iterate over the events which have been encountered in the data fed to the > - parser. This method yields ``(event, elem)`` pairs, where *event* is a > + Return an iterator over the events which have been encountered in the > + data fed to the > + parser. The iterator yields ``(event, elem)`` pairs, where *event* is a > string representing the type of event (e.g. ``"end"``) and *elem* is the > encountered :class:`Element` object. > > Events provided in a previous call to :meth:`read_events` will not be > - yielded again. As events are consumed from the internal queue only as > - they are retrieved from the iterator, multiple readers calling > - :meth:`read_events` in parallel will have unpredictable results. > + yielded again. Events are consumed from the internal queue only when > + they are retrieved from the iterator, so multiple readers iterating in > + parallel over iterators obtained from :meth:`read_events` will have > + unpredictable results. > > .. note:: > > 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 > @@ -1088,9 +1088,10 @@ > xml.etree > --------- > > -Add an event-driven parser for non-blocking applications, > -:class:`~xml.etree.ElementTree.XMLPullParser`. > -(Contributed by Antoine Pitrou in :issue:`17741`.) > +A new parser, :class:`~xml.etree.ElementTree.XMLPullParser`, allows a > +non-blocking applications to parse XML documents. An example can be > +seen at :ref:`elementtree-pull-parsing`. (Contributed by Antoine > +Pitrou in :issue:`17741`.) > > The :mod:`xml.etree.ElementTree` :func:`~xml.etree.ElementTree.tostring` and > :func:`~xml.etree.ElementTree.tostringlist` functions, and the > diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py > --- a/Lib/xml/etree/ElementTree.py > +++ b/Lib/xml/etree/ElementTree.py > @@ -1251,7 +1251,7 @@ > self._close_and_return_root() > > def read_events(self): > - """Iterate over currently available (event, elem) pairs. > + """Return an iterator over currently available (event, elem) pairs. > > Events are consumed from the internal event queue as they are > retrieved from the iterator. > diff --git a/Misc/NEWS b/Misc/NEWS > --- a/Misc/NEWS > +++ b/Misc/NEWS > @@ -2193,14 +2193,14 @@ > - Issue #17555: Fix ForkAwareThreadLock so that size of after fork > registry does not grow exponentially with generation of process. > > -- Issue #17707: multiprocessing.Queue's get() method does not block for short > - timeouts. > - > -- Isuse #17720: Fix the Python implementation of pickle.Unpickler to correctly > +- Issue #17707: fix regression in multiprocessing.Queue's get() method where > + it did not block for short timeouts. > + > +- Issue #17720: Fix the Python implementation of pickle.Unpickler to correctly > process the APPENDS opcode when it is used on non-list objects. > > -- Issue #17012: shutil.which() no longer fallbacks to the PATH environment > - variable if empty path argument is specified. Patch by Serhiy Storchaka. > +- Issue #17012: shutil.which() no longer falls back to the PATH environment > + variable if an empty path argument is specified. Patch by Serhiy Storchaka. > > - Issue #17710: Fix pickle raising a SystemError on bogus input. > > > -- > Repository URL: http://hg.python.org/cpython > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > https://mail.python.org/mailman/listinfo/python-checkins > -------------- next part -------------- An HTML attachment was scrubbed... URL: From python-checkins at python.org Mon Jan 6 16:24:48 2014 From: python-checkins at python.org (larry.hastings) Date: Mon, 6 Jan 2014 16:24:48 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Regenerated_pydoc/topics?= =?utf-8?q?=2Epy=2C_and_fix_a_=22suspicious=22_doc_error=2E?= Message-ID: <3dygWN1B3HzT0F@mail.python.org> http://hg.python.org/cpython/rev/f2a958c80485 changeset: 88317:f2a958c80485 parent: 88312:172a6bfdd91b user: Larry Hastings date: Sun Jan 05 04:35:56 2014 -0800 summary: Regenerated pydoc/topics.py, and fix a "suspicious" doc error. files: Doc/reference/import.rst | 2 +- Lib/pydoc_data/topics.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -440,7 +440,7 @@ For compatibility with existing loaders, the import machinery will use the ``load_module()`` method of loaders if it exists and the loader does - not also implement ``exec_module(). However, ``load_module()`` has been + not also implement ``exec_module()``. However, ``load_module()`` has been deprecated and loaders should implement ``exec_module()`` instead. The ``load_module()`` method must implement all the boilerplate loading 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,10 +1,10 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Sun Nov 24 06:50:34 2013 +# Autogenerated by Sphinx on Sun Jan 5 04:33:19 2014 topics = {'assert': '\nThe ``assert`` statement\n************************\n\nAssert statements are a convenient way to insert debugging assertions\ninto a program:\n\n assert_stmt ::= "assert" expression ["," expression]\n\nThe simple form, ``assert expression``, is equivalent to\n\n if __debug__:\n if not expression: raise AssertionError\n\nThe extended form, ``assert expression1, expression2``, is equivalent\nto\n\n if __debug__:\n if not expression1: raise AssertionError(expression2)\n\nThese equivalences assume that ``__debug__`` and ``AssertionError``\nrefer to the built-in variables with those names. In the current\nimplementation, the built-in variable ``__debug__`` is ``True`` under\nnormal circumstances, ``False`` when optimization is requested\n(command line option -O). The current code generator emits no code\nfor an assert statement when optimization is requested at compile\ntime. Note that it is unnecessary to include the source code for the\nexpression that failed in the error message; it will be displayed as\npart of the stack trace.\n\nAssignments to ``__debug__`` are illegal. The value for the built-in\nvariable is determined when the interpreter starts.\n', 'assignment': '\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The object\n must be an iterable with the same number of items as there are\n targets in the target list, and the items are assigned, from left to\n right, to the corresponding targets.\n\n * If the target list contains one target prefixed with an asterisk,\n called a "starred" target: The object must be a sequence with at\n least as many items as there are targets in the target list, minus\n one. The first items of the sequence are assigned, from left to\n right, to the targets before the starred target. The final items\n of the sequence are assigned to the targets after the starred\n target. A list of the remaining items in the sequence is then\n assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of items\n as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a ``global`` or ``nonlocal``\n statement in the current code block: the name is bound to the\n object in the current local namespace.\n\n * Otherwise: the name is bound to the object in the global namespace\n or the outer namespace determined by ``nonlocal``, respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in square\n brackets: The object must be an iterable with the same number of\n items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, ``TypeError`` is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily ``AttributeError``).\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n ``a.x`` can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target ``a.x`` is\n always set as an instance attribute, creating it if necessary.\n Thus, the two occurrences of ``a.x`` do not necessarily refer to the\n same attribute: if the RHS expression refers to a class attribute,\n the LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with ``property()``.\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, ``IndexError`` is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the ``__setitem__()`` method is called\n with appropriate arguments.\n\n* If the target is a slicing: The primary expression in the reference\n is evaluated. It should yield a mutable sequence object (such as a\n list). The assigned object should be a sequence object of the same\n type. Next, the lower and upper bound expressions are evaluated,\n insofar they are present; defaults are zero and the sequence\'s\n length. The bounds should evaluate to integers. If either bound is\n negative, the sequence\'s length is added to it. The resulting\n bounds are clipped to lie between zero and the sequence\'s length,\n inclusive. Finally, the sequence object is asked to replace the\n slice with the items of the assigned sequence. The length of the\n slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the object\n allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nWARNING: Although the definition of assignment implies that overlaps\nbetween the left-hand side and the right-hand side are \'safe\' (for\nexample ``a, b = b, a`` swaps two variables), overlaps *within* the\ncollection of assigned-to variables are not safe! For instance, the\nfollowing program prints ``[0, 2]``:\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2\n print(x)\n\nSee also:\n\n **PEP 3132** - Extended Iterable Unpacking\n The specification for the ``*target`` feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', 'atom-identifiers': '\nIdentifiers (Names)\n*******************\n\nAn identifier occurring as an atom is a name. See section\n*Identifiers and keywords* for lexical definition and section *Naming\nand binding* for documentation of naming and binding.\n\nWhen the name is bound to an object, evaluation of the atom yields\nthat object. When a name is not bound, an attempt to evaluate it\nraises a ``NameError`` exception.\n\n**Private name mangling:** When an identifier that textually occurs in\na class definition begins with two or more underscore characters and\ndoes not end in two or more underscores, it is considered a *private\nname* of that class. Private names are transformed to a longer form\nbefore code is generated for them. The transformation inserts the\nclass name, with leading underscores removed and a single underscore\ninserted, in front of the name. For example, the identifier\n``__spam`` occurring in a class named ``Ham`` will be transformed to\n``_Ham__spam``. This transformation is independent of the syntactical\ncontext in which the identifier is used. If the transformed name is\nextremely long (longer than 255 characters), implementation defined\ntruncation may happen. If the class name consists only of underscores,\nno transformation is done.\n', 'atom-literals': "\nLiterals\n********\n\nPython supports string and bytes literals and various numeric\nliterals:\n\n literal ::= stringliteral | bytesliteral\n | integer | floatnumber | imagnumber\n\nEvaluation of a literal yields an object of the given type (string,\nbytes, integer, floating point number, complex number) with the given\nvalue. The value may be approximated in the case of floating point\nand imaginary (complex) literals. See section *Literals* for details.\n\nAll literals correspond to immutable data types, and hence the\nobject's identity is less important than its value. Multiple\nevaluations of literals with the same value (either the same\noccurrence in the program text or a different occurrence) may obtain\nthe same object or a different object with the same value.\n", - 'attribute-access': '\nCustomizing attribute access\n****************************\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A sequence must be\n returned. ``dir()`` converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n========================\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n====================\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n=========\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n--------------------------\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n', + 'attribute-access': '\nCustomizing attribute access\n****************************\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A sequence must be\n returned. ``dir()`` converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n========================\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n====================\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n=========\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n--------------------------\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``bytes`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n', 'attribute-references': '\nAttribute references\n********************\n\nAn attribute reference is a primary followed by a period and a name:\n\n attributeref ::= primary "." identifier\n\nThe primary must evaluate to an object of a type that supports\nattribute references, which most objects do. This object is then\nasked to produce the attribute whose name is the identifier (which can\nbe customized by overriding the ``__getattr__()`` method). If this\nattribute is not available, the exception ``AttributeError`` is\nraised. Otherwise, the type and value of the object produced is\ndetermined by the object. Multiple evaluations of the same attribute\nreference may yield different objects.\n', 'augassign': '\nAugmented assignment statements\n*******************************\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', 'binary': '\nBinary arithmetic operations\n****************************\n\nThe binary arithmetic operations have the conventional priority\nlevels. Note that some of these operations also apply to certain non-\nnumeric types. Apart from the power operator, there are only two\nlevels, one for multiplicative operators and one for additive\noperators:\n\n m_expr ::= u_expr | m_expr "*" u_expr | m_expr "//" u_expr | m_expr "/" u_expr\n | m_expr "%" u_expr\n a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr\n\nThe ``*`` (multiplication) operator yields the product of its\narguments. The arguments must either both be numbers, or one argument\nmust be an integer and the other must be a sequence. In the former\ncase, the numbers are converted to a common type and then multiplied\ntogether. In the latter case, sequence repetition is performed; a\nnegative repetition factor yields an empty sequence.\n\nThe ``/`` (division) and ``//`` (floor division) operators yield the\nquotient of their arguments. The numeric arguments are first\nconverted to a common type. Division of integers yields a float, while\nfloor division of integers results in an integer; the result is that\nof mathematical division with the \'floor\' function applied to the\nresult. Division by zero raises the ``ZeroDivisionError`` exception.\n\nThe ``%`` (modulo) operator yields the remainder from the division of\nthe first argument by the second. The numeric arguments are first\nconverted to a common type. A zero right argument raises the\n``ZeroDivisionError`` exception. The arguments may be floating point\nnumbers, e.g., ``3.14%0.7`` equals ``0.34`` (since ``3.14`` equals\n``4*0.7 + 0.34``.) The modulo operator always yields a result with\nthe same sign as its second operand (or zero); the absolute value of\nthe result is strictly smaller than the absolute value of the second\noperand [1].\n\nThe floor division and modulo operators are connected by the following\nidentity: ``x == (x//y)*y + (x%y)``. Floor division and modulo are\nalso connected with the built-in function ``divmod()``: ``divmod(x, y)\n== (x//y, x%y)``. [2].\n\nIn addition to performing the modulo operation on numbers, the ``%``\noperator is also overloaded by string objects to perform old-style\nstring formatting (also known as interpolation). The syntax for\nstring formatting is described in the Python Library Reference,\nsection *printf-style String Formatting*.\n\nThe floor division operator, the modulo operator, and the ``divmod()``\nfunction are not defined for complex numbers. Instead, convert to a\nfloating point number using the ``abs()`` function if appropriate.\n\nThe ``+`` (addition) operator yields the sum of its arguments. The\narguments must either both be numbers or both sequences of the same\ntype. In the former case, the numbers are converted to a common type\nand then added together. In the latter case, the sequences are\nconcatenated.\n\nThe ``-`` (subtraction) operator yields the difference of its\narguments. The numeric arguments are first converted to a common\ntype.\n', @@ -60,13 +60,13 @@ 'shifting': '\nShifting operations\n*******************\n\nThe shifting operations have lower priority than the arithmetic\noperations:\n\n shift_expr ::= a_expr | shift_expr ( "<<" | ">>" ) a_expr\n\nThese operators accept integers as arguments. They shift the first\nargument to the left or right by the number of bits given by the\nsecond argument.\n\nA right shift by *n* bits is defined as floor division by\n``pow(2,n)``. A left shift by *n* bits is defined as multiplication\nwith ``pow(2,n)``.\n\nNote: In the current implementation, the right-hand operand is required to\n be at most ``sys.maxsize``. If the right-hand operand is larger\n than ``sys.maxsize`` an ``OverflowError`` exception is raised.\n', 'slicings': '\nSlicings\n********\n\nA slicing selects a range of items in a sequence object (e.g., a\nstring, tuple or list). Slicings may be used as expressions or as\ntargets in assignment or ``del`` statements. The syntax for a\nslicing:\n\n slicing ::= primary "[" slice_list "]"\n slice_list ::= slice_item ("," slice_item)* [","]\n slice_item ::= expression | proper_slice\n proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" [stride] ]\n lower_bound ::= expression\n upper_bound ::= expression\n stride ::= expression\n\nThere is ambiguity in the formal syntax here: anything that looks like\nan expression list also looks like a slice list, so any subscription\ncan be interpreted as a slicing. Rather than further complicating the\nsyntax, this is disambiguated by defining that in this case the\ninterpretation as a subscription takes priority over the\ninterpretation as a slicing (this is the case if the slice list\ncontains no proper slice).\n\nThe semantics for a slicing are as follows. The primary must evaluate\nto a mapping object, and it is indexed (using the same\n``__getitem__()`` method as normal subscription) with a key that is\nconstructed from the slice list, as follows. If the slice list\ncontains at least one comma, the key is a tuple containing the\nconversion of the slice items; otherwise, the conversion of the lone\nslice item is the key. The conversion of a slice item that is an\nexpression is that expression. The conversion of a proper slice is a\nslice object (see section *The standard type hierarchy*) whose\n``start``, ``stop`` and ``step`` attributes are the values of the\nexpressions given as lower bound, upper bound and stride,\nrespectively, substituting ``None`` for missing expressions.\n', 'specialattrs': '\nSpecial Attributes\n******************\n\nThe implementation adds a few special read-only attributes to several\nobject types, where they are relevant. Some of these are not reported\nby the ``dir()`` built-in function.\n\nobject.__dict__\n\n A dictionary or other mapping object used to store an object\'s\n (writable) attributes.\n\ninstance.__class__\n\n The class to which a class instance belongs.\n\nclass.__bases__\n\n The tuple of base classes of a class object.\n\nclass.__name__\n\n The name of the class or type.\n\nclass.__qualname__\n\n The *qualified name* of the class or type.\n\n New in version 3.3.\n\nclass.__mro__\n\n This attribute is a tuple of classes that are considered when\n looking for base classes during method resolution.\n\nclass.mro()\n\n This method can be overridden by a metaclass to customize the\n method resolution order for its instances. It is called at class\n instantiation, and its result is stored in ``__mro__``.\n\nclass.__subclasses__()\n\n Each class keeps a list of weak references to its immediate\n subclasses. This method returns a list of all those references\n still alive. Example:\n\n >>> int.__subclasses__()\n []\n\n-[ Footnotes ]-\n\n[1] Additional information on these special methods may be found in\n the Python Reference Manual (*Basic customization*).\n\n[2] As a consequence, the list ``[1, 2]`` is considered equal to\n ``[1.0, 2.0]``, and similarly for tuples.\n\n[3] They must have since the parser can\'t tell the type of the\n operands.\n\n[4] Cased characters are those with general category property being\n one of "Lu" (Letter, uppercase), "Ll" (Letter, lowercase), or "Lt"\n (Letter, titlecase).\n\n[5] To format only a tuple you should therefore provide a singleton\n tuple whose only element is the tuple to be formatted.\n', - 'specialnames': '\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named ``__getitem__()``, and ``x`` is an instance of this\nclass, then ``x[i]`` is roughly equivalent to ``type(x).__getitem__(x,\ni)``. Except where mentioned, attempts to execute an operation raise\nan exception when no appropriate method is defined (typically\n``AttributeError`` or ``TypeError``).\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n``NodeList`` interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected and cleaned up when the cyclic garbage collector is\n enabled (it\'s on by default). Refer to the documentation for the\n ``gc`` module for more information about this topic.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by ``str(object)`` and the built-in functions ``format()``\n and ``print()`` to compute the "informal" or nicely printable\n string representation of an object. The return value must be a\n *string* object.\n\n This method differs from ``object.__repr__()`` in that there is no\n expectation that ``__str__()`` return a valid Python expression: a\n more convenient or concise representation can be used.\n\n The default implementation defined by the built-in type ``object``\n calls ``object.__repr__()``.\n\nobject.__bytes__(self)\n\n Called by ``bytes()`` to compute a byte-string representation of an\n object. This should return a ``bytes`` object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``str.format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see ``functools.total_ordering()``.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n Note: ``hash()`` truncates the value returned from an object\'s custom\n ``__hash__()`` method to the size of a ``Py_ssize_t``. This is\n typically 8 bytes on 64-bit builds and 4 bytes on 32-bit builds.\n If an object\'s ``__hash__()`` must interoperate on builds of\n different bit sizes, be sure to check the width on all supported\n builds. An easy way to do this is with ``python -c "import sys;\n print(sys.hash_info.width)"``\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns an appropriate value such\n that ``x == y`` implies both that ``x is y`` and ``hash(x) ==\n hash(y)``.\n\n A class that overrides ``__eq__()`` and does not define\n ``__hash__()`` will have its ``__hash__()`` implicitly set to\n ``None``. When the ``__hash__()`` method of a class is ``None``,\n instances of the class will raise an appropriate ``TypeError`` when\n a program attempts to retrieve their hash value, and will also be\n correctly identified as unhashable when checking ``isinstance(obj,\n collections.Hashable``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``.\n\n If a class that does not override ``__eq__()`` wishes to suppress\n hash support, it should include ``__hash__ = None`` in the class\n definition. A class which defines its own ``__hash__()`` that\n explicitly raises a ``TypeError`` would be incorrectly identified\n as hashable by an ``isinstance(obj, collections.Hashable)`` call.\n\n Note: By default, the ``__hash__()`` values of str, bytes and datetime\n objects are "salted" with an unpredictable random value.\n Although they remain constant within an individual Python\n process, they are not predictable between repeated invocations of\n Python.This is intended to provide protection against a denial-\n of-service caused by carefully-chosen inputs that exploit the\n worst case performance of a dict insertion, O(n^2) complexity.\n See http://www.ocert.org/advisories/ocert-2011-003.html for\n details.Changing hash values affects the iteration order of\n dicts, sets and other mappings. Python has never made guarantees\n about this ordering (and it typically varies between 32-bit and\n 64-bit builds).See also ``PYTHONHASHSEED``.\n\n Changed in version 3.3: Hash randomization is enabled by default.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A sequence must be\n returned. ``dir()`` converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using ``type()``. The class body\nis executed in a new namespace and the class name is bound locally to\nthe result of ``type(name, bases, namespace)``.\n\nThe class creation process can be customised by passing the\n``metaclass`` keyword argument in the class definition line, or by\ninheriting from an existing class that included such an argument. In\nthe following example, both ``MyClass`` and ``MySubclass`` are\ninstances of ``Meta``:\n\n class Meta(type):\n pass\n\n class MyClass(metaclass=Meta):\n pass\n\n class MySubclass(MyClass):\n pass\n\nAny other keyword arguments that are specified in the class definition\nare passed through to all metaclass operations described below.\n\nWhen a class definition is executed, the following steps occur:\n\n* the appropriate metaclass is determined\n\n* the class namespace is prepared\n\n* the class body is executed\n\n* the class object is created\n\n\nDetermining the appropriate metaclass\n-------------------------------------\n\nThe appropriate metaclass for a class definition is determined as\nfollows:\n\n* if no bases and no explicit metaclass are given, then ``type()`` is\n used\n\n* if an explicit metaclass is given and it is *not* an instance of\n ``type()``, then it is used directly as the metaclass\n\n* if an instance of ``type()`` is given as the explicit metaclass, or\n bases are defined, then the most derived metaclass is used\n\nThe most derived metaclass is selected from the explicitly specified\nmetaclass (if any) and the metaclasses (i.e. ``type(cls)``) of all\nspecified base classes. The most derived metaclass is one which is a\nsubtype of *all* of these candidate metaclasses. If none of the\ncandidate metaclasses meets that criterion, then the class definition\nwill fail with ``TypeError``.\n\n\nPreparing the class namespace\n-----------------------------\n\nOnce the appropriate metaclass has been identified, then the class\nnamespace is prepared. If the metaclass has a ``__prepare__``\nattribute, it is called as ``namespace = metaclass.__prepare__(name,\nbases, **kwds)`` (where the additional keyword arguments, if any, come\nfrom the class definition).\n\nIf the metaclass has no ``__prepare__`` attribute, then the class\nnamespace is initialised as an empty ``dict()`` instance.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3000\n Introduced the ``__prepare__`` namespace hook\n\n\nExecuting the class body\n------------------------\n\nThe class body is executed (approximately) as ``exec(body, globals(),\nnamespace)``. The key difference from a normal call to ``exec()`` is\nthat lexical scoping allows the class body (including any methods) to\nreference names from the current and outer scopes when the class\ndefinition occurs inside a function.\n\nHowever, even when the class definition occurs inside the function,\nmethods defined inside the class still cannot see names defined at the\nclass scope. Class variables must be accessed through the first\nparameter of instance or class methods, and cannot be accessed at all\nfrom static methods.\n\n\nCreating the class object\n-------------------------\n\nOnce the class namespace has been populated by executing the class\nbody, the class object is created by calling ``metaclass(name, bases,\nnamespace, **kwds)`` (the additional keywords passed here are the same\nas those passed to ``__prepare__``).\n\nThis class object is the one that will be referenced by the zero-\nargument form of ``super()``. ``__class__`` is an implicit closure\nreference created by the compiler if any methods in a class body refer\nto either ``__class__`` or ``super``. This allows the zero argument\nform of ``super()`` to correctly identify the class being defined\nbased on lexical scoping, while the class or instance that was used to\nmake the current call is identified based on the first argument passed\nto the method.\n\nAfter the class object is created, it is passed to the class\ndecorators included in the class definition (if any) and the resulting\nobject is bound in the local namespace as the defined class.\n\nSee also:\n\n **PEP 3135** - New super\n Describes the implicit ``__class__`` closure reference\n\n\nMetaclass example\n-----------------\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored include logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n``collections.OrderedDict`` to remember the order that class members\nwere defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, namespace, **kwds):\n result = type.__new__(cls, name, bases, dict(namespace))\n result.members = tuple(namespace)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s ``__prepare__()`` method which returns an\nempty ``collections.OrderedDict``. That mapping records the methods\nand attributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s ``__new__()`` method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called ``members``.\n\n\nCustomizing instance and subclass checks\n========================================\n\nThe following methods are used to override the default behavior of the\n``isinstance()`` and ``issubclass()`` built-in functions.\n\nIn particular, the metaclass ``abc.ABCMeta`` implements these methods\nin order to allow the addition of Abstract Base Classes (ABCs) as\n"virtual base classes" to any class or type (including built-in\ntypes), including other ABCs.\n\nclass.__instancecheck__(self, instance)\n\n Return true if *instance* should be considered a (direct or\n indirect) instance of *class*. If defined, called to implement\n ``isinstance(instance, class)``.\n\nclass.__subclasscheck__(self, subclass)\n\n Return true if *subclass* should be considered a (direct or\n indirect) subclass of *class*. If defined, called to implement\n ``issubclass(subclass, class)``.\n\nNote that these methods are looked up on the type (metaclass) of a\nclass. They cannot be defined as class methods in the actual class.\nThis is consistent with the lookup of special methods that are called\non instances, only in this case the instance is itself a class.\n\nSee also:\n\n **PEP 3119** - Introducing Abstract Base Classes\n Includes the specification for customizing ``isinstance()`` and\n ``issubclass()`` behavior through ``__instancecheck__()`` and\n ``__subclasscheck__()``, with motivation for this functionality\n in the context of adding Abstract Base Classes (see the ``abc``\n module) to the language.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python\'s standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping\'s keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn\'t define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nobject.__length_hint__(self)\n\n Called to implement ``operator.length_hint()``. Should return an\n estimated length for the object (which may be greater or less than\n the actual length). The length must be an integer ``>=`` 0. This\n method is purely an optimization and is never required for\n correctness.\n\n New in version 3.4.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` built-in will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define ``__contains__()``, the membership\n test first tries iteration via ``__iter__()``, then the old\n sequence iteration protocol via ``__getitem__()``, see *this\n section in the language reference*.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [2] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left operand\'s\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand\'s\n non-reflected method. This behavior allows subclasses to\n override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C:\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as ``__hash__()`` and ``__repr__()`` that are implemented\nby all objects, including type objects. If the implicit lookup of\nthese methods used the conventional lookup process, they would fail\nwhen invoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe ``__getattribute__()`` method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the ``__getattribute__()`` machinery in this fashion\nprovides significant scope for speed optimisations within the\ninterpreter, at the cost of some flexibility in the handling of\nspecial methods (the special method *must* be set on the class object\nitself in order to be consistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type, under\n certain controlled conditions. It generally isn\'t a good idea\n though, since it can lead to some very strange behaviour if it is\n handled incorrectly.\n\n[2] For operands of the same type, it is assumed that if the non-\n reflected method (such as ``__add__()``) fails the operation is\n not supported, which is why the reflected method is not called.\n', - 'string-methods': '\nString Methods\n**************\n\nStrings implement all of the *common* sequence operations, along with\nthe additional methods described below.\n\nStrings also support two styles of string formatting, one providing a\nlarge degree of flexibility and customization (see ``str.format()``,\n*Format String Syntax* and *String Formatting*) and the other based on\nC ``printf`` style formatting that handles a narrower range of types\nand is slightly harder to use correctly, but is often faster for the\ncases it can handle (*printf-style String Formatting*).\n\nThe *Text Processing Services* section of the standard library covers\na number of other modules that provide various text related utilities\n(including regular expression support in the ``re`` module).\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.casefold()\n\n Return a casefolded copy of the string. Casefolded strings may be\n used for caseless matching.\n\n Casefolding is similar to lowercasing but more aggressive because\n it is intended to remove all case distinctions in a string. For\n example, the German lowercase letter ``\'\xc3\x9f\'`` is equivalent to\n ``"ss"``. Since it is already lowercase, ``lower()`` would do\n nothing to ``\'\xc3\x9f\'``; ``casefold()`` converts it to ``"ss"``.\n\n The casefolding algorithm is described in section 3.13 of the\n Unicode Standard.\n\n New in version 3.3.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is ``\'utf-8\'``. *errors* may be given to set a different\n error handling scheme. The default for *errors* is ``\'strict\'``,\n meaning that encoding errors raise a ``UnicodeError``. Other\n possible values are ``\'ignore\'``, ``\'replace\'``,\n ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs(tabsize=8)\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. Tab positions occur every *tabsize* characters\n (default is 8, giving tab positions at columns 0, 8, 16 and so on).\n To expand the string, the current column is set to zero and the\n string is examined character by character. If the character is a\n tab (``\\t``), one or more space characters are inserted in the\n result until the current column is equal to the next tab position.\n (The tab character itself is not copied.) If the character is a\n newline (``\\n``) or return (``\\r``), it is copied and the current\n column is reset to zero. Any other character is copied unchanged\n and the current column is incremented by one regardless of how the\n character is represented when printed.\n\n >>> \'01\\t012\\t0123\\t01234\'.expandtabs()\n \'01 012 0123 01234\'\n >>> \'01\\t012\\t0123\\t01234\'.expandtabs(4)\n \'01 012 0123 01234\'\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\n Note: The ``find()`` method should be used only if you need to know the\n position of *sub*. To check if *sub* is a substring or not, use\n the ``in`` operator:\n\n >>> \'Py\' in \'Python\'\n True\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces ``{}``. Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to ``str.format(**mapping)``, except that ``mapping`` is\n used directly and not copied to a ``dict`` . This is useful if for\n example ``mapping`` is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character\n ``c`` is alphanumeric if one of the following returns ``True``:\n ``c.isalpha()``, ``c.isdecimal()``, ``c.isdigit()``, or\n ``c.isnumeric()``.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that can be used to\n form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\n Use ``keyword.iskeyword()`` to test for reserved identifiers such\n as ``def`` and ``class``.\n\nstr.islower()\n\n Return true if all cased characters [4] in the string are lowercase\n and there is at least one cased character, false otherwise.\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters [4] in the string are uppercase\n and there is at least one cased character, false otherwise.\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *iterable*, including ``bytes`` objects.\n The separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than or\n equal to ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string with all the cased characters [4]\n converted to lowercase.\n\n The lowercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than or\n equal to ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified or ``-1``, then there is\n no limit on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. This method uses the *universal newlines* approach to\n splitting lines. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\n For example, ``\'ab c\\n\\nde fg\\rkl\\r\\n\'.splitlines()`` returns\n ``[\'ab c\', \'\', \'de fg\', \'kl\']``, while the same call with\n ``splitlines(True)`` returns ``[\'ab c\\n\', \'\\n\', \'de fg\\r\',\n \'kl\\r\\n\']``.\n\n Unlike ``split()`` when a delimiter string *sep* is given, this\n method returns an empty list for the empty string, and a terminal\n line break does not result in an extra line.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa. Note that it is not necessarily true that\n ``s.swapcase().swapcase() == s``.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n ... return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n ... lambda mo: mo.group(0)[0].upper() +\n ... mo.group(0)[1:].lower(),\n ... s)\n ...\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string with all the cased characters [4]\n converted to uppercase. Note that ``str.upper().isupper()`` might\n be ``False`` if ``s`` contains uncased characters or if the Unicode\n category of the resulting character(s) is not "Lu" (Letter,\n uppercase), but e.g. "Lt" (Letter, titlecase).\n\n The uppercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than or equal to ``len(s)``.\n', + 'specialnames': '\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named ``__getitem__()``, and ``x`` is an instance of this\nclass, then ``x[i]`` is roughly equivalent to ``type(x).__getitem__(x,\ni)``. Except where mentioned, attempts to execute an operation raise\nan exception when no appropriate method is defined (typically\n``AttributeError`` or ``TypeError``).\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n``NodeList`` interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected and cleaned up when the cyclic garbage collector is\n enabled (it\'s on by default). Refer to the documentation for the\n ``gc`` module for more information about this topic.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by ``str(object)`` and the built-in functions ``format()``\n and ``print()`` to compute the "informal" or nicely printable\n string representation of an object. The return value must be a\n *string* object.\n\n This method differs from ``object.__repr__()`` in that there is no\n expectation that ``__str__()`` return a valid Python expression: a\n more convenient or concise representation can be used.\n\n The default implementation defined by the built-in type ``object``\n calls ``object.__repr__()``.\n\nobject.__bytes__(self)\n\n Called by ``bytes()`` to compute a byte-string representation of an\n object. This should return a ``bytes`` object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``str.format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see ``functools.total_ordering()``.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n Note: ``hash()`` truncates the value returned from an object\'s custom\n ``__hash__()`` method to the size of a ``Py_ssize_t``. This is\n typically 8 bytes on 64-bit builds and 4 bytes on 32-bit builds.\n If an object\'s ``__hash__()`` must interoperate on builds of\n different bit sizes, be sure to check the width on all supported\n builds. An easy way to do this is with ``python -c "import sys;\n print(sys.hash_info.width)"``\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns an appropriate value such\n that ``x == y`` implies both that ``x is y`` and ``hash(x) ==\n hash(y)``.\n\n A class that overrides ``__eq__()`` and does not define\n ``__hash__()`` will have its ``__hash__()`` implicitly set to\n ``None``. When the ``__hash__()`` method of a class is ``None``,\n instances of the class will raise an appropriate ``TypeError`` when\n a program attempts to retrieve their hash value, and will also be\n correctly identified as unhashable when checking ``isinstance(obj,\n collections.Hashable``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``.\n\n If a class that does not override ``__eq__()`` wishes to suppress\n hash support, it should include ``__hash__ = None`` in the class\n definition. A class which defines its own ``__hash__()`` that\n explicitly raises a ``TypeError`` would be incorrectly identified\n as hashable by an ``isinstance(obj, collections.Hashable)`` call.\n\n Note: By default, the ``__hash__()`` values of str, bytes and datetime\n objects are "salted" with an unpredictable random value.\n Although they remain constant within an individual Python\n process, they are not predictable between repeated invocations of\n Python.This is intended to provide protection against a denial-\n of-service caused by carefully-chosen inputs that exploit the\n worst case performance of a dict insertion, O(n^2) complexity.\n See http://www.ocert.org/advisories/ocert-2011-003.html for\n details.Changing hash values affects the iteration order of\n dicts, sets and other mappings. Python has never made guarantees\n about this ordering (and it typically varies between 32-bit and\n 64-bit builds).See also ``PYTHONHASHSEED``.\n\n Changed in version 3.3: Hash randomization is enabled by default.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A sequence must be\n returned. ``dir()`` converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``bytes`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using ``type()``. The class body\nis executed in a new namespace and the class name is bound locally to\nthe result of ``type(name, bases, namespace)``.\n\nThe class creation process can be customised by passing the\n``metaclass`` keyword argument in the class definition line, or by\ninheriting from an existing class that included such an argument. In\nthe following example, both ``MyClass`` and ``MySubclass`` are\ninstances of ``Meta``:\n\n class Meta(type):\n pass\n\n class MyClass(metaclass=Meta):\n pass\n\n class MySubclass(MyClass):\n pass\n\nAny other keyword arguments that are specified in the class definition\nare passed through to all metaclass operations described below.\n\nWhen a class definition is executed, the following steps occur:\n\n* the appropriate metaclass is determined\n\n* the class namespace is prepared\n\n* the class body is executed\n\n* the class object is created\n\n\nDetermining the appropriate metaclass\n-------------------------------------\n\nThe appropriate metaclass for a class definition is determined as\nfollows:\n\n* if no bases and no explicit metaclass are given, then ``type()`` is\n used\n\n* if an explicit metaclass is given and it is *not* an instance of\n ``type()``, then it is used directly as the metaclass\n\n* if an instance of ``type()`` is given as the explicit metaclass, or\n bases are defined, then the most derived metaclass is used\n\nThe most derived metaclass is selected from the explicitly specified\nmetaclass (if any) and the metaclasses (i.e. ``type(cls)``) of all\nspecified base classes. The most derived metaclass is one which is a\nsubtype of *all* of these candidate metaclasses. If none of the\ncandidate metaclasses meets that criterion, then the class definition\nwill fail with ``TypeError``.\n\n\nPreparing the class namespace\n-----------------------------\n\nOnce the appropriate metaclass has been identified, then the class\nnamespace is prepared. If the metaclass has a ``__prepare__``\nattribute, it is called as ``namespace = metaclass.__prepare__(name,\nbases, **kwds)`` (where the additional keyword arguments, if any, come\nfrom the class definition).\n\nIf the metaclass has no ``__prepare__`` attribute, then the class\nnamespace is initialised as an empty ``dict()`` instance.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3000\n Introduced the ``__prepare__`` namespace hook\n\n\nExecuting the class body\n------------------------\n\nThe class body is executed (approximately) as ``exec(body, globals(),\nnamespace)``. The key difference from a normal call to ``exec()`` is\nthat lexical scoping allows the class body (including any methods) to\nreference names from the current and outer scopes when the class\ndefinition occurs inside a function.\n\nHowever, even when the class definition occurs inside the function,\nmethods defined inside the class still cannot see names defined at the\nclass scope. Class variables must be accessed through the first\nparameter of instance or class methods, and cannot be accessed at all\nfrom static methods.\n\n\nCreating the class object\n-------------------------\n\nOnce the class namespace has been populated by executing the class\nbody, the class object is created by calling ``metaclass(name, bases,\nnamespace, **kwds)`` (the additional keywords passed here are the same\nas those passed to ``__prepare__``).\n\nThis class object is the one that will be referenced by the zero-\nargument form of ``super()``. ``__class__`` is an implicit closure\nreference created by the compiler if any methods in a class body refer\nto either ``__class__`` or ``super``. This allows the zero argument\nform of ``super()`` to correctly identify the class being defined\nbased on lexical scoping, while the class or instance that was used to\nmake the current call is identified based on the first argument passed\nto the method.\n\nAfter the class object is created, it is passed to the class\ndecorators included in the class definition (if any) and the resulting\nobject is bound in the local namespace as the defined class.\n\nSee also:\n\n **PEP 3135** - New super\n Describes the implicit ``__class__`` closure reference\n\n\nMetaclass example\n-----------------\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored include logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n``collections.OrderedDict`` to remember the order that class members\nwere defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, namespace, **kwds):\n result = type.__new__(cls, name, bases, dict(namespace))\n result.members = tuple(namespace)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s ``__prepare__()`` method which returns an\nempty ``collections.OrderedDict``. That mapping records the methods\nand attributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s ``__new__()`` method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called ``members``.\n\n\nCustomizing instance and subclass checks\n========================================\n\nThe following methods are used to override the default behavior of the\n``isinstance()`` and ``issubclass()`` built-in functions.\n\nIn particular, the metaclass ``abc.ABCMeta`` implements these methods\nin order to allow the addition of Abstract Base Classes (ABCs) as\n"virtual base classes" to any class or type (including built-in\ntypes), including other ABCs.\n\nclass.__instancecheck__(self, instance)\n\n Return true if *instance* should be considered a (direct or\n indirect) instance of *class*. If defined, called to implement\n ``isinstance(instance, class)``.\n\nclass.__subclasscheck__(self, subclass)\n\n Return true if *subclass* should be considered a (direct or\n indirect) subclass of *class*. If defined, called to implement\n ``issubclass(subclass, class)``.\n\nNote that these methods are looked up on the type (metaclass) of a\nclass. They cannot be defined as class methods in the actual class.\nThis is consistent with the lookup of special methods that are called\non instances, only in this case the instance is itself a class.\n\nSee also:\n\n **PEP 3119** - Introducing Abstract Base Classes\n Includes the specification for customizing ``isinstance()`` and\n ``issubclass()`` behavior through ``__instancecheck__()`` and\n ``__subclasscheck__()``, with motivation for this functionality\n in the context of adding Abstract Base Classes (see the ``abc``\n module) to the language.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python\'s standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping\'s keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn\'t define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nobject.__length_hint__(self)\n\n Called to implement ``operator.length_hint()``. Should return an\n estimated length for the object (which may be greater or less than\n the actual length). The length must be an integer ``>=`` 0. This\n method is purely an optimization and is never required for\n correctness.\n\n New in version 3.4.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` built-in will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define ``__contains__()``, the membership\n test first tries iteration via ``__iter__()``, then the old\n sequence iteration protocol via ``__getitem__()``, see *this\n section in the language reference*.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [2] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left operand\'s\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand\'s\n non-reflected method. This behavior allows subclasses to\n override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C:\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as ``__hash__()`` and ``__repr__()`` that are implemented\nby all objects, including type objects. If the implicit lookup of\nthese methods used the conventional lookup process, they would fail\nwhen invoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe ``__getattribute__()`` method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the ``__getattribute__()`` machinery in this fashion\nprovides significant scope for speed optimisations within the\ninterpreter, at the cost of some flexibility in the handling of\nspecial methods (the special method *must* be set on the class object\nitself in order to be consistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type, under\n certain controlled conditions. It generally isn\'t a good idea\n though, since it can lead to some very strange behaviour if it is\n handled incorrectly.\n\n[2] For operands of the same type, it is assumed that if the non-\n reflected method (such as ``__add__()``) fails the operation is\n not supported, which is why the reflected method is not called.\n', + 'string-methods': '\nString Methods\n**************\n\nStrings implement all of the *common* sequence operations, along with\nthe additional methods described below.\n\nStrings also support two styles of string formatting, one providing a\nlarge degree of flexibility and customization (see ``str.format()``,\n*Format String Syntax* and *String Formatting*) and the other based on\nC ``printf`` style formatting that handles a narrower range of types\nand is slightly harder to use correctly, but is often faster for the\ncases it can handle (*printf-style String Formatting*).\n\nThe *Text Processing Services* section of the standard library covers\na number of other modules that provide various text related utilities\n(including regular expression support in the ``re`` module).\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.casefold()\n\n Return a casefolded copy of the string. Casefolded strings may be\n used for caseless matching.\n\n Casefolding is similar to lowercasing but more aggressive because\n it is intended to remove all case distinctions in a string. For\n example, the German lowercase letter ``\'\xc3\x9f\'`` is equivalent to\n ``"ss"``. Since it is already lowercase, ``lower()`` would do\n nothing to ``\'\xc3\x9f\'``; ``casefold()`` converts it to ``"ss"``.\n\n The casefolding algorithm is described in section 3.13 of the\n Unicode Standard.\n\n New in version 3.3.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is ``\'utf-8\'``. *errors* may be given to set a different\n error handling scheme. The default for *errors* is ``\'strict\'``,\n meaning that encoding errors raise a ``UnicodeError``. Other\n possible values are ``\'ignore\'``, ``\'replace\'``,\n ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs(tabsize=8)\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. Tab positions occur every *tabsize* characters\n (default is 8, giving tab positions at columns 0, 8, 16 and so on).\n To expand the string, the current column is set to zero and the\n string is examined character by character. If the character is a\n tab (``\\t``), one or more space characters are inserted in the\n result until the current column is equal to the next tab position.\n (The tab character itself is not copied.) If the character is a\n newline (``\\n``) or return (``\\r``), it is copied and the current\n column is reset to zero. Any other character is copied unchanged\n and the current column is incremented by one regardless of how the\n character is represented when printed.\n\n >>> \'01\\t012\\t0123\\t01234\'.expandtabs()\n \'01 012 0123 01234\'\n >>> \'01\\t012\\t0123\\t01234\'.expandtabs(4)\n \'01 012 0123 01234\'\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\n Note: The ``find()`` method should be used only if you need to know the\n position of *sub*. To check if *sub* is a substring or not, use\n the ``in`` operator:\n\n >>> \'Py\' in \'Python\'\n True\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces ``{}``. Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to ``str.format(**mapping)``, except that ``mapping`` is\n used directly and not copied to a ``dict``. This is useful if for\n example ``mapping`` is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character\n ``c`` is alphanumeric if one of the following returns ``True``:\n ``c.isalpha()``, ``c.isdecimal()``, ``c.isdigit()``, or\n ``c.isnumeric()``.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that can be used to\n form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\n Use ``keyword.iskeyword()`` to test for reserved identifiers such\n as ``def`` and ``class``.\n\nstr.islower()\n\n Return true if all cased characters [4] in the string are lowercase\n and there is at least one cased character, false otherwise.\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters [4] in the string are uppercase\n and there is at least one cased character, false otherwise.\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *iterable*, including ``bytes`` objects.\n The separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than or\n equal to ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string with all the cased characters [4]\n converted to lowercase.\n\n The lowercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than or\n equal to ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified or ``-1``, then there is\n no limit on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. This method uses the *universal newlines* approach to\n splitting lines. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\n For example, ``\'ab c\\n\\nde fg\\rkl\\r\\n\'.splitlines()`` returns\n ``[\'ab c\', \'\', \'de fg\', \'kl\']``, while the same call with\n ``splitlines(True)`` returns ``[\'ab c\\n\', \'\\n\', \'de fg\\r\',\n \'kl\\r\\n\']``.\n\n Unlike ``split()`` when a delimiter string *sep* is given, this\n method returns an empty list for the empty string, and a terminal\n line break does not result in an extra line.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa. Note that it is not necessarily true that\n ``s.swapcase().swapcase() == s``.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n ... return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n ... lambda mo: mo.group(0)[0].upper() +\n ... mo.group(0)[1:].lower(),\n ... s)\n ...\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string with all the cased characters [4]\n converted to uppercase. Note that ``str.upper().isupper()`` might\n be ``False`` if ``s`` contains uncased characters or if the Unicode\n category of the resulting character(s) is not "Lu" (Letter,\n uppercase), but e.g. "Lt" (Letter, titlecase).\n\n The uppercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than or equal to ``len(s)``.\n', 'strings': '\nString and Bytes literals\n*************************\n\nString literals are described by the following lexical definitions:\n\n stringliteral ::= [stringprefix](shortstring | longstring)\n stringprefix ::= "r" | "u" | "R" | "U"\n shortstring ::= "\'" shortstringitem* "\'" | \'"\' shortstringitem* \'"\'\n longstring ::= "\'\'\'" longstringitem* "\'\'\'" | \'"""\' longstringitem* \'"""\'\n shortstringitem ::= shortstringchar | stringescapeseq\n longstringitem ::= longstringchar | stringescapeseq\n shortstringchar ::= \n longstringchar ::= \n stringescapeseq ::= "\\" \n\n bytesliteral ::= bytesprefix(shortbytes | longbytes)\n bytesprefix ::= "b" | "B" | "br" | "Br" | "bR" | "BR" | "rb" | "rB" | "Rb" | "RB"\n shortbytes ::= "\'" shortbytesitem* "\'" | \'"\' shortbytesitem* \'"\'\n longbytes ::= "\'\'\'" longbytesitem* "\'\'\'" | \'"""\' longbytesitem* \'"""\'\n shortbytesitem ::= shortbyteschar | bytesescapeseq\n longbytesitem ::= longbyteschar | bytesescapeseq\n shortbyteschar ::= \n longbyteschar ::= \n bytesescapeseq ::= "\\" \n\nOne syntactic restriction not indicated by these productions is that\nwhitespace is not allowed between the ``stringprefix`` or\n``bytesprefix`` and the rest of the literal. The source character set\nis defined by the encoding declaration; it is UTF-8 if no encoding\ndeclaration is given in the source file; see section *Encoding\ndeclarations*.\n\nIn plain English: Both types of literals can be enclosed in matching\nsingle quotes (``\'``) or double quotes (``"``). They can also be\nenclosed in matching groups of three single or double quotes (these\nare generally referred to as *triple-quoted strings*). The backslash\n(``\\``) character is used to escape characters that otherwise have a\nspecial meaning, such as newline, backslash itself, or the quote\ncharacter.\n\nBytes literals are always prefixed with ``\'b\'`` or ``\'B\'``; they\nproduce an instance of the ``bytes`` type instead of the ``str`` type.\nThey may only contain ASCII characters; bytes with a numeric value of\n128 or greater must be expressed with escapes.\n\nAs of Python 3.3 it is possible again to prefix unicode strings with a\n``u`` prefix to simplify maintenance of dual 2.x and 3.x codebases.\n\nBoth string and bytes literals may optionally be prefixed with a\nletter ``\'r\'`` or ``\'R\'``; such strings are called *raw strings* and\ntreat backslashes as literal characters. As a result, in string\nliterals, ``\'\\U\'`` and ``\'\\u\'`` escapes in raw strings are not treated\nspecially. Given that Python 2.x\'s raw unicode literals behave\ndifferently than Python 3.x\'s the ``\'ur\'`` syntax is not supported.\n\n New in version 3.3: The ``\'rb\'`` prefix of raw bytes literals has\n been added as a synonym of ``\'br\'``.\n\n New in version 3.3: Support for the unicode legacy literal\n (``u\'value\'``) was reintroduced to simplify the maintenance of dual\n Python 2.x and 3.x codebases. See **PEP 414** for more information.\n\nIn triple-quoted strings, unescaped newlines and quotes are allowed\n(and are retained), except that three unescaped quotes in a row\nterminate the string. (A "quote" is the character used to open the\nstring, i.e. either ``\'`` or ``"``.)\n\nUnless an ``\'r\'`` or ``\'R\'`` prefix is present, escape sequences in\nstrings are interpreted according to rules similar to those used by\nStandard C. The recognized escape sequences are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\newline`` | Backslash and newline ignored | |\n+-------------------+-----------------------------------+---------+\n| ``\\\\`` | Backslash (``\\``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\\'`` | Single quote (``\'``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\"`` | Double quote (``"``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\a`` | ASCII Bell (BEL) | |\n+-------------------+-----------------------------------+---------+\n| ``\\b`` | ASCII Backspace (BS) | |\n+-------------------+-----------------------------------+---------+\n| ``\\f`` | ASCII Formfeed (FF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\n`` | ASCII Linefeed (LF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\r`` | ASCII Carriage Return (CR) | |\n+-------------------+-----------------------------------+---------+\n| ``\\t`` | ASCII Horizontal Tab (TAB) | |\n+-------------------+-----------------------------------+---------+\n| ``\\v`` | ASCII Vertical Tab (VT) | |\n+-------------------+-----------------------------------+---------+\n| ``\\ooo`` | Character with octal value *ooo* | (1,3) |\n+-------------------+-----------------------------------+---------+\n| ``\\xhh`` | Character with hex value *hh* | (2,3) |\n+-------------------+-----------------------------------+---------+\n\nEscape sequences only recognized in string literals are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\N{name}`` | Character named *name* in the | (4) |\n| | Unicode database | |\n+-------------------+-----------------------------------+---------+\n| ``\\uxxxx`` | Character with 16-bit hex value | (5) |\n| | *xxxx* | |\n+-------------------+-----------------------------------+---------+\n| ``\\Uxxxxxxxx`` | Character with 32-bit hex value | (6) |\n| | *xxxxxxxx* | |\n+-------------------+-----------------------------------+---------+\n\nNotes:\n\n1. As in Standard C, up to three octal digits are accepted.\n\n2. Unlike in Standard C, exactly two hex digits are required.\n\n3. In a bytes literal, hexadecimal and octal escapes denote the byte\n with the given value. In a string literal, these escapes denote a\n Unicode character with the given value.\n\n4. Changed in version 3.3: Support for name aliases [1] has been\n added.\n\n5. Individual code units which form parts of a surrogate pair can be\n encoded using this escape sequence. Exactly four hex digits are\n required.\n\n6. Any Unicode character can be encoded this way. Exactly eight hex\n digits are required.\n\nUnlike Standard C, all unrecognized escape sequences are left in the\nstring unchanged, i.e., *the backslash is left in the string*. (This\nbehavior is useful when debugging: if an escape sequence is mistyped,\nthe resulting output is more easily recognized as broken.) It is also\nimportant to note that the escape sequences only recognized in string\nliterals fall into the category of unrecognized escapes for bytes\nliterals.\n\nEven in a raw string, string quotes can be escaped with a backslash,\nbut the backslash remains in the string; for example, ``r"\\""`` is a\nvalid string literal consisting of two characters: a backslash and a\ndouble quote; ``r"\\"`` is not a valid string literal (even a raw\nstring cannot end in an odd number of backslashes). Specifically, *a\nraw string cannot end in a single backslash* (since the backslash\nwould escape the following quote character). Note also that a single\nbackslash followed by a newline is interpreted as those two characters\nas part of the string, *not* as a line continuation.\n', 'subscriptions': '\nSubscriptions\n*************\n\nA subscription selects an item of a sequence (string, tuple or list)\nor mapping (dictionary) object:\n\n subscription ::= primary "[" expression_list "]"\n\nThe primary must evaluate to an object that supports subscription,\ne.g. a list or dictionary. User-defined objects can support\nsubscription by defining a ``__getitem__()`` method.\n\nFor built-in objects, there are two types of objects that support\nsubscription:\n\nIf the primary is a mapping, the expression list must evaluate to an\nobject whose value is one of the keys of the mapping, and the\nsubscription selects the value in the mapping that corresponds to that\nkey. (The expression list is a tuple except if it has exactly one\nitem.)\n\nIf the primary is a sequence, the expression (list) must evaluate to\nan integer or a slice (as discussed in the following section).\n\nThe formal syntax makes no special provision for negative indices in\nsequences; however, built-in sequences all provide a ``__getitem__()``\nmethod that interprets negative indices by adding the length of the\nsequence to the index (so that ``x[-1]`` selects the last item of\n``x``). The resulting value must be a nonnegative integer less than\nthe number of items in the sequence, and the subscription selects the\nitem whose index is that value (counting from zero). Since the support\nfor negative indices and slicing occurs in the object\'s\n``__getitem__()`` method, subclasses overriding this method will need\nto explicitly add that support.\n\nA string\'s items are characters. A character is not a separate data\ntype but a string of exactly one character.\n', 'truth': "\nTruth Value Testing\n*******************\n\nAny object can be tested for truth value, for use in an ``if`` or\n``while`` condition or as operand of the Boolean operations below. The\nfollowing values are considered false:\n\n* ``None``\n\n* ``False``\n\n* zero of any numeric type, for example, ``0``, ``0.0``, ``0j``.\n\n* any empty sequence, for example, ``''``, ``()``, ``[]``.\n\n* any empty mapping, for example, ``{}``.\n\n* instances of user-defined classes, if the class defines a\n ``__bool__()`` or ``__len__()`` method, when that method returns the\n integer zero or ``bool`` value ``False``. [1]\n\nAll other values are considered true --- so objects of many types are\nalways true.\n\nOperations and built-in functions that have a Boolean result always\nreturn ``0`` or ``False`` for false and ``1`` or ``True`` for true,\nunless otherwise stated. (Important exception: the Boolean operations\n``or`` and ``and`` always return one of their operands.)\n", 'try': '\nThe ``try`` statement\n*********************\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception it is re-raised at the end of\nthe ``finally`` clause. If the ``finally`` clause raises another\nexception, the saved exception is set as the context of the new\nexception. If the ``finally`` clause executes a ``return`` or\n``break`` statement, the saved exception is discarded:\n\n def f():\n try:\n 1/0\n finally:\n return 42\n\n >>> f()\n 42\n\nThe exception information is not available to the program during\nexecution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n', - 'types': '\nThe standard type hierarchy\n***************************\n\nBelow is a list of the types that are built into Python. Extension\nmodules (written in C, Java, or other languages, depending on the\nimplementation) can define additional types. Future versions of\nPython may add types to the type hierarchy (e.g., rational numbers,\nefficiently stored arrays of integers, etc.), although such additions\nwill often be provided via the standard library instead.\n\nSome of the type descriptions below contain a paragraph listing\n\'special attributes.\' These are attributes that provide access to the\nimplementation and are not intended for general use. Their definition\nmay change in the future.\n\nNone\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name ``None``.\n It is used to signify the absence of a value in many situations,\n e.g., it is returned from functions that don\'t explicitly return\n anything. Its truth value is false.\n\nNotImplemented\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name\n ``NotImplemented``. Numeric methods and rich comparison methods may\n return this value if they do not implement the operation for the\n operands provided. (The interpreter will then try the reflected\n operation, or some other fallback, depending on the operator.) Its\n truth value is true.\n\nEllipsis\n This type has a single value. There is a single object with this\n value. This object is accessed through the literal ``...`` or the\n built-in name ``Ellipsis``. Its truth value is true.\n\n``numbers.Number``\n These are created by numeric literals and returned as results by\n arithmetic operators and arithmetic built-in functions. Numeric\n objects are immutable; once created their value never changes.\n Python numbers are of course strongly related to mathematical\n numbers, but subject to the limitations of numerical representation\n in computers.\n\n Python distinguishes between integers, floating point numbers, and\n complex numbers:\n\n ``numbers.Integral``\n These represent elements from the mathematical set of integers\n (positive and negative).\n\n There are two types of integers:\n\n Integers (``int``)\n\n These represent numbers in an unlimited range, subject to\n available (virtual) memory only. For the purpose of shift\n and mask operations, a binary representation is assumed, and\n negative numbers are represented in a variant of 2\'s\n complement which gives the illusion of an infinite string of\n sign bits extending to the left.\n\n Booleans (``bool``)\n These represent the truth values False and True. The two\n objects representing the values False and True are the only\n Boolean objects. The Boolean type is a subtype of the integer\n type, and Boolean values behave like the values 0 and 1,\n respectively, in almost all contexts, the exception being\n that when converted to a string, the strings ``"False"`` or\n ``"True"`` are returned, respectively.\n\n The rules for integer representation are intended to give the\n most meaningful interpretation of shift and mask operations\n involving negative integers.\n\n ``numbers.Real`` (``float``)\n These represent machine-level double precision floating point\n numbers. You are at the mercy of the underlying machine\n architecture (and C or Java implementation) for the accepted\n range and handling of overflow. Python does not support single-\n precision floating point numbers; the savings in processor and\n memory usage that are usually the reason for using these is\n dwarfed by the overhead of using objects in Python, so there is\n no reason to complicate the language with two kinds of floating\n point numbers.\n\n ``numbers.Complex`` (``complex``)\n These represent complex numbers as a pair of machine-level\n double precision floating point numbers. The same caveats apply\n as for floating point numbers. The real and imaginary parts of a\n complex number ``z`` can be retrieved through the read-only\n attributes ``z.real`` and ``z.imag``.\n\nSequences\n These represent finite ordered sets indexed by non-negative\n numbers. The built-in function ``len()`` returns the number of\n items of a sequence. When the length of a sequence is *n*, the\n index set contains the numbers 0, 1, ..., *n*-1. Item *i* of\n sequence *a* is selected by ``a[i]``.\n\n Sequences also support slicing: ``a[i:j]`` selects all items with\n index *k* such that *i* ``<=`` *k* ``<`` *j*. When used as an\n expression, a slice is a sequence of the same type. This implies\n that the index set is renumbered so that it starts at 0.\n\n Some sequences also support "extended slicing" with a third "step"\n parameter: ``a[i:j:k]`` selects all items of *a* with index *x*\n where ``x = i + n*k``, *n* ``>=`` ``0`` and *i* ``<=`` *x* ``<``\n *j*.\n\n Sequences are distinguished according to their mutability:\n\n Immutable sequences\n An object of an immutable sequence type cannot change once it is\n created. (If the object contains references to other objects,\n these other objects may be mutable and may be changed; however,\n the collection of objects directly referenced by an immutable\n object cannot change.)\n\n The following types are immutable sequences:\n\n Strings\n A string is a sequence of values that represent Unicode\n codepoints. All the codepoints in range ``U+0000 - U+10FFFF``\n can be represented in a string. Python doesn\'t have a\n ``chr`` type, and every character in the string is\n represented as a string object with length ``1``. The built-\n in function ``ord()`` converts a character to its codepoint\n (as an integer); ``chr()`` converts an integer in range ``0 -\n 10FFFF`` to the corresponding character. ``str.encode()`` can\n be used to convert a ``str`` to ``bytes`` using the given\n encoding, and ``bytes.decode()`` can be used to achieve the\n opposite.\n\n Tuples\n The items of a tuple are arbitrary Python objects. Tuples of\n two or more items are formed by comma-separated lists of\n expressions. A tuple of one item (a \'singleton\') can be\n formed by affixing a comma to an expression (an expression by\n itself does not create a tuple, since parentheses must be\n usable for grouping of expressions). An empty tuple can be\n formed by an empty pair of parentheses.\n\n Bytes\n A bytes object is an immutable array. The items are 8-bit\n bytes, represented by integers in the range 0 <= x < 256.\n Bytes literals (like ``b\'abc\'``) and the built-in function\n ``bytes()`` can be used to construct bytes objects. Also,\n bytes objects can be decoded to strings via the ``decode()``\n method.\n\n Mutable sequences\n Mutable sequences can be changed after they are created. The\n subscription and slicing notations can be used as the target of\n assignment and ``del`` (delete) statements.\n\n There are currently two intrinsic mutable sequence types:\n\n Lists\n The items of a list are arbitrary Python objects. Lists are\n formed by placing a comma-separated list of expressions in\n square brackets. (Note that there are no special cases needed\n to form lists of length 0 or 1.)\n\n Byte Arrays\n A bytearray object is a mutable array. They are created by\n the built-in ``bytearray()`` constructor. Aside from being\n mutable (and hence unhashable), byte arrays otherwise provide\n the same interface and functionality as immutable bytes\n objects.\n\n The extension module ``array`` provides an additional example of\n a mutable sequence type, as does the ``collections`` module.\n\nSet types\n These represent unordered, finite sets of unique, immutable\n objects. As such, they cannot be indexed by any subscript. However,\n they can be iterated over, and the built-in function ``len()``\n returns the number of items in a set. Common uses for sets are fast\n membership testing, removing duplicates from a sequence, and\n computing mathematical operations such as intersection, union,\n difference, and symmetric difference.\n\n For set elements, the same immutability rules apply as for\n dictionary keys. Note that numeric types obey the normal rules for\n numeric comparison: if two numbers compare equal (e.g., ``1`` and\n ``1.0``), only one of them can be contained in a set.\n\n There are currently two intrinsic set types:\n\n Sets\n These represent a mutable set. They are created by the built-in\n ``set()`` constructor and can be modified afterwards by several\n methods, such as ``add()``.\n\n Frozen sets\n These represent an immutable set. They are created by the\n built-in ``frozenset()`` constructor. As a frozenset is\n immutable and *hashable*, it can be used again as an element of\n another set, or as a dictionary key.\n\nMappings\n These represent finite sets of objects indexed by arbitrary index\n sets. The subscript notation ``a[k]`` selects the item indexed by\n ``k`` from the mapping ``a``; this can be used in expressions and\n as the target of assignments or ``del`` statements. The built-in\n function ``len()`` returns the number of items in a mapping.\n\n There is currently a single intrinsic mapping type:\n\n Dictionaries\n These represent finite sets of objects indexed by nearly\n arbitrary values. The only types of values not acceptable as\n keys are values containing lists or dictionaries or other\n mutable types that are compared by value rather than by object\n identity, the reason being that the efficient implementation of\n dictionaries requires a key\'s hash value to remain constant.\n Numeric types used for keys obey the normal rules for numeric\n comparison: if two numbers compare equal (e.g., ``1`` and\n ``1.0``) then they can be used interchangeably to index the same\n dictionary entry.\n\n Dictionaries are mutable; they can be created by the ``{...}``\n notation (see section *Dictionary displays*).\n\n The extension modules ``dbm.ndbm`` and ``dbm.gnu`` provide\n additional examples of mapping types, as does the\n ``collections`` module.\n\nCallable types\n These are the types to which the function call operation (see\n section *Calls*) can be applied:\n\n User-defined functions\n A user-defined function object is created by a function\n definition (see section *Function definitions*). It should be\n called with an argument list containing the same number of items\n as the function\'s formal parameter list.\n\n Special attributes:\n\n +---------------------------+---------------------------------+-------------+\n | Attribute | Meaning | |\n +===========================+=================================+=============+\n | ``__doc__`` | The function\'s documentation | Writable |\n | | string, or ``None`` if | |\n | | unavailable | |\n +---------------------------+---------------------------------+-------------+\n | ``__name__`` | The function\'s name | Writable |\n +---------------------------+---------------------------------+-------------+\n | ``__qualname__`` | The function\'s *qualified name* | Writable |\n | | New in version 3.3. | |\n +---------------------------+---------------------------------+-------------+\n | ``__module__`` | The name of the module the | Writable |\n | | function was defined in, or | |\n | | ``None`` if unavailable. | |\n +---------------------------+---------------------------------+-------------+\n | ``__defaults__`` | A tuple containing default | Writable |\n | | argument values for those | |\n | | arguments that have defaults, | |\n | | or ``None`` if no arguments | |\n | | have a default value | |\n +---------------------------+---------------------------------+-------------+\n | ``__code__`` | The code object representing | Writable |\n | | the compiled function body. | |\n +---------------------------+---------------------------------+-------------+\n | ``__globals__`` | A reference to the dictionary | Read-only |\n | | that holds the function\'s | |\n | | global variables --- the global | |\n | | namespace of the module in | |\n | | which the function was defined. | |\n +---------------------------+---------------------------------+-------------+\n | ``__dict__`` | The namespace supporting | Writable |\n | | arbitrary function attributes. | |\n +---------------------------+---------------------------------+-------------+\n | ``__closure__`` | ``None`` or a tuple of cells | Read-only |\n | | that contain bindings for the | |\n | | function\'s free variables. | |\n +---------------------------+---------------------------------+-------------+\n | ``__annotations__`` | A dict containing annotations | Writable |\n | | of parameters. The keys of the | |\n | | dict are the parameter names, | |\n | | or ``\'return\'`` for the return | |\n | | annotation, if provided. | |\n +---------------------------+---------------------------------+-------------+\n | ``__kwdefaults__`` | A dict containing defaults for | Writable |\n | | keyword-only parameters. | |\n +---------------------------+---------------------------------+-------------+\n\n Most of the attributes labelled "Writable" check the type of the\n assigned value.\n\n Function objects also support getting and setting arbitrary\n attributes, which can be used, for example, to attach metadata\n to functions. Regular attribute dot-notation is used to get and\n set such attributes. *Note that the current implementation only\n supports function attributes on user-defined functions. Function\n attributes on built-in functions may be supported in the\n future.*\n\n Additional information about a function\'s definition can be\n retrieved from its code object; see the description of internal\n types below.\n\n Instance methods\n An instance method object combines a class, a class instance and\n any callable object (normally a user-defined function).\n\n Special read-only attributes: ``__self__`` is the class instance\n object, ``__func__`` is the function object; ``__doc__`` is the\n method\'s documentation (same as ``__func__.__doc__``);\n ``__name__`` is the method name (same as ``__func__.__name__``);\n ``__module__`` is the name of the module the method was defined\n in, or ``None`` if unavailable.\n\n Methods also support accessing (but not setting) the arbitrary\n function attributes on the underlying function object.\n\n User-defined method objects may be created when getting an\n attribute of a class (perhaps via an instance of that class), if\n that attribute is a user-defined function object or a class\n method object.\n\n When an instance method object is created by retrieving a user-\n defined function object from a class via one of its instances,\n its ``__self__`` attribute is the instance, and the method\n object is said to be bound. The new method\'s ``__func__``\n attribute is the original function object.\n\n When a user-defined method object is created by retrieving\n another method object from a class or instance, the behaviour is\n the same as for a function object, except that the ``__func__``\n attribute of the new instance is not the original method object\n but its ``__func__`` attribute.\n\n When an instance method object is created by retrieving a class\n method object from a class or instance, its ``__self__``\n attribute is the class itself, and its ``__func__`` attribute is\n the function object underlying the class method.\n\n When an instance method object is called, the underlying\n function (``__func__``) is called, inserting the class instance\n (``__self__``) in front of the argument list. For instance,\n when ``C`` is a class which contains a definition for a function\n ``f()``, and ``x`` is an instance of ``C``, calling ``x.f(1)``\n is equivalent to calling ``C.f(x, 1)``.\n\n When an instance method object is derived from a class method\n object, the "class instance" stored in ``__self__`` will\n actually be the class itself, so that calling either ``x.f(1)``\n or ``C.f(1)`` is equivalent to calling ``f(C,1)`` where ``f`` is\n the underlying function.\n\n Note that the transformation from function object to instance\n method object happens each time the attribute is retrieved from\n the instance. In some cases, a fruitful optimization is to\n assign the attribute to a local variable and call that local\n variable. Also notice that this transformation only happens for\n user-defined functions; other callable objects (and all non-\n callable objects) are retrieved without transformation. It is\n also important to note that user-defined functions which are\n attributes of a class instance are not converted to bound\n methods; this *only* happens when the function is an attribute\n of the class.\n\n Generator functions\n A function or method which uses the ``yield`` statement (see\n section *The yield statement*) is called a *generator function*.\n Such a function, when called, always returns an iterator object\n which can be used to execute the body of the function: calling\n the iterator\'s ``iterator.__next__()`` method will cause the\n function to execute until it provides a value using the\n ``yield`` statement. When the function executes a ``return``\n statement or falls off the end, a ``StopIteration`` exception is\n raised and the iterator will have reached the end of the set of\n values to be returned.\n\n Built-in functions\n A built-in function object is a wrapper around a C function.\n Examples of built-in functions are ``len()`` and ``math.sin()``\n (``math`` is a standard built-in module). The number and type of\n the arguments are determined by the C function. Special read-\n only attributes: ``__doc__`` is the function\'s documentation\n string, or ``None`` if unavailable; ``__name__`` is the\n function\'s name; ``__self__`` is set to ``None`` (but see the\n next item); ``__module__`` is the name of the module the\n function was defined in or ``None`` if unavailable.\n\n Built-in methods\n This is really a different disguise of a built-in function, this\n time containing an object passed to the C function as an\n implicit extra argument. An example of a built-in method is\n ``alist.append()``, assuming *alist* is a list object. In this\n case, the special read-only attribute ``__self__`` is set to the\n object denoted by *alist*.\n\n Classes\n Classes are callable. These objects normally act as factories\n for new instances of themselves, but variations are possible for\n class types that override ``__new__()``. The arguments of the\n call are passed to ``__new__()`` and, in the typical case, to\n ``__init__()`` to initialize the new instance.\n\n Class Instances\n Instances of arbitrary classes can be made callable by defining\n a ``__call__()`` method in their class.\n\nModules\n Modules are a basic organizational unit of Python code, and are\n created by the *import system* as invoked either by the ``import``\n statement (see ``import``), or by calling functions such as\n ``importlib.import_module()`` and built-in ``__import__()``. A\n module object has a namespace implemented by a dictionary object\n (this is the dictionary referenced by the ``__globals__`` attribute\n of functions defined in the module). Attribute references are\n translated to lookups in this dictionary, e.g., ``m.x`` is\n equivalent to ``m.__dict__["x"]``. A module object does not contain\n the code object used to initialize the module (since it isn\'t\n needed once the initialization is done).\n\n Attribute assignment updates the module\'s namespace dictionary,\n e.g., ``m.x = 1`` is equivalent to ``m.__dict__["x"] = 1``.\n\n Special read-only attribute: ``__dict__`` is the module\'s namespace\n as a dictionary object.\n\n **CPython implementation detail:** Because of the way CPython\n clears module dictionaries, the module dictionary will be cleared\n when the module falls out of scope even if the dictionary still has\n live references. To avoid this, copy the dictionary or keep the\n module around while using its dictionary directly.\n\n Predefined (writable) attributes: ``__name__`` is the module\'s\n name; ``__doc__`` is the module\'s documentation string, or ``None``\n if unavailable; ``__file__`` is the pathname of the file from which\n the module was loaded, if it was loaded from a file. The\n ``__file__`` attribute may be missing for certain types of modules,\n such as C modules that are statically linked into the interpreter;\n for extension modules loaded dynamically from a shared library, it\n is the pathname of the shared library file.\n\nCustom classes\n Custom class types are typically created by class definitions (see\n section *Class definitions*). A class has a namespace implemented\n by a dictionary object. Class attribute references are translated\n to lookups in this dictionary, e.g., ``C.x`` is translated to\n ``C.__dict__["x"]`` (although there are a number of hooks which\n allow for other means of locating attributes). When the attribute\n name is not found there, the attribute search continues in the base\n classes. This search of the base classes uses the C3 method\n resolution order which behaves correctly even in the presence of\n \'diamond\' inheritance structures where there are multiple\n inheritance paths leading back to a common ancestor. Additional\n details on the C3 MRO used by Python can be found in the\n documentation accompanying the 2.3 release at\n http://www.python.org/download/releases/2.3/mro/.\n\n When a class attribute reference (for class ``C``, say) would yield\n a class method object, it is transformed into an instance method\n object whose ``__self__`` attributes is ``C``. When it would yield\n a static method object, it is transformed into the object wrapped\n by the static method object. See section *Implementing Descriptors*\n for another way in which attributes retrieved from a class may\n differ from those actually contained in its ``__dict__``.\n\n Class attribute assignments update the class\'s dictionary, never\n the dictionary of a base class.\n\n A class object can be called (see above) to yield a class instance\n (see below).\n\n Special attributes: ``__name__`` is the class name; ``__module__``\n is the module name in which the class was defined; ``__dict__`` is\n the dictionary containing the class\'s namespace; ``__bases__`` is a\n tuple (possibly empty or a singleton) containing the base classes,\n in the order of their occurrence in the base class list;\n ``__doc__`` is the class\'s documentation string, or None if\n undefined.\n\nClass instances\n A class instance is created by calling a class object (see above).\n A class instance has a namespace implemented as a dictionary which\n is the first place in which attribute references are searched.\n When an attribute is not found there, and the instance\'s class has\n an attribute by that name, the search continues with the class\n attributes. If a class attribute is found that is a user-defined\n function object, it is transformed into an instance method object\n whose ``__self__`` attribute is the instance. Static method and\n class method objects are also transformed; see above under\n "Classes". See section *Implementing Descriptors* for another way\n in which attributes of a class retrieved via its instances may\n differ from the objects actually stored in the class\'s\n ``__dict__``. If no class attribute is found, and the object\'s\n class has a ``__getattr__()`` method, that is called to satisfy the\n lookup.\n\n Attribute assignments and deletions update the instance\'s\n dictionary, never a class\'s dictionary. If the class has a\n ``__setattr__()`` or ``__delattr__()`` method, this is called\n instead of updating the instance dictionary directly.\n\n Class instances can pretend to be numbers, sequences, or mappings\n if they have methods with certain special names. See section\n *Special method names*.\n\n Special attributes: ``__dict__`` is the attribute dictionary;\n ``__class__`` is the instance\'s class.\n\nI/O objects (also known as file objects)\n A *file object* represents an open file. Various shortcuts are\n available to create file objects: the ``open()`` built-in function,\n and also ``os.popen()``, ``os.fdopen()``, and the ``makefile()``\n method of socket objects (and perhaps by other functions or methods\n provided by extension modules).\n\n The objects ``sys.stdin``, ``sys.stdout`` and ``sys.stderr`` are\n initialized to file objects corresponding to the interpreter\'s\n standard input, output and error streams; they are all open in text\n mode and therefore follow the interface defined by the\n ``io.TextIOBase`` abstract class.\n\nInternal types\n A few types used internally by the interpreter are exposed to the\n user. Their definitions may change with future versions of the\n interpreter, but they are mentioned here for completeness.\n\n Code objects\n Code objects represent *byte-compiled* executable Python code,\n or *bytecode*. The difference between a code object and a\n function object is that the function object contains an explicit\n reference to the function\'s globals (the module in which it was\n defined), while a code object contains no context; also the\n default argument values are stored in the function object, not\n in the code object (because they represent values calculated at\n run-time). Unlike function objects, code objects are immutable\n and contain no references (directly or indirectly) to mutable\n objects.\n\n Special read-only attributes: ``co_name`` gives the function\n name; ``co_argcount`` is the number of positional arguments\n (including arguments with default values); ``co_nlocals`` is the\n number of local variables used by the function (including\n arguments); ``co_varnames`` is a tuple containing the names of\n the local variables (starting with the argument names);\n ``co_cellvars`` is a tuple containing the names of local\n variables that are referenced by nested functions;\n ``co_freevars`` is a tuple containing the names of free\n variables; ``co_code`` is a string representing the sequence of\n bytecode instructions; ``co_consts`` is a tuple containing the\n literals used by the bytecode; ``co_names`` is a tuple\n containing the names used by the bytecode; ``co_filename`` is\n the filename from which the code was compiled;\n ``co_firstlineno`` is the first line number of the function;\n ``co_lnotab`` is a string encoding the mapping from bytecode\n offsets to line numbers (for details see the source code of the\n interpreter); ``co_stacksize`` is the required stack size\n (including local variables); ``co_flags`` is an integer encoding\n a number of flags for the interpreter.\n\n The following flag bits are defined for ``co_flags``: bit\n ``0x04`` is set if the function uses the ``*arguments`` syntax\n to accept an arbitrary number of positional arguments; bit\n ``0x08`` is set if the function uses the ``**keywords`` syntax\n to accept arbitrary keyword arguments; bit ``0x20`` is set if\n the function is a generator.\n\n Future feature declarations (``from __future__ import\n division``) also use bits in ``co_flags`` to indicate whether a\n code object was compiled with a particular feature enabled: bit\n ``0x2000`` is set if the function was compiled with future\n division enabled; bits ``0x10`` and ``0x1000`` were used in\n earlier versions of Python.\n\n Other bits in ``co_flags`` are reserved for internal use.\n\n If a code object represents a function, the first item in\n ``co_consts`` is the documentation string of the function, or\n ``None`` if undefined.\n\n Frame objects\n Frame objects represent execution frames. They may occur in\n traceback objects (see below).\n\n Special read-only attributes: ``f_back`` is to the previous\n stack frame (towards the caller), or ``None`` if this is the\n bottom stack frame; ``f_code`` is the code object being executed\n in this frame; ``f_locals`` is the dictionary used to look up\n local variables; ``f_globals`` is used for global variables;\n ``f_builtins`` is used for built-in (intrinsic) names;\n ``f_lasti`` gives the precise instruction (this is an index into\n the bytecode string of the code object).\n\n Special writable attributes: ``f_trace``, if not ``None``, is a\n function called at the start of each source code line (this is\n used by the debugger); ``f_lineno`` is the current line number\n of the frame --- writing to this from within a trace function\n jumps to the given line (only for the bottom-most frame). A\n debugger can implement a Jump command (aka Set Next Statement)\n by writing to f_lineno.\n\n Frame objects support one method:\n\n frame.clear()\n\n This method clears all references to local variables held by\n the frame. Also, if the frame belonged to a generator, the\n generator is finalized. This helps break reference cycles\n involving frame objects (for example when catching an\n exception and storing its traceback for later use).\n\n ``RuntimeError`` is raised if the frame is currently\n executing.\n\n New in version 3.4.\n\n Traceback objects\n Traceback objects represent a stack trace of an exception. A\n traceback object is created when an exception occurs. When the\n search for an exception handler unwinds the execution stack, at\n each unwound level a traceback object is inserted in front of\n the current traceback. When an exception handler is entered,\n the stack trace is made available to the program. (See section\n *The try statement*.) It is accessible as the third item of the\n tuple returned by ``sys.exc_info()``. When the program contains\n no suitable handler, the stack trace is written (nicely\n formatted) to the standard error stream; if the interpreter is\n interactive, it is also made available to the user as\n ``sys.last_traceback``.\n\n Special read-only attributes: ``tb_next`` is the next level in\n the stack trace (towards the frame where the exception\n occurred), or ``None`` if there is no next level; ``tb_frame``\n points to the execution frame of the current level;\n ``tb_lineno`` gives the line number where the exception\n occurred; ``tb_lasti`` indicates the precise instruction. The\n line number and last instruction in the traceback may differ\n from the line number of its frame object if the exception\n occurred in a ``try`` statement with no matching except clause\n or with a finally clause.\n\n Slice objects\n Slice objects are used to represent slices for ``__getitem__()``\n methods. They are also created by the built-in ``slice()``\n function.\n\n Special read-only attributes: ``start`` is the lower bound;\n ``stop`` is the upper bound; ``step`` is the step value; each is\n ``None`` if omitted. These attributes can have any type.\n\n Slice objects support one method:\n\n slice.indices(self, length)\n\n This method takes a single integer argument *length* and\n computes information about the slice that the slice object\n would describe if applied to a sequence of *length* items.\n It returns a tuple of three integers; respectively these are\n the *start* and *stop* indices and the *step* or stride\n length of the slice. Missing or out-of-bounds indices are\n handled in a manner consistent with regular slices.\n\n Static method objects\n Static method objects provide a way of defeating the\n transformation of function objects to method objects described\n above. A static method object is a wrapper around any other\n object, usually a user-defined method object. When a static\n method object is retrieved from a class or a class instance, the\n object actually returned is the wrapped object, which is not\n subject to any further transformation. Static method objects are\n not themselves callable, although the objects they wrap usually\n are. Static method objects are created by the built-in\n ``staticmethod()`` constructor.\n\n Class method objects\n A class method object, like a static method object, is a wrapper\n around another object that alters the way in which that object\n is retrieved from classes and class instances. The behaviour of\n class method objects upon such retrieval is described above,\n under "User-defined methods". Class method objects are created\n by the built-in ``classmethod()`` constructor.\n', + 'types': '\nThe standard type hierarchy\n***************************\n\nBelow is a list of the types that are built into Python. Extension\nmodules (written in C, Java, or other languages, depending on the\nimplementation) can define additional types. Future versions of\nPython may add types to the type hierarchy (e.g., rational numbers,\nefficiently stored arrays of integers, etc.), although such additions\nwill often be provided via the standard library instead.\n\nSome of the type descriptions below contain a paragraph listing\n\'special attributes.\' These are attributes that provide access to the\nimplementation and are not intended for general use. Their definition\nmay change in the future.\n\nNone\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name ``None``.\n It is used to signify the absence of a value in many situations,\n e.g., it is returned from functions that don\'t explicitly return\n anything. Its truth value is false.\n\nNotImplemented\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name\n ``NotImplemented``. Numeric methods and rich comparison methods may\n return this value if they do not implement the operation for the\n operands provided. (The interpreter will then try the reflected\n operation, or some other fallback, depending on the operator.) Its\n truth value is true.\n\nEllipsis\n This type has a single value. There is a single object with this\n value. This object is accessed through the literal ``...`` or the\n built-in name ``Ellipsis``. Its truth value is true.\n\n``numbers.Number``\n These are created by numeric literals and returned as results by\n arithmetic operators and arithmetic built-in functions. Numeric\n objects are immutable; once created their value never changes.\n Python numbers are of course strongly related to mathematical\n numbers, but subject to the limitations of numerical representation\n in computers.\n\n Python distinguishes between integers, floating point numbers, and\n complex numbers:\n\n ``numbers.Integral``\n These represent elements from the mathematical set of integers\n (positive and negative).\n\n There are two types of integers:\n\n Integers (``int``)\n\n These represent numbers in an unlimited range, subject to\n available (virtual) memory only. For the purpose of shift\n and mask operations, a binary representation is assumed, and\n negative numbers are represented in a variant of 2\'s\n complement which gives the illusion of an infinite string of\n sign bits extending to the left.\n\n Booleans (``bool``)\n These represent the truth values False and True. The two\n objects representing the values ``False`` and ``True`` are\n the only Boolean objects. The Boolean type is a subtype of\n the integer type, and Boolean values behave like the values 0\n and 1, respectively, in almost all contexts, the exception\n being that when converted to a string, the strings\n ``"False"`` or ``"True"`` are returned, respectively.\n\n The rules for integer representation are intended to give the\n most meaningful interpretation of shift and mask operations\n involving negative integers.\n\n ``numbers.Real`` (``float``)\n These represent machine-level double precision floating point\n numbers. You are at the mercy of the underlying machine\n architecture (and C or Java implementation) for the accepted\n range and handling of overflow. Python does not support single-\n precision floating point numbers; the savings in processor and\n memory usage that are usually the reason for using these is\n dwarfed by the overhead of using objects in Python, so there is\n no reason to complicate the language with two kinds of floating\n point numbers.\n\n ``numbers.Complex`` (``complex``)\n These represent complex numbers as a pair of machine-level\n double precision floating point numbers. The same caveats apply\n as for floating point numbers. The real and imaginary parts of a\n complex number ``z`` can be retrieved through the read-only\n attributes ``z.real`` and ``z.imag``.\n\nSequences\n These represent finite ordered sets indexed by non-negative\n numbers. The built-in function ``len()`` returns the number of\n items of a sequence. When the length of a sequence is *n*, the\n index set contains the numbers 0, 1, ..., *n*-1. Item *i* of\n sequence *a* is selected by ``a[i]``.\n\n Sequences also support slicing: ``a[i:j]`` selects all items with\n index *k* such that *i* ``<=`` *k* ``<`` *j*. When used as an\n expression, a slice is a sequence of the same type. This implies\n that the index set is renumbered so that it starts at 0.\n\n Some sequences also support "extended slicing" with a third "step"\n parameter: ``a[i:j:k]`` selects all items of *a* with index *x*\n where ``x = i + n*k``, *n* ``>=`` ``0`` and *i* ``<=`` *x* ``<``\n *j*.\n\n Sequences are distinguished according to their mutability:\n\n Immutable sequences\n An object of an immutable sequence type cannot change once it is\n created. (If the object contains references to other objects,\n these other objects may be mutable and may be changed; however,\n the collection of objects directly referenced by an immutable\n object cannot change.)\n\n The following types are immutable sequences:\n\n Strings\n A string is a sequence of values that represent Unicode\n codepoints. All the codepoints in range ``U+0000 - U+10FFFF``\n can be represented in a string. Python doesn\'t have a\n ``chr`` type, and every character in the string is\n represented as a string object with length ``1``. The built-\n in function ``ord()`` converts a character to its codepoint\n (as an integer); ``chr()`` converts an integer in range ``0 -\n 10FFFF`` to the corresponding character. ``str.encode()`` can\n be used to convert a ``str`` to ``bytes`` using the given\n encoding, and ``bytes.decode()`` can be used to achieve the\n opposite.\n\n Tuples\n The items of a tuple are arbitrary Python objects. Tuples of\n two or more items are formed by comma-separated lists of\n expressions. A tuple of one item (a \'singleton\') can be\n formed by affixing a comma to an expression (an expression by\n itself does not create a tuple, since parentheses must be\n usable for grouping of expressions). An empty tuple can be\n formed by an empty pair of parentheses.\n\n Bytes\n A bytes object is an immutable array. The items are 8-bit\n bytes, represented by integers in the range 0 <= x < 256.\n Bytes literals (like ``b\'abc\'``) and the built-in function\n ``bytes()`` can be used to construct bytes objects. Also,\n bytes objects can be decoded to strings via the ``decode()``\n method.\n\n Mutable sequences\n Mutable sequences can be changed after they are created. The\n subscription and slicing notations can be used as the target of\n assignment and ``del`` (delete) statements.\n\n There are currently two intrinsic mutable sequence types:\n\n Lists\n The items of a list are arbitrary Python objects. Lists are\n formed by placing a comma-separated list of expressions in\n square brackets. (Note that there are no special cases needed\n to form lists of length 0 or 1.)\n\n Byte Arrays\n A bytearray object is a mutable array. They are created by\n the built-in ``bytearray()`` constructor. Aside from being\n mutable (and hence unhashable), byte arrays otherwise provide\n the same interface and functionality as immutable bytes\n objects.\n\n The extension module ``array`` provides an additional example of\n a mutable sequence type, as does the ``collections`` module.\n\nSet types\n These represent unordered, finite sets of unique, immutable\n objects. As such, they cannot be indexed by any subscript. However,\n they can be iterated over, and the built-in function ``len()``\n returns the number of items in a set. Common uses for sets are fast\n membership testing, removing duplicates from a sequence, and\n computing mathematical operations such as intersection, union,\n difference, and symmetric difference.\n\n For set elements, the same immutability rules apply as for\n dictionary keys. Note that numeric types obey the normal rules for\n numeric comparison: if two numbers compare equal (e.g., ``1`` and\n ``1.0``), only one of them can be contained in a set.\n\n There are currently two intrinsic set types:\n\n Sets\n These represent a mutable set. They are created by the built-in\n ``set()`` constructor and can be modified afterwards by several\n methods, such as ``add()``.\n\n Frozen sets\n These represent an immutable set. They are created by the\n built-in ``frozenset()`` constructor. As a frozenset is\n immutable and *hashable*, it can be used again as an element of\n another set, or as a dictionary key.\n\nMappings\n These represent finite sets of objects indexed by arbitrary index\n sets. The subscript notation ``a[k]`` selects the item indexed by\n ``k`` from the mapping ``a``; this can be used in expressions and\n as the target of assignments or ``del`` statements. The built-in\n function ``len()`` returns the number of items in a mapping.\n\n There is currently a single intrinsic mapping type:\n\n Dictionaries\n These represent finite sets of objects indexed by nearly\n arbitrary values. The only types of values not acceptable as\n keys are values containing lists or dictionaries or other\n mutable types that are compared by value rather than by object\n identity, the reason being that the efficient implementation of\n dictionaries requires a key\'s hash value to remain constant.\n Numeric types used for keys obey the normal rules for numeric\n comparison: if two numbers compare equal (e.g., ``1`` and\n ``1.0``) then they can be used interchangeably to index the same\n dictionary entry.\n\n Dictionaries are mutable; they can be created by the ``{...}``\n notation (see section *Dictionary displays*).\n\n The extension modules ``dbm.ndbm`` and ``dbm.gnu`` provide\n additional examples of mapping types, as does the\n ``collections`` module.\n\nCallable types\n These are the types to which the function call operation (see\n section *Calls*) can be applied:\n\n User-defined functions\n A user-defined function object is created by a function\n definition (see section *Function definitions*). It should be\n called with an argument list containing the same number of items\n as the function\'s formal parameter list.\n\n Special attributes:\n\n +---------------------------+---------------------------------+-------------+\n | Attribute | Meaning | |\n +===========================+=================================+=============+\n | ``__doc__`` | The function\'s documentation | Writable |\n | | string, or ``None`` if | |\n | | unavailable | |\n +---------------------------+---------------------------------+-------------+\n | ``__name__`` | The function\'s name | Writable |\n +---------------------------+---------------------------------+-------------+\n | ``__qualname__`` | The function\'s *qualified name* | Writable |\n | | New in version 3.3. | |\n +---------------------------+---------------------------------+-------------+\n | ``__module__`` | The name of the module the | Writable |\n | | function was defined in, or | |\n | | ``None`` if unavailable. | |\n +---------------------------+---------------------------------+-------------+\n | ``__defaults__`` | A tuple containing default | Writable |\n | | argument values for those | |\n | | arguments that have defaults, | |\n | | or ``None`` if no arguments | |\n | | have a default value | |\n +---------------------------+---------------------------------+-------------+\n | ``__code__`` | The code object representing | Writable |\n | | the compiled function body. | |\n +---------------------------+---------------------------------+-------------+\n | ``__globals__`` | A reference to the dictionary | Read-only |\n | | that holds the function\'s | |\n | | global variables --- the global | |\n | | namespace of the module in | |\n | | which the function was defined. | |\n +---------------------------+---------------------------------+-------------+\n | ``__dict__`` | The namespace supporting | Writable |\n | | arbitrary function attributes. | |\n +---------------------------+---------------------------------+-------------+\n | ``__closure__`` | ``None`` or a tuple of cells | Read-only |\n | | that contain bindings for the | |\n | | function\'s free variables. | |\n +---------------------------+---------------------------------+-------------+\n | ``__annotations__`` | A dict containing annotations | Writable |\n | | of parameters. The keys of the | |\n | | dict are the parameter names, | |\n | | and ``\'return\'`` for the return | |\n | | annotation, if provided. | |\n +---------------------------+---------------------------------+-------------+\n | ``__kwdefaults__`` | A dict containing defaults for | Writable |\n | | keyword-only parameters. | |\n +---------------------------+---------------------------------+-------------+\n\n Most of the attributes labelled "Writable" check the type of the\n assigned value.\n\n Function objects also support getting and setting arbitrary\n attributes, which can be used, for example, to attach metadata\n to functions. Regular attribute dot-notation is used to get and\n set such attributes. *Note that the current implementation only\n supports function attributes on user-defined functions. Function\n attributes on built-in functions may be supported in the\n future.*\n\n Additional information about a function\'s definition can be\n retrieved from its code object; see the description of internal\n types below.\n\n Instance methods\n An instance method object combines a class, a class instance and\n any callable object (normally a user-defined function).\n\n Special read-only attributes: ``__self__`` is the class instance\n object, ``__func__`` is the function object; ``__doc__`` is the\n method\'s documentation (same as ``__func__.__doc__``);\n ``__name__`` is the method name (same as ``__func__.__name__``);\n ``__module__`` is the name of the module the method was defined\n in, or ``None`` if unavailable.\n\n Methods also support accessing (but not setting) the arbitrary\n function attributes on the underlying function object.\n\n User-defined method objects may be created when getting an\n attribute of a class (perhaps via an instance of that class), if\n that attribute is a user-defined function object or a class\n method object.\n\n When an instance method object is created by retrieving a user-\n defined function object from a class via one of its instances,\n its ``__self__`` attribute is the instance, and the method\n object is said to be bound. The new method\'s ``__func__``\n attribute is the original function object.\n\n When a user-defined method object is created by retrieving\n another method object from a class or instance, the behaviour is\n the same as for a function object, except that the ``__func__``\n attribute of the new instance is not the original method object\n but its ``__func__`` attribute.\n\n When an instance method object is created by retrieving a class\n method object from a class or instance, its ``__self__``\n attribute is the class itself, and its ``__func__`` attribute is\n the function object underlying the class method.\n\n When an instance method object is called, the underlying\n function (``__func__``) is called, inserting the class instance\n (``__self__``) in front of the argument list. For instance,\n when ``C`` is a class which contains a definition for a function\n ``f()``, and ``x`` is an instance of ``C``, calling ``x.f(1)``\n is equivalent to calling ``C.f(x, 1)``.\n\n When an instance method object is derived from a class method\n object, the "class instance" stored in ``__self__`` will\n actually be the class itself, so that calling either ``x.f(1)``\n or ``C.f(1)`` is equivalent to calling ``f(C,1)`` where ``f`` is\n the underlying function.\n\n Note that the transformation from function object to instance\n method object happens each time the attribute is retrieved from\n the instance. In some cases, a fruitful optimization is to\n assign the attribute to a local variable and call that local\n variable. Also notice that this transformation only happens for\n user-defined functions; other callable objects (and all non-\n callable objects) are retrieved without transformation. It is\n also important to note that user-defined functions which are\n attributes of a class instance are not converted to bound\n methods; this *only* happens when the function is an attribute\n of the class.\n\n Generator functions\n A function or method which uses the ``yield`` statement (see\n section *The yield statement*) is called a *generator function*.\n Such a function, when called, always returns an iterator object\n which can be used to execute the body of the function: calling\n the iterator\'s ``iterator.__next__()`` method will cause the\n function to execute until it provides a value using the\n ``yield`` statement. When the function executes a ``return``\n statement or falls off the end, a ``StopIteration`` exception is\n raised and the iterator will have reached the end of the set of\n values to be returned.\n\n Built-in functions\n A built-in function object is a wrapper around a C function.\n Examples of built-in functions are ``len()`` and ``math.sin()``\n (``math`` is a standard built-in module). The number and type of\n the arguments are determined by the C function. Special read-\n only attributes: ``__doc__`` is the function\'s documentation\n string, or ``None`` if unavailable; ``__name__`` is the\n function\'s name; ``__self__`` is set to ``None`` (but see the\n next item); ``__module__`` is the name of the module the\n function was defined in or ``None`` if unavailable.\n\n Built-in methods\n This is really a different disguise of a built-in function, this\n time containing an object passed to the C function as an\n implicit extra argument. An example of a built-in method is\n ``alist.append()``, assuming *alist* is a list object. In this\n case, the special read-only attribute ``__self__`` is set to the\n object denoted by *alist*.\n\n Classes\n Classes are callable. These objects normally act as factories\n for new instances of themselves, but variations are possible for\n class types that override ``__new__()``. The arguments of the\n call are passed to ``__new__()`` and, in the typical case, to\n ``__init__()`` to initialize the new instance.\n\n Class Instances\n Instances of arbitrary classes can be made callable by defining\n a ``__call__()`` method in their class.\n\nModules\n Modules are a basic organizational unit of Python code, and are\n created by the *import system* as invoked either by the ``import``\n statement (see ``import``), or by calling functions such as\n ``importlib.import_module()`` and built-in ``__import__()``. A\n module object has a namespace implemented by a dictionary object\n (this is the dictionary referenced by the ``__globals__`` attribute\n of functions defined in the module). Attribute references are\n translated to lookups in this dictionary, e.g., ``m.x`` is\n equivalent to ``m.__dict__["x"]``. A module object does not contain\n the code object used to initialize the module (since it isn\'t\n needed once the initialization is done).\n\n Attribute assignment updates the module\'s namespace dictionary,\n e.g., ``m.x = 1`` is equivalent to ``m.__dict__["x"] = 1``.\n\n Special read-only attribute: ``__dict__`` is the module\'s namespace\n as a dictionary object.\n\n **CPython implementation detail:** Because of the way CPython\n clears module dictionaries, the module dictionary will be cleared\n when the module falls out of scope even if the dictionary still has\n live references. To avoid this, copy the dictionary or keep the\n module around while using its dictionary directly.\n\n Predefined (writable) attributes: ``__name__`` is the module\'s\n name; ``__doc__`` is the module\'s documentation string, or ``None``\n if unavailable; ``__file__`` is the pathname of the file from which\n the module was loaded, if it was loaded from a file. The\n ``__file__`` attribute may be missing for certain types of modules,\n such as C modules that are statically linked into the interpreter;\n for extension modules loaded dynamically from a shared library, it\n is the pathname of the shared library file.\n\nCustom classes\n Custom class types are typically created by class definitions (see\n section *Class definitions*). A class has a namespace implemented\n by a dictionary object. Class attribute references are translated\n to lookups in this dictionary, e.g., ``C.x`` is translated to\n ``C.__dict__["x"]`` (although there are a number of hooks which\n allow for other means of locating attributes). When the attribute\n name is not found there, the attribute search continues in the base\n classes. This search of the base classes uses the C3 method\n resolution order which behaves correctly even in the presence of\n \'diamond\' inheritance structures where there are multiple\n inheritance paths leading back to a common ancestor. Additional\n details on the C3 MRO used by Python can be found in the\n documentation accompanying the 2.3 release at\n http://www.python.org/download/releases/2.3/mro/.\n\n When a class attribute reference (for class ``C``, say) would yield\n a class method object, it is transformed into an instance method\n object whose ``__self__`` attributes is ``C``. When it would yield\n a static method object, it is transformed into the object wrapped\n by the static method object. See section *Implementing Descriptors*\n for another way in which attributes retrieved from a class may\n differ from those actually contained in its ``__dict__``.\n\n Class attribute assignments update the class\'s dictionary, never\n the dictionary of a base class.\n\n A class object can be called (see above) to yield a class instance\n (see below).\n\n Special attributes: ``__name__`` is the class name; ``__module__``\n is the module name in which the class was defined; ``__dict__`` is\n the dictionary containing the class\'s namespace; ``__bases__`` is a\n tuple (possibly empty or a singleton) containing the base classes,\n in the order of their occurrence in the base class list;\n ``__doc__`` is the class\'s documentation string, or None if\n undefined.\n\nClass instances\n A class instance is created by calling a class object (see above).\n A class instance has a namespace implemented as a dictionary which\n is the first place in which attribute references are searched.\n When an attribute is not found there, and the instance\'s class has\n an attribute by that name, the search continues with the class\n attributes. If a class attribute is found that is a user-defined\n function object, it is transformed into an instance method object\n whose ``__self__`` attribute is the instance. Static method and\n class method objects are also transformed; see above under\n "Classes". See section *Implementing Descriptors* for another way\n in which attributes of a class retrieved via its instances may\n differ from the objects actually stored in the class\'s\n ``__dict__``. If no class attribute is found, and the object\'s\n class has a ``__getattr__()`` method, that is called to satisfy the\n lookup.\n\n Attribute assignments and deletions update the instance\'s\n dictionary, never a class\'s dictionary. If the class has a\n ``__setattr__()`` or ``__delattr__()`` method, this is called\n instead of updating the instance dictionary directly.\n\n Class instances can pretend to be numbers, sequences, or mappings\n if they have methods with certain special names. See section\n *Special method names*.\n\n Special attributes: ``__dict__`` is the attribute dictionary;\n ``__class__`` is the instance\'s class.\n\nI/O objects (also known as file objects)\n A *file object* represents an open file. Various shortcuts are\n available to create file objects: the ``open()`` built-in function,\n and also ``os.popen()``, ``os.fdopen()``, and the ``makefile()``\n method of socket objects (and perhaps by other functions or methods\n provided by extension modules).\n\n The objects ``sys.stdin``, ``sys.stdout`` and ``sys.stderr`` are\n initialized to file objects corresponding to the interpreter\'s\n standard input, output and error streams; they are all open in text\n mode and therefore follow the interface defined by the\n ``io.TextIOBase`` abstract class.\n\nInternal types\n A few types used internally by the interpreter are exposed to the\n user. Their definitions may change with future versions of the\n interpreter, but they are mentioned here for completeness.\n\n Code objects\n Code objects represent *byte-compiled* executable Python code,\n or *bytecode*. The difference between a code object and a\n function object is that the function object contains an explicit\n reference to the function\'s globals (the module in which it was\n defined), while a code object contains no context; also the\n default argument values are stored in the function object, not\n in the code object (because they represent values calculated at\n run-time). Unlike function objects, code objects are immutable\n and contain no references (directly or indirectly) to mutable\n objects.\n\n Special read-only attributes: ``co_name`` gives the function\n name; ``co_argcount`` is the number of positional arguments\n (including arguments with default values); ``co_nlocals`` is the\n number of local variables used by the function (including\n arguments); ``co_varnames`` is a tuple containing the names of\n the local variables (starting with the argument names);\n ``co_cellvars`` is a tuple containing the names of local\n variables that are referenced by nested functions;\n ``co_freevars`` is a tuple containing the names of free\n variables; ``co_code`` is a string representing the sequence of\n bytecode instructions; ``co_consts`` is a tuple containing the\n literals used by the bytecode; ``co_names`` is a tuple\n containing the names used by the bytecode; ``co_filename`` is\n the filename from which the code was compiled;\n ``co_firstlineno`` is the first line number of the function;\n ``co_lnotab`` is a string encoding the mapping from bytecode\n offsets to line numbers (for details see the source code of the\n interpreter); ``co_stacksize`` is the required stack size\n (including local variables); ``co_flags`` is an integer encoding\n a number of flags for the interpreter.\n\n The following flag bits are defined for ``co_flags``: bit\n ``0x04`` is set if the function uses the ``*arguments`` syntax\n to accept an arbitrary number of positional arguments; bit\n ``0x08`` is set if the function uses the ``**keywords`` syntax\n to accept arbitrary keyword arguments; bit ``0x20`` is set if\n the function is a generator.\n\n Future feature declarations (``from __future__ import\n division``) also use bits in ``co_flags`` to indicate whether a\n code object was compiled with a particular feature enabled: bit\n ``0x2000`` is set if the function was compiled with future\n division enabled; bits ``0x10`` and ``0x1000`` were used in\n earlier versions of Python.\n\n Other bits in ``co_flags`` are reserved for internal use.\n\n If a code object represents a function, the first item in\n ``co_consts`` is the documentation string of the function, or\n ``None`` if undefined.\n\n Frame objects\n Frame objects represent execution frames. They may occur in\n traceback objects (see below).\n\n Special read-only attributes: ``f_back`` is to the previous\n stack frame (towards the caller), or ``None`` if this is the\n bottom stack frame; ``f_code`` is the code object being executed\n in this frame; ``f_locals`` is the dictionary used to look up\n local variables; ``f_globals`` is used for global variables;\n ``f_builtins`` is used for built-in (intrinsic) names;\n ``f_lasti`` gives the precise instruction (this is an index into\n the bytecode string of the code object).\n\n Special writable attributes: ``f_trace``, if not ``None``, is a\n function called at the start of each source code line (this is\n used by the debugger); ``f_lineno`` is the current line number\n of the frame --- writing to this from within a trace function\n jumps to the given line (only for the bottom-most frame). A\n debugger can implement a Jump command (aka Set Next Statement)\n by writing to f_lineno.\n\n Frame objects support one method:\n\n frame.clear()\n\n This method clears all references to local variables held by\n the frame. Also, if the frame belonged to a generator, the\n generator is finalized. This helps break reference cycles\n involving frame objects (for example when catching an\n exception and storing its traceback for later use).\n\n ``RuntimeError`` is raised if the frame is currently\n executing.\n\n New in version 3.4.\n\n Traceback objects\n Traceback objects represent a stack trace of an exception. A\n traceback object is created when an exception occurs. When the\n search for an exception handler unwinds the execution stack, at\n each unwound level a traceback object is inserted in front of\n the current traceback. When an exception handler is entered,\n the stack trace is made available to the program. (See section\n *The try statement*.) It is accessible as the third item of the\n tuple returned by ``sys.exc_info()``. When the program contains\n no suitable handler, the stack trace is written (nicely\n formatted) to the standard error stream; if the interpreter is\n interactive, it is also made available to the user as\n ``sys.last_traceback``.\n\n Special read-only attributes: ``tb_next`` is the next level in\n the stack trace (towards the frame where the exception\n occurred), or ``None`` if there is no next level; ``tb_frame``\n points to the execution frame of the current level;\n ``tb_lineno`` gives the line number where the exception\n occurred; ``tb_lasti`` indicates the precise instruction. The\n line number and last instruction in the traceback may differ\n from the line number of its frame object if the exception\n occurred in a ``try`` statement with no matching except clause\n or with a finally clause.\n\n Slice objects\n Slice objects are used to represent slices for ``__getitem__()``\n methods. They are also created by the built-in ``slice()``\n function.\n\n Special read-only attributes: ``start`` is the lower bound;\n ``stop`` is the upper bound; ``step`` is the step value; each is\n ``None`` if omitted. These attributes can have any type.\n\n Slice objects support one method:\n\n slice.indices(self, length)\n\n This method takes a single integer argument *length* and\n computes information about the slice that the slice object\n would describe if applied to a sequence of *length* items.\n It returns a tuple of three integers; respectively these are\n the *start* and *stop* indices and the *step* or stride\n length of the slice. Missing or out-of-bounds indices are\n handled in a manner consistent with regular slices.\n\n Static method objects\n Static method objects provide a way of defeating the\n transformation of function objects to method objects described\n above. A static method object is a wrapper around any other\n object, usually a user-defined method object. When a static\n method object is retrieved from a class or a class instance, the\n object actually returned is the wrapped object, which is not\n subject to any further transformation. Static method objects are\n not themselves callable, although the objects they wrap usually\n are. Static method objects are created by the built-in\n ``staticmethod()`` constructor.\n\n Class method objects\n A class method object, like a static method object, is a wrapper\n around another object that alters the way in which that object\n is retrieved from classes and class instances. The behaviour of\n class method objects upon such retrieval is described above,\n under "User-defined methods". Class method objects are created\n by the built-in ``classmethod()`` constructor.\n', 'typesfunctions': '\nFunctions\n*********\n\nFunction objects are created by function definitions. The only\noperation on a function object is to call it: ``func(argument-list)``.\n\nThere are really two flavors of function objects: built-in functions\nand user-defined functions. Both support the same operation (to call\nthe function), but the implementation is different, hence the\ndifferent object types.\n\nSee *Function definitions* for more information.\n', 'typesmapping': '\nMapping Types --- ``dict``\n**************************\n\nA *mapping* object maps *hashable* values to arbitrary objects.\nMappings are mutable objects. There is currently only one standard\nmapping type, the *dictionary*. (For other containers see the built-\nin ``list``, ``set``, and ``tuple`` classes, and the ``collections``\nmodule.)\n\nA dictionary\'s keys are *almost* arbitrary values. Values that are\nnot *hashable*, that is, values containing lists, dictionaries or\nother mutable types (that are compared by value rather than by object\nidentity) may not be used as keys. Numeric types used for keys obey\nthe normal rules for numeric comparison: if two numbers compare equal\n(such as ``1`` and ``1.0``) then they can be used interchangeably to\nindex the same dictionary entry. (Note however, that since computers\nstore floating-point numbers as approximations it is usually unwise to\nuse them as dictionary keys.)\n\nDictionaries can be created by placing a comma-separated list of\n``key: value`` pairs within braces, for example: ``{\'jack\': 4098,\n\'sjoerd\': 4127}`` or ``{4098: \'jack\', 4127: \'sjoerd\'}``, or by the\n``dict`` constructor.\n\nclass class dict(**kwarg)\nclass class dict(mapping, **kwarg)\nclass class dict(iterable, **kwarg)\n\n Return a new dictionary initialized from an optional positional\n argument and a possibly empty set of keyword arguments.\n\n If no positional argument is given, an empty dictionary is created.\n If a positional argument is given and it is a mapping object, a\n dictionary is created with the same key-value pairs as the mapping\n object. Otherwise, the positional argument must be an *iterator*\n object. Each item in the iterable must itself be an iterator with\n exactly two objects. The first object of each item becomes a key\n in the new dictionary, and the second object the corresponding\n value. If a key occurs more than once, the last value for that key\n becomes the corresponding value in the new dictionary.\n\n If keyword arguments are given, the keyword arguments and their\n values are added to the dictionary created from the positional\n argument. If a key being added is already present, the value from\n the keyword argument replaces the value from the positional\n argument.\n\n To illustrate, the following examples all return a dictionary equal\n to ``{"one": 1, "two": 2, "three": 3}``:\n\n >>> a = dict(one=1, two=2, three=3)\n >>> b = {\'one\': 1, \'two\': 2, \'three\': 3}\n >>> c = dict(zip([\'one\', \'two\', \'three\'], [1, 2, 3]))\n >>> d = dict([(\'two\', 2), (\'one\', 1), (\'three\', 3)])\n >>> e = dict({\'three\': 3, \'one\': 1, \'two\': 2})\n >>> a == b == c == d == e\n True\n\n Providing keyword arguments as in the first example only works for\n keys that are valid Python identifiers. Otherwise, any valid keys\n can be used.\n\n These are the operations that dictionaries support (and therefore,\n custom mapping types should support too):\n\n len(d)\n\n Return the number of items in the dictionary *d*.\n\n d[key]\n\n Return the item of *d* with key *key*. Raises a ``KeyError`` if\n *key* is not in the map.\n\n If a subclass of dict defines a method ``__missing__()``, if the\n key *key* is not present, the ``d[key]`` operation calls that\n method with the key *key* as argument. The ``d[key]`` operation\n then returns or raises whatever is returned or raised by the\n ``__missing__(key)`` call if the key is not present. No other\n operations or methods invoke ``__missing__()``. If\n ``__missing__()`` is not defined, ``KeyError`` is raised.\n ``__missing__()`` must be a method; it cannot be an instance\n variable:\n\n >>> class Counter(dict):\n ... def __missing__(self, key):\n ... return 0\n >>> c = Counter()\n >>> c[\'red\']\n 0\n >>> c[\'red\'] += 1\n >>> c[\'red\']\n 1\n\n See ``collections.Counter`` for a complete implementation\n including other methods helpful for accumulating and managing\n tallies.\n\n d[key] = value\n\n Set ``d[key]`` to *value*.\n\n del d[key]\n\n Remove ``d[key]`` from *d*. Raises a ``KeyError`` if *key* is\n not in the map.\n\n key in d\n\n Return ``True`` if *d* has a key *key*, else ``False``.\n\n key not in d\n\n Equivalent to ``not key in d``.\n\n iter(d)\n\n Return an iterator over the keys of the dictionary. This is a\n shortcut for ``iter(d.keys())``.\n\n clear()\n\n Remove all items from the dictionary.\n\n copy()\n\n Return a shallow copy of the dictionary.\n\n classmethod fromkeys(seq[, value])\n\n Create a new dictionary with keys from *seq* and values set to\n *value*.\n\n ``fromkeys()`` is a class method that returns a new dictionary.\n *value* defaults to ``None``.\n\n get(key[, default])\n\n Return the value for *key* if *key* is in the dictionary, else\n *default*. If *default* is not given, it defaults to ``None``,\n so that this method never raises a ``KeyError``.\n\n items()\n\n Return a new view of the dictionary\'s items (``(key, value)``\n pairs). See the *documentation of view objects*.\n\n keys()\n\n Return a new view of the dictionary\'s keys. See the\n *documentation of view objects*.\n\n pop(key[, default])\n\n If *key* is in the dictionary, remove it and return its value,\n else return *default*. If *default* is not given and *key* is\n not in the dictionary, a ``KeyError`` is raised.\n\n popitem()\n\n Remove and return an arbitrary ``(key, value)`` pair from the\n dictionary.\n\n ``popitem()`` is useful to destructively iterate over a\n dictionary, as often used in set algorithms. If the dictionary\n is empty, calling ``popitem()`` raises a ``KeyError``.\n\n setdefault(key[, default])\n\n If *key* is in the dictionary, return its value. If not, insert\n *key* with a value of *default* and return *default*. *default*\n defaults to ``None``.\n\n update([other])\n\n Update the dictionary with the key/value pairs from *other*,\n overwriting existing keys. Return ``None``.\n\n ``update()`` accepts either another dictionary object or an\n iterable of key/value pairs (as tuples or other iterables of\n length two). If keyword arguments are specified, the dictionary\n is then updated with those key/value pairs: ``d.update(red=1,\n blue=2)``.\n\n values()\n\n Return a new view of the dictionary\'s values. See the\n *documentation of view objects*.\n\nSee also:\n\n ``types.MappingProxyType`` can be used to create a read-only view\n of a ``dict``.\n\n\nDictionary view objects\n=======================\n\nThe objects returned by ``dict.keys()``, ``dict.values()`` and\n``dict.items()`` are *view objects*. They provide a dynamic view on\nthe dictionary\'s entries, which means that when the dictionary\nchanges, the view reflects these changes.\n\nDictionary views can be iterated over to yield their respective data,\nand support membership tests:\n\nlen(dictview)\n\n Return the number of entries in the dictionary.\n\niter(dictview)\n\n Return an iterator over the keys, values or items (represented as\n tuples of ``(key, value)``) in the dictionary.\n\n Keys and values are iterated over in an arbitrary order which is\n non-random, varies across Python implementations, and depends on\n the dictionary\'s history of insertions and deletions. If keys,\n values and items views are iterated over with no intervening\n modifications to the dictionary, the order of items will directly\n correspond. This allows the creation of ``(value, key)`` pairs\n using ``zip()``: ``pairs = zip(d.values(), d.keys())``. Another\n way to create the same list is ``pairs = [(v, k) for (k, v) in\n d.items()]``.\n\n Iterating views while adding or deleting entries in the dictionary\n may raise a ``RuntimeError`` or fail to iterate over all entries.\n\nx in dictview\n\n Return ``True`` if *x* is in the underlying dictionary\'s keys,\n values or items (in the latter case, *x* should be a ``(key,\n value)`` tuple).\n\nKeys views are set-like since their entries are unique and hashable.\nIf all values are hashable, so that ``(key, value)`` pairs are unique\nand hashable, then the items view is also set-like. (Values views are\nnot treated as set-like since the entries are generally not unique.)\nFor set-like views, all of the operations defined for the abstract\nbase class ``collections.abc.Set`` are available (for example, ``==``,\n``<``, or ``^``).\n\nAn example of dictionary view usage:\n\n >>> dishes = {\'eggs\': 2, \'sausage\': 1, \'bacon\': 1, \'spam\': 500}\n >>> keys = dishes.keys()\n >>> values = dishes.values()\n\n >>> # iteration\n >>> n = 0\n >>> for val in values:\n ... n += val\n >>> print(n)\n 504\n\n >>> # keys and values are iterated over in the same order\n >>> list(keys)\n [\'eggs\', \'bacon\', \'sausage\', \'spam\']\n >>> list(values)\n [2, 1, 1, 500]\n\n >>> # view objects are dynamic and reflect dict changes\n >>> del dishes[\'eggs\']\n >>> del dishes[\'sausage\']\n >>> list(keys)\n [\'spam\', \'bacon\']\n\n >>> # set operations\n >>> keys & {\'eggs\', \'bacon\', \'salad\'}\n {\'bacon\'}\n >>> keys ^ {\'sausage\', \'juice\'}\n {\'juice\', \'sausage\', \'bacon\', \'spam\'}\n', 'typesmethods': '\nMethods\n*******\n\nMethods are functions that are called using the attribute notation.\nThere are two flavors: built-in methods (such as ``append()`` on\nlists) and class instance methods. Built-in methods are described\nwith the types that support them.\n\nIf you access a method (a function defined in a class namespace)\nthrough an instance, you get a special object: a *bound method* (also\ncalled *instance method*) object. When called, it will add the\n``self`` argument to the argument list. Bound methods have two\nspecial read-only attributes: ``m.__self__`` is the object on which\nthe method operates, and ``m.__func__`` is the function implementing\nthe method. Calling ``m(arg-1, arg-2, ..., arg-n)`` is completely\nequivalent to calling ``m.__func__(m.__self__, arg-1, arg-2, ...,\narg-n)``.\n\nLike function objects, bound method objects support getting arbitrary\nattributes. However, since method attributes are actually stored on\nthe underlying function object (``meth.__func__``), setting method\nattributes on bound methods is disallowed. Attempting to set an\nattribute on a method results in an ``AttributeError`` being raised.\nIn order to set a method attribute, you need to explicitly set it on\nthe underlying function object:\n\n >>> class C:\n ... def method(self):\n ... pass\n ...\n >>> c = C()\n >>> c.method.whoami = \'my name is method\' # can\'t set on the method\n Traceback (most recent call last):\n File "", line 1, in \n AttributeError: \'method\' object has no attribute \'whoami\'\n >>> c.method.__func__.whoami = \'my name is method\'\n >>> c.method.whoami\n \'my name is method\'\n\nSee *The standard type hierarchy* for more information.\n', -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 6 16:24:49 2014 From: python-checkins at python.org (larry.hastings) Date: Mon, 6 Jan 2014 16:24:49 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Bump_version_number_for_3?= =?utf-8?b?LjQuMGIyLg==?= Message-ID: <3dygWP2tLyzT0F@mail.python.org> http://hg.python.org/cpython/rev/ba32913eb13e changeset: 88318:ba32913eb13e tag: v3.4.0b2 user: Larry Hastings date: Sun Jan 05 04:40:25 2014 -0800 summary: Bump version number for 3.4.0b2. files: Include/patchlevel.h | 4 ++-- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/RPM/python-3.4.spec | 2 +- README | 2 +- 5 files changed, 6 insertions(+), 6 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 4 #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.4.0b1" +#define PY_VERSION "3.4.0b2" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -13,5 +13,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.4.0b1" +__version__ = "3.4.0b2" #--end constants-- diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1,1 +1,1 @@ -IDLE_VERSION = "3.4.0b1" +IDLE_VERSION = "3.4.0b2" diff --git a/Misc/RPM/python-3.4.spec b/Misc/RPM/python-3.4.spec --- a/Misc/RPM/python-3.4.spec +++ b/Misc/RPM/python-3.4.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 3.4.0b1 +%define version 3.4.0b2 %define libvers 3.4 #--end constants-- %define release 1pydotorg diff --git a/README b/README --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Python version 3.4.0 beta 1 +This is Python version 3.4.0 beta 2 =================================== Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 6 16:24:50 2014 From: python-checkins at python.org (larry.hastings) Date: Mon, 6 Jan 2014 16:24:50 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Added_tag_v3=2E4=2E0b2_for?= =?utf-8?q?_changeset_ba32913eb13e?= Message-ID: <3dygWQ4Cg6z7LjX@mail.python.org> http://hg.python.org/cpython/rev/9dac16369df8 changeset: 88319:9dac16369df8 user: Larry Hastings date: Sun Jan 05 04:43:31 2014 -0800 summary: Added tag v3.4.0b2 for changeset ba32913eb13e files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -123,3 +123,4 @@ dd9cdf90a5073510877e9dd5112f8e6cf20d5e89 v3.4.0a3 e245b0d7209bb6d0e19316e1e2af1aa9c2139104 v3.4.0a4 3405dc9a6afaa0a06dd1f6f182ec5c998dce6f5f v3.4.0b1 +ba32913eb13ec545a46dd0ce18035b6c416f0d78 v3.4.0b2 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 6 16:24:51 2014 From: python-checkins at python.org (larry.hastings) Date: Mon, 6 Jan 2014 16:24:51 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Post-release_engineering?= =?utf-8?q?=3B_updated_NEWS_and_version_string=2E?= Message-ID: <3dygWR6VDwz7Lk0@mail.python.org> http://hg.python.org/cpython/rev/d26ff99508cb changeset: 88320:d26ff99508cb user: Larry Hastings date: Mon Jan 06 07:17:47 2014 -0800 summary: Post-release engineering; updated NEWS and version string. 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.4.0b2" +#define PY_VERSION "3.4.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.4.0 Release Candidate 1? +=============================================== + +Release date: 2014-01-19 + +Core and Builtins +----------------- + +Library +------- + + What's New in Python 3.4.0 Beta 2? ================================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 6 16:24:53 2014 From: python-checkins at python.org (larry.hastings) Date: Mon, 6 Jan 2014 16:24:53 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E4=2E0b2_release_revisions_back_into_mainline?= =?utf-8?q?=2E?= Message-ID: <3dygWT3Hvsz7Ljk@mail.python.org> http://hg.python.org/cpython/rev/44c4ba63631d changeset: 88321:44c4ba63631d parent: 88320:d26ff99508cb parent: 88314:247f12fecf2b user: Larry Hastings date: Mon Jan 06 07:24:19 2014 -0800 summary: Merge 3.4.0b2 release revisions back into mainline. files: Doc/reference/datamodel.rst | 14 +++++++-- Lib/tarfile.py | 2 +- Lib/test/test_format.py | 5 --- Lib/test/test_unicode.py | 29 ++++++++++++++++++++ Misc/NEWS | 4 ++ Objects/setobject.c | 15 ++++++++++- Objects/unicodeobject.c | 35 +++++++++++++++++++----- 7 files changed, 86 insertions(+), 18 deletions(-) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -2080,9 +2080,17 @@ .. method:: object.__index__(self) - Called to implement :func:`operator.index`. Also called whenever Python needs - an integer object (such as in slicing, or in the built-in :func:`bin`, - :func:`hex` and :func:`oct` functions). Must return an integer. + Called to implement :func:`operator.index`, and whenever Python needs to + losslessly convert the numeric object to an integer object (such as in + slicing, or in the built-in :func:`bin`, :func:`hex` and :func:`oct` + functions). Presence of this method indicates that the numeric object is + an integer type. Must return an integer. + + .. note:: + + When :meth:`__index__` is defined, :meth:`__int__` should also be defined, + and both shuld return the same value, in order to have a coherent integer + type class. .. _context-managers: diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -196,7 +196,7 @@ # A 0o200 byte indicates a positive number, a 0o377 byte a negative # number. if 0 <= n < 8 ** (digits - 1): - s = bytes("%0*o" % (digits - 1, n), "ascii") + NUL + s = bytes("%0*o" % (digits - 1, int(n)), "ascii") + NUL elif format == GNU_FORMAT and -256 ** (digits - 1) <= n < 256 ** (digits - 1): if n >= 0: s = bytearray([0o200]) diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py --- a/Lib/test/test_format.py +++ b/Lib/test/test_format.py @@ -142,7 +142,6 @@ testformat("%#+027.23X", big, "+0X0001234567890ABCDEF12345") # same, except no 0 flag testformat("%#+27.23X", big, " +0X001234567890ABCDEF12345") - testformat("%x", float(big), "123456_______________", 6) big = 0o12345670123456701234567012345670 # 32 octal digits testformat("%o", big, "12345670123456701234567012345670") testformat("%o", -big, "-12345670123456701234567012345670") @@ -182,7 +181,6 @@ testformat("%034.33o", big, "0012345670123456701234567012345670") # base marker shouldn't change that testformat("%0#34.33o", big, "0o012345670123456701234567012345670") - testformat("%o", float(big), "123456__________________________", 6) # Some small ints, in both Python int and flavors). testformat("%d", 42, "42") testformat("%d", -42, "-42") @@ -193,7 +191,6 @@ testformat("%#x", 1, "0x1") testformat("%#X", 1, "0X1") testformat("%#X", 1, "0X1") - testformat("%#x", 1.0, "0x1") testformat("%#o", 1, "0o1") testformat("%#o", 1, "0o1") testformat("%#o", 0, "0o0") @@ -210,12 +207,10 @@ testformat("%x", -0x42, "-42") testformat("%x", 0x42, "42") testformat("%x", -0x42, "-42") - testformat("%x", float(0x42), "42") testformat("%o", 0o42, "42") testformat("%o", -0o42, "-42") testformat("%o", 0o42, "42") testformat("%o", -0o42, "-42") - testformat("%o", float(0o42), "42") testformat("%r", "\u0378", "'\\u0378'") # non printable testformat("%a", "\u0378", "'\\u0378'") # non printable testformat("%r", "\u0374", "'\u0374'") # printable 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 @@ -1126,6 +1126,35 @@ self.assertEqual('%.1s' % "a\xe9\u20ac", 'a') self.assertEqual('%.2s' % "a\xe9\u20ac", 'a\xe9') + #issue 19995 + class PsuedoInt: + def __init__(self, value): + self.value = int(value) + def __int__(self): + return self.value + def __index__(self): + return self.value + class PsuedoFloat: + def __init__(self, value): + self.value = float(value) + def __int__(self): + return int(self.value) + pi = PsuedoFloat(3.1415) + letter_m = PsuedoInt(109) + self.assertEquals('%x' % 42, '2a') + self.assertEquals('%X' % 15, 'F') + self.assertEquals('%o' % 9, '11') + self.assertEquals('%c' % 109, 'm') + self.assertEquals('%x' % letter_m, '6d') + self.assertEquals('%X' % letter_m, '6D') + self.assertEquals('%o' % letter_m, '155') + self.assertEquals('%c' % letter_m, 'm') + self.assertRaises(TypeError, '%x'.__mod__, pi) + self.assertRaises(TypeError, '%x'.__mod__, 3.14) + self.assertRaises(TypeError, '%X'.__mod__, 2.11) + self.assertRaises(TypeError, '%o'.__mod__, 1.79) + self.assertRaises(TypeError, '%c'.__mod__, pi) + def test_formatting_with_enum(self): # issue18780 import enum diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,10 @@ - Issue #19969: PyBytes_FromFormatV() now raises an OverflowError if "%c" argument is not in range [0; 255]. +- Issue #19995: %c, %o, %x, and %X now raise TypeError on non-integer input; + reworded docs to clarify that an integer type should define both __int__ + and __index__. + - Issue #19787: PyThread_set_key_value() now always set the value. In Python 3.3, the function did nothing if the key already exists (if the current value is a non-NULL pointer). diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -738,6 +738,17 @@ static Py_hash_t frozenset_hash(PyObject *self) { + /* Most of the constants in this hash algorithm are randomly choosen + large primes with "interesting bit patterns" and that passed + tests for good collision statistics on a variety of problematic + datasets such as: + + ps = [] + for r in range(21): + ps += itertools.combinations(range(20), r) + num_distinct_hashes = len({hash(frozenset(s)) for s in ps}) + + */ PySetObject *so = (PySetObject *)self; Py_uhash_t h, hash = 1927868237UL; setentry *entry; @@ -754,8 +765,10 @@ hashes so that many distinct combinations collapse to only a handful of distinct hash values. */ h = entry->hash; - hash ^= (h ^ (h << 16) ^ 89869747UL) * 3644798167UL; + hash ^= ((h ^ 89869747UL) ^ (h << 16)) * 3644798167UL; } + /* Make the final result spread-out in a different pattern + than the algorithem for tuples or other python objects. */ hash = hash * 69069U + 907133923UL; if (hash == -1) hash = 590923713UL; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13988,7 +13988,7 @@ return result; } -/* Format an integer. +/* Format an integer or a float as an integer. * Return 1 if the number has been formatted into the writer, * 0 if the number has been formatted into *p_output * -1 and raise an exception on error */ @@ -14005,11 +14005,19 @@ goto wrongtype; if (!PyLong_Check(v)) { - iobj = PyNumber_Long(v); - if (iobj == NULL) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) - goto wrongtype; - return -1; + if (type == 'o' || type == 'x' || type == 'X') { + iobj = PyNumber_Index(v); + if (iobj == NULL) { + return -1; + } + } + else { + iobj = PyNumber_Long(v); + if (iobj == NULL ) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + goto wrongtype; + return -1; + } } assert(PyLong_Check(iobj)); } @@ -14079,8 +14087,18 @@ goto onError; } else { + PyObject *iobj; + long x; + /* make sure number is a type of integer */ + if (!PyLong_Check(v)) { + iobj = PyNumber_Index(v); + if (iobj == NULL) { + goto onError; + } + v = iobj; + Py_DECREF(iobj); + } /* Integer input truncated to a character */ - long x; x = PyLong_AsLong(v); if (x == -1 && PyErr_Occurred()) goto onError; @@ -14282,7 +14300,8 @@ /* Format one argument. Supported conversion specifiers: - "s", "r", "a": any type - - "i", "d", "u", "o", "x", "X": int + - "i", "d", "u": int or float + - "o", "x", "X": int - "e", "E", "f", "F", "g", "G": float - "c": int or str (1 character) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 6 16:27:24 2014 From: python-checkins at python.org (larry.hastings) Date: Mon, 6 Jan 2014 16:27:24 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Updated_3=2E4_release_schedul?= =?utf-8?q?e_PEP=2C_moving_completed_beta_2_release?= Message-ID: <3dygZN5g7lz7LjN@mail.python.org> http://hg.python.org/peps/rev/acf6cf65a8a7 changeset: 5338:acf6cf65a8a7 user: Larry Hastings date: Mon Jan 06 07:27:11 2014 -0800 summary: Updated 3.4 release schedule PEP, moving completed beta 2 release from "future" to "released". files: pep-0429.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0429.txt b/pep-0429.txt --- a/pep-0429.txt +++ b/pep-0429.txt @@ -41,12 +41,12 @@ - 3.4.0 alpha 3: September 29, 2013 - 3.4.0 alpha 4: October 20, 2013 - 3.4.0 beta 1: November 24, 2013 +- 3.4.0 beta 2: January 5, 2014 (Beta 1 is also "feature freeze"--no new features beyond this point.) The anticipated schedule for future releases: -- 3.4.0 beta 2: January 5, 2014 - 3.4.0 candidate 1: January 19, 2014 - 3.4.0 candidate 2: February 2, 2014 - 3.4.0 final: February 23, 2014 -- Repository URL: http://hg.python.org/peps From rdmurray at bitdance.com Mon Jan 6 17:22:08 2014 From: rdmurray at bitdance.com (R. David Murray) Date: Mon, 06 Jan 2014 11:22:08 -0500 Subject: [Python-checkins] [Python-Dev] cpython: whatsnew: XMLPullParser, plus some doc updates. In-Reply-To: References: <3dxnZS1P8vz7Lmc@mail.python.org> Message-ID: <20140106162208.CFC842500AA@webabinitio.net> On Tue, 07 Jan 2014 01:22:21 +1000, Nick Coghlan wrote: > On 5 Jan 2014 12:54, "r.david.murray" wrote: > > > > http://hg.python.org/cpython/rev/069f88f4935f > > changeset: 88308:069f88f4935f > > user: R David Murray > > date: Sat Jan 04 23:52:50 2014 -0500 > > summary: > > whatsnew: XMLPullParser, plus some doc updates. > > > > I was confused by the text saying that read_events "iterated", since it > > actually returns an iterator (that's what a generator does) that the > > caller must then iterate. So I tidied up the language. I'm not sure > > what the sentence "Events provided in a previous call to read_events() > > will not be yielded again." is trying to convey, so I didn't try to fix > that. > > It's a mutating API - once the events have been retrieved, that's it, > they're gone from the internal state. Suggestions for wording improvements > welcome :) Well, my guess as to what it meant was roughly: "An Event will be yielded exactly once regardless of how many read_events iterators are processed." Looking at the code, though, I'm not sure that's actually true. The code does not appear to be thread-safe. Of course, it isn't intended to be used in a threaded context, but the docs don't quite make that explicit. I imagine that's the intent of the statement about "parallel" reading, but it doesn't actually say that the code is not thread safe. It reads more as if it is warning that the order of retrieval would be unpredictable. --David From python-checkins at python.org Mon Jan 6 18:51:44 2014 From: python-checkins at python.org (gregory.p.smith) Date: Mon, 6 Jan 2014 18:51:44 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fixes_issue190?= =?utf-8?q?81=3A_When_a_zipimport_=2Ezip_file_in_sys=2Epath_being_imported?= Message-ID: <3dykmw2lyhzRCV@mail.python.org> http://hg.python.org/cpython/rev/8dbf8edb7128 changeset: 88322:8dbf8edb7128 branch: 2.7 parent: 88316:e57660acc6d4 user: Gregory P. Smith date: Mon Jan 06 09:46:46 2014 -0800 summary: Fixes issue19081: When a zipimport .zip file in sys.path being imported from is modified during the lifetime of the Python process after zipimport has already opened and cached the zip's table of contents it now fstat's the file after opening it upon every attempt to access anything within and will re-read the table of contents if the .zip file inode, size or mtime have changed. It would've been nicer to hold any .zip file used by zipimport open for the duration of the process but that would be more invasive and add an additional open file descriptor to all zipimport using processes. It also would likely not fix the problem on Windows due to different filesystem semantics. files: Lib/test/test_zipimport.py | 103 +++++++- Modules/zipimport.c | 294 ++++++++++++++++++++---- 2 files changed, 324 insertions(+), 73 deletions(-) diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py --- a/Lib/test/test_zipimport.py +++ b/Lib/test/test_zipimport.py @@ -1,3 +1,4 @@ +import io import sys import os import marshal @@ -55,6 +56,27 @@ TEMP_ZIP = os.path.abspath("junk95142" + os.extsep + "zip") +def _write_zip_package(zipname, files, + data_to_prepend=b"", compression=ZIP_STORED): + z = ZipFile(zipname, "w") + try: + for name, (mtime, data) in files.items(): + zinfo = ZipInfo(name, time.localtime(mtime)) + zinfo.compress_type = compression + z.writestr(zinfo, data) + finally: + z.close() + + if data_to_prepend: + # Prepend data to the start of the zipfile + with open(zipname, "rb") as f: + zip_data = f.read() + + with open(zipname, "wb") as f: + f.write(data_to_prepend) + f.write(zip_data) + + class UncompressedZipImportTestCase(ImportHooksBaseTestCase): compression = ZIP_STORED @@ -67,26 +89,9 @@ ImportHooksBaseTestCase.setUp(self) def doTest(self, expected_ext, files, *modules, **kw): - z = ZipFile(TEMP_ZIP, "w") + _write_zip_package(TEMP_ZIP, files, data_to_prepend=kw.get("stuff"), + compression=self.compression) try: - for name, (mtime, data) in files.items(): - zinfo = ZipInfo(name, time.localtime(mtime)) - zinfo.compress_type = self.compression - z.writestr(zinfo, data) - z.close() - - stuff = kw.get("stuff", None) - if stuff is not None: - # Prepend 'stuff' to the start of the zipfile - f = open(TEMP_ZIP, "rb") - data = f.read() - f.close() - - f = open(TEMP_ZIP, "wb") - f.write(stuff) - f.write(data) - f.close() - sys.path.insert(0, TEMP_ZIP) mod = __import__(".".join(modules), globals(), locals(), @@ -101,7 +106,6 @@ self.assertEqual(file, os.path.join(TEMP_ZIP, *modules) + expected_ext) finally: - z.close() os.remove(TEMP_ZIP) def testAFakeZlib(self): @@ -387,6 +391,64 @@ compression = ZIP_DEFLATED +class ZipFileModifiedAfterImportTestCase(ImportHooksBaseTestCase): + def setUp(self): + zipimport._zip_directory_cache.clear() + zipimport._zip_stat_cache.clear() + ImportHooksBaseTestCase.setUp(self) + + def tearDown(self): + ImportHooksBaseTestCase.tearDown(self) + if os.path.exists(TEMP_ZIP): + os.remove(TEMP_ZIP) + + def testZipFileChangesAfterFirstImport(self): + """Alter the zip file after caching its index and try an import.""" + packdir = TESTPACK + os.sep + files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc), + packdir + TESTMOD + ".py": (NOW, "test_value = 38\n"), + "ziptest_a.py": (NOW, "test_value = 23\n"), + "ziptest_b.py": (NOW, "test_value = 42\n"), + "ziptest_c.py": (NOW, "test_value = 1337\n")} + zipfile_path = TEMP_ZIP + _write_zip_package(zipfile_path, files) + self.assertTrue(os.path.exists(zipfile_path)) + sys.path.insert(0, zipfile_path) + + # Import something out of the zipfile and confirm it is correct. + testmod = __import__(TESTPACK + "." + TESTMOD, + globals(), locals(), ["__dummy__"]) + self.assertEqual(testmod.test_value, 38) + # Import something else out of the zipfile and confirm it is correct. + ziptest_b = __import__("ziptest_b", globals(), locals(), ["test_value"]) + self.assertEqual(ziptest_b.test_value, 42) + + # Truncate and fill the zip file with non-zip garbage. + with io.open(zipfile_path, "rb") as orig_zip_file: + orig_zip_file_contents = orig_zip_file.read() + with io.open(zipfile_path, "wb") as byebye_valid_zip_file: + byebye_valid_zip_file.write(b"Tear down this wall!\n"*1987) + # Now that the zipfile has been replaced, import something else from it + # which should fail as the file contents are now garbage. + with self.assertRaises(ImportError): + ziptest_a = __import__("ziptest_a", globals(), locals(), + ["test_value"]) + + # Now lets make it a valid zipfile that has some garbage at the start. + # This alters all of the offsets within the file + with io.open(zipfile_path, "wb") as new_zip_file: + new_zip_file.write(b"X"*1991) # The year Python was created. + new_zip_file.write(orig_zip_file_contents) + + # Now that the zip file has been "restored" to a valid but different + # zipfile the zipimporter should *successfully* re-read the new zip + # file's end of file central index and be able to import from it again. + ziptest_a = __import__("ziptest_a", globals(), locals(), ["test_value"]) + self.assertEqual(ziptest_a.test_value, 23) + ziptest_c = __import__("ziptest_c", globals(), locals(), ["test_value"]) + self.assertEqual(ziptest_c.test_value, 1337) + + class BadFileZipImportTestCase(unittest.TestCase): def assertZipFailure(self, filename): self.assertRaises(zipimport.ZipImportError, @@ -464,6 +526,7 @@ UncompressedZipImportTestCase, CompressedZipImportTestCase, BadFileZipImportTestCase, + ZipFileModifiedAfterImportTestCase, ) finally: test_support.unlink(TESTMOD) diff --git a/Modules/zipimport.c b/Modules/zipimport.c --- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -42,10 +42,16 @@ static PyObject *ZipImportError; static PyObject *zip_directory_cache = NULL; +static PyObject *zip_stat_cache = NULL; +/* posix.fstat or nt.fstat function. Used due to posixmodule.c's + * superior fstat implementation over libc's on Windows. */ +static PyObject *fstat_function = NULL; /* posix.fstat() or nt.fstat() */ /* forward decls */ -static PyObject *read_directory(char *archive); -static PyObject *get_data(char *archive, PyObject *toc_entry); +static FILE *fopen_rb_and_stat(char *path, PyObject **py_stat_p); +static FILE *safely_reopen_archive(ZipImporter *self, char **archive_p); +static PyObject *read_directory(FILE *fp, char *archive); +static PyObject *get_data(FILE *fp, char *archive, PyObject *toc_entry); static PyObject *get_module_code(ZipImporter *self, char *fullname, int *p_ispackage, char **p_modpath); @@ -126,12 +132,38 @@ PyObject *files; files = PyDict_GetItemString(zip_directory_cache, path); if (files == NULL) { - files = read_directory(buf); - if (files == NULL) + PyObject *zip_stat = NULL; + FILE *fp = fopen_rb_and_stat(buf, &zip_stat); + if (fp == NULL) { + PyErr_Format(ZipImportError, "can't open Zip file: " + "'%.200s'", buf); + Py_XDECREF(zip_stat); return -1; + } + + if (Py_VerboseFlag) + PySys_WriteStderr("# zipimport: %s not cached, " + "reading TOC.\n", path); + + files = read_directory(fp, buf); + fclose(fp); + if (files == NULL) { + Py_XDECREF(zip_stat); + return -1; + } if (PyDict_SetItemString(zip_directory_cache, path, - files) != 0) + files) != 0) { + Py_DECREF(files); + Py_XDECREF(zip_stat); return -1; + } + if (zip_stat && PyDict_SetItemString(zip_stat_cache, path, + zip_stat) != 0) { + Py_DECREF(files); + Py_DECREF(zip_stat); + return -1; + } + Py_XDECREF(zip_stat); } else Py_INCREF(files); @@ -419,11 +451,12 @@ zipimporter_get_data(PyObject *obj, PyObject *args) { ZipImporter *self = (ZipImporter *)obj; - char *path; + char *path, *archive; + FILE *fp; #ifdef ALTSEP char *p, buf[MAXPATHLEN + 1]; #endif - PyObject *toc_entry; + PyObject *toc_entry, *data; Py_ssize_t len; if (!PyArg_ParseTuple(args, "s:zipimporter.get_data", &path)) @@ -448,12 +481,19 @@ path = path + len + 1; } + fp = safely_reopen_archive(self, &archive); + if (fp == NULL) + return NULL; + toc_entry = PyDict_GetItemString(self->files, path); if (toc_entry == NULL) { PyErr_SetFromErrnoWithFilename(PyExc_IOError, path); + fclose(fp); return NULL; } - return get_data(PyString_AsString(self->archive), toc_entry); + data = get_data(fp, archive, toc_entry); + fclose(fp); + return data; } static PyObject * @@ -473,7 +513,8 @@ { ZipImporter *self = (ZipImporter *)obj; PyObject *toc_entry; - char *fullname, *subname, path[MAXPATHLEN+1]; + FILE *fp; + char *fullname, *subname, path[MAXPATHLEN+1], *archive; int len; enum zi_module_info mi; @@ -501,13 +542,20 @@ else strcpy(path + len, ".py"); + fp = safely_reopen_archive(self, &archive); + if (fp == NULL) + return NULL; + toc_entry = PyDict_GetItemString(self->files, path); - if (toc_entry != NULL) - return get_data(PyString_AsString(self->archive), toc_entry); + if (toc_entry != NULL) { + PyObject *data = get_data(fp, archive, toc_entry); + fclose(fp); + return data; + } + fclose(fp); /* we have the module, but no source */ - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyDoc_STRVAR(doc_find_module, @@ -662,7 +710,139 @@ } /* - read_directory(archive) -> files dict (new reference) + fopen_rb_and_stat(path, &py_stat) -> FILE * + + Opens path in "rb" mode and populates the Python py_stat stat_result + with information about the opened file. *py_stat may not be changed + if there is no fstat_function or if fstat_function fails. + + Returns NULL and does nothing to *py_stat if the open failed. +*/ +static FILE * +fopen_rb_and_stat(char *path, PyObject **py_stat_p) +{ + FILE *fp; + assert(py_stat_p != NULL); + assert(*py_stat_p == NULL); + + fp = fopen(path, "rb"); + if (fp == NULL) { + return NULL; + } + + if (fstat_function) { + PyObject *stat_result = PyObject_CallFunction(fstat_function, + "i", fileno(fp)); + if (stat_result == NULL) { + PyErr_Clear(); /* We can function without it. */ + } else { + *py_stat_p = stat_result; + } + } + + return fp; +} + +/* Return 1 if objects a and b fail a Py_EQ test for an attr. */ +static int +compare_obj_attr_strings(PyObject *obj_a, PyObject *obj_b, char *attr_name) +{ + int problem = 0; + PyObject *attr_a = PyObject_GetAttrString(obj_a, attr_name); + PyObject *attr_b = PyObject_GetAttrString(obj_b, attr_name); + if (attr_a == NULL || attr_b == NULL) + problem = 1; + else + problem = (PyObject_RichCompareBool(attr_a, attr_b, Py_EQ) != 1); + Py_XDECREF(attr_a); + Py_XDECREF(attr_b); + return problem; +} + +/* + * Returns an open FILE * on success and sets *archive_p to point to + * a read only C string representation of the archive name (as a + * convenience for use in error messages). + * + * Returns NULL on error with the Python error context set. + */ +static FILE * +safely_reopen_archive(ZipImporter *self, char **archive_p) +{ + FILE *fp; + PyObject *stat_now = NULL; + char *archive; + + assert(archive_p != NULL); + *archive_p = PyString_AsString(self->archive); + if (*archive_p == NULL) + return NULL; + archive = *archive_p; + + fp = fopen_rb_and_stat(archive, &stat_now); + if (!fp) { + PyErr_Format(PyExc_IOError, + "zipimport: can not open file %s", archive); + Py_XDECREF(stat_now); + return NULL; + } + + if (stat_now != NULL) { + int problem = 0; + PyObject *files; + PyObject *prev_stat = PyDict_GetItemString(zip_stat_cache, archive); + /* Test stat_now vs the old cached stat on some key attributes. */ + if (prev_stat != NULL) { + problem = compare_obj_attr_strings(prev_stat, stat_now, + "st_ino"); + problem |= compare_obj_attr_strings(prev_stat, stat_now, + "st_size"); + problem |= compare_obj_attr_strings(prev_stat, stat_now, + "st_mtime"); + } else { + if (Py_VerboseFlag) + PySys_WriteStderr("# zipimport: no stat data for %s!\n", + archive); + problem = 1; + } + + if (problem) { + if (Py_VerboseFlag) + PySys_WriteStderr("# zipimport: %s modified since last" + " import, rereading TOC.\n", archive); + files = read_directory(fp, archive); + if (files == NULL) { + Py_DECREF(stat_now); + fclose(fp); + return NULL; + } + if (PyDict_SetItem(zip_directory_cache, self->archive, + files) != 0) { + Py_DECREF(files); + Py_DECREF(stat_now); + fclose(fp); + return NULL; + } + if (stat_now && PyDict_SetItem(zip_stat_cache, self->archive, + stat_now) != 0) { + Py_DECREF(files); + Py_DECREF(stat_now); + fclose(fp); + return NULL; + } + Py_XDECREF(self->files); /* free the old value. */ + self->files = files; + } else { + /* No problem, discard the new stat data. */ + Py_DECREF(stat_now); + } + } /* stat succeeded */ + + return fp; +} + +/* + read_directory(fp, archive) -> files dict (new reference) Given a path to a Zip archive, build a dict, mapping file names (local to the archive, using SEP as a separator) to toc entries. @@ -683,10 +863,9 @@ data_size and file_offset are 0. */ static PyObject * -read_directory(char *archive) +read_directory(FILE *fp, char *archive) { PyObject *files = NULL; - FILE *fp; long compress, crc, data_size, file_size, file_offset, date, time; long header_offset, name_size, header_size, header_position; long i, l, count; @@ -696,6 +875,7 @@ char *p, endof_central_dir[22]; long arc_offset; /* offset from beginning of file to start of zip-archive */ + assert(fp != NULL); if (strlen(archive) > MAXPATHLEN) { PyErr_SetString(PyExc_OverflowError, "Zip path name is too long"); @@ -703,28 +883,18 @@ } strcpy(path, archive); - fp = fopen(archive, "rb"); - if (fp == NULL) { - PyErr_Format(ZipImportError, "can't open Zip file: " - "'%.200s'", archive); - return NULL; - } - if (fseek(fp, -22, SEEK_END) == -1) { - fclose(fp); PyErr_Format(ZipImportError, "can't read Zip file: %s", archive); return NULL; } header_position = ftell(fp); if (fread(endof_central_dir, 1, 22, fp) != 22) { - fclose(fp); PyErr_Format(ZipImportError, "can't read Zip file: " "'%.200s'", archive); return NULL; } if (get_long((unsigned char *)endof_central_dir) != 0x06054B50) { /* Bad: End of Central Dir signature */ - fclose(fp); PyErr_Format(ZipImportError, "not a Zip file: " "'%.200s'", archive); return NULL; @@ -793,18 +963,15 @@ goto error; count++; } - fclose(fp); if (Py_VerboseFlag) PySys_WriteStderr("# zipimport: found %ld names in %s\n", count, archive); return files; fseek_error: - fclose(fp); Py_XDECREF(files); PyErr_Format(ZipImportError, "can't read Zip file: %s", archive); return NULL; error: - fclose(fp); Py_XDECREF(files); return NULL; } @@ -841,14 +1008,13 @@ return decompress; } -/* Given a path to a Zip file and a toc_entry, return the (uncompressed) +/* Given a FILE* to a Zip file and a toc_entry, return the (uncompressed) data as a new reference. */ static PyObject * -get_data(char *archive, PyObject *toc_entry) +get_data(FILE *fp, char *archive, PyObject *toc_entry) { PyObject *raw_data, *data = NULL, *decompress; char *buf; - FILE *fp; int err; Py_ssize_t bytes_read = 0; long l; @@ -862,16 +1028,8 @@ return NULL; } - fp = fopen(archive, "rb"); - if (!fp) { - PyErr_Format(PyExc_IOError, - "zipimport: can not open file %s", archive); - return NULL; - } - /* Check to make sure the local file header is correct */ if (fseek(fp, file_offset, 0) == -1) { - fclose(fp); PyErr_Format(ZipImportError, "can't read Zip file: %s", archive); return NULL; } @@ -882,11 +1040,9 @@ PyErr_Format(ZipImportError, "bad local file header in %s", archive); - fclose(fp); return NULL; } if (fseek(fp, file_offset + 26, 0) == -1) { - fclose(fp); PyErr_Format(ZipImportError, "can't read Zip file: %s", archive); return NULL; } @@ -898,7 +1054,6 @@ raw_data = PyString_FromStringAndSize((char *)NULL, compress == 0 ? data_size : data_size + 1); if (raw_data == NULL) { - fclose(fp); return NULL; } buf = PyString_AsString(raw_data); @@ -907,11 +1062,9 @@ if (err == 0) { bytes_read = fread(buf, 1, data_size, fp); } else { - fclose(fp); PyErr_Format(ZipImportError, "can't read Zip file: %s", archive); return NULL; } - fclose(fp); if (err || bytes_read != data_size) { PyErr_SetString(PyExc_IOError, "zipimport: can't read data"); @@ -1107,17 +1260,13 @@ /* Return the code object for the module named by 'fullname' from the Zip archive as a new reference. */ static PyObject * -get_code_from_data(ZipImporter *self, int ispackage, int isbytecode, - time_t mtime, PyObject *toc_entry) +get_code_from_data(char *archive, FILE *fp, int ispackage, + int isbytecode, time_t mtime, PyObject *toc_entry) { PyObject *data, *code; char *modpath; - char *archive = PyString_AsString(self->archive); - if (archive == NULL) - return NULL; - - data = get_data(archive, toc_entry); + data = get_data(fp, archive, toc_entry); if (data == NULL) return NULL; @@ -1152,12 +1301,19 @@ for (zso = zip_searchorder; *zso->suffix; zso++) { PyObject *code = NULL; + FILE *fp; + char *archive; strcpy(path + len, zso->suffix); if (Py_VerboseFlag > 1) PySys_WriteStderr("# trying %s%c%s\n", PyString_AsString(self->archive), SEP, path); + + fp = safely_reopen_archive(self, &archive); + if (fp == NULL) + return NULL; + toc_entry = PyDict_GetItemString(self->files, path); if (toc_entry != NULL) { time_t mtime = 0; @@ -1168,9 +1324,10 @@ mtime = get_mtime_of_source(self, path); if (p_ispackage != NULL) *p_ispackage = ispackage; - code = get_code_from_data(self, ispackage, + code = get_code_from_data(archive, fp, ispackage, isbytecode, mtime, toc_entry); + fclose(fp); if (code == Py_None) { /* bad magic number or non-matching mtime in byte code, try next */ @@ -1182,6 +1339,7 @@ PyTuple_GetItem(toc_entry, 0)); return code; } + fclose(fp); } PyErr_Format(ZipImportError, "can't find module '%.200s'", fullname); return NULL; @@ -1199,6 +1357,8 @@ subclass of ImportError, so it can be caught as ImportError, too.\n\ - _zip_directory_cache: a dict, mapping archive paths to zip directory\n\ info dicts, as used in zipimporter._files.\n\ +- _zip_stat_cache: a dict, mapping archive paths to stat_result\n\ + info for the .zip the last time anything was imported from it.\n\ \n\ It is usually not needed to use the zipimport module explicitly; it is\n\ used by the builtin import mechanism for sys.path items that are paths\n\ @@ -1247,6 +1407,7 @@ (PyObject *)&ZipImporter_Type) < 0) return; + Py_XDECREF(zip_directory_cache); /* Avoid embedded interpreter leaks. */ zip_directory_cache = PyDict_New(); if (zip_directory_cache == NULL) return; @@ -1254,4 +1415,31 @@ if (PyModule_AddObject(mod, "_zip_directory_cache", zip_directory_cache) < 0) return; + + Py_XDECREF(zip_stat_cache); /* Avoid embedded interpreter leaks. */ + zip_stat_cache = PyDict_New(); + if (zip_stat_cache == NULL) + return; + Py_INCREF(zip_stat_cache); + if (PyModule_AddObject(mod, "_zip_stat_cache", zip_stat_cache) < 0) + return; + + { + /* We cannot import "os" here as that is a .py/.pyc file that could + * live within a zipped up standard library. Import the posix or nt + * builtin that provides the fstat() function we want instead. */ + PyObject *os_like_module; + Py_XDECREF(fstat_function); /* Avoid embedded interpreter leaks. */ + os_like_module = PyImport_ImportModule("posix"); + if (os_like_module == NULL) { + os_like_module = PyImport_ImportModule("nt"); + } + if (os_like_module != NULL) { + fstat_function = PyObject_GetAttrString(os_like_module, "fstat"); + Py_DECREF(os_like_module); + } + if (fstat_function == NULL) { + PyErr_Clear(); /* non-fatal, we'll go on without it. */ + } + } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 6 18:51:45 2014 From: python-checkins at python.org (gregory.p.smith) Date: Mon, 6 Jan 2014 18:51:45 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_news_entry_for?= =?utf-8?q?_issue19081_fix=2E?= Message-ID: <3dykmx55pKzSXf@mail.python.org> http://hg.python.org/cpython/rev/90a99059aa36 changeset: 88323:90a99059aa36 branch: 2.7 user: Gregory P. Smith date: Mon Jan 06 09:50:19 2014 -0800 summary: news entry for issue19081 fix. files: Misc/NEWS | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,11 @@ Core and Builtins ----------------- +- Issue #19081: When a zipimport .zip file in sys.path being imported from + is modified during the lifetime of the Python process after zipimport has + already cached the zip's table of contents we detect this and recover + rather than read bad data from the .zip (causing odd import errors). + - Raise a better error when non-unicode codecs are used for a file's coding cookie. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 6 18:51:47 2014 From: python-checkins at python.org (gregory.p.smith) Date: Mon, 6 Jan 2014 18:51:47 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_normalize_whit?= =?utf-8?q?espace_from_prior_issue19081_fix_commit=2E?= Message-ID: <3dykmz09lLz7Ljd@mail.python.org> http://hg.python.org/cpython/rev/cbeb22969da1 changeset: 88324:cbeb22969da1 branch: 2.7 user: Gregory P. Smith date: Mon Jan 06 09:51:32 2014 -0800 summary: normalize whitespace from prior issue19081 fix commit. files: Lib/test/test_zipimport.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py --- a/Lib/test/test_zipimport.py +++ b/Lib/test/test_zipimport.py @@ -70,11 +70,11 @@ if data_to_prepend: # Prepend data to the start of the zipfile with open(zipname, "rb") as f: - zip_data = f.read() + zip_data = f.read() with open(zipname, "wb") as f: - f.write(data_to_prepend) - f.write(zip_data) + f.write(data_to_prepend) + f.write(zip_data) class UncompressedZipImportTestCase(ImportHooksBaseTestCase): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 6 19:34:33 2014 From: python-checkins at python.org (larry.hastings) Date: Mon, 6 Jan 2014 19:34:33 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320142=3A_Py=5Fbuf?= =?utf-8?q?fer_variables_generated_by_Argument_Clinic_are_now?= Message-ID: <3dylkK5FhYzSfC@mail.python.org> http://hg.python.org/cpython/rev/16ff19d1d367 changeset: 88325:16ff19d1d367 parent: 88321:44c4ba63631d user: Larry Hastings date: Mon Jan 06 10:34:00 2014 -0800 summary: Issue #20142: Py_buffer variables generated by Argument Clinic are now initialized with a default value. files: Misc/NEWS | 5 +++++ Modules/zlibmodule.c | 8 ++++---- Tools/clinic/clinic.py | 10 +++++++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,11 @@ Library ------- +Tools/Demos +----------- + +- Issue #20142: Py_buffer variables generated by Argument Clinic are now + initialized with a default value. What's New in Python 3.4.0 Beta 2? ================================== diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -198,7 +198,7 @@ zlib_compress(PyModuleDef *module, PyObject *args) { PyObject *return_value = NULL; - Py_buffer bytes; + Py_buffer bytes = {NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL}; int group_right_1 = 0; int level = 0; @@ -227,7 +227,7 @@ static PyObject * zlib_compress_impl(PyModuleDef *module, Py_buffer *bytes, int group_right_1, int level) -/*[clinic checksum: f490708eff84be652b5ebe7fe622ab73ac12c888]*/ +/*[clinic checksum: 9f055a396620bc1a8a13d74c3496249528b32b0d]*/ { PyObject *ReturnVal = NULL; Byte *input, *output = NULL; @@ -789,7 +789,7 @@ zlib_Decompress_decompress(PyObject *self, PyObject *args) { PyObject *return_value = NULL; - Py_buffer data; + Py_buffer data = {NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL}; unsigned int max_length = 0; if (!PyArg_ParseTuple(args, @@ -808,7 +808,7 @@ static PyObject * zlib_Decompress_decompress_impl(compobject *self, Py_buffer *data, unsigned int max_length) -/*[clinic checksum: 3599698948f5a712f5a8309491671cc2ce969d2c]*/ +/*[clinic checksum: 5b1e4f9f1ef8eca55fff78356f9df0c81232ed3b]*/ { int err; unsigned int old_length, length = DEFAULTALLOC; diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1488,7 +1488,12 @@ declaration.append('\nPy_ssize_clean_t ') declaration.append(self.length_name()) declaration.append(';') - return "".join(declaration) + s = "".join(declaration) + # double up curly-braces, this string will be used + # as part of a format_map() template later + s = s.replace("{", "{{") + s = s.replace("}", "}}") + return s def initialize(self): """ @@ -1742,6 +1747,9 @@ c_ignored_default = "{NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL}" def converter_init(self, *, types='bytes bytearray buffer', nullable=False): + if self.default != unspecified: + fail("There is no legal default value for Py_buffer ") + self.c_default = self.c_ignored_default types = set(types.strip().split()) bytes_type = set(('bytes',)) bytearray_type = set(('bytearray',)) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 6 20:10:57 2014 From: python-checkins at python.org (larry.hastings) Date: Mon, 6 Jan 2014 20:10:57 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320143=3A_The_line?= =?utf-8?q?_numbers_reported_in_Argument_Clinic_errors_are?= Message-ID: <3dymXK6716z7Ljy@mail.python.org> http://hg.python.org/cpython/rev/9c8d31d69044 changeset: 88326:9c8d31d69044 user: Larry Hastings date: Mon Jan 06 11:10:08 2014 -0800 summary: Issue #20143: The line numbers reported in Argument Clinic errors are now more accurate. files: Misc/NEWS | 3 +++ Tools/clinic/clinic.py | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -16,6 +16,9 @@ Tools/Demos ----------- +- Issue #20143: The line numbers reported in Argument Clinic errors are + now more accurate. + - Issue #20142: Py_buffer variables generated by Argument Clinic are now initialized with a default value. diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -943,8 +943,9 @@ fail("Checksum mismatch!\nExpected: {}\nComputed: {}".format(checksum, computed)) else: # put back output - self.input.extend(reversed(output.splitlines(keepends=True))) - self.line_number -= len(output) + output_lines = output.splitlines(keepends=True) + self.line_number -= len(output_lines) + self.input.extend(reversed(output_lines)) output = None return Block(input_output(), dsl_name, output=output) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 6 22:32:54 2014 From: python-checkins at python.org (r.david.murray) Date: Mon, 6 Jan 2014 22:32:54 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_pydoc=2EScanne?= =?utf-8?q?r_removal=2C_check=5Foutput_input_parm=2C_operator=2Epy=2E?= Message-ID: <3dyqh63Js2z7LjN@mail.python.org> http://hg.python.org/cpython/rev/0473c770b523 changeset: 88327:0473c770b523 user: R David Murray date: Sun Jan 05 20:52:06 2014 -0500 summary: whatsnew: pydoc.Scanner removal, check_output input parm, operator.py. Also fleshed out the entry on struct.iter_unpack. files: Doc/whatsnew/3.4.rst | 30 ++++++++++++++++++++++++++++-- 1 files changed, 28 insertions(+), 2 deletions(-) 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 @@ -794,6 +794,14 @@ processes. (Contributed by Nick Coghlan in :issue:`19946`) +operator +-------- + +There is now a pure-python version of the :mod:`operator` module available for +reference and for use by alternate implementations of Python. (Contributed by +Zachary Ware in :issue:`16694`.) + + os -- @@ -981,8 +989,19 @@ struct ------ -Streaming struct unpacking using :func:`struct.iter_unpack`. -(Contributed by Antoine Pitrou in :issue:`17804`.) +:mod:`struct` now supports the streamed unpacking of a buffer containing +repeated instances of a given format of data. Both a module level +:mod:`~struct.iter_unpack` function and a :meth:`struct.Struct.iter_unpack` +method on compiled formats have been added. (Contributed by Antoine Pitrou in +:issue:`17804`.) + + +subprocess +---------- + +:func:`~subprocess.check_output` now accepts an *input* argument that can +be used to provide the contents of ``stdin`` for the command that is run. +(Contributed by Zack Weinberg in :issue:`16624`.) sunau @@ -1378,6 +1397,13 @@ :mod:`marshal`. (Contributed by Dan Riti in :issue:`15480`.) +Code Cleanups +------------- + +* The unused and undocumented internal ``Scanner`` class has been removed from + the :mod:`pydoc` module. + + Porting to Python 3.4 ===================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 6 22:32:55 2014 From: python-checkins at python.org (r.david.murray) Date: Mon, 6 Jan 2014 22:32:55 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_ssl_getpeercer?= =?utf-8?q?t/do=5Fhandshake_raise_OSError=2C_weakref_=5F=5Fcallback=5F=5F?= =?utf-8?q?=2E?= Message-ID: <3dyqh762hDz7Ljs@mail.python.org> http://hg.python.org/cpython/rev/2798ebe65fb1 changeset: 88328:2798ebe65fb1 user: R David Murray date: Mon Jan 06 16:32:05 2014 -0500 summary: whatsnew: ssl getpeercert/do_handshake raise OSError, weakref __callback__. Also add a missing word to gc entry, and delete a now-obsolete doc note in the weakref __callback__ docs. (Opened an issue for rewriting the section that compares finalizers and __del__ method.) files: Doc/library/weakref.rst | 11 +---------- Doc/whatsnew/3.4.rst | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -123,15 +123,6 @@ weakref. If there is no callback or if the referent of the weakref is no longer alive then this attribute will have value ``None``. - .. note:: - - Like :meth:`__del__` methods, weak reference callbacks can be - called during interpreter shutdown when module globals have been - overwritten with :const:`None`. This can make writing robust - weak reference callbacks a challenge. Callbacks registered - using :class:`finalize` do not have to worry about this issue - because they will not be run after module teardown has begun. - .. versionchanged:: 3.4 Added the :attr:`__callback__` attribute. @@ -247,7 +238,7 @@ .. class:: finalize(obj, func, *args, **kwargs) Return a callable finalizer object which will be called when *obj* - is garbage collected. Unlike an ordinary weak reference, a finalizer is + is garbage collected. Unlike an ordinary weak reference, a finalizer will always survive until the reference object is collected, greatly simplifying lifecycle management. 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 @@ -657,9 +657,9 @@ gc -- -New :func:`~gc.get_stats` returns a list of three per-generation dictionaries -containing the collections statistics since interpreter startup. (Contributed -by Antoine Pitrou in :issue:`16351`.) +New function :func:`~gc.get_stats` returns a list of three per-generation +dictionaries containing the collections statistics since interpreter startup. +(Contributed by Antoine Pitrou in :issue:`16351`.) hashlib @@ -1103,6 +1103,10 @@ carefully manage the lifecycle of the weak reference itself. (Contributed by Richard Oudkerk in :issue:`15528`) +The callback, if any, associated with a :class:`~weakref.ref` is now +exposed via the :attr:`~weakref.ref.__callback__` attribute. (Contributed +by Mark Dickinson in :issue:`17643`.) + xml.etree --------- @@ -1482,6 +1486,12 @@ compliance with the language spec; Jython and PyPy already were. (:issue:`17434`). +* :meth:`ssl.SSLSocket.getpeercert` and :meth:`ssl.SSLSocket.do_handshake` + now raise an :exc:`OSError` with ``ENOTCONN`` when the ``SSLSocket`` is not + connected, instead of the previous behavior of raising an + :exc:`AttributError`. In addition, :meth:`~ssl.SSLSocket.getpeercert` + will raise a :exc:`ValueError` if the handshake has not yet been done. + Changes in the C API -------------------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 7 01:09:30 2014 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 7 Jan 2014 01:09:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Fix_deadlock_in?= =?utf-8?q?_readexactly=28=29=2E_Fixes_issue_=2320154=2E?= Message-ID: <3dyv8p2xvLz7LjN@mail.python.org> http://hg.python.org/cpython/rev/54d32e01bbfd changeset: 88329:54d32e01bbfd user: Guido van Rossum date: Mon Jan 06 16:09:18 2014 -0800 summary: asyncio: Fix deadlock in readexactly(). Fixes issue #20154. files: Lib/asyncio/streams.py | 29 +++++++++++++++++++---------- Misc/NEWS | 2 ++ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -220,6 +220,7 @@ if loop is None: loop = events.get_event_loop() self._loop = loop + # TODO: Use a bytearray for a buffer, like the transport. self._buffer = collections.deque() # Deque of bytes objects. self._byte_count = 0 # Bytes in buffer. self._eof = False # Whether we're done. @@ -384,15 +385,23 @@ if self._exception is not None: raise self._exception - 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 self._byte_count < n and not self._eof: - assert not self._waiter - self._waiter = futures.Future(loop=self._loop) - try: - yield from self._waiter - finally: - self._waiter = None + blocks = [] + while n > 0: + block = yield from self.read(n) + if not block: + break + blocks.append(block) + n -= len(block) - return (yield from self.read(n)) + # TODO: Raise EOFError if we break before n == 0? (That would + # be a change in specification, but I've always had to add an + # explicit size check to the caller.) + + return b''.join(blocks) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -75,6 +75,8 @@ Library ------- +- Issue #20154: Deadlock in asyncio.StreamReader.readexactly(). + - Issue #16113: Remove sha3 module again. - Issue #20111: pathlib.Path.with_suffix() now sanity checks the given suffix. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 7 04:51:08 2014 From: python-checkins at python.org (eric.snow) Date: Tue, 7 Jan 2014 04:51:08 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Remove_dead_PEP_451_code?= =?utf-8?q?=2E?= Message-ID: <3dz04X3Xfxz7LkJ@mail.python.org> http://hg.python.org/cpython/rev/2b50ac02a5a8 changeset: 88330:2b50ac02a5a8 user: Eric Snow date: Mon Jan 06 20:38:16 2014 -0700 summary: Remove dead PEP 451 code. files: Lib/importlib/_bootstrap.py | 10 ---------- Lib/test/test_importlib/test_spec.py | 12 ------------ 2 files changed, 0 insertions(+), 22 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -1183,15 +1183,6 @@ pass return module - # XXX If we don't end up using this for pythonrun.c/runpy, we should - # get rid of it. - def _load_existing(self, module): - """Exec the spec'ed module into an existing module's namespace.""" - # For use by runpy. - with _installed_safely(module): - loaded = self.exec(module) - return loaded - def _load_unlocked(self): # A helper for direct use by the import system. if self.spec.loader is not None: @@ -1389,7 +1380,6 @@ @classmethod def find_spec(cls, fullname, path=None, target=None): - # XXX untested! Need a Windows person to write tests (otherwise mock out appropriately) filepath = cls._search_registry(fullname) if filepath is None: return None diff --git a/Lib/test/test_importlib/test_spec.py b/Lib/test/test_importlib/test_spec.py --- a/Lib/test/test_importlib/test_spec.py +++ b/Lib/test/test_importlib/test_spec.py @@ -437,18 +437,6 @@ loaded = self.bootstrap._SpecMethods(self.spec).load() self.assertNotIn(self.spec.name, sys.modules) - def test_load_existing(self): - existing = type(sys)('ham') - existing.count = 5 - self.spec.loader = NewLoader() - with CleanImport(self.name): - sys.modules[self.name] = existing - assert self.spec.name == self.name - loaded = self.bootstrap._SpecMethods(self.spec).load() - - self.assertEqual(loaded.eggs, 1) - self.assertFalse(hasattr(loaded, 'ham')) - def test_load_legacy(self): self.spec.loader = LegacyLoader() with CleanImport(self.spec.name): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 7 04:51:09 2014 From: python-checkins at python.org (eric.snow) Date: Tue, 7 Jan 2014 04:51:09 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2319703=3A_Update_p?= =?utf-8?q?ydoc_to_use_the_new_importer_APIs=2E?= Message-ID: <3dz04Y5Zwvz7Lkl@mail.python.org> http://hg.python.org/cpython/rev/f67ccb4490ea changeset: 88331:f67ccb4490ea user: Eric Snow date: Mon Jan 06 20:42:59 2014 -0700 summary: Issue #19703: Update pydoc to use the new importer APIs. files: Lib/pydoc.py | 17 +++++++++++++---- Lib/test/test_pydoc.py | 2 ++ Misc/NEWS | 2 ++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -246,8 +246,12 @@ else: # Must be a binary module, which has to be imported. loader = loader_cls('__temp__', filename) + # XXX We probably don't need to pass in the loader here. + spec = importlib.util.spec_from_file_location('__temp__', filename, + loader=loader) + _spec = importlib._bootstrap._SpecMethods(spec) try: - module = loader.load_module('__temp__') + module = _spec.load() except: return None del sys.modules['__temp__'] @@ -277,8 +281,11 @@ loader = importlib._bootstrap.SourcelessFileLoader(name, path) else: loader = importlib._bootstrap.SourceFileLoader(name, path) + # XXX We probably don't need to pass in the loader here. + spec = importlib.util.spec_from_file_location(name, path, loader=loader) + _spec = importlib._bootstrap._SpecMethods(spec) try: - return loader.load_module(name) + return _spec.load() except: raise ErrorDuringImport(path, sys.exc_info()) @@ -2008,10 +2015,11 @@ callback(None, modname, '') else: try: - loader = importer.find_module(modname) + spec = pkgutil._get_spec(importer, modname) except SyntaxError: # raised by tests for bad coding cookies or BOM continue + loader = spec.loader if hasattr(loader, 'get_source'): try: source = loader.get_source(modname) @@ -2025,8 +2033,9 @@ else: path = None else: + _spec = importlib._bootstrap._SpecMethods(spec) try: - module = loader.load_module(modname) + module = _spec.load() except ImportError: if onerror: onerror(modname) 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 @@ -649,8 +649,10 @@ def test_importfile(self): loaded_pydoc = pydoc.importfile(pydoc.__file__) + self.assertIsNot(loaded_pydoc, pydoc) self.assertEqual(loaded_pydoc.__name__, 'pydoc') self.assertEqual(loaded_pydoc.__file__, pydoc.__file__) + self.assertEqual(loaded_pydoc.__spec__, pydoc.__spec__) class TestDescriptions(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -287,6 +287,8 @@ - Issue #19708: Update pkgutil to use the new importer APIs. +- Issue #19703: Update pydoc to use the new importer APIs. + - Issue #19851: Fixed a regression in reloading sub-modules. - ssl.create_default_context() sets OP_NO_COMPRESSION to prevent CRIME. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 7 04:51:11 2014 From: python-checkins at python.org (eric.snow) Date: Tue, 7 Jan 2014 04:51:11 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Remove_more_usage_of_APIs_?= =?utf-8?q?deprecated_by_PEP_451=2E?= Message-ID: <3dz04b0Pp3z7Lkt@mail.python.org> http://hg.python.org/cpython/rev/bfcbe41e892d changeset: 88332:bfcbe41e892d user: Eric Snow date: Mon Jan 06 20:42:59 2014 -0700 summary: Remove more usage of APIs deprecated by PEP 451. files: Lib/idlelib/EditorWindow.py | 8 ++++---- Lib/pkgutil.py | 13 +++++++------ Lib/pyclbr.py | 9 +++++---- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -659,20 +659,20 @@ return # XXX Ought to insert current file's directory in front of path try: - loader = importlib.find_loader(name) + spec = importlib.find_spec(name) except (ValueError, ImportError) as msg: tkMessageBox.showerror("Import error", str(msg), parent=self.text) return - if loader is None: + if spec is None: tkMessageBox.showerror("Import error", "module not found", parent=self.text) return - if not isinstance(loader, importlib.abc.SourceLoader): + if not isinstance(spec.loader, importlib.abc.SourceLoader): tkMessageBox.showerror("Import error", "not a source-based module", parent=self.text) return try: - file_path = loader.get_filename(name) + file_path = spec.loader.get_filename(name) except AttributeError: tkMessageBox.showerror("Import error", "loader does not support get_filename", diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py --- a/Lib/pkgutil.py +++ b/Lib/pkgutil.py @@ -554,13 +554,14 @@ finder = get_importer(dir) if finder is not None: + portions = [] + if hasattr(finder, 'find_spec'): + spec = finder.find_spec(final_name) + if spec is not None: + portions = spec.submodule_search_locations or [] # Is this finder PEP 420 compliant? - if hasattr(finder, 'find_loader'): - loader, portions = finder.find_loader(final_name) - else: - # No, no need to call it - loader = None - portions = [] + elif hasattr(finder, 'find_loader'): + _, portions = finder.find_loader(final_name) for portion in portions: # XXX This may still add duplicate entries to path on diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -140,13 +140,14 @@ search_path = path else: search_path = path + sys.path - loader = importlib.find_loader(fullmodule, search_path) - fname = loader.get_filename(fullmodule) + # XXX This will change once issue19944 lands. + spec = importlib.find_spec(fullmodule, search_path) + fname = spec.loader.get_filename(fullmodule) _modules[fullmodule] = dict - if loader.is_package(fullmodule): + if spec.loader.is_package(fullmodule): dict['__path__'] = [os.path.dirname(fname)] try: - source = loader.get_source(fullmodule) + source = spec.loader.get_source(fullmodule) if source is None: return dict except (AttributeError, ImportError): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 7 04:51:12 2014 From: python-checkins at python.org (eric.snow) Date: Tue, 7 Jan 2014 04:51:12 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_19713=3A_Add_PEP_451?= =?utf-8?q?-related_deprecations=2E?= Message-ID: <3dz04c5S29z7Lkr@mail.python.org> http://hg.python.org/cpython/rev/37caaf21f827 changeset: 88333:37caaf21f827 user: Eric Snow date: Mon Jan 06 20:49:04 2014 -0700 summary: Issue 19713: Add PEP 451-related deprecations. files: Lib/importlib/__init__.py | 6 +- Lib/importlib/_bootstrap.py | 124 +- Lib/importlib/abc.py | 13 +- Lib/importlib/util.py | 20 +- Lib/test/test_importlib/extension/test_finder.py | 5 +- Lib/test/test_importlib/frozen/test_loader.py | 42 +- Lib/test/test_importlib/source/test_file_loader.py | 54 +- Lib/test/test_importlib/source/test_finder.py | 49 +- Lib/test/test_importlib/source/test_source_encoding.py | 21 +- Lib/test/test_importlib/test_abc.py | 13 +- Lib/test/test_importlib/test_api.py | 27 +- Lib/test/test_importlib/test_spec.py | 2 +- Lib/test/test_importlib/test_util.py | 26 +- Misc/NEWS | 3 +- Python/importlib.h | 7978 +++++---- 15 files changed, 4342 insertions(+), 4041 deletions(-) diff --git a/Lib/importlib/__init__.py b/Lib/importlib/__init__.py --- a/Lib/importlib/__init__.py +++ b/Lib/importlib/__init__.py @@ -12,6 +12,7 @@ import _imp # Just the builtin component, NOT the full Python module import sys import types +import warnings try: import _frozen_importlib as _bootstrap @@ -77,13 +78,16 @@ return spec -# XXX Deprecate... def find_loader(name, path=None): """Return the loader for the specified module. This is a backward-compatible wrapper around find_spec(). + This function is deprecated in favor of importlib.find_spec(). + """ + warnings.warn('Use importlib.find_spec() instead.', DeprecationWarning, + stacklevel=2) try: loader = sys.modules[name].__loader__ if loader is None: diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -564,7 +564,11 @@ def _find_module_shim(self, fullname): """Try to find a loader for the specified module by delegating to - self.find_loader().""" + self.find_loader(). + + This method is deprecated in favor of finder.find_spec(). + + """ # Call find_loader(). If it returns a string (indicating this # is a namespace package portion), generate a warning and # return None. @@ -576,8 +580,11 @@ def _load_module_shim(self, fullname): - """Load the specified module into sys.modules and return it.""" - # XXX Deprecation Warning here... + """Load the specified module into sys.modules and return it. + + This method is deprecated. Use loader.exec_module instead. + + """ spec = spec_from_loader(fullname, self) methods = _SpecMethods(spec) if fullname in sys.modules: @@ -683,7 +690,9 @@ # The implementation of ModuleType__repr__(). loader = getattr(module, '__loader__', None) if hasattr(loader, 'module_repr'): - # XXX Deprecation Warning here... + # As soon as BuiltinImporter, FrozenImporter, and NamespaceLoader + # drop their implementations for module_repr. we can add a + # deprecation warning here. try: return loader.module_repr(module) except Exception: @@ -1149,17 +1158,27 @@ return module self.init_module_attrs(module, _override=True) if not hasattr(self.spec.loader, 'exec_module'): - # XXX DeprecationWarning goes here... + # (issue19713) Once BuiltinImporter and ExtensionFileLoader + # have exec_module() implemented, we can add a deprecation + # warning here. self.spec.loader.load_module(name) else: self._exec(module) return sys.modules[name] def _load_backward_compatible(self): - # XXX DeprecationWarning goes here... + # (issue19713) Once BuiltinImporter and ExtensionFileLoader + # have exec_module() implemented, we can add a deprecation + # warning here. spec = self.spec # The module must be in sys.modules! - spec.loader.load_module(spec.name) + try: + _warnings + except NameError: + # We must be importing builtins in setup(). + spec.loader.load_module(spec.name) + else: + spec.loader.load_module(spec.name) module = sys.modules[spec.name] if getattr(module, '__loader__', None) is None: try: @@ -1233,7 +1252,11 @@ @staticmethod def module_repr(module): - # XXX deprecate + """Return repr for the module. + + The method is deprecated. The import machinery does the job itself. + + """ return ''.format(module.__name__) @classmethod @@ -1251,6 +1274,8 @@ If 'path' is ever specified then the search is considered a failure. + This method is deprecated. Use find_spec() instead. + """ spec = cls.find_spec(fullname, path) return spec.loader if spec is not None else None @@ -1259,6 +1284,8 @@ @_requires_builtin def load_module(cls, fullname): """Load a built-in module.""" + # Once an exec_module() implementation is added we can also + # add a deprecation warning here. with _ManageReload(fullname): module = _call_with_frames_removed(_imp.init_builtin, fullname) module.__loader__ = cls @@ -1281,7 +1308,6 @@ @_requires_builtin def is_package(cls, fullname): """Return False as built-in modules are never packages.""" - # XXX DeprecationWarning here... return False @@ -1296,7 +1322,11 @@ @staticmethod def module_repr(m): - # XXX deprecate + """Return repr for the module. + + The method is deprecated. The import machinery does the job itself. + + """ return ''.format(m.__name__) @classmethod @@ -1308,7 +1338,11 @@ @classmethod def find_module(cls, fullname, path=None): - """Find a frozen module.""" + """Find a frozen module. + + This method is deprecated. Use find_spec() instead. + + """ return cls if _imp.is_frozen(fullname) else None @staticmethod @@ -1322,7 +1356,11 @@ @classmethod def load_module(cls, fullname): - """Load a frozen module.""" + """Load a frozen module. + + This method is deprecated. Use exec_module() instead. + + """ return _load_module_shim(cls, fullname) @classmethod @@ -1395,7 +1433,11 @@ @classmethod def find_module(cls, fullname, path=None): - """Find module named in the registry.""" + """Find module named in the registry. + + This method is deprecated. Use exec_module() instead. + + """ spec = cls.find_spec(fullname, path) if spec is not None: return spec.loader @@ -1408,7 +1450,6 @@ """Base class of common code needed by both SourceLoader and SourcelessFileLoader.""" - # XXX deprecate? def is_package(self, fullname): """Concrete implementation of InspectLoader.is_package by checking if the path returned by get_filename has a filename of '__init__.py'.""" @@ -1558,9 +1599,12 @@ @_check_name def load_module(self, fullname): - """Load a module from a file.""" + """Load a module from a file. + + This method is deprecated. Use exec_module() instead. + + """ # The only reason for this method is for the name check. - # Issue #14857: Avoid the zero-argument form of super so the implementation # of that form can be updated without breaking the frozen module return super(FileLoader, self).load_module(fullname) @@ -1660,6 +1704,8 @@ @_check_name def load_module(self, fullname): """Load an extension module.""" + # Once an exec_module() implementation is added we can also + # add a deprecation warning here. with _ManageReload(fullname): module = _call_with_frames_removed(_imp.load_dynamic, fullname, self.path) @@ -1754,9 +1800,13 @@ def __init__(self, name, path, path_finder): self._path = _NamespacePath(name, path, path_finder) - # XXX Deprecate @classmethod def module_repr(cls, module): + """Return repr for the module. + + The method is deprecated. The import machinery does the job itself. + + """ return ''.format(module.__name__) def is_package(self, fullname): @@ -1768,9 +1818,16 @@ def get_code(self, fullname): return compile('', '', 'exec', dont_inherit=True) - # XXX Deprecate + def exec_module(self, module): + pass + def load_module(self, fullname): - """Load a namespace module.""" + """Load a namespace module. + + This method is deprecated. Use exec_module() instead. + + """ + # The import system never calls this method. _verbose_message('namespace module loaded with path {!r}', self._path) return _load_module_shim(self, fullname) @@ -1825,6 +1882,8 @@ @classmethod def _legacy_get_spec(cls, fullname, finder): + # This would be a good place for a DeprecationWarning if + # we ended up going that route. if hasattr(finder, 'find_loader'): loader, portions = finder.find_loader(fullname) else: @@ -1893,8 +1952,11 @@ @classmethod def find_module(cls, fullname, path=None): """find the module on sys.path or 'path' based on sys.path_hooks and - sys.path_importer_cache.""" - # XXX Deprecation warning here. + sys.path_importer_cache. + + This method is deprecated. Use find_spec() instead. + + """ spec = cls.find_spec(fullname, path) if spec is None: return None @@ -1932,7 +1994,11 @@ def find_loader(self, fullname): """Try to find a loader for the specified module, or the namespace - package portions. Returns (loader, list-of-portions).""" + package portions. Returns (loader, list-of-portions). + + This method is deprecated. Use find_spec() instead. + + """ spec = self.find_spec(fullname) if spec is None: return None, [] @@ -2065,6 +2131,15 @@ return '{}.{}'.format(base, name) if name else base +def _find_spec_legacy(finder, name, path): + # This would be a good place for a DeprecationWarning if + # we ended up going that route. + loader = finder.find_module(name, path) + if loader is None: + return None + return spec_from_loader(name, loader) + + def _find_spec(name, path, target=None): """Find a module's loader.""" if not sys.meta_path: @@ -2078,10 +2153,9 @@ try: find_spec = finder.find_spec except AttributeError: - loader = finder.find_module(name, path) - if loader is None: + spec = _find_spec_legacy(finder, name, path) + if spec is None: continue - spec = spec_from_loader(name, loader) else: spec = find_spec(name, path, target) if spec is not None: diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py --- a/Lib/importlib/abc.py +++ b/Lib/importlib/abc.py @@ -43,13 +43,14 @@ # We don't define find_spec() here since that would break # hasattr checks we do to support backward compatibility. - # XXX Deprecate def find_module(self, fullname, path): """Return a loader for the module. If no module is found, return None. The fullname is a str and the path is a list of strings or None. + This method is deprecated in favor of finder.find_spec(). + """ return None @@ -69,7 +70,6 @@ # We don't define find_spec() here since that would break # hasattr checks we do to support backward compatibility. - # XXX Deprecate. def find_loader(self, fullname): """Return (loader, namespace portion) for the path entry. @@ -81,10 +81,11 @@ The portion will be discarded if another path entry finder locates the module as a normal module or package. + This method is deprecated in favor of finder.find_spec(). + """ return None, [] - # XXX Deprecate. find_module = _bootstrap._find_module_shim def invalidate_caches(self): @@ -115,7 +116,6 @@ # We don't define exec_module() here since that would break # hasattr checks we do to support backward compatibility. - # XXX Deprecate. def load_module(self, fullname): """Return the loaded module. @@ -124,16 +124,19 @@ ImportError is raised on failure. + This method is deprecated in favor of loader.exec_module(). + """ raise ImportError - # XXX Deprecate. def module_repr(self, module): """Return a module's repr. Used by the module type when the method does not raise NotImplementedError. + This method is deprecated. + """ # The exception will cause ModuleType.__repr__ to ignore this method. raise NotImplementedError diff --git a/Lib/importlib/util.py b/Lib/importlib/util.py --- a/Lib/importlib/util.py +++ b/Lib/importlib/util.py @@ -55,11 +55,16 @@ module.__initializing__ = False -# XXX deprecate def set_package(fxn): - """Set __package__ on the returned module.""" + """Set __package__ on the returned module. + + This function is deprecated. + + """ @functools.wraps(fxn) def set_package_wrapper(*args, **kwargs): + warnings.warn('The import system now takes care of this automatically.', + DeprecationWarning, stacklevel=2) module = fxn(*args, **kwargs) if getattr(module, '__package__', None) is None: module.__package__ = module.__name__ @@ -69,11 +74,16 @@ return set_package_wrapper -# XXX deprecate def set_loader(fxn): - """Set __loader__ on the returned module.""" + """Set __loader__ on the returned module. + + This function is deprecated. + + """ @functools.wraps(fxn) def set_loader_wrapper(self, *args, **kwargs): + warnings.warn('The import system now takes care of this automatically.', + DeprecationWarning, stacklevel=2) module = fxn(self, *args, **kwargs) if getattr(module, '__loader__', None) is None: module.__loader__ = self @@ -100,7 +110,7 @@ """ warnings.warn('The import system now takes care of this automatically.', - PendingDeprecationWarning, stacklevel=2) + DeprecationWarning, stacklevel=2) @functools.wraps(fxn) def module_for_loader_wrapper(self, fullname, *args, **kwargs): with _module_to_load(fullname) as module: diff --git a/Lib/test/test_importlib/extension/test_finder.py b/Lib/test/test_importlib/extension/test_finder.py --- a/Lib/test/test_importlib/extension/test_finder.py +++ b/Lib/test/test_importlib/extension/test_finder.py @@ -5,6 +5,7 @@ machinery = test_util.import_importlib('importlib.machinery') import unittest +import warnings # XXX find_spec tests @@ -16,7 +17,9 @@ importer = self.machinery.FileFinder(util.PATH, (self.machinery.ExtensionFileLoader, self.machinery.EXTENSION_SUFFIXES)) - return importer.find_module(fullname) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + return importer.find_module(fullname) def test_module(self): self.assertTrue(self.find_module(util.NAME)) diff --git a/Lib/test/test_importlib/frozen/test_loader.py b/Lib/test/test_importlib/frozen/test_loader.py --- a/Lib/test/test_importlib/frozen/test_loader.py +++ b/Lib/test/test_importlib/frozen/test_loader.py @@ -8,6 +8,7 @@ from test.support import captured_stdout import types import unittest +import warnings class ExecModuleTests(abc.LoaderTests): @@ -60,8 +61,16 @@ expected=value)) self.assertEqual(output, 'Hello world!\n') + def test_module_repr(self): + name = '__hello__' + module, output = self.exec_module(name) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + repr_str = self.machinery.FrozenImporter.module_repr(module) + self.assertEqual(repr_str, + "") - def test_module_repr(self): + def test_module_repr_indirect(self): name = '__hello__' module, output = self.exec_module(name) self.assertEqual(repr(module), @@ -84,7 +93,9 @@ def test_module(self): with util.uncache('__hello__'), captured_stdout() as stdout: - module = self.machinery.FrozenImporter.load_module('__hello__') + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + module = self.machinery.FrozenImporter.load_module('__hello__') check = {'__name__': '__hello__', '__package__': '', '__loader__': self.machinery.FrozenImporter, @@ -96,7 +107,9 @@ def test_package(self): with util.uncache('__phello__'), captured_stdout() as stdout: - module = self.machinery.FrozenImporter.load_module('__phello__') + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + module = self.machinery.FrozenImporter.load_module('__phello__') check = {'__name__': '__phello__', '__package__': '__phello__', '__path__': [], @@ -113,7 +126,9 @@ def test_lacking_parent(self): with util.uncache('__phello__', '__phello__.spam'), \ captured_stdout() as stdout: - module = self.machinery.FrozenImporter.load_module('__phello__.spam') + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + module = self.machinery.FrozenImporter.load_module('__phello__.spam') check = {'__name__': '__phello__.spam', '__package__': '__phello__', '__loader__': self.machinery.FrozenImporter, @@ -128,17 +143,28 @@ def test_module_reuse(self): with util.uncache('__hello__'), captured_stdout() as stdout: - module1 = self.machinery.FrozenImporter.load_module('__hello__') - module2 = self.machinery.FrozenImporter.load_module('__hello__') + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + module1 = self.machinery.FrozenImporter.load_module('__hello__') + module2 = self.machinery.FrozenImporter.load_module('__hello__') self.assertIs(module1, module2) self.assertEqual(stdout.getvalue(), 'Hello world!\nHello world!\n') def test_module_repr(self): with util.uncache('__hello__'), captured_stdout(): + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + module = self.machinery.FrozenImporter.load_module('__hello__') + repr_str = self.machinery.FrozenImporter.module_repr(module) + self.assertEqual(repr_str, + "") + + def test_module_repr_indirect(self): + with util.uncache('__hello__'), captured_stdout(): module = self.machinery.FrozenImporter.load_module('__hello__') - self.assertEqual(repr(module), - "") + self.assertEqual(repr(module), + "") # No way to trigger an error in a frozen module. test_state_after_failure = None diff --git a/Lib/test/test_importlib/source/test_file_loader.py b/Lib/test/test_importlib/source/test_file_loader.py --- a/Lib/test/test_importlib/source/test_file_loader.py +++ b/Lib/test/test_importlib/source/test_file_loader.py @@ -16,6 +16,7 @@ import sys import types import unittest +import warnings from test.support import make_legacy_pyc, unload @@ -39,7 +40,9 @@ loader = Tester('blah', 'blah.py') self.addCleanup(unload, 'blah') - module = loader.load_module() # Should not raise an exception. + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + module = loader.load_module() # Should not raise an exception. def test_get_filename_API(self): # If fullname is not set then assume self.path is desired. @@ -70,7 +73,9 @@ def test_module(self): with source_util.create_modules('_temp') as mapping: loader = self.machinery.SourceFileLoader('_temp', mapping['_temp']) - module = loader.load_module('_temp') + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + module = loader.load_module('_temp') self.assertIn('_temp', sys.modules) check = {'__name__': '_temp', '__file__': mapping['_temp'], '__package__': ''} @@ -81,7 +86,9 @@ with source_util.create_modules('_pkg.__init__') as mapping: loader = self.machinery.SourceFileLoader('_pkg', mapping['_pkg.__init__']) - module = loader.load_module('_pkg') + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + module = loader.load_module('_pkg') self.assertIn('_pkg', sys.modules) check = {'__name__': '_pkg', '__file__': mapping['_pkg.__init__'], '__path__': [os.path.dirname(mapping['_pkg.__init__'])], @@ -94,7 +101,9 @@ with source_util.create_modules('_pkg.__init__', '_pkg.mod')as mapping: loader = self.machinery.SourceFileLoader('_pkg.mod', mapping['_pkg.mod']) - module = loader.load_module('_pkg.mod') + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + module = loader.load_module('_pkg.mod') self.assertIn('_pkg.mod', sys.modules) check = {'__name__': '_pkg.mod', '__file__': mapping['_pkg.mod'], '__package__': '_pkg'} @@ -108,12 +117,16 @@ def test_module_reuse(self): with source_util.create_modules('_temp') as mapping: loader = self.machinery.SourceFileLoader('_temp', mapping['_temp']) - module = loader.load_module('_temp') + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + module = loader.load_module('_temp') module_id = id(module) module_dict_id = id(module.__dict__) with open(mapping['_temp'], 'w') as file: file.write("testing_var = 42\n") - module = loader.load_module('_temp') + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + module = loader.load_module('_temp') self.assertIn('testing_var', module.__dict__, "'testing_var' not in " "{0}".format(list(module.__dict__.keys()))) @@ -138,7 +151,9 @@ for attr in attributes: self.assertEqual(getattr(orig_module, attr), value) with self.assertRaises(SyntaxError): - loader.load_module(name) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + loader.load_module(name) for attr in attributes: self.assertEqual(getattr(orig_module, attr), value) @@ -149,7 +164,9 @@ file.write('=') loader = self.machinery.SourceFileLoader('_temp', mapping['_temp']) with self.assertRaises(SyntaxError): - loader.load_module('_temp') + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + loader.load_module('_temp') self.assertNotIn('_temp', sys.modules) def test_file_from_empty_string_dir(self): @@ -161,7 +178,9 @@ try: with util.uncache('_temp'): loader = self.machinery.SourceFileLoader('_temp', file_path) - mod = loader.load_module('_temp') + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + mod = loader.load_module('_temp') self.assertEqual(file_path, mod.__file__) self.assertEqual(self.util.cache_from_source(file_path), mod.__cached__) @@ -196,7 +215,9 @@ self.assertTrue(os.path.exists(compiled)) os.unlink(compiled) # PEP 302 - mod = loader.load_module('_temp') # XXX + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + mod = loader.load_module('_temp') # XXX # Sanity checks. self.assertEqual(mod.__cached__, compiled) self.assertEqual(mod.x, 5) @@ -210,7 +231,9 @@ with self.assertRaises(ImportError): loader.exec_module(module) with self.assertRaises(ImportError): - loader.load_module('bad name') + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + loader.load_module('bad name') Frozen_SimpleTest, Source_SimpleTest = util.test_both( SimpleTest, importlib=importlib, machinery=machinery, abc=importlib_abc, @@ -221,7 +244,10 @@ def import_(self, file, module_name): loader = self.loader(module_name, file) - module = loader.load_module(module_name) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + # XXX Change to use exec_module(). + module = loader.load_module(module_name) self.assertIn(module_name, sys.modules) def manipulate_bytecode(self, name, mapping, manipulator, *, @@ -332,7 +358,9 @@ def import_(self, file, module_name): loader = self.loader(module_name, file) - module = loader.load_module(module_name) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + module = loader.load_module(module_name) self.assertIn(module_name, sys.modules) diff --git a/Lib/test/test_importlib/source/test_finder.py b/Lib/test/test_importlib/source/test_finder.py --- a/Lib/test/test_importlib/source/test_finder.py +++ b/Lib/test/test_importlib/source/test_finder.py @@ -46,6 +46,10 @@ self.machinery.BYTECODE_SUFFIXES)] return self.machinery.FileFinder(root, *loader_details) + def import_(self, root, module): + finder = self.get_finder(root) + return self._find(finder, module, loader_only=True) + def run_test(self, test, create=None, *, compile_=None, unlink=None): """Test the finding of 'test' with the creation of modules listed in 'create'. @@ -127,7 +131,7 @@ with open('mod.py', 'w') as file: file.write("# test file for importlib") try: - loader = finder.find_module('mod') + loader = self._find(finder, 'mod', loader_only=True) self.assertTrue(hasattr(loader, 'load_module')) finally: os.unlink('mod.py') @@ -145,8 +149,10 @@ mod = 'mod' with source_util.create_modules(mod) as mapping: finder = self.get_finder(mapping['.root']) - self.assertIsNotNone(finder.find_module(mod)) - self.assertIsNone(finder.find_module(mod)) + found = self._find(finder, 'mod', loader_only=True) + self.assertIsNotNone(found) + found = self._find(finder, 'mod', loader_only=True) + self.assertIsNone(found) @unittest.skipUnless(sys.platform != 'win32', 'os.chmod() does not support the needed arguments under Windows') @@ -170,29 +176,52 @@ self.addCleanup(cleanup, tempdir) os.chmod(tempdir.name, stat.S_IWUSR | stat.S_IXUSR) finder = self.get_finder(tempdir.name) - self.assertEqual((None, []), finder.find_loader('doesnotexist')) + found = self._find(finder, 'doesnotexist') + self.assertEqual(found, self.NOT_FOUND) def test_ignore_file(self): # If a directory got changed to a file from underneath us, then don't # worry about looking for submodules. with tempfile.NamedTemporaryFile() as file_obj: finder = self.get_finder(file_obj.name) - self.assertEqual((None, []), finder.find_loader('doesnotexist')) + found = self._find(finder, 'doesnotexist') + self.assertEqual(found, self.NOT_FOUND) + class FinderTestsPEP451(FinderTests): - def import_(self, root, module): - found = self.get_finder(root).find_spec(module) - return found.loader if found is not None else found + NOT_FOUND = None + + def _find(self, finder, name, loader_only=False): + spec = finder.find_spec(name) + return spec.loader if spec is not None else spec Frozen_FinderTestsPEP451, Source_FinderTestsPEP451 = util.test_both( FinderTestsPEP451, machinery=machinery) +class FinderTestsPEP420(FinderTests): + + NOT_FOUND = (None, []) + + def _find(self, finder, name, loader_only=False): + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + loader_portions = finder.find_loader(name) + return loader_portions[0] if loader_only else loader_portions + +Frozen_FinderTestsPEP420, Source_FinderTestsPEP420 = util.test_both( + FinderTestsPEP420, machinery=machinery) + + class FinderTestsPEP302(FinderTests): - def import_(self, root, module): - return self.get_finder(root).find_module(module) + NOT_FOUND = None + + def _find(self, finder, name, loader_only=False): + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + return finder.find_module(name) Frozen_FinderTestsPEP302, Source_FinderTestsPEP302 = util.test_both( FinderTestsPEP302, machinery=machinery) diff --git a/Lib/test/test_importlib/source/test_source_encoding.py b/Lib/test/test_importlib/source/test_source_encoding.py --- a/Lib/test/test_importlib/source/test_source_encoding.py +++ b/Lib/test/test_importlib/source/test_source_encoding.py @@ -12,6 +12,7 @@ # imported for the parser to use. import unicodedata import unittest +import warnings CODING_RE = re.compile(r'^[ \t\f]*#.*coding[:=][ \t]*([-\w.]+)', re.ASCII) @@ -102,7 +103,9 @@ class EncodingTestPEP302(EncodingTest): def load(self, loader): - return loader.load_module(self.module_name) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + return loader.load_module(self.module_name) Frozen_EncodingTestPEP302, Source_EncodingTestPEP302 = util.test_both( EncodingTestPEP302, machinery=machinery) @@ -121,8 +124,8 @@ with open(mapping[module_name], 'wb') as file: file.write(source) loader = self.machinery.SourceFileLoader(module_name, - mapping[module_name]) - return loader.load_module(module_name) + mapping[module_name]) + return self.load(loader, module_name) # [cr] def test_cr(self): @@ -138,9 +141,9 @@ class LineEndingTestPEP451(LineEndingTest): - def load(self, loader): - module = types.ModuleType(self.module_name) - module.__spec__ = importlib.util.spec_from_loader(self.module_name, loader) + def load(self, loader, module_name): + module = types.ModuleType(module_name) + module.__spec__ = importlib.util.spec_from_loader(module_name, loader) loader.exec_module(module) return module @@ -149,8 +152,10 @@ class LineEndingTestPEP302(LineEndingTest): - def load(self, loader): - return loader.load_module(self.module_name) + def load(self, loader, module_name): + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + return loader.load_module(module_name) Frozen_LineEndingTestPEP302, Source_LineEndingTestPEP302 = util.test_both( LineEndingTestPEP302, machinery=machinery) diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py --- a/Lib/test/test_importlib/test_abc.py +++ b/Lib/test/test_importlib/test_abc.py @@ -8,6 +8,7 @@ import types import unittest from unittest import mock +import warnings from . import util @@ -388,7 +389,9 @@ mocked_get_code.side_effect = ImportError with self.assertRaises(ImportError): loader = self.InspectLoaderSubclass() - loader.load_module(self.module_name) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + loader.load_module(self.module_name) def test_get_code_None(self): # If get_code() returns None, raise ImportError. @@ -631,7 +634,9 @@ # __path__ (for packages), __file__, and __cached__. # The module should also be put into sys.modules. with util.uncache(self.name): - module = self.loader.load_module(self.name) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + module = self.loader.load_module(self.name) self.verify_module(module) self.assertEqual(module.__path__, [os.path.dirname(self.path)]) self.assertIn(self.name, sys.modules) @@ -642,7 +647,9 @@ # Testing the values for a package are covered by test_load_module. self.setUp(is_package=False) with util.uncache(self.name): - module = self.loader.load_module(self.name) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + module = self.loader.load_module(self.name) self.verify_module(module) self.assertTrue(not hasattr(module, '__path__')) diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py --- a/Lib/test/test_importlib/test_api.py +++ b/Lib/test/test_importlib/test_api.py @@ -10,6 +10,7 @@ from test import support import types import unittest +import warnings @contextmanager @@ -143,7 +144,9 @@ loader = 'a loader!' module.__loader__ = loader sys.modules[name] = module - found = self.init.find_loader(name) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + found = self.init.find_loader(name) self.assertEqual(loader, found) def test_sys_modules_loader_is_None(self): @@ -154,7 +157,9 @@ module.__loader__ = None sys.modules[name] = module with self.assertRaises(ValueError): - self.init.find_loader(name) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + self.init.find_loader(name) def test_sys_modules_loader_is_not_set(self): # Should raise ValueError @@ -168,14 +173,18 @@ pass sys.modules[name] = module with self.assertRaises(ValueError): - self.init.find_loader(name) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + self.init.find_loader(name) def test_success(self): # Return the loader found on sys.meta_path. name = 'some_mod' with util.uncache(name): with util.import_state(meta_path=[self.FakeMetaFinder]): - self.assertEqual((name, None), self.init.find_loader(name)) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + self.assertEqual((name, None), self.init.find_loader(name)) def test_success_path(self): # Searching on a path should work. @@ -183,12 +192,16 @@ path = 'path to some place' with util.uncache(name): with util.import_state(meta_path=[self.FakeMetaFinder]): - self.assertEqual((name, path), - self.init.find_loader(name, path)) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + self.assertEqual((name, path), + self.init.find_loader(name, path)) def test_nothing(self): # None is returned upon failure to find a loader. - self.assertIsNone(self.init.find_loader('nevergoingtofindthismodule')) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + self.assertIsNone(self.init.find_loader('nevergoingtofindthismodule')) class Frozen_FindLoaderTests(FindLoaderTests, unittest.TestCase): init = frozen_init diff --git a/Lib/test/test_importlib/test_spec.py b/Lib/test/test_importlib/test_spec.py --- a/Lib/test/test_importlib/test_spec.py +++ b/Lib/test/test_importlib/test_spec.py @@ -50,7 +50,7 @@ HAM = -1 with warnings.catch_warnings(): - warnings.simplefilter("ignore", PendingDeprecationWarning) + warnings.simplefilter("ignore", DeprecationWarning) @frozen_util.module_for_loader def load_module(self, module): diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py --- a/Lib/test/test_importlib/test_util.py +++ b/Lib/test/test_importlib/test_util.py @@ -41,14 +41,14 @@ @classmethod def module_for_loader(cls, func): with warnings.catch_warnings(): - warnings.simplefilter('ignore', PendingDeprecationWarning) + warnings.simplefilter('ignore', DeprecationWarning) return cls.util.module_for_loader(func) def test_warning(self): # Should raise a PendingDeprecationWarning when used. with warnings.catch_warnings(): - warnings.simplefilter('error', PendingDeprecationWarning) - with self.assertRaises(PendingDeprecationWarning): + warnings.simplefilter('error', DeprecationWarning) + with self.assertRaises(DeprecationWarning): func = self.util.module_for_loader(lambda x: x) def return_module(self, name): @@ -172,7 +172,9 @@ passing through set_package.""" fxn = lambda: module wrapped = self.util.set_package(fxn) - wrapped() + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + wrapped() self.assertTrue(hasattr(module, '__package__')) self.assertEqual(expect, module.__package__) @@ -212,7 +214,9 @@ def test_decorator_attrs(self): def fxn(module): pass - wrapped = self.util.set_package(fxn) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + wrapped = self.util.set_package(fxn) self.assertEqual(wrapped.__name__, fxn.__name__) self.assertEqual(wrapped.__qualname__, fxn.__qualname__) @@ -236,19 +240,25 @@ del loader.module.__loader__ except AttributeError: pass - self.assertEqual(loader, loader.load_module('blah').__loader__) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + self.assertEqual(loader, loader.load_module('blah').__loader__) def test_attribute_is_None(self): loader = self.DummyLoader() loader.module = types.ModuleType('blah') loader.module.__loader__ = None - self.assertEqual(loader, loader.load_module('blah').__loader__) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + self.assertEqual(loader, loader.load_module('blah').__loader__) def test_not_reset(self): loader = self.DummyLoader() loader.module = types.ModuleType('blah') loader.module.__loader__ = 42 - self.assertEqual(42, loader.load_module('blah').__loader__) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + self.assertEqual(42, loader.load_module('blah').__loader__) class Frozen_SetLoaderTests(SetLoaderTests, unittest.TestCase): class DummyLoader: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -283,7 +283,8 @@ - Issue #6477: Added support for pickling the types of built-in singletons (i.e., Ellipsis, NotImplemented, None). -- Issue #19713: Move away from using find_module/load_module. +- Issue #19713: Add remaining PEP 451-related deprecations and move away + from using find_module/find_loaer/load_module. - Issue #19708: Update pkgutil to use the new importer APIs. diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue Jan 7 09:46:21 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 07 Jan 2014 09:46:21 +0100 Subject: [Python-checkins] Daily reference leaks (54d32e01bbfd): sum=11 Message-ID: results for 54d32e01bbfd on branch "default" -------------------------------------------- test_asyncio leaked [0, 4, 0] memory blocks, sum=4 test_audioop leaked [1, 1, 1] references, sum=3 test_site leaked [0, 2, 0] references, sum=2 test_site leaked [0, 2, 0] memory blocks, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogkKOhhA', '-x'] From python-checkins at python.org Tue Jan 7 10:11:26 2014 From: python-checkins at python.org (gregory.p.smith) Date: Tue, 7 Jan 2014 10:11:26 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Should_fix_the?= =?utf-8?q?_issue19081_fix_on_Windows=2E__Don=27t_let_the_previous?= Message-ID: <3dz7B6269Lz7Lkl@mail.python.org> http://hg.python.org/cpython/rev/e09644eb6b20 changeset: 88334:e09644eb6b20 branch: 2.7 parent: 88324:cbeb22969da1 user: Gregory P. Smith date: Tue Jan 07 01:11:09 2014 -0800 summary: Should fix the issue19081 fix on Windows. Don't let the previous posix module ImportError cause the nt module import to fail. files: Modules/zipimport.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Modules/zipimport.c b/Modules/zipimport.c --- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -1429,9 +1429,10 @@ * live within a zipped up standard library. Import the posix or nt * builtin that provides the fstat() function we want instead. */ PyObject *os_like_module; - Py_XDECREF(fstat_function); /* Avoid embedded interpreter leaks. */ + Py_CLEAR(fstat_function); /* Avoid embedded interpreter leaks. */ os_like_module = PyImport_ImportModule("posix"); if (os_like_module == NULL) { + PyErr_Clear(); os_like_module = PyImport_ImportModule("nt"); } if (os_like_module != NULL) { @@ -1440,6 +1441,8 @@ } if (fstat_function == NULL) { PyErr_Clear(); /* non-fatal, we'll go on without it. */ + if (Py_VerboseFlag) + PySys_WriteStderr("# zipimport unable to use os.fstat().\n"); } } } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 7 14:42:14 2014 From: python-checkins at python.org (victor.stinner) Date: Tue, 7 Jan 2014 14:42:14 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320162=3A_test=5Fh?= =?utf-8?q?ash=5Fdistribution=28=29_uses_subTest=28=29_to_mention_the_pref?= =?utf-8?q?ix_in?= Message-ID: <3dzFBZ1xMFzPVW@mail.python.org> http://hg.python.org/cpython/rev/81f8b4744f1a changeset: 88335:81f8b4744f1a parent: 88333:37caaf21f827 user: Victor Stinner date: Tue Jan 07 14:40:51 2014 +0100 summary: Issue #20162: test_hash_distribution() uses subTest() to mention the prefix in the error message. files: Lib/test/test_hash.py | 19 ++++++++++--------- 1 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_hash.py b/Lib/test/test_hash.py --- a/Lib/test/test_hash.py +++ b/Lib/test/test_hash.py @@ -330,15 +330,16 @@ base = "abcdefghabcdefg" for i in range(1, len(base)): prefix = base[:i] - s15 = set() - s255 = set() - for c in range(256): - h = hash(prefix + chr(c)) - s15.add(h & 0xf) - s255.add(h & 0xff) - # SipHash24 distribution depends on key, usually > 60% - self.assertGreater(len(s15), 8, prefix) - self.assertGreater(len(s255), 128, prefix) + with self.subTest(prefix=prefix): + s15 = set() + s255 = set() + for c in range(256): + h = hash(prefix + chr(c)) + s15.add(h & 0xf) + s255.add(h & 0xff) + # SipHash24 distribution depends on key, usually > 60% + self.assertGreater(len(s15), 8, prefix) + self.assertGreater(len(s255), 128, prefix) if __name__ == "__main__": unittest.main() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 7 17:52:14 2014 From: python-checkins at python.org (brett.cannon) Date: Tue, 7 Jan 2014 17:52:14 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320096=3A_Update_t?= =?utf-8?q?he_Python_2/3_porting_HOWTO_to_focus_on?= Message-ID: <3dzKPp4v9Nz7LjR@mail.python.org> http://hg.python.org/cpython/rev/e4d98ed54c53 changeset: 88336:e4d98ed54c53 user: Brett Cannon date: Tue Jan 07 11:52:04 2014 -0500 summary: Issue #20096: Update the Python 2/3 porting HOWTO to focus on source-compatibility instead of 2to3. files: Doc/howto/pyporting.rst | 580 ++++++++++----------------- 1 files changed, 214 insertions(+), 366 deletions(-) diff --git a/Doc/howto/pyporting.rst b/Doc/howto/pyporting.rst --- a/Doc/howto/pyporting.rst +++ b/Doc/howto/pyporting.rst @@ -10,258 +10,183 @@ With Python 3 being the future of Python while Python 2 is still in active use, it is good to have your project available for both major releases of - Python. This guide is meant to help you choose which strategy works best - for your project to support both Python 2 & 3 along with how to execute - that strategy. + Python. This guide is meant to help you figure out how best to support both + Python 2 & 3 simultaneously. If you are looking to port an extension module instead of pure Python code, please see :ref:`cporting-howto`. + If you would like to read one core Python developer's take on why Python 3 + came into existence, you can read Nick Coghlan's `Python 3 Q & A`_. -Choosing a Strategy -=================== + If you prefer to read a (free) book on porting a project to Python 3, + consider reading `Porting to Python 3`_ by Lennart Regebro which should cover + much of what is discussed in this HOWTO. -When a project chooses to support both Python 2 & 3, -a decision needs to be made as to how to go about accomplishing that goal. -The chosen strategy will depend on how large the project's existing -codebase is and how much divergence you want from your current Python 2 codebase -(e.g., changing your code to work simultaneously with Python 2 and 3). + For help with porting, you can email the python-porting_ mailing list with + questions. -If you would prefer to maintain a codebase which is semantically **and** -syntactically compatible with Python 2 & 3 simultaneously, you can write -:ref:`use_same_source`. While this tends to lead to somewhat non-idiomatic -code, it does mean you keep a rapid development process for you, the developer. -If your project is brand-new or does not have a large codebase, then you may -want to consider writing/porting :ref:`all of your code for Python 3 -and use 3to2 ` to port your code for Python 2. +Before You Begin +================ -Finally, you do have the option of :ref:`using 2to3 ` to translate -Python 2 code into Python 3 code (with some manual help). This can take the -form of branching your code and using 2to3 to start a Python 3 branch. You can -also have users perform the translation at installation time automatically so -that you only have to maintain a Python 2 codebase. +If your project is on the Cheeseshop_/PyPI_, make sure it has the proper +`trove classifiers`_ to signify what versions of Python it **currently** +supports. At minimum you should specify the major version(s), e.g. +``Programming Language :: Python :: 2`` if your project currently only supports +Python 2. It is preferrable that you be as specific as possible by listing every +major/minor version of Python that you support, e.g. if your project supports +Python 2.6 and 2.7, then you want the classifiers of:: -Regardless of which approach you choose, porting is not as hard or -time-consuming as you might initially think. You can also tackle the problem -piece-meal as a good portion of porting is simply updating your code to follow -current best practices in a Python 2/3 compatible way. + Programming Language :: Python :: 2 + Programming Language :: Python :: 2.6 + Programming Language :: Python :: 2.7 +Once your project supports Python 3 you will want to go back and add the +appropriate classifiers for Python 3 as well. This is important as setting the +``Programming Language :: Python :: 3`` classifier will lead to your project +being listed under the `Python 3 Packages`_ section of PyPI. -Universal Bits of Advice ------------------------- +Make sure you have a robust test suite. You need to +make sure everything continues to work, just like when you support a new +minor/feature release of Python. This means making sure your test suite is +thorough and is ported properly between Python 2 & 3 (consider using coverage_ +to measure that you have effective test coverage). You will also most likely +want to use something like tox_ to automate testing between all of your +supported versions of Python. You will also want to **port your tests first** so +that you can make sure that you detect breakage during the transition. Tests also +tend to be simpler than the code they are testing so it gives you an idea of how +easy it can be to port code. -Regardless of what strategy you pick, there are a few things you should -consider. - -One is make sure you have a robust test suite. You need to make sure everything -continues to work, just like when you support a new minor/feature release of -Python. This means making sure your test suite is thorough and is ported -properly between Python 2 & 3. You will also most likely want to use something -like tox_ to automate testing between both a Python 2 and Python 3 interpreter. - -Two, once your project has Python 3 support, make sure to add the proper -classifier on the Cheeseshop_ (PyPI_). To have your project listed as Python 3 -compatible it must have the -`Python 3 classifier `_ -(from -http://techspot.zzzeek.org/2011/01/24/zzzeek-s-guide-to-python-3-porting/):: - - setup( - name='Your Library', - version='1.0', - classifiers=[ - # make sure to use :: Python *and* :: Python :: 3 so - # that pypi can list the package on the python 3 page - 'Programming Language :: Python', - 'Programming Language :: Python :: 3' - ], - packages=['yourlibrary'], - # make sure to add custom_fixers to the MANIFEST.in - include_package_data=True, - # ... - ) - - -Doing so will cause your project to show up in the -`Python 3 packages list -`_. You will know -you set the classifier properly as visiting your project page on the Cheeseshop -will show a Python 3 logo in the upper-left corner of the page. - -Three, the six_ project provides a library which helps iron out differences -between Python 2 & 3. If you find there is a sticky point that is a continual -point of contention in your translation or maintenance of code, consider using -a source-compatible solution relying on six. If you have to create your own -Python 2/3 compatible solution, you can use ``sys.version_info[0] >= 3`` as a -guard. - -Four, read all the approaches. Just because some bit of advice applies to one -approach more than another doesn't mean that some advice doesn't apply to other -strategies. This is especially true of whether you decide to use 2to3 or be -source-compatible; tips for one approach almost always apply to the other. - -Five, drop support for older Python versions if possible. `Python 2.5`_ +Drop support for older Python versions if possible. `Python 2.5`_ introduced a lot of useful syntax and libraries which have become idiomatic in Python 3. `Python 2.6`_ introduced future statements which makes compatibility much easier if you are going from Python 2 to 3. -`Python 2.7`_ continues the trend in the stdlib. So choose the newest version +`Python 2.7`_ continues the trend in the stdlib. Choose the newest version of Python which you believe can be your minimum support version and work from there. -Six, target the newest version of Python 3 that you can. Beyond just the usual +Target the newest version of Python 3 that you can. Beyond just the usual bugfixes, compatibility has continued to improve between Python 2 and 3 as time -has passed. This is especially true for Python 3.3 where the ``u`` prefix for -strings is allowed, making source-compatible Python code easier. +has passed. E.g. Python 3.3 added back the ``u`` prefix for +strings, making source-compatible Python code easier to write. -Seven, make sure to look at the `Other Resources`_ for tips from other people -which may help you out. +Writing Source-Compatible Python 2/3 Code +========================================= -.. _tox: http://codespeak.net/tox/ -.. _Cheeseshop: -.. _PyPI: http://pypi.python.org/ -.. _six: http://packages.python.org/six -.. _Python 2.7: http://www.python.org/2.7.x -.. _Python 2.6: http://www.python.org/2.6.x -.. _Python 2.5: http://www.python.org/2.5.x -.. _Python 2.4: http://www.python.org/2.4.x -.. _Python 2.3: http://www.python.org/2.3.x -.. _Python 2.2: http://www.python.org/2.2.x +Over the years the Python community has discovered that the easiest way to +support both Python 2 and 3 in parallel is to write Python code that works in +either version. While this might sound counter-intuitive at first, it actually +is not difficult and typically only requires following some select +(non-idiomatic) practices and using some key projects to help make bridging +between Python 2 and 3 easier. +Projects to Consider +-------------------- -.. _use_3to2: +The lowest level library for suppoting Python 2 & 3 simultaneously is six_. +Reading through its documentation will give you an idea of where exactly the +Python language changed between versions 2 & 3 and thus what you will want the +library to help you continue to support. -Python 3 and 3to2 -================= +To help automate porting your code over to using six, you can use +modernize_. This project will attempt to rewrite your code to be as modern as +possible while using six to smooth out any differences between Python 2 & 3. -If you are starting a new project or your codebase is small enough, you may -want to consider writing your code for Python 3 and backporting to Python 2 -using 3to2_. Thanks to Python 3 being more strict about things than Python 2 -(e.g., bytes vs. strings), the source translation can be easier and more -straightforward than from Python 2 to 3. Plus it gives you more direct -experience developing in Python 3 which, since it is the future of Python, is a -good thing long-term. +If you want to write your compatible code to feel more like Python 3 there is +the future_ project. It tries to provide backports of objects from Python 3 so +that you can use them from Python 2-compatible code, e.g. replacing the +``bytes`` type from Python 2 with the one from Python 3. +It also provides a translation script like modernize (its translation code is +actually partially based on it) to help start working with a pre-existing code +base. It is also unique in that its translation script will also port Python 3 +code backwards as well as Python 2 code forwards. -A drawback of this approach is that 3to2 is a third-party project. This means -that the Python core developers (and thus this guide) can make no promises -about how well 3to2 works at any time. There is nothing to suggest, though, -that 3to2 is not a high-quality project. +Tips & Tricks +------------- -.. _3to2: https://bitbucket.org/amentajo/lib3to2/overview - - -.. _use_2to3: - -Python 2 and 2to3 -================= - -Included with Python since 2.6, the 2to3_ tool (and :mod:`lib2to3` module) -helps with porting Python 2 to Python 3 by performing various source -translations. This is a perfect solution for projects which wish to branch -their Python 3 code from their Python 2 codebase and maintain them as -independent codebases. You can even begin preparing to use this approach -today by writing future-compatible Python code which works cleanly in -Python 2 in conjunction with 2to3; all steps outlined below will work -with Python 2 code up to the point when the actual use of 2to3 occurs. - -Use of 2to3 as an on-demand translation step at install time is also possible, -preventing the need to maintain a separate Python 3 codebase, but this approach -does come with some drawbacks. While users will only have to pay the -translation cost once at installation, you as a developer will need to pay the -cost regularly during development. If your codebase is sufficiently large -enough then the translation step ends up acting like a compilation step, -robbing you of the rapid development process you are used to with Python. -Obviously the time required to translate a project will vary, so do an -experimental translation just to see how long it takes to evaluate whether you -prefer this approach compared to using :ref:`use_same_source` or simply keeping -a separate Python 3 codebase. - -Below are the typical steps taken by a project which tries to support -Python 2 & 3 while keeping the code directly executable by Python 2. - +To help with writing source-compatible code using one of the projects mentioned +in `Projects to Consider`_, consider following the below suggestions. Some of +them are handled by the suggested projects, so if you do use one of them then +read their documentation first to see which suggestions below will taken care of +for you. Support Python 2.7 ------------------- +////////////////// As a first step, make sure that your project is compatible with `Python 2.7`_. This is just good to do as Python 2.7 is the last release of Python 2 and thus will be used for a rather long time. It also allows for use of the ``-3`` flag -to Python to help discover places in your code which 2to3 cannot handle but are -known to cause issues. +to Python to help discover places in your code where compatibility might be an +issue (the ``-3`` flag is in Python 2.6 but Python 2.7 adds more warnings). Try to Support `Python 2.6`_ and Newer Only -------------------------------------------- +/////////////////////////////////////////// While not possible for all projects, if you can support `Python 2.6`_ and newer **only**, your life will be much easier. Various future statements, stdlib additions, etc. exist only in Python 2.6 and later which greatly assist in -porting to Python 3. But if you project must keep support for `Python 2.5`_ (or -even `Python 2.4`_) then it is still possible to port to Python 3. +supporting Python 3. But if you project must keep support for `Python 2.5`_ then +it is still possible to simultaneously support Python 3. Below are the benefits you gain if you only have to support Python 2.6 and newer. Some of these options are personal choice while others are **strongly** recommended (the ones that are more for personal choice are labeled as such). If you continue to support older versions of Python then you -at least need to watch out for situations that these solutions fix. +at least need to watch out for situations that these solutions fix and handle +them appropriately (which is where library help from e.g. six_ comes in handy). ``from __future__ import print_function`` ''''''''''''''''''''''''''''''''''''''''' -This is a personal choice. 2to3 handles the translation from the print -statement to the print function rather well so this is an optional step. This -future statement does help, though, with getting used to typing -``print('Hello, World')`` instead of ``print 'Hello, World'``. +It will not only get you used to typing ``print()`` as a function instead of a +statement, but it will also give you the various benefits the function has over +the Python 2 statement (six_ provides a function if you support Python 2.5 or +older). ``from __future__ import unicode_literals`` ''''''''''''''''''''''''''''''''''''''''''' -Another personal choice. You can always mark what you want to be a (unicode) -string with a ``u`` prefix to get the same effect. But regardless of whether -you use this future statement or not, you **must** make sure you know exactly -which Python 2 strings you want to be bytes, and which are to be strings. This -means you should, **at minimum** mark all strings that are meant to be text -strings with a ``u`` prefix if you do not use this future statement. Python 3.3 -allows strings to continue to have the ``u`` prefix (it's a no-op in that case) -to make it easier for code to be source-compatible between Python 2 & 3. +If you choose not to use this future statement you should then mark all of your +text strings with a ``u`` prefix and only support Python 3.3 or newer. But you +are **strongly** advised to do one or the other (six_ provides a function in +case you don't want to use the future statement **and** you want to support +Python 3.2 or older). Bytes literals '''''''''''''' -This is a **very** important one. The ability to prefix Python 2 strings that -are meant to contain bytes with a ``b`` prefix help to very clearly delineate -what is and is not a Python 3 string. When you run 2to3 on code, all Python 2 -strings become Python 3 strings **unless** they are prefixed with ``b``. +This is a **very** important one. Prefix Python 2 strings that +are meant to contain bytes with a ``b`` prefix to very clearly delineate +what is and is not a Python 3 text string (six_ provides a function to use for +Python 2.5 compatibility). This point cannot be stressed enough: make sure you know what all of your string -literals in Python 2 are meant to become in Python 3. Any string literal that +literals in Python 2 are meant to be in Python 3. Any string literal that should be treated as bytes should have the ``b`` prefix. Any string literal that should be Unicode/text in Python 2 should either have the ``u`` literal (supported, but ignored, in Python 3.3 and later) or you should have ``from __future__ import unicode_literals`` at the top of the file. But the key -point is you should know how Python 3 will treat everyone one of your string +point is you should know how Python 3 will treat every one one of your string literals and you should mark them as appropriate. There are some differences between byte literals in Python 2 and those in Python 3 thanks to the bytes type just being an alias to ``str`` in Python 2. -Probably the biggest "gotcha" is that indexing results in different values. In -Python 2, the value of ``b'py'[1]`` is ``'y'``, while in Python 3 it's ``121``. -You can avoid this disparity by always slicing at the size of a single element: -``b'py'[1:2]`` is ``'y'`` in Python 2 and ``b'y'`` in Python 3 (i.e., close -enough). +See the `Handle Common "Gotchas"`_ section for what to watch out for. -You cannot concatenate bytes and strings in Python 3. But since Python -2 has bytes aliased to ``str``, it will succeed: ``b'a' + u'b'`` works in -Python 2, but ``b'a' + 'b'`` in Python 3 is a :exc:`TypeError`. A similar issue -also comes about when doing comparisons between bytes and strings. +``from __future__ import absolute_import`` +'''''''''''''''''''''''''''''''''''''''''' +Discussed in more detail below, but you should use this future statement to +prevent yourself from accidentally using implicit relative imports. Supporting `Python 2.5`_ and Newer Only ---------------------------------------- +/////////////////////////////////////// If you are supporting `Python 2.5`_ and newer there are still some features of Python that you can utilize. @@ -271,7 +196,7 @@ '''''''''''''''''''''''''''''''''''''''''' Implicit relative imports (e.g., importing ``spam.bacon`` from within -``spam.eggs`` with the statement ``import bacon``) does not work in Python 3. +``spam.eggs`` with the statement ``import bacon``) do not work in Python 3. This future statement moves away from that and allows the use of explicit relative imports (e.g., ``from . import bacon``). @@ -281,7 +206,7 @@ the statement, but you still want the __future__ statement to prevent implicit relative imports. In `Python 2.7`_ the __future__ statement is not needed. In other words, unless you are only supporting Python 2.7 or a version earlier -than Python 2.5, use the __future__ statement. +than Python 2.5, use this __future__ statement. Mark all Unicode strings with a ``u`` prefix @@ -290,17 +215,65 @@ While Python 2.6 has a ``__future__`` statement to automatically cause Python 2 to treat all string literals as Unicode, Python 2.5 does not have that shortcut. This means you should go through and mark all string literals with a ``u`` -prefix to turn them explicitly into Unicode strings where appropriate. That -leaves all unmarked string literals to be considered byte literals in Python 3. +prefix to turn them explicitly into text strings where appropriate and only +support Python 3.3 or newer. Otherwise use a project like six_ which provides a +function to pass all text string literals through. +Capturing the Currently Raised Exception +'''''''''''''''''''''''''''''''''''''''' + +In Python 2.5 and earlier the syntax to access the current exception is:: + + try: + raise Exception() + except Exception, exc: + # Current exception is 'exc'. + pass + +This syntax changed in Python 3 (and backported to `Python 2.6`_ and later) +to:: + + try: + raise Exception() + except Exception as exc: + # Current exception is 'exc'. + # In Python 3, 'exc' is restricted to the block; in Python 2.6/2.7 it will "leak". + pass + +Because of this syntax change you must change how you capture the current +exception in Python 2.5 and earlier to:: + + try: + raise Exception() + except Exception: + import sys + exc = sys.exc_info()[1] + # Current exception is 'exc'. + pass + +You can get more information about the raised exception from +:func:`sys.exc_info` than simply the current exception instance, but you most +likely don't need it. + +.. note:: + In Python 3, the traceback is attached to the exception instance + through the ``__traceback__`` attribute. If the instance is saved in + a local variable that persists outside of the ``except`` block, the + traceback will create a reference cycle with the current frame and its + dictionary of local variables. This will delay reclaiming dead + resources until the next cyclic :term:`garbage collection` pass. + + In Python 2, this problem only occurs if you save the traceback itself + (e.g. the third element of the tuple returned by :func:`sys.exc_info`) + in a variable. + Handle Common "Gotchas" ------------------------ +/////////////////////// -There are a few things that just consistently come up as sticking points for -people which 2to3 cannot handle automatically or can easily be done in Python 2 -to help modernize your code. +These are things to watch out for no matter what version of Python 2 you are +supporting which are not syntactic considerations. ``from __future__ import division`` @@ -357,9 +330,9 @@ the bytes/string dichotomy. Because Python 2 allowed the ``str`` type to hold textual data, people have over the years been rather loose in their delineation of what ``str`` instances held text compared to bytes. In Python 3 you cannot -be so care-free anymore and need to properly handle the difference. The key +be so care-free anymore and need to properly handle the difference. The key to handling this issue is to make sure that **every** string literal in your -Python 2 code is either syntactically of functionally marked as either bytes or +Python 2 code is either syntactically or functionally marked as either bytes or text data. After this is done you then need to make sure your APIs are designed to either handle a specific type or made to be properly polymorphic. @@ -466,14 +439,7 @@ happen to use the ``unicode(self).encode('utf8')`` idiom as the body of your ``__str__()`` method). -There are two ways to solve this issue. One is to use a custom 2to3 fixer. The -blog post at http://lucumr.pocoo.org/2011/1/22/forwards-compatible-python/ -specifies how to do this. That will allow 2to3 to change all instances of ``def -__unicode(self): ...`` to ``def __str__(self): ...``. This does require that you -define your ``__str__()`` method in Python 2 before your ``__unicode__()`` -method. - -The other option is to use a mixin class. This allows you to only define a +You can use a mixin class to work around this. This allows you to only define a ``__unicode__()`` method for your class and let the mixin derive ``__str__()`` for you (code from http://lucumr.pocoo.org/2011/1/22/forwards-compatible-python/):: @@ -516,6 +482,7 @@ Even better is to use the documented attributes the exception provides. + Don't use ``__getslice__`` & Friends '''''''''''''''''''''''''''''''''''' @@ -527,23 +494,22 @@ Updating doctests ''''''''''''''''' -2to3_ will attempt to generate fixes for doctests that it comes across. It's -not perfect, though. If you wrote a monolithic set of doctests (e.g., a single -docstring containing all of your doctests), you should at least consider -breaking the doctests up into smaller pieces to make it more manageable to fix. -Otherwise it might very well be worth your time and effort to port your tests -to :mod:`unittest`. +Don't forget to make them Python 2/3 compatible as well. If you wrote a +monolithic set of doctests (e.g., a single docstring containing all of your +doctests), you should at least consider breaking the doctests up into smaller +pieces to make it more manageable to fix. Otherwise it might very well be worth +your time and effort to port your tests to :mod:`unittest`. -Update `map` for imbalanced input sequences -''''''''''''''''''''''''''''''''''''''''''' +Update ``map`` for imbalanced input sequences +''''''''''''''''''''''''''''''''''''''''''''' -With Python 2, `map` would pad input sequences of unequal length with +With Python 2, ``map`` would pad input sequences of unequal length with `None` values, returning a sequence as long as the longest input sequence. -With Python 3, if the input sequences to `map` are of unequal length, `map` +With Python 3, if the input sequences to ``map`` are of unequal length, ``map`` will stop at the termination of the shortest of the sequences. For full -compatibility with `map` from Python 2.x, also wrap the sequences in +compatibility with ``map`` from Python 2.x, also wrap the sequences in :func:`itertools.zip_longest`, e.g. ``map(func, *sequences)`` becomes ``list(map(func, itertools.zip_longest(*sequences)))``. @@ -557,171 +523,30 @@ to Python 3. -Run 2to3 --------- +Alternative Approaches +====================== -Once you have made your Python 2 code future-compatible with Python 3, it's -time to use 2to3_ to actually port your code. +While supporting Python 2 & 3 simultaneously is typically the preferred choice +by people so that they can continue to improve code and have it work for the +most number of users, your life may be easier if you only have to support one +major version of Python going forward. +Supporting Only Python 3 Going Forward From Python 2 Code +--------------------------------------------------------- -Manually -'''''''' +If you have Python 2 code but going forward only want to improve it as Python 3 +code, then you can use 2to3_ to translate your Python 2 code to Python 3 code. +This is only recommended, though, if your current version of your project is +going into maintenance mode and you want all new features to be exclusive to +Python 3. -To manually convert source code using 2to3_, you use the ``2to3`` script that -is installed with Python 2.6 and later.:: - 2to3 +Backporting Python 3 code to Python 2 +------------------------------------- -This will cause 2to3 to write out a diff with all of the fixers applied for the -converted source code. If you would like 2to3 to go ahead and apply the changes -you can pass it the ``-w`` flag:: - - 2to3 -w - -There are other flags available to control exactly which fixers are applied, -etc. - - -During Installation -''''''''''''''''''' - -When a user installs your project for Python 3, you can have either -:mod:`distutils` or Distribute_ run 2to3_ on your behalf. -For distutils, use the following idiom:: - - try: # Python 3 - from distutils.command.build_py import build_py_2to3 as build_py - except ImportError: # Python 2 - from distutils.command.build_py import build_py - - setup(cmdclass = {'build_py': build_py}, - # ... - ) - -For Distribute:: - - setup(use_2to3=True, - # ... - ) - -This will allow you to not have to distribute a separate Python 3 version of -your project. It does require, though, that when you perform development that -you at least build your project and use the built Python 3 source for testing. - - -Verify & Test -------------- - -At this point you should (hopefully) have your project converted in such a way -that it works in Python 3. Verify it by running your unit tests and making sure -nothing has gone awry. If you miss something then figure out how to fix it in -Python 3, backport to your Python 2 code, and run your code through 2to3 again -to verify the fix transforms properly. - - -.. _2to3: http://docs.python.org/py3k/library/2to3.html -.. _Distribute: http://packages.python.org/distribute/ - - -.. _use_same_source: - -Python 2/3 Compatible Source -============================ - -While it may seem counter-intuitive, you can write Python code which is -source-compatible between Python 2 & 3. It does lead to code that is not -entirely idiomatic Python (e.g., having to extract the currently raised -exception from ``sys.exc_info()[1]``), but it can be run under Python 2 -**and** Python 3 without using 2to3_ as a translation step (although the tool -should be used to help find potential portability problems). This allows you to -continue to have a rapid development process regardless of whether you are -developing under Python 2 or Python 3. Whether this approach or using -:ref:`use_2to3` works best for you will be a per-project decision. - -To get a complete idea of what issues you will need to deal with, see the -`What's New in Python 3.0`_. Others have reorganized the data in other formats -such as http://docs.pythonsprints.com/python3_porting/py-porting.html\ . - -The following are some steps to take to try to support both Python 2 & 3 from -the same source code. - - -.. _What's New in Python 3.0: http://docs.python.org/release/3.0/whatsnew/3.0.html - - -Follow The Steps for Using 2to3_ --------------------------------- - -All of the steps outlined in how to -:ref:`port Python 2 code with 2to3 ` apply -to creating a Python 2/3 codebase. This includes trying only support Python 2.6 -or newer (the :mod:`__future__` statements work in Python 3 without issue), -eliminating warnings that are triggered by ``-3``, etc. - -You should even consider running 2to3_ over your code (without committing the -changes). This will let you know where potential pain points are within your -code so that you can fix them properly before they become an issue. - - -Use six_ --------- - -The six_ project contains many things to help you write portable Python code. -You should make sure to read its documentation from beginning to end and use -any and all features it provides. That way you will minimize any mistakes you -might make in writing cross-version code. - - -Capturing the Currently Raised Exception ----------------------------------------- - -One change between Python 2 and 3 that will require changing how you code (if -you support `Python 2.5`_ and earlier) is -accessing the currently raised exception. In Python 2.5 and earlier the syntax -to access the current exception is:: - - try: - raise Exception() - except Exception, exc: - # Current exception is 'exc' - pass - -This syntax changed in Python 3 (and backported to `Python 2.6`_ and later) -to:: - - try: - raise Exception() - except Exception as exc: - # Current exception is 'exc' - # In Python 3, 'exc' is restricted to the block; Python 2.6 will "leak" - pass - -Because of this syntax change you must change to capturing the current -exception to:: - - try: - raise Exception() - except Exception: - import sys - exc = sys.exc_info()[1] - # Current exception is 'exc' - pass - -You can get more information about the raised exception from -:func:`sys.exc_info` than simply the current exception instance, but you most -likely don't need it. - -.. note:: - In Python 3, the traceback is attached to the exception instance - through the ``__traceback__`` attribute. If the instance is saved in - a local variable that persists outside of the ``except`` block, the - traceback will create a reference cycle with the current frame and its - dictionary of local variables. This will delay reclaiming dead - resources until the next cyclic :term:`garbage collection` pass. - - In Python 2, this problem only occurs if you save the traceback itself - (e.g. the third element of the tuple returned by :func:`sys.exc_info`) - in a variable. +If you have Python 3 code and have little interest in supporting Python 2 you +can use 3to2_ to translate from Python 3 code to Python 2 code. This is only +recommended if you don't plan to heavily support Python 2 users. Other Resources @@ -729,18 +554,41 @@ The authors of the following blog posts, wiki pages, and books deserve special thanks for making public their tips for porting Python 2 code to Python 3 (and -thus helping provide information for this document): +thus helping provide information for this document and its various revisions +over the years): +* http://wiki.python.org/moin/PortingPythonToPy3k * http://python3porting.com/ * http://docs.pythonsprints.com/python3_porting/py-porting.html * http://techspot.zzzeek.org/2011/01/24/zzzeek-s-guide-to-python-3-porting/ * http://dabeaz.blogspot.com/2011/01/porting-py65-and-my-superboard-to.html * http://lucumr.pocoo.org/2011/1/22/forwards-compatible-python/ * http://lucumr.pocoo.org/2010/2/11/porting-to-python-3-a-guide/ -* http://wiki.python.org/moin/PortingPythonToPy3k * https://wiki.ubuntu.com/Python/3 If you feel there is something missing from this document that should be added, please email the python-porting_ mailing list. + + +.. _2to3: http://docs.python.org/2/library/2to3.html +.. _3to2: https://pypi.python.org/pypi/3to2 +.. _Cheeseshop: PyPI_ +.. _coverage: https://pypi.python.org/pypi/coverage +.. _future: http://python-future.org/ +.. _modernize: https://github.com/mitsuhiko/python-modernize +.. _Porting to Python 3: http://python3porting.com/ +.. _PyPI: http://pypi.python.org/ +.. _Python 2.2: http://www.python.org/2.2.x +.. _Python 2.5: http://www.python.org/2.5.x +.. _Python 2.6: http://www.python.org/2.6.x +.. _Python 2.7: http://www.python.org/2.7.x +.. _Python 2.5: http://www.python.org/2.5.x +.. _Python 3.3: http://www.python.org/3.3.x +.. _Python 3 Packages: https://pypi.python.org/pypi?:action=browse&c=533&show=all +.. _Python 3 Q & A: http://ncoghlan-devs-python-notes.readthedocs.org/en/latest/python3/questions_and_answers.html .. _python-porting: http://mail.python.org/mailman/listinfo/python-porting +.. _six: https://pypi.python.org/pypi/six +.. _tox: https://pypi.python.org/pypi/tox +.. _trove classifiers: https://pypi.python.org/pypi?%3Aaction=list_classifiers + -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 7 18:33:30 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 7 Jan 2014 18:33:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMDcy?= =?utf-8?q?=3A_Fixed_multiple_errors_in_tkinter_with_wantobjects_is_False?= =?utf-8?q?=2E?= Message-ID: <3dzLKQ0nVSz7LjP@mail.python.org> http://hg.python.org/cpython/rev/2d81d0d42ae2 changeset: 88337:2d81d0d42ae2 branch: 3.3 parent: 88292:28337a8fb502 user: Serhiy Storchaka date: Tue Jan 07 19:27:42 2014 +0200 summary: Issue #20072: Fixed multiple errors in tkinter with wantobjects is False. * Misc.image_names(), Misc.image_types(), Wm.wm_colormapwindows(), and LabelFrame.panes() now always return a tuple. * Fixed error of comparing str and int in tt.LabeledScale._adjust(). * ttk.Notebook.index() now always returns int. * ttk.Notebook.tabs() now always returns a tuple. * ttk.Entry.bbox() now always returns a tuple of ints. * ttk.Entry.validate() now always correctly works. * ttk.Combobox.current() now always returns int. * ttk.Panedwindow.sashpos() now always returns int. * ttk.Treeview.bbox() now always returns a tuple of ints. * ttk.Treeview.get_children() now always returns a tuple. * ttk.Treeview.exists() now always correctly works. * ttk.Treeview.index() now always returns int. * ttk.Treeview.tag_has() now always returns 0 or 1. * And numerous other errors in methods which returns a tuple, list or dict. * Fixed ttk tests for wantobjects is False. files: Lib/tkinter/__init__.py | 19 +- Lib/tkinter/test/test_ttk/test_extensions.py | 22 +- Lib/tkinter/test/test_ttk/test_functions.py | 6 +- Lib/tkinter/test/test_ttk/test_style.py | 3 +- Lib/tkinter/test/test_ttk/test_widgets.py | 113 ++++++--- Lib/tkinter/ttk.py | 59 +++- Misc/NEWS | 2 + 7 files changed, 153 insertions(+), 71 deletions(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -1459,11 +1459,11 @@ def image_names(self): """Return a list of all existing image names.""" - return self.tk.call('image', 'names') + return self.tk.splitlist(self.tk.call('image', 'names')) def image_types(self): """Return a list of all available image types (e.g. phote bitmap).""" - return self.tk.call('image', 'types') + return self.tk.splitlist(self.tk.call('image', 'types')) class CallWrapper: @@ -1577,7 +1577,11 @@ if len(wlist) > 1: wlist = (wlist,) # Tk needs a list of windows here args = ('wm', 'colormapwindows', self._w) + wlist - return [self._nametowidget(x) for x in self.tk.call(args)] + if wlist: + self.tk.call(args) + else: + return [self._nametowidget(x) + for x in self.tk.splitlist(self.tk.call(args))] colormapwindows = wm_colormapwindows def wm_command(self, value=None): """Store VALUE in WM_COMMAND property. It is the command @@ -3472,8 +3476,11 @@ Valid resource names: background, data, file, foreground, maskdata, maskfile.""" Image.__init__(self, 'bitmap', name, cnf, master, **kw) -def image_names(): return _default_root.tk.call('image', 'names') -def image_types(): return _default_root.tk.call('image', 'types') +def image_names(): + return _default_root.tk.splitlist(_default_root.tk.call('image', 'names')) + +def image_types(): + return _default_root.tk.splitlist(_default_root.tk.call('image', 'types')) class Spinbox(Widget, XView): @@ -3842,7 +3849,7 @@ def panes(self): """Returns an ordered list of the child panes.""" - return self.tk.call(self._w, 'panes') + return self.tk.splitlist(self.tk.call(self._w, 'panes')) ###################################################################### # Extensions: 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 @@ -29,7 +29,10 @@ name = myvar._name x = ttk.LabeledScale(variable=myvar) x.destroy() - self.assertEqual(x.tk.globalgetvar(name), myvar.get()) + if x.tk.wantobjects(): + self.assertEqual(x.tk.globalgetvar(name), myvar.get()) + else: + self.assertEqual(float(x.tk.globalgetvar(name)), myvar.get()) del myvar self.assertRaises(tkinter.TclError, x.tk.globalgetvar, name) @@ -59,8 +62,10 @@ x.destroy() # variable initialization/passing - passed_expected = ((2.5, 2), ('0', 0), (0, 0), (10, 10), + passed_expected = (('0', 0), (0, 0), (10, 10), (-1, -1), (sys.maxsize + 1, sys.maxsize + 1)) + if x.tk.wantobjects(): + passed_expected += ((2.5, 2),) for pair in passed_expected: x = ttk.LabeledScale(from_=pair[0]) self.assertEqual(x.value, pair[1]) @@ -123,7 +128,7 @@ self.assertNotEqual(prev_xcoord, curr_xcoord) # the label widget should have been repositioned too linfo_2 = lscale.label.place_info() - self.assertEqual(lscale.label['text'], 0) + self.assertEqual(lscale.label['text'], 0 if lscale.tk.wantobjects() else '0') self.assertEqual(curr_xcoord, int(linfo_2['x'])) # change the range back lscale.scale.configure(from_=0, to=10) @@ -145,15 +150,20 @@ # 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.label['text'], newval) + self.assertEqual(x.label['text'], + newval if x.tk.wantobjects() else str(newval)) self.assertGreater(x.scale.coords()[0], curr_xcoord) self.assertEqual(x.scale.coords()[0], int(x.label.place_info()['x'])) # value outside range - x.value = x.scale['to'] + 1 # no changes shouldn't happen + if x.tk.wantobjects(): + conv = lambda x: x + else: + conv = int + x.value = conv(x.scale['to']) + 1 # no changes shouldn't happen x.update() - self.assertEqual(x.label['text'], newval) + self.assertEqual(conv(x.label['text']), newval) self.assertEqual(x.scale.coords()[0], int(x.label.place_info()['x'])) diff --git a/Lib/tkinter/test/test_ttk/test_functions.py b/Lib/tkinter/test/test_ttk/test_functions.py --- a/Lib/tkinter/test/test_ttk/test_functions.py +++ b/Lib/tkinter/test/test_ttk/test_functions.py @@ -393,8 +393,10 @@ ('name', 'no_minus', 'value')) self.assertRaises(ValueError, ttk._list_from_layouttuple, ('something', '-children')) # no children - self.assertRaises(ValueError, ttk._list_from_layouttuple, - ('something', '-children', 'value')) # invalid children + import tkinter + if not tkinter._default_root or tkinter._default_root.wantobjects(): + self.assertRaises(ValueError, ttk._list_from_layouttuple, + ('something', '-children', 'value')) # invalid children def test_val_or_dict(self): diff --git a/Lib/tkinter/test/test_ttk/test_style.py b/Lib/tkinter/test/test_ttk/test_style.py --- a/Lib/tkinter/test/test_ttk/test_style.py +++ b/Lib/tkinter/test/test_ttk/test_style.py @@ -25,7 +25,8 @@ style = self.style style.map('TButton', background=[('active', 'background', 'blue')]) self.assertEqual(style.map('TButton', 'background'), - [('active', 'background', 'blue')]) + [('active', 'background', 'blue')] if style.tk.wantobjects() else + [('active background', 'blue')]) self.assertIsInstance(style.map('TButton'), dict) diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py --- a/Lib/tkinter/test/test_ttk/test_widgets.py +++ b/Lib/tkinter/test/test_ttk/test_widgets.py @@ -382,15 +382,21 @@ # testing values with empty string set through configure self.combo.configure(values=[1, '', 2]) - self.assertEqual(self.combo['values'], ('1', '', '2')) + self.assertEqual(self.combo['values'], + ('1', '', '2') if self.wantobjects else + '1 {} 2') # testing values with spaces self.combo['values'] = ['a b', 'a\tb', 'a\nb'] - self.assertEqual(self.combo['values'], ('a b', 'a\tb', 'a\nb')) + self.assertEqual(self.combo['values'], + ('a b', 'a\tb', 'a\nb') if self.wantobjects else + '{a b} {a\tb} {a\nb}') # testing values with special characters self.combo['values'] = [r'a\tb', '"a"', '} {'] - self.assertEqual(self.combo['values'], (r'a\tb', '"a"', '} {')) + self.assertEqual(self.combo['values'], + (r'a\tb', '"a"', '} {') if self.wantobjects else + r'a\\tb {"a"} \}\ \{') # out of range self.assertRaises(tkinter.TclError, self.combo.current, @@ -400,7 +406,8 @@ # testing creating combobox with empty string in values combo2 = ttk.Combobox(values=[1, 2, '']) - self.assertEqual(combo2['values'], ('1', '2', '')) + self.assertEqual(combo2['values'], + ('1', '2', '') if self.wantobjects else '1 2 {}') combo2.destroy() @@ -654,9 +661,11 @@ child = ttk.Label() self.paned.add(child) self.assertIsInstance(self.paned.pane(0), dict) - self.assertEqual(self.paned.pane(0, weight=None), 0) + self.assertEqual(self.paned.pane(0, weight=None), + 0 if self.wantobjects else '0') # newer form for querying a single option - self.assertEqual(self.paned.pane(0, 'weight'), 0) + self.assertEqual(self.paned.pane(0, 'weight'), + 0 if self.wantobjects else '0') self.assertEqual(self.paned.pane(0), self.paned.pane(str(child))) self.assertRaises(tkinter.TclError, self.paned.pane, 0, @@ -711,20 +720,25 @@ cbtn = ttk.Radiobutton(command=cb_test, variable=myvar, value=0) cbtn2 = ttk.Radiobutton(command=cb_test, variable=myvar, value=1) + if self.wantobjects: + conv = lambda x: x + else: + conv = int + res = cbtn.invoke() self.assertEqual(res, "cb test called") - self.assertEqual(cbtn['value'], myvar.get()) + self.assertEqual(conv(cbtn['value']), myvar.get()) self.assertEqual(myvar.get(), - cbtn.tk.globalgetvar(cbtn['variable'])) + conv(cbtn.tk.globalgetvar(cbtn['variable']))) self.assertTrue(success) cbtn2['command'] = '' res = cbtn2.invoke() self.assertEqual(str(res), '') self.assertLessEqual(len(success), 1) - self.assertEqual(cbtn2['value'], myvar.get()) + self.assertEqual(conv(cbtn2['value']), myvar.get()) self.assertEqual(myvar.get(), - cbtn.tk.globalgetvar(cbtn['variable'])) + conv(cbtn.tk.globalgetvar(cbtn['variable']))) self.assertEqual(str(cbtn['variable']), str(cbtn2['variable'])) @@ -812,10 +826,15 @@ def test_get(self): + if self.wantobjects: + conv = lambda x: x + else: + conv = float + scale_width = self.scale.winfo_width() self.assertEqual(self.scale.get(scale_width, 0), self.scale['to']) - self.assertEqual(self.scale.get(0, 0), self.scale['from']) + self.assertEqual(conv(self.scale.get(0, 0)), conv(self.scale['from'])) self.assertEqual(self.scale.get(), self.scale['value']) self.scale['value'] = 30 self.assertEqual(self.scale.get(), self.scale['value']) @@ -825,32 +844,37 @@ def test_set(self): + if self.wantobjects: + conv = lambda x: x + else: + conv = float + # set restricts the max/min values according to the current range - max = self.scale['to'] + max = conv(self.scale['to']) new_max = max + 10 self.scale.set(new_max) - self.assertEqual(self.scale.get(), max) - min = self.scale['from'] + self.assertEqual(conv(self.scale.get()), max) + min = conv(self.scale['from']) self.scale.set(min - 1) - self.assertEqual(self.scale.get(), min) + self.assertEqual(conv(self.scale.get()), min) # changing directly the variable doesn't impose this limitation tho var = tkinter.DoubleVar() self.scale['variable'] = var var.set(max + 5) - self.assertEqual(self.scale.get(), var.get()) - self.assertEqual(self.scale.get(), max + 5) + self.assertEqual(conv(self.scale.get()), var.get()) + self.assertEqual(conv(self.scale.get()), max + 5) del var # the same happens with the value option self.scale['value'] = max + 10 - self.assertEqual(self.scale.get(), max + 10) - self.assertEqual(self.scale.get(), self.scale['value']) + self.assertEqual(conv(self.scale.get()), max + 10) + self.assertEqual(conv(self.scale.get()), conv(self.scale['value'])) # nevertheless, note that the max/min values we can get specifying # x, y coords are the ones according to the current range - self.assertEqual(self.scale.get(0, 0), min) - self.assertEqual(self.scale.get(self.scale.winfo_width(), 0), max) + self.assertEqual(conv(self.scale.get(0, 0)), min) + self.assertEqual(conv(self.scale.get(self.scale.winfo_width(), 0)), max) self.assertRaises(tkinter.TclError, self.scale.set, None) @@ -1204,6 +1228,8 @@ self.tv.column('test', width=50) bbox_column0 = self.tv.bbox(children[0], 0) root_width = self.tv.column('#0', width=None) + if not self.wantobjects: + root_width = int(root_width) self.assertEqual(bbox_column0[0], bbox[0] + root_width) # verify that bbox of a closed item is the empty string @@ -1243,12 +1269,15 @@ # return a dict with all options/values self.assertIsInstance(self.tv.column('#0'), dict) # return a single value of the given option - self.assertIsInstance(self.tv.column('#0', width=None), int) + if self.wantobjects: + self.assertIsInstance(self.tv.column('#0', width=None), int) # set a new value for an option self.tv.column('#0', width=10) # testing new way to get option value - self.assertEqual(self.tv.column('#0', 'width'), 10) - self.assertEqual(self.tv.column('#0', width=None), 10) + self.assertEqual(self.tv.column('#0', 'width'), + 10 if self.wantobjects else '10') + self.assertEqual(self.tv.column('#0', width=None), + 10 if self.wantobjects else '10') # check read-only option self.assertRaises(tkinter.TclError, self.tv.column, '#0', id='X') @@ -1461,11 +1490,14 @@ # unicode values value = '\xe1ba' item = self.tv.insert('', 'end', values=(value, )) - self.assertEqual(self.tv.item(item, 'values'), (value, )) - self.assertEqual(self.tv.item(item, values=None), (value, )) + self.assertEqual(self.tv.item(item, 'values'), + (value,) if self.wantobjects else value) + self.assertEqual(self.tv.item(item, values=None), + (value,) if self.wantobjects else value) - self.tv.item(item, values=list(self.tv.item(item, values=None))) - self.assertEqual(self.tv.item(item, values=None), (value, )) + self.tv.item(item, values=self.root.splitlist(self.tv.item(item, values=None))) + self.assertEqual(self.tv.item(item, values=None), + (value,) if self.wantobjects else value) self.assertIsInstance(self.tv.item(item), dict) @@ -1475,17 +1507,21 @@ # item tags item = self.tv.insert('', 'end', tags=[1, 2, value]) - self.assertEqual(self.tv.item(item, tags=None), ('1', '2', value)) + self.assertEqual(self.tv.item(item, tags=None), + ('1', '2', value) if self.wantobjects else + '1 2 %s' % value) self.tv.item(item, tags=[]) self.assertFalse(self.tv.item(item, tags=None)) self.tv.item(item, tags=(1, 2)) - self.assertEqual(self.tv.item(item, tags=None), ('1', '2')) + self.assertEqual(self.tv.item(item, tags=None), + ('1', '2') if self.wantobjects else '1 2') # values with spaces item = self.tv.insert('', 'end', values=('a b c', '%s %s' % (value, value))) self.assertEqual(self.tv.item(item, values=None), - ('a b c', '%s %s' % (value, value))) + ('a b c', '%s %s' % (value, value)) if self.wantobjects else + '{a b c} {%s %s}' % (value, value)) # text self.assertEqual(self.tv.item( @@ -1502,19 +1538,24 @@ self.assertEqual(self.tv.set(item), {'A': 'a', 'B': 'b'}) self.tv.set(item, 'B', 'a') - self.assertEqual(self.tv.item(item, values=None), ('a', 'a')) + self.assertEqual(self.tv.item(item, values=None), + ('a', 'a') if self.wantobjects else 'a a') self.tv['columns'] = ['B'] self.assertEqual(self.tv.set(item), {'B': 'a'}) self.tv.set(item, 'B', 'b') self.assertEqual(self.tv.set(item, column='B'), 'b') - self.assertEqual(self.tv.item(item, values=None), ('b', 'a')) + self.assertEqual(self.tv.item(item, values=None), + ('b', 'a') if self.wantobjects else 'b a') self.tv.set(item, 'B', 123) - self.assertEqual(self.tv.set(item, 'B'), 123) - self.assertEqual(self.tv.item(item, values=None), (123, 'a')) - self.assertEqual(self.tv.set(item), {'B': 123}) + self.assertEqual(self.tv.set(item, 'B'), + 123 if self.wantobjects else '123') + self.assertEqual(self.tv.item(item, values=None), + (123, 'a') if self.wantobjects else '123 a') + self.assertEqual(self.tv.set(item), + {'B': 123} if self.wantobjects else {'B': '123'}) # inexistent column self.assertRaises(tkinter.TclError, self.tv.set, item, 'A') diff --git a/Lib/tkinter/ttk.py b/Lib/tkinter/ttk.py --- a/Lib/tkinter/ttk.py +++ b/Lib/tkinter/ttk.py @@ -293,6 +293,9 @@ indx += 2 if opt == 'children': + if (tkinter._default_root and + not tkinter._default_root.wantobjects()): + val = tkinter._default_root.splitlist(val) val = _list_from_layouttuple(val) opts[opt] = val @@ -313,6 +316,8 @@ if len(options) % 2: # option specified without a value, return its value return res + if tkinter._default_root: + res = tkinter._default_root.splitlist(res) return _dict_from_tcltuple(res) def _convert_stringval(value): @@ -325,6 +330,14 @@ return value +def _to_number(x): + if isinstance(x, str): + if '.' in x: + x = float(x) + else: + x = int(x) + return x + def tclobjs_to_py(adict): """Returns adict with its values converted from Tcl objects to Python objects.""" @@ -395,8 +408,8 @@ or something else of your preference. A statespec is compound of one or more states and then a value.""" if query_opt is not None: - return _list_from_statespec( - self.tk.call(self._name, "map", style, '-%s' % query_opt)) + return _list_from_statespec(self.tk.splitlist( + self.tk.call(self._name, "map", style, '-%s' % query_opt))) return _dict_from_tcltuple( self.tk.call(self._name, "map", style, *(_format_mapdict(kw)))) @@ -453,8 +466,8 @@ lspec = "null" # could be any other word, but this may make sense # when calling layout(style) later - return _list_from_layouttuple( - self.tk.call(self._name, "layout", style, lspec)) + return _list_from_layouttuple(self.tk.splitlist( + self.tk.call(self._name, "layout", style, lspec))) def element_create(self, elementname, etype, *args, **kw): @@ -466,12 +479,12 @@ def element_names(self): """Returns the list of elements defined in the current theme.""" - return self.tk.call(self._name, "element", "names") + return self.tk.splitlist(self.tk.call(self._name, "element", "names")) def element_options(self, elementname): """Return the list of elementname's options.""" - return self.tk.call(self._name, "element", "options", elementname) + return self.tk.splitlist(self.tk.call(self._name, "element", "options", elementname)) def theme_create(self, themename, parent=None, settings=None): @@ -505,7 +518,7 @@ def theme_names(self): """Returns a list of all known themes.""" - return self.tk.call(self._name, "theme", "names") + return self.tk.splitlist(self.tk.call(self._name, "theme", "names")) def theme_use(self, themename=None): @@ -568,7 +581,8 @@ matches statespec and False otherwise. If callback is specified, then it will be invoked with *args, **kw if the widget state matches statespec. statespec is expected to be a sequence.""" - ret = self.tk.call(self._w, "instate", ' '.join(statespec)) + ret = self.tk.getboolean( + self.tk.call(self._w, "instate", ' '.join(statespec))) if ret and callback: return callback(*args, **kw) @@ -667,7 +681,7 @@ def bbox(self, index): """Return a tuple of (x, y, width, height) which describes the bounding box of the character given by index.""" - return self.tk.call(self._w, "bbox", index) + return self._getints(self.tk.call(self._w, "bbox", index)) def identify(self, x, y): @@ -680,7 +694,7 @@ """Force revalidation, independent of the conditions specified by the validate option. Returns False if validation fails, True if it succeeds. Sets or clears the invalid state accordingly.""" - return bool(self.tk.call(self._w, "validate")) + return bool(self.tk.getboolean(self.tk.call(self._w, "validate"))) class Combobox(Entry): @@ -707,6 +721,8 @@ element at position newindex in the list of values. Otherwise, returns the index of the current value in the list of values or -1 if the current value does not appear in the list.""" + if newindex is None: + return self.tk.getint(self.tk.call(self._w, "current")) return self.tk.call(self._w, "current", newindex) @@ -861,7 +877,7 @@ def index(self, tab_id): """Returns the numeric index of the tab specified by tab_id, or the total number of tabs if tab_id is the string "end".""" - return self.tk.call(self._w, "index", tab_id) + return self.tk.getint(self.tk.call(self._w, "index", tab_id)) def insert(self, pos, child, **kw): @@ -896,7 +912,7 @@ def tabs(self): """Returns a list of windows managed by the notebook.""" - return self.tk.call(self._w, "tabs") or () + return self.tk.splitlist(self.tk.call(self._w, "tabs") or ()) def enable_traversal(self): @@ -979,7 +995,7 @@ constrained to be between 0 and the total size of the widget. Returns the new position of sash number index.""" - return self.tk.call(self._w, "sashpos", index, newpos) + return self.tk.getint(self.tk.call(self._w, "sashpos", index, newpos)) PanedWindow = Panedwindow # tkinter name compatibility @@ -1179,14 +1195,15 @@ If column is specified, returns the bounding box of that cell. If the item is not visible (i.e., if it is a descendant of a closed item or is scrolled offscreen), returns an empty string.""" - return self.tk.call(self._w, "bbox", item, column) + return self._getints(self.tk.call(self._w, "bbox", item, column)) or '' def get_children(self, item=None): """Returns a tuple of children belonging to item. If item is not specified, returns root children.""" - return self.tk.call(self._w, "children", item or '') or () + return self.tk.splitlist( + self.tk.call(self._w, "children", item or '') or ()) def set_children(self, item, *newchildren): @@ -1227,7 +1244,7 @@ def exists(self, item): """Returns True if the specified item is present in the tree, False otherwise.""" - return bool(self.tk.call(self._w, "exists", item)) + return bool(self.tk.getboolean(self.tk.call(self._w, "exists", item))) def focus(self, item=None): @@ -1309,7 +1326,7 @@ def index(self, item): """Returns the integer index of item within its parent's list of children.""" - return self.tk.call(self._w, "index", item) + return self.tk.getint(self.tk.call(self._w, "index", item)) def insert(self, parent, index, iid=None, **kw): @@ -1418,7 +1435,7 @@ value of given column in given item to the specified value.""" res = self.tk.call(self._w, "set", item, column, value) if column is None and value is None: - return _dict_from_tcltuple(res, False) + return _dict_from_tcltuple(self.tk.splitlist(res), False) else: return res @@ -1449,7 +1466,8 @@ all items which have the specified tag. * Availability: Tk 8.6""" - return self.tk.call(self._w, "tag", "has", tagname, item) + return self.tk.getboolean( + self.tk.call(self._w, "tag", "has", tagname, item)) # Extensions @@ -1521,7 +1539,8 @@ self.label.place_configure(x=x, y=y) - from_, to = self.scale['from'], self.scale['to'] + from_ = _to_number(self.scale['from']) + to = _to_number(self.scale['to']) if to < from_: from_, to = to, from_ newval = self._variable.get() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -31,6 +31,8 @@ Library ------- +- Issue #20072: Fixed multiple errors in tkinter with wantobjects is False. + - Issue #20108: Avoid parameter name clash in inspect.getcallargs(). - Issue #12692: Backport the fix for ResourceWarning in test_urllib2net. This -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 7 18:33:31 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 7 Jan 2014 18:33:31 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320072=3A_Fixed_multiple_errors_in_tkinter_with_?= =?utf-8?q?wantobjects_is_False=2E?= Message-ID: <3dzLKR6HFqz7Ljt@mail.python.org> http://hg.python.org/cpython/rev/1628cd94db52 changeset: 88338:1628cd94db52 parent: 88336:e4d98ed54c53 parent: 88337:2d81d0d42ae2 user: Serhiy Storchaka date: Tue Jan 07 19:30:36 2014 +0200 summary: Issue #20072: Fixed multiple errors in tkinter with wantobjects is False. * Misc.image_names(), Misc.image_types(), Wm.wm_colormapwindows(), and LabelFrame.panes() now always return a tuple. * Fixed error of comparing str and int in tt.LabeledScale._adjust(). * ttk.Notebook.index() now always returns int. * ttk.Notebook.tabs() now always returns a tuple. * ttk.Entry.bbox() now always returns a tuple of ints. * ttk.Entry.validate() now always correctly works. * ttk.Combobox.current() now always returns int. * ttk.Panedwindow.sashpos() now always returns int. * ttk.Treeview.bbox() now always returns a tuple of ints. * ttk.Treeview.get_children() now always returns a tuple. * ttk.Treeview.exists() now always correctly works. * ttk.Treeview.index() now always returns int. * ttk.Treeview.tag_has() now always returns 0 or 1. * And numerous other errors in methods which returns a tuple, list or dict. * Fixed ttk tests for wantobjects is False. files: Lib/tkinter/__init__.py | 19 +- Lib/tkinter/test/test_ttk/test_extensions.py | 22 +- Lib/tkinter/test/test_ttk/test_functions.py | 6 +- Lib/tkinter/test/test_ttk/test_style.py | 3 +- Lib/tkinter/test/test_ttk/test_widgets.py | 113 ++++++--- Lib/tkinter/ttk.py | 59 +++- Misc/NEWS | 2 + 7 files changed, 153 insertions(+), 71 deletions(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -1459,11 +1459,11 @@ def image_names(self): """Return a list of all existing image names.""" - return self.tk.call('image', 'names') + return self.tk.splitlist(self.tk.call('image', 'names')) def image_types(self): """Return a list of all available image types (e.g. phote bitmap).""" - return self.tk.call('image', 'types') + return self.tk.splitlist(self.tk.call('image', 'types')) class CallWrapper: @@ -1577,7 +1577,11 @@ if len(wlist) > 1: wlist = (wlist,) # Tk needs a list of windows here args = ('wm', 'colormapwindows', self._w) + wlist - return [self._nametowidget(x) for x in self.tk.call(args)] + if wlist: + self.tk.call(args) + else: + return [self._nametowidget(x) + for x in self.tk.splitlist(self.tk.call(args))] colormapwindows = wm_colormapwindows def wm_command(self, value=None): """Store VALUE in WM_COMMAND property. It is the command @@ -3433,8 +3437,11 @@ Valid resource names: background, data, file, foreground, maskdata, maskfile.""" Image.__init__(self, 'bitmap', name, cnf, master, **kw) -def image_names(): return _default_root.tk.call('image', 'names') -def image_types(): return _default_root.tk.call('image', 'types') +def image_names(): + return _default_root.tk.splitlist(_default_root.tk.call('image', 'names')) + +def image_types(): + return _default_root.tk.splitlist(_default_root.tk.call('image', 'types')) class Spinbox(Widget, XView): @@ -3803,7 +3810,7 @@ def panes(self): """Returns an ordered list of the child panes.""" - return self.tk.call(self._w, 'panes') + return self.tk.splitlist(self.tk.call(self._w, 'panes')) ###################################################################### # Extensions: 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 @@ -29,7 +29,10 @@ name = myvar._name x = ttk.LabeledScale(variable=myvar) x.destroy() - self.assertEqual(x.tk.globalgetvar(name), myvar.get()) + if x.tk.wantobjects(): + self.assertEqual(x.tk.globalgetvar(name), myvar.get()) + else: + self.assertEqual(float(x.tk.globalgetvar(name)), myvar.get()) del myvar self.assertRaises(tkinter.TclError, x.tk.globalgetvar, name) @@ -59,8 +62,10 @@ x.destroy() # variable initialization/passing - passed_expected = ((2.5, 2), ('0', 0), (0, 0), (10, 10), + passed_expected = (('0', 0), (0, 0), (10, 10), (-1, -1), (sys.maxsize + 1, sys.maxsize + 1)) + if x.tk.wantobjects(): + passed_expected += ((2.5, 2),) for pair in passed_expected: x = ttk.LabeledScale(from_=pair[0]) self.assertEqual(x.value, pair[1]) @@ -123,7 +128,7 @@ self.assertNotEqual(prev_xcoord, curr_xcoord) # the label widget should have been repositioned too linfo_2 = lscale.label.place_info() - self.assertEqual(lscale.label['text'], 0) + self.assertEqual(lscale.label['text'], 0 if lscale.tk.wantobjects() else '0') self.assertEqual(curr_xcoord, int(linfo_2['x'])) # change the range back lscale.scale.configure(from_=0, to=10) @@ -145,15 +150,20 @@ # 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.label['text'], newval) + self.assertEqual(x.label['text'], + newval if x.tk.wantobjects() else str(newval)) self.assertGreater(x.scale.coords()[0], curr_xcoord) self.assertEqual(x.scale.coords()[0], int(x.label.place_info()['x'])) # value outside range - x.value = x.scale['to'] + 1 # no changes shouldn't happen + if x.tk.wantobjects(): + conv = lambda x: x + else: + conv = int + x.value = conv(x.scale['to']) + 1 # no changes shouldn't happen x.update() - self.assertEqual(x.label['text'], newval) + self.assertEqual(conv(x.label['text']), newval) self.assertEqual(x.scale.coords()[0], int(x.label.place_info()['x'])) diff --git a/Lib/tkinter/test/test_ttk/test_functions.py b/Lib/tkinter/test/test_ttk/test_functions.py --- a/Lib/tkinter/test/test_ttk/test_functions.py +++ b/Lib/tkinter/test/test_ttk/test_functions.py @@ -393,8 +393,10 @@ ('name', 'no_minus', 'value')) self.assertRaises(ValueError, ttk._list_from_layouttuple, ('something', '-children')) # no children - self.assertRaises(ValueError, ttk._list_from_layouttuple, - ('something', '-children', 'value')) # invalid children + import tkinter + if not tkinter._default_root or tkinter._default_root.wantobjects(): + self.assertRaises(ValueError, ttk._list_from_layouttuple, + ('something', '-children', 'value')) # invalid children def test_val_or_dict(self): diff --git a/Lib/tkinter/test/test_ttk/test_style.py b/Lib/tkinter/test/test_ttk/test_style.py --- a/Lib/tkinter/test/test_ttk/test_style.py +++ b/Lib/tkinter/test/test_ttk/test_style.py @@ -25,7 +25,8 @@ style = self.style style.map('TButton', background=[('active', 'background', 'blue')]) self.assertEqual(style.map('TButton', 'background'), - [('active', 'background', 'blue')]) + [('active', 'background', 'blue')] if style.tk.wantobjects() else + [('active background', 'blue')]) self.assertIsInstance(style.map('TButton'), dict) diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py --- a/Lib/tkinter/test/test_ttk/test_widgets.py +++ b/Lib/tkinter/test/test_ttk/test_widgets.py @@ -382,15 +382,21 @@ # testing values with empty string set through configure self.combo.configure(values=[1, '', 2]) - self.assertEqual(self.combo['values'], ('1', '', '2')) + self.assertEqual(self.combo['values'], + ('1', '', '2') if self.wantobjects else + '1 {} 2') # testing values with spaces self.combo['values'] = ['a b', 'a\tb', 'a\nb'] - self.assertEqual(self.combo['values'], ('a b', 'a\tb', 'a\nb')) + self.assertEqual(self.combo['values'], + ('a b', 'a\tb', 'a\nb') if self.wantobjects else + '{a b} {a\tb} {a\nb}') # testing values with special characters self.combo['values'] = [r'a\tb', '"a"', '} {'] - self.assertEqual(self.combo['values'], (r'a\tb', '"a"', '} {')) + self.assertEqual(self.combo['values'], + (r'a\tb', '"a"', '} {') if self.wantobjects else + r'a\\tb {"a"} \}\ \{') # out of range self.assertRaises(tkinter.TclError, self.combo.current, @@ -400,7 +406,8 @@ # testing creating combobox with empty string in values combo2 = ttk.Combobox(values=[1, 2, '']) - self.assertEqual(combo2['values'], ('1', '2', '')) + self.assertEqual(combo2['values'], + ('1', '2', '') if self.wantobjects else '1 2 {}') combo2.destroy() @@ -654,9 +661,11 @@ child = ttk.Label() self.paned.add(child) self.assertIsInstance(self.paned.pane(0), dict) - self.assertEqual(self.paned.pane(0, weight=None), 0) + self.assertEqual(self.paned.pane(0, weight=None), + 0 if self.wantobjects else '0') # newer form for querying a single option - self.assertEqual(self.paned.pane(0, 'weight'), 0) + self.assertEqual(self.paned.pane(0, 'weight'), + 0 if self.wantobjects else '0') self.assertEqual(self.paned.pane(0), self.paned.pane(str(child))) self.assertRaises(tkinter.TclError, self.paned.pane, 0, @@ -711,20 +720,25 @@ cbtn = ttk.Radiobutton(command=cb_test, variable=myvar, value=0) cbtn2 = ttk.Radiobutton(command=cb_test, variable=myvar, value=1) + if self.wantobjects: + conv = lambda x: x + else: + conv = int + res = cbtn.invoke() self.assertEqual(res, "cb test called") - self.assertEqual(cbtn['value'], myvar.get()) + self.assertEqual(conv(cbtn['value']), myvar.get()) self.assertEqual(myvar.get(), - cbtn.tk.globalgetvar(cbtn['variable'])) + conv(cbtn.tk.globalgetvar(cbtn['variable']))) self.assertTrue(success) cbtn2['command'] = '' res = cbtn2.invoke() self.assertEqual(str(res), '') self.assertLessEqual(len(success), 1) - self.assertEqual(cbtn2['value'], myvar.get()) + self.assertEqual(conv(cbtn2['value']), myvar.get()) self.assertEqual(myvar.get(), - cbtn.tk.globalgetvar(cbtn['variable'])) + conv(cbtn.tk.globalgetvar(cbtn['variable']))) self.assertEqual(str(cbtn['variable']), str(cbtn2['variable'])) @@ -812,10 +826,15 @@ def test_get(self): + if self.wantobjects: + conv = lambda x: x + else: + conv = float + scale_width = self.scale.winfo_width() self.assertEqual(self.scale.get(scale_width, 0), self.scale['to']) - self.assertEqual(self.scale.get(0, 0), self.scale['from']) + self.assertEqual(conv(self.scale.get(0, 0)), conv(self.scale['from'])) self.assertEqual(self.scale.get(), self.scale['value']) self.scale['value'] = 30 self.assertEqual(self.scale.get(), self.scale['value']) @@ -825,32 +844,37 @@ def test_set(self): + if self.wantobjects: + conv = lambda x: x + else: + conv = float + # set restricts the max/min values according to the current range - max = self.scale['to'] + max = conv(self.scale['to']) new_max = max + 10 self.scale.set(new_max) - self.assertEqual(self.scale.get(), max) - min = self.scale['from'] + self.assertEqual(conv(self.scale.get()), max) + min = conv(self.scale['from']) self.scale.set(min - 1) - self.assertEqual(self.scale.get(), min) + self.assertEqual(conv(self.scale.get()), min) # changing directly the variable doesn't impose this limitation tho var = tkinter.DoubleVar() self.scale['variable'] = var var.set(max + 5) - self.assertEqual(self.scale.get(), var.get()) - self.assertEqual(self.scale.get(), max + 5) + self.assertEqual(conv(self.scale.get()), var.get()) + self.assertEqual(conv(self.scale.get()), max + 5) del var # the same happens with the value option self.scale['value'] = max + 10 - self.assertEqual(self.scale.get(), max + 10) - self.assertEqual(self.scale.get(), self.scale['value']) + self.assertEqual(conv(self.scale.get()), max + 10) + self.assertEqual(conv(self.scale.get()), conv(self.scale['value'])) # nevertheless, note that the max/min values we can get specifying # x, y coords are the ones according to the current range - self.assertEqual(self.scale.get(0, 0), min) - self.assertEqual(self.scale.get(self.scale.winfo_width(), 0), max) + self.assertEqual(conv(self.scale.get(0, 0)), min) + self.assertEqual(conv(self.scale.get(self.scale.winfo_width(), 0)), max) self.assertRaises(tkinter.TclError, self.scale.set, None) @@ -1204,6 +1228,8 @@ self.tv.column('test', width=50) bbox_column0 = self.tv.bbox(children[0], 0) root_width = self.tv.column('#0', width=None) + if not self.wantobjects: + root_width = int(root_width) self.assertEqual(bbox_column0[0], bbox[0] + root_width) # verify that bbox of a closed item is the empty string @@ -1243,12 +1269,15 @@ # return a dict with all options/values self.assertIsInstance(self.tv.column('#0'), dict) # return a single value of the given option - self.assertIsInstance(self.tv.column('#0', width=None), int) + if self.wantobjects: + self.assertIsInstance(self.tv.column('#0', width=None), int) # set a new value for an option self.tv.column('#0', width=10) # testing new way to get option value - self.assertEqual(self.tv.column('#0', 'width'), 10) - self.assertEqual(self.tv.column('#0', width=None), 10) + self.assertEqual(self.tv.column('#0', 'width'), + 10 if self.wantobjects else '10') + self.assertEqual(self.tv.column('#0', width=None), + 10 if self.wantobjects else '10') # check read-only option self.assertRaises(tkinter.TclError, self.tv.column, '#0', id='X') @@ -1461,11 +1490,14 @@ # unicode values value = '\xe1ba' item = self.tv.insert('', 'end', values=(value, )) - self.assertEqual(self.tv.item(item, 'values'), (value, )) - self.assertEqual(self.tv.item(item, values=None), (value, )) + self.assertEqual(self.tv.item(item, 'values'), + (value,) if self.wantobjects else value) + self.assertEqual(self.tv.item(item, values=None), + (value,) if self.wantobjects else value) - self.tv.item(item, values=list(self.tv.item(item, values=None))) - self.assertEqual(self.tv.item(item, values=None), (value, )) + self.tv.item(item, values=self.root.splitlist(self.tv.item(item, values=None))) + self.assertEqual(self.tv.item(item, values=None), + (value,) if self.wantobjects else value) self.assertIsInstance(self.tv.item(item), dict) @@ -1475,17 +1507,21 @@ # item tags item = self.tv.insert('', 'end', tags=[1, 2, value]) - self.assertEqual(self.tv.item(item, tags=None), ('1', '2', value)) + self.assertEqual(self.tv.item(item, tags=None), + ('1', '2', value) if self.wantobjects else + '1 2 %s' % value) self.tv.item(item, tags=[]) self.assertFalse(self.tv.item(item, tags=None)) self.tv.item(item, tags=(1, 2)) - self.assertEqual(self.tv.item(item, tags=None), ('1', '2')) + self.assertEqual(self.tv.item(item, tags=None), + ('1', '2') if self.wantobjects else '1 2') # values with spaces item = self.tv.insert('', 'end', values=('a b c', '%s %s' % (value, value))) self.assertEqual(self.tv.item(item, values=None), - ('a b c', '%s %s' % (value, value))) + ('a b c', '%s %s' % (value, value)) if self.wantobjects else + '{a b c} {%s %s}' % (value, value)) # text self.assertEqual(self.tv.item( @@ -1502,19 +1538,24 @@ self.assertEqual(self.tv.set(item), {'A': 'a', 'B': 'b'}) self.tv.set(item, 'B', 'a') - self.assertEqual(self.tv.item(item, values=None), ('a', 'a')) + self.assertEqual(self.tv.item(item, values=None), + ('a', 'a') if self.wantobjects else 'a a') self.tv['columns'] = ['B'] self.assertEqual(self.tv.set(item), {'B': 'a'}) self.tv.set(item, 'B', 'b') self.assertEqual(self.tv.set(item, column='B'), 'b') - self.assertEqual(self.tv.item(item, values=None), ('b', 'a')) + self.assertEqual(self.tv.item(item, values=None), + ('b', 'a') if self.wantobjects else 'b a') self.tv.set(item, 'B', 123) - self.assertEqual(self.tv.set(item, 'B'), 123) - self.assertEqual(self.tv.item(item, values=None), (123, 'a')) - self.assertEqual(self.tv.set(item), {'B': 123}) + self.assertEqual(self.tv.set(item, 'B'), + 123 if self.wantobjects else '123') + self.assertEqual(self.tv.item(item, values=None), + (123, 'a') if self.wantobjects else '123 a') + self.assertEqual(self.tv.set(item), + {'B': 123} if self.wantobjects else {'B': '123'}) # inexistent column self.assertRaises(tkinter.TclError, self.tv.set, item, 'A') diff --git a/Lib/tkinter/ttk.py b/Lib/tkinter/ttk.py --- a/Lib/tkinter/ttk.py +++ b/Lib/tkinter/ttk.py @@ -293,6 +293,9 @@ indx += 2 if opt == 'children': + if (tkinter._default_root and + not tkinter._default_root.wantobjects()): + val = tkinter._default_root.splitlist(val) val = _list_from_layouttuple(val) opts[opt] = val @@ -313,6 +316,8 @@ if len(options) % 2: # option specified without a value, return its value return res + if tkinter._default_root: + res = tkinter._default_root.splitlist(res) return _dict_from_tcltuple(res) def _convert_stringval(value): @@ -325,6 +330,14 @@ return value +def _to_number(x): + if isinstance(x, str): + if '.' in x: + x = float(x) + else: + x = int(x) + return x + def tclobjs_to_py(adict): """Returns adict with its values converted from Tcl objects to Python objects.""" @@ -395,8 +408,8 @@ or something else of your preference. A statespec is compound of one or more states and then a value.""" if query_opt is not None: - return _list_from_statespec( - self.tk.call(self._name, "map", style, '-%s' % query_opt)) + return _list_from_statespec(self.tk.splitlist( + self.tk.call(self._name, "map", style, '-%s' % query_opt))) return _dict_from_tcltuple( self.tk.call(self._name, "map", style, *(_format_mapdict(kw)))) @@ -453,8 +466,8 @@ lspec = "null" # could be any other word, but this may make sense # when calling layout(style) later - return _list_from_layouttuple( - self.tk.call(self._name, "layout", style, lspec)) + return _list_from_layouttuple(self.tk.splitlist( + self.tk.call(self._name, "layout", style, lspec))) def element_create(self, elementname, etype, *args, **kw): @@ -466,12 +479,12 @@ def element_names(self): """Returns the list of elements defined in the current theme.""" - return self.tk.call(self._name, "element", "names") + return self.tk.splitlist(self.tk.call(self._name, "element", "names")) def element_options(self, elementname): """Return the list of elementname's options.""" - return self.tk.call(self._name, "element", "options", elementname) + return self.tk.splitlist(self.tk.call(self._name, "element", "options", elementname)) def theme_create(self, themename, parent=None, settings=None): @@ -505,7 +518,7 @@ def theme_names(self): """Returns a list of all known themes.""" - return self.tk.call(self._name, "theme", "names") + return self.tk.splitlist(self.tk.call(self._name, "theme", "names")) def theme_use(self, themename=None): @@ -568,7 +581,8 @@ matches statespec and False otherwise. If callback is specified, then it will be invoked with *args, **kw if the widget state matches statespec. statespec is expected to be a sequence.""" - ret = self.tk.call(self._w, "instate", ' '.join(statespec)) + ret = self.tk.getboolean( + self.tk.call(self._w, "instate", ' '.join(statespec))) if ret and callback: return callback(*args, **kw) @@ -667,7 +681,7 @@ def bbox(self, index): """Return a tuple of (x, y, width, height) which describes the bounding box of the character given by index.""" - return self.tk.call(self._w, "bbox", index) + return self._getints(self.tk.call(self._w, "bbox", index)) def identify(self, x, y): @@ -680,7 +694,7 @@ """Force revalidation, independent of the conditions specified by the validate option. Returns False if validation fails, True if it succeeds. Sets or clears the invalid state accordingly.""" - return bool(self.tk.call(self._w, "validate")) + return bool(self.tk.getboolean(self.tk.call(self._w, "validate"))) class Combobox(Entry): @@ -707,6 +721,8 @@ element at position newindex in the list of values. Otherwise, returns the index of the current value in the list of values or -1 if the current value does not appear in the list.""" + if newindex is None: + return self.tk.getint(self.tk.call(self._w, "current")) return self.tk.call(self._w, "current", newindex) @@ -861,7 +877,7 @@ def index(self, tab_id): """Returns the numeric index of the tab specified by tab_id, or the total number of tabs if tab_id is the string "end".""" - return self.tk.call(self._w, "index", tab_id) + return self.tk.getint(self.tk.call(self._w, "index", tab_id)) def insert(self, pos, child, **kw): @@ -896,7 +912,7 @@ def tabs(self): """Returns a list of windows managed by the notebook.""" - return self.tk.call(self._w, "tabs") or () + return self.tk.splitlist(self.tk.call(self._w, "tabs") or ()) def enable_traversal(self): @@ -979,7 +995,7 @@ constrained to be between 0 and the total size of the widget. Returns the new position of sash number index.""" - return self.tk.call(self._w, "sashpos", index, newpos) + return self.tk.getint(self.tk.call(self._w, "sashpos", index, newpos)) PanedWindow = Panedwindow # tkinter name compatibility @@ -1179,14 +1195,15 @@ If column is specified, returns the bounding box of that cell. If the item is not visible (i.e., if it is a descendant of a closed item or is scrolled offscreen), returns an empty string.""" - return self.tk.call(self._w, "bbox", item, column) + return self._getints(self.tk.call(self._w, "bbox", item, column)) or '' def get_children(self, item=None): """Returns a tuple of children belonging to item. If item is not specified, returns root children.""" - return self.tk.call(self._w, "children", item or '') or () + return self.tk.splitlist( + self.tk.call(self._w, "children", item or '') or ()) def set_children(self, item, *newchildren): @@ -1227,7 +1244,7 @@ def exists(self, item): """Returns True if the specified item is present in the tree, False otherwise.""" - return bool(self.tk.call(self._w, "exists", item)) + return bool(self.tk.getboolean(self.tk.call(self._w, "exists", item))) def focus(self, item=None): @@ -1309,7 +1326,7 @@ def index(self, item): """Returns the integer index of item within its parent's list of children.""" - return self.tk.call(self._w, "index", item) + return self.tk.getint(self.tk.call(self._w, "index", item)) def insert(self, parent, index, iid=None, **kw): @@ -1418,7 +1435,7 @@ value of given column in given item to the specified value.""" res = self.tk.call(self._w, "set", item, column, value) if column is None and value is None: - return _dict_from_tcltuple(res, False) + return _dict_from_tcltuple(self.tk.splitlist(res), False) else: return res @@ -1449,7 +1466,8 @@ all items which have the specified tag. * Availability: Tk 8.6""" - return self.tk.call(self._w, "tag", "has", tagname, item) + return self.tk.getboolean( + self.tk.call(self._w, "tag", "has", tagname, item)) # Extensions @@ -1521,7 +1539,8 @@ self.label.place_configure(x=x, y=y) - from_, to = self.scale['from'], self.scale['to'] + from_ = _to_number(self.scale['from']) + to = _to_number(self.scale['to']) if to < from_: from_, to = to, from_ newval = self._variable.get() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,8 @@ Library ------- +- Issue #20072: Fixed multiple errors in tkinter with wantobjects is False. + Tools/Demos ----------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 7 18:33:33 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 7 Jan 2014 18:33:33 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIwMDcy?= =?utf-8?q?=3A_Fixed_multiple_errors_in_tkinter_with_wantobjects_is_False?= =?utf-8?q?=2E?= Message-ID: <3dzLKT3w60z7LkQ@mail.python.org> http://hg.python.org/cpython/rev/89b3836f7378 changeset: 88339:89b3836f7378 branch: 2.7 parent: 88334:e09644eb6b20 user: Serhiy Storchaka date: Tue Jan 07 19:32:58 2014 +0200 summary: Issue #20072: Fixed multiple errors in tkinter with wantobjects is False. * Misc.image_names(), Misc.image_types(), Wm.wm_colormapwindows(), and LabelFrame.panes() now always return a tuple. * Fixed _stringify() for non-ASCII strings. * Fixed error of comparing str and int in tt.LabeledScale._adjust(). * ttk.Notebook.index() now always returns int. * ttk.Notebook.tabs() now always returns a tuple. * ttk.Entry.bbox() now always returns a tuple of ints. * ttk.Entry.validate() now always correctly works. * ttk.Combobox.current() now always returns int. * ttk.Panedwindow.sashpos() now always returns int. * ttk.Treeview.bbox() now always returns a tuple of ints. * ttk.Treeview.get_children() now always returns a tuple. * ttk.Treeview.exists() now always correctly works. * ttk.Treeview.index() now always returns int. * ttk.Treeview.tag_has() now always returns 0 or 1. * And numerous other errors in methods which returns a tuple, list or dict. * Fixed ttk tests for wantobjects is False. files: Lib/lib-tk/Tkinter.py | 24 +- Lib/lib-tk/test/test_ttk/test_extensions.py | 22 +- Lib/lib-tk/test/test_ttk/test_functions.py | 6 +- Lib/lib-tk/test/test_ttk/test_style.py | 3 +- Lib/lib-tk/test/test_ttk/test_widgets.py | 115 ++++++--- Lib/lib-tk/ttk.py | 59 +++- Misc/NEWS | 2 + 7 files changed, 156 insertions(+), 75 deletions(-) diff --git a/Lib/lib-tk/Tkinter.py b/Lib/lib-tk/Tkinter.py --- a/Lib/lib-tk/Tkinter.py +++ b/Lib/lib-tk/Tkinter.py @@ -76,9 +76,9 @@ else: value = '{%s}' % _join(value) else: - if isinstance(value, basestring): - value = unicode(value) - else: + if isinstance(value, str): + value = unicode(value, 'utf-8') + elif not isinstance(value, unicode): value = str(value) if not value: value = '{}' @@ -1456,11 +1456,11 @@ def image_names(self): """Return a list of all existing image names.""" - return self.tk.call('image', 'names') + return self.tk.splitlist(self.tk.call('image', 'names')) def image_types(self): """Return a list of all available image types (e.g. phote bitmap).""" - return self.tk.call('image', 'types') + return self.tk.splitlist(self.tk.call('image', 'types')) class CallWrapper: @@ -1574,7 +1574,10 @@ if len(wlist) > 1: wlist = (wlist,) # Tk needs a list of windows here args = ('wm', 'colormapwindows', self._w) + wlist - return map(self._nametowidget, self.tk.call(args)) + if wlist: + self.tk.call(args) + else: + return map(self._nametowidget, self.tk.splitlist(self.tk.call(args))) colormapwindows = wm_colormapwindows def wm_command(self, value=None): """Store VALUE in WM_COMMAND property. It is the command @@ -3374,8 +3377,11 @@ Valid resource names: background, data, file, foreground, maskdata, maskfile.""" Image.__init__(self, 'bitmap', name, cnf, master, **kw) -def image_names(): return _default_root.tk.call('image', 'names') -def image_types(): return _default_root.tk.call('image', 'types') +def image_names(): + return _default_root.tk.splitlist(_default_root.tk.call('image', 'names')) + +def image_types(): + return _default_root.tk.splitlist(_default_root.tk.call('image', 'types')) class Spinbox(Widget, XView): @@ -3744,7 +3750,7 @@ def panes(self): """Returns an ordered list of the child panes.""" - return self.tk.call(self._w, 'panes') + return self.tk.splitlist(self.tk.call(self._w, 'panes')) ###################################################################### # Extensions: diff --git a/Lib/lib-tk/test/test_ttk/test_extensions.py b/Lib/lib-tk/test/test_ttk/test_extensions.py --- a/Lib/lib-tk/test/test_ttk/test_extensions.py +++ b/Lib/lib-tk/test/test_ttk/test_extensions.py @@ -29,7 +29,10 @@ name = myvar._name x = ttk.LabeledScale(variable=myvar) x.destroy() - self.assertEqual(x.tk.globalgetvar(name), myvar.get()) + if x.tk.wantobjects(): + self.assertEqual(x.tk.globalgetvar(name), myvar.get()) + else: + self.assertEqual(float(x.tk.globalgetvar(name)), myvar.get()) del myvar self.assertRaises(Tkinter.TclError, x.tk.globalgetvar, name) @@ -59,8 +62,10 @@ x.destroy() # variable initialization/passing - passed_expected = ((2.5, 2), ('0', 0), (0, 0), (10, 10), + passed_expected = (('0', 0), (0, 0), (10, 10), (-1, -1), (sys.maxint + 1, sys.maxint + 1)) + if x.tk.wantobjects(): + passed_expected += ((2.5, 2),) for pair in passed_expected: x = ttk.LabeledScale(from_=pair[0]) self.assertEqual(x.value, pair[1]) @@ -123,7 +128,7 @@ self.assertNotEqual(prev_xcoord, curr_xcoord) # the label widget should have been repositioned too linfo_2 = lscale.label.place_info() - self.assertEqual(lscale.label['text'], 0) + self.assertEqual(lscale.label['text'], 0 if lscale.tk.wantobjects() else '0') self.assertEqual(curr_xcoord, int(linfo_2['x'])) # change the range back lscale.scale.configure(from_=0, to=10) @@ -145,15 +150,20 @@ # 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.label['text'], newval) + self.assertEqual(x.label['text'], + newval if x.tk.wantobjects() else str(newval)) self.assertGreater(x.scale.coords()[0], curr_xcoord) self.assertEqual(x.scale.coords()[0], int(x.label.place_info()['x'])) # value outside range - x.value = x.scale['to'] + 1 # no changes shouldn't happen + if x.tk.wantobjects(): + conv = lambda x: x + else: + conv = int + x.value = conv(x.scale['to']) + 1 # no changes shouldn't happen x.update() - self.assertEqual(x.label['text'], newval) + self.assertEqual(conv(x.label['text']), newval) self.assertEqual(x.scale.coords()[0], int(x.label.place_info()['x'])) diff --git a/Lib/lib-tk/test/test_ttk/test_functions.py b/Lib/lib-tk/test/test_ttk/test_functions.py --- a/Lib/lib-tk/test/test_ttk/test_functions.py +++ b/Lib/lib-tk/test/test_ttk/test_functions.py @@ -394,8 +394,10 @@ ('name', 'no_minus', 'value')) self.assertRaises(ValueError, ttk._list_from_layouttuple, ('something', '-children')) # no children - self.assertRaises(ValueError, ttk._list_from_layouttuple, - ('something', '-children', 'value')) # invalid children + import Tkinter + if not Tkinter._default_root or Tkinter._default_root.wantobjects(): + self.assertRaises(ValueError, ttk._list_from_layouttuple, + ('something', '-children', 'value')) # invalid children def test_val_or_dict(self): diff --git a/Lib/lib-tk/test/test_ttk/test_style.py b/Lib/lib-tk/test/test_ttk/test_style.py --- a/Lib/lib-tk/test/test_ttk/test_style.py +++ b/Lib/lib-tk/test/test_ttk/test_style.py @@ -25,7 +25,8 @@ style = self.style style.map('TButton', background=[('active', 'background', 'blue')]) self.assertEqual(style.map('TButton', 'background'), - [('active', 'background', 'blue')]) + [('active', 'background', 'blue')] if style.tk.wantobjects() else + [('active background', 'blue')]) self.assertIsInstance(style.map('TButton'), dict) diff --git a/Lib/lib-tk/test/test_ttk/test_widgets.py b/Lib/lib-tk/test/test_ttk/test_widgets.py --- a/Lib/lib-tk/test/test_ttk/test_widgets.py +++ b/Lib/lib-tk/test/test_ttk/test_widgets.py @@ -21,7 +21,7 @@ widget = self.create() self.assertEqual(widget['class'], '') errmsg='attempt to change read-only option' - if tcl_version < (8, 6): + if tcl_version < (8, 6, 0): # actually this was changen in 8.6b3 errmsg='Attempt to change read-only option' self.checkInvalidParam(widget, 'class', 'Foo', errmsg=errmsg) widget2 = self.create(class_='Foo') @@ -383,15 +383,21 @@ # testing values with empty string set through configure self.combo.configure(values=[1, '', 2]) - self.assertEqual(self.combo['values'], ('1', '', '2')) + self.assertEqual(self.combo['values'], + ('1', '', '2') if self.wantobjects else + '1 {} 2') # testing values with spaces self.combo['values'] = ['a b', 'a\tb', 'a\nb'] - self.assertEqual(self.combo['values'], ('a b', 'a\tb', 'a\nb')) + self.assertEqual(self.combo['values'], + ('a b', 'a\tb', 'a\nb') if self.wantobjects else + '{a b} {a\tb} {a\nb}') # testing values with special characters self.combo['values'] = [r'a\tb', '"a"', '} {'] - self.assertEqual(self.combo['values'], (r'a\tb', '"a"', '} {')) + self.assertEqual(self.combo['values'], + (r'a\tb', '"a"', '} {') if self.wantobjects else + r'a\\tb {"a"} \}\ \{') # out of range self.assertRaises(Tkinter.TclError, self.combo.current, @@ -401,7 +407,8 @@ # testing creating combobox with empty string in values combo2 = ttk.Combobox(values=[1, 2, '']) - self.assertEqual(combo2['values'], ('1', '2', '')) + self.assertEqual(combo2['values'], + ('1', '2', '') if self.wantobjects else '1 2 {}') combo2.destroy() @@ -655,9 +662,11 @@ child = ttk.Label() self.paned.add(child) self.assertIsInstance(self.paned.pane(0), dict) - self.assertEqual(self.paned.pane(0, weight=None), 0) + self.assertEqual(self.paned.pane(0, weight=None), + 0 if self.wantobjects else '0') # newer form for querying a single option - self.assertEqual(self.paned.pane(0, 'weight'), 0) + self.assertEqual(self.paned.pane(0, 'weight'), + 0 if self.wantobjects else '0') self.assertEqual(self.paned.pane(0), self.paned.pane(str(child))) self.assertRaises(Tkinter.TclError, self.paned.pane, 0, @@ -712,20 +721,25 @@ cbtn = ttk.Radiobutton(command=cb_test, variable=myvar, value=0) cbtn2 = ttk.Radiobutton(command=cb_test, variable=myvar, value=1) + if self.wantobjects: + conv = lambda x: x + else: + conv = int + res = cbtn.invoke() self.assertEqual(res, "cb test called") - self.assertEqual(cbtn['value'], myvar.get()) + self.assertEqual(conv(cbtn['value']), myvar.get()) self.assertEqual(myvar.get(), - cbtn.tk.globalgetvar(cbtn['variable'])) + conv(cbtn.tk.globalgetvar(cbtn['variable']))) self.assertTrue(success) cbtn2['command'] = '' res = cbtn2.invoke() self.assertEqual(str(res), '') self.assertLessEqual(len(success), 1) - self.assertEqual(cbtn2['value'], myvar.get()) + self.assertEqual(conv(cbtn2['value']), myvar.get()) self.assertEqual(myvar.get(), - cbtn.tk.globalgetvar(cbtn['variable'])) + conv(cbtn.tk.globalgetvar(cbtn['variable']))) self.assertEqual(str(cbtn['variable']), str(cbtn2['variable'])) @@ -813,10 +827,15 @@ def test_get(self): + if self.wantobjects: + conv = lambda x: x + else: + conv = float + scale_width = self.scale.winfo_width() self.assertEqual(self.scale.get(scale_width, 0), self.scale['to']) - self.assertEqual(self.scale.get(0, 0), self.scale['from']) + self.assertEqual(conv(self.scale.get(0, 0)), conv(self.scale['from'])) self.assertEqual(self.scale.get(), self.scale['value']) self.scale['value'] = 30 self.assertEqual(self.scale.get(), self.scale['value']) @@ -826,32 +845,37 @@ def test_set(self): + if self.wantobjects: + conv = lambda x: x + else: + conv = float + # set restricts the max/min values according to the current range - max = self.scale['to'] + max = conv(self.scale['to']) new_max = max + 10 self.scale.set(new_max) - self.assertEqual(self.scale.get(), max) - min = self.scale['from'] + self.assertEqual(conv(self.scale.get()), max) + min = conv(self.scale['from']) self.scale.set(min - 1) - self.assertEqual(self.scale.get(), min) + self.assertEqual(conv(self.scale.get()), min) # changing directly the variable doesn't impose this limitation tho var = Tkinter.DoubleVar() self.scale['variable'] = var var.set(max + 5) - self.assertEqual(self.scale.get(), var.get()) - self.assertEqual(self.scale.get(), max + 5) + self.assertEqual(conv(self.scale.get()), var.get()) + self.assertEqual(conv(self.scale.get()), max + 5) del var # the same happens with the value option self.scale['value'] = max + 10 - self.assertEqual(self.scale.get(), max + 10) - self.assertEqual(self.scale.get(), self.scale['value']) + self.assertEqual(conv(self.scale.get()), max + 10) + self.assertEqual(conv(self.scale.get()), conv(self.scale['value'])) # nevertheless, note that the max/min values we can get specifying # x, y coords are the ones according to the current range - self.assertEqual(self.scale.get(0, 0), min) - self.assertEqual(self.scale.get(self.scale.winfo_width(), 0), max) + self.assertEqual(conv(self.scale.get(0, 0)), min) + self.assertEqual(conv(self.scale.get(self.scale.winfo_width(), 0)), max) self.assertRaises(Tkinter.TclError, self.scale.set, None) @@ -1205,6 +1229,8 @@ self.tv.column('test', width=50) bbox_column0 = self.tv.bbox(children[0], 0) root_width = self.tv.column('#0', width=None) + if not self.wantobjects: + root_width = int(root_width) self.assertEqual(bbox_column0[0], bbox[0] + root_width) # verify that bbox of a closed item is the empty string @@ -1244,12 +1270,15 @@ # return a dict with all options/values self.assertIsInstance(self.tv.column('#0'), dict) # return a single value of the given option - self.assertIsInstance(self.tv.column('#0', width=None), int) + if self.wantobjects: + self.assertIsInstance(self.tv.column('#0', width=None), int) # set a new value for an option self.tv.column('#0', width=10) # testing new way to get option value - self.assertEqual(self.tv.column('#0', 'width'), 10) - self.assertEqual(self.tv.column('#0', width=None), 10) + self.assertEqual(self.tv.column('#0', 'width'), + 10 if self.wantobjects else '10') + self.assertEqual(self.tv.column('#0', width=None), + 10 if self.wantobjects else '10') # check read-only option self.assertRaises(Tkinter.TclError, self.tv.column, '#0', id='X') @@ -1462,11 +1491,14 @@ # unicode values value = u'\xe1ba' item = self.tv.insert('', 'end', values=(value, )) - self.assertEqual(self.tv.item(item, 'values'), (value, )) - self.assertEqual(self.tv.item(item, values=None), (value, )) + self.assertEqual(self.tv.item(item, 'values'), + (value,) if self.wantobjects else value) + self.assertEqual(self.tv.item(item, values=None), + (value,) if self.wantobjects else value) - self.tv.item(item, values=list(self.tv.item(item, values=None))) - self.assertEqual(self.tv.item(item, values=None), (value, )) + self.tv.item(item, values=self.root.splitlist(self.tv.item(item, values=None))) + self.assertEqual(self.tv.item(item, values=None), + (value,) if self.wantobjects else value) self.assertIsInstance(self.tv.item(item), dict) @@ -1476,17 +1508,21 @@ # item tags item = self.tv.insert('', 'end', tags=[1, 2, value]) - self.assertEqual(self.tv.item(item, tags=None), ('1', '2', value)) + self.assertEqual(self.tv.item(item, tags=None), + ('1', '2', value) if self.wantobjects else + '1 2 %s' % value) self.tv.item(item, tags=[]) self.assertFalse(self.tv.item(item, tags=None)) self.tv.item(item, tags=(1, 2)) - self.assertEqual(self.tv.item(item, tags=None), ('1', '2')) + self.assertEqual(self.tv.item(item, tags=None), + ('1', '2') if self.wantobjects else '1 2') # values with spaces item = self.tv.insert('', 'end', values=('a b c', '%s %s' % (value, value))) self.assertEqual(self.tv.item(item, values=None), - ('a b c', '%s %s' % (value, value))) + ('a b c', '%s %s' % (value, value)) if self.wantobjects else + '{a b c} {%s %s}' % (value, value)) # text self.assertEqual(self.tv.item( @@ -1503,19 +1539,24 @@ self.assertEqual(self.tv.set(item), {'A': 'a', 'B': 'b'}) self.tv.set(item, 'B', 'a') - self.assertEqual(self.tv.item(item, values=None), ('a', 'a')) + self.assertEqual(self.tv.item(item, values=None), + ('a', 'a') if self.wantobjects else 'a a') self.tv['columns'] = ['B'] self.assertEqual(self.tv.set(item), {'B': 'a'}) self.tv.set(item, 'B', 'b') self.assertEqual(self.tv.set(item, column='B'), 'b') - self.assertEqual(self.tv.item(item, values=None), ('b', 'a')) + self.assertEqual(self.tv.item(item, values=None), + ('b', 'a') if self.wantobjects else 'b a') self.tv.set(item, 'B', 123) - self.assertEqual(self.tv.set(item, 'B'), 123) - self.assertEqual(self.tv.item(item, values=None), (123, 'a')) - self.assertEqual(self.tv.set(item), {'B': 123}) + self.assertEqual(self.tv.set(item, 'B'), + 123 if self.wantobjects else '123') + self.assertEqual(self.tv.item(item, values=None), + (123, 'a') if self.wantobjects else '123 a') + self.assertEqual(self.tv.set(item), + {'B': 123} if self.wantobjects else {'B': '123'}) # inexistent column self.assertRaises(Tkinter.TclError, self.tv.set, item, 'A') diff --git a/Lib/lib-tk/ttk.py b/Lib/lib-tk/ttk.py --- a/Lib/lib-tk/ttk.py +++ b/Lib/lib-tk/ttk.py @@ -295,6 +295,9 @@ indx += 2 if opt == 'children': + if (Tkinter._default_root and + not Tkinter._default_root.wantobjects()): + val = Tkinter._default_root.splitlist(val) val = _list_from_layouttuple(val) opts[opt] = val @@ -315,6 +318,8 @@ if len(options) % 2: # option specified without a value, return its value return res + if Tkinter._default_root: + res = Tkinter._default_root.splitlist(res) return _dict_from_tcltuple(res) def _convert_stringval(value): @@ -327,6 +332,14 @@ return value +def _to_number(x): + if isinstance(x, str): + if '.' in x: + x = float(x) + else: + x = int(x) + return x + def tclobjs_to_py(adict): """Returns adict with its values converted from Tcl objects to Python objects.""" @@ -397,8 +410,8 @@ or something else of your preference. A statespec is compound of one or more states and then a value.""" if query_opt is not None: - return _list_from_statespec( - self.tk.call(self._name, "map", style, '-%s' % query_opt)) + return _list_from_statespec(self.tk.splitlist( + self.tk.call(self._name, "map", style, '-%s' % query_opt))) return _dict_from_tcltuple( self.tk.call(self._name, "map", style, *(_format_mapdict(kw)))) @@ -455,8 +468,8 @@ lspec = "null" # could be any other word, but this may make sense # when calling layout(style) later - return _list_from_layouttuple( - self.tk.call(self._name, "layout", style, lspec)) + return _list_from_layouttuple(self.tk.splitlist( + self.tk.call(self._name, "layout", style, lspec))) def element_create(self, elementname, etype, *args, **kw): @@ -468,12 +481,12 @@ def element_names(self): """Returns the list of elements defined in the current theme.""" - return self.tk.call(self._name, "element", "names") + return self.tk.splitlist(self.tk.call(self._name, "element", "names")) def element_options(self, elementname): """Return the list of elementname's options.""" - return self.tk.call(self._name, "element", "options", elementname) + return self.tk.splitlist(self.tk.call(self._name, "element", "options", elementname)) def theme_create(self, themename, parent=None, settings=None): @@ -507,7 +520,7 @@ def theme_names(self): """Returns a list of all known themes.""" - return self.tk.call(self._name, "theme", "names") + return self.tk.splitlist(self.tk.call(self._name, "theme", "names")) def theme_use(self, themename=None): @@ -570,7 +583,8 @@ matches statespec and False otherwise. If callback is specified, then it will be invoked with *args, **kw if the widget state matches statespec. statespec is expected to be a sequence.""" - ret = self.tk.call(self._w, "instate", ' '.join(statespec)) + ret = self.tk.getboolean( + self.tk.call(self._w, "instate", ' '.join(statespec))) if ret and callback: return callback(*args, **kw) @@ -669,7 +683,7 @@ def bbox(self, index): """Return a tuple of (x, y, width, height) which describes the bounding box of the character given by index.""" - return self.tk.call(self._w, "bbox", index) + return self._getints(self.tk.call(self._w, "bbox", index)) def identify(self, x, y): @@ -682,7 +696,7 @@ """Force revalidation, independent of the conditions specified by the validate option. Returns False if validation fails, True if it succeeds. Sets or clears the invalid state accordingly.""" - return bool(self.tk.call(self._w, "validate")) + return bool(self.tk.getboolean(self.tk.call(self._w, "validate"))) class Combobox(Entry): @@ -709,6 +723,8 @@ element at position newindex in the list of values. Otherwise, returns the index of the current value in the list of values or -1 if the current value does not appear in the list.""" + if newindex is None: + return self.tk.getint(self.tk.call(self._w, "current")) return self.tk.call(self._w, "current", newindex) @@ -863,7 +879,7 @@ def index(self, tab_id): """Returns the numeric index of the tab specified by tab_id, or the total number of tabs if tab_id is the string "end".""" - return self.tk.call(self._w, "index", tab_id) + return self.tk.getint(self.tk.call(self._w, "index", tab_id)) def insert(self, pos, child, **kw): @@ -898,7 +914,7 @@ def tabs(self): """Returns a list of windows managed by the notebook.""" - return self.tk.call(self._w, "tabs") or () + return self.tk.splitlist(self.tk.call(self._w, "tabs") or ()) def enable_traversal(self): @@ -981,7 +997,7 @@ constrained to be between 0 and the total size of the widget. Returns the new position of sash number index.""" - return self.tk.call(self._w, "sashpos", index, newpos) + return self.tk.getint(self.tk.call(self._w, "sashpos", index, newpos)) PanedWindow = Panedwindow # Tkinter name compatibility @@ -1181,14 +1197,15 @@ If column is specified, returns the bounding box of that cell. If the item is not visible (i.e., if it is a descendant of a closed item or is scrolled offscreen), returns an empty string.""" - return self.tk.call(self._w, "bbox", item, column) + return self._getints(self.tk.call(self._w, "bbox", item, column)) or '' def get_children(self, item=None): """Returns a tuple of children belonging to item. If item is not specified, returns root children.""" - return self.tk.call(self._w, "children", item or '') or () + return self.tk.splitlist( + self.tk.call(self._w, "children", item or '') or ()) def set_children(self, item, *newchildren): @@ -1229,7 +1246,7 @@ def exists(self, item): """Returns True if the specified item is present in the tree, False otherwise.""" - return bool(self.tk.call(self._w, "exists", item)) + return bool(self.tk.getboolean(self.tk.call(self._w, "exists", item))) def focus(self, item=None): @@ -1311,7 +1328,7 @@ def index(self, item): """Returns the integer index of item within its parent's list of children.""" - return self.tk.call(self._w, "index", item) + return self.tk.getint(self.tk.call(self._w, "index", item)) def insert(self, parent, index, iid=None, **kw): @@ -1420,7 +1437,7 @@ value of given column in given item to the specified value.""" res = self.tk.call(self._w, "set", item, column, value) if column is None and value is None: - return _dict_from_tcltuple(res, False) + return _dict_from_tcltuple(self.tk.splitlist(res), False) else: return res @@ -1451,7 +1468,8 @@ all items which have the specified tag. * Availability: Tk 8.6""" - return self.tk.call(self._w, "tag", "has", tagname, item) + return self.tk.getboolean( + self.tk.call(self._w, "tag", "has", tagname, item)) # Extensions @@ -1523,7 +1541,8 @@ self.label.place_configure(x=x, y=y) - from_, to = self.scale['from'], self.scale['to'] + from_ = _to_number(self.scale['from']) + to = _to_number(self.scale['to']) if to < from_: from_, to = to, from_ newval = self._variable.get() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,6 +35,8 @@ Library ------- +- Issue #20072: Fixed multiple errors in tkinter with wantobjects is False. + - Issue #1065986: pydoc can now handle unicode strings. - Issue #16039: CVE-2013-1752: Change use of readline in imaplib module to -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 7 20:31:33 2014 From: python-checkins at python.org (r.david.murray) Date: Tue, 7 Jan 2014 20:31:33 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_expand_=27dis?= =?utf-8?q?=27_entry=2E?= Message-ID: <3dzNxd1rD3z7LjQ@mail.python.org> http://hg.python.org/cpython/rev/e2494137b118 changeset: 88340:e2494137b118 parent: 88338:1628cd94db52 user: R David Murray date: Tue Jan 07 14:30:17 2014 -0500 summary: whatsnew: expand 'dis' entry. Also add one missing versionadded. files: Doc/library/dis.rst | 2 + Doc/whatsnew/3.4.rst | 56 ++++++++++++++++++++++++++++---- 2 files changed, 51 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 @@ -40,6 +40,8 @@ Bytecode analysis ----------------- +.. versionadded:: 3.4 + The bytecode analysis API allows pieces of Python code to be wrapped in a :class:`Bytecode` object that provides easy access to details of the compiled code. 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 @@ -558,15 +558,57 @@ dis --- +Functions :func:`~dis.show_code`, :func:`~dis.dis`, :func:`~dis.distb`, and +:func:`~dis.disassemble` now accept a keyword-only *file* argument that +controls where they write their output. + The :mod:`dis` module is now built around an :class:`~dis.Instruction` class -that provides details of individual bytecode operations and a -:func:`~dis.get_instructions` iterator that emits the Instruction stream for a -given piece of Python code. The various display tools in the :mod:`dis` -module have been updated to be based on these new components. +that provides object oriented access to the details of each individual bytecode +operation. -The new :class:`dis.Bytecode` class provides an object-oriented API for -inspecting bytecode, both in human-readable form and for iterating over -instructions. +A new method, :func:`~dis.get_instructions`, provides an iterator that emits +the Instruction stream for a given piece of Python code. Thus it is now +possible to write a program that inspects and manipulates a bytecode +object in ways different from those provided by the :mod:`~dis` module +itself. For example:: + + >>> import dis + >>> for instr in dis.get_instructions(lambda x: x + 1): + ... print(instr.opname) + LOAD_FAST + LOAD_CONST + BINARY_ADD + RETURN_VALUE + +The various display tools in the :mod:`dis` module have been rewritten to use +these new components. + +In addition, a new application-friendly class :class:`~dis.Bytecode` provides +an object-oriented API for inspecting bytecode in both in human-readable form +and for iterating over instructions. The :class:`~dis.Bytecode` constructor +takes the same arguments that :func:`~dis.get_instruction` does (plus an +optional *current_offset*), and the resulting object can be iterated to produce +:class:`~dis.Instruction` objects. But it also has a :mod:`~dis.Bytecode.dis` +method, equivalent to calling :mod:`~dis.dis` on the constructor argument, but +returned as a multi-line string:: + + >>> bytecode = dis.Bytecode(lambda x: x +1, current_offset=3) + >>> for instr in bytecode: + ... print('{} ({})'.format(instr.opname, instr.opcode)) + LOAD_FAST (124) + LOAD_CONST (100) + BINARY_ADD (23) + RETURN_VALUE (83) + >>> bytecode.dis().splitlines() # doctest: +NORMALIZE_WHITESPACE + [' 1 0 LOAD_FAST 0 (x)', + ' --> 3 LOAD_CONST 1 (1)', + ' 6 BINARY_ADD', + ' 7 RETURN_VALUE'] + +:class:`~dis.Bytecode` also has a class method, +:meth:`~dis.Bytecode.from_traceback`, that provides the ability to manipulate a +traceback (that is, ``print(Bytecode.from_traceback(tb).dis())`` is equivalent +to ``distb(tb)``). (Contributed by Nick Coghlan, Ryan Kelly and Thomas Kluyver in :issue:`11816` and Claudiu Popa in :issue:`17916`) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 7 20:53:55 2014 From: python-checkins at python.org (larry.hastings) Date: Tue, 7 Jan 2014 20:53:55 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320144=3A_Argument?= =?utf-8?q?_Clinic_now_supports_simple_constants_as_parameter?= Message-ID: <3dzPRR2Flgz7Lk7@mail.python.org> http://hg.python.org/cpython/rev/c96dba33f019 changeset: 88341:c96dba33f019 user: Larry Hastings date: Tue Jan 07 11:53:01 2014 -0800 summary: Issue #20144: Argument Clinic now supports simple constants as parameter default values. inspect.Signature correspondingly supports them in __text_signature__ fields for builtins. files: Lib/inspect.py | 56 ++++++++++++++++++-- Lib/test/test_inspect.py | 13 ++++- Misc/NEWS | 6 ++ Modules/_sre.c | 70 +++++++++++++++++++------- Modules/_testcapimodule.c | 12 ++++ Tools/clinic/clinic.py | 28 ++++++++- 6 files changed, 153 insertions(+), 32 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1974,18 +1974,60 @@ parameters = [] empty = Parameter.empty + invalid = object() + + def parse_attribute(node): + if not isinstance(node.ctx, ast.Load): + return None + + value = node.value + o = parse_node(value) + if o is invalid: + return invalid + + if isinstance(value, ast.Name): + name = o + if name not in sys.modules: + return invalid + o = sys.modules[name] + + return getattr(o, node.attr, invalid) + + def parse_node(node): + if isinstance(node, ast.arg): + if node.annotation != None: + raise ValueError("Annotations are not currently supported") + return node.arg + if isinstance(node, ast.Num): + return node.n + if isinstance(node, ast.Str): + return node.s + if isinstance(node, ast.NameConstant): + return node.value + if isinstance(node, ast.Attribute): + return parse_attribute(node) + if isinstance(node, ast.Name): + if not isinstance(node.ctx, ast.Load): + return invalid + return node.id + return invalid def p(name_node, default_node, default=empty): - name = name_node.arg - - if isinstance(default_node, ast.Num): - default = default.n - elif isinstance(default_node, ast.NameConstant): - default = default_node.value + name = parse_node(name_node) + if name is invalid: + return None + if default_node: + o = parse_node(default_node) + if o is invalid: + return None + default = o if o is not invalid else default parameters.append(Parameter(name, kind, default=default, annotation=empty)) # non-keyword-only parameters - for name, default in reversed(list(itertools.zip_longest(reversed(f.args.args), reversed(f.args.defaults), fillvalue=None))): + args = reversed(f.args.args) + defaults = reversed(f.args.defaults) + iter = itertools.zip_longest(args, defaults, fillvalue=None) + for name, default in reversed(list(iter)): p(name, default) # *args diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -15,6 +15,7 @@ from concurrent.futures import ThreadPoolExecutor except ImportError: ThreadPoolExecutor = None +import _testcapi from test.support import run_unittest, TESTFN, DirsOnSysPath from test.support import MISSING_C_DOCSTRINGS @@ -1593,9 +1594,19 @@ @unittest.skipIf(MISSING_C_DOCSTRINGS, "Signature information for builtins requires docstrings") def test_signature_on_builtins(self): + # min doesn't have a signature (yet) self.assertEqual(inspect.signature(min), None) - signature = inspect.signature(os.stat) + + signature = inspect.signature(_testcapi.docstring_with_signature_with_defaults) self.assertTrue(isinstance(signature, inspect.Signature)) + def p(name): return signature.parameters[name].default + self.assertEqual(p('s'), 'avocado') + self.assertEqual(p('d'), 3.14) + self.assertEqual(p('i'), 35) + self.assertEqual(p('c'), sys.maxsize) + self.assertEqual(p('n'), None) + self.assertEqual(p('t'), True) + self.assertEqual(p('f'), False) def test_signature_on_non_function(self): with self.assertRaisesRegex(TypeError, 'is not a callable object'): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,11 +13,17 @@ Library ------- +- Issue #20144: inspect.Signature now supports parsing simple symbolic + constants as parameter default values in __text_signature__. + - Issue #20072: Fixed multiple errors in tkinter with wantobjects is False. Tools/Demos ----------- +- Issue #20144: Argument Clinic now supports simple symbolic constants + as parameter default values. + - Issue #20143: The line numbers reported in Argument Clinic errors are now more accurate. diff --git a/Modules/_sre.c b/Modules/_sre.c --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -526,21 +526,58 @@ return sre_ucs4_search(state, pattern); } -static PyObject* -pattern_match(PatternObject* self, PyObject* args, PyObject* kw) +/*[clinic] +module _sre +class _sre.SRE_Pattern + +_sre.SRE_Pattern.match as pattern_match + + self: self(type="PatternObject *") + pattern: object + pos: Py_ssize_t = 0 + endpos: Py_ssize_t(c_default="PY_SSIZE_T_MAX") = sys.maxsize + +Matches zero or more characters at the beginning of the string. +[clinic]*/ + +PyDoc_STRVAR(pattern_match__doc__, +"match(pattern, pos=0, endpos=sys.maxsize)\n" +"Matches zero or more characters at the beginning of the string."); + +#define PATTERN_MATCH_METHODDEF \ + {"match", (PyCFunction)pattern_match, METH_VARARGS|METH_KEYWORDS, pattern_match__doc__}, + +static PyObject * +pattern_match_impl(PatternObject *self, PyObject *pattern, Py_ssize_t pos, Py_ssize_t endpos); + +static PyObject * +pattern_match(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + static char *_keywords[] = {"pattern", "pos", "endpos", NULL}; + PyObject *pattern; + Py_ssize_t pos = 0; + Py_ssize_t endpos = PY_SSIZE_T_MAX; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O|nn:match", _keywords, + &pattern, &pos, &endpos)) + goto exit; + return_value = pattern_match_impl((PatternObject *)self, pattern, pos, endpos); + +exit: + return return_value; +} + +static PyObject * +pattern_match_impl(PatternObject *self, PyObject *pattern, Py_ssize_t pos, Py_ssize_t endpos) +/*[clinic checksum: 63e59c5f3019efe6c1f3acdec42b2d3595e14a09]*/ { SRE_STATE state; Py_ssize_t status; - - PyObject* string; - Py_ssize_t start = 0; - Py_ssize_t end = PY_SSIZE_T_MAX; - static char* kwlist[] = { "pattern", "pos", "endpos", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, kw, "O|nn:match", kwlist, - &string, &start, &end)) - return NULL; - - string = state_init(&state, self, string, start, end); + PyObject *string; + + string = state_init(&state, (PatternObject *)self, pattern, pos, endpos); if (!string) return NULL; @@ -556,7 +593,7 @@ state_fini(&state); - return pattern_new_match(self, &state, status); + return (PyObject *)pattern_new_match(self, &state, status); } static PyObject* @@ -1254,10 +1291,6 @@ return result; } -PyDoc_STRVAR(pattern_match_doc, -"match(string[, pos[, endpos]]) -> match object or None.\n\ - Matches zero or more characters at the beginning of the string"); - PyDoc_STRVAR(pattern_fullmatch_doc, "fullmatch(string[, pos[, endpos]]) -> match object or None.\n\ Matches against all of the string"); @@ -1295,8 +1328,7 @@ PyDoc_STRVAR(pattern_doc, "Compiled regular expression objects"); static PyMethodDef pattern_methods[] = { - {"match", (PyCFunction) pattern_match, METH_VARARGS|METH_KEYWORDS, - pattern_match_doc}, + PATTERN_MATCH_METHODDEF {"fullmatch", (PyCFunction) pattern_fullmatch, METH_VARARGS|METH_KEYWORDS, pattern_fullmatch_doc}, {"search", (PyCFunction) pattern_search, METH_VARARGS|METH_KEYWORDS, diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2869,6 +2869,15 @@ "This docstring has a valid signature and some extra newlines." ); +PyDoc_STRVAR(docstring_with_signature_with_defaults, +"docstring_with_signature_with_defaults(s='avocado', d=3.14, i=35, c=sys.maxsize, n=None, t=True, f=False)\n" +"\n" +"\n" +"\n" +"This docstring has a valid signature with parameters,\n" +"and the parameters take defaults of varying types." +); + #ifdef WITH_THREAD typedef struct { PyThread_type_lock start_event; @@ -3087,6 +3096,9 @@ {"docstring_with_signature_and_extra_newlines", (PyCFunction)test_with_docstring, METH_NOARGS, docstring_with_signature_and_extra_newlines}, + {"docstring_with_signature_with_defaults", + (PyCFunction)test_with_docstring, METH_NOARGS, + docstring_with_signature_with_defaults}, #ifdef WITH_THREAD {"call_in_temporary_c_thread", call_in_temporary_c_thread, METH_O, PyDoc_STR("set_error_class(error_class) -> None")}, diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1362,15 +1362,15 @@ # Only used by format units ending with '#'. length = False - def __init__(self, name, function, default=unspecified, *, doc_default=None, required=False, annotation=unspecified, **kwargs): + def __init__(self, name, function, default=unspecified, *, doc_default=None, c_default=None, py_default=None, required=False, annotation=unspecified, **kwargs): self.function = function self.name = name if default is not unspecified: self.default = default - self.py_default = py_repr(default) + self.py_default = py_default if py_default is not None else py_repr(default) self.doc_default = doc_default if doc_default is not None else self.py_default - self.c_default = c_repr(default) + self.c_default = c_default if c_default is not None else c_repr(default) elif doc_default is not None: fail(function.fullname + " argument " + name + " specified a 'doc_default' without having a 'default'") if annotation != unspecified: @@ -2315,18 +2315,36 @@ function_args = module.body[0].args parameter = function_args.args[0] + py_default = None + + parameter_name = parameter.arg + name, legacy, kwargs = self.parse_converter(parameter.annotation) + if function_args.defaults: expr = function_args.defaults[0] # mild hack: explicitly support NULL as a default value if isinstance(expr, ast.Name) and expr.id == 'NULL': value = NULL + elif isinstance(expr, ast.Attribute): + a = [] + n = expr + while isinstance(n, ast.Attribute): + a.append(n.attr) + n = n.value + if not isinstance(n, ast.Name): + fail("Malformed default value (looked like a Python constant)") + a.append(n.id) + py_default = ".".join(reversed(a)) + value = None + c_default = kwargs.get("c_default") + if not (isinstance(c_default, str) and c_default): + fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.") + kwargs["py_default"] = py_default else: value = ast.literal_eval(expr) else: value = unspecified - parameter_name = parameter.arg - name, legacy, kwargs = self.parse_converter(parameter.annotation) dict = legacy_converters if legacy else converters legacy_str = "legacy " if legacy else "" if name not in dict: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 7 21:13:46 2014 From: python-checkins at python.org (larry.hastings) Date: Tue, 7 Jan 2014 21:13:46 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320141=3A_Improved?= =?utf-8?q?_Argument_Clinic=27s_support_for_the_PyArg=5FParse_=22O!=22?= Message-ID: <3dzPtL5ckLz7LjQ@mail.python.org> http://hg.python.org/cpython/rev/ddb5cd3e0860 changeset: 88342:ddb5cd3e0860 user: Larry Hastings date: Tue Jan 07 12:13:13 2014 -0800 summary: Issue #20141: Improved Argument Clinic's support for the PyArg_Parse "O!" format unit. files: Doc/howto/clinic.rst | 27 +- Misc/NEWS | 3 + Modules/unicodedata.c | 10 +- Python/importlib.h | 8709 +++++++++++++-------------- Tools/clinic/clinic.py | 28 +- 5 files changed, 4384 insertions(+), 4393 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -640,7 +640,7 @@ ``'K'`` ``unsigned_PY_LONG_LONG`` ``'L'`` ``PY_LONG_LONG`` ``'n'`` ``Py_ssize_t`` -``'O!'`` ``object(type='name_of_Python_type')`` +``'O!'`` ``object(subclass_of='&PySomething_Type')`` ``'O&'`` ``object(converter='name_of_c_function')`` ``'O'`` ``object`` ``'p'`` ``bool`` @@ -693,20 +693,22 @@ (But "legacy converters" don't support arguments. That's why we skipped them for your first function.) The argument you specified to the format unit is now an argument to the converter; this -argument is either ``converter`` (for ``O&``), ``type`` (for ``O!``), +argument is either ``converter`` (for ``O&``), ``subclass_of`` (for ``O!``), or ``encoding`` (for all the format units that start with ``e``). -Note that ``object()`` must explicitly support each Python type you specify -for the ``type`` argument. Currently it only supports ``str``. It should be -easy to add more, just edit ``Tools/clinic/clinic.py``, search for ``O!`` in -the text, and add more entries to the dict mapping types to strings just above it. +When using ``subclass_of``, you may also want to use the other +custom argument for ``object()``: ``type``, which lets you set the type +actually used for the parameter. For example, if you want to ensure +that the object is a subclass of ``PyUnicode_Type``, you probably want +to use the converter ``object(type='PyUnicodeObject *', subclass_of='&PyUnicode_Type')``. -Note also that this approach takes away some possible flexibility for the format -units starting with ``e``. It used to be possible to decide at runtime what +One possible problem with using Argument Clinic: it takes away some possible +flexibility for the format units starting with ``e``. When writing a +``PyArg_Parse`` call by hand, you could theoretically decide at runtime what encoding string to pass in to :c:func:`PyArg_ParseTuple`. But now this string must -be hard-coded at compile-time. This limitation is deliberate; it made supporting -this format unit much easier, and may allow for future compile-time optimizations. -This restriction does not seem unreasonable; CPython itself always passes in static +be hard-coded at Argument-Clinic-preprocessing-time. This limitation is deliberate; +it made supporting this format unit much easier, and may allow for future optimizations. +This restriction doesn't seem unreasonable; CPython itself always passes in static hard-coded encoding strings for parameters whose format units start with ``e``. @@ -796,7 +798,8 @@ ``self_converter`` or a subclass thereof. What's the point? This lets you automatically cast ``self`` -from ``PyObject *`` to a custom type. +from ``PyObject *`` to a custom type, just like ``object()`` +does with its ``type`` parameter. How do you specify the custom type you want to cast ``self`` to? If you only have one or two functions with the same type for ``self``, diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -21,6 +21,9 @@ Tools/Demos ----------- +- Issue #20141: Improved Argument Clinic's support for the PyArg_Parse "O!" + format unit. + - Issue #20144: Argument Clinic now supports simple symbolic constants as parameter default values. diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -117,7 +117,7 @@ unicodedata.UCD.decimal - unichr: object(type='str') + unichr: object(type='PyUnicodeObject *', subclass_of='&PyUnicode_Type') default: object=NULL / @@ -140,13 +140,13 @@ {"decimal", (PyCFunction)unicodedata_UCD_decimal, METH_VARARGS, unicodedata_UCD_decimal__doc__}, static PyObject * -unicodedata_UCD_decimal_impl(PyObject *self, PyObject *unichr, PyObject *default_value); +unicodedata_UCD_decimal_impl(PyObject *self, PyUnicodeObject *unichr, PyObject *default_value); static PyObject * unicodedata_UCD_decimal(PyObject *self, PyObject *args) { PyObject *return_value = NULL; - PyObject *unichr; + PyUnicodeObject *unichr; PyObject *default_value = NULL; if (!PyArg_ParseTuple(args, @@ -160,8 +160,8 @@ } static PyObject * -unicodedata_UCD_decimal_impl(PyObject *self, PyObject *unichr, PyObject *default_value) -/*[clinic checksum: 9576fa55f4ea0be82968af39dc9d0283e634beeb]*/ +unicodedata_UCD_decimal_impl(PyObject *self, PyUnicodeObject *unichr, PyObject *default_value) +/*[clinic checksum: 73edde0e9cd5913ea174c4fa81504369761b7426]*/ { PyUnicodeObject *v = (PyUnicodeObject *)unichr; int have_old = 0; diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1358,6 +1358,12 @@ # by format units starting with 'e'. encoding = None + # Should this object be required to be a subclass of a specific type? + # If not None, should be a string representing a pointer to a + # PyTypeObject (e.g. "&PyUnicode_Type"). + # Only used by the 'O!' format unit (and the "object" converter). + subclass_of = None + # Do we want an adjacent '_length' variable for this variable? # Only used by format units ending with '#'. length = False @@ -1446,7 +1452,9 @@ list.append(self.converter) if self.encoding: - list.append(self.encoding) + list.append(c_repr(self.encoding)) + elif self.subclass_of: + list.append(self.subclass_of) legal_name = ensure_legal_c_identifier(self.name) s = ("&" if self.parse_by_reference else "") + legal_name @@ -1627,20 +1635,12 @@ type = 'PyObject *' format_unit = 'O' - def converter_init(self, *, type=None): - if type: - assert isinstance(type, str) - assert type.isidentifier() - try: - type = eval(type) - # need more of these! - type = { - str: '&PyUnicode_Type', - }[type] - except NameError: - type = type + def converter_init(self, *, type=None, subclass_of=None): + if subclass_of: self.format_unit = 'O!' - self.encoding = type + self.subclass_of = subclass_of + if type is not None: + self.type = type @add_legacy_c_converter('s#', length=True) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 7 21:21:46 2014 From: python-checkins at python.org (larry.hastings) Date: Tue, 7 Jan 2014 21:21:46 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320157=3A_When_Arg?= =?utf-8?q?ument_Clinic_renames_a_parameter_because_its_name?= Message-ID: <3dzQ3Z3D6tz7LjV@mail.python.org> http://hg.python.org/cpython/rev/f61c63ec4e70 changeset: 88343:f61c63ec4e70 user: Larry Hastings date: Tue Jan 07 12:21:08 2014 -0800 summary: Issue #20157: When Argument Clinic renames a parameter because its name collides with a C keyword, it no longer exposes that rename to PyArg_Parse. files: Misc/NEWS | 3 +++ Tools/clinic/clinic.py | 18 +++++++++++++----- Tools/clinic/clinic_test.py | 19 +++++++++++++++++++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -21,6 +21,9 @@ Tools/Demos ----------- +- Issue #20157: When Argument Clinic renames a parameter because its name + collides with a C keyword, it no longer exposes that rename to PyArg_Parse. + - Issue #20141: Improved Argument Clinic's support for the PyArg_Parse "O!" format unit. diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -8,7 +8,6 @@ import abc import ast import atexit -import clinic import collections import contextlib import functools @@ -898,13 +897,21 @@ def parse_clinic_block(self, dsl_name): input_add, input_output = text_accumulator() self.block_start_line_number = self.line_number + 1 - stop_line = self.language.stop_line.format(dsl_name=dsl_name) + '\n' + stop_line = self.language.stop_line.format(dsl_name=dsl_name) body_prefix = self.language.body_prefix.format(dsl_name=dsl_name) + def is_stop_line(line): + # make sure to recognize stop line even if it + # doesn't end with EOL (it could be the very end of the file) + if not line.startswith(stop_line): + return False + remainder = line[len(stop_line):] + return (not remainder) or remainder.isspace() + # consume body of program while self.input: line = self._line() - if line == stop_line or self.is_start_line(line): + if is_stop_line(line) or self.is_start_line(line): break if body_prefix: line = line.lstrip() @@ -1396,7 +1403,8 @@ data is a CRenderData instance. """ self.parameter = parameter - name = ensure_legal_c_identifier(self.name) + original_name = self.name + name = ensure_legal_c_identifier(original_name) # declarations d = self.declaration() @@ -1414,7 +1422,7 @@ data.impl_arguments.append(self.length_name()) # keywords - data.keywords.append(name) + data.keywords.append(original_name) # format_units if self.is_optional() and '|' not in data.format_units: diff --git a/Tools/clinic/clinic_test.py b/Tools/clinic/clinic_test.py --- a/Tools/clinic/clinic_test.py +++ b/Tools/clinic/clinic_test.py @@ -54,6 +54,25 @@ _module_and_class = clinic.Clinic._module_and_class +class ClinicWholeFileTest(TestCase): + def test_eol(self): + # regression test: + # clinic's block parser didn't recognize + # the "end line" for the block if it + # didn't end in "\n" (as in, the last) + # byte of the file was '/'. + # so it woudl spit out an end line for you. + # and since you really already had one, + # the last line of the block got corrupted. + c = clinic.Clinic(clinic.CLanguage()) + raw = "/*[clinic]\nfoo\n[clinic]*/" + cooked = c.parse(raw).splitlines() + end_line = cooked[2].rstrip() + # this test is redundant, it's just here explicitly to catch + # the regression test so we don't forget what it looked like + self.assertNotEqual(end_line, "[clinic]*/[clinic]*/") + self.assertEqual(end_line, "[clinic]*/") + class ClinicGroupPermuterTest(TestCase): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 7 21:42:30 2014 From: python-checkins at python.org (larry.hastings) Date: Tue, 7 Jan 2014 21:42:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2319273=3A_The_mark?= =?utf-8?q?er_comments_Argument_Clinic_uses_have_been_changed?= Message-ID: <3dzQWV0D63z7LjV@mail.python.org> http://hg.python.org/cpython/rev/e8307cf23af4 changeset: 88344:e8307cf23af4 user: Larry Hastings date: Tue Jan 07 12:41:53 2014 -0800 summary: Issue #19273: The marker comments Argument Clinic uses have been changed to improve readability. files: Doc/howto/clinic.rst | 126 +++++++++++++------------- Misc/NEWS | 3 + Modules/_cursesmodule.c | 12 +- Modules/_datetimemodule.c | 12 +- Modules/_dbmmodule.c | 24 ++-- Modules/_opcode.c | 14 +- Modules/_pickle.c | 124 ++++++++++++------------ Modules/_weakref.c | 14 +- Modules/posixmodule.c | 32 +++--- Modules/unicodedata.c | 12 +- Modules/zlibmodule.c | 30 +++--- Objects/dictobject.c | 12 +- Objects/unicodeobject.c | 12 +- Tools/clinic/clinic.py | 13 +- 14 files changed, 222 insertions(+), 218 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -35,12 +35,12 @@ Argument Clinic will scan over the file looking for lines that look exactly like this:: - /*[clinic] + /*[clinic input] When it finds one, it reads everything up to a line that looks -like this:: +exactly like this:: - [clinic]*/ + [clinic start generated code]*/ Everything in between these two lines is input for Argument Clinic. All of these lines, including the beginning and ending comment @@ -51,11 +51,11 @@ immediately after the block, followed by a comment containing a checksum. The Argument Clinic block now looks like this:: - /*[clinic] + /*[clinic input] ... clinic input goes here ... - [clinic]*/ + [clinic start generated code]*/ ... clinic output goes here ... - /*[clinic checksum:...]*/ + /*[clinic end generated code: checksum=...]*/ If you run Argument Clinic on the same file a second time, Argument Clinic will discard the old output and write out the new output with a fresh checksum @@ -68,9 +68,9 @@ For the sake of clarity, here's the terminology we'll use with Argument Clinic: -* The first line of the comment (``/*[clinic]``) is the *start line*. -* The last line of the initial comment (``[clinic]*/``) is the *end line*. -* The last line (``/*[clinic checksum:...]*/``) is the *checksum line*. +* The first line of the comment (``/*[clinic input]``) is the *start line*. +* The last line of the initial comment (``[clinic start generated code]*/``) is the *end line*. +* The last line (``/*[clinic end generated code: checksum=...]*/``) is the *checksum line*. * In between the start line and the end line is the *input*. * In between the end line and the checksum line is the *output*. * All the text collectively, from the start line to the checksum line inclusively, @@ -111,8 +111,8 @@ 3. Add the following boilerplate above the function, creating our block:: - /*[clinic] - [clinic]*/ + /*[clinic input] + [clinic start generated code]*/ 4. Cut the docstring and paste it in between the ``[clinic]`` lines, removing all the junk that makes it a properly quoted C string. @@ -122,9 +122,9 @@ Sample:: - /*[clinic] + /*[clinic input] Write a pickled representation of obj to the open file. - [clinic]*/ + [clinic start generated code]*/ 5. If your docstring doesn't have a "summary" line, Argument Clinic will complain. So let's make sure it has one. The "summary" line should @@ -143,11 +143,11 @@ Sample:: - /*[clinic] + /*[clinic input] pickle.Pickler.dump Write a pickled representation of obj to the open file. - [clinic]*/ + [clinic start generated code]*/ 7. If this is the first time that module or class has been used with Argument Clinic in this C file, @@ -159,16 +159,16 @@ Sample:: - /*[clinic] + /*[clinic input] module pickle class pickle.Pickler - [clinic]*/ + [clinic start generated code]*/ - /*[clinic] + /*[clinic input] pickle.Pickler.dump Write a pickled representation of obj to the open file. - [clinic]*/ + [clinic start generated code]*/ 8. Declare each of the parameters to the function. Each parameter @@ -207,18 +207,18 @@ Sample:: - /*[clinic] + /*[clinic input] module pickle class pickle.Pickler - [clinic]*/ + [clinic start generated code]*/ - /*[clinic] + /*[clinic input] pickle.Pickler.dump obj: 'O' Write a pickled representation of obj to the open file. - [clinic]*/ + [clinic start generated code]*/ 9. If your function has ``|`` in the format string, meaning some parameters have default values, you can ignore it. Argument @@ -247,19 +247,19 @@ Sample:: - /*[clinic] + /*[clinic input] module pickle class pickle.Pickler - [clinic]*/ + [clinic start generated code]*/ - /*[clinic] + /*[clinic input] pickle.Pickler.dump obj: 'O' / Write a pickled representation of obj to the open file. - [clinic]*/ + [clinic start generated code]*/ 11. It's helpful to write a per-parameter docstring for each parameter. But per-parameter docstrings are optional; you can skip this step @@ -274,12 +274,12 @@ Sample:: - /*[clinic] + /*[clinic input] module pickle class pickle.Pickler - [clinic]*/ + [clinic start generated code]*/ - /*[clinic] + /*[clinic input] pickle.Pickler.dump obj: 'O' @@ -287,19 +287,19 @@ / Write a pickled representation of obj to the open file. - [clinic]*/ + [clinic start generated code]*/ 12. Save and close the file, then run ``Tools/clinic/clinic.py`` on it. With luck everything worked and your block now has output! Reopen the file in your text editor to see:: - /*[clinic] + /*[clinic input] module pickle class pickle.Pickler - [clinic]*/ - /*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + [clinic start generated code]*/ + /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ - /*[clinic] + /*[clinic input] pickle.Pickler.dump obj: 'O' @@ -307,7 +307,7 @@ / Write a pickled representation of obj to the open file. - [clinic]*/ + [clinic start generated code]*/ PyDoc_STRVAR(pickle_Pickler_dump__doc__, "Write a pickled representation of obj to the open file.\n" @@ -315,7 +315,7 @@ ... static PyObject * pickle_Pickler_dump_impl(PyObject *self, PyObject *obj) - /*[clinic checksum: 3bd30745bf206a48f8b576a1da3d90f55a0a4187]*/ + /*[clinic end generated code: checksum=3bd30745bf206a48f8b576a1da3d90f55a0a4187]*/ Obviously, if Argument Clinic didn't produce any output, it's because it found an error in your input. Keep fixing your errors and retrying @@ -373,7 +373,7 @@ static return_type your_function_impl(...) - /*[clinic checksum: ...]*/ + /*[clinic end generated code: checksum=...]*/ { ... @@ -383,13 +383,13 @@ Sample:: - /*[clinic] + /*[clinic input] module pickle class pickle.Pickler - [clinic]*/ - /*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + [clinic start generated code]*/ + /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ - /*[clinic] + /*[clinic input] pickle.Pickler.dump obj: 'O' @@ -397,7 +397,7 @@ / Write a pickled representation of obj to the open file. - [clinic]*/ + [clinic start generated code]*/ PyDoc_STRVAR(pickle_Pickler_dump__doc__, "Write a pickled representation of obj to the open file.\n" @@ -405,7 +405,7 @@ ... static PyObject * pickle_Pickler_dump_impl(PyObject *self, PyObject *obj) - /*[clinic checksum: 3bd30745bf206a48f8b576a1da3d90f55a0a4187]*/ + /*[clinic end generated code: checksum=3bd30745bf206a48f8b576a1da3d90f55a0a4187]*/ { /* Check whether the Pickler was initialized correctly (issue3664). Developers often forget to call __init__() in their subclasses, which @@ -470,7 +470,7 @@ For example, if we wanted to rename the C function names generated for ``pickle.Pickler.dump``, it'd look like this:: - /*[clinic] + /*[clinic input] pickle.Pickler.dump as pickler_dumper ... @@ -515,7 +515,7 @@ uses optional groups to make the first two parameters and the last parameter optional:: - /*[clinic] + /*[clinic input] curses.window.addch @@ -666,7 +666,7 @@ As an example, here's our sample ``pickle.Pickler.dump`` using the proper converter:: - /*[clinic] + /*[clinic input] pickle.Pickler.dump obj: object @@ -674,7 +674,7 @@ / Write a pickled representation of obj to the open file. - [clinic]*/ + [clinic start generated code]*/ Argument Clinic will show you all the converters it has available. For each converter it'll show you all the parameters @@ -769,9 +769,9 @@ A Python block uses different delimiter lines than an Argument Clinic function block. It looks like this:: - /*[python] + /*[python input] # python code goes here - [python]*/ + [python start generated code]*/ All the code inside the Python block is executed at the time it's parsed. All text written to stdout inside the block @@ -780,9 +780,9 @@ As an example, here's a Python block that adds a static integer variable to the C code:: - /*[python] + /*[python input] print('static int __ignored_unused_variable__ = 0;') - [python]*/ + [python start generated code]*/ static int __ignored_unused_variable__ = 0; /*[python checksum:...]*/ @@ -806,7 +806,7 @@ you can directly use Argument Clinic's existing ``self`` converter, passing in the type you want to use as the ``type`` parameter:: - /*[clinic] + /*[clinic input] _pickle.Pickler.dump @@ -815,18 +815,18 @@ / Write a pickled representation of the given object to the open file. - [clinic]*/ + [clinic start generated code]*/ On the other hand, if you have a lot of functions that will use the same type for ``self``, it's best to create your own converter, subclassing ``self_converter`` but overwriting the ``type`` member:: - /*[clinic] + /*[clinic input] class PicklerObject_converter(self_converter): type = "PicklerObject *" - [clinic]*/ + [clinic start generated code]*/ - /*[clinic] + /*[clinic input] _pickle.Pickler.dump @@ -835,7 +835,7 @@ / Write a pickled representation of the given object to the open file. - [clinic]*/ + [clinic start generated code]*/ @@ -917,14 +917,14 @@ Here's the simplest example of a custom converter, from ``Modules/zlibmodule.c``:: - /*[python] + /*[python input] class uint_converter(CConverter): type = 'unsigned int' converter = 'uint_converter' - [python]*/ - /*[python checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + [python start generated code]*/ + /*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ This block adds a converter to Argument Clinic named ``uint``. Parameters declared as ``uint`` will be declared as type ``unsigned int``, and will @@ -963,8 +963,8 @@ Since Python comments are different from C comments, Argument Clinic blocks embedded in Python files look slightly different. They look like this:: - #/*[python] + #/*[python input] #print("def foo(): pass") - #[python]*/ + #[python start generated code]*/ def foo(): pass #/*[python checksum:...]*/ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -21,6 +21,9 @@ Tools/Demos ----------- +- Issue #19273: The marker comments Argument Clinic uses have been changed + to improve readability. + - Issue #20157: When Argument Clinic renames a parameter because its name collides with a C keyword, it no longer exposes that rename to PyArg_Parse. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -134,11 +134,11 @@ #define STRICT_SYSV_CURSES #endif -/*[clinic] +/*[clinic input] module curses class curses.window -[clinic]*/ -/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +[clinic start generated code]*/ +/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ /* Definition of exception curses.error */ @@ -555,7 +555,7 @@ /* Addch, Addstr, Addnstr */ -/*[clinic] +/*[clinic input] curses.window.addch @@ -581,7 +581,7 @@ overwriting any character previously painted at that location. By default, the character position and attributes are the current settings for the window object. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(curses_window_addch__doc__, "addch([x, y,] ch, [attr])\n" @@ -650,7 +650,7 @@ static PyObject * curses_window_addch_impl(PyObject *self, int group_left_1, int x, int y, PyObject *ch, int group_right_1, long attr) -/*[clinic checksum: 44ed958b891cde91205e584c766e048f3999714f]*/ +/*[clinic end generated code: checksum=44ed958b891cde91205e584c766e048f3999714f]*/ { PyCursesWindowObject *cwself = (PyCursesWindowObject *)self; int coordinates_group = group_left_1; diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -16,11 +16,11 @@ #include "datetime.h" #undef Py_BUILD_CORE -/*[clinic] +/*[clinic input] module datetime class datetime.datetime -[clinic]*/ -/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +[clinic start generated code]*/ +/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ /* We require that C int be at least 32 bits, and use int virtually * everywhere. In just a few cases we use a temp long, where a Python @@ -4145,7 +4145,7 @@ tzinfo); } -/*[clinic] +/*[clinic input] @classmethod datetime.datetime.now @@ -4156,7 +4156,7 @@ Returns new datetime object representing current time local to tz. If no tz is specified, uses local timezone. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(datetime_datetime_now__doc__, "now(tz=None)\n" @@ -4192,7 +4192,7 @@ static PyObject * datetime_datetime_now_impl(PyTypeObject *cls, PyObject *tz) -/*[clinic checksum: ca3d26a423b3f633b260c7622e303f0915a96f7c]*/ +/*[clinic end generated code: checksum=ca3d26a423b3f633b260c7622e303f0915a96f7c]*/ { PyObject *self; diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c --- a/Modules/_dbmmodule.c +++ b/Modules/_dbmmodule.c @@ -28,11 +28,11 @@ #error "No ndbm.h available!" #endif -/*[clinic] +/*[clinic input] module dbm class dbm.dbm -[clinic]*/ -/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +[clinic start generated code]*/ +/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ typedef struct { PyObject_HEAD @@ -49,13 +49,13 @@ static PyObject *DbmError; -/*[python] +/*[python input] class dbmobject_converter(self_converter): type = "dbmobject *" def converter_init(self): self.name = 'dp' -[python]*/ -/*[python checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +[python start generated code]*/ +/*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ static PyObject * newdbmobject(const char *file, int flags, int mode) @@ -263,7 +263,7 @@ 0, /* sq_inplace_repeat */ }; -/*[clinic] +/*[clinic input] dbm.dbm.get @@ -276,7 +276,7 @@ / Return the value for key if present, otherwise default. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(dbm_dbm_get__doc__, "get(key, [default])\n" @@ -318,7 +318,7 @@ static PyObject * dbm_dbm_get_impl(dbmobject *dp, const char *key, Py_ssize_clean_t key_length, int group_right_1, PyObject *default_value) -/*[clinic checksum: 28cf8928811bde51e535d67ae98ea039d79df717]*/ +/*[clinic end generated code: checksum=28cf8928811bde51e535d67ae98ea039d79df717]*/ { datum dbm_key, val; @@ -440,7 +440,7 @@ /* ----------------------------------------------------------------- */ -/*[clinic] +/*[clinic input] dbm.open as dbmopen @@ -458,7 +458,7 @@ Return a database object. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(dbmopen__doc__, "open(filename, flags=\'r\', mode=0o666)\n" @@ -498,7 +498,7 @@ static PyObject * dbmopen_impl(PyModuleDef *module, const char *filename, const char *flags, int mode) -/*[clinic checksum: fb265f75641553ccd963f84c143b35c11f9121fc]*/ +/*[clinic end generated code: checksum=fb265f75641553ccd963f84c143b35c11f9121fc]*/ { int iflags; diff --git a/Modules/_opcode.c b/Modules/_opcode.c --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -1,12 +1,12 @@ #include "Python.h" #include "opcode.h" -/*[clinic] +/*[clinic input] module _opcode -[clinic]*/ -/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +[clinic start generated code]*/ +/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ -/*[clinic] +/*[clinic input] _opcode.stack_effect -> int @@ -18,7 +18,7 @@ / Compute the stack effect of the opcode. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(_opcode_stack_effect__doc__, "stack_effect(opcode, [oparg])\n" @@ -64,10 +64,10 @@ static int _opcode_stack_effect_impl(PyModuleDef *module, int opcode, int group_right_1, int oparg) -/*[clinic checksum: e880e62dc7b0de73403026eaf4f8074aa106358b]*/ +/*[clinic end generated code: checksum=e880e62dc7b0de73403026eaf4f8074aa106358b]*/ { int effect; - if (HAS_ARG(opcode)) { + if (HAS_ARG(opcode)) { if (!group_right_1) { PyErr_SetString(PyExc_ValueError, "stack_effect: opcode requires oparg but oparg was not specified"); diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -4,16 +4,16 @@ PyDoc_STRVAR(pickle_module_doc, "Optimized C implementation for the Python pickle module."); -/*[clinic] +/*[clinic input] module _pickle class _pickle.Pickler class _pickle.PicklerMemoProxy class _pickle.Unpickler class _pickle.UnpicklerMemoProxy -[clinic]*/ -/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ - -/*[python] +[clinic start generated code]*/ +/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + +/*[python input] class PicklerObject_converter(self_converter): type = "PicklerObject *" @@ -25,8 +25,8 @@ class UnpicklerMemoProxyObject_converter(self_converter): type = "UnpicklerMemoProxyObject *" -[python]*/ -/*[python checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +[python start generated code]*/ +/*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ /* Bump this when new opcodes are added to the pickle protocol. */ enum { @@ -140,7 +140,7 @@ PyObject *PickleError; PyObject *PicklingError; PyObject *UnpicklingError; - + /* copyreg.dispatch_table, {type_object: pickling_function} */ PyObject *dispatch_table; @@ -1770,7 +1770,7 @@ else if (self->bin && (sizeof(long) <= 4 || (val <= 0x7fffffffL && val >= (-0x7fffffffL - 1)))) { - /* result fits in a signed 4-byte integer. + /* result fits in a signed 4-byte integer. Note: we can't use -0x80000000L in the above condition because some compilers (e.g., MSVC) will promote 0x80000000L to an unsigned type @@ -3492,21 +3492,21 @@ cls = PyTuple_GET_ITEM(argtup, 0); if (!PyType_Check(cls)) { - PyErr_Format(st->PicklingError, + PyErr_Format(st->PicklingError, "first item from NEWOBJ_EX argument tuple must " "be a class, not %.200s", Py_TYPE(cls)->tp_name); return -1; } args = PyTuple_GET_ITEM(argtup, 1); if (!PyTuple_Check(args)) { - PyErr_Format(st->PicklingError, + PyErr_Format(st->PicklingError, "second item from NEWOBJ_EX argument tuple must " "be a tuple, not %.200s", Py_TYPE(args)->tp_name); return -1; } kwargs = PyTuple_GET_ITEM(argtup, 2); if (!PyDict_Check(kwargs)) { - PyErr_Format(st->PicklingError, + PyErr_Format(st->PicklingError, "third item from NEWOBJ_EX argument tuple must " "be a dict, not %.200s", Py_TYPE(kwargs)->tp_name); return -1; @@ -3874,7 +3874,7 @@ return 0; } -/*[clinic] +/*[clinic input] _pickle.Pickler.clear_memo @@ -3886,7 +3886,7 @@ pickler has already seen, so that shared or recursive objects are pickled by reference and not by value. This method is useful when re-using picklers. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(_pickle_Pickler_clear_memo__doc__, "clear_memo()\n" @@ -3915,7 +3915,7 @@ static PyObject * _pickle_Pickler_clear_memo_impl(PicklerObject *self) -/*[clinic checksum: 0574593b102fffb8e781d7bb9b536ceffc525ac1]*/ +/*[clinic end generated code: checksum=0574593b102fffb8e781d7bb9b536ceffc525ac1]*/ { if (self->memo) PyMemoTable_Clear(self->memo); @@ -3923,7 +3923,7 @@ Py_RETURN_NONE; } -/*[clinic] +/*[clinic input] _pickle.Pickler.dump @@ -3932,7 +3932,7 @@ / Write a pickled representation of the given object to the open file. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(_pickle_Pickler_dump__doc__, "dump(obj)\n" @@ -3943,7 +3943,7 @@ static PyObject * _pickle_Pickler_dump(PicklerObject *self, PyObject *obj) -/*[clinic checksum: b72a69ec98737fabf66dae7c5a3210178bdbd3e6]*/ +/*[clinic end generated code: checksum=b72a69ec98737fabf66dae7c5a3210178bdbd3e6]*/ { /* Check whether the Pickler was initialized correctly (issue3664). Developers often forget to call __init__() in their subclasses, which @@ -4018,7 +4018,7 @@ } -/*[clinic] +/*[clinic input] _pickle.Pickler.__init__ @@ -4045,7 +4045,7 @@ If *fix_imports* is True and protocol is less than 3, pickle will try to map the new Python 3 names to the old module names used in Python 2, so that the pickle data stream is readable with Python 2. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(_pickle_Pickler___init____doc__, "__init__(file, protocol=None, fix_imports=True)\n" @@ -4095,7 +4095,7 @@ static PyObject * _pickle_Pickler___init___impl(PicklerObject *self, PyObject *file, PyObject *protocol, int fix_imports) -/*[clinic checksum: 2b5ce6452544600478cf9f4b701ab9d9b5efbab9]*/ +/*[clinic end generated code: checksum=2b5ce6452544600478cf9f4b701ab9d9b5efbab9]*/ { _Py_IDENTIFIER(persistent_id); _Py_IDENTIFIER(dispatch_table); @@ -4173,13 +4173,13 @@ PicklerObject *pickler; /* Pickler whose memo table we're proxying. */ } PicklerMemoProxyObject; -/*[clinic] +/*[clinic input] _pickle.PicklerMemoProxy.clear self: PicklerMemoProxyObject Remove all items from memo. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(_pickle_PicklerMemoProxy_clear__doc__, "clear()\n" @@ -4203,20 +4203,20 @@ static PyObject * _pickle_PicklerMemoProxy_clear_impl(PicklerMemoProxyObject *self) -/*[clinic checksum: c6ca252530ccb3ea2f4b33507b51b183f23b24c7]*/ +/*[clinic end generated code: checksum=c6ca252530ccb3ea2f4b33507b51b183f23b24c7]*/ { if (self->pickler->memo) PyMemoTable_Clear(self->pickler->memo); Py_RETURN_NONE; } -/*[clinic] +/*[clinic input] _pickle.PicklerMemoProxy.copy self: PicklerMemoProxyObject Copy the memo to a new object. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(_pickle_PicklerMemoProxy_copy__doc__, "copy()\n" @@ -4240,7 +4240,7 @@ static PyObject * _pickle_PicklerMemoProxy_copy_impl(PicklerMemoProxyObject *self) -/*[clinic checksum: 808c4d5a37359ed5fb2efe81dbe5ff480719f470]*/ +/*[clinic end generated code: checksum=808c4d5a37359ed5fb2efe81dbe5ff480719f470]*/ { Py_ssize_t i; PyMemoTable *memo; @@ -4277,13 +4277,13 @@ return NULL; } -/*[clinic] +/*[clinic input] _pickle.PicklerMemoProxy.__reduce__ self: PicklerMemoProxyObject Implement pickle support. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(_pickle_PicklerMemoProxy___reduce____doc__, "__reduce__()\n" @@ -4307,7 +4307,7 @@ static PyObject * _pickle_PicklerMemoProxy___reduce___impl(PicklerMemoProxyObject *self) -/*[clinic checksum: 2293152bdf53951a012d430767b608f5fb4213b5]*/ +/*[clinic end generated code: checksum=2293152bdf53951a012d430767b608f5fb4213b5]*/ { PyObject *reduce_value, *dict_args; PyObject *contents = _pickle_PicklerMemoProxy_copy_impl(self); @@ -5348,12 +5348,12 @@ Py_DECREF(args); return -1; } - + if (!PyType_Check(cls)) { Py_DECREF(kwargs); Py_DECREF(args); Py_DECREF(cls); - PyErr_Format(st->UnpicklingError, + PyErr_Format(st->UnpicklingError, "NEWOBJ_EX class argument must be a type, not %.200s", Py_TYPE(cls)->tp_name); return -1; @@ -6317,7 +6317,7 @@ return value; } -/*[clinic] +/*[clinic input] _pickle.Unpickler.load @@ -6326,7 +6326,7 @@ Read a pickled object representation from the open file object given in the constructor, and return the reconstituted object hierarchy specified therein. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(_pickle_Unpickler_load__doc__, "load()\n" @@ -6354,7 +6354,7 @@ static PyObject * _pickle_Unpickler_load_impl(PyObject *self) -/*[clinic checksum: 55f35fcaf034817e75c355ec50b7878577355899]*/ +/*[clinic end generated code: checksum=55f35fcaf034817e75c355ec50b7878577355899]*/ { UnpicklerObject *unpickler = (UnpicklerObject*)self; @@ -6377,7 +6377,7 @@ function is used for loading any global (i.e., functions), not just classes. The name is kept only for backward compatibility. */ -/*[clinic] +/*[clinic input] _pickle.Unpickler.find_class @@ -6394,7 +6394,7 @@ This method is called whenever a class or a function object is needed. Both arguments passed are str objects. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(_pickle_Unpickler_find_class__doc__, "find_class(module_name, global_name)\n" @@ -6432,7 +6432,7 @@ static PyObject * _pickle_Unpickler_find_class_impl(UnpicklerObject *self, PyObject *module_name, PyObject *global_name) -/*[clinic checksum: 1f353d13a32c9d94feb1466b3c2d0529a7e5650e]*/ +/*[clinic end generated code: checksum=1f353d13a32c9d94feb1466b3c2d0529a7e5650e]*/ { PyObject *global; PyObject *modules_dict; @@ -6581,7 +6581,7 @@ return 0; } -/*[clinic] +/*[clinic input] _pickle.Unpickler.__init__ @@ -6612,7 +6612,7 @@ instances pickled by Python 2; these default to 'ASCII' and 'strict', respectively. The *encoding* can be 'bytes' to read these 8-bit string instances as bytes objects. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(_pickle_Unpickler___init____doc__, "__init__(file, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" @@ -6665,7 +6665,7 @@ static PyObject * _pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file, int fix_imports, const char *encoding, const char *errors) -/*[clinic checksum: 9ce6783224e220573d42a94fe1bb7199d6f1c5a6]*/ +/*[clinic end generated code: checksum=9ce6783224e220573d42a94fe1bb7199d6f1c5a6]*/ { _Py_IDENTIFIER(persistent_load); @@ -6737,13 +6737,13 @@ UnpicklerObject *unpickler; } UnpicklerMemoProxyObject; -/*[clinic] +/*[clinic input] _pickle.UnpicklerMemoProxy.clear self: UnpicklerMemoProxyObject Remove all items from memo. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(_pickle_UnpicklerMemoProxy_clear__doc__, "clear()\n" @@ -6767,7 +6767,7 @@ static PyObject * _pickle_UnpicklerMemoProxy_clear_impl(UnpicklerMemoProxyObject *self) -/*[clinic checksum: e0f99c26d48444a3f58f598bec3190c66595fce7]*/ +/*[clinic end generated code: checksum=e0f99c26d48444a3f58f598bec3190c66595fce7]*/ { _Unpickler_MemoCleanup(self->unpickler); self->unpickler->memo = _Unpickler_NewMemo(self->unpickler->memo_size); @@ -6776,13 +6776,13 @@ Py_RETURN_NONE; } -/*[clinic] +/*[clinic input] _pickle.UnpicklerMemoProxy.copy self: UnpicklerMemoProxyObject Copy the memo to a new object. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(_pickle_UnpicklerMemoProxy_copy__doc__, "copy()\n" @@ -6806,7 +6806,7 @@ static PyObject * _pickle_UnpicklerMemoProxy_copy_impl(UnpicklerMemoProxyObject *self) -/*[clinic checksum: 8c0ab91c0b694ea71a1774650898a760d1ab4765]*/ +/*[clinic end generated code: checksum=8c0ab91c0b694ea71a1774650898a760d1ab4765]*/ { Py_ssize_t i; PyObject *new_memo = PyDict_New(); @@ -6836,13 +6836,13 @@ return NULL; } -/*[clinic] +/*[clinic input] _pickle.UnpicklerMemoProxy.__reduce__ self: UnpicklerMemoProxyObject Implement pickling support. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(_pickle_UnpicklerMemoProxy___reduce____doc__, "__reduce__()\n" @@ -6866,7 +6866,7 @@ static PyObject * _pickle_UnpicklerMemoProxy___reduce___impl(UnpicklerMemoProxyObject *self) -/*[clinic checksum: 4ee76a65511291f0de2e9e63db395d2e5d6d8df6]*/ +/*[clinic end generated code: checksum=4ee76a65511291f0de2e9e63db395d2e5d6d8df6]*/ { PyObject *reduce_value; PyObject *constructor_args; @@ -7141,7 +7141,7 @@ 0, /*tp_is_gc*/ }; -/*[clinic] +/*[clinic input] _pickle.dump @@ -7172,7 +7172,7 @@ If *fix_imports* is True and protocol is less than 3, pickle will try to map the new Python 3 names to the old module names used in Python 2, so that the pickle data stream is readable with Python 2. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(_pickle_dump__doc__, "dump(obj, file, protocol=None, *, fix_imports=True)\n" @@ -7226,7 +7226,7 @@ static PyObject * _pickle_dump_impl(PyModuleDef *module, PyObject *obj, PyObject *file, PyObject *protocol, int fix_imports) -/*[clinic checksum: eb5c23e64da34477178230b704d2cc9c6b6650ea]*/ +/*[clinic end generated code: checksum=eb5c23e64da34477178230b704d2cc9c6b6650ea]*/ { PicklerObject *pickler = _Pickler_New(); @@ -7253,7 +7253,7 @@ return NULL; } -/*[clinic] +/*[clinic input] _pickle.dumps @@ -7275,7 +7275,7 @@ If *fix_imports* is True and *protocol* is less than 3, pickle will try to map the new Python 3 names to the old module names used in Python 2, so that the pickle data stream is readable with Python 2. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(_pickle_dumps__doc__, "dumps(obj, protocol=None, *, fix_imports=True)\n" @@ -7320,7 +7320,7 @@ static PyObject * _pickle_dumps_impl(PyModuleDef *module, PyObject *obj, PyObject *protocol, int fix_imports) -/*[clinic checksum: e9b915d61202a9692cb6c6718db74fe54fc9c4d1]*/ +/*[clinic end generated code: checksum=e9b915d61202a9692cb6c6718db74fe54fc9c4d1]*/ { PyObject *result; PicklerObject *pickler = _Pickler_New(); @@ -7343,7 +7343,7 @@ return NULL; } -/*[clinic] +/*[clinic input] _pickle.load @@ -7376,7 +7376,7 @@ instances pickled by Python 2; these default to 'ASCII' and 'strict', respectively. The *encoding* can be 'bytes' to read these 8-bit string instances as bytes objects. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(_pickle_load__doc__, "load(file, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" @@ -7432,7 +7432,7 @@ static PyObject * _pickle_load_impl(PyModuleDef *module, PyObject *file, int fix_imports, const char *encoding, const char *errors) -/*[clinic checksum: b41f06970e57acf2fd602e4b7f88e3f3e1e53087]*/ +/*[clinic end generated code: checksum=b41f06970e57acf2fd602e4b7f88e3f3e1e53087]*/ { PyObject *result; UnpicklerObject *unpickler = _Unpickler_New(); @@ -7457,7 +7457,7 @@ return NULL; } -/*[clinic] +/*[clinic input] _pickle.loads @@ -7481,7 +7481,7 @@ instances pickled by Python 2; these default to 'ASCII' and 'strict', respectively. The *encoding* can be 'bytes' to read these 8-bit string instances as bytes objects. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(_pickle_loads__doc__, "loads(data, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" @@ -7528,7 +7528,7 @@ static PyObject * _pickle_loads_impl(PyModuleDef *module, PyObject *data, int fix_imports, const char *encoding, const char *errors) -/*[clinic checksum: 0663de43aca6c21508a777e29d98c9c3a6e7f72d]*/ +/*[clinic end generated code: checksum=0663de43aca6c21508a777e29d98c9c3a6e7f72d]*/ { PyObject *result; UnpicklerObject *unpickler = _Unpickler_New(); diff --git a/Modules/_weakref.c b/Modules/_weakref.c --- a/Modules/_weakref.c +++ b/Modules/_weakref.c @@ -4,12 +4,12 @@ #define GET_WEAKREFS_LISTPTR(o) \ ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o)) -/*[clinic] +/*[clinic input] module _weakref -[clinic]*/ -/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +[clinic start generated code]*/ +/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ -/*[clinic] +/*[clinic input] _weakref.getweakrefcount -> Py_ssize_t @@ -17,7 +17,7 @@ / Return the number of weak references to 'object'. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(_weakref_getweakrefcount__doc__, "getweakrefcount(object)\n" @@ -45,13 +45,13 @@ static Py_ssize_t _weakref_getweakrefcount_impl(PyModuleDef *module, PyObject *object) -/*[clinic checksum: 436e8fbe0297434375f039d8c2d9fc3a9bbe773c]*/ +/*[clinic end generated code: checksum=436e8fbe0297434375f039d8c2d9fc3a9bbe773c]*/ { PyWeakReference **list; if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))) return 0; - + list = GET_WEAKREFS_LISTPTR(object); return _PyWeakref_GetWeakrefCount(*list); } diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -181,10 +181,10 @@ #endif /* ! __WATCOMC__ || __QNX__ */ -/*[clinic] +/*[clinic input] module os -[clinic]*/ -/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +[clinic start generated code]*/ +/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ #ifndef _MSC_VER @@ -2355,7 +2355,7 @@ #endif -/*[python] +/*[python input] class path_t_converter(CConverter): @@ -2396,10 +2396,10 @@ self.c_default = 'DEFAULT_DIR_FD' -[python]*/ -/*[python checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ - -/*[clinic] +[python start generated code]*/ +/*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + +/*[clinic input] os.stat -> object(doc_default='stat_result') @@ -2427,7 +2427,7 @@ It's an error to use dir_fd or follow_symlinks when specifying path as an open file descriptor. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(os_stat__doc__, "stat(path, *, dir_fd=None, follow_symlinks=True)\n" @@ -2481,7 +2481,7 @@ static PyObject * os_stat_impl(PyModuleDef *module, path_t *path, int dir_fd, int follow_symlinks) -/*[clinic checksum: 85a71ad602e89f8e280118da976f70cd2f9abdf1]*/ +/*[clinic end generated code: checksum=85a71ad602e89f8e280118da976f70cd2f9abdf1]*/ { return posix_do_stat("stat", path, dir_fd, follow_symlinks); } @@ -2522,7 +2522,7 @@ #else #define OS_ACCESS_DIR_FD_CONVERTER dir_fd_unavailable #endif -/*[clinic] +/*[clinic input] os.access -> object(doc_default='True if granted, False otherwise') path: path_t(allow_fd=True) @@ -2559,7 +2559,7 @@ routine can be used in a suid/sgid environment to test if the invoking user has the specified access to the path. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(os_access__doc__, "access(path, mode, *, dir_fd=None, effective_ids=False, follow_symlinks=True)\n" @@ -2622,7 +2622,7 @@ static PyObject * os_access_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd, int effective_ids, int follow_symlinks) -/*[clinic checksum: 636e835c36562a2fc11acab75314634127fdf769]*/ +/*[clinic end generated code: checksum=636e835c36562a2fc11acab75314634127fdf769]*/ { PyObject *return_value = NULL; @@ -2706,7 +2706,7 @@ #ifdef HAVE_TTYNAME -/*[clinic] +/*[clinic input] os.ttyname -> DecodeFSDefault fd: int @@ -2715,7 +2715,7 @@ / Return the name of the terminal device connected to 'fd'. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(os_ttyname__doc__, "ttyname(fd)\n" @@ -2752,7 +2752,7 @@ static char * os_ttyname_impl(PyModuleDef *module, int fd) -/*[clinic checksum: 0f368134dc0a7f21f25185e2e6bacf7675fb473a]*/ +/*[clinic end generated code: checksum=0f368134dc0a7f21f25185e2e6bacf7675fb473a]*/ { char *ret; diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -17,11 +17,11 @@ #include "ucnhash.h" #include "structmember.h" -/*[clinic] +/*[clinic input] module unicodedata class unicodedata.UCD -[clinic]*/ -/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +[clinic start generated code]*/ +/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ /* character properties */ @@ -113,7 +113,7 @@ /* --- Module API --------------------------------------------------------- */ -/*[clinic] +/*[clinic input] unicodedata.UCD.decimal @@ -126,7 +126,7 @@ Returns the decimal value assigned to the Unicode character unichr as integer. If no such value is defined, default is returned, or, if not given, ValueError is raised. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(unicodedata_UCD_decimal__doc__, "decimal(unichr, default=None)\n" @@ -161,7 +161,7 @@ static PyObject * unicodedata_UCD_decimal_impl(PyObject *self, PyUnicodeObject *unichr, PyObject *default_value) -/*[clinic checksum: 73edde0e9cd5913ea174c4fa81504369761b7426]*/ +/*[clinic end generated code: checksum=73edde0e9cd5913ea174c4fa81504369761b7426]*/ { PyUnicodeObject *v = (PyUnicodeObject *)unichr; int have_old = 0; diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -81,12 +81,12 @@ PyErr_Format(ZlibError, "Error %d %s: %.200s", err, msg, zmsg); } -/*[clinic] +/*[clinic input] module zlib class zlib.Compress class zlib.Decompress -[clinic]*/ -/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +[clinic start generated code]*/ +/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ PyDoc_STRVAR(compressobj__doc__, "compressobj(level=-1, method=DEFLATED, wbits=15, memlevel=8,\n" @@ -164,7 +164,7 @@ PyMem_RawFree(ptr); } -/*[clinic] +/*[clinic input] zlib.compress bytes: Py_buffer @@ -177,7 +177,7 @@ Returns compressed string. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(zlib_compress__doc__, "compress(bytes, [level])\n" @@ -227,7 +227,7 @@ static PyObject * zlib_compress_impl(PyModuleDef *module, Py_buffer *bytes, int group_right_1, int level) -/*[clinic checksum: 9f055a396620bc1a8a13d74c3496249528b32b0d]*/ +/*[clinic end generated code: checksum=9f055a396620bc1a8a13d74c3496249528b32b0d]*/ { PyObject *ReturnVal = NULL; Byte *input, *output = NULL; @@ -306,14 +306,14 @@ return ReturnVal; } -/*[python] +/*[python input] class uint_converter(CConverter): type = 'unsigned int' converter = 'uint_converter' -[python]*/ -/*[python checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +[python start generated code]*/ +/*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ static int uint_converter(PyObject *obj, void *ptr) @@ -743,7 +743,7 @@ return 0; } -/*[clinic] +/*[clinic input] zlib.Decompress.decompress @@ -762,7 +762,7 @@ After calling this function, some of the input data may still be stored in internal buffers for later processing. Call the flush() method to clear these buffers. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(zlib_Decompress_decompress__doc__, "decompress(data, max_length=0)\n" @@ -808,7 +808,7 @@ static PyObject * zlib_Decompress_decompress_impl(compobject *self, Py_buffer *data, unsigned int max_length) -/*[clinic checksum: 5b1e4f9f1ef8eca55fff78356f9df0c81232ed3b]*/ +/*[clinic end generated code: checksum=5b1e4f9f1ef8eca55fff78356f9df0c81232ed3b]*/ { int err; unsigned int old_length, length = DEFAULTALLOC; @@ -1026,13 +1026,13 @@ #ifdef HAVE_ZLIB_COPY -/*[clinic] +/*[clinic input] zlib.Compress.copy self: self(type="compobject *") Return a copy of the compression object. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(zlib_Compress_copy__doc__, "copy()\n" @@ -1056,7 +1056,7 @@ static PyObject * zlib_Compress_copy_impl(compobject *self) -/*[clinic checksum: 2f454ee15be3bc53cfb4e845c3f891f68be4c8e4]*/ +/*[clinic end generated code: checksum=2f454ee15be3bc53cfb4e845c3f891f68be4c8e4]*/ { compobject *retval = NULL; int err; diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -69,10 +69,10 @@ #include "Python.h" #include "stringlib/eq.h" -/*[clinic] +/*[clinic input] class dict -[clinic]*/ -/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +[clinic start generated code]*/ +/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ typedef struct { /* Cached hash code of me_key. */ @@ -2164,7 +2164,7 @@ return res; } -/*[clinic] +/*[clinic input] @coexist dict.__contains__ @@ -2173,7 +2173,7 @@ / True if D has a key k, else False" -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(dict___contains____doc__, "__contains__(key)\n" @@ -2184,7 +2184,7 @@ static PyObject * dict___contains__(PyObject *self, PyObject *key) -/*[clinic checksum: 3bbac5ce898ae630d9668fa1c8b3afb645ff22e8]*/ +/*[clinic end generated code: checksum=3bbac5ce898ae630d9668fa1c8b3afb645ff22e8]*/ { register PyDictObject *mp = (PyDictObject *)self; Py_hash_t hash; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -47,10 +47,10 @@ #include #endif -/*[clinic] +/*[clinic input] class str -[clinic]*/ -/*[clinic checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +[clinic start generated code]*/ +/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ /* --- Globals ------------------------------------------------------------ @@ -12860,7 +12860,7 @@ return case_operation(self, do_swapcase); } -/*[clinic] +/*[clinic input] @staticmethod str.maketrans as unicode_maketrans @@ -12882,7 +12882,7 @@ 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. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(unicode_maketrans__doc__, "maketrans(x, y=None, z=None)\n" @@ -12922,7 +12922,7 @@ static PyObject * unicode_maketrans_impl(void *null, PyObject *x, PyObject *y, PyObject *z) -/*[clinic checksum: 7f76f414a0dfd0c614e0d4717872eeb520516da7]*/ +/*[clinic end generated code: checksum=7f76f414a0dfd0c614e0d4717872eeb520516da7]*/ { PyObject *new = NULL, *key, *value; Py_ssize_t i = 0; diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -291,10 +291,10 @@ class PythonLanguage(Language): language = 'Python' - start_line = "#/*[{dsl_name}]" + start_line = "#/*[{dsl_name} input]" body_prefix = "#" - stop_line = "#[{dsl_name}]*/" - checksum_line = "#/*[{dsl_name} checksum: {checksum}]*/" + stop_line = "#[{dsl_name} start generated code]*/" + checksum_line = "#/*[{dsl_name} end generated code: checksum={checksum}]*/" def permute_left_option_groups(l): @@ -359,11 +359,12 @@ class CLanguage(Language): + body_prefix = "#" language = 'C' - start_line = "/*[{dsl_name}]" + start_line = "/*[{dsl_name} input]" body_prefix = "" - stop_line = "[{dsl_name}]*/" - checksum_line = "/*[{dsl_name} checksum: {checksum}]*/" + stop_line = "[{dsl_name} start generated code]*/" + checksum_line = "/*[{dsl_name} end generated code: checksum={checksum}]*/" def render(self, signatures): function = None -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 7 21:52:53 2014 From: python-checkins at python.org (brett.cannon) Date: Tue, 7 Jan 2014 21:52:53 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2319719=3A_Update_v?= =?utf-8?q?arious_finder_and_loader_ABCs_such_that_their?= Message-ID: <3dzQlT49jZz7LjQ@mail.python.org> http://hg.python.org/cpython/rev/21786a7f8036 changeset: 88345:21786a7f8036 user: Brett Cannon date: Tue Jan 07 15:52:42 2014 -0500 summary: Issue #19719: Update various finder and loader ABCs such that their old methods now provide implementations when PEP 451 APIs are present. This should help with backwards-compatibility with code which has not been updated to work with PEP 451. files: Doc/library/importlib.rst | 16 +- Lib/importlib/abc.py | 32 +++- Lib/test/test_importlib/test_abc.py | 132 ++++++++++++++++ Misc/NEWS | 4 + 4 files changed, 176 insertions(+), 8 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -275,9 +275,13 @@ will be the value of :attr:`__path__` from the parent package. If a loader cannot be found, ``None`` is returned. + If :meth:`find_spec` is defined, backwards-compatible functionality is + provided. + .. versionchanged:: 3.4 Returns ``None`` when called instead of raising - :exc:`NotImplementedError`. + :exc:`NotImplementedError`. Can use :meth:`find_spec` to provide + functionality. .. deprecated:: 3.4 Use :meth:`find_spec` instead. @@ -325,8 +329,12 @@ ``portion`` is the empty list then no loader or location for a namespace package were found (i.e. failure to find anything for the module). + If :meth:`find_spec` is defined then backwards-compatible functionality is + provided. + .. versionchanged:: 3.4 Returns ``(None, [])`` instead of raising :exc:`NotImplementedError`. + Uses :meth:`find_spec` when available to provide functionality. .. deprecated:: 3.4 Use :meth:`find_spec` instead. @@ -413,9 +421,13 @@ :func:`importlib.util.module_for_loader` decorator can handle the details for :attr:`__package__`. + When :meth:`exec_module` is available then backwards-compatible + functionality is provided. + .. versionchanged:: 3.4 Raise :exc:`ImportError` when called instead of - :exc:`NotImplementedError`. + :exc:`NotImplementedError`. Functionality provided when + :meth:`exec_module` is available. .. deprecated:: 3.4 The recommended API for loading a module is :meth:`exec_module` diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py --- a/Lib/importlib/abc.py +++ b/Lib/importlib/abc.py @@ -49,10 +49,15 @@ If no module is found, return None. The fullname is a str and the path is a list of strings or None. - This method is deprecated in favor of finder.find_spec(). + This method is deprecated in favor of finder.find_spec(). If find_spec() + exists then backwards-compatible functionality is provided for this + method. """ - return None + if not hasattr(self, 'find_spec'): + return None + found = self.find_spec(fullname, path) + return found.loader if found is not None else None def invalidate_caches(self): """An optional method for clearing the finder's cache, if any. @@ -81,10 +86,21 @@ The portion will be discarded if another path entry finder locates the module as a normal module or package. - This method is deprecated in favor of finder.find_spec(). + This method is deprecated in favor of finder.find_spec(). If find_spec() + is provided than backwards-compatible functionality is provided. """ - return None, [] + if not hasattr(self, 'find_spec'): + return None, [] + found = self.find_spec(fullname) + if found is not None: + if not found.submodule_search_locations: + portions = [] + else: + portions = found.submodule_search_locations + return found.loader, portions + else: + return None, [] find_module = _bootstrap._find_module_shim @@ -124,10 +140,14 @@ ImportError is raised on failure. - This method is deprecated in favor of loader.exec_module(). + This method is deprecated in favor of loader.exec_module(). If + exec_module() exists then it is used to provide a backwards-compatible + functionality for this method. """ - raise ImportError + if not hasattr(self, 'exec_module'): + raise ImportError + return _bootstrap._load_module_shim(self, fullname) def module_repr(self, module): """Return a module's repr. diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py --- a/Lib/test/test_importlib/test_abc.py +++ b/Lib/test/test_importlib/test_abc.py @@ -14,6 +14,7 @@ frozen_init, source_init = util.import_importlib('importlib') frozen_abc, source_abc = util.import_importlib('importlib.abc') +machinery = util.import_importlib('importlib.machinery') frozen_util, source_util = util.import_importlib('importlib.util') ##### Inheritance ############################################################## @@ -285,6 +286,137 @@ tests = make_return_value_tests(ExecutionLoader, InspectLoaderDefaultsTests) Frozen_ELDefaultTests, Source_ELDefaultsTests = tests +##### MetaPathFinder concrete methods ########################################## + +class MetaPathFinderFindModuleTests: + + @classmethod + def finder(cls, spec): + class MetaPathSpecFinder(cls.abc.MetaPathFinder): + + def find_spec(self, fullname, path, target=None): + self.called_for = fullname, path + return spec + + return MetaPathSpecFinder() + + def test_no_spec(self): + finder = self.finder(None) + path = ['a', 'b', 'c'] + name = 'blah' + found = finder.find_module(name, path) + self.assertIsNone(found) + self.assertEqual(name, finder.called_for[0]) + self.assertEqual(path, finder.called_for[1]) + + def test_spec(self): + loader = object() + spec = self.util.spec_from_loader('blah', loader) + finder = self.finder(spec) + found = finder.find_module('blah', None) + self.assertIs(found, spec.loader) + + +Frozen_MPFFindModuleTests, Source_MPFFindModuleTests = util.test_both( + MetaPathFinderFindModuleTests, + abc=(frozen_abc, source_abc), + util=(frozen_util, source_util)) + +##### PathEntryFinder concrete methods ######################################### + +class PathEntryFinderFindLoaderTests: + + @classmethod + def finder(cls, spec): + class PathEntrySpecFinder(cls.abc.PathEntryFinder): + + def find_spec(self, fullname, target=None): + self.called_for = fullname + return spec + + return PathEntrySpecFinder() + + def test_no_spec(self): + finder = self.finder(None) + name = 'blah' + found = finder.find_loader(name) + self.assertIsNone(found[0]) + self.assertEqual([], found[1]) + self.assertEqual(name, finder.called_for) + + def test_spec_with_loader(self): + loader = object() + spec = self.util.spec_from_loader('blah', loader) + finder = self.finder(spec) + found = finder.find_loader('blah') + self.assertIs(found[0], spec.loader) + + def test_spec_with_portions(self): + spec = self.machinery.ModuleSpec('blah', None) + paths = ['a', 'b', 'c'] + spec.submodule_search_locations = paths + finder = self.finder(spec) + found = finder.find_loader('blah') + self.assertIsNone(found[0]) + self.assertEqual(paths, found[1]) + + +Frozen_PEFFindLoaderTests, Source_PEFFindLoaderTests = util.test_both( + PathEntryFinderFindLoaderTests, + abc=(frozen_abc, source_abc), + machinery=machinery, + util=(frozen_util, source_util)) + + +##### Loader concrete methods ################################################## +class LoaderLoadModuleTests: + + def loader(self): + class SpecLoader(self.abc.Loader): + found = None + def exec_module(self, module): + self.found = module + + def is_package(self, fullname): + """Force some non-default module state to be set.""" + return True + + return SpecLoader() + + def test_fresh(self): + loader = self.loader() + name = 'blah' + with util.uncache(name): + loader.load_module(name) + module = loader.found + self.assertIs(sys.modules[name], module) + self.assertEqual(loader, module.__loader__) + self.assertEqual(loader, module.__spec__.loader) + self.assertEqual(name, module.__name__) + self.assertEqual(name, module.__spec__.name) + self.assertIsNotNone(module.__path__) + self.assertIsNotNone(module.__path__, + module.__spec__.submodule_search_locations) + + def test_reload(self): + name = 'blah' + loader = self.loader() + module = types.ModuleType(name) + module.__spec__ = self.util.spec_from_loader(name, loader) + module.__loader__ = loader + with util.uncache(name): + sys.modules[name] = module + loader.load_module(name) + found = loader.found + self.assertIs(found, sys.modules[name]) + self.assertIs(module, sys.modules[name]) + + +Frozen_LoaderLoadModuleTests, Source_LoaderLoadModuleTests = util.test_both( + LoaderLoadModuleTests, + abc=(frozen_abc, source_abc), + util=(frozen_util, source_util)) + ##### InspectLoader concrete methods ########################################### class InspectLoaderSourceToCodeTests: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,10 @@ Library ------- +- Issue #19719: Make importlib.abc.MetaPathFinder.find_module(), + PathEntryFinder.find_loader(), and Loader.load_module() use PEP 451 APIs to + help with backwards-compatibility. + - Issue #20144: inspect.Signature now supports parsing simple symbolic constants as parameter default values in __text_signature__. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 7 23:01:12 2014 From: python-checkins at python.org (brett.cannon) Date: Tue, 7 Jan 2014 23:01:12 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2312837=3A_Silence_?= =?utf-8?q?a_Clang_compiler_warning_on_OS_X=2E?= Message-ID: <3dzSGJ3l02z7LjY@mail.python.org> http://hg.python.org/cpython/rev/407c9c297ff7 changeset: 88346:407c9c297ff7 user: Brett Cannon date: Tue Jan 07 17:01:01 2014 -0500 summary: Issue #12837: Silence a Clang compiler warning on OS X. Now makes CPython build without warnings on OS X under Clang with -Wno-unused-value -Wno-empty-body -Qunused-arguments -Wno-deprecated-declarations. Thanks to David Watson for taking an initial stab at a solution. files: Misc/NEWS | 6 ++++++ Modules/socketmodule.c | 16 +++++++++++++++- 2 files changed, 21 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,12 @@ - Issue #20142: Py_buffer variables generated by Argument Clinic are now initialized with a default value. +Build +----- + +- Issue #12837: Silence a tautological comparison warning on OS X under Clang in + socketmodule.c. + What's New in Python 3.4.0 Beta 2? ================================== diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -1885,8 +1885,22 @@ sizeof(cmsgh->cmsg_len)); /* Note that POSIX allows msg_controllen to be of signed type. */ - if (cmsgh == NULL || msg->msg_control == NULL || msg->msg_controllen < 0) + if (cmsgh == NULL || msg->msg_control == NULL) return 0; + /* Note that POSIX allows msg_controllen to be of a signed type. This is + annoying under OS X as it's unsigned there and so it triggers a + tautological comparison warning under Clang when compared against 0. + Since the check is valid on other platforms, silence the warning under + Clang. */ + #ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wtautological-compare" + #endif + if (msg->msg_controllen < 0) + return 0; + #ifdef __clang__ + #pragma clang diagnostic pop + #endif if (space < cmsg_len_end) space = cmsg_len_end; cmsg_offset = (char *)cmsgh - (char *)msg->msg_control; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 7 23:03:29 2014 From: python-checkins at python.org (zach.ware) Date: Tue, 7 Jan 2014 23:03:29 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2319723=3A_Fix_issu?= =?utf-8?q?e_number_typo_in_Misc/NEWS?= Message-ID: <3dzSJx6bs6z7Ljn@mail.python.org> http://hg.python.org/cpython/rev/aa153113d273 changeset: 88347:aa153113d273 user: Zachary Ware date: Tue Jan 07 16:01:28 2014 -0600 summary: Issue #19723: Fix issue number typo in Misc/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 @@ -25,7 +25,7 @@ Tools/Demos ----------- -- Issue #19273: The marker comments Argument Clinic uses have been changed +- Issue #19723: The marker comments Argument Clinic uses have been changed to improve readability. - Issue #20157: When Argument Clinic renames a parameter because its name -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 7 23:25:58 2014 From: python-checkins at python.org (larry.hastings) Date: Tue, 7 Jan 2014 23:25:58 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2319723=3A_Missed_o?= =?utf-8?q?ne_conversion_to_the_new_Argument_Clinic_syntax=2E?= Message-ID: <3dzSpt31vqz7Ljt@mail.python.org> http://hg.python.org/cpython/rev/e634b377d5cc changeset: 88348:e634b377d5cc user: Larry Hastings date: Tue Jan 07 14:25:26 2014 -0800 summary: Issue #19723: Missed one conversion to the new Argument Clinic syntax. files: Modules/_sre.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/_sre.c b/Modules/_sre.c --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -526,7 +526,7 @@ return sre_ucs4_search(state, pattern); } -/*[clinic] +/*[clinic input] module _sre class _sre.SRE_Pattern @@ -538,7 +538,7 @@ endpos: Py_ssize_t(c_default="PY_SSIZE_T_MAX") = sys.maxsize Matches zero or more characters at the beginning of the string. -[clinic]*/ +[clinic start generated code]*/ PyDoc_STRVAR(pattern_match__doc__, "match(pattern, pos=0, endpos=sys.maxsize)\n" @@ -571,7 +571,7 @@ static PyObject * pattern_match_impl(PatternObject *self, PyObject *pattern, Py_ssize_t pos, Py_ssize_t endpos) -/*[clinic checksum: 63e59c5f3019efe6c1f3acdec42b2d3595e14a09]*/ +/*[clinic end generated code: checksum=63e59c5f3019efe6c1f3acdec42b2d3595e14a09]*/ { SRE_STATE state; Py_ssize_t status; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 8 02:03:33 2014 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 8 Jan 2014 02:03:33 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_typo_in_asyncio/stream?= =?utf-8?b?cy5weS4=?= Message-ID: <3dzXJj2JYBz7LjM@mail.python.org> http://hg.python.org/cpython/rev/a9bffe9bdeab changeset: 88349:a9bffe9bdeab user: Guido van Rossum date: Tue Jan 07 17:03:26 2014 -0800 summary: Fix typo in asyncio/streams.py. files: Lib/asyncio/streams.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -199,7 +199,7 @@ drained and the protocol is resumed. """ if self._reader._exception is not None: - raise self._writer._exception + raise self._reader._exception if self._transport._conn_lost: # Uses private variable. raise ConnectionResetError('Connection lost') if not self._protocol._paused: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 8 03:34:47 2014 From: python-checkins at python.org (gregory.p.smith) Date: Wed, 8 Jan 2014 03:34:47 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Fixes_Issue_?= =?utf-8?q?=2319081=3A_When_a_zipimport_=2Ezip_file_in_sys=2Epath_being_im?= =?utf-8?q?ported_from?= Message-ID: <3dzZKz0zTDz7LjZ@mail.python.org> http://hg.python.org/cpython/rev/2807a5f011e4 changeset: 88350:2807a5f011e4 branch: 3.3 parent: 88337:2d81d0d42ae2 user: Gregory P. Smith date: Tue Jan 07 18:30:07 2014 -0800 summary: Fixes Issue #19081: When a zipimport .zip file in sys.path being imported from is modified during the lifetime of the Python process after zipimport has already cached the zip's table of contents we detect this and recover rather than read bad data from the .zip (causing odd import errors). files: Lib/test/test_zipimport.py | 104 +++++++- Misc/NEWS | 5 + Modules/zipimport.c | 285 ++++++++++++++++++++---- 3 files changed, 328 insertions(+), 66 deletions(-) diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py --- a/Lib/test/test_zipimport.py +++ b/Lib/test/test_zipimport.py @@ -46,6 +46,27 @@ pyc_ext = ('.pyc' if __debug__ else '.pyo') +def _write_zip_package(zipname, files, + data_to_prepend=b"", compression=ZIP_STORED): + z = ZipFile(zipname, "w") + try: + for name, (mtime, data) in files.items(): + zinfo = ZipInfo(name, time.localtime(mtime)) + zinfo.compress_type = compression + z.writestr(zinfo, data) + finally: + z.close() + + if data_to_prepend: + # Prepend data to the start of the zipfile + with open(zipname, "rb") as f: + zip_data = f.read() + + with open(zipname, "wb") as f: + f.write(data_to_prepend) + f.write(zip_data) + + class UncompressedZipImportTestCase(ImportHooksBaseTestCase): compression = ZIP_STORED @@ -58,23 +79,9 @@ ImportHooksBaseTestCase.setUp(self) def doTest(self, expected_ext, files, *modules, **kw): - z = ZipFile(TEMP_ZIP, "w") + _write_zip_package(TEMP_ZIP, files, data_to_prepend=kw.get("stuff"), + compression=self.compression) try: - for name, (mtime, data) in files.items(): - zinfo = ZipInfo(name, time.localtime(mtime)) - zinfo.compress_type = self.compression - z.writestr(zinfo, data) - z.close() - - stuff = kw.get("stuff", None) - if stuff is not None: - # Prepend 'stuff' to the start of the zipfile - with open(TEMP_ZIP, "rb") as f: - data = f.read() - with open(TEMP_ZIP, "wb") as f: - f.write(stuff) - f.write(data) - sys.path.insert(0, TEMP_ZIP) mod = __import__(".".join(modules), globals(), locals(), @@ -89,7 +96,8 @@ self.assertEqual(file, os.path.join(TEMP_ZIP, *modules) + expected_ext) finally: - z.close() + while TEMP_ZIP in sys.path: + sys.path.remove(TEMP_ZIP) os.remove(TEMP_ZIP) def testAFakeZlib(self): @@ -395,10 +403,67 @@ compression = ZIP_DEFLATED +class ZipFileModifiedAfterImportTestCase(ImportHooksBaseTestCase): + def setUp(self): + zipimport._zip_directory_cache.clear() + zipimport._zip_stat_cache.clear() + ImportHooksBaseTestCase.setUp(self) + + def tearDown(self): + ImportHooksBaseTestCase.tearDown(self) + if os.path.exists(TEMP_ZIP): + os.remove(TEMP_ZIP) + + def testZipFileChangesAfterFirstImport(self): + """Alter the zip file after caching its index and try an import.""" + packdir = TESTPACK + os.sep + files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc), + packdir + TESTMOD + ".py": (NOW, "test_value = 38\n"), + "ziptest_a.py": (NOW, "test_value = 23\n"), + "ziptest_b.py": (NOW, "test_value = 42\n"), + "ziptest_c.py": (NOW, "test_value = 1337\n")} + zipfile_path = TEMP_ZIP + _write_zip_package(zipfile_path, files) + self.assertTrue(os.path.exists(zipfile_path)) + sys.path.insert(0, zipfile_path) + + # Import something out of the zipfile and confirm it is correct. + testmod = __import__(TESTPACK + "." + TESTMOD, + globals(), locals(), ["__dummy__"]) + self.assertEqual(testmod.test_value, 38) + # Import something else out of the zipfile and confirm it is correct. + ziptest_b = __import__("ziptest_b", globals(), locals(), ["test_value"]) + self.assertEqual(ziptest_b.test_value, 42) + + # Truncate and fill the zip file with non-zip garbage. + with open(zipfile_path, "rb") as orig_zip_file: + orig_zip_file_contents = orig_zip_file.read() + with open(zipfile_path, "wb") as byebye_valid_zip_file: + byebye_valid_zip_file.write(b"Tear down this wall!\n"*1987) + # Now that the zipfile has been replaced, import something else from it + # which should fail as the file contents are now garbage. + with self.assertRaises(ImportError): + ziptest_a = __import__("ziptest_a", globals(), locals(), + ["test_value"]) + self.assertEqual(ziptest_a.test_value, 23) + + # Now lets make it a valid zipfile that has some garbage at the start. + # This alters all of the offsets within the file + with open(zipfile_path, "wb") as new_zip_file: + new_zip_file.write(b"X"*1991) # The year Python was created. + new_zip_file.write(orig_zip_file_contents) + + # Now that the zip file has been "restored" to a valid but different + # zipfile the zipimporter should *successfully* re-read the new zip + # file's end of file central index and be able to import from it again. + ziptest_c = __import__("ziptest_c", globals(), locals(), ["test_value"]) + self.assertEqual(ziptest_c.test_value, 1337) + + class BadFileZipImportTestCase(unittest.TestCase): def assertZipFailure(self, filename): - self.assertRaises(zipimport.ZipImportError, - zipimport.zipimporter, filename) + with self.assertRaises(zipimport.ZipImportError): + zipimport.zipimporter(filename) def testNoFile(self): self.assertZipFailure('AdfjdkFJKDFJjdklfjs') @@ -472,6 +537,7 @@ UncompressedZipImportTestCase, CompressedZipImportTestCase, BadFileZipImportTestCase, + ZipFileModifiedAfterImportTestCase, ) finally: support.unlink(TESTMOD) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ Core and Builtins ----------------- +- Issue #19081: When a zipimport .zip file in sys.path being imported from + is modified during the lifetime of the Python process after zipimport has + already cached the zip's table of contents we detect this and recover + rather than read bad data from the .zip (causing odd import errors). + - Issue #17432: Drop UCS2 from names of Unicode functions in python3.def. - Issue #19969: PyBytes_FromFormatV() now raises an OverflowError if "%c" diff --git a/Modules/zipimport.c b/Modules/zipimport.c --- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -45,10 +45,16 @@ static PyObject *ZipImportError; /* read_directory() cache */ static PyObject *zip_directory_cache = NULL; +static PyObject *zip_stat_cache = NULL; +/* posix.fstat or nt.fstat function. Used due to posixmodule.c's + * superior fstat implementation over libc's on Windows. */ +static PyObject *fstat_function = NULL; /* posix.fstat() or nt.fstat() */ /* forward decls */ -static PyObject *read_directory(PyObject *archive); -static PyObject *get_data(PyObject *archive, PyObject *toc_entry); +static FILE *fopen_rb_and_stat(PyObject *path, PyObject **py_stat_p); +static FILE *safely_reopen_archive(ZipImporter *self); +static PyObject *read_directory(FILE *fp, PyObject *archive); +static PyObject *get_data(FILE *fp, PyObject *archive, PyObject *toc_entry); static PyObject *get_module_code(ZipImporter *self, PyObject *fullname, int *p_ispackage, PyObject **p_modpath); @@ -128,11 +134,39 @@ files = PyDict_GetItem(zip_directory_cache, filename); if (files == NULL) { - files = read_directory(filename); - if (files == NULL) + PyObject *zip_stat = NULL; + FILE *fp = fopen_rb_and_stat(filename, &zip_stat); + if (fp == NULL) { + if (!PyErr_Occurred()) + PyErr_Format(ZipImportError, "can't open Zip file: %R", + filename); + + Py_XDECREF(zip_stat); goto error; - if (PyDict_SetItem(zip_directory_cache, filename, files) != 0) + } + + if (Py_VerboseFlag) + PySys_FormatStderr("# zipimport: %U not cached, " + "reading TOC.\n", filename); + + files = read_directory(fp, filename); + fclose(fp); + if (files == NULL) { + Py_XDECREF(zip_stat); goto error; + } + if (PyDict_SetItem(zip_directory_cache, filename, files) != 0) { + Py_DECREF(files); + Py_XDECREF(zip_stat); + goto error; + } + if (zip_stat && PyDict_SetItem(zip_stat_cache, filename, + zip_stat) != 0) { + Py_DECREF(files); + Py_DECREF(zip_stat); + goto error; + } + Py_XDECREF(zip_stat); } else Py_INCREF(files); @@ -554,10 +588,11 @@ { ZipImporter *self = (ZipImporter *)obj; PyObject *path, *key; + FILE *fp; #ifdef ALTSEP _Py_IDENTIFIER(replace); #endif - PyObject *toc_entry; + PyObject *toc_entry, *data; Py_ssize_t path_start, path_len, len; if (!PyArg_ParseTuple(args, "U:zipimporter.get_data", &path)) @@ -585,15 +620,23 @@ key = PyUnicode_Substring(path, path_start, path_len); if (key == NULL) goto error; + + fp = safely_reopen_archive(self); + if (fp == NULL) + goto error; + toc_entry = PyDict_GetItem(self->files, key); if (toc_entry == NULL) { PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, key); Py_DECREF(key); + fclose(fp); goto error; } Py_DECREF(key); Py_DECREF(path); - return get_data(self->archive, toc_entry); + data = get_data(fp, self->archive, toc_entry); + fclose(fp); + return data; error: Py_DECREF(path); return NULL; @@ -618,6 +661,7 @@ PyObject *toc_entry; PyObject *fullname, *subname, *path, *fullpath; enum zi_module_info mi; + FILE *fp; if (!PyArg_ParseTuple(args, "U:zipimporter.get_source", &fullname)) return NULL; @@ -647,11 +691,18 @@ if (fullpath == NULL) return NULL; + fp = safely_reopen_archive(self); + if (fp == NULL) { + Py_DECREF(fullpath); + return NULL; + } + toc_entry = PyDict_GetItem(self->files, fullpath); Py_DECREF(fullpath); if (toc_entry != NULL) { PyObject *res, *bytes; - bytes = get_data(self->archive, toc_entry); + bytes = get_data(fp, self->archive, toc_entry); + fclose(fp); if (bytes == NULL) return NULL; res = PyUnicode_FromStringAndSize(PyBytes_AS_STRING(bytes), @@ -659,10 +710,10 @@ Py_DECREF(bytes); return res; } + fclose(fp); /* we have the module, but no source */ - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyDoc_STRVAR(doc_find_module, @@ -828,10 +879,135 @@ return x; } +/* Return 1 if objects a and b fail a Py_EQ test for an attr. */ +static int +compare_obj_attr_strings(PyObject *obj_a, PyObject *obj_b, char *attr_name) +{ + int problem = 0; + PyObject *attr_a = PyObject_GetAttrString(obj_a, attr_name); + PyObject *attr_b = PyObject_GetAttrString(obj_b, attr_name); + if (attr_a == NULL || attr_b == NULL) + problem = 1; + else + problem = (PyObject_RichCompareBool(attr_a, attr_b, Py_EQ) != 1); + Py_XDECREF(attr_a); + Py_XDECREF(attr_b); + return problem; +} + /* - read_directory(archive) -> files dict (new reference) + * Returns an open FILE * on success. + * Returns NULL on error with the Python error context set. + */ +static FILE * +safely_reopen_archive(ZipImporter *self) +{ + FILE *fp; + PyObject *stat_now = NULL; - Given a path to a Zip archive, build a dict, mapping file names + fp = fopen_rb_and_stat(self->archive, &stat_now); + if (!fp) { + PyErr_Format(ZipImportError, + "zipimport: can not open file %U", self->archive); + Py_XDECREF(stat_now); + return NULL; + } + + if (stat_now != NULL) { + int problem = 0; + PyObject *files; + PyObject *prev_stat = PyDict_GetItem(zip_stat_cache, self->archive); + /* Test stat_now vs the old cached stat on some key attributes. */ + if (prev_stat != NULL) { + problem = compare_obj_attr_strings(prev_stat, stat_now, + "st_ino"); + problem |= compare_obj_attr_strings(prev_stat, stat_now, + "st_size"); + problem |= compare_obj_attr_strings(prev_stat, stat_now, + "st_mtime"); + } else { + if (Py_VerboseFlag) + PySys_FormatStderr("# zipimport: no stat data for %U!\n", + self->archive); + problem = 1; + } + + if (problem) { + if (Py_VerboseFlag) + PySys_FormatStderr("# zipimport: %U modified since last" + " import, rereading TOC.\n", self->archive); + files = read_directory(fp, self->archive); + if (files == NULL) { + Py_DECREF(stat_now); + fclose(fp); + return NULL; + } + if (PyDict_SetItem(zip_directory_cache, self->archive, + files) != 0) { + Py_DECREF(files); + Py_DECREF(stat_now); + fclose(fp); + return NULL; + } + if (stat_now && PyDict_SetItem(zip_stat_cache, self->archive, + stat_now) != 0) { + Py_DECREF(files); + Py_DECREF(stat_now); + fclose(fp); + return NULL; + } + Py_XDECREF(self->files); /* free the old value. */ + self->files = files; + } else { + /* No problem, discard the new stat data. */ + Py_DECREF(stat_now); + } + } /* stat succeeded */ + + return fp; +} + +/* + fopen_rb_and_stat(path, &py_stat) -> FILE * + + Opens path in "rb" mode and populates the Python py_stat stat_result + with information about the opened file. *py_stat may not be changed + if there is no fstat_function or if fstat_function fails. + + Returns NULL and does nothing to *py_stat if the open failed. +*/ +static FILE * +fopen_rb_and_stat(PyObject *path, PyObject **py_stat_p) +{ + FILE *fp; + assert(py_stat_p != NULL); + assert(*py_stat_p == NULL); + + fp = _Py_fopen(path, "rb"); + if (fp == NULL) { + if (!PyErr_Occurred()) + PyErr_Format(ZipImportError, + "zipimport: can not open file %U", path); + return NULL; + } + + if (fstat_function) { + PyObject *stat_result = PyObject_CallFunction(fstat_function, + "i", fileno(fp)); + if (stat_result == NULL) { + PyErr_Clear(); /* We can function without it. */ + } else { + *py_stat_p = stat_result; + } + } + + return fp; +} + +/* + read_directory(fp, archive) -> files dict (new reference) + + Given an open Zip archive, build a dict, mapping file names (local to the archive, using SEP as a separator) to toc entries. A toc_entry is a tuple: @@ -851,10 +1027,9 @@ data_size and file_offset are 0. */ static PyObject * -read_directory(PyObject *archive) +read_directory(FILE *fp, PyObject *archive) { PyObject *files = NULL; - FILE *fp; unsigned short flags; short compress, time, date, name_size; long crc, data_size, file_size, header_size; @@ -869,27 +1044,18 @@ const char *charset; int bootstrap; - fp = _Py_fopen(archive, "rb"); - if (fp == NULL) { - if (!PyErr_Occurred()) - PyErr_Format(ZipImportError, "can't open Zip file: %R", archive); - return NULL; - } - + assert(fp != NULL); if (fseek(fp, -22, SEEK_END) == -1) { - fclose(fp); PyErr_Format(ZipImportError, "can't read Zip file: %R", archive); return NULL; } header_position = ftell(fp); if (fread(endof_central_dir, 1, 22, fp) != 22) { - fclose(fp); PyErr_Format(ZipImportError, "can't read Zip file: %R", archive); return NULL; } if (get_long((unsigned char *)endof_central_dir) != 0x06054B50) { /* Bad: End of Central Dir signature */ - fclose(fp); PyErr_Format(ZipImportError, "not a Zip file: %R", archive); return NULL; } @@ -983,19 +1149,16 @@ goto error; count++; } - fclose(fp); if (Py_VerboseFlag) PySys_FormatStderr("# zipimport: found %ld names in %R\n", count, archive); return files; fseek_error: - fclose(fp); Py_XDECREF(files); Py_XDECREF(nameobj); PyErr_Format(ZipImportError, "can't read Zip file: %R", archive); return NULL; error: - fclose(fp); Py_XDECREF(files); Py_XDECREF(nameobj); return NULL; @@ -1034,14 +1197,13 @@ return decompress; } -/* Given a path to a Zip file and a toc_entry, return the (uncompressed) +/* Given a FILE* to a Zip file and a toc_entry, return the (uncompressed) data as a new reference. */ static PyObject * -get_data(PyObject *archive, PyObject *toc_entry) +get_data(FILE *fp, PyObject *archive, PyObject *toc_entry) { PyObject *raw_data, *data = NULL, *decompress; char *buf; - FILE *fp; int err; Py_ssize_t bytes_read = 0; long l; @@ -1055,17 +1217,8 @@ return NULL; } - fp = _Py_fopen(archive, "rb"); - if (!fp) { - if (!PyErr_Occurred()) - PyErr_Format(PyExc_IOError, - "zipimport: can not open file %U", archive); - return NULL; - } - /* Check to make sure the local file header is correct */ if (fseek(fp, file_offset, 0) == -1) { - fclose(fp); PyErr_Format(ZipImportError, "can't read Zip file: %R", archive); return NULL; } @@ -1076,11 +1229,9 @@ PyErr_Format(ZipImportError, "bad local file header in %U", archive); - fclose(fp); return NULL; } if (fseek(fp, file_offset + 26, 0) == -1) { - fclose(fp); PyErr_Format(ZipImportError, "can't read Zip file: %R", archive); return NULL; } @@ -1095,7 +1246,6 @@ raw_data = PyBytes_FromStringAndSize((char *)NULL, bytes_size); if (raw_data == NULL) { - fclose(fp); return NULL; } buf = PyBytes_AsString(raw_data); @@ -1104,11 +1254,9 @@ if (err == 0) { bytes_read = fread(buf, 1, data_size, fp); } else { - fclose(fp); PyErr_Format(ZipImportError, "can't read Zip file: %R", archive); return NULL; } - fclose(fp); if (err || bytes_read != data_size) { PyErr_SetString(PyExc_IOError, "zipimport: can't read data"); @@ -1329,12 +1477,12 @@ /* Return the code object for the module named by 'fullname' from the Zip archive as a new reference. */ static PyObject * -get_code_from_data(ZipImporter *self, int ispackage, int isbytecode, +get_code_from_data(ZipImporter *self, FILE *fp, int ispackage, int isbytecode, time_t mtime, PyObject *toc_entry) { PyObject *data, *modpath, *code; - data = get_data(self->archive, toc_entry); + data = get_data(fp, self->archive, toc_entry); if (data == NULL) return NULL; @@ -1356,6 +1504,7 @@ PyObject *code = NULL, *toc_entry, *subname; PyObject *path, *fullpath = NULL; struct st_zip_searchorder *zso; + FILE *fp; subname = get_subname(fullname); if (subname == NULL) @@ -1366,6 +1515,12 @@ if (path == NULL) return NULL; + fp = safely_reopen_archive(self); + if (fp == NULL) { + Py_DECREF(path); + return NULL; + } + for (zso = zip_searchorder; *zso->suffix; zso++) { code = NULL; @@ -1376,6 +1531,7 @@ if (Py_VerboseFlag > 1) PySys_FormatStderr("# trying %U%c%U\n", self->archive, (int)SEP, fullpath); + toc_entry = PyDict_GetItem(self->files, fullpath); if (toc_entry != NULL) { time_t mtime = 0; @@ -1391,7 +1547,7 @@ Py_CLEAR(fullpath); if (p_ispackage != NULL) *p_ispackage = ispackage; - code = get_code_from_data(self, ispackage, + code = get_code_from_data(self, fp, ispackage, isbytecode, mtime, toc_entry); if (code == Py_None) { @@ -1411,6 +1567,7 @@ } PyErr_Format(ZipImportError, "can't find module %R", fullname); exit: + fclose(fp); Py_DECREF(path); Py_XDECREF(fullpath); return code; @@ -1428,6 +1585,8 @@ subclass of ImportError, so it can be caught as ImportError, too.\n\ - _zip_directory_cache: a dict, mapping archive paths to zip directory\n\ info dicts, as used in zipimporter._files.\n\ +- _zip_stat_cache: a dict, mapping archive paths to stat_result\n\ + info for the .zip the last time anything was imported from it.\n\ \n\ It is usually not needed to use the zipimport module explicitly; it is\n\ used by the builtin import mechanism for sys.path items that are paths\n\ @@ -1487,6 +1646,7 @@ (PyObject *)&ZipImporter_Type) < 0) return NULL; + Py_XDECREF(zip_directory_cache); /* Avoid embedded interpreter leaks. */ zip_directory_cache = PyDict_New(); if (zip_directory_cache == NULL) return NULL; @@ -1494,5 +1654,36 @@ if (PyModule_AddObject(mod, "_zip_directory_cache", zip_directory_cache) < 0) return NULL; + + Py_XDECREF(zip_stat_cache); /* Avoid embedded interpreter leaks. */ + zip_stat_cache = PyDict_New(); + if (zip_stat_cache == NULL) + return NULL; + Py_INCREF(zip_stat_cache); + if (PyModule_AddObject(mod, "_zip_stat_cache", zip_stat_cache) < 0) + return NULL; + + { + /* We cannot import "os" here as that is a .py/.pyc file that could + * live within a zipped up standard library. Import the posix or nt + * builtin that provides the fstat() function we want instead. */ + PyObject *os_like_module; + Py_CLEAR(fstat_function); /* Avoid embedded interpreter leaks. */ + os_like_module = PyImport_ImportModule("posix"); + if (os_like_module == NULL) { + PyErr_Clear(); + os_like_module = PyImport_ImportModule("nt"); + } + if (os_like_module != NULL) { + fstat_function = PyObject_GetAttrString(os_like_module, "fstat"); + Py_DECREF(os_like_module); + } + if (fstat_function == NULL) { + PyErr_Clear(); /* non-fatal, we'll go on without it. */ + if (Py_VerboseFlag) + PySys_WriteStderr("# zipimport unable to use os.fstat().\n"); + } + } + return mod; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 8 03:34:48 2014 From: python-checkins at python.org (gregory.p.smith) Date: Wed, 8 Jan 2014 03:34:48 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Fixes_issue_=2319081=3A_When_a_zipimport_=2Ezip_file_in_?= =?utf-8?q?sys=2Epath_being_imported_from?= Message-ID: <3dzZL05Bt9z7Ljq@mail.python.org> http://hg.python.org/cpython/rev/20b77ff040b6 changeset: 88351:20b77ff040b6 parent: 88349:a9bffe9bdeab parent: 88350:2807a5f011e4 user: Gregory P. Smith date: Tue Jan 07 18:34:23 2014 -0800 summary: Fixes issue #19081: When a zipimport .zip file in sys.path being imported from is modified during the lifetime of the Python process after zipimport has already cached the zip's table of contents we detect this and recover rather than read bad data from the .zip (causing odd import errors). files: Lib/test/test_zipimport.py | 104 +++++++- Misc/NEWS | 5 + Modules/zipimport.c | 286 ++++++++++++++++++++---- 3 files changed, 328 insertions(+), 67 deletions(-) diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py --- a/Lib/test/test_zipimport.py +++ b/Lib/test/test_zipimport.py @@ -71,6 +71,27 @@ support.modules_cleanup(*self.modules_before) +def _write_zip_package(zipname, files, + data_to_prepend=b"", compression=ZIP_STORED): + z = ZipFile(zipname, "w") + try: + for name, (mtime, data) in files.items(): + zinfo = ZipInfo(name, time.localtime(mtime)) + zinfo.compress_type = compression + z.writestr(zinfo, data) + finally: + z.close() + + if data_to_prepend: + # Prepend data to the start of the zipfile + with open(zipname, "rb") as f: + zip_data = f.read() + + with open(zipname, "wb") as f: + f.write(data_to_prepend) + f.write(zip_data) + + class UncompressedZipImportTestCase(ImportHooksBaseTestCase): compression = ZIP_STORED @@ -83,23 +104,9 @@ ImportHooksBaseTestCase.setUp(self) def doTest(self, expected_ext, files, *modules, **kw): - z = ZipFile(TEMP_ZIP, "w") + _write_zip_package(TEMP_ZIP, files, data_to_prepend=kw.get("stuff"), + compression=self.compression) try: - for name, (mtime, data) in files.items(): - zinfo = ZipInfo(name, time.localtime(mtime)) - zinfo.compress_type = self.compression - z.writestr(zinfo, data) - z.close() - - stuff = kw.get("stuff", None) - if stuff is not None: - # Prepend 'stuff' to the start of the zipfile - with open(TEMP_ZIP, "rb") as f: - data = f.read() - with open(TEMP_ZIP, "wb") as f: - f.write(stuff) - f.write(data) - sys.path.insert(0, TEMP_ZIP) mod = __import__(".".join(modules), globals(), locals(), @@ -114,7 +121,8 @@ self.assertEqual(file, os.path.join(TEMP_ZIP, *modules) + expected_ext) finally: - z.close() + while TEMP_ZIP in sys.path: + sys.path.remove(TEMP_ZIP) os.remove(TEMP_ZIP) def testAFakeZlib(self): @@ -422,10 +430,67 @@ compression = ZIP_DEFLATED +class ZipFileModifiedAfterImportTestCase(ImportHooksBaseTestCase): + def setUp(self): + zipimport._zip_directory_cache.clear() + zipimport._zip_stat_cache.clear() + ImportHooksBaseTestCase.setUp(self) + + def tearDown(self): + ImportHooksBaseTestCase.tearDown(self) + if os.path.exists(TEMP_ZIP): + os.remove(TEMP_ZIP) + + def testZipFileChangesAfterFirstImport(self): + """Alter the zip file after caching its index and try an import.""" + packdir = TESTPACK + os.sep + files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc), + packdir + TESTMOD + ".py": (NOW, "test_value = 38\n"), + "ziptest_a.py": (NOW, "test_value = 23\n"), + "ziptest_b.py": (NOW, "test_value = 42\n"), + "ziptest_c.py": (NOW, "test_value = 1337\n")} + zipfile_path = TEMP_ZIP + _write_zip_package(zipfile_path, files) + self.assertTrue(os.path.exists(zipfile_path)) + sys.path.insert(0, zipfile_path) + + # Import something out of the zipfile and confirm it is correct. + testmod = __import__(TESTPACK + "." + TESTMOD, + globals(), locals(), ["__dummy__"]) + self.assertEqual(testmod.test_value, 38) + # Import something else out of the zipfile and confirm it is correct. + ziptest_b = __import__("ziptest_b", globals(), locals(), ["test_value"]) + self.assertEqual(ziptest_b.test_value, 42) + + # Truncate and fill the zip file with non-zip garbage. + with open(zipfile_path, "rb") as orig_zip_file: + orig_zip_file_contents = orig_zip_file.read() + with open(zipfile_path, "wb") as byebye_valid_zip_file: + byebye_valid_zip_file.write(b"Tear down this wall!\n"*1987) + # Now that the zipfile has been replaced, import something else from it + # which should fail as the file contents are now garbage. + with self.assertRaises(ImportError): + ziptest_a = __import__("ziptest_a", globals(), locals(), + ["test_value"]) + self.assertEqual(ziptest_a.test_value, 23) + + # Now lets make it a valid zipfile that has some garbage at the start. + # This alters all of the offsets within the file + with open(zipfile_path, "wb") as new_zip_file: + new_zip_file.write(b"X"*1991) # The year Python was created. + new_zip_file.write(orig_zip_file_contents) + + # Now that the zip file has been "restored" to a valid but different + # zipfile the zipimporter should *successfully* re-read the new zip + # file's end of file central index and be able to import from it again. + ziptest_c = __import__("ziptest_c", globals(), locals(), ["test_value"]) + self.assertEqual(ziptest_c.test_value, 1337) + + class BadFileZipImportTestCase(unittest.TestCase): def assertZipFailure(self, filename): - self.assertRaises(zipimport.ZipImportError, - zipimport.zipimporter, filename) + with self.assertRaises(zipimport.ZipImportError): + zipimport.zipimporter(filename) def testNoFile(self): self.assertZipFailure('AdfjdkFJKDFJjdklfjs') @@ -499,6 +564,7 @@ UncompressedZipImportTestCase, CompressedZipImportTestCase, BadFileZipImportTestCase, + ZipFileModifiedAfterImportTestCase, ) finally: support.unlink(TESTMOD) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ Core and Builtins ----------------- +- Issue #19081: When a zipimport .zip file in sys.path being imported from + is modified during the lifetime of the Python process after zipimport has + already cached the zip's table of contents we detect this and recover + rather than read bad data from the .zip (causing odd import errors). + Library ------- diff --git a/Modules/zipimport.c b/Modules/zipimport.c --- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -49,10 +49,16 @@ static PyObject *ZipImportError; /* read_directory() cache */ static PyObject *zip_directory_cache = NULL; +static PyObject *zip_stat_cache = NULL; +/* posix.fstat or nt.fstat function. Used due to posixmodule.c's + * superior fstat implementation over libc's on Windows. */ +static PyObject *fstat_function = NULL; /* posix.fstat() or nt.fstat() */ /* forward decls */ -static PyObject *read_directory(PyObject *archive); -static PyObject *get_data(PyObject *archive, PyObject *toc_entry); +static FILE *fopen_rb_and_stat(PyObject *path, PyObject **py_stat_p); +static FILE *safely_reopen_archive(ZipImporter *self); +static PyObject *read_directory(FILE *fp, PyObject *archive); +static PyObject *get_data(FILE *fp, PyObject *archive, PyObject *toc_entry); static PyObject *get_module_code(ZipImporter *self, PyObject *fullname, int *p_ispackage, PyObject **p_modpath); @@ -131,11 +137,39 @@ files = PyDict_GetItem(zip_directory_cache, filename); if (files == NULL) { - files = read_directory(filename); - if (files == NULL) + PyObject *zip_stat = NULL; + FILE *fp = fopen_rb_and_stat(filename, &zip_stat); + if (fp == NULL) { + if (!PyErr_Occurred()) + PyErr_Format(ZipImportError, "can't open Zip file: %R", + filename); + + Py_XDECREF(zip_stat); goto error; - if (PyDict_SetItem(zip_directory_cache, filename, files) != 0) + } + + if (Py_VerboseFlag) + PySys_FormatStderr("# zipimport: %U not cached, " + "reading TOC.\n", filename); + + files = read_directory(fp, filename); + fclose(fp); + if (files == NULL) { + Py_XDECREF(zip_stat); goto error; + } + if (PyDict_SetItem(zip_directory_cache, filename, files) != 0) { + Py_DECREF(files); + Py_XDECREF(zip_stat); + goto error; + } + if (zip_stat && PyDict_SetItem(zip_stat_cache, filename, + zip_stat) != 0) { + Py_DECREF(files); + Py_DECREF(zip_stat); + goto error; + } + Py_XDECREF(zip_stat); } else Py_INCREF(files); @@ -560,7 +594,8 @@ { ZipImporter *self = (ZipImporter *)obj; PyObject *path, *key; - PyObject *toc_entry; + FILE *fp; + PyObject *toc_entry, *data; Py_ssize_t path_start, path_len, len; if (!PyArg_ParseTuple(args, "U:zipimporter.get_data", &path)) @@ -588,15 +623,23 @@ key = PyUnicode_Substring(path, path_start, path_len); if (key == NULL) goto error; + + fp = safely_reopen_archive(self); + if (fp == NULL) + goto error; + toc_entry = PyDict_GetItem(self->files, key); if (toc_entry == NULL) { PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, key); Py_DECREF(key); + fclose(fp); goto error; } Py_DECREF(key); Py_DECREF(path); - return get_data(self->archive, toc_entry); + data = get_data(fp, self->archive, toc_entry); + fclose(fp); + return data; error: Py_DECREF(path); return NULL; @@ -621,6 +664,7 @@ PyObject *toc_entry; PyObject *fullname, *subname, *path, *fullpath; enum zi_module_info mi; + FILE *fp; if (!PyArg_ParseTuple(args, "U:zipimporter.get_source", &fullname)) return NULL; @@ -650,11 +694,18 @@ if (fullpath == NULL) return NULL; + fp = safely_reopen_archive(self); + if (fp == NULL) { + Py_DECREF(fullpath); + return NULL; + } + toc_entry = PyDict_GetItem(self->files, fullpath); Py_DECREF(fullpath); if (toc_entry != NULL) { PyObject *res, *bytes; - bytes = get_data(self->archive, toc_entry); + bytes = get_data(fp, self->archive, toc_entry); + fclose(fp); if (bytes == NULL) return NULL; res = PyUnicode_FromStringAndSize(PyBytes_AS_STRING(bytes), @@ -662,10 +713,10 @@ Py_DECREF(bytes); return res; } + fclose(fp); /* we have the module, but no source */ - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyDoc_STRVAR(doc_find_module, @@ -831,10 +882,135 @@ return x; } +/* Return 1 if objects a and b fail a Py_EQ test for an attr. */ +static int +compare_obj_attr_strings(PyObject *obj_a, PyObject *obj_b, char *attr_name) +{ + int problem = 0; + PyObject *attr_a = PyObject_GetAttrString(obj_a, attr_name); + PyObject *attr_b = PyObject_GetAttrString(obj_b, attr_name); + if (attr_a == NULL || attr_b == NULL) + problem = 1; + else + problem = (PyObject_RichCompareBool(attr_a, attr_b, Py_EQ) != 1); + Py_XDECREF(attr_a); + Py_XDECREF(attr_b); + return problem; +} + /* - read_directory(archive) -> files dict (new reference) + * Returns an open FILE * on success. + * Returns NULL on error with the Python error context set. + */ +static FILE * +safely_reopen_archive(ZipImporter *self) +{ + FILE *fp; + PyObject *stat_now = NULL; - Given a path to a Zip archive, build a dict, mapping file names + fp = fopen_rb_and_stat(self->archive, &stat_now); + if (!fp) { + PyErr_Format(ZipImportError, + "zipimport: can not open file %U", self->archive); + Py_XDECREF(stat_now); + return NULL; + } + + if (stat_now != NULL) { + int problem = 0; + PyObject *files; + PyObject *prev_stat = PyDict_GetItem(zip_stat_cache, self->archive); + /* Test stat_now vs the old cached stat on some key attributes. */ + if (prev_stat != NULL) { + problem = compare_obj_attr_strings(prev_stat, stat_now, + "st_ino"); + problem |= compare_obj_attr_strings(prev_stat, stat_now, + "st_size"); + problem |= compare_obj_attr_strings(prev_stat, stat_now, + "st_mtime"); + } else { + if (Py_VerboseFlag) + PySys_FormatStderr("# zipimport: no stat data for %U!\n", + self->archive); + problem = 1; + } + + if (problem) { + if (Py_VerboseFlag) + PySys_FormatStderr("# zipimport: %U modified since last" + " import, rereading TOC.\n", self->archive); + files = read_directory(fp, self->archive); + if (files == NULL) { + Py_DECREF(stat_now); + fclose(fp); + return NULL; + } + if (PyDict_SetItem(zip_directory_cache, self->archive, + files) != 0) { + Py_DECREF(files); + Py_DECREF(stat_now); + fclose(fp); + return NULL; + } + if (stat_now && PyDict_SetItem(zip_stat_cache, self->archive, + stat_now) != 0) { + Py_DECREF(files); + Py_DECREF(stat_now); + fclose(fp); + return NULL; + } + Py_XDECREF(self->files); /* free the old value. */ + self->files = files; + } else { + /* No problem, discard the new stat data. */ + Py_DECREF(stat_now); + } + } /* stat succeeded */ + + return fp; +} + +/* + fopen_rb_and_stat(path, &py_stat) -> FILE * + + Opens path in "rb" mode and populates the Python py_stat stat_result + with information about the opened file. *py_stat may not be changed + if there is no fstat_function or if fstat_function fails. + + Returns NULL and does nothing to *py_stat if the open failed. +*/ +static FILE * +fopen_rb_and_stat(PyObject *path, PyObject **py_stat_p) +{ + FILE *fp; + assert(py_stat_p != NULL); + assert(*py_stat_p == NULL); + + fp = _Py_fopen_obj(path, "rb"); + if (fp == NULL) { + if (!PyErr_Occurred()) + PyErr_Format(ZipImportError, + "zipimport: can not open file %U", path); + return NULL; + } + + if (fstat_function) { + PyObject *stat_result = PyObject_CallFunction(fstat_function, + "i", fileno(fp)); + if (stat_result == NULL) { + PyErr_Clear(); /* We can function without it. */ + } else { + *py_stat_p = stat_result; + } + } + + return fp; +} + +/* + read_directory(fp, archive) -> files dict (new reference) + + Given an open Zip archive, build a dict, mapping file names (local to the archive, using SEP as a separator) to toc entries. A toc_entry is a tuple: @@ -854,10 +1030,9 @@ data_size and file_offset are 0. */ static PyObject * -read_directory(PyObject *archive) +read_directory(FILE *fp, PyObject *archive) { PyObject *files = NULL; - FILE *fp; unsigned short flags; short compress, time, date, name_size; long crc, data_size, file_size, header_size; @@ -873,27 +1048,18 @@ const char *charset; int bootstrap; - fp = _Py_fopen_obj(archive, "rb"); - if (fp == NULL) { - if (!PyErr_Occurred()) - PyErr_Format(ZipImportError, "can't open Zip file: %R", archive); - return NULL; - } - + assert(fp != NULL); if (fseek(fp, -22, SEEK_END) == -1) { - fclose(fp); PyErr_Format(ZipImportError, "can't read Zip file: %R", archive); return NULL; } header_position = ftell(fp); if (fread(endof_central_dir, 1, 22, fp) != 22) { - fclose(fp); PyErr_Format(ZipImportError, "can't read Zip file: %R", archive); return NULL; } if (get_long((unsigned char *)endof_central_dir) != 0x06054B50) { /* Bad: End of Central Dir signature */ - fclose(fp); PyErr_Format(ZipImportError, "not a Zip file: %R", archive); return NULL; } @@ -1000,19 +1166,16 @@ goto error; count++; } - fclose(fp); if (Py_VerboseFlag) PySys_FormatStderr("# zipimport: found %ld names in %R\n", count, archive); return files; file_error: - fclose(fp); Py_XDECREF(files); Py_XDECREF(nameobj); PyErr_Format(ZipImportError, "can't read Zip file: %R", archive); return NULL; error: - fclose(fp); Py_XDECREF(files); Py_XDECREF(nameobj); return NULL; @@ -1051,14 +1214,13 @@ return decompress; } -/* Given a path to a Zip file and a toc_entry, return the (uncompressed) +/* Given a FILE* to a Zip file and a toc_entry, return the (uncompressed) data as a new reference. */ static PyObject * -get_data(PyObject *archive, PyObject *toc_entry) +get_data(FILE *fp, PyObject *archive, PyObject *toc_entry) { PyObject *raw_data, *data = NULL, *decompress; char *buf; - FILE *fp; int err; Py_ssize_t bytes_read = 0; long l; @@ -1072,17 +1234,8 @@ return NULL; } - fp = _Py_fopen_obj(archive, "rb"); - if (!fp) { - if (!PyErr_Occurred()) - PyErr_Format(PyExc_IOError, - "zipimport: can not open file %U", archive); - return NULL; - } - /* Check to make sure the local file header is correct */ if (fseek(fp, file_offset, 0) == -1) { - fclose(fp); PyErr_Format(ZipImportError, "can't read Zip file: %R", archive); return NULL; } @@ -1094,11 +1247,9 @@ PyErr_Format(ZipImportError, "bad local file header in %U", archive); - fclose(fp); return NULL; } if (fseek(fp, file_offset + 26, 0) == -1) { - fclose(fp); PyErr_Format(ZipImportError, "can't read Zip file: %R", archive); return NULL; } @@ -1106,7 +1257,6 @@ l = 30 + PyMarshal_ReadShortFromFile(fp) + PyMarshal_ReadShortFromFile(fp); /* local header size */ if (PyErr_Occurred()) { - fclose(fp); return NULL; } file_offset += l; /* Start of file data */ @@ -1117,7 +1267,6 @@ raw_data = PyBytes_FromStringAndSize((char *)NULL, bytes_size); if (raw_data == NULL) { - fclose(fp); return NULL; } buf = PyBytes_AsString(raw_data); @@ -1126,11 +1275,9 @@ if (err == 0) { bytes_read = fread(buf, 1, data_size, fp); } else { - fclose(fp); PyErr_Format(ZipImportError, "can't read Zip file: %R", archive); return NULL; } - fclose(fp); if (err || bytes_read != data_size) { PyErr_SetString(PyExc_IOError, "zipimport: can't read data"); @@ -1351,12 +1498,12 @@ /* Return the code object for the module named by 'fullname' from the Zip archive as a new reference. */ static PyObject * -get_code_from_data(ZipImporter *self, int ispackage, int isbytecode, +get_code_from_data(ZipImporter *self, FILE *fp, int ispackage, int isbytecode, time_t mtime, PyObject *toc_entry) { PyObject *data, *modpath, *code; - data = get_data(self->archive, toc_entry); + data = get_data(fp, self->archive, toc_entry); if (data == NULL) return NULL; @@ -1378,6 +1525,7 @@ PyObject *code = NULL, *toc_entry, *subname; PyObject *path, *fullpath = NULL; struct st_zip_searchorder *zso; + FILE *fp; subname = get_subname(fullname); if (subname == NULL) @@ -1388,6 +1536,12 @@ if (path == NULL) return NULL; + fp = safely_reopen_archive(self); + if (fp == NULL) { + Py_DECREF(path); + return NULL; + } + for (zso = zip_searchorder; *zso->suffix; zso++) { code = NULL; @@ -1398,6 +1552,7 @@ if (Py_VerboseFlag > 1) PySys_FormatStderr("# trying %U%c%U\n", self->archive, (int)SEP, fullpath); + toc_entry = PyDict_GetItem(self->files, fullpath); if (toc_entry != NULL) { time_t mtime = 0; @@ -1413,7 +1568,7 @@ Py_CLEAR(fullpath); if (p_ispackage != NULL) *p_ispackage = ispackage; - code = get_code_from_data(self, ispackage, + code = get_code_from_data(self, fp, ispackage, isbytecode, mtime, toc_entry); if (code == Py_None) { @@ -1433,6 +1588,7 @@ } PyErr_Format(ZipImportError, "can't find module %R", fullname); exit: + fclose(fp); Py_DECREF(path); Py_XDECREF(fullpath); return code; @@ -1450,6 +1606,8 @@ subclass of ImportError, so it can be caught as ImportError, too.\n\ - _zip_directory_cache: a dict, mapping archive paths to zip directory\n\ info dicts, as used in zipimporter._files.\n\ +- _zip_stat_cache: a dict, mapping archive paths to stat_result\n\ + info for the .zip the last time anything was imported from it.\n\ \n\ It is usually not needed to use the zipimport module explicitly; it is\n\ used by the builtin import mechanism for sys.path items that are paths\n\ @@ -1509,6 +1667,7 @@ (PyObject *)&ZipImporter_Type) < 0) return NULL; + Py_XDECREF(zip_directory_cache); /* Avoid embedded interpreter leaks. */ zip_directory_cache = PyDict_New(); if (zip_directory_cache == NULL) return NULL; @@ -1516,5 +1675,36 @@ if (PyModule_AddObject(mod, "_zip_directory_cache", zip_directory_cache) < 0) return NULL; + + Py_XDECREF(zip_stat_cache); /* Avoid embedded interpreter leaks. */ + zip_stat_cache = PyDict_New(); + if (zip_stat_cache == NULL) + return NULL; + Py_INCREF(zip_stat_cache); + if (PyModule_AddObject(mod, "_zip_stat_cache", zip_stat_cache) < 0) + return NULL; + + { + /* We cannot import "os" here as that is a .py/.pyc file that could + * live within a zipped up standard library. Import the posix or nt + * builtin that provides the fstat() function we want instead. */ + PyObject *os_like_module; + Py_CLEAR(fstat_function); /* Avoid embedded interpreter leaks. */ + os_like_module = PyImport_ImportModule("posix"); + if (os_like_module == NULL) { + PyErr_Clear(); + os_like_module = PyImport_ImportModule("nt"); + } + if (os_like_module != NULL) { + fstat_function = PyObject_GetAttrString(os_like_module, "fstat"); + Py_DECREF(os_like_module); + } + if (fstat_function == NULL) { + PyErr_Clear(); /* non-fatal, we'll go on without it. */ + if (Py_VerboseFlag) + PySys_WriteStderr("# zipimport unable to use os.fstat().\n"); + } + } + return mod; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 8 03:40:02 2014 From: python-checkins at python.org (gregory.p.smith) Date: Wed, 8 Jan 2014 03:40:02 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_cleanup_for_th?= =?utf-8?q?e_issue_19081_fix_-_pull_the_file_open_and_close_outside_of_the?= Message-ID: <3dzZS213sWz7LjX@mail.python.org> http://hg.python.org/cpython/rev/5609135c6e86 changeset: 88352:5609135c6e86 branch: 2.7 parent: 88339:89b3836f7378 user: Gregory P. Smith date: Tue Jan 07 18:39:48 2014 -0800 summary: cleanup for the issue 19081 fix - pull the file open and close outside of the zip_searchorder scanning loop in get_module_code(). [already done in 3.3 and 3.4] files: Modules/zipimport.c | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Modules/zipimport.c b/Modules/zipimport.c --- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -1292,6 +1292,8 @@ char *subname, path[MAXPATHLEN + 1]; int len; struct st_zip_searchorder *zso; + FILE *fp; + char *archive; subname = get_subname(fullname); @@ -1299,10 +1301,12 @@ if (len < 0) return NULL; + fp = safely_reopen_archive(self, &archive); + if (fp == NULL) + return NULL; + for (zso = zip_searchorder; *zso->suffix; zso++) { PyObject *code = NULL; - FILE *fp; - char *archive; strcpy(path + len, zso->suffix); if (Py_VerboseFlag > 1) @@ -1310,10 +1314,6 @@ PyString_AsString(self->archive), SEP, path); - fp = safely_reopen_archive(self, &archive); - if (fp == NULL) - return NULL; - toc_entry = PyDict_GetItemString(self->files, path); if (toc_entry != NULL) { time_t mtime = 0; @@ -1327,7 +1327,6 @@ code = get_code_from_data(archive, fp, ispackage, isbytecode, mtime, toc_entry); - fclose(fp); if (code == Py_None) { /* bad magic number or non-matching mtime in byte code, try next */ @@ -1337,11 +1336,12 @@ if (code != NULL && p_modpath != NULL) *p_modpath = PyString_AsString( PyTuple_GetItem(toc_entry, 0)); + fclose(fp); return code; } - fclose(fp); } PyErr_Format(ZipImportError, "can't find module '%.200s'", fullname); + fclose(fp); return NULL; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 8 07:33:35 2014 From: python-checkins at python.org (eric.snow) Date: Wed, 8 Jan 2014 07:33:35 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_19713=3A_Remove_PEP_?= =?utf-8?q?451-related_code_that_should_have_been_factored_out=2E?= Message-ID: <3dzgdW6zHKz7LjZ@mail.python.org> http://hg.python.org/cpython/rev/c0b0e7aef360 changeset: 88353:c0b0e7aef360 parent: 88351:20b77ff040b6 user: Eric Snow date: Tue Jan 07 23:29:19 2014 -0700 summary: Issue 19713: Remove PEP 451-related code that should have been factored out. This code was an artifact of issuing a DeprecationWarning for the lack of loader.exec_module(). However, we have deferred such warnings to later Python versions. files: Lib/importlib/_bootstrap.py | 28 +- Python/importlib.h | 2405 +++++++++++----------- 2 files changed, 1192 insertions(+), 1241 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -994,25 +994,11 @@ """Convenience wrapper around spec objects to provide spec-specific methods.""" + # The various spec_from_* functions could be made factory methods here. + def __init__(self, spec): self.spec = spec - @classmethod - def from_module(cls, module): - """Create a spec from a module's attributes.""" - try: - spec = module.__spec__ - except AttributeError: - try: - loader = spec.__loader__ - except AttributeError: - spec = _find_spec(module.__name__) - if spec is None: - spec = spec_from_loader(module.__name__, loader) - else: - spec = spec_from_loader(module.__name__, loader) - return cls(spec) - def module_repr(self): """Return the repr to use for the module.""" # We mostly replicate _module_repr() using the spec attributes. @@ -1171,14 +1157,8 @@ # have exec_module() implemented, we can add a deprecation # warning here. spec = self.spec - # The module must be in sys.modules! - try: - _warnings - except NameError: - # We must be importing builtins in setup(). - spec.loader.load_module(spec.name) - else: - spec.loader.load_module(spec.name) + spec.loader.load_module(spec.name) + # The module must be in sys.modules at this point! module = sys.modules[spec.name] if getattr(module, '__loader__', None) is None: try: diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed Jan 8 09:46:15 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 08 Jan 2014 09:46:15 +0100 Subject: [Python-checkins] Daily reference leaks (a9bffe9bdeab): sum=3 Message-ID: results for a9bffe9bdeab on branch "default" -------------------------------------------- test_audioop leaked [1, 1, 1] references, sum=3 test_site leaked [2, 0, -2] references, sum=0 test_site leaked [2, 0, -2] memory blocks, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogzWvqez', '-x'] From python-checkins at python.org Wed Jan 8 15:36:13 2014 From: python-checkins at python.org (victor.stinner) Date: Wed, 8 Jan 2014 15:36:13 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMTEz?= =?utf-8?q?=3A_os=2Ereadv=28=29_and_os=2Ewritev=28=29_now_raise_an_OSError?= =?utf-8?q?_exception_on?= Message-ID: <3dztLP2Zmjz7LjZ@mail.python.org> http://hg.python.org/cpython/rev/1437f499024d changeset: 88354:1437f499024d branch: 3.3 parent: 88350:2807a5f011e4 user: Victor Stinner date: Wed Jan 08 15:21:28 2014 +0100 summary: Issue #20113: os.readv() and os.writev() now raise an OSError exception on error instead of returning -1. files: Lib/test/test_os.py | 9 +++++++++ Lib/test/test_posix.py | 10 +++++++++- Misc/NEWS | 3 +++ Modules/posixmodule.c | 24 +++++++++++++++--------- 4 files changed, 36 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 @@ -1227,6 +1227,11 @@ def test_read(self): self.check(os.read, 1) + @unittest.skipUnless(hasattr(os, 'readv'), 'test needs os.readv()') + def test_readv(self): + buf = bytearray(10) + self.check(os.readv, [buf]) + @unittest.skipUnless(hasattr(os, 'tcsetpgrp'), 'test needs os.tcsetpgrp()') def test_tcsetpgrpt(self): self.check(os.tcsetpgrp, 0) @@ -1235,6 +1240,10 @@ def test_write(self): self.check(os.write, b" ") + @unittest.skipUnless(hasattr(os, 'writev'), 'test needs os.writev()') + def test_writev(self): + self.check(os.writev, [b'abc']) + class LinkTests(unittest.TestCase): def setUp(self): 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 @@ -283,9 +283,14 @@ def test_writev(self): fd = os.open(support.TESTFN, os.O_RDWR | os.O_CREAT) try: - os.writev(fd, (b'test1', b'tt2', b't3')) + n = os.writev(fd, (b'test1', b'tt2', b't3')) + self.assertEqual(n, 10) + os.lseek(fd, 0, os.SEEK_SET) self.assertEqual(b'test1tt2t3', posix.read(fd, 10)) + + # Issue #20113: empty list of buffers should not crash + self.assertEqual(posix.writev(fd, []), 0) finally: os.close(fd) @@ -298,6 +303,9 @@ buf = [bytearray(i) for i in [5, 3, 2]] self.assertEqual(posix.readv(fd, buf), 10) self.assertEqual([b'test1', b'tt2', b't3'], [bytes(i) for i in buf]) + + # Issue #20113: empty list of buffers should not crash + self.assertEqual(posix.readv(fd, []), 0) finally: os.close(fd) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,9 @@ Library ------- +- Issue #20113: os.readv() and os.writev() now raise an OSError exception on + error instead of returning -1. + - Issue #20072: Fixed multiple errors in tkinter with wantobjects is False. - Issue #20108: Avoid parameter name clash in inspect.getcallargs(). diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -8050,14 +8050,14 @@ *iov = PyMem_New(struct iovec, cnt); if (*iov == NULL) { PyErr_NoMemory(); - return total; + return -1; } *buf = PyMem_New(Py_buffer, cnt); if (*buf == NULL) { PyMem_Del(*iov); PyErr_NoMemory(); - return total; + return -1; } for (i = 0; i < cnt; i++) { @@ -8082,7 +8082,7 @@ PyBuffer_Release(&(*buf)[j]); } PyMem_Del(*buf); - return 0; + return -1; } static void @@ -8122,7 +8122,7 @@ } cnt = PySequence_Size(seq); - if (!iov_setup(&iov, &buf, seq, cnt, PyBUF_WRITABLE)) + if (iov_setup(&iov, &buf, seq, cnt, PyBUF_WRITABLE) < 0) return NULL; Py_BEGIN_ALLOW_THREADS @@ -8130,6 +8130,9 @@ Py_END_ALLOW_THREADS iov_cleanup(iov, buf, cnt); + if (n < 0) + return posix_error(); + return PyLong_FromSsize_t(n); } #endif @@ -8254,8 +8257,8 @@ Py_ssize_t i = 0; /* Avoid uninitialized warning */ sf.hdr_cnt = PySequence_Size(headers); if (sf.hdr_cnt > 0 && - !(i = iov_setup(&(sf.headers), &hbuf, - headers, sf.hdr_cnt, PyBUF_SIMPLE))) + (i = iov_setup(&(sf.headers), &hbuf, + headers, sf.hdr_cnt, PyBUF_SIMPLE)) < 0) return NULL; #ifdef __APPLE__ sbytes += i; @@ -8271,8 +8274,8 @@ Py_ssize_t i = 0; /* Avoid uninitialized warning */ sf.trl_cnt = PySequence_Size(trailers); if (sf.trl_cnt > 0 && - !(i = iov_setup(&(sf.trailers), &tbuf, - trailers, sf.trl_cnt, PyBUF_SIMPLE))) + (i = iov_setup(&(sf.trailers), &tbuf, + trailers, sf.trl_cnt, PyBUF_SIMPLE)) < 0) return NULL; #ifdef __APPLE__ sbytes += i; @@ -8483,7 +8486,7 @@ } cnt = PySequence_Size(seq); - if (!iov_setup(&iov, &buf, seq, cnt, PyBUF_SIMPLE)) { + if (iov_setup(&iov, &buf, seq, cnt, PyBUF_SIMPLE) < 0) { return NULL; } @@ -8492,6 +8495,9 @@ Py_END_ALLOW_THREADS iov_cleanup(iov, buf, cnt); + if (res < 0) + return posix_error(); + return PyLong_FromSsize_t(res); } #endif -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 8 15:36:15 2014 From: python-checkins at python.org (victor.stinner) Date: Wed, 8 Jan 2014 15:36:15 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogKE1lcmdlIDMuMykgSXNzdWUgIzIwMTEzOiBvcy5yZWFkdigpIGFuZCBv?= =?utf-8?q?s=2Ewritev=28=29_now_raise_an_OSError?= Message-ID: <3dztLR0Sk5z7Ljl@mail.python.org> http://hg.python.org/cpython/rev/cd50efdce294 changeset: 88355:cd50efdce294 parent: 88353:c0b0e7aef360 parent: 88354:1437f499024d user: Victor Stinner date: Wed Jan 08 15:26:12 2014 +0100 summary: (Merge 3.3) Issue #20113: os.readv() and os.writev() now raise an OSError exception on error instead of returning -1. files: Lib/test/test_os.py | 9 +++++++++ Lib/test/test_posix.py | 10 +++++++++- Misc/NEWS | 3 +++ Modules/posixmodule.c | 24 +++++++++++++++--------- 4 files changed, 36 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 @@ -1267,6 +1267,11 @@ def test_read(self): self.check(os.read, 1) + @unittest.skipUnless(hasattr(os, 'readv'), 'test needs os.readv()') + def test_readv(self): + buf = bytearray(10) + self.check(os.readv, [buf]) + @unittest.skipUnless(hasattr(os, 'tcsetpgrp'), 'test needs os.tcsetpgrp()') def test_tcsetpgrpt(self): self.check(os.tcsetpgrp, 0) @@ -1275,6 +1280,10 @@ def test_write(self): self.check(os.write, b" ") + @unittest.skipUnless(hasattr(os, 'writev'), 'test needs os.writev()') + def test_writev(self): + self.check(os.writev, [b'abc']) + class LinkTests(unittest.TestCase): def setUp(self): 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 @@ -283,9 +283,14 @@ def test_writev(self): fd = os.open(support.TESTFN, os.O_RDWR | os.O_CREAT) try: - os.writev(fd, (b'test1', b'tt2', b't3')) + n = os.writev(fd, (b'test1', b'tt2', b't3')) + self.assertEqual(n, 10) + os.lseek(fd, 0, os.SEEK_SET) self.assertEqual(b'test1tt2t3', posix.read(fd, 10)) + + # Issue #20113: empty list of buffers should not crash + self.assertEqual(posix.writev(fd, []), 0) finally: os.close(fd) @@ -298,6 +303,9 @@ buf = [bytearray(i) for i in [5, 3, 2]] self.assertEqual(posix.readv(fd, buf), 10) self.assertEqual([b'test1', b'tt2', b't3'], [bytes(i) for i in buf]) + + # Issue #20113: empty list of buffers should not crash + self.assertEqual(posix.readv(fd, []), 0) finally: os.close(fd) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,9 @@ Library ------- +- Issue #20113: os.readv() and os.writev() now raise an OSError exception on + error instead of returning -1. + - Issue #19719: Make importlib.abc.MetaPathFinder.find_module(), PathEntryFinder.find_loader(), and Loader.load_module() use PEP 451 APIs to help with backwards-compatibility. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -8011,14 +8011,14 @@ *iov = PyMem_New(struct iovec, cnt); if (*iov == NULL) { PyErr_NoMemory(); - return total; + return -1; } *buf = PyMem_New(Py_buffer, cnt); if (*buf == NULL) { PyMem_Del(*iov); PyErr_NoMemory(); - return total; + return -1; } for (i = 0; i < cnt; i++) { @@ -8043,7 +8043,7 @@ PyBuffer_Release(&(*buf)[j]); } PyMem_Del(*buf); - return 0; + return -1; } static void @@ -8083,7 +8083,7 @@ } cnt = PySequence_Size(seq); - if (!iov_setup(&iov, &buf, seq, cnt, PyBUF_WRITABLE)) + if (iov_setup(&iov, &buf, seq, cnt, PyBUF_WRITABLE) < 0) return NULL; Py_BEGIN_ALLOW_THREADS @@ -8091,6 +8091,9 @@ Py_END_ALLOW_THREADS iov_cleanup(iov, buf, cnt); + if (n < 0) + return posix_error(); + return PyLong_FromSsize_t(n); } #endif @@ -8216,8 +8219,8 @@ Py_ssize_t i = 0; /* Avoid uninitialized warning */ sf.hdr_cnt = PySequence_Size(headers); if (sf.hdr_cnt > 0 && - !(i = iov_setup(&(sf.headers), &hbuf, - headers, sf.hdr_cnt, PyBUF_SIMPLE))) + (i = iov_setup(&(sf.headers), &hbuf, + headers, sf.hdr_cnt, PyBUF_SIMPLE)) < 0) return NULL; #ifdef __APPLE__ sbytes += i; @@ -8233,8 +8236,8 @@ Py_ssize_t i = 0; /* Avoid uninitialized warning */ sf.trl_cnt = PySequence_Size(trailers); if (sf.trl_cnt > 0 && - !(i = iov_setup(&(sf.trailers), &tbuf, - trailers, sf.trl_cnt, PyBUF_SIMPLE))) + (i = iov_setup(&(sf.trailers), &tbuf, + trailers, sf.trl_cnt, PyBUF_SIMPLE)) < 0) return NULL; #ifdef __APPLE__ sbytes += i; @@ -8475,7 +8478,7 @@ } cnt = PySequence_Size(seq); - if (!iov_setup(&iov, &buf, seq, cnt, PyBUF_SIMPLE)) { + if (iov_setup(&iov, &buf, seq, cnt, PyBUF_SIMPLE) < 0) { return NULL; } @@ -8484,6 +8487,9 @@ Py_END_ALLOW_THREADS iov_cleanup(iov, buf, cnt); + if (res < 0) + return posix_error(); + return PyLong_FromSsize_t(res); } #endif -- Repository URL: http://hg.python.org/cpython From zachary.ware at gmail.com Fri Jan 3 17:27:18 2014 From: zachary.ware at gmail.com (Zachary Ware) Date: Fri, 3 Jan 2014 10:27:18 -0600 Subject: [Python-checkins] cpython: add unicode_char() in unicodeobject.c to factorize code In-Reply-To: <3dwl7d4x8cz7Ljs@mail.python.org> References: <3dwl7d4x8cz7Ljs@mail.python.org> Message-ID: On Fri, Jan 3, 2014 at 6:01 AM, victor.stinner wrote: > http://hg.python.org/cpython/rev/d453c95def31 > changeset: 88271:d453c95def31 > user: Victor Stinner > date: Fri Jan 03 12:53:47 2014 +0100 > summary: > add unicode_char() in unicodeobject.c to factorize code > > files: > Objects/unicodeobject.c | 86 ++++++++++------------------ > 1 files changed, 31 insertions(+), 55 deletions(-) > > > diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c > --- a/Objects/unicodeobject.c > +++ b/Objects/unicodeobject.c > @@ -2887,17 +2883,7 @@ > return NULL; > } > > - if ((Py_UCS4)ordinal < 256) > - return get_latin1_char((unsigned char)ordinal); > - > - v = PyUnicode_New(1, ordinal); > - if (v == NULL) > - return NULL; > - kind = PyUnicode_KIND(v); > - data = PyUnicode_DATA(v); > - PyUnicode_WRITE(kind, data, 0, ordinal); > - assert(_PyUnicode_CheckConsistency(v, 1)); > - return v; > + return unicode_char((Py_UCS4)ordinal); > } > > PyObject * > @@ -11354,17 +11340,7 @@ > kind = PyUnicode_KIND(self); > data = PyUnicode_DATA(self); > ch = PyUnicode_READ(kind, data, index); > - if (ch < 256) > - return get_latin1_char(ch); > - > - res = PyUnicode_New(1, ch); > - if (res == NULL) > - return NULL; > - kind = PyUnicode_KIND(res); > - data = PyUnicode_DATA(res); > - PyUnicode_WRITE(kind, data, 0, ch); > - assert(_PyUnicode_CheckConsistency(res, 1)); > - return res; > + return unicode_char(ch); > } > > /* Believe it or not, this produces the same value for ASCII strings The above-quoted parts of this changeset caused several compiler warnings due to unused variables. On 32-bit Windows: ..\Objects\unicodeobject.c(2881): warning C4101: 'kind' : unreferenced local variable [P:\ath\to\cpython\PCbuild\pythoncore.vcxproj] ..\Objects\unicodeobject.c(2879): warning C4101: 'v' : unreferenced local variable [P:\ath\to\cpython\PCbuild\pythoncore.vcxproj] ..\Objects\unicodeobject.c(2880): warning C4101: 'data' : unreferenced local variable [P:\ath\to\cpython\PCbuild\pythoncore.vcxproj] ..\Objects\unicodeobject.c(11333): warning C4101: 'res' : unreferenced local variable [P:\ath\to\cpython\PCbuild\pythoncore.vcxproj] I believe this should fix it, but I'll leave it up to you to confirm that, Victor :) diff -r 8a3718f31188 Objects/unicodeobject.c --- a/Objects/unicodeobject.c Fri Jan 03 15:53:20 2014 +0100 +++ b/Objects/unicodeobject.c Fri Jan 03 10:20:12 2014 -0600 @@ -2876,10 +2876,6 @@ PyObject * PyUnicode_FromOrdinal(int ordinal) { - PyObject *v; - void *data; - int kind; - if (ordinal < 0 || ordinal > MAX_UNICODE) { PyErr_SetString(PyExc_ValueError, "chr() arg not in range(0x110000)"); @@ -11330,7 +11326,6 @@ void *data; enum PyUnicode_Kind kind; Py_UCS4 ch; - PyObject *res; if (!PyUnicode_Check(self) || PyUnicode_READY(self) == -1) { PyErr_BadArgument(); -- Zach From victor.stinner at gmail.com Fri Jan 3 17:42:23 2014 From: victor.stinner at gmail.com (Victor Stinner) Date: Fri, 3 Jan 2014 17:42:23 +0100 Subject: [Python-checkins] [Python-Dev] cpython: add unicode_char() in unicodeobject.c to factorize code In-Reply-To: References: <3dwl7d4x8cz7Ljs@mail.python.org> Message-ID: 2014/1/3 Zachary Ware : > The above-quoted parts of this changeset caused several compiler > warnings due to unused variables. On 32-bit Windows: > (...) > I believe this should fix it, but I'll leave it up to you to confirm > that, Victor :) Oh, I didn't notice these warnings. I fixed them, thanks. Victor From python-checkins at python.org Wed Jan 8 16:01:54 2014 From: python-checkins at python.org (victor.stinner) Date: Wed, 8 Jan 2014 16:01:54 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMTEz?= =?utf-8?q?=3A_Fix_test=5Fposix_on_OpenIndiana?= Message-ID: <3dztw24YjXz7Ljb@mail.python.org> http://hg.python.org/cpython/rev/1993a8ec3f19 changeset: 88356:1993a8ec3f19 branch: 3.3 parent: 88354:1437f499024d user: Victor Stinner date: Wed Jan 08 16:01:31 2014 +0100 summary: Issue #20113: Fix test_posix on OpenIndiana files: Lib/test/test_posix.py | 18 ++++++++++++++++-- 1 files changed, 16 insertions(+), 2 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 @@ -290,7 +290,14 @@ self.assertEqual(b'test1tt2t3', posix.read(fd, 10)) # Issue #20113: empty list of buffers should not crash - self.assertEqual(posix.writev(fd, []), 0) + try: + size = posix.writev(fd, []) + except OSError: + # writev(fd, []) raises OSError(22, "Invalid argument") + # on OpenIndiana + pass + else: + self.assertEqual(size, 0) finally: os.close(fd) @@ -305,7 +312,14 @@ self.assertEqual([b'test1', b'tt2', b't3'], [bytes(i) for i in buf]) # Issue #20113: empty list of buffers should not crash - self.assertEqual(posix.readv(fd, []), 0) + try: + size = posix.readv(fd, []) + except OSError: + # readv(fd, []) raises OSError(22, "Invalid argument") + # on OpenIndiana + pass + else: + self.assertEqual(size, 0) finally: os.close(fd) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 8 16:01:55 2014 From: python-checkins at python.org (victor.stinner) Date: Wed, 8 Jan 2014 16:01:55 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_=28Merge_3=2E3=29_Issue_=2320113=3A_Fix_test=5Fposix_on_?= =?utf-8?q?OpenIndiana?= Message-ID: <3dztw367Gpz7Ljr@mail.python.org> http://hg.python.org/cpython/rev/f1f707dd7cae changeset: 88357:f1f707dd7cae parent: 88355:cd50efdce294 parent: 88356:1993a8ec3f19 user: Victor Stinner date: Wed Jan 08 16:01:42 2014 +0100 summary: (Merge 3.3) Issue #20113: Fix test_posix on OpenIndiana files: Lib/test/test_posix.py | 18 ++++++++++++++++-- 1 files changed, 16 insertions(+), 2 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 @@ -290,7 +290,14 @@ self.assertEqual(b'test1tt2t3', posix.read(fd, 10)) # Issue #20113: empty list of buffers should not crash - self.assertEqual(posix.writev(fd, []), 0) + try: + size = posix.writev(fd, []) + except OSError: + # writev(fd, []) raises OSError(22, "Invalid argument") + # on OpenIndiana + pass + else: + self.assertEqual(size, 0) finally: os.close(fd) @@ -305,7 +312,14 @@ self.assertEqual([b'test1', b'tt2', b't3'], [bytes(i) for i in buf]) # Issue #20113: empty list of buffers should not crash - self.assertEqual(posix.readv(fd, []), 0) + try: + size = posix.readv(fd, []) + except OSError: + # readv(fd, []) raises OSError(22, "Invalid argument") + # on OpenIndiana + pass + else: + self.assertEqual(size, 0) finally: os.close(fd) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 8 23:21:34 2014 From: python-checkins at python.org (r.david.murray) Date: Wed, 8 Jan 2014 23:21:34 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_FileIO=2Ereada?= =?utf-8?q?ll_performance=2C_os=2Ecpu=5Fcount=2E?= Message-ID: <3f04gL0Jk6zNGX@mail.python.org> http://hg.python.org/cpython/rev/57dd16953c8c changeset: 88358:57dd16953c8c user: R David Murray date: Wed Jan 08 17:21:22 2014 -0500 summary: whatsnew: FileIO.readall performance, os.cpu_count. And more news item tweaks. files: Doc/whatsnew/3.4.rst | 12 ++++++++++++ Misc/NEWS | 12 +++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) 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 @@ -853,6 +853,11 @@ * :func:`os.get_inheritable`, :func:`os.set_inheritable` * :func:`os.get_handle_inheritable`, :func:`os.set_handle_inheritable` +The :mod:`os` module now provides a :func:`~os.cpu_count` function, analogous to +the :func:`multiprocessing.cpu_count` function (which is now implemented in +terms of the new :mod:`os` function). (Contributed by Trent Nelson, Yogesh +Chaudhari, Victor Stinner, and Charles-Fran?ois Natali in :issue:`17914`.) + pdb --- @@ -985,6 +990,8 @@ using the new :mod:`enum` module. This allows meaningful names to be printed during debugging, instead of integer "magic numbers". +The :data:`~socket.AF_LINK` constant is now available on BSD and OSX. + sqlite3 ------- @@ -1341,6 +1348,11 @@ strings is now significantly faster. (Contributed by Victor Stinner and Antoine Pitrou in :issue:`15596`.) +* A performance issue in :meth:`io.FileIO.readall` has been solved. This + particularly affects Windows, and significantly speeds up the case of piping + significant amounts of data through :mod:`subprocess`. (Contributed + by Richard Oudkerk in :issue:`15758`.) + Deprecated diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2163,9 +2163,11 @@ - Issue #15758: Fix FileIO.readall() so it no longer has O(n**2) complexity. -- Issue #14596: The struct.Struct() objects now use more compact implementation. - -- Issue #17981: Closed socket on error in SysLogHandler. +- Issue #14596: The struct.Struct() objects now use a more compact + implementation. + +- Issue #17981: logging's SysLogHandler now closes the socket when it catches + socket OSErrors. - Issue #17964: Fix os.sysconf(): the return type of the C sysconf() function is long, not int. @@ -2186,8 +2188,8 @@ - Issue #17915: Fix interoperability of xml.sax with file objects returned by codecs.open(). -- Issue #16601: Restarting iteration over tarfile no more continues from where - it left off. Patch by Michael Birtwell. +- Issue #16601: Restarting iteration over tarfile really restarts rather + than continuing from where it left off. Patch by Michael Birtwell. - Issue #17289: The readline module now plays nicer with external modules or applications changing the rl_completer_word_break_characters global -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 8 23:38:23 2014 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 8 Jan 2014 23:38:23 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Overhaul_PEP_460=2C_and_add_m?= =?utf-8?q?yself_as_author?= Message-ID: <3f052l1KnBz7LjP@mail.python.org> http://hg.python.org/peps/rev/0eb61dc46738 changeset: 5339:0eb61dc46738 user: Antoine Pitrou date: Wed Jan 08 23:38:18 2014 +0100 summary: Overhaul PEP 460, and add myself as author files: pep-0460.txt | 203 ++++++++++++++++++-------------------- 1 files changed, 95 insertions(+), 108 deletions(-) diff --git a/pep-0460.txt b/pep-0460.txt --- a/pep-0460.txt +++ b/pep-0460.txt @@ -1,8 +1,8 @@ PEP: 460 -Title: Add bytes % args and bytes.format(args) to Python 3.5 +Title: Add binary interpolation and formatting Version: $Revision$ Last-Modified: $Date$ -Author: Victor Stinner +Author: Victor Stinner , Antoine Pitrou Status: Draft Type: Standards Track Content-Type: text/x-rst @@ -13,136 +13,124 @@ Abstract ======== -Add ``bytes % args`` operator and ``bytes.format(args)`` method to -Python 3.5. +This PEP proposes to add minimal formatting operations to bytes and +bytearray objects. The proposed additions are: + +* ``bytes % ...`` and ``bytearray % ...`` for percent-formatting, + similar in syntax to percent-formatting on ``str`` objects + (accepting a single object, a tuple or a dict). + +* ``bytes.format(...)`` and ``bytearray.format(...)`` for a formatting + similar in syntax to ``str.format()`` (accepting positional as well as + keyword arguments). Rationale ========= -``bytes % args`` and ``bytes.format(args)`` have been removed in Python -2. This operator and this method are requested by Mercurial and Twisted -developers to ease porting their project on Python 3. +In Python 2, ``str % args`` and ``str.format(args)`` allow the formatting +and interpolation of 8-bit strings. This feature has commonly been used +for the assembling of protocol messages when protocols are known to use +a fixed encoding. -Python 3 suggests to format text first and then encode to bytes. In -some cases, it does not make sense because arguments are bytes strings. -Typical usage is a network protocol which is binary, since data are -send to and received from sockets. For example, SMTP, SIP, HTTP, IMAP, -POP, FTP are ASCII commands interspersed with binary data. +Python 3 generally mandates that text be stored and manipulated as unicode +(i.e. ``str`` objects, not ``bytes``). In some cases, though, it makes +sense to manipulate ``bytes`` objects directly. Typical usage is binary +network protocols, where you can want to interpolate and assemble several +bytes object (some of them literals, some of them compute) to produce +complete protocol messages. For example, protocols such as HTTP or SIP +have headers with ASCII names and opaque "textual" values using a varying +and/or sometimes ill-defined encoding. Moreover, those headers can be +followed by a binary body... which can be chunked and decorated with ASCII +headers and trailers! -Using multiple ``bytes + bytes`` instructions is inefficient because it -requires temporary buffers and copies which are slow and waste memory. -Python 3.3 optimizes ``str2 += str2`` but not ``bytes2 += bytes1``. +While there are reasonably efficient ways to accumulate binary data +(such as using a ``bytearray`` object, the ``bytes.join`` method or +even ``io.BytesIO``), none of them leads to the kind of readable and +intuitive code that is produced by a %-formatted or {}-formatted template +and a formatting operation. -``bytes % args`` and ``bytes.format(args)`` were asked since 2008, even -before the first release of Python 3.0 (see issue #3982). -``struct.pack()`` is incomplete. For example, a number cannot be -formatted as decimal and it does not support padding bytes string. +Binary formatting features +========================== -Mercurial 2.8 still supports Python 2.4. +Supported features +------------------ +In this proposal, percent-formatting for ``bytes`` and ``bytearray`` +supports the following features: -Needed and excluded features -============================ +* Looking up formatting arguments by position as well as by name (i.e., + ``%s`` as well as ``%(name)s``). +* ``%s`` will try to get a ``Py_buffer`` on the given value, and fallback + on calling ``__bytes__``. The resulting binary data is inserted at + the given point in the string. This is expected to work with bytes, + bytearray and memoryview objects (as well as a couple others such + as pathlib's path objects). +* ``%c`` will accept an integer between 0 and 255, and insert a byte of the + given value. -Needed features +Braces-formatting for ``bytes`` and ``bytearray`` supports the following +features: -* Bytes strings: bytes, bytearray and memoryview types -* Format integer numbers as decimal -* Padding with spaces and null bytes -* "%s" should use the buffer protocol, not str() +* All the kinds of argument lookup supported by ``str.format()`` (explicit + positional lookup, auto-incremented positional lookup, keyword lookup, + attribute lookup, etc.) +* Insertion of binary data when no modifier or layout is specified + (e.g. ``{}``, ``{0}``, ``{name}``). This has the same semantics as + ``%s`` for percent-formatting (see above). +* The ``c`` modifier will accept an integer between 0 and 255, and insert a + byte of the given value (same as ``%c`` above). -The feature set is minimal to keep the implementation as simple as -possible to limit the cost of the implementation. ``str % args`` and -``str.format(args)`` are already complex and difficult to maintain, the -code is heavily optimized. +Unsupported features +-------------------- -Excluded features: +All other features present in formatting of ``str`` objects (either +through the percent operator or the ``str.format()`` method) are +unsupported. Those features imply treating the recipient of the +operator or method as text, which goes counter to the text / bytes +separation (for example, accepting ``%d`` as a format code would imply +that the bytes object really is a ASCII-compatible text string). -* no implicit conversion from Unicode to bytes (ex: encode to ASCII or - to Latin1) -* Locale support (``{!n}`` format for numbers). Locales are related to - text and usually to an encoding. -* ``repr()``, ``ascii()``: ``%r``, ``{!r}``, ``%a`` and ``{!a}`` - formats. ``repr()`` and ``ascii()`` are used to debug, the output is - displayed a terminal or a graphical widget. They are more related to - text. -* Attribute access: ``{obj.attr}`` -* Indexing: ``{dict[key]}`` -* Features of struct.pack(). For example, format a number as 32 bit unsigned - integer in network endian. The ``struct.pack()`` can be used to prepare - arguments, the implementation should be kept simple. -* Features of int.to_bytes(). -* Features of ctypes. -* New format protocol like a new ``__bformat__()`` method. Since the -* list of - supported types is short, there is no need to add a new protocol. - Other types must be explicitly casted. -* Alternate format for integer. For example, ``'{|#x}'.format(0x123)`` - to get ``0x123``. It is more related to debug, and the prefix can be - easily be written in the format string (ex: ``0x%x``). -* Relation with format() and the __format__() protocol. bytes.format() - and str.format() are unrelated. - -Unknown: - -* Format integer to hexadecimal? ``%x`` and ``%X`` -* Format integer to octal? ``%o`` -* Format integer to binary? ``{!b}`` -* Alignment? -* Truncating? Truncate or raise an error? -* format keywords? ``b'{arg}'.format(arg=5)`` -* ``str % dict`` ? ``b'%(arg)s' % {'arg': 5)`` -* Floating point number? -* ``%i``, ``%u`` and ``%d`` formats for integer numbers? -* Signed number? ``%+i`` and ``%-i`` - - -bytes % args -============ - -Formatters: - -* ``"%c"``: one byte -* ``"%s"``: integer or bytes strings -* ``"%20s"`` pads to 20 bytes with spaces (``b' '``) -* ``"%020s"`` pads to 20 bytes with zeros (``b'0'``) -* ``"%\020s"`` pads to 20 bytes with null bytes (``b'\0'``) - - -bytes.format(args) -================== - -Formatters: - -* ``"{!c}"``: one byte -* ``"{!s}"``: integer or bytes strings -* ``"{!.20s}"`` pads to 20 bytes with spaces (``b' '``) -* ``"{!.020s}"`` pads to 20 bytes with zeros (``b'0'``) -* ``"{!\020s}"`` pads to 20 bytes with null bytes (``b'\0'``) - - -Examples -======== - -* ``b'a%sc%s' % (b'b', 4)`` gives ``b'abc4'`` -* ``b'a{}c{}'.format(b'b', 4)`` gives ``b'abc4'`` -* ``b'%c'`` % 88`` gives ``b'X``' -* ``b'%%'`` gives ``b'%'`` +Amongst those unsupported features are not only most type-specific +format codes, but also the various layout specifiers such as padding +or alignment. Besides, ``str`` objects are not acceptable as arguments +to the formatting operations, even when using e.g. the ``%s`` format code. Criticisms ========== * The development cost and maintenance cost. -* In 3.3 encoding to ascii or latin1 is as fast as memcpy -* Developers must work around the lack of bytes%args and - bytes.format(args) anyway to support Python 3.0-3.4 -* bytes.join() is consistently faster than format to join bytes strings. -* Formatting functions can be implemented in a third party module +* In 3.3 encoding to ASCII or latin-1 is as fast as memcpy (but it still + creates a separate object). +* Developers will have to work around the lack of binary formatting anyway, + if they want to to support Python 3.4 and earlier. +* bytes.join() is consistently faster than format to join bytes strings + (XXX *is it?*). +* Formatting functions could be implemented in a third party module, + rather than added to builtin types. +Other proposals +=============== + +A new type datatype +------------------- + +It was proposed to create a new datatype specialized for "network +programming". The authors of this PEP believe this is counter-productive. +Python 3 already has several major types dedicated to manipulation of +binary data: ``bytes``, ``bytearray``, ``memoryview``, ``io.BytesIO``. + +Adding yet another type would make things more confusing for users, and +interoperability between libraries more painful (also potentially +sub-optimal, due to the necessary conversions). + +Moreover, not one type would be needed, but two: one immutable type (to +allow for hashing), and one mutable type (as efficient accumulation is +often necessary when working with network messages). + References ========== @@ -172,4 +160,3 @@ fill-column: 70 coding: utf-8 End: - -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Jan 9 00:15:04 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 9 Jan 2014 00:15:04 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_460=3A_8-bit_string_=3D?= =?utf-8?q?=3E_bytes_string?= Message-ID: <3f05s43d3pz7LjX@mail.python.org> http://hg.python.org/peps/rev/286d2a6182dd changeset: 5340:286d2a6182dd user: Victor Stinner date: Thu Jan 09 00:14:57 2014 +0100 summary: PEP 460: 8-bit string => bytes string files: pep-0460.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0460.txt b/pep-0460.txt --- a/pep-0460.txt +++ b/pep-0460.txt @@ -29,7 +29,7 @@ ========= In Python 2, ``str % args`` and ``str.format(args)`` allow the formatting -and interpolation of 8-bit strings. This feature has commonly been used +and interpolation of bytes strings. This feature has commonly been used for the assembling of protocol messages when protocols are known to use a fixed encoding. -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Jan 9 00:17:01 2014 From: python-checkins at python.org (r.david.murray) Date: Thu, 9 Jan 2014 00:17:01 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fix_verb_tense?= =?utf-8?q?=2E?= Message-ID: <3f05vK5Np3z7LjP@mail.python.org> http://hg.python.org/cpython/rev/4c4ae679eec3 changeset: 88359:4c4ae679eec3 branch: 2.7 parent: 88352:5609135c6e86 user: R David Murray date: Wed Jan 08 18:08:37 2014 -0500 summary: Fix verb tense. files: Doc/library/base64.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/base64.rst b/Doc/library/base64.rst --- a/Doc/library/base64.rst +++ b/Doc/library/base64.rst @@ -93,7 +93,7 @@ digit 0 is always mapped to the letter O). For security purposes the default is ``None``, so that 0 and 1 are not allowed in the input. - The decoded string is returned. A :exc:`TypeError` is raised if *s* were + The decoded string is returned. A :exc:`TypeError` is raised if *s* is incorrectly padded or if there are non-alphabet characters present in the string. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 00:17:03 2014 From: python-checkins at python.org (r.david.murray) Date: Thu, 9 Jan 2014 00:17:03 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Fix_verb_tense?= =?utf-8?q?_in_base64_docs=2C_and_the_phrasing_of_a_news_entry=2E?= Message-ID: <3f05vM0WSKz7LjX@mail.python.org> http://hg.python.org/cpython/rev/04dabdbd512c changeset: 88360:04dabdbd512c branch: 3.3 parent: 88356:1993a8ec3f19 user: R David Murray date: Wed Jan 08 18:09:29 2014 -0500 summary: Fix verb tense in base64 docs, and the phrasing of a news entry. files: Doc/library/base64.rst | 2 +- Misc/NEWS | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/base64.rst b/Doc/library/base64.rst --- a/Doc/library/base64.rst +++ b/Doc/library/base64.rst @@ -103,7 +103,7 @@ digit 0 is always mapped to the letter O). For security purposes the default is ``None``, so that 0 and 1 are not allowed in the input. - The decoded byte string is returned. A :exc:`binascii.Error` is raised if *s* were + The decoded byte string is returned. A :exc:`binascii.Error` is raised if *s* is incorrectly padded or if there are non-alphabet characters present in the string. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -710,9 +710,9 @@ - Issue #18025: Fixed a segfault in io.BufferedIOBase.readinto() when raw stream's read() returns more bytes than requested. -- Issue #18011: base64.b32decode() now raises a binascii.Error if there are - non-alphabet characters present in the input string to conform a docstring. - Updated the module documentation. +- Issue #18011: As was originally intended, base64.b32decode() now raises a + binascii.Error if there are non-b32-alphabet characters present in the input + string, instead of a TypeError. - Issue #13772: Restored directory detection of targets in ``os.symlink`` on Windows, which was temporarily removed in Python 3.2.3 due to an incomplete -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 00:17:04 2014 From: python-checkins at python.org (r.david.murray) Date: Thu, 9 Jan 2014 00:17:04 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge=3A_Fix_verb_tense_in_base64_docs=2C_and_the_phrasi?= =?utf-8?q?ng_of_a_news_entry=2E?= Message-ID: <3f05vN26t6z7Lk0@mail.python.org> http://hg.python.org/cpython/rev/ef83c1414c85 changeset: 88361:ef83c1414c85 parent: 88358:57dd16953c8c parent: 88360:04dabdbd512c user: R David Murray date: Wed Jan 08 18:14:20 2014 -0500 summary: Merge: Fix verb tense in base64 docs, and the phrasing of a news entry. files: Doc/library/base64.rst | 2 +- Misc/NEWS | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/base64.rst b/Doc/library/base64.rst --- a/Doc/library/base64.rst +++ b/Doc/library/base64.rst @@ -107,7 +107,7 @@ digit 0 is always mapped to the letter O). For security purposes the default is ``None``, so that 0 and 1 are not allowed in the input. - The decoded byte string is returned. A :exc:`binascii.Error` is raised if *s* were + The decoded byte string is returned. A :exc:`binascii.Error` is raised if *s* is incorrectly padded or if there are non-alphabet characters present in the string. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2131,9 +2131,9 @@ - Issue #18025: Fixed a segfault in io.BufferedIOBase.readinto() when raw stream's read() returns more bytes than requested. -- Issue #18011: base64.b32decode() now raises a binascii.Error if there are - non-alphabet characters present in the input string to conform a docstring. - Updated the module documentation. +- Issue #18011: As was originally intended, base64.b32decode() now raises a + binascii.Error if there are non-b32-alphabet characters present in the input + string, instead of a TypeError. - Issue #18072: Implement importlib.abc.InspectLoader.get_code() and importlib.abc.ExecutionLoader.get_code(). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 00:17:05 2014 From: python-checkins at python.org (r.david.murray) Date: Thu, 9 Jan 2014 00:17:05 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_InspectLoader?= =?utf-8?q?=2Eget=5Fcode_now_concrete=2C_b32decode_raises_binascii=2EError?= =?utf-8?q?=2E?= Message-ID: <3f05vP3rMQz7LkB@mail.python.org> http://hg.python.org/cpython/rev/9e3f5b5bcf7e changeset: 88362:9e3f5b5bcf7e user: R David Murray date: Wed Jan 08 18:16:02 2014 -0500 summary: whatsnew: InspectLoader.get_code now concrete, b32decode raises binascii.Error. And a news item rephrase. files: Doc/library/importlib.rst | 8 ++++---- Doc/whatsnew/3.4.rst | 12 ++++++++++++ Misc/NEWS | 4 ++-- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -478,10 +478,10 @@ .. method:: get_code(fullname) - Return the code object for a module. - ``None`` should be returned if the module does not have a code object - (e.g. built-in module). :exc:`ImportError` is raised if loader cannot - find the requested module. + Return the code object for a module, or ``None`` if the module does not + have a code object (as would be the case, for example, for a built-in + module). Raise an :exc:`ImportError` if loader cannot find the + requested module. .. note:: While the method has a default implementation, it is suggested that 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 @@ -750,6 +750,11 @@ is equivalent to ``compile(data, path, 'exec', dont_inherit=True)``. (Contributed by Eric Snow and Brett Cannon in :issue:`15627`.) +:class:`~importlib.abc.InspectLoader` also now has a default implementation +for the :meth:`~importlib.abc.InspectLoader.get_code` method. However, +it will normally be desirable to override the default implementation +for performance reasons. (Contributed by Brett Cannon in :issue:`18072`.) + inspect ------- @@ -1546,6 +1551,13 @@ :exc:`AttributError`. In addition, :meth:`~ssl.SSLSocket.getpeercert` will raise a :exc:`ValueError` if the handshake has not yet been done. +* :func:`base64.b32decode` now raises a :exc:`binascii.Error` when the + input string contains non-b32-alphabet characters, instead of a + :exc:`TypeError`. This particular :exc:`TypeError` was missed when the other + :exc:`TypeError`\ s were converted. (Contributed by Serhiy Storchaka in + :issue:`18011`.) Note: this change was also inadvertently applied in Python + 3.3.3. + Changes in the C API -------------------- diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2144,8 +2144,8 @@ - Issue #17269: Workaround for socket.getaddrinfo crash on MacOS X with port None or "0" and flags AI_NUMERICSERV. -- Issue #16986: ElementTree now correctly parses a string input not only when - an internal XML encoding is UTF-8 or US-ASCII. +- Issue #16986: ElementTree now correctly works with string input when the + internal XML encoding is not UTF-8 or US-ASCII. - Issue #17996: socket module now exposes AF_LINK constant on BSD and OSX. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu Jan 9 09:46:08 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 09 Jan 2014 09:46:08 +0100 Subject: [Python-checkins] Daily reference leaks (9e3f5b5bcf7e): sum=935 Message-ID: results for 9e3f5b5bcf7e on branch "default" -------------------------------------------- test_asyncio leaked [4, 0, 0] memory blocks, sum=4 test_audioop leaked [1, 1, 1] references, sum=3 test_pkgutil leaked [21, 21, 21] references, sum=63 test_pkgutil leaked [18, 18, 18] memory blocks, sum=54 test_runpy leaked [84, 84, 84] references, sum=252 test_runpy leaked [71, 71, 71] memory blocks, sum=213 test_site leaked [2, -2, 2] references, sum=2 test_site leaked [2, -2, 2] memory blocks, sum=2 test_zipimport leaked [20, 20, 20] references, sum=60 test_zipimport leaked [17, 17, 17] memory blocks, sum=51 test_zipimport_support leaked [42, 42, 42] references, sum=126 test_zipimport_support leaked [35, 35, 35] memory blocks, sum=105 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogu0u1Tz', '-x'] From python-checkins at python.org Thu Jan 9 13:54:25 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 9 Jan 2014 13:54:25 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMDc4?= =?utf-8?q?=3A_Reading_malformed_zipfiles_no_longer_hangs_with_100=25_CPU?= Message-ID: <3f0S2T5M2Rz7LjP@mail.python.org> http://hg.python.org/cpython/rev/0cf1defd5ac4 changeset: 88363:0cf1defd5ac4 branch: 3.3 parent: 88360:04dabdbd512c user: Serhiy Storchaka date: Thu Jan 09 14:50:20 2014 +0200 summary: Issue #20078: Reading malformed zipfiles no longer hangs with 100% CPU consumption. files: Lib/test/test_zipfile.py | 31 ++++++++++++++++++++++++++++ Lib/zipfile.py | 2 + Misc/NEWS | 3 ++ 3 files changed, 36 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 @@ -293,6 +293,36 @@ buf = fp.read(test_size) self.assertEqual(len(buf), test_size) + def test_truncated_zipfile(self): + fp = io.BytesIO() + with zipfile.ZipFile(fp, mode='w') as zipf: + zipf.writestr('strfile', self.data, compress_type=self.compression) + end_offset = fp.tell() + zipfiledata = fp.getvalue() + + fp = io.BytesIO(zipfiledata) + with zipfile.ZipFile(fp) as zipf: + with zipf.open('strfile') as zipopen: + fp.truncate(end_offset - 20) + with self.assertRaises(EOFError): + zipopen.read() + + fp = io.BytesIO(zipfiledata) + with zipfile.ZipFile(fp) as zipf: + with zipf.open('strfile') as zipopen: + fp.truncate(end_offset - 20) + with self.assertRaises(EOFError): + while zipopen.read(100): + pass + + fp = io.BytesIO(zipfiledata) + with zipfile.ZipFile(fp) as zipf: + with zipf.open('strfile') as zipopen: + fp.truncate(end_offset - 20) + with self.assertRaises(EOFError): + while zipopen.read1(100): + pass + def tearDown(self): unlink(TESTFN) unlink(TESTFN2) @@ -389,6 +419,7 @@ with zipfile.ZipFile(TESTFN2, "w") as zipfp: self.assertRaises(ValueError, zipfp.write, TESTFN) + @requires_zlib class DeflateTestsWithSourceFile(AbstractTestsWithSourceFile, unittest.TestCase): diff --git a/Lib/zipfile.py b/Lib/zipfile.py --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -860,6 +860,8 @@ data = self._fileobj.read(n) self._compress_left -= len(data) + if not data: + raise EOFError if self._decrypter is not None: data = bytes(map(self._decrypter, data)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,9 @@ Library ------- +- Issue #20078: Reading malformed zipfiles no longer hangs with 100% CPU + consumption. + - Issue #20113: os.readv() and os.writev() now raise an OSError exception on error instead of returning -1. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 13:54:27 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 9 Jan 2014 13:54:27 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320078=3A_Reading_malformed_zipfiles_no_longer_h?= =?utf-8?q?angs_with_100=25_CPU?= Message-ID: <3f0S2W0Nf1z7LjT@mail.python.org> http://hg.python.org/cpython/rev/79ea4ce431b1 changeset: 88364:79ea4ce431b1 parent: 88362:9e3f5b5bcf7e parent: 88363:0cf1defd5ac4 user: Serhiy Storchaka date: Thu Jan 09 14:53:41 2014 +0200 summary: Issue #20078: Reading malformed zipfiles no longer hangs with 100% CPU consumption. files: Lib/test/test_zipfile.py | 31 ++++++++++++++++++++++++++++ Lib/zipfile.py | 2 + Misc/NEWS | 3 ++ 3 files changed, 36 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 @@ -297,6 +297,36 @@ buf = fp.read(test_size) self.assertEqual(len(buf), test_size) + def test_truncated_zipfile(self): + fp = io.BytesIO() + with zipfile.ZipFile(fp, mode='w') as zipf: + zipf.writestr('strfile', self.data, compress_type=self.compression) + end_offset = fp.tell() + zipfiledata = fp.getvalue() + + fp = io.BytesIO(zipfiledata) + with zipfile.ZipFile(fp) as zipf: + with zipf.open('strfile') as zipopen: + fp.truncate(end_offset - 20) + with self.assertRaises(EOFError): + zipopen.read() + + fp = io.BytesIO(zipfiledata) + with zipfile.ZipFile(fp) as zipf: + with zipf.open('strfile') as zipopen: + fp.truncate(end_offset - 20) + with self.assertRaises(EOFError): + while zipopen.read(100): + pass + + fp = io.BytesIO(zipfiledata) + with zipfile.ZipFile(fp) as zipf: + with zipf.open('strfile') as zipopen: + fp.truncate(end_offset - 20) + with self.assertRaises(EOFError): + while zipopen.read1(100): + pass + def tearDown(self): unlink(TESTFN) unlink(TESTFN2) @@ -393,6 +423,7 @@ with zipfile.ZipFile(TESTFN2, "w") as zipfp: self.assertRaises(ValueError, zipfp.write, TESTFN) + @requires_zlib class DeflateTestsWithSourceFile(AbstractTestsWithSourceFile, unittest.TestCase): diff --git a/Lib/zipfile.py b/Lib/zipfile.py --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -862,6 +862,8 @@ data = self._fileobj.read(n) self._compress_left -= len(data) + if not data: + raise EOFError if self._decrypter is not None: data = bytes(map(self._decrypter, data)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,9 @@ Library ------- +- Issue #20078: Reading malformed zipfiles no longer hangs with 100% CPU + consumption. + - Issue #20113: os.readv() and os.writev() now raise an OSError exception on error instead of returning -1. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 16:37:06 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 9 Jan 2014 16:37:06 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_fix_zipimport_?= =?utf-8?q?ref_leak?= Message-ID: <3f0WfB6STNz7LjN@mail.python.org> http://hg.python.org/cpython/rev/d28242a636c7 changeset: 88365:d28242a636c7 branch: 3.3 parent: 88363:0cf1defd5ac4 user: Benjamin Peterson date: Thu Jan 09 09:36:10 2014 -0600 summary: fix zipimport ref leak files: Modules/zipimport.c | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/Modules/zipimport.c b/Modules/zipimport.c --- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -958,10 +958,8 @@ } Py_XDECREF(self->files); /* free the old value. */ self->files = files; - } else { - /* No problem, discard the new stat data. */ - Py_DECREF(stat_now); } + Py_DECREF(stat_now); } /* stat succeeded */ return fp; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 16:37:08 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 9 Jan 2014 16:37:08 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3f0WfD17qVz7LjT@mail.python.org> http://hg.python.org/cpython/rev/a1a5c4274c1c changeset: 88366:a1a5c4274c1c parent: 88364:79ea4ce431b1 parent: 88365:d28242a636c7 user: Benjamin Peterson date: Thu Jan 09 09:36:23 2014 -0600 summary: merge 3.3 files: Modules/zipimport.c | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/Modules/zipimport.c b/Modules/zipimport.c --- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -961,10 +961,8 @@ } Py_XDECREF(self->files); /* free the old value. */ self->files = files; - } else { - /* No problem, discard the new stat data. */ - Py_DECREF(stat_now); } + Py_DECREF(stat_now); } /* stat succeeded */ return fp; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 16:37:09 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 9 Jan 2014 16:37:09 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_fix_zipimport_?= =?utf-8?q?ref_leak?= Message-ID: <3f0WfF2wLTz7LkC@mail.python.org> http://hg.python.org/cpython/rev/30d761849a27 changeset: 88367:30d761849a27 branch: 2.7 parent: 88359:4c4ae679eec3 user: Benjamin Peterson date: Thu Jan 09 09:36:10 2014 -0600 summary: fix zipimport ref leak files: Modules/zipimport.c | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/Modules/zipimport.c b/Modules/zipimport.c --- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -832,10 +832,8 @@ } Py_XDECREF(self->files); /* free the old value. */ self->files = files; - } else { - /* No problem, discard the new stat data. */ - Py_DECREF(stat_now); } + Py_DECREF(stat_now); } /* stat succeeded */ return fp; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 17:42:29 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 9 Jan 2014 17:42:29 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4OTYw?= =?utf-8?q?=3A_Fix_bugs_with_Python_source_code_encoding_in_the_second_lin?= =?utf-8?q?e=2E?= Message-ID: <3f0Y5d2kBKz7LmQ@mail.python.org> http://hg.python.org/cpython/rev/1bdcaf6c0eb5 changeset: 88368:1bdcaf6c0eb5 branch: 3.3 parent: 88365:d28242a636c7 user: Serhiy Storchaka date: Thu Jan 09 18:36:09 2014 +0200 summary: Issue #18960: Fix bugs with Python source code encoding in the second line. * The first line of Python script could be executed twice when the source encoding (not equal to 'utf-8') was specified on the second line. * Now the source encoding declaration on the second line isn't effective if the first line contains anything except a comment. * As a consequence, 'python -x' works now again with files with the source encoding declarations specified on the second file, and can be used again to make Python batch files on Windows. * The tokenize module now ignore the source encoding declaration on the second line if the first line contains anything except a comment. * IDLE now ignores the source encoding declaration on the second line if the first line contains anything except a comment. * 2to3 and the findnocoding.py script now ignore the source encoding declaration on the second line if the first line contains anything except a comment. files: Lib/idlelib/IOBinding.py | 3 ++ Lib/lib2to3/pgen2/tokenize.py | 3 ++ Lib/test/test_tokenize.py | 33 +++++++++++++++++++++++ Lib/tokenize.py | 3 ++ Misc/NEWS | 20 +++++++++++++ Parser/tokenizer.c | 26 +++++++++++++++-- Tools/scripts/findnocoding.py | 4 ++- 7 files changed, 87 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/IOBinding.py b/Lib/idlelib/IOBinding.py --- a/Lib/idlelib/IOBinding.py +++ b/Lib/idlelib/IOBinding.py @@ -64,6 +64,7 @@ ### 'encoding' is used below in encode(), check! coding_re = re.compile(r'^[ \t\f]*#.*coding[:=][ \t]*([-\w.]+)', re.ASCII) +blank_re = re.compile(r'^[ \t\f]*(?:[#\r\n]|$)', re.ASCII) def coding_spec(data): """Return the encoding declaration according to PEP 263. @@ -93,6 +94,8 @@ match = coding_re.match(line) if match is not None: break + if not blank_re.match(line): + return None else: return None name = match.group(1) diff --git a/Lib/lib2to3/pgen2/tokenize.py b/Lib/lib2to3/pgen2/tokenize.py --- a/Lib/lib2to3/pgen2/tokenize.py +++ b/Lib/lib2to3/pgen2/tokenize.py @@ -237,6 +237,7 @@ toks_append(tokval) cookie_re = re.compile(r'^[ \t\f]*#.*coding[:=][ \t]*([-\w.]+)', re.ASCII) +blank_re = re.compile(br'^[ \t\f]*(?:[#\r\n]|$)', re.ASCII) def _get_normal_name(orig_enc): """Imitates get_normal_name in tokenizer.c.""" @@ -309,6 +310,8 @@ encoding = find_cookie(first) if encoding: return encoding, [first] + if not blank_re.match(first): + return default, [first] second = read_or_stop() if not second: diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -885,6 +885,39 @@ readline = self.get_readline(lines) self.assertRaises(SyntaxError, detect_encoding, readline) + def test_cookie_second_line_noncommented_first_line(self): + lines = ( + b"print('\xc2\xa3')\n", + b'# vim: set fileencoding=iso8859-15 :\n', + b"print('\xe2\x82\xac')\n" + ) + encoding, consumed_lines = detect_encoding(self.get_readline(lines)) + self.assertEqual(encoding, 'utf-8') + expected = [b"print('\xc2\xa3')\n"] + self.assertEqual(consumed_lines, expected) + + def test_cookie_second_line_commented_first_line(self): + lines = ( + b"#print('\xc2\xa3')\n", + b'# vim: set fileencoding=iso8859-15 :\n', + b"print('\xe2\x82\xac')\n" + ) + encoding, consumed_lines = detect_encoding(self.get_readline(lines)) + self.assertEqual(encoding, 'iso8859-15') + expected = [b"#print('\xc2\xa3')\n", b'# vim: set fileencoding=iso8859-15 :\n'] + self.assertEqual(consumed_lines, expected) + + def test_cookie_second_line_empty_first_line(self): + lines = ( + b'\n', + b'# vim: set fileencoding=iso8859-15 :\n', + b"print('\xe2\x82\xac')\n" + ) + encoding, consumed_lines = detect_encoding(self.get_readline(lines)) + self.assertEqual(encoding, 'iso8859-15') + expected = [b'\n', b'# vim: set fileencoding=iso8859-15 :\n'] + self.assertEqual(consumed_lines, expected) + def test_latin1_normalization(self): # See get_normal_name() in tokenizer.c. encodings = ("latin-1", "iso-8859-1", "iso-latin-1", "latin-1-unix", diff --git a/Lib/tokenize.py b/Lib/tokenize.py --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -32,6 +32,7 @@ import collections from io import TextIOWrapper cookie_re = re.compile(r'^[ \t\f]*#.*coding[:=][ \t]*([-\w.]+)', re.ASCII) +blank_re = re.compile(br'^[ \t\f]*(?:[#\r\n]|$)', re.ASCII) import token __all__ = token.__all__ + ["COMMENT", "tokenize", "detect_encoding", @@ -409,6 +410,8 @@ encoding = find_cookie(first) if encoding: return encoding, [first] + if not blank_re.match(first): + return default, [first] second = read_or_stop() if not second: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,13 @@ Core and Builtins ----------------- +- Issue #18960: The first line of Python script could be executed twice when + the source encoding was specified on the second line. Now the source encoding + declaration on the second line isn't effective if the first line contains + anything except a comment. 'python -x' works now again with files with the + source encoding declarations, and can be used to make Python batch files + on Windows. + - Issue #19081: When a zipimport .zip file in sys.path being imported from is modified during the lifetime of the Python process after zipimport has already cached the zip's table of contents we detect this and recover @@ -36,6 +43,9 @@ Library ------- +- Issue #18960: The tokenize module now ignore the source encoding declaration + on the second line if the first line contains anything except a comment. + - Issue #20078: Reading malformed zipfiles no longer hangs with 100% CPU consumption. @@ -204,6 +214,9 @@ IDLE ---- +- Issue #18960: IDLE now ignores the source encoding declaration on the second + line if the first line contains anything except a comment. + - Issue #20058: sys.stdin.readline() in IDLE now always returns only one line. - Issue #19481: print() of string subclass instance in IDLE no longer hangs. @@ -281,6 +294,13 @@ - Add workaround for VS 2010 nmake clean issue. VS 2010 doesn't set up PATH for nmake.exe correctly. +Tools/Demos +----------- + +- Issue #18960: 2to3 and the findnocoding.py script now ignore the source + encoding declaration on the second line if the first line contains anything + except a comment. + What's New in Python 3.3.3? =========================== diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -283,13 +283,27 @@ char *cs; int r = 1; - if (tok->cont_line) + if (tok->cont_line) { /* It's a continuation line, so it can't be a coding spec. */ + tok->read_coding_spec = 1; return 1; + } if (!get_coding_spec(line, &cs, size, tok)) return 0; - if (!cs) + if (!cs) { + Py_ssize_t i; + for (i = 0; i < size; i++) { + if (line[i] == '#' || line[i] == '\n' || line[i] == '\r') + break; + if (line[i] != ' ' && line[i] != '\t' && line[i] != '\014') { + /* Stop checking coding spec after a line containing + * anything except a comment. */ + tok->read_coding_spec = 1; + break; + } + } return 1; + } tok->read_coding_spec = 1; if (tok->encoding == NULL) { assert(tok->decoding_state == STATE_RAW); @@ -476,13 +490,17 @@ _Py_IDENTIFIER(open); _Py_IDENTIFIER(readline); int fd; + long pos; io = PyImport_ImportModuleNoBlock("io"); if (io == NULL) goto cleanup; fd = fileno(tok->fp); - if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { + /* Due to buffering the file offset for fd can be different from the file + * position of tok->fp. */ + pos = ftell(tok->fp); + if (pos == -1 || lseek(fd, (off_t)pos, SEEK_SET) == (off_t)-1) { PyErr_SetFromErrnoWithFilename(PyExc_OSError, NULL); goto cleanup; } @@ -751,7 +769,7 @@ if (newl[0]) { if (!check_coding_spec(str, newl[0] - str, tok, buf_setreadl)) return error_ret(tok); - if (tok->enc == NULL && newl[1]) { + if (tok->enc == NULL && !tok->read_coding_spec && newl[1]) { if (!check_coding_spec(newl[0]+1, newl[1] - newl[0], tok, buf_setreadl)) return error_ret(tok); diff --git a/Tools/scripts/findnocoding.py b/Tools/scripts/findnocoding.py --- a/Tools/scripts/findnocoding.py +++ b/Tools/scripts/findnocoding.py @@ -33,6 +33,7 @@ decl_re = re.compile(rb'^[ \t\f]*#.*coding[:=][ \t]*([-\w.]+)') +blank_re = re.compile(rb'^[ \t\f]*(?:[#\r\n]|$)') def get_declaration(line): match = decl_re.match(line) @@ -58,7 +59,8 @@ line1 = infile.readline() line2 = infile.readline() - if get_declaration(line1) or get_declaration(line2): + if (get_declaration(line1) or + blank_re.match(line1) and get_declaration(line2)): # the file does have an encoding declaration, so trust it return False -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 17:42:30 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 9 Jan 2014 17:42:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318960=3A_Fix_bugs_with_Python_source_code_encod?= =?utf-8?q?ing_in_the_second_line=2E?= Message-ID: <3f0Y5f6x2bz7LqL@mail.python.org> http://hg.python.org/cpython/rev/04c05e408cbd changeset: 88369:04c05e408cbd parent: 88366:a1a5c4274c1c parent: 88368:1bdcaf6c0eb5 user: Serhiy Storchaka date: Thu Jan 09 18:41:59 2014 +0200 summary: Issue #18960: Fix bugs with Python source code encoding in the second line. * The first line of Python script could be executed twice when the source encoding (not equal to 'utf-8') was specified on the second line. * Now the source encoding declaration on the second line isn't effective if the first line contains anything except a comment. * As a consequence, 'python -x' works now again with files with the source encoding declarations specified on the second file, and can be used again to make Python batch files on Windows. * The tokenize module now ignore the source encoding declaration on the second line if the first line contains anything except a comment. * IDLE now ignores the source encoding declaration on the second line if the first line contains anything except a comment. * 2to3 and the findnocoding.py script now ignore the source encoding declaration on the second line if the first line contains anything except a comment. files: Lib/idlelib/IOBinding.py | 3 ++ Lib/lib2to3/pgen2/tokenize.py | 3 ++ Lib/test/test_tokenize.py | 33 +++++++++++++++++++++++ Lib/tokenize.py | 3 ++ Misc/NEWS | 20 +++++++++++++ Parser/tokenizer.c | 26 +++++++++++++++-- Tools/scripts/findnocoding.py | 4 ++- 7 files changed, 87 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/IOBinding.py b/Lib/idlelib/IOBinding.py --- a/Lib/idlelib/IOBinding.py +++ b/Lib/idlelib/IOBinding.py @@ -64,6 +64,7 @@ ### 'encoding' is used below in encode(), check! coding_re = re.compile(r'^[ \t\f]*#.*coding[:=][ \t]*([-\w.]+)', re.ASCII) +blank_re = re.compile(r'^[ \t\f]*(?:[#\r\n]|$)', re.ASCII) def coding_spec(data): """Return the encoding declaration according to PEP 263. @@ -93,6 +94,8 @@ match = coding_re.match(line) if match is not None: break + if not blank_re.match(line): + return None else: return None name = match.group(1) diff --git a/Lib/lib2to3/pgen2/tokenize.py b/Lib/lib2to3/pgen2/tokenize.py --- a/Lib/lib2to3/pgen2/tokenize.py +++ b/Lib/lib2to3/pgen2/tokenize.py @@ -237,6 +237,7 @@ toks_append(tokval) cookie_re = re.compile(r'^[ \t\f]*#.*coding[:=][ \t]*([-\w.]+)', re.ASCII) +blank_re = re.compile(br'^[ \t\f]*(?:[#\r\n]|$)', re.ASCII) def _get_normal_name(orig_enc): """Imitates get_normal_name in tokenizer.c.""" @@ -309,6 +310,8 @@ encoding = find_cookie(first) if encoding: return encoding, [first] + if not blank_re.match(first): + return default, [first] second = read_or_stop() if not second: diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -885,6 +885,39 @@ readline = self.get_readline(lines) self.assertRaises(SyntaxError, detect_encoding, readline) + def test_cookie_second_line_noncommented_first_line(self): + lines = ( + b"print('\xc2\xa3')\n", + b'# vim: set fileencoding=iso8859-15 :\n', + b"print('\xe2\x82\xac')\n" + ) + encoding, consumed_lines = detect_encoding(self.get_readline(lines)) + self.assertEqual(encoding, 'utf-8') + expected = [b"print('\xc2\xa3')\n"] + self.assertEqual(consumed_lines, expected) + + def test_cookie_second_line_commented_first_line(self): + lines = ( + b"#print('\xc2\xa3')\n", + b'# vim: set fileencoding=iso8859-15 :\n', + b"print('\xe2\x82\xac')\n" + ) + encoding, consumed_lines = detect_encoding(self.get_readline(lines)) + self.assertEqual(encoding, 'iso8859-15') + expected = [b"#print('\xc2\xa3')\n", b'# vim: set fileencoding=iso8859-15 :\n'] + self.assertEqual(consumed_lines, expected) + + def test_cookie_second_line_empty_first_line(self): + lines = ( + b'\n', + b'# vim: set fileencoding=iso8859-15 :\n', + b"print('\xe2\x82\xac')\n" + ) + encoding, consumed_lines = detect_encoding(self.get_readline(lines)) + self.assertEqual(encoding, 'iso8859-15') + expected = [b'\n', b'# vim: set fileencoding=iso8859-15 :\n'] + self.assertEqual(consumed_lines, expected) + def test_latin1_normalization(self): # See get_normal_name() in tokenizer.c. encodings = ("latin-1", "iso-8859-1", "iso-latin-1", "latin-1-unix", diff --git a/Lib/tokenize.py b/Lib/tokenize.py --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -32,6 +32,7 @@ import collections from io import TextIOWrapper cookie_re = re.compile(r'^[ \t\f]*#.*coding[:=][ \t]*([-\w.]+)', re.ASCII) +blank_re = re.compile(br'^[ \t\f]*(?:[#\r\n]|$)', re.ASCII) import token __all__ = token.__all__ + ["COMMENT", "tokenize", "detect_encoding", @@ -409,6 +410,8 @@ encoding = find_cookie(first) if encoding: return encoding, [first] + if not blank_re.match(first): + return default, [first] second = read_or_stop() if not second: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,13 @@ Core and Builtins ----------------- +- Issue #18960: The first line of Python script could be executed twice when + the source encoding was specified on the second line. Now the source encoding + declaration on the second line isn't effective if the first line contains + anything except a comment. 'python -x' works now again with files with the + source encoding declarations, and can be used to make Python batch files + on Windows. + - Issue #19081: When a zipimport .zip file in sys.path being imported from is modified during the lifetime of the Python process after zipimport has already cached the zip's table of contents we detect this and recover @@ -18,6 +25,9 @@ Library ------- +- Issue #18960: The tokenize module now ignore the source encoding declaration + on the second line if the first line contains anything except a comment. + - Issue #20078: Reading malformed zipfiles no longer hangs with 100% CPU consumption. @@ -33,9 +43,19 @@ - Issue #20072: Fixed multiple errors in tkinter with wantobjects is False. +IDLE +---- + +- Issue #18960: IDLE now ignores the source encoding declaration on the second + line if the first line contains anything except a comment. + Tools/Demos ----------- +- Issue #18960: 2to3 and the findnocoding.py script now ignore the source + encoding declaration on the second line if the first line contains anything + except a comment. + - Issue #19723: The marker comments Argument Clinic uses have been changed to improve readability. diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -283,13 +283,27 @@ char *cs; int r = 1; - if (tok->cont_line) + if (tok->cont_line) { /* It's a continuation line, so it can't be a coding spec. */ + tok->read_coding_spec = 1; return 1; + } if (!get_coding_spec(line, &cs, size, tok)) return 0; - if (!cs) + if (!cs) { + Py_ssize_t i; + for (i = 0; i < size; i++) { + if (line[i] == '#' || line[i] == '\n' || line[i] == '\r') + break; + if (line[i] != ' ' && line[i] != '\t' && line[i] != '\014') { + /* Stop checking coding spec after a line containing + * anything except a comment. */ + tok->read_coding_spec = 1; + break; + } + } return 1; + } tok->read_coding_spec = 1; if (tok->encoding == NULL) { assert(tok->decoding_state == STATE_RAW); @@ -476,13 +490,17 @@ _Py_IDENTIFIER(open); _Py_IDENTIFIER(readline); int fd; + long pos; io = PyImport_ImportModuleNoBlock("io"); if (io == NULL) goto cleanup; fd = fileno(tok->fp); - if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { + /* Due to buffering the file offset for fd can be different from the file + * position of tok->fp. */ + pos = ftell(tok->fp); + if (pos == -1 || lseek(fd, (off_t)pos, SEEK_SET) == (off_t)-1) { PyErr_SetFromErrnoWithFilename(PyExc_OSError, NULL); goto cleanup; } @@ -752,7 +770,7 @@ if (newl[0]) { if (!check_coding_spec(str, newl[0] - str, tok, buf_setreadl)) return error_ret(tok); - if (tok->enc == NULL && newl[1]) { + if (tok->enc == NULL && !tok->read_coding_spec && newl[1]) { if (!check_coding_spec(newl[0]+1, newl[1] - newl[0], tok, buf_setreadl)) return error_ret(tok); diff --git a/Tools/scripts/findnocoding.py b/Tools/scripts/findnocoding.py --- a/Tools/scripts/findnocoding.py +++ b/Tools/scripts/findnocoding.py @@ -33,6 +33,7 @@ decl_re = re.compile(rb'^[ \t\f]*#.*coding[:=][ \t]*([-\w.]+)') +blank_re = re.compile(rb'^[ \t\f]*(?:[#\r\n]|$)') def get_declaration(line): match = decl_re.match(line) @@ -58,7 +59,8 @@ line1 = infile.readline() line2 = infile.readline() - if get_declaration(line1) or get_declaration(line2): + if (get_declaration(line1) or + blank_re.match(line1) and get_declaration(line2)): # the file does have an encoding declaration, so trust it return False -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 18:12:43 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 9 Jan 2014 18:12:43 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_clear_zip_stat?= =?utf-8?q?_cache_after_each_ref_leak_run?= Message-ID: <3f0YmW6GrWz7Lks@mail.python.org> http://hg.python.org/cpython/rev/fafac90b69c4 changeset: 88370:fafac90b69c4 branch: 3.3 parent: 88368:1bdcaf6c0eb5 user: Benjamin Peterson date: Thu Jan 09 11:10:30 2014 -0600 summary: clear zip stat cache after each ref leak run files: Lib/test/regrtest.py | 11 +++++++---- Lib/test/test_pkgutil.py | 5 ----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -1318,9 +1318,10 @@ try: import zipimport except ImportError: - zdc = None # Run unmodified on platforms without zipimport support + zsc = zdc = None # Run unmodified on platforms without zipimport support else: zdc = zipimport._zip_directory_cache.copy() + zsc = zipimport._zip_stat_cache.copy() abcs = {} for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]: if not isabstract(abc): @@ -1343,13 +1344,13 @@ print("beginning", repcount, "repetitions", file=sys.stderr) print(("1234567890"*(repcount//10 + 1))[:repcount], file=sys.stderr) sys.stderr.flush() - dash_R_cleanup(fs, ps, pic, zdc, abcs) + dash_R_cleanup(fs, ps, pic, zdc, zsc, abcs) for i in range(repcount): rc_before = sys.gettotalrefcount() run_the_test() sys.stderr.write('.') sys.stderr.flush() - dash_R_cleanup(fs, ps, pic, zdc, abcs) + dash_R_cleanup(fs, ps, pic, zdc, zsc, abcs) rc_after = sys.gettotalrefcount() if i >= nwarmup: deltas.append(rc_after - rc_before) @@ -1364,7 +1365,7 @@ return True return False -def dash_R_cleanup(fs, ps, pic, zdc, abcs): +def dash_R_cleanup(fs, ps, pic, zdc, zsc, abcs): import gc, copyreg import _strptime, linecache import urllib.parse, urllib.request, mimetypes, doctest @@ -1390,6 +1391,8 @@ else: zipimport._zip_directory_cache.clear() zipimport._zip_directory_cache.update(zdc) + zipimport._zip_stat_cache.clear() + zipimport._zip_stat_cache.update(zsc) # clear type cache sys._clear_type_cache() diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py --- a/Lib/test/test_pkgutil.py +++ b/Lib/test/test_pkgutil.py @@ -338,11 +338,6 @@ def test_main(): run_unittest(PkgutilTests, PkgutilPEP302Tests, ExtendPathTests, NestedNamespacePackageTest, ImportlibMigrationTests) - # this is necessary if test is run repeated (like when finding leaks) - import zipimport - import importlib - zipimport._zip_directory_cache.clear() - importlib.invalidate_caches() if __name__ == '__main__': -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 18:12:45 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 9 Jan 2014 18:12:45 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3f0YmY0qszz7LjM@mail.python.org> http://hg.python.org/cpython/rev/73228af705f6 changeset: 88371:73228af705f6 parent: 88369:04c05e408cbd parent: 88370:fafac90b69c4 user: Benjamin Peterson date: Thu Jan 09 11:12:31 2014 -0600 summary: merge 3.3 files: Lib/test/regrtest.py | 9 ++++++--- Lib/test/test_pkgutil.py | 5 ----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -1373,9 +1373,10 @@ try: import zipimport except ImportError: - zdc = None # Run unmodified on platforms without zipimport support + zsc = zdc = None # Run unmodified on platforms without zipimport support else: zdc = zipimport._zip_directory_cache.copy() + zsc = zipimport._zip_stat_cache.copy() abcs = {} for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]: if not isabstract(abc): @@ -1394,7 +1395,7 @@ sys.stderr.flush() for i in range(repcount): indirect_test() - alloc_after, rc_after = dash_R_cleanup(fs, ps, pic, zdc, abcs) + alloc_after, rc_after = dash_R_cleanup(fs, ps, pic, zdc, zsc, abcs) sys.stderr.write('.') sys.stderr.flush() if i >= nwarmup: @@ -1428,7 +1429,7 @@ failed = True return failed -def dash_R_cleanup(fs, ps, pic, zdc, abcs): +def dash_R_cleanup(fs, ps, pic, zdc, zsc, abcs): import gc, copyreg import _strptime, linecache import urllib.parse, urllib.request, mimetypes, doctest @@ -1454,6 +1455,8 @@ else: zipimport._zip_directory_cache.clear() zipimport._zip_directory_cache.update(zdc) + zipimport._zip_stat_cache.clear() + zipimport._zip_stat_cache.update(zsc) # clear type cache sys._clear_type_cache() diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py --- a/Lib/test/test_pkgutil.py +++ b/Lib/test/test_pkgutil.py @@ -349,11 +349,6 @@ def test_main(): run_unittest(PkgutilTests, PkgutilPEP302Tests, ExtendPathTests, NestedNamespacePackageTest, ImportlibMigrationTests) - # this is necessary if test is run repeated (like when finding leaks) - import zipimport - import importlib - zipimport._zip_directory_cache.clear() - importlib.invalidate_caches() if __name__ == '__main__': -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 18:17:52 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 9 Jan 2014 18:17:52 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_clear_zip_stat?= =?utf-8?q?_cache_after_each_ref_leak_run?= Message-ID: <3f0YtS5hn9z7LjM@mail.python.org> http://hg.python.org/cpython/rev/369bf9fbaeff changeset: 88372:369bf9fbaeff branch: 2.7 parent: 88367:30d761849a27 user: Benjamin Peterson date: Thu Jan 09 11:10:30 2014 -0600 summary: clear zip stat cache after each ref leak run files: Lib/test/regrtest.py | 11 +++++++---- Lib/test/test_pkgutil.py | 4 +--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -1002,9 +1002,10 @@ try: import zipimport except ImportError: - zdc = None # Run unmodified on platforms without zipimport support + zsc = zdc = None # Run unmodified on platforms without zipimport support else: zdc = zipimport._zip_directory_cache.copy() + zsc = zipimport._zip_stat_cache.copy() abcs = {} modules = _abcoll, _pyio for abc in [getattr(mod, a) for mod in modules for a in mod.__all__]: @@ -1027,12 +1028,12 @@ repcount = nwarmup + ntracked print >> sys.stderr, "beginning", repcount, "repetitions" print >> sys.stderr, ("1234567890"*(repcount//10 + 1))[:repcount] - dash_R_cleanup(fs, ps, pic, zdc, abcs) + dash_R_cleanup(fs, ps, pic, zdc, zsc, abcs) for i in range(repcount): rc_before = sys.gettotalrefcount() run_the_test() sys.stderr.write('.') - dash_R_cleanup(fs, ps, pic, zdc, abcs) + dash_R_cleanup(fs, ps, pic, zdc, zsc, abcs) rc_after = sys.gettotalrefcount() if i >= nwarmup: deltas.append(rc_after - rc_before) @@ -1046,7 +1047,7 @@ return True return False -def dash_R_cleanup(fs, ps, pic, zdc, abcs): +def dash_R_cleanup(fs, ps, pic, zdc, zsc, abcs): import gc, copy_reg import _strptime, linecache dircache = test_support.import_module('dircache', deprecated=True) @@ -1072,6 +1073,8 @@ else: zipimport._zip_directory_cache.clear() zipimport._zip_directory_cache.update(zdc) + zipimport._zip_stat_cache.clear() + zipimport._zip_stat_cache.update(zsc) # clear type cache sys._clear_type_cache() diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py --- a/Lib/test/test_pkgutil.py +++ b/Lib/test/test_pkgutil.py @@ -133,9 +133,7 @@ def test_main(): run_unittest(PkgutilTests, PkgutilPEP302Tests) - # this is necessary if test is run repeated (like when finding leaks) - import zipimport - zipimport._zip_directory_cache.clear() + if __name__ == '__main__': test_main() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 19:14:17 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 9 Jan 2014 19:14:17 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Do_not_reset_t?= =?utf-8?q?he_line_number_because_we_already_set_file_position_to_correct?= Message-ID: <3f0b7Y0VGDz7Ljd@mail.python.org> http://hg.python.org/cpython/rev/875a514671dd changeset: 88373:875a514671dd branch: 3.3 parent: 88370:fafac90b69c4 user: Serhiy Storchaka date: Thu Jan 09 20:12:49 2014 +0200 summary: Do not reset the line number because we already set file position to correct value. (fixes error in patch for issue #18960) files: Lib/test/test_traceback.py | 4 ++++ Parser/tokenizer.c | 8 -------- 2 files changed, 4 insertions(+), 8 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 @@ -146,6 +146,10 @@ text, charset, 4) do_test("#!shebang\n# coding: {0}\n".format(charset), text, charset, 5) + do_test(" \t\f\n# coding: {0}\n".format(charset), + text, charset, 5) + # Issue #18960: coding spec should has no effect + do_test("0\n# coding: GBK\n", "h\xe9 ho", 'utf-8', 5) class TracebackFormatTests(unittest.TestCase): diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -514,14 +514,6 @@ readline = _PyObject_GetAttrId(stream, &PyId_readline); tok->decoding_readline = readline; - /* The file has been reopened; parsing will restart from - * the beginning of the file, we have to reset the line number. - * But this function has been called from inside tok_nextc() which - * will increment lineno before it returns. So we set it -1 so that - * the next call to tok_nextc() will start with tok->lineno == 0. - */ - tok->lineno = -1; - cleanup: Py_XDECREF(stream); Py_XDECREF(io); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 19:14:18 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 9 Jan 2014 19:14:18 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Do_not_reset_the_line_number_because_we_already_set_file?= =?utf-8?q?_position_to_correct?= Message-ID: <3f0b7Z2QpQz7Lk6@mail.python.org> http://hg.python.org/cpython/rev/2af308f79727 changeset: 88374:2af308f79727 parent: 88371:73228af705f6 parent: 88373:875a514671dd user: Serhiy Storchaka date: Thu Jan 09 20:13:52 2014 +0200 summary: Do not reset the line number because we already set file position to correct value. (fixes error in patch for issue #18960) files: Lib/test/test_traceback.py | 4 ++++ Parser/tokenizer.c | 8 -------- 2 files changed, 4 insertions(+), 8 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 @@ -146,6 +146,10 @@ text, charset, 4) do_test("#!shebang\n# coding: {0}\n".format(charset), text, charset, 5) + do_test(" \t\f\n# coding: {0}\n".format(charset), + text, charset, 5) + # Issue #18960: coding spec should has no effect + do_test("0\n# coding: GBK\n", "h\xe9 ho", 'utf-8', 5) class TracebackFormatTests(unittest.TestCase): diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -514,14 +514,6 @@ readline = _PyObject_GetAttrId(stream, &PyId_readline); tok->decoding_readline = readline; - /* The file has been reopened; parsing will restart from - * the beginning of the file, we have to reset the line number. - * But this function has been called from inside tok_nextc() which - * will increment lineno before it returns. So we set it -1 so that - * the next call to tok_nextc() will start with tok->lineno == 0. - */ - tok->lineno = -1; - cleanup: Py_XDECREF(stream); Py_XDECREF(io); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 19:52:19 2014 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 9 Jan 2014 19:52:19 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIwMjA3?= =?utf-8?q?=3A_Always_disable_SSLv2_except_when_PROTOCOL=5FSSLv2_is_explic?= =?utf-8?q?itly?= Message-ID: <3f0bzR6k1gz7Ljg@mail.python.org> http://hg.python.org/cpython/rev/163c09041280 changeset: 88375:163c09041280 branch: 2.7 parent: 88372:369bf9fbaeff user: Antoine Pitrou date: Thu Jan 09 19:52:12 2014 +0100 summary: Issue #20207: Always disable SSLv2 except when PROTOCOL_SSLv2 is explicitly asked for. files: Lib/test/test_ssl.py | 2 +- Misc/NEWS | 3 +++ Modules/_ssl.c | 7 +++++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -1052,7 +1052,7 @@ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True) try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL) try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED) - try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True) + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False) try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False) try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,6 +35,9 @@ Library ------- +- Issue #20207: Always disable SSLv2 except when PROTOCOL_SSLv2 is explicitly + asked for. + - Issue #20072: Fixed multiple errors in tkinter with wantobjects is False. - Issue #1065986: pydoc can now handle unicode strings. diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -273,6 +273,7 @@ char *errstr = NULL; int ret; int verification_mode; + long options; self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */ if (self == NULL) @@ -372,8 +373,10 @@ } /* ssl compatibility */ - SSL_CTX_set_options(self->ctx, - SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); + options = SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; + if (proto_version != PY_SSL_VERSION_SSL2) + options |= SSL_OP_NO_SSLv2; + SSL_CTX_set_options(self->ctx, options); verification_mode = SSL_VERIFY_NONE; if (certreq == PY_SSL_CERT_OPTIONAL) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 20:09:12 2014 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 9 Jan 2014 20:09:12 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMjA3?= =?utf-8?q?=3A_Always_disable_SSLv2_except_when_PROTOCOL=5FSSLv2_is_explic?= =?utf-8?q?itly?= Message-ID: <3f0cLw6m8Zz7LjR@mail.python.org> http://hg.python.org/cpython/rev/613b403ca9f1 changeset: 88376:613b403ca9f1 branch: 3.3 parent: 88373:875a514671dd user: Antoine Pitrou date: Thu Jan 09 20:02:20 2014 +0100 summary: Issue #20207: Always disable SSLv2 except when PROTOCOL_SSLv2 is explicitly asked for. files: Lib/test/test_ssl.py | 10 ++++------ Misc/NEWS | 3 +++ Modules/_ssl.c | 7 +++++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -534,9 +534,7 @@ @skip_if_broken_ubuntu_ssl def test_options(self): ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) - # OP_ALL is the default value - self.assertEqual(ssl.OP_ALL, ctx.options) - ctx.options |= ssl.OP_NO_SSLv2 + # OP_ALL | OP_NO_SSLv2 is the default value self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2, ctx.options) ctx.options |= ssl.OP_NO_SSLv3 @@ -1585,7 +1583,7 @@ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True) try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL) try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED) - try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True) + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False) try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False) try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False) # SSLv23 client with specific SSL options @@ -1593,9 +1591,9 @@ # No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, client_options=ssl.OP_NO_SSLv2) - try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True, + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, client_options=ssl.OP_NO_SSLv3) - try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True, + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, client_options=ssl.OP_NO_TLSv1) @skip_if_broken_ubuntu_ssl diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,9 @@ Library ------- +- Issue #20207: Always disable SSLv2 except when PROTOCOL_SSLv2 is explicitly + asked for. + - Issue #18960: The tokenize module now ignore the source encoding declaration on the second line if the first line contains anything except a comment. diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -1737,6 +1737,7 @@ char *kwlist[] = {"protocol", NULL}; PySSLContext *self; int proto_version = PY_SSL_VERSION_SSL23; + long options; SSL_CTX *ctx = NULL; if (!PyArg_ParseTupleAndKeywords( @@ -1782,8 +1783,10 @@ #endif /* Defaults */ SSL_CTX_set_verify(self->ctx, SSL_VERIFY_NONE, NULL); - SSL_CTX_set_options(self->ctx, - SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); + options = SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; + if (proto_version != PY_SSL_VERSION_SSL2) + options |= SSL_OP_NO_SSLv2; + SSL_CTX_set_options(self->ctx, options); #define SID_CTX "Python" SSL_CTX_set_session_id_context(self->ctx, (const unsigned char *) SID_CTX, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 20:09:14 2014 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 9 Jan 2014 20:09:14 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Remove_conditi?= =?utf-8?q?onal=3A_it_is_useless_at_this_point_=28OpenSSL_headers_are_not_?= =?utf-8?q?yet?= Message-ID: <3f0cLy1mKDz7LjR@mail.python.org> http://hg.python.org/cpython/rev/da8486e3e0eb changeset: 88377:da8486e3e0eb branch: 3.3 user: Antoine Pitrou date: Thu Jan 09 20:07:41 2014 +0100 summary: Remove conditional: it is useless at this point (OpenSSL headers are not yet included) files: Modules/_ssl.c | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -70,9 +70,7 @@ }; enum py_ssl_version { -#ifndef OPENSSL_NO_SSL2 PY_SSL_VERSION_SSL2, -#endif PY_SSL_VERSION_SSL3=1, PY_SSL_VERSION_SSL23, PY_SSL_VERSION_TLS1 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 20:09:15 2014 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 9 Jan 2014 20:09:15 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320207=3A_Always_disable_SSLv2_except_when_PROTO?= =?utf-8?q?COL=5FSSLv2_is_explicitly?= Message-ID: <3f0cLz5nbqz7Lk8@mail.python.org> http://hg.python.org/cpython/rev/e02288de43ed changeset: 88378:e02288de43ed parent: 88374:2af308f79727 parent: 88377:da8486e3e0eb user: Antoine Pitrou date: Thu Jan 09 20:09:03 2014 +0100 summary: Issue #20207: Always disable SSLv2 except when PROTOCOL_SSLv2 is explicitly asked for. files: Lib/test/test_ssl.py | 10 ++++------ Misc/NEWS | 3 +++ Modules/_ssl.c | 9 +++++---- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -670,9 +670,7 @@ @skip_if_broken_ubuntu_ssl def test_options(self): ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) - # OP_ALL is the default value - self.assertEqual(ssl.OP_ALL, ctx.options) - ctx.options |= ssl.OP_NO_SSLv2 + # OP_ALL | OP_NO_SSLv2 is the default value self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2, ctx.options) ctx.options |= ssl.OP_NO_SSLv3 @@ -2095,7 +2093,7 @@ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True) try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL) try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED) - try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True) + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False) try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False) try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False) # SSLv23 client with specific SSL options @@ -2103,9 +2101,9 @@ # No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, client_options=ssl.OP_NO_SSLv2) - try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True, + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, client_options=ssl.OP_NO_SSLv3) - try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True, + try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, client_options=ssl.OP_NO_TLSv1) @skip_if_broken_ubuntu_ssl diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,9 @@ Library ------- +- Issue #20207: Always disable SSLv2 except when PROTOCOL_SSLv2 is explicitly + asked for. + - Issue #18960: The tokenize module now ignore the source encoding declaration on the second line if the first line contains anything except a comment. diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -134,9 +134,7 @@ }; enum py_ssl_version { -#ifndef OPENSSL_NO_SSL2 PY_SSL_VERSION_SSL2, -#endif PY_SSL_VERSION_SSL3=1, PY_SSL_VERSION_SSL23, #if HAVE_TLSv1_2 @@ -1999,6 +1997,7 @@ char *kwlist[] = {"protocol", NULL}; PySSLContext *self; int proto_version = PY_SSL_VERSION_SSL23; + long options; SSL_CTX *ctx = NULL; if (!PyArg_ParseTupleAndKeywords( @@ -2055,8 +2054,10 @@ self->check_hostname = 0; /* Defaults */ SSL_CTX_set_verify(self->ctx, SSL_VERIFY_NONE, NULL); - SSL_CTX_set_options(self->ctx, - SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); + options = SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; + if (proto_version != PY_SSL_VERSION_SSL2) + options |= SSL_OP_NO_SSLv2; + SSL_CTX_set_options(self->ctx, options); #define SID_CTX "Python" SSL_CTX_set_session_id_context(self->ctx, (const unsigned char *) SID_CTX, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 21:30:24 2014 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 9 Jan 2014 21:30:24 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Try_to_fix_tes?= =?utf-8?q?t=5Fssl_failures_on_some_buildbots?= Message-ID: <3f0f8c12Fqz7Lkg@mail.python.org> http://hg.python.org/cpython/rev/36e17a81f81f changeset: 88379:36e17a81f81f branch: 3.3 parent: 88377:da8486e3e0eb user: Antoine Pitrou date: Thu Jan 09 21:28:48 2014 +0100 summary: Try to fix test_ssl failures on some buildbots files: Lib/test/test_ssl.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -1440,9 +1440,9 @@ ssl.get_protocol_name(server_protocol), certtype)) client_context = ssl.SSLContext(client_protocol) - client_context.options = ssl.OP_ALL | client_options + client_context.options |= client_options server_context = ssl.SSLContext(server_protocol) - server_context.options = ssl.OP_ALL | server_options + server_context.options |= server_options for ctx in (client_context, server_context): ctx.verify_mode = certsreqs # NOTE: we must enable "ALL" ciphers, otherwise an SSLv23 client -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 21:30:25 2014 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 9 Jan 2014 21:30:25 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Try_to_fix_test=5Fssl_failures_on_some_buildbots?= Message-ID: <3f0f8d2nycz7Lkq@mail.python.org> http://hg.python.org/cpython/rev/3e1895f19820 changeset: 88380:3e1895f19820 parent: 88378:e02288de43ed parent: 88379:36e17a81f81f user: Antoine Pitrou date: Thu Jan 09 21:30:17 2014 +0100 summary: Try to fix test_ssl failures on some buildbots files: Lib/test/test_ssl.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -1859,9 +1859,9 @@ ssl.get_protocol_name(server_protocol), certtype)) client_context = ssl.SSLContext(client_protocol) - client_context.options = ssl.OP_ALL | client_options + client_context.options |= client_options server_context = ssl.SSLContext(server_protocol) - server_context.options = ssl.OP_ALL | server_options + server_context.options |= server_options # NOTE: we must enable "ALL" ciphers on the client, otherwise an # SSLv23 client will send an SSLv3 hello (rather than SSLv2) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 22:02:06 2014 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 9 Jan 2014 22:02:06 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_460=3A_add_=2Eformat=5Fma?= =?utf-8?b?cCgp?= Message-ID: <3f0fsB3ww4z7Lk8@mail.python.org> http://hg.python.org/peps/rev/8947cdc6b22e changeset: 5341:8947cdc6b22e user: Antoine Pitrou date: Thu Jan 09 22:02:01 2014 +0100 summary: PEP 460: add .format_map() files: pep-0460.txt | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/pep-0460.txt b/pep-0460.txt --- a/pep-0460.txt +++ b/pep-0460.txt @@ -24,12 +24,16 @@ similar in syntax to ``str.format()`` (accepting positional as well as keyword arguments). +* ``bytes.format_map(...)`` and ``bytearray.format_map(...)`` for an + API similar to ``str.format_map(...)``, with the same formatting + syntax and semantics as ``bytes.format()`` and ``bytearray.format()``. + Rationale ========= In Python 2, ``str % args`` and ``str.format(args)`` allow the formatting -and interpolation of bytes strings. This feature has commonly been used +and interpolation of bytestrings. This feature has commonly been used for the assembling of protocol messages when protocols are known to use a fixed encoding. -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Jan 9 22:19:17 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 9 Jan 2014 22:19:17 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzEzMTA3?= =?utf-8?q?=3A_argparse_and_optparse_no_longer_raises_an_exception_when_ou?= =?utf-8?q?tput?= Message-ID: <3f0gF12RWyz7LjX@mail.python.org> http://hg.python.org/cpython/rev/779de7b4909b changeset: 88381:779de7b4909b branch: 2.7 parent: 88375:163c09041280 user: Serhiy Storchaka date: Thu Jan 09 23:13:48 2014 +0200 summary: Issue #13107: argparse and optparse no longer raises an exception when output a help on environment with too small COLUMNS. Based on patch by Elazar Gershuni. files: Lib/argparse.py | 8 ++- Lib/optparse.py | 7 ++- Lib/test/test_argparse.py | 54 +++++++++++++++++++++++++++ Lib/test/test_optparse.py | 35 +++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 4 ++ 6 files changed, 103 insertions(+), 6 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -168,6 +168,8 @@ self._prog = prog self._indent_increment = indent_increment self._max_help_position = max_help_position + self._max_help_position = min(max_help_position, + max(width - 20, indent_increment * 2)) self._width = width self._current_indent = 0 @@ -339,7 +341,7 @@ else: line_len = len(indent) - 1 for part in parts: - if line_len + 1 + len(part) > text_width: + if line_len + 1 + len(part) > text_width and line: lines.append(indent + ' '.join(line)) line = [] line_len = len(indent) - 1 @@ -478,7 +480,7 @@ def _format_text(self, text): if '%(prog)' in text: text = text % dict(prog=self._prog) - text_width = self._width - self._current_indent + text_width = max(self._width - self._current_indent, 11) indent = ' ' * self._current_indent return self._fill_text(text, text_width, indent) + '\n\n' @@ -486,7 +488,7 @@ # determine the required width and the entry label help_position = min(self._action_max_length + 2, self._max_help_position) - help_width = self._width - help_position + help_width = max(self._width - help_position, 11) action_width = help_position - self._current_indent - 2 action_header = self._format_action_invocation(action) diff --git a/Lib/optparse.py b/Lib/optparse.py --- a/Lib/optparse.py +++ b/Lib/optparse.py @@ -204,7 +204,6 @@ short_first): self.parser = None self.indent_increment = indent_increment - self.help_position = self.max_help_position = max_help_position if width is None: try: width = int(os.environ['COLUMNS']) @@ -212,6 +211,8 @@ width = 80 width -= 2 self.width = width + self.help_position = self.max_help_position = \ + min(max_help_position, max(width - 20, indent_increment * 2)) self.current_indent = 0 self.level = 0 self.help_width = None # computed later @@ -256,7 +257,7 @@ Format a paragraph of free-form text for inclusion in the help output at the current indentation level. """ - text_width = self.width - self.current_indent + text_width = max(self.width - self.current_indent, 11) indent = " "*self.current_indent return textwrap.fill(text, text_width, @@ -337,7 +338,7 @@ self.dedent() self.dedent() self.help_position = min(max_len + 2, self.max_help_position) - self.help_width = self.width - self.help_position + self.help_width = max(self.width - self.help_position, 11) def format_option_strings(self, option): """Return a comma-separated list of option strings & metavariables.""" diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2936,6 +2936,60 @@ 0.1 ''' +class TestShortColumns(HelpTestCase): + '''Test extremely small number of columns. + + TestCase prevents "COLUMNS" from being too small in the tests themselves, + but we don't want any exceptions thrown in such case. Only ugly representation. + ''' + def setUp(self): + env = test_support.EnvironmentVarGuard() + env.set("COLUMNS", '15') + self.addCleanup(env.__exit__) + + parser_signature = TestHelpBiggerOptionals.parser_signature + argument_signatures = TestHelpBiggerOptionals.argument_signatures + argument_group_signatures = TestHelpBiggerOptionals.argument_group_signatures + usage = '''\ + usage: PROG + [-h] + [-v] + [-x] + [--y Y] + foo + bar + ''' + help = usage + '''\ + + DESCRIPTION + + positional arguments: + foo + FOO HELP + bar + BAR HELP + + optional arguments: + -h, --help + show this + help + message and + exit + -v, --version + show + program's + version + number and + exit + -x + X HELP + --y Y + Y HELP + + EPILOG + ''' + version = TestHelpBiggerOptionals.version + class TestHelpBiggerOptionalGroups(HelpTestCase): """Make sure that argument help aligns when options are longer""" diff --git a/Lib/test/test_optparse.py b/Lib/test/test_optparse.py --- a/Lib/test/test_optparse.py +++ b/Lib/test/test_optparse.py @@ -1444,6 +1444,39 @@ -h, --help show this help message and exit """ +_expected_very_help_short_lines = """\ +Usage: bar.py [options] + +Options: + -a APPLE + throw + APPLEs at + basket + -b NUM, --boo=NUM + shout + "boo!" NUM + times (in + order to + frighten + away all + the evil + spirits + that cause + trouble and + mayhem) + --foo=FOO + store FOO + in the foo + list for + later + fooing + -h, --help + show this + help + message and + exit +""" + class TestHelp(BaseTest): def setUp(self): self.parser = self.make_parser(80) @@ -1505,6 +1538,8 @@ # we look at $COLUMNS. self.parser = self.make_parser(60) self.assertHelpEquals(_expected_help_short_lines) + self.parser = self.make_parser(0) + self.assertHelpEquals(_expected_very_help_short_lines) def test_help_unicode(self): self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -357,6 +357,7 @@ Thomas Gellekum Gabriel Genellina Christos Georgiou +Elazar Gershuni Ben Gertzfield Nadim Ghaznavi Dinu Gherman diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,6 +35,10 @@ Library ------- +- Issue #13107: argparse and optparse no longer raises an exception when output + a help on environment with too small COLUMNS. Based on patch by + Elazar Gershuni. + - Issue #20207: Always disable SSLv2 except when PROTOCOL_SSLv2 is explicitly asked for. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 22:19:19 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 9 Jan 2014 22:19:19 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzEzMTA3?= =?utf-8?q?=3A_argparse_and_optparse_no_longer_raises_an_exception_when_ou?= =?utf-8?q?tput?= Message-ID: <3f0gF308XNz7LjX@mail.python.org> http://hg.python.org/cpython/rev/c6c30b682e14 changeset: 88382:c6c30b682e14 branch: 3.3 parent: 88379:36e17a81f81f user: Serhiy Storchaka date: Thu Jan 09 23:14:27 2014 +0200 summary: Issue #13107: argparse and optparse no longer raises an exception when output a help on environment with too small COLUMNS. Based on patch by Elazar Gershuni. files: Lib/argparse.py | 8 ++- Lib/optparse.py | 7 ++- Lib/test/test_argparse.py | 54 +++++++++++++++++++++++++++ Lib/test/test_optparse.py | 35 +++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 4 ++ 6 files changed, 103 insertions(+), 6 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -165,6 +165,8 @@ self._prog = prog self._indent_increment = indent_increment self._max_help_position = max_help_position + self._max_help_position = min(max_help_position, + max(width - 20, indent_increment * 2)) self._width = width self._current_indent = 0 @@ -336,7 +338,7 @@ else: line_len = len(indent) - 1 for part in parts: - if line_len + 1 + len(part) > text_width: + if line_len + 1 + len(part) > text_width and line: lines.append(indent + ' '.join(line)) line = [] line_len = len(indent) - 1 @@ -476,7 +478,7 @@ def _format_text(self, text): if '%(prog)' in text: text = text % dict(prog=self._prog) - text_width = self._width - self._current_indent + text_width = max(self._width - self._current_indent, 11) indent = ' ' * self._current_indent return self._fill_text(text, text_width, indent) + '\n\n' @@ -484,7 +486,7 @@ # determine the required width and the entry label help_position = min(self._action_max_length + 2, self._max_help_position) - help_width = self._width - help_position + help_width = max(self._width - help_position, 11) action_width = help_position - self._current_indent - 2 action_header = self._format_action_invocation(action) diff --git a/Lib/optparse.py b/Lib/optparse.py --- a/Lib/optparse.py +++ b/Lib/optparse.py @@ -209,7 +209,6 @@ short_first): self.parser = None self.indent_increment = indent_increment - self.help_position = self.max_help_position = max_help_position if width is None: try: width = int(os.environ['COLUMNS']) @@ -217,6 +216,8 @@ width = 80 width -= 2 self.width = width + self.help_position = self.max_help_position = \ + min(max_help_position, max(width - 20, indent_increment * 2)) self.current_indent = 0 self.level = 0 self.help_width = None # computed later @@ -261,7 +262,7 @@ Format a paragraph of free-form text for inclusion in the help output at the current indentation level. """ - text_width = self.width - self.current_indent + text_width = max(self.width - self.current_indent, 11) indent = " "*self.current_indent return textwrap.fill(text, text_width, @@ -342,7 +343,7 @@ self.dedent() self.dedent() self.help_position = min(max_len + 2, self.max_help_position) - self.help_width = self.width - self.help_position + self.help_width = max(self.width - self.help_position, 11) def format_option_strings(self, option): """Return a comma-separated list of option strings & metavariables.""" diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -2973,6 +2973,60 @@ 0.1 ''' +class TestShortColumns(HelpTestCase): + '''Test extremely small number of columns. + + TestCase prevents "COLUMNS" from being too small in the tests themselves, + but we don't want any exceptions thrown in such case. Only ugly representation. + ''' + def setUp(self): + env = support.EnvironmentVarGuard() + env.set("COLUMNS", '15') + self.addCleanup(env.__exit__) + + parser_signature = TestHelpBiggerOptionals.parser_signature + argument_signatures = TestHelpBiggerOptionals.argument_signatures + argument_group_signatures = TestHelpBiggerOptionals.argument_group_signatures + usage = '''\ + usage: PROG + [-h] + [-v] + [-x] + [--y Y] + foo + bar + ''' + help = usage + '''\ + + DESCRIPTION + + positional arguments: + foo + FOO HELP + bar + BAR HELP + + optional arguments: + -h, --help + show this + help + message and + exit + -v, --version + show + program's + version + number and + exit + -x + X HELP + --y Y + Y HELP + + EPILOG + ''' + version = TestHelpBiggerOptionals.version + class TestHelpBiggerOptionalGroups(HelpTestCase): """Make sure that argument help aligns when options are longer""" diff --git a/Lib/test/test_optparse.py b/Lib/test/test_optparse.py --- a/Lib/test/test_optparse.py +++ b/Lib/test/test_optparse.py @@ -1443,6 +1443,39 @@ -h, --help show this help message and exit """ +_expected_very_help_short_lines = """\ +Usage: bar.py [options] + +Options: + -a APPLE + throw + APPLEs at + basket + -b NUM, --boo=NUM + shout + "boo!" NUM + times (in + order to + frighten + away all + the evil + spirits + that cause + trouble and + mayhem) + --foo=FOO + store FOO + in the foo + list for + later + fooing + -h, --help + show this + help + message and + exit +""" + class TestHelp(BaseTest): def setUp(self): self.parser = self.make_parser(80) @@ -1500,6 +1533,8 @@ # we look at $COLUMNS. self.parser = self.make_parser(60) self.assertHelpEquals(_expected_help_short_lines) + self.parser = self.make_parser(0) + self.assertHelpEquals(_expected_very_help_short_lines) def test_help_unicode(self): self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -430,6 +430,7 @@ Thomas Gellekum Gabriel Genellina Christos Georgiou +Elazar Gershuni Ben Gertzfield Nadim Ghaznavi Dinu Gherman diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,10 @@ Library ------- +- Issue #13107: argparse and optparse no longer raises an exception when output + a help on environment with too small COLUMNS. Based on patch by + Elazar Gershuni. + - Issue #20207: Always disable SSLv2 except when PROTOCOL_SSLv2 is explicitly asked for. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 9 22:19:21 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 9 Jan 2014 22:19:21 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2313107=3A_argparse_and_optparse_no_longer_raises?= =?utf-8?q?_an_exception_when_output?= Message-ID: <3f0gF54Z12z7LjX@mail.python.org> http://hg.python.org/cpython/rev/48bcd03cd29f changeset: 88383:48bcd03cd29f parent: 88380:3e1895f19820 parent: 88382:c6c30b682e14 user: Serhiy Storchaka date: Thu Jan 09 23:18:41 2014 +0200 summary: Issue #13107: argparse and optparse no longer raises an exception when output a help on environment with too small COLUMNS. Based on patch by Elazar Gershuni. files: Lib/argparse.py | 8 ++- Lib/optparse.py | 7 ++- Lib/test/test_argparse.py | 54 +++++++++++++++++++++++++++ Lib/test/test_optparse.py | 35 +++++++++++++++++ Misc/NEWS | 4 ++ 5 files changed, 102 insertions(+), 6 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -165,6 +165,8 @@ self._prog = prog self._indent_increment = indent_increment self._max_help_position = max_help_position + self._max_help_position = min(max_help_position, + max(width - 20, indent_increment * 2)) self._width = width self._current_indent = 0 @@ -336,7 +338,7 @@ else: line_len = len(indent) - 1 for part in parts: - if line_len + 1 + len(part) > text_width: + if line_len + 1 + len(part) > text_width and line: lines.append(indent + ' '.join(line)) line = [] line_len = len(indent) - 1 @@ -476,7 +478,7 @@ def _format_text(self, text): if '%(prog)' in text: text = text % dict(prog=self._prog) - text_width = self._width - self._current_indent + text_width = max(self._width - self._current_indent, 11) indent = ' ' * self._current_indent return self._fill_text(text, text_width, indent) + '\n\n' @@ -484,7 +486,7 @@ # determine the required width and the entry label help_position = min(self._action_max_length + 2, self._max_help_position) - help_width = self._width - help_position + help_width = max(self._width - help_position, 11) action_width = help_position - self._current_indent - 2 action_header = self._format_action_invocation(action) diff --git a/Lib/optparse.py b/Lib/optparse.py --- a/Lib/optparse.py +++ b/Lib/optparse.py @@ -209,7 +209,6 @@ short_first): self.parser = None self.indent_increment = indent_increment - self.help_position = self.max_help_position = max_help_position if width is None: try: width = int(os.environ['COLUMNS']) @@ -217,6 +216,8 @@ width = 80 width -= 2 self.width = width + self.help_position = self.max_help_position = \ + min(max_help_position, max(width - 20, indent_increment * 2)) self.current_indent = 0 self.level = 0 self.help_width = None # computed later @@ -261,7 +262,7 @@ Format a paragraph of free-form text for inclusion in the help output at the current indentation level. """ - text_width = self.width - self.current_indent + text_width = max(self.width - self.current_indent, 11) indent = " "*self.current_indent return textwrap.fill(text, text_width, @@ -342,7 +343,7 @@ self.dedent() self.dedent() self.help_position = min(max_len + 2, self.max_help_position) - self.help_width = self.width - self.help_position + self.help_width = max(self.width - self.help_position, 11) def format_option_strings(self, option): """Return a comma-separated list of option strings & metavariables.""" diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -3005,6 +3005,60 @@ 0.1 ''' +class TestShortColumns(HelpTestCase): + '''Test extremely small number of columns. + + TestCase prevents "COLUMNS" from being too small in the tests themselves, + but we don't want any exceptions thrown in such case. Only ugly representation. + ''' + def setUp(self): + env = support.EnvironmentVarGuard() + env.set("COLUMNS", '15') + self.addCleanup(env.__exit__) + + parser_signature = TestHelpBiggerOptionals.parser_signature + argument_signatures = TestHelpBiggerOptionals.argument_signatures + argument_group_signatures = TestHelpBiggerOptionals.argument_group_signatures + usage = '''\ + usage: PROG + [-h] + [-v] + [-x] + [--y Y] + foo + bar + ''' + help = usage + '''\ + + DESCRIPTION + + positional arguments: + foo + FOO HELP + bar + BAR HELP + + optional arguments: + -h, --help + show this + help + message and + exit + -v, --version + show + program's + version + number and + exit + -x + X HELP + --y Y + Y HELP + + EPILOG + ''' + version = TestHelpBiggerOptionals.version + class TestHelpBiggerOptionalGroups(HelpTestCase): """Make sure that argument help aligns when options are longer""" diff --git a/Lib/test/test_optparse.py b/Lib/test/test_optparse.py --- a/Lib/test/test_optparse.py +++ b/Lib/test/test_optparse.py @@ -1443,6 +1443,39 @@ -h, --help show this help message and exit """ +_expected_very_help_short_lines = """\ +Usage: bar.py [options] + +Options: + -a APPLE + throw + APPLEs at + basket + -b NUM, --boo=NUM + shout + "boo!" NUM + times (in + order to + frighten + away all + the evil + spirits + that cause + trouble and + mayhem) + --foo=FOO + store FOO + in the foo + list for + later + fooing + -h, --help + show this + help + message and + exit +""" + class TestHelp(BaseTest): def setUp(self): self.parser = self.make_parser(80) @@ -1500,6 +1533,8 @@ # we look at $COLUMNS. self.parser = self.make_parser(60) self.assertHelpEquals(_expected_help_short_lines) + self.parser = self.make_parser(0) + self.assertHelpEquals(_expected_very_help_short_lines) def test_help_unicode(self): self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,10 @@ Library ------- +- Issue #13107: argparse and optparse no longer raises an exception when output + a help on environment with too small COLUMNS. Based on patch by + Elazar Gershuni. + - Issue #20207: Always disable SSLv2 except when PROTOCOL_SSLv2 is explicitly asked for. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 00:02:45 2014 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 10 Jan 2014 00:02:45 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_assertEquals_is_deprecated?= =?utf-8?q?=2C_use_assertEqual_instead=2E?= Message-ID: <3f0jXP3fkNz7LjP@mail.python.org> http://hg.python.org/cpython/rev/e64130c222f3 changeset: 88384:e64130c222f3 user: Antoine Pitrou date: Fri Jan 10 00:02:38 2014 +0100 summary: assertEquals is deprecated, use assertEqual instead. files: Lib/test/test_unicode.py | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 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 @@ -1141,14 +1141,14 @@ return int(self.value) pi = PsuedoFloat(3.1415) letter_m = PsuedoInt(109) - self.assertEquals('%x' % 42, '2a') - self.assertEquals('%X' % 15, 'F') - self.assertEquals('%o' % 9, '11') - self.assertEquals('%c' % 109, 'm') - self.assertEquals('%x' % letter_m, '6d') - self.assertEquals('%X' % letter_m, '6D') - self.assertEquals('%o' % letter_m, '155') - self.assertEquals('%c' % letter_m, 'm') + self.assertEqual('%x' % 42, '2a') + self.assertEqual('%X' % 15, 'F') + self.assertEqual('%o' % 9, '11') + self.assertEqual('%c' % 109, 'm') + self.assertEqual('%x' % letter_m, '6d') + self.assertEqual('%X' % letter_m, '6D') + self.assertEqual('%o' % letter_m, '155') + self.assertEqual('%c' % letter_m, 'm') self.assertRaises(TypeError, '%x'.__mod__, pi) self.assertRaises(TypeError, '%x'.__mod__, 3.14) self.assertRaises(TypeError, '%X'.__mod__, 2.11) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 01:03:36 2014 From: python-checkins at python.org (brett.cannon) Date: Fri, 10 Jan 2014 01:03:36 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320152=3A_import?= =?utf-8?q?=2Ec_now_uses_Argument_Clinic=2E?= Message-ID: <3f0ktc0SvJz7LjZ@mail.python.org> http://hg.python.org/cpython/rev/1f3242fb0c9c changeset: 88385:1f3242fb0c9c user: Brett Cannon date: Thu Jan 09 19:03:32 2014 -0500 summary: Issue #20152: import.c now uses Argument Clinic. files: Misc/NEWS | 2 + Python/import.c | 546 ++++++++++++++++++++++++++++++----- 2 files changed, 463 insertions(+), 85 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,8 @@ Library ------- +- Issue #20152: Ported Python/import.c over to Argument Clinic. + - Issue #13107: argparse and optparse no longer raises an exception when output a help on environment with too small COLUMNS. Based on patch by Elazar Gershuni. diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -31,6 +31,19 @@ static PyObject *initstr = NULL; +/*[clinic input] +module _imp +[clinic start generated code]*/ +/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + +/*[python input] +class fs_unicode_converter(CConverter): + type = 'PyObject *' + converter = 'PyUnicode_FSDecoder' + +[python start generated code]*/ +/*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + /* Initialize things */ void @@ -210,8 +223,39 @@ #endif +/*[clinic input] +_imp.lock_held + +Return True if the import lock is currently held, else False. + +On platforms without threads, return False. +[clinic start generated code]*/ + +PyDoc_STRVAR(_imp_lock_held__doc__, +"lock_held()\n" +"Return True if the import lock is currently held, else False.\n" +"\n" +"On platforms without threads, return False."); + +#define _IMP_LOCK_HELD_METHODDEF \ + {"lock_held", (PyCFunction)_imp_lock_held, METH_NOARGS, _imp_lock_held__doc__}, + static PyObject * -imp_lock_held(PyObject *self, PyObject *noargs) +_imp_lock_held_impl(PyModuleDef *module); + +static PyObject * +_imp_lock_held(PyModuleDef *module, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + return_value = _imp_lock_held_impl(module); + + return return_value; +} + +static PyObject * +_imp_lock_held_impl(PyModuleDef *module) +/*[clinic end generated code: checksum=c5858b257881f94dee95526229a8d1a57ccff158]*/ { #ifdef WITH_THREAD return PyBool_FromLong(import_lock_thread != -1); @@ -220,8 +264,41 @@ #endif } +/*[clinic input] +_imp.acquire_lock + +Acquires the interpreter's import lock for the current thread. + +This lock should be used by import hooks to ensure thread-safety when importing +modules. On platforms without threads, this function does nothing. +[clinic start generated code]*/ + +PyDoc_STRVAR(_imp_acquire_lock__doc__, +"acquire_lock()\n" +"Acquires the interpreter\'s import lock for the current thread.\n" +"\n" +"This lock should be used by import hooks to ensure thread-safety when importing\n" +"modules. On platforms without threads, this function does nothing."); + +#define _IMP_ACQUIRE_LOCK_METHODDEF \ + {"acquire_lock", (PyCFunction)_imp_acquire_lock, METH_NOARGS, _imp_acquire_lock__doc__}, + static PyObject * -imp_acquire_lock(PyObject *self, PyObject *noargs) +_imp_acquire_lock_impl(PyModuleDef *module); + +static PyObject * +_imp_acquire_lock(PyModuleDef *module, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + return_value = _imp_acquire_lock_impl(module); + + return return_value; +} + +static PyObject * +_imp_acquire_lock_impl(PyModuleDef *module) +/*[clinic end generated code: checksum=badb56ed0079a6b902c9616fe068d572765b1863]*/ { #ifdef WITH_THREAD _PyImport_AcquireLock(); @@ -230,8 +307,39 @@ return Py_None; } +/*[clinic input] +_imp.release_lock + +Release the interpreter's import lock. + +On platforms without threads, this function does nothing. +[clinic start generated code]*/ + +PyDoc_STRVAR(_imp_release_lock__doc__, +"release_lock()\n" +"Release the interpreter\'s import lock.\n" +"\n" +"On platforms without threads, this function does nothing."); + +#define _IMP_RELEASE_LOCK_METHODDEF \ + {"release_lock", (PyCFunction)_imp_release_lock, METH_NOARGS, _imp_release_lock__doc__}, + static PyObject * -imp_release_lock(PyObject *self, PyObject *noargs) +_imp_release_lock_impl(PyModuleDef *module); + +static PyObject * +_imp_release_lock(PyModuleDef *module, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + return_value = _imp_release_lock_impl(module); + + return return_value; +} + +static PyObject * +_imp_release_lock_impl(PyModuleDef *module) +/*[clinic end generated code: checksum=f1c2a75e3136a113184e0af2a676d5f0b5b685b4]*/ { #ifdef WITH_THREAD if (_PyImport_ReleaseLock() < 0) { @@ -817,28 +925,57 @@ Py_DECREF(oldname); } +/*[clinic input] +_imp._fix_co_filename + + code: object(type="PyCodeObject *", subclass_of="&PyCode_Type") + Code object to change. + + path: unicode + File path to use. + / + +Changes code.co_filename to specify the passed-in file path. +[clinic start generated code]*/ + +PyDoc_STRVAR(_imp__fix_co_filename__doc__, +"_fix_co_filename(code, path)\n" +"Changes code.co_filename to specify the passed-in file path.\n" +"\n" +" code\n" +" Code object to change.\n" +" path\n" +" File path to use."); + +#define _IMP__FIX_CO_FILENAME_METHODDEF \ + {"_fix_co_filename", (PyCFunction)_imp__fix_co_filename, METH_VARARGS, _imp__fix_co_filename__doc__}, + static PyObject * -imp_fix_co_filename(PyObject *self, PyObject *args) +_imp__fix_co_filename_impl(PyModuleDef *module, PyCodeObject *code, PyObject *path); + +static PyObject * +_imp__fix_co_filename(PyModuleDef *module, PyObject *args) { - PyObject *co; - PyObject *file_path; + PyObject *return_value = NULL; + PyCodeObject *code; + PyObject *path; - if (!PyArg_ParseTuple(args, "OO:_fix_co_filename", &co, &file_path)) - return NULL; + if (!PyArg_ParseTuple(args, + "O!U:_fix_co_filename", + &PyCode_Type, &code, &path)) + goto exit; + return_value = _imp__fix_co_filename_impl(module, code, path); - if (!PyCode_Check(co)) { - PyErr_SetString(PyExc_TypeError, - "first argument must be a code object"); - return NULL; - } +exit: + return return_value; +} - if (!PyUnicode_Check(file_path)) { - PyErr_SetString(PyExc_TypeError, - "second argument must be a string"); - return NULL; - } +static PyObject * +_imp__fix_co_filename_impl(PyModuleDef *module, PyCodeObject *code, PyObject *path) +/*[clinic end generated code: checksum=4f55bad308072b30ad1921068fc4ce85bd2b39bf]*/ - update_compiled_module((PyCodeObject*)co, file_path); +{ + update_compiled_module((PyCodeObject*)code, path); Py_RETURN_NONE; } @@ -1691,8 +1828,35 @@ return r; } +/*[clinic input] +_imp.extension_suffixes + +Returns the list of file suffixes used to identify extension modules. +[clinic start generated code]*/ + +PyDoc_STRVAR(_imp_extension_suffixes__doc__, +"extension_suffixes()\n" +"Returns the list of file suffixes used to identify extension modules."); + +#define _IMP_EXTENSION_SUFFIXES_METHODDEF \ + {"extension_suffixes", (PyCFunction)_imp_extension_suffixes, METH_NOARGS, _imp_extension_suffixes__doc__}, + static PyObject * -imp_extension_suffixes(PyObject *self, PyObject *noargs) +_imp_extension_suffixes_impl(PyModuleDef *module); + +static PyObject * +_imp_extension_suffixes(PyModuleDef *module, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + return_value = _imp_extension_suffixes_impl(module); + + return return_value; +} + +static PyObject * +_imp_extension_suffixes_impl(PyModuleDef *module) +/*[clinic end generated code: checksum=835921e67fd698e22e101eea64839d1ad62b6451]*/ { PyObject *list; const char *suffix; @@ -1720,14 +1884,48 @@ return list; } +/*[clinic input] +_imp.init_builtin + + name: unicode + / + +Initializes a built-in module. +[clinic start generated code]*/ + +PyDoc_STRVAR(_imp_init_builtin__doc__, +"init_builtin(name)\n" +"Initializes a built-in module."); + +#define _IMP_INIT_BUILTIN_METHODDEF \ + {"init_builtin", (PyCFunction)_imp_init_builtin, METH_VARARGS, _imp_init_builtin__doc__}, + static PyObject * -imp_init_builtin(PyObject *self, PyObject *args) +_imp_init_builtin_impl(PyModuleDef *module, PyObject *name); + +static PyObject * +_imp_init_builtin(PyModuleDef *module, PyObject *args) { + PyObject *return_value = NULL; PyObject *name; + + if (!PyArg_ParseTuple(args, + "U:init_builtin", + &name)) + goto exit; + return_value = _imp_init_builtin_impl(module, name); + +exit: + return return_value; +} + +static PyObject * +_imp_init_builtin_impl(PyModuleDef *module, PyObject *name) +/*[clinic end generated code: checksum=59239206e5b2fb59358066e72fd0e72e55a7baf5]*/ +{ int ret; PyObject *m; - if (!PyArg_ParseTuple(args, "U:init_builtin", &name)) - return NULL; + ret = init_builtin(name); if (ret < 0) return NULL; @@ -1740,14 +1938,48 @@ return m; } +/*[clinic input] +_imp.init_frozen + + name: unicode + / + +Initializes a frozen module. +[clinic start generated code]*/ + +PyDoc_STRVAR(_imp_init_frozen__doc__, +"init_frozen(name)\n" +"Initializes a frozen module."); + +#define _IMP_INIT_FROZEN_METHODDEF \ + {"init_frozen", (PyCFunction)_imp_init_frozen, METH_VARARGS, _imp_init_frozen__doc__}, + static PyObject * -imp_init_frozen(PyObject *self, PyObject *args) +_imp_init_frozen_impl(PyModuleDef *module, PyObject *name); + +static PyObject * +_imp_init_frozen(PyModuleDef *module, PyObject *args) { + PyObject *return_value = NULL; PyObject *name; + + if (!PyArg_ParseTuple(args, + "U:init_frozen", + &name)) + goto exit; + return_value = _imp_init_frozen_impl(module, name); + +exit: + return return_value; +} + +static PyObject * +_imp_init_frozen_impl(PyModuleDef *module, PyObject *name) +/*[clinic end generated code: checksum=503fcc3de9961263e4d9484259af357a7d287a0b]*/ +{ int ret; PyObject *m; - if (!PyArg_ParseTuple(args, "U:init_frozen", &name)) - return NULL; + ret = PyImport_ImportFrozenModuleObject(name); if (ret < 0) return NULL; @@ -1760,61 +1992,229 @@ return m; } +/*[clinic input] +_imp.get_frozen_object + + name: unicode + / + +Create a code object for a frozen module. +[clinic start generated code]*/ + +PyDoc_STRVAR(_imp_get_frozen_object__doc__, +"get_frozen_object(name)\n" +"Create a code object for a frozen module."); + +#define _IMP_GET_FROZEN_OBJECT_METHODDEF \ + {"get_frozen_object", (PyCFunction)_imp_get_frozen_object, METH_VARARGS, _imp_get_frozen_object__doc__}, + static PyObject * -imp_get_frozen_object(PyObject *self, PyObject *args) +_imp_get_frozen_object_impl(PyModuleDef *module, PyObject *name); + +static PyObject * +_imp_get_frozen_object(PyModuleDef *module, PyObject *args) { + PyObject *return_value = NULL; PyObject *name; - if (!PyArg_ParseTuple(args, "U:get_frozen_object", &name)) - return NULL; + if (!PyArg_ParseTuple(args, + "U:get_frozen_object", + &name)) + goto exit; + return_value = _imp_get_frozen_object_impl(module, name); + +exit: + return return_value; +} + +static PyObject * +_imp_get_frozen_object_impl(PyModuleDef *module, PyObject *name) +/*[clinic end generated code: checksum=7a6423a4daf139496b9a394ff3ac6130089d1cba]*/ +{ return get_frozen_object(name); } +/*[clinic input] +_imp.is_frozen_package + + name: unicode + / + +Returns True if the module name is of a frozen package. +[clinic start generated code]*/ + +PyDoc_STRVAR(_imp_is_frozen_package__doc__, +"is_frozen_package(name)\n" +"Returns True if the module name is of a frozen package."); + +#define _IMP_IS_FROZEN_PACKAGE_METHODDEF \ + {"is_frozen_package", (PyCFunction)_imp_is_frozen_package, METH_VARARGS, _imp_is_frozen_package__doc__}, + static PyObject * -imp_is_frozen_package(PyObject *self, PyObject *args) +_imp_is_frozen_package_impl(PyModuleDef *module, PyObject *name); + +static PyObject * +_imp_is_frozen_package(PyModuleDef *module, PyObject *args) { + PyObject *return_value = NULL; PyObject *name; - if (!PyArg_ParseTuple(args, "U:is_frozen_package", &name)) - return NULL; + if (!PyArg_ParseTuple(args, + "U:is_frozen_package", + &name)) + goto exit; + return_value = _imp_is_frozen_package_impl(module, name); + +exit: + return return_value; +} + +static PyObject * +_imp_is_frozen_package_impl(PyModuleDef *module, PyObject *name) +/*[clinic end generated code: checksum=dc7e361ea30b6945b8bbe7266d7b9a5ea433b510]*/ +{ return is_frozen_package(name); } +/*[clinic input] +_imp.is_builtin + + name: unicode + / + +Returns True if the module name corresponds to a built-in module. +[clinic start generated code]*/ + +PyDoc_STRVAR(_imp_is_builtin__doc__, +"is_builtin(name)\n" +"Returns True if the module name corresponds to a built-in module."); + +#define _IMP_IS_BUILTIN_METHODDEF \ + {"is_builtin", (PyCFunction)_imp_is_builtin, METH_VARARGS, _imp_is_builtin__doc__}, + static PyObject * -imp_is_builtin(PyObject *self, PyObject *args) +_imp_is_builtin_impl(PyModuleDef *module, PyObject *name); + +static PyObject * +_imp_is_builtin(PyModuleDef *module, PyObject *args) { + PyObject *return_value = NULL; PyObject *name; - if (!PyArg_ParseTuple(args, "U:is_builtin", &name)) - return NULL; + + if (!PyArg_ParseTuple(args, + "U:is_builtin", + &name)) + goto exit; + return_value = _imp_is_builtin_impl(module, name); + +exit: + return return_value; +} + +static PyObject * +_imp_is_builtin_impl(PyModuleDef *module, PyObject *name) +/*[clinic end generated code: checksum=353938c1d55210a1e3850d3ccba7539d02165cac]*/ +{ return PyLong_FromLong(is_builtin(name)); } +/*[clinic input] +_imp.is_frozen + + name: unicode + / + +Returns True if the module name corresponds to a frozen module. +[clinic start generated code]*/ + +PyDoc_STRVAR(_imp_is_frozen__doc__, +"is_frozen(name)\n" +"Returns True if the module name corresponds to a frozen module."); + +#define _IMP_IS_FROZEN_METHODDEF \ + {"is_frozen", (PyCFunction)_imp_is_frozen, METH_VARARGS, _imp_is_frozen__doc__}, + static PyObject * -imp_is_frozen(PyObject *self, PyObject *args) +_imp_is_frozen_impl(PyModuleDef *module, PyObject *name); + +static PyObject * +_imp_is_frozen(PyModuleDef *module, PyObject *args) { + PyObject *return_value = NULL; PyObject *name; + + if (!PyArg_ParseTuple(args, + "U:is_frozen", + &name)) + goto exit; + return_value = _imp_is_frozen_impl(module, name); + +exit: + return return_value; +} + +static PyObject * +_imp_is_frozen_impl(PyModuleDef *module, PyObject *name) +/*[clinic end generated code: checksum=978b547ddcb76fa6c4a181ad53569c9acf382c7b]*/ +{ const struct _frozen *p; - if (!PyArg_ParseTuple(args, "U:is_frozen", &name)) - return NULL; + p = find_frozen(name); return PyBool_FromLong((long) (p == NULL ? 0 : p->size)); } #ifdef HAVE_DYNAMIC_LOADING +/*[clinic input] +_imp.load_dynamic + + name: unicode + path: fs_unicode + file: object = NULL + / + +Loads an extension module. +[clinic start generated code]*/ + +PyDoc_STRVAR(_imp_load_dynamic__doc__, +"load_dynamic(name, path, file=None)\n" +"Loads an extension module."); + +#define _IMP_LOAD_DYNAMIC_METHODDEF \ + {"load_dynamic", (PyCFunction)_imp_load_dynamic, METH_VARARGS, _imp_load_dynamic__doc__}, + static PyObject * -imp_load_dynamic(PyObject *self, PyObject *args) +_imp_load_dynamic_impl(PyModuleDef *module, PyObject *name, PyObject *path, PyObject *file); + +static PyObject * +_imp_load_dynamic(PyModuleDef *module, PyObject *args) { - PyObject *name, *pathname, *fob = NULL, *mod; + PyObject *return_value = NULL; + PyObject *name; + PyObject *path; + PyObject *file = NULL; + + if (!PyArg_ParseTuple(args, + "UO&|O:load_dynamic", + &name, PyUnicode_FSDecoder, &path, &file)) + goto exit; + return_value = _imp_load_dynamic_impl(module, name, path, file); + +exit: + return return_value; +} + +static PyObject * +_imp_load_dynamic_impl(PyModuleDef *module, PyObject *name, PyObject *path, PyObject *file) +/*[clinic end generated code: checksum=6795f65d9ce003ccaf08e4e8eef484dc52e262d0]*/ +{ + PyObject *mod; FILE *fp; - if (!PyArg_ParseTuple(args, "UO&|O:load_dynamic", - &name, PyUnicode_FSDecoder, &pathname, &fob)) - return NULL; - if (fob != NULL) { - fp = _Py_fopen_obj(pathname, "r"); + if (file != NULL) { + fp = _Py_fopen_obj(path, "r"); if (fp == NULL) { - Py_DECREF(pathname); + Py_DECREF(path); if (!PyErr_Occurred()) PyErr_SetFromErrno(PyExc_IOError); return NULL; @@ -1822,8 +2222,8 @@ } else fp = NULL; - mod = _PyImport_LoadDynamicModule(name, pathname, fp); - Py_DECREF(pathname); + mod = _PyImport_LoadDynamicModule(name, path, fp); + Py_DECREF(path); if (fp) fclose(fp); return mod; @@ -1832,49 +2232,25 @@ #endif /* HAVE_DYNAMIC_LOADING */ -/* Doc strings */ - PyDoc_STRVAR(doc_imp, "(Extremely) low-level import machinery bits as used by importlib and imp."); -PyDoc_STRVAR(doc_extension_suffixes, -"extension_suffixes() -> list of strings\n\ -Returns the list of file suffixes used to identify extension modules."); - -PyDoc_STRVAR(doc_lock_held, -"lock_held() -> boolean\n\ -Return True if the import lock is currently held, else False.\n\ -On platforms without threads, return False."); - -PyDoc_STRVAR(doc_acquire_lock, -"acquire_lock() -> None\n\ -Acquires the interpreter's import lock for the current thread.\n\ -This lock should be used by import hooks to ensure thread-safety\n\ -when importing modules.\n\ -On platforms without threads, this function does nothing."); - -PyDoc_STRVAR(doc_release_lock, -"release_lock() -> None\n\ -Release the interpreter's import lock.\n\ -On platforms without threads, this function does nothing."); - static PyMethodDef imp_methods[] = { - {"extension_suffixes", imp_extension_suffixes, METH_NOARGS, - doc_extension_suffixes}, - {"lock_held", imp_lock_held, METH_NOARGS, doc_lock_held}, - {"acquire_lock", imp_acquire_lock, METH_NOARGS, doc_acquire_lock}, - {"release_lock", imp_release_lock, METH_NOARGS, doc_release_lock}, - {"get_frozen_object", imp_get_frozen_object, METH_VARARGS}, - {"is_frozen_package", imp_is_frozen_package, METH_VARARGS}, - {"init_builtin", imp_init_builtin, METH_VARARGS}, - {"init_frozen", imp_init_frozen, METH_VARARGS}, - {"is_builtin", imp_is_builtin, METH_VARARGS}, - {"is_frozen", imp_is_frozen, METH_VARARGS}, + _IMP_EXTENSION_SUFFIXES_METHODDEF + _IMP_LOCK_HELD_METHODDEF + _IMP_ACQUIRE_LOCK_METHODDEF + _IMP_RELEASE_LOCK_METHODDEF + _IMP_GET_FROZEN_OBJECT_METHODDEF + _IMP_IS_FROZEN_PACKAGE_METHODDEF + _IMP_INIT_BUILTIN_METHODDEF + _IMP_INIT_FROZEN_METHODDEF + _IMP_IS_BUILTIN_METHODDEF + _IMP_IS_FROZEN_METHODDEF #ifdef HAVE_DYNAMIC_LOADING - {"load_dynamic", imp_load_dynamic, METH_VARARGS}, + _IMP_LOAD_DYNAMIC_METHODDEF #endif - {"_fix_co_filename", imp_fix_co_filename, METH_VARARGS}, - {NULL, NULL} /* sentinel */ + _IMP__FIX_CO_FILENAME_METHODDEF + {NULL, NULL} /* sentinel */ }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 04:41:45 2014 From: python-checkins at python.org (zach.ware) Date: Fri, 10 Jan 2014 04:41:45 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2320200=3A_Argumen?= =?utf-8?q?t_Clinic_custom_converter_example_should_be_in_a?= Message-ID: <3f0qkK2lSlz7Ljg@mail.python.org> http://hg.python.org/cpython/rev/5a8301002f5a changeset: 88386:5a8301002f5a user: Zachary Ware date: Thu Jan 09 21:41:23 2014 -0600 summary: Closes #20200: Argument Clinic custom converter example should be in a 'python' clinic block, not a 'clinic' clinic block. Patch written by Ryan Smith-Roberts. files: Doc/howto/clinic.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -821,10 +821,10 @@ type for ``self``, it's best to create your own converter, subclassing ``self_converter`` but overwriting the ``type`` member:: - /*[clinic input] + /*[python input] class PicklerObject_converter(self_converter): type = "PicklerObject *" - [clinic start generated code]*/ + [python start generated code]*/ /*[clinic input] -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Jan 10 09:48:33 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 10 Jan 2014 09:48:33 +0100 Subject: [Python-checkins] Daily reference leaks (1f3242fb0c9c): sum=-1 Message-ID: results for 1f3242fb0c9c on branch "default" -------------------------------------------- test_audioop leaked [1, 1, 1] references, sum=3 test_site leaked [-2, 2, -2] references, sum=-2 test_site leaked [-2, 2, -2] memory blocks, sum=-2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogpXXmgo', '-x'] From python-checkins at python.org Fri Jan 10 10:11:01 2014 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 10 Jan 2014 10:11:01 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_460=3A_mention_that_=5F?= =?utf-8?q?=5Fformat=5F=5F_isn=27t_called?= Message-ID: <3f0z2F13slz7Lss@mail.python.org> http://hg.python.org/peps/rev/639204b77d80 changeset: 5342:639204b77d80 user: Antoine Pitrou date: Fri Jan 10 10:10:56 2014 +0100 summary: PEP 460: mention that __format__ isn't called files: pep-0460.txt | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/pep-0460.txt b/pep-0460.txt --- a/pep-0460.txt +++ b/pep-0460.txt @@ -101,6 +101,8 @@ or alignment. Besides, ``str`` objects are not acceptable as arguments to the formatting operations, even when using e.g. the ``%s`` format code. +``__format__`` isn't called. + Criticisms ========== -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri Jan 10 12:42:00 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 10 Jan 2014 12:42:00 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE5ODg2?= =?utf-8?q?=3A_Use_better_estimated_memory_requirements_for_bigmem_tests?= =?utf-8?q?=2E?= Message-ID: <3f12NS4l2rz7Ll0@mail.python.org> http://hg.python.org/cpython/rev/aee672ba9c38 changeset: 88387:aee672ba9c38 branch: 2.7 parent: 88381:779de7b4909b user: Serhiy Storchaka date: Fri Jan 10 13:36:56 2014 +0200 summary: Issue #19886: Use better estimated memory requirements for bigmem tests. Incorrect requirements can cause memory swapping. files: Lib/test/test_hashlib.py | 28 +++++++++------------------- Lib/test/test_marshal.py | 2 +- Misc/NEWS | 2 ++ 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -207,30 +207,20 @@ self.check('md5', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', 'd174ab98d277d9f5a5611c2c9f419d9f') - @precisionbigmemtest(size=_4G + 5, memuse=1) + @unittest.skipIf(sys.maxsize < _4G + 5, 'test cannot run on 32-bit systems') + @precisionbigmemtest(size=_4G + 5, memuse=1, dry_run=False) def test_case_md5_huge(self, size): - if size == _4G + 5: - try: - self.check('md5', 'A'*size, 'c9af2dff37468ce5dfee8f2cfc0a9c6d') - except OverflowError: - pass # 32-bit arch + self.check('md5', 'A'*size, 'c9af2dff37468ce5dfee8f2cfc0a9c6d') - @precisionbigmemtest(size=_4G + 5, memuse=1) + @unittest.skipIf(sys.maxsize < _4G + 5, 'test cannot run on 32-bit systems') + @precisionbigmemtest(size=_4G + 5, memuse=1, dry_run=False) def test_case_md5_huge_update(self, size): - if size == _4G + 5: - try: - self.check_update('md5', 'A'*size, - 'c9af2dff37468ce5dfee8f2cfc0a9c6d') - except OverflowError: - pass # 32-bit arch + self.check_update('md5', 'A'*size, 'c9af2dff37468ce5dfee8f2cfc0a9c6d') - @precisionbigmemtest(size=_4G - 1, memuse=1) + @unittest.skipIf(sys.maxsize < _4G - 1, 'test cannot run on 32-bit systems') + @precisionbigmemtest(size=_4G - 1, memuse=1, dry_run=False) def test_case_md5_uintmax(self, size): - if size == _4G - 1: - try: - self.check('md5', 'A'*size, '28138d306ff1b8281f1a9067e1a1a2b3') - except OverflowError: - pass # 32-bit arch + self.check('md5', 'A'*size, '28138d306ff1b8281f1a9067e1a1a2b3') # use the three examples from Federal Information Processing Standards # Publication 180-1, Secure Hash Standard, 1995 April 17 diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -286,7 +286,7 @@ self.check_unmarshallable('x' * size) @test_support.precisionbigmemtest(size=LARGE_SIZE, - memuse=character_size, dry_run=False) + memuse=character_size + 2, dry_run=False) def test_unicode(self, size): self.check_unmarshallable(u'x' * size) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -161,6 +161,8 @@ Tests ----- +- Issue #19886: Use better estimated memory requirements for bigmem tests. + - Backported tests for Tkinter variables. - Issue #19320: test_tcl no longer fails when wantobjects is false. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 12:42:02 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 10 Jan 2014 12:42:02 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE5ODg2?= =?utf-8?q?=3A_Use_better_estimated_memory_requirements_for_bigmem_tests?= =?utf-8?q?=2E?= Message-ID: <3f12NV0NvHz7LlD@mail.python.org> http://hg.python.org/cpython/rev/2ca26065fb00 changeset: 88388:2ca26065fb00 branch: 3.3 parent: 88382:c6c30b682e14 user: Serhiy Storchaka date: Fri Jan 10 13:37:54 2014 +0200 summary: Issue #19886: Use better estimated memory requirements for bigmem tests. Incorrect requirements can cause memory swapping. files: Lib/test/pickletester.py | 12 +++++------- Lib/test/test_bz2.py | 2 +- Lib/test/test_hashlib.py | 18 ++++++------------ Lib/test/test_marshal.py | 10 +++++----- Lib/test/test_xml_etree_c.py | 4 +--- Misc/NEWS | 2 ++ 6 files changed, 20 insertions(+), 28 deletions(-) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -19,8 +19,6 @@ # kind of outer loop. protocols = range(pickle.HIGHEST_PROTOCOL + 1) -ascii_char_size = 1 - # Return True if opcode code appears in the pickle, else False. def opcode_in_pickle(code, pickle): @@ -1331,7 +1329,7 @@ # Binary protocols can serialize longs of up to 2GB-1 - @bigmemtest(size=_2G, memuse=1 + 1, dry_run=False) + @bigmemtest(size=_2G, memuse=3.6, dry_run=False) def test_huge_long_32b(self, size): data = 1 << (8 * size) try: @@ -1347,7 +1345,7 @@ # (older protocols don't have a dedicated opcode for bytes and are # too inefficient) - @bigmemtest(size=_2G, memuse=1 + 1, dry_run=False) + @bigmemtest(size=_2G, memuse=2.5, dry_run=False) def test_huge_bytes_32b(self, size): data = b"abcd" * (size // 4) try: @@ -1363,7 +1361,7 @@ finally: data = None - @bigmemtest(size=_4G, memuse=1 + 1, dry_run=False) + @bigmemtest(size=_4G, memuse=2.5, dry_run=False) def test_huge_bytes_64b(self, size): data = b"a" * size try: @@ -1378,7 +1376,7 @@ # All protocols use 1-byte per printable ASCII character; we add another # byte because the encoded form has to be copied into the internal buffer. - @bigmemtest(size=_2G, memuse=2 + ascii_char_size, dry_run=False) + @bigmemtest(size=_2G, memuse=8, dry_run=False) def test_huge_str_32b(self, size): data = "abcd" * (size // 4) try: @@ -1395,7 +1393,7 @@ # BINUNICODE (protocols 1, 2 and 3) cannot carry more than # 2**32 - 1 bytes of utf-8 encoded unicode. - @bigmemtest(size=_4G, memuse=1 + ascii_char_size, dry_run=False) + @bigmemtest(size=_4G, memuse=8, dry_run=False) def test_huge_str_64b(self, size): data = "a" * size try: 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 @@ -679,7 +679,7 @@ self.assertRaises(EOFError, bz2d.decompress, b"anything") self.assertRaises(EOFError, bz2d.decompress, b"") - @bigmemtest(size=_4G + 100, memuse=3) + @bigmemtest(size=_4G + 100, memuse=3.3) def testDecompress4G(self, size): # "Test BZ2Decompressor.decompress() with >4GiB input" blocksize = 10 * 1024 * 1024 diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -235,21 +235,15 @@ b'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', 'd174ab98d277d9f5a5611c2c9f419d9f') - @bigmemtest(size=_4G + 5, memuse=1) + @unittest.skipIf(sys.maxsize < _4G + 5, 'test cannot run on 32-bit systems') + @bigmemtest(size=_4G + 5, memuse=1, dry_run=False) def test_case_md5_huge(self, size): - if size == _4G + 5: - try: - self.check('md5', b'A'*size, 'c9af2dff37468ce5dfee8f2cfc0a9c6d') - except OverflowError: - pass # 32-bit arch + self.check('md5', b'A'*size, 'c9af2dff37468ce5dfee8f2cfc0a9c6d') - @bigmemtest(size=_4G - 1, memuse=1) + @unittest.skipIf(sys.maxsize < _4G - 1, 'test cannot run on 32-bit systems') + @bigmemtest(size=_4G - 1, memuse=1, dry_run=False) def test_case_md5_uintmax(self, size): - if size == _4G - 1: - try: - self.check('md5', b'A'*size, '28138d306ff1b8281f1a9067e1a1a2b3') - except OverflowError: - pass # 32-bit arch + self.check('md5', b'A'*size, '28138d306ff1b8281f1a9067e1a1a2b3') # use the three examples from Federal Information Processing Standards # Publication 180-1, Secure Hash Standard, 1995 April 17 diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -303,19 +303,19 @@ def check_unmarshallable(self, data): self.assertRaises(ValueError, marshal.dump, data, NullWriter()) - @support.bigmemtest(size=LARGE_SIZE, memuse=1, dry_run=False) + @support.bigmemtest(size=LARGE_SIZE, memuse=2, dry_run=False) def test_bytes(self, size): self.check_unmarshallable(b'x' * size) - @support.bigmemtest(size=LARGE_SIZE, memuse=1, dry_run=False) + @support.bigmemtest(size=LARGE_SIZE, memuse=2, dry_run=False) def test_str(self, size): self.check_unmarshallable('x' * size) - @support.bigmemtest(size=LARGE_SIZE, memuse=pointer_size, dry_run=False) + @support.bigmemtest(size=LARGE_SIZE, memuse=pointer_size + 1, dry_run=False) def test_tuple(self, size): self.check_unmarshallable((None,) * size) - @support.bigmemtest(size=LARGE_SIZE, memuse=pointer_size, dry_run=False) + @support.bigmemtest(size=LARGE_SIZE, memuse=pointer_size + 1, dry_run=False) def test_list(self, size): self.check_unmarshallable([None] * size) @@ -331,7 +331,7 @@ def test_frozenset(self, size): self.check_unmarshallable(frozenset(range(size))) - @support.bigmemtest(size=LARGE_SIZE, memuse=1, dry_run=False) + @support.bigmemtest(size=LARGE_SIZE, memuse=2, dry_run=False) def test_bytearray(self, size): self.check_unmarshallable(bytearray(size)) diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py --- a/Lib/test/test_xml_etree_c.py +++ b/Lib/test/test_xml_etree_c.py @@ -12,10 +12,8 @@ class MiscTests(unittest.TestCase): # Issue #8651. - @support.bigmemtest(size=support._2G + 100, memuse=1) + @support.bigmemtest(size=support._2G + 100, memuse=1, dry_run=False) def test_length_overflow(self, size): - if size < support._2G + 100: - self.skipTest("not enough free memory, need at least 2 GB") data = b'x' * size parser = cET.XMLParser() try: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -234,6 +234,8 @@ Tests ----- +- Issue #19886: Use better estimated memory requirements for bigmem tests. + - Issue #20055: Fix test_shutil under Windows with symlink privileges held. Patch by Vajrasky Kok. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 12:42:03 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 10 Jan 2014 12:42:03 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2319886=3A_Use_better_estimated_memory_requiremen?= =?utf-8?q?ts_for_bigmem_tests=2E?= Message-ID: <3f12NW36tZz7Lk5@mail.python.org> http://hg.python.org/cpython/rev/fff1455e1147 changeset: 88389:fff1455e1147 parent: 88386:5a8301002f5a parent: 88388:2ca26065fb00 user: Serhiy Storchaka date: Fri Jan 10 13:39:27 2014 +0200 summary: Issue #19886: Use better estimated memory requirements for bigmem tests. Incorrect requirements can cause memory swapping. files: Lib/test/pickletester.py | 12 ++++----- Lib/test/test_bz2.py | 2 +- Lib/test/test_hashlib.py | 29 ++++++++--------------- Lib/test/test_marshal.py | 10 ++++---- Lib/test/test_xml_etree_c.py | 4 +-- Misc/NEWS | 5 ++++ 6 files changed, 27 insertions(+), 35 deletions(-) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -21,8 +21,6 @@ # kind of outer loop. protocols = range(pickle.HIGHEST_PROTOCOL + 1) -ascii_char_size = 1 - # Return True if opcode code appears in the pickle, else False. def opcode_in_pickle(code, pickle): @@ -1643,7 +1641,7 @@ # Binary protocols can serialize longs of up to 2GB-1 - @bigmemtest(size=_2G, memuse=1 + 1, dry_run=False) + @bigmemtest(size=_2G, memuse=3.6, dry_run=False) def test_huge_long_32b(self, size): data = 1 << (8 * size) try: @@ -1660,7 +1658,7 @@ # (older protocols don't have a dedicated opcode for bytes and are # too inefficient) - @bigmemtest(size=_2G, memuse=1 + 1, dry_run=False) + @bigmemtest(size=_2G, memuse=2.5, dry_run=False) def test_huge_bytes_32b(self, size): data = b"abcd" * (size // 4) try: @@ -1681,7 +1679,7 @@ finally: data = None - @bigmemtest(size=_4G, memuse=1 + 1, dry_run=False) + @bigmemtest(size=_4G, memuse=2.5, dry_run=False) def test_huge_bytes_64b(self, size): data = b"acbd" * (size // 4) try: @@ -1711,7 +1709,7 @@ # All protocols use 1-byte per printable ASCII character; we add another # byte because the encoded form has to be copied into the internal buffer. - @bigmemtest(size=_2G, memuse=2 + ascii_char_size, dry_run=False) + @bigmemtest(size=_2G, memuse=8, dry_run=False) def test_huge_str_32b(self, size): data = "abcd" * (size // 4) try: @@ -1738,7 +1736,7 @@ # of utf-8 encoded unicode. BINUNICODE8 (protocol 4) supports these huge # unicode strings however. - @bigmemtest(size=_4G, memuse=2 + ascii_char_size, dry_run=False) + @bigmemtest(size=_4G, memuse=8, dry_run=False) def test_huge_str_64b(self, size): data = "abcd" * (size // 4) try: 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 @@ -686,7 +686,7 @@ self.assertRaises(EOFError, bz2d.decompress, b"anything") self.assertRaises(EOFError, bz2d.decompress, b"") - @bigmemtest(size=_4G + 100, memuse=3) + @bigmemtest(size=_4G + 100, memuse=3.3) def testDecompress4G(self, size): # "Test BZ2Decompressor.decompress() with >4GiB input" blocksize = 10 * 1024 * 1024 diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -256,21 +256,15 @@ b'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', 'd174ab98d277d9f5a5611c2c9f419d9f') - @bigmemtest(size=_4G + 5, memuse=1) + @unittest.skipIf(sys.maxsize < _4G + 5, 'test cannot run on 32-bit systems') + @bigmemtest(size=_4G + 5, memuse=1, dry_run=False) def test_case_md5_huge(self, size): - if size == _4G + 5: - try: - self.check('md5', b'A'*size, 'c9af2dff37468ce5dfee8f2cfc0a9c6d') - except OverflowError: - pass # 32-bit arch + self.check('md5', b'A'*size, 'c9af2dff37468ce5dfee8f2cfc0a9c6d') - @bigmemtest(size=_4G - 1, memuse=1) + @unittest.skipIf(sys.maxsize < _4G - 1, 'test cannot run on 32-bit systems') + @bigmemtest(size=_4G - 1, memuse=1, dry_run=False) def test_case_md5_uintmax(self, size): - if size == _4G - 1: - try: - self.check('md5', b'A'*size, '28138d306ff1b8281f1a9067e1a1a2b3') - except OverflowError: - pass # 32-bit arch + self.check('md5', b'A'*size, '28138d306ff1b8281f1a9067e1a1a2b3') # use the three examples from Federal Information Processing Standards # Publication 180-1, Secure Hash Standard, 1995 April 17 @@ -379,14 +373,11 @@ "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb"+ "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b") - @bigmemtest(size=_4G + 5, memuse=1) + @unittest.skipIf(sys.maxsize < _4G + 5, 'test cannot run on 32-bit systems') + @bigmemtest(size=_4G + 5, memuse=1, dry_run=False) def test_case_sha3_224_huge(self, size): - if size == _4G + 5: - try: - self.check('sha3_224', b'A'*size, - '58ef60057c9dddb6a87477e9ace5a26f0d9db01881cf9b10a9f8c224') - except OverflowError: - pass # 32-bit arch + self.check('sha3_224', b'A'*size, + '58ef60057c9dddb6a87477e9ace5a26f0d9db01881cf9b10a9f8c224') def test_gil(self): # Check things work fine with an input larger than the size required diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -288,19 +288,19 @@ def check_unmarshallable(self, data): self.assertRaises(ValueError, marshal.dump, data, NullWriter()) - @support.bigmemtest(size=LARGE_SIZE, memuse=1, dry_run=False) + @support.bigmemtest(size=LARGE_SIZE, memuse=2, dry_run=False) def test_bytes(self, size): self.check_unmarshallable(b'x' * size) - @support.bigmemtest(size=LARGE_SIZE, memuse=1, dry_run=False) + @support.bigmemtest(size=LARGE_SIZE, memuse=2, dry_run=False) def test_str(self, size): self.check_unmarshallable('x' * size) - @support.bigmemtest(size=LARGE_SIZE, memuse=pointer_size, dry_run=False) + @support.bigmemtest(size=LARGE_SIZE, memuse=pointer_size + 1, dry_run=False) def test_tuple(self, size): self.check_unmarshallable((None,) * size) - @support.bigmemtest(size=LARGE_SIZE, memuse=pointer_size, dry_run=False) + @support.bigmemtest(size=LARGE_SIZE, memuse=pointer_size + 1, dry_run=False) def test_list(self, size): self.check_unmarshallable([None] * size) @@ -316,7 +316,7 @@ def test_frozenset(self, size): self.check_unmarshallable(frozenset(range(size))) - @support.bigmemtest(size=LARGE_SIZE, memuse=1, dry_run=False) + @support.bigmemtest(size=LARGE_SIZE, memuse=2, dry_run=False) def test_bytearray(self, size): self.check_unmarshallable(bytearray(size)) diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py --- a/Lib/test/test_xml_etree_c.py +++ b/Lib/test/test_xml_etree_c.py @@ -13,10 +13,8 @@ class MiscTests(unittest.TestCase): # Issue #8651. - @support.bigmemtest(size=support._2G + 100, memuse=1) + @support.bigmemtest(size=support._2G + 100, memuse=1, dry_run=False) def test_length_overflow(self, size): - if size < support._2G + 100: - self.skipTest("not enough free memory, need at least 2 GB") data = b'x' * size parser = cET.XMLParser() try: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -58,6 +58,11 @@ - Issue #18960: IDLE now ignores the source encoding declaration on the second line if the first line contains anything except a comment. +Tests +----- + +- Issue #19886: Use better estimated memory requirements for bigmem tests. + Tools/Demos ----------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 13:44:14 2014 From: python-checkins at python.org (brett.cannon) Date: Fri, 10 Jan 2014 13:44:14 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Remove_an_unneeded_cast=2E?= Message-ID: <3f13mG6SRDz7Lmf@mail.python.org> http://hg.python.org/cpython/rev/93bf227664d6 changeset: 88390:93bf227664d6 user: Brett Cannon date: Fri Jan 10 07:43:55 2014 -0500 summary: Remove an unneeded cast. files: Python/import.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -975,7 +975,7 @@ /*[clinic end generated code: checksum=4f55bad308072b30ad1921068fc4ce85bd2b39bf]*/ { - update_compiled_module((PyCodeObject*)code, path); + update_compiled_module(code, path); Py_RETURN_NONE; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 14:11:38 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 10 Jan 2014 14:11:38 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE5ODA0?= =?utf-8?q?=3A_The_test=5Ffind=5Fmac_test_in_test=5Fuuid_is_now_skipped_if?= =?utf-8?q?_the?= Message-ID: <3f14Mt65Gyz7Lkr@mail.python.org> http://hg.python.org/cpython/rev/34ae4333d3bf changeset: 88391:34ae4333d3bf branch: 2.7 parent: 88387:aee672ba9c38 user: Serhiy Storchaka date: Fri Jan 10 15:05:27 2014 +0200 summary: Issue #19804: The test_find_mac test in test_uuid is now skipped if the ifconfig executable is not available. files: Lib/test/test_uuid.py | 11 +++++++++++ Misc/NEWS | 3 +++ 2 files changed, 14 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -358,6 +358,17 @@ def mock_popen(cmd): return io.BytesIO(data) + path = os.environ.get("PATH", os.defpath).split(os.pathsep) + path.extend(('/sbin', '/usr/sbin')) + for dir in path: + executable = os.path.join(dir, 'ifconfig') + if (os.path.exists(executable) and + os.access(executable, os.F_OK | os.X_OK) and + not os.path.isdir(executable)): + break + else: + self.skipTest('requires ifconfig') + with test_support.swap_attr(os, 'popen', mock_popen): mac = uuid._find_mac( command='ifconfig', diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -161,6 +161,9 @@ Tests ----- +- Issue #19804: The test_find_mac test in test_uuid is now skipped if the + ifconfig executable is not available. + - Issue #19886: Use better estimated memory requirements for bigmem tests. - Backported tests for Tkinter variables. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 14:11:40 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 10 Jan 2014 14:11:40 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE5ODA0?= =?utf-8?q?=3A_The_test=5Ffind=5Fmac_test_in_test=5Fuuid_is_now_skipped_if?= =?utf-8?q?_the?= Message-ID: <3f14Mw0dh8z7Lkx@mail.python.org> http://hg.python.org/cpython/rev/201077b57fe0 changeset: 88392:201077b57fe0 branch: 3.3 parent: 88388:2ca26065fb00 user: Serhiy Storchaka date: Fri Jan 10 15:06:59 2014 +0200 summary: Issue #19804: The test_find_mac test in test_uuid is now skipped if the ifconfig executable is not available. files: Lib/test/test_uuid.py | 6 ++++++ Misc/NEWS | 3 +++ 2 files changed, 9 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -3,6 +3,7 @@ import builtins import io import os +import shutil import uuid def importable(name): @@ -369,6 +370,11 @@ def mock_popen(cmd): return io.StringIO(data) + if shutil.which('ifconfig') is None: + path = os.pathsep.join(('/sbin', '/usr/sbin')) + if shutil.which('ifconfig', path=path) is None: + self.skipTest('requires ifconfig') + with support.swap_attr(os, 'popen', mock_popen): mac = uuid._find_mac( command='ifconfig', diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -234,6 +234,9 @@ Tests ----- +- Issue #19804: The test_find_mac test in test_uuid is now skipped if the + ifconfig executable is not available. + - Issue #19886: Use better estimated memory requirements for bigmem tests. - Issue #20055: Fix test_shutil under Windows with symlink privileges held. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 14:11:41 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 10 Jan 2014 14:11:41 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2319804=3A_The_test=5Ffind=5Fmac_test_in_test=5Fu?= =?utf-8?q?uid_is_now_skipped_if_the?= Message-ID: <3f14Mx3FLXz7Lkw@mail.python.org> http://hg.python.org/cpython/rev/51dc9b2a5b35 changeset: 88393:51dc9b2a5b35 parent: 88390:93bf227664d6 parent: 88392:201077b57fe0 user: Serhiy Storchaka date: Fri Jan 10 15:08:07 2014 +0200 summary: Issue #19804: The test_find_mac test in test_uuid is now skipped if the ifconfig executable is not available. files: Lib/test/test_uuid.py | 6 ++++++ Misc/NEWS | 3 +++ 2 files changed, 9 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -3,6 +3,7 @@ import builtins import io import os +import shutil import uuid def importable(name): @@ -369,6 +370,11 @@ def mock_popen(cmd): return io.StringIO(data) + if shutil.which('ifconfig') is None: + path = os.pathsep.join(('/sbin', '/usr/sbin')) + if shutil.which('ifconfig', path=path) is None: + self.skipTest('requires ifconfig') + with support.swap_attr(os, 'popen', mock_popen): mac = uuid._find_mac( command='ifconfig', diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -389,6 +389,9 @@ Tests ----- +- Issue #19804: The test_find_mac test in test_uuid is now skipped if the + ifconfig executable is not available. + - Issue #20055: Fix test_shutil under Windows with symlink privileges held. Patch by Vajrasky Kok. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 14:35:35 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 10 Jan 2014 14:35:35 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIwMDg2?= =?utf-8?q?=3A_Output_more_details_when_test=5Fgetsetlocale=5Fissue1813_is?= =?utf-8?q?_failed=2E?= Message-ID: <3f14vW1MnXz7Lk5@mail.python.org> http://hg.python.org/cpython/rev/3696b9ae6b17 changeset: 88394:3696b9ae6b17 branch: 2.7 parent: 88391:34ae4333d3bf user: Serhiy Storchaka date: Fri Jan 10 15:34:51 2014 +0200 summary: Issue #20086: Output more details when test_getsetlocale_issue1813 is failed. files: Lib/test/test_locale.py | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_locale.py b/Lib/test/test_locale.py --- a/Lib/test/test_locale.py +++ b/Lib/test/test_locale.py @@ -477,7 +477,12 @@ # Unsupported locale on this system self.skipTest('test needs Turkish locale') loc = locale.getlocale() - locale.setlocale(locale.LC_CTYPE, loc) + try: + locale.setlocale(locale.LC_CTYPE, loc) + except Exception as e: + self.fail("Failed to set locale %r (default locale is %r): %r" % + (loc, oldlocale, e)) + print("set locale %r (default locale is %r)" % (loc, oldlocale)) self.assertEqual(loc, locale.getlocale()) def test_normalize_issue12752(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 16:25:13 2014 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 10 Jan 2014 16:25:13 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_fix_build_when?= =?utf-8?q?_SCHED=5FSPORADIC_is_defined_=28closes_=2320217=29?= Message-ID: <3f17L16sMsz7LlS@mail.python.org> http://hg.python.org/cpython/rev/4f74ea7eba03 changeset: 88395:4f74ea7eba03 branch: 3.3 parent: 88392:201077b57fe0 user: Benjamin Peterson date: Fri Jan 10 09:22:40 2014 -0600 summary: fix build when SCHED_SPORADIC is defined (closes #20217) files: Misc/NEWS | 2 ++ Modules/posixmodule.c | 2 +- 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,8 @@ Library ------- +- Issue #20217: Fix build in SCHED_SPORADIC is defined. + - Issue #13107: argparse and optparse no longer raises an exception when output a help on environment with too small COLUMNS. Based on patch by Elazar Gershuni. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -11863,7 +11863,7 @@ if (ins(d, "SCHED_FIFO", (long)SCHED_FIFO)) return -1; if (ins(d, "SCHED_RR", (long)SCHED_RR)) return -1; #ifdef SCHED_SPORADIC - if (ins(d, "SCHED_SPORADIC", (long)SCHED_SPORADIC) return -1; + if (ins(d, "SCHED_SPORADIC", (long)SCHED_SPORADIC)) return -1; #endif #ifdef SCHED_BATCH if (ins(d, "SCHED_BATCH", (long)SCHED_BATCH)) return -1; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 16:25:15 2014 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 10 Jan 2014 16:25:15 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_null_merge_from_3=2E3?= Message-ID: <3f17L31mYhz7Llc@mail.python.org> http://hg.python.org/cpython/rev/f71f65caf53e changeset: 88396:f71f65caf53e parent: 88393:51dc9b2a5b35 parent: 88395:4f74ea7eba03 user: Benjamin Peterson date: Fri Jan 10 09:24:59 2014 -0600 summary: null merge from 3.3 files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 21:43:23 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 10 Jan 2014 21:43:23 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogRml4ZWQgdGVzdF90?= =?utf-8?q?empfilepager_in_test=5Fpydoc_on_Windows=2E?= Message-ID: <3f1GP70CTVz7Lk0@mail.python.org> http://hg.python.org/cpython/rev/0e5df5b62488 changeset: 88397:0e5df5b62488 branch: 2.7 parent: 88394:3696b9ae6b17 user: Serhiy Storchaka date: Fri Jan 10 22:43:03 2014 +0200 summary: Fixed test_tempfilepager in test_pydoc on Windows. Filename such as r'c:\users\db3l\appdata\local\temp\tmph3vkvf' contains '\t' which is interpreted by ast.literal_eval() as a tabulation. files: Lib/test/test_pydoc.py | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -473,8 +473,9 @@ output = {} def mock_system(cmd): - import ast - output['content'] = open(ast.literal_eval(cmd.strip())).read() + filename = cmd.strip()[1:-1] + self.assertEqual('"' + filename + '"', cmd.strip()) + output['content'] = open(filename).read() saved, os.system = os.system, mock_system try: pydoc.tempfilepager(doc, '') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 22:25:48 2014 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 10 Jan 2014 22:25:48 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Don=27t_special?= =?utf-8?q?-case_GeneratorExit_in_Condition=2Ewait=28=29=2E?= Message-ID: <3f1HL42SSBz7Ll7@mail.python.org> http://hg.python.org/cpython/rev/a6a8308cbfae changeset: 88398:a6a8308cbfae parent: 88396:f71f65caf53e user: Guido van Rossum date: Fri Jan 10 13:25:38 2014 -0800 summary: asyncio: Don't special-case GeneratorExit in Condition.wait(). files: Lib/asyncio/locks.py | 7 +------ 1 files changed, 1 insertions(+), 6 deletions(-) diff --git a/Lib/asyncio/locks.py b/Lib/asyncio/locks.py --- a/Lib/asyncio/locks.py +++ b/Lib/asyncio/locks.py @@ -251,7 +251,6 @@ if not self.locked(): raise RuntimeError('cannot wait on un-acquired lock') - keep_lock = True self.release() try: fut = futures.Future(loop=self._loop) @@ -262,12 +261,8 @@ finally: self._waiters.remove(fut) - except GeneratorExit: - keep_lock = False # Prevent yield in finally clause. - raise finally: - if keep_lock: - yield from self.acquire() + yield from self.acquire() @tasks.coroutine def wait_for(self, predicate): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 22:30:37 2014 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 10 Jan 2014 22:30:37 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Tiny_cleanup_in?= =?utf-8?q?_streams=2Epy=2E?= Message-ID: <3f1HRd5mHdz7Lk2@mail.python.org> http://hg.python.org/cpython/rev/73ac104876ea changeset: 88399:73ac104876ea user: Guido van Rossum date: Fri Jan 10 13:26:38 2014 -0800 summary: asyncio: Tiny cleanup in streams.py. files: Lib/asyncio/streams.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -38,7 +38,7 @@ if loop is None: loop = events.get_event_loop() reader = StreamReader(limit=limit, loop=loop) - protocol = StreamReaderProtocol(reader) + protocol = StreamReaderProtocol(reader, loop=loop) transport, _ = yield from loop.create_connection( lambda: protocol, host, port, **kwds) writer = StreamWriter(transport, protocol, reader, loop) @@ -151,7 +151,7 @@ This exposes write(), writelines(), [can_]write_eof(), get_extra_info() and close(). It adds drain() which returns an optional Future on which you can wait for flow control. It also - adds a transport attribute which references the Transport + adds a transport property which references the Transport directly. """ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 22:30:39 2014 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 10 Jan 2014 22:30:39 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Fix_race_in_sub?= =?utf-8?q?process_transport=2C_by_Victor_Stinner=2E?= Message-ID: <3f1HRg0SZXz7Lk2@mail.python.org> http://hg.python.org/cpython/rev/14161c960900 changeset: 88400:14161c960900 user: Guido van Rossum date: Fri Jan 10 13:28:59 2014 -0800 summary: asyncio: Fix race in subprocess transport, by Victor Stinner. files: Lib/asyncio/unix_events.py | 3 ++- 1 files changed, 2 insertions(+), 1 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 @@ -160,9 +160,10 @@ transp = _UnixSubprocessTransport(self, protocol, args, shell, stdin, stdout, stderr, bufsize, extra=None, **kwargs) + yield from transp._post_init() watcher.add_child_handler(transp.get_pid(), self._child_watcher_callback, transp) - yield from transp._post_init() + return transp def _child_watcher_callback(self, pid, returncode, transp): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 22:30:40 2014 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 10 Jan 2014 22:30:40 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Minimal_pty_sup?= =?utf-8?q?port_in_UNIX_read_pipe=2C_by_Jonathan_Slenders=2E?= Message-ID: <3f1HRh2LdGz7Ll3@mail.python.org> http://hg.python.org/cpython/rev/8a41abdb190a changeset: 88401:8a41abdb190a user: Guido van Rossum date: Fri Jan 10 13:30:04 2014 -0800 summary: asyncio: Minimal pty support in UNIX read pipe, by Jonathan Slenders. files: Lib/asyncio/unix_events.py | 7 +- Lib/test/test_asyncio/test_events.py | 42 ++++++++++++++++ 2 files changed, 47 insertions(+), 2 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 @@ -190,7 +190,9 @@ self._pipe = pipe self._fileno = pipe.fileno() mode = os.fstat(self._fileno).st_mode - if not (stat.S_ISFIFO(mode) or stat.S_ISSOCK(mode)): + if not (stat.S_ISFIFO(mode) or + stat.S_ISSOCK(mode) or + stat.S_ISCHR(mode)): raise ValueError("Pipe transport is for pipes/sockets only.") _set_nonblocking(self._fileno) self._protocol = protocol @@ -228,7 +230,8 @@ def _fatal_error(self, exc): # should be called by exception handler only - logger.exception('Fatal error for %s', self) + if not (isinstance(exc, OSError) and exc.errno == errno.EIO): + logger.exception('Fatal error for %s', self) self._close(exc) def _close(self, exc): 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 @@ -132,6 +132,8 @@ self.state.append('EOF') def connection_lost(self, exc): + if 'EOF' not in self.state: + self.state.append('EOF') # It is okay if EOF is missed. assert self.state == ['INITIAL', 'CONNECTED', 'EOF'], self.state self.state.append('CLOSED') if self.done: @@ -955,6 +957,46 @@ @unittest.skipUnless(sys.platform != 'win32', "Don't support pipes for Windows") + def test_read_pty_output(self): + proto = None + + def factory(): + nonlocal proto + proto = MyReadPipeProto(loop=self.loop) + return proto + + master, slave = os.openpty() + master_read_obj = io.open(master, 'rb', 0) + + @tasks.coroutine + def connect(): + t, p = yield from self.loop.connect_read_pipe(factory, + master_read_obj) + self.assertIs(p, proto) + self.assertIs(t, proto.transport) + self.assertEqual(['INITIAL', 'CONNECTED'], proto.state) + self.assertEqual(0, proto.nbytes) + + self.loop.run_until_complete(connect()) + + os.write(slave, b'1') + test_utils.run_until(self.loop, lambda: proto.nbytes) + self.assertEqual(1, proto.nbytes) + + os.write(slave, b'2345') + test_utils.run_until(self.loop, lambda: proto.nbytes >= 5) + self.assertEqual(['INITIAL', 'CONNECTED'], proto.state) + self.assertEqual(5, proto.nbytes) + + os.close(slave) + self.loop.run_until_complete(proto.done) + self.assertEqual( + ['INITIAL', 'CONNECTED', 'EOF', 'CLOSED'], proto.state) + # extra info is available + self.assertIsNotNone(proto.transport.get_extra_info('pipe')) + + @unittest.skipUnless(sys.platform != 'win32', + "Don't support pipes for Windows") def test_write_pipe(self): proto = None transport = None -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 23:12:23 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 10 Jan 2014 23:12:23 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Try_to_fix_som?= =?utf-8?q?e_ttk_tests=2E__Error_messages_were_changed_in_8=2E6b3=2E?= Message-ID: <3f1JMq6pRLz7Ll7@mail.python.org> http://hg.python.org/cpython/rev/0fab2f9b7edc changeset: 88402:0fab2f9b7edc branch: 2.7 parent: 88397:0e5df5b62488 user: Serhiy Storchaka date: Sat Jan 11 00:09:50 2014 +0200 summary: Try to fix some ttk tests. Error messages were changed in 8.6b3. files: Lib/lib-tk/test/test_ttk/test_widgets.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/lib-tk/test/test_ttk/test_widgets.py b/Lib/lib-tk/test/test_ttk/test_widgets.py --- a/Lib/lib-tk/test/test_ttk/test_widgets.py +++ b/Lib/lib-tk/test/test_ttk/test_widgets.py @@ -6,7 +6,7 @@ import support from test_functions import MockTclObj, MockStateSpec -from support import tcl_version +from support import tcl_version, get_tk_patchlevel from widget_tests import (add_standard_options, noconv, noconv_meth, AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests, @@ -21,7 +21,7 @@ widget = self.create() self.assertEqual(widget['class'], '') errmsg='attempt to change read-only option' - if tcl_version < (8, 6, 0): # actually this was changen in 8.6b3 + if get_tk_patchlevel() < (8, 6, 0): # actually this was changen in 8.6b3 errmsg='Attempt to change read-only option' self.checkInvalidParam(widget, 'class', 'Foo', errmsg=errmsg) widget2 = self.create(class_='Foo') @@ -577,7 +577,7 @@ widget = self.create() self.assertEqual(str(widget['orient']), 'vertical') errmsg='attempt to change read-only option' - if tcl_version < (8, 6): + if get_tk_patchlevel() < (8, 6, 0): # actually this was changen in 8.6b3 errmsg='Attempt to change read-only option' self.checkInvalidParam(widget, 'orient', 'horizontal', errmsg=errmsg) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 23:12:25 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 10 Jan 2014 23:12:25 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Try_to_fix_som?= =?utf-8?q?e_ttk_tests=2E__Error_messages_were_changed_in_8=2E6b3=2E?= Message-ID: <3f1JMs214Bz7Lm9@mail.python.org> http://hg.python.org/cpython/rev/e00fc830937c changeset: 88403:e00fc830937c branch: 3.3 parent: 88395:4f74ea7eba03 user: Serhiy Storchaka date: Sat Jan 11 00:10:04 2014 +0200 summary: Try to fix some ttk tests. Error messages were changed in 8.6b3. files: Lib/tkinter/test/test_ttk/test_widgets.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py --- a/Lib/tkinter/test/test_ttk/test_widgets.py +++ b/Lib/tkinter/test/test_ttk/test_widgets.py @@ -6,7 +6,7 @@ import tkinter.test.support as support from tkinter.test.test_ttk.test_functions import MockTclObj -from tkinter.test.support import tcl_version +from tkinter.test.support import tcl_version, get_tk_patchlevel from tkinter.test.widget_tests import (add_standard_options, noconv, AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests, setUpModule) @@ -20,7 +20,7 @@ widget = self.create() self.assertEqual(widget['class'], '') errmsg='attempt to change read-only option' - if tcl_version < (8, 6): + if get_tk_patchlevel() < (8, 6, 0): # actually this was changed in 8.6b3 errmsg='Attempt to change read-only option' self.checkInvalidParam(widget, 'class', 'Foo', errmsg=errmsg) widget2 = self.create(class_='Foo') @@ -576,7 +576,7 @@ widget = self.create() self.assertEqual(str(widget['orient']), 'vertical') errmsg='attempt to change read-only option' - if tcl_version < (8, 6): + if get_tk_patchlevel() < (8, 6, 0): # actually this was changen in 8.6b3 errmsg='Attempt to change read-only option' self.checkInvalidParam(widget, 'orient', 'horizontal', errmsg=errmsg) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 10 23:12:26 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 10 Jan 2014 23:12:26 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Try_to_fix_some_ttk_tests=2E__Error_messages_were_change?= =?utf-8?q?d_in_8=2E6b3=2E?= Message-ID: <3f1JMt49HRz7Lm4@mail.python.org> http://hg.python.org/cpython/rev/a7aa5a8c1c37 changeset: 88404:a7aa5a8c1c37 parent: 88401:8a41abdb190a parent: 88403:e00fc830937c user: Serhiy Storchaka date: Sat Jan 11 00:10:56 2014 +0200 summary: Try to fix some ttk tests. Error messages were changed in 8.6b3. files: Lib/tkinter/test/test_ttk/test_widgets.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py --- a/Lib/tkinter/test/test_ttk/test_widgets.py +++ b/Lib/tkinter/test/test_ttk/test_widgets.py @@ -6,7 +6,7 @@ import tkinter.test.support as support from tkinter.test.test_ttk.test_functions import MockTclObj -from tkinter.test.support import tcl_version +from tkinter.test.support import tcl_version, get_tk_patchlevel from tkinter.test.widget_tests import (add_standard_options, noconv, AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests, setUpModule) @@ -20,7 +20,7 @@ widget = self.create() self.assertEqual(widget['class'], '') errmsg='attempt to change read-only option' - if tcl_version < (8, 6): + if get_tk_patchlevel() < (8, 6, 0): # actually this was changed in 8.6b3 errmsg='Attempt to change read-only option' self.checkInvalidParam(widget, 'class', 'Foo', errmsg=errmsg) widget2 = self.create(class_='Foo') @@ -576,7 +576,7 @@ widget = self.create() self.assertEqual(str(widget['orient']), 'vertical') errmsg='attempt to change read-only option' - if tcl_version < (8, 6): + if get_tk_patchlevel() < (8, 6, 0): # actually this was changen in 8.6b3 errmsg='Attempt to change read-only option' self.checkInvalidParam(widget, 'orient', 'horizontal', errmsg=errmsg) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 11 00:05:08 2014 From: python-checkins at python.org (victor.stinner) Date: Sat, 11 Jan 2014 00:05:08 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Cleanup_properly_proactor_?= =?utf-8?q?event_loop?= Message-ID: <3f1KXh5Bw7z7Lk0@mail.python.org> http://hg.python.org/cpython/rev/0f4cd0cb1f76 changeset: 88405:0f4cd0cb1f76 user: Victor Stinner date: Sat Jan 11 00:03:21 2014 +0100 summary: Cleanup properly proactor event loop * store the "self reading" future when the "self pipe" is closed (when the event loop is closed) * store "accept" futures to cancel them when we stop serving * close the "accept socket" if the "accept future" is cancelled Fix many warnings which can be seen when unit tests are run in verbose mode. files: Lib/asyncio/proactor_events.py | 10 ++++++++++ Lib/asyncio/windows_events.py | 17 +++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -330,6 +330,8 @@ logger.debug('Using proactor: %s', proactor.__class__.__name__) self._proactor = proactor self._selector = proactor # convenient alias + self._self_reading_future = None + self._accept_futures = {} # socket file descriptor => Future proactor.set_loop(self) self._make_self_pipe() @@ -365,6 +367,7 @@ self._proactor = None self._selector = None super().close() + self._accept_futures.clear() def sock_recv(self, sock, n): return self._proactor.recv(sock, n) @@ -382,6 +385,9 @@ raise NotImplementedError def _close_self_pipe(self): + if self._self_reading_future is not None: + self._self_reading_future.cancel() + self._self_reading_future = None self._ssock.close() self._ssock = None self._csock.close() @@ -405,6 +411,7 @@ self.close() raise else: + self._self_reading_future = f f.add_done_callback(self._loop_self_reading) def _write_to_self(self): @@ -430,6 +437,7 @@ except futures.CancelledError: sock.close() else: + self._accept_futures[sock.fileno()] = f f.add_done_callback(loop) self.call_soon(loop) @@ -438,5 +446,7 @@ pass # XXX hard work currently done in poll def _stop_serving(self, sock): + for future in self._accept_futures.values(): + future.cancel() self._proactor._stop_serving(sock) sock.close() 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 @@ -168,9 +168,6 @@ self.call_soon(loop) return [server] - def _stop_serving(self, server): - server.close() - @tasks.coroutine def _make_subprocess_transport(self, protocol, args, shell, stdin, stdout, stderr, bufsize, @@ -260,7 +257,19 @@ conn.settimeout(listener.gettimeout()) return conn, conn.getpeername() - return self._register(ov, listener, finish_accept) + @tasks.coroutine + def accept_coro(future, conn): + # Coroutine closing the accept socket if the future is cancelled + try: + yield from future + except futures.CancelledError: + conn.close() + raise + + future = self._register(ov, listener, finish_accept) + coro = accept_coro(future, conn) + tasks.async(coro, loop=self._loop) + return future def connect(self, conn, address): self._register_with_iocp(conn) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 11 00:16:58 2014 From: python-checkins at python.org (victor.stinner) Date: Sat, 11 Jan 2014 00:16:58 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_ResourceWarning_in_tes?= =?utf-8?q?t=5Fasyncio=2Etest=5Fwindows=5Fevents=3A?= Message-ID: <3f1KpL3tTDz7Llt@mail.python.org> http://hg.python.org/cpython/rev/52fbc7bb78ad changeset: 88406:52fbc7bb78ad user: Victor Stinner date: Sat Jan 11 00:16:50 2014 +0100 summary: Fix ResourceWarning in test_asyncio.test_windows_events: close the write end of the socket pair files: Lib/test/test_asyncio/test_windows_events.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_asyncio/test_windows_events.py b/Lib/test/test_asyncio/test_windows_events.py --- a/Lib/test/test_asyncio/test_windows_events.py +++ b/Lib/test/test_asyncio/test_windows_events.py @@ -49,6 +49,7 @@ trans.close() self.loop.run_until_complete(f) self.assertEqual(f.result(), b'') + b.close() def test_double_bind(self): ADDRESS = r'\\.\pipe\test_double_bind-%s' % os.getpid() -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Jan 11 09:46:21 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 11 Jan 2014 09:46:21 +0100 Subject: [Python-checkins] Daily reference leaks (52fbc7bb78ad): sum=3 Message-ID: results for 52fbc7bb78ad on branch "default" -------------------------------------------- test_audioop leaked [1, 1, 1] references, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogDvIwPL', '-x'] From python-checkins at python.org Sat Jan 11 10:53:28 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 11 Jan 2014 10:53:28 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Fixed_the_serv?= =?utf-8?q?e=2Epy_script=2E?= Message-ID: <3f1bwm3h1Qz7LjP@mail.python.org> http://hg.python.org/cpython/rev/e6dccdd55e5a changeset: 88407:e6dccdd55e5a branch: 3.3 parent: 88403:e00fc830937c user: Serhiy Storchaka date: Sat Jan 11 11:52:20 2014 +0200 summary: Fixed the serve.py script. The application object must return an iterable yielding bytestrings. files: Tools/scripts/serve.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Tools/scripts/serve.py b/Tools/scripts/serve.py --- a/Tools/scripts/serve.py +++ b/Tools/scripts/serve.py @@ -22,7 +22,7 @@ return util.FileWrapper(open(fn, "rb")) else: respond('404 Not Found', [('Content-Type', 'text/plain')]) - return ['not found'] + return [b'not found'] if __name__ == '__main__': path = sys.argv[1] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 11 10:53:29 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 11 Jan 2014 10:53:29 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Fixed_the_serve=2Epy_script=2E?= Message-ID: <3f1bwn5TLwz7LjP@mail.python.org> http://hg.python.org/cpython/rev/a5b9ae8b4547 changeset: 88408:a5b9ae8b4547 parent: 88406:52fbc7bb78ad parent: 88407:e6dccdd55e5a user: Serhiy Storchaka date: Sat Jan 11 11:53:13 2014 +0200 summary: Fixed the serve.py script. The application object must return an iterable yielding bytestrings. files: Tools/scripts/serve.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Tools/scripts/serve.py b/Tools/scripts/serve.py --- a/Tools/scripts/serve.py +++ b/Tools/scripts/serve.py @@ -22,7 +22,7 @@ return util.FileWrapper(open(fn, "rb")) else: respond('404 Not Found', [('Content-Type', 'text/plain')]) - return ['not found'] + return [b'not found'] if __name__ == '__main__': path = sys.argv[1] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 11 12:16:00 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 11 Jan 2014 12:16:00 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogdGtpbnRlci5UZXh0?= =?utf-8?q?=2Edebug=28=29_now_always_returns_0/1=2E?= Message-ID: <3f1dm04mSCz7Lk6@mail.python.org> http://hg.python.org/cpython/rev/7dab4feec126 changeset: 88409:7dab4feec126 branch: 2.7 parent: 88402:0fab2f9b7edc user: Serhiy Storchaka date: Sat Jan 11 13:12:58 2014 +0200 summary: tkinter.Text.debug() now always returns 0/1. Fixed regression inroduced in issue #6157. files: Lib/lib-tk/Tkinter.py | 2 +- Lib/lib-tk/test/test_tkinter/test_text.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Lib/lib-tk/Tkinter.py b/Lib/lib-tk/Tkinter.py --- a/Lib/lib-tk/Tkinter.py +++ b/Lib/lib-tk/Tkinter.py @@ -2921,7 +2921,7 @@ """Turn on the internal consistency checks of the B-Tree inside the text widget according to BOOLEAN.""" if boolean is None: - return self.tk.call(self._w, 'debug') + return self.tk.getboolean(self.tk.call(self._w, 'debug')) self.tk.call(self._w, 'debug', boolean) def delete(self, index1, index2=None): """Delete the characters between INDEX1 and INDEX2 (not included).""" diff --git a/Lib/lib-tk/test/test_tkinter/test_text.py b/Lib/lib-tk/test/test_tkinter/test_text.py --- a/Lib/lib-tk/test/test_tkinter/test_text.py +++ b/Lib/lib-tk/test/test_tkinter/test_text.py @@ -16,13 +16,12 @@ def test_debug(self): text = self.text - wantobjects = self.root.wantobjects() olddebug = text.debug() try: text.debug(0) - self.assertEqual(text.debug(), 0 if wantobjects else '0') + self.assertEqual(text.debug(), 0) text.debug(1) - self.assertEqual(text.debug(), 1 if wantobjects else '1') + self.assertEqual(text.debug(), 1) finally: text.debug(olddebug) self.assertEqual(text.debug(), olddebug) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 11 12:16:01 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 11 Jan 2014 12:16:01 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogdGtpbnRlci5UZXh0?= =?utf-8?q?=2Edebug=28=29_now_always_returns_0/1=2E?= Message-ID: <3f1dm16dwlz7Lk8@mail.python.org> http://hg.python.org/cpython/rev/05e84d3ecd1e changeset: 88410:05e84d3ecd1e branch: 3.3 parent: 88407:e6dccdd55e5a user: Serhiy Storchaka date: Sat Jan 11 13:13:46 2014 +0200 summary: tkinter.Text.debug() now always returns 0/1. Fixed a regression inroduced in issue #6157. files: Lib/tkinter/__init__.py | 2 +- Lib/tkinter/test/test_tkinter/test_text.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -3002,7 +3002,7 @@ """Turn on the internal consistency checks of the B-Tree inside the text widget according to BOOLEAN.""" if boolean is None: - return self.tk.call(self._w, 'debug') + return self.tk.getboolean(self.tk.call(self._w, 'debug')) self.tk.call(self._w, 'debug', boolean) def delete(self, index1, index2=None): """Delete the characters between INDEX1 and INDEX2 (not included).""" diff --git a/Lib/tkinter/test/test_tkinter/test_text.py b/Lib/tkinter/test/test_tkinter/test_text.py --- a/Lib/tkinter/test/test_tkinter/test_text.py +++ b/Lib/tkinter/test/test_tkinter/test_text.py @@ -16,13 +16,12 @@ def test_debug(self): text = self.text - wantobjects = self.root.wantobjects() olddebug = text.debug() try: text.debug(0) - self.assertEqual(text.debug(), 0 if wantobjects else '0') + self.assertEqual(text.debug(), 0) text.debug(1) - self.assertEqual(text.debug(), 1 if wantobjects else '1') + self.assertEqual(text.debug(), 1) finally: text.debug(olddebug) self.assertEqual(text.debug(), olddebug) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 11 12:16:03 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 11 Jan 2014 12:16:03 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_tkinter=2EText=2Edebug=28=29_now_always_returns_0/1=2E?= Message-ID: <3f1dm31Scpz7Ljr@mail.python.org> http://hg.python.org/cpython/rev/e7d922d8ee03 changeset: 88411:e7d922d8ee03 parent: 88408:a5b9ae8b4547 parent: 88410:05e84d3ecd1e user: Serhiy Storchaka date: Sat Jan 11 13:15:39 2014 +0200 summary: tkinter.Text.debug() now always returns 0/1. Fixed a regression inroduced in issue #6157. files: Lib/tkinter/__init__.py | 2 +- Lib/tkinter/test/test_tkinter/test_text.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -2963,7 +2963,7 @@ """Turn on the internal consistency checks of the B-Tree inside the text widget according to BOOLEAN.""" if boolean is None: - return self.tk.call(self._w, 'debug') + return self.tk.getboolean(self.tk.call(self._w, 'debug')) self.tk.call(self._w, 'debug', boolean) def delete(self, index1, index2=None): """Delete the characters between INDEX1 and INDEX2 (not included).""" diff --git a/Lib/tkinter/test/test_tkinter/test_text.py b/Lib/tkinter/test/test_tkinter/test_text.py --- a/Lib/tkinter/test/test_tkinter/test_text.py +++ b/Lib/tkinter/test/test_tkinter/test_text.py @@ -16,13 +16,12 @@ def test_debug(self): text = self.text - wantobjects = self.root.wantobjects() olddebug = text.debug() try: text.debug(0) - self.assertEqual(text.debug(), 0 if wantobjects else '0') + self.assertEqual(text.debug(), 0) text.debug(1) - self.assertEqual(text.debug(), 1 if wantobjects else '1') + self.assertEqual(text.debug(), 1) finally: text.debug(olddebug) self.assertEqual(text.debug(), olddebug) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 11 19:51:48 2014 From: python-checkins at python.org (georg.brandl) Date: Sat, 11 Jan 2014 19:51:48 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_minor_markup_bug=3A_su?= =?utf-8?q?b-toctrees_should_not_have_=3Anumbered=3A?= Message-ID: <3f1qsw0pq5z7Ljk@mail.python.org> http://hg.python.org/cpython/rev/782df7697ed6 changeset: 88412:782df7697ed6 user: Georg Brandl date: Sat Jan 11 19:52:17 2014 +0100 summary: Fix minor markup bug: sub-toctrees should not have :numbered: files: Doc/library/asyncio.rst | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Doc/library/asyncio.rst b/Doc/library/asyncio.rst --- a/Doc/library/asyncio.rst +++ b/Doc/library/asyncio.rst @@ -43,7 +43,6 @@ .. toctree:: :maxdepth: 3 - :numbered: asyncio-eventloop.rst asyncio-task.rst -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 11 20:04:01 2014 From: python-checkins at python.org (georg.brandl) Date: Sat, 11 Jan 2014 20:04:01 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Update_Sphinx_?= =?utf-8?q?toolchain=2E?= Message-ID: <3f1r8102P7z7LjX@mail.python.org> http://hg.python.org/cpython/rev/87bdee4d633a changeset: 88413:87bdee4d633a branch: 3.3 parent: 88410:05e84d3ecd1e user: Georg Brandl date: Sat Jan 11 20:04:19 2014 +0100 summary: Update Sphinx toolchain. files: Doc/Makefile | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/Makefile b/Doc/Makefile --- a/Doc/Makefile +++ b/Doc/Makefile @@ -41,19 +41,19 @@ checkout: @if [ ! -d tools/sphinx ]; then \ echo "Checking out Sphinx..."; \ - svn checkout $(SVNROOT)/external/Sphinx-1.0.7/sphinx tools/sphinx; \ + svn checkout $(SVNROOT)/external/Sphinx-1.2/sphinx tools/sphinx; \ fi @if [ ! -d tools/docutils ]; then \ echo "Checking out Docutils..."; \ - svn checkout $(SVNROOT)/external/docutils-0.6/docutils tools/docutils; \ + svn checkout $(SVNROOT)/external/docutils-0.11/docutils tools/docutils; \ fi @if [ ! -d tools/jinja2 ]; then \ echo "Checking out Jinja..."; \ - svn checkout $(SVNROOT)/external/Jinja-2.3.1/jinja2 tools/jinja2; \ + svn checkout $(SVNROOT)/external/Jinja2-2.7.2/jinja2 tools/jinja2; \ fi @if [ ! -d tools/pygments ]; then \ echo "Checking out Pygments..."; \ - svn checkout $(SVNROOT)/external/Pygments-1.5dev-20120930/pygments tools/pygments; \ + svn checkout $(SVNROOT)/external/Pygments-1.6/pygments tools/pygments; \ fi update: clean checkout -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 11 20:04:02 2014 From: python-checkins at python.org (georg.brandl) Date: Sat, 11 Jan 2014 20:04:02 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E3?= Message-ID: <3f1r821Xjjz7Ljn@mail.python.org> http://hg.python.org/cpython/rev/90cd87f64632 changeset: 88414:90cd87f64632 parent: 88412:782df7697ed6 parent: 88413:87bdee4d633a user: Georg Brandl date: Sat Jan 11 20:04:29 2014 +0100 summary: Merge with 3.3 files: Doc/Makefile | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/Makefile b/Doc/Makefile --- a/Doc/Makefile +++ b/Doc/Makefile @@ -41,19 +41,19 @@ checkout: @if [ ! -d tools/sphinx ]; then \ echo "Checking out Sphinx..."; \ - svn checkout $(SVNROOT)/external/Sphinx-1.0.7/sphinx tools/sphinx; \ + svn checkout $(SVNROOT)/external/Sphinx-1.2/sphinx tools/sphinx; \ fi @if [ ! -d tools/docutils ]; then \ echo "Checking out Docutils..."; \ - svn checkout $(SVNROOT)/external/docutils-0.6/docutils tools/docutils; \ + svn checkout $(SVNROOT)/external/docutils-0.11/docutils tools/docutils; \ fi @if [ ! -d tools/jinja2 ]; then \ echo "Checking out Jinja..."; \ - svn checkout $(SVNROOT)/external/Jinja-2.3.1/jinja2 tools/jinja2; \ + svn checkout $(SVNROOT)/external/Jinja2-2.7.2/jinja2 tools/jinja2; \ fi @if [ ! -d tools/pygments ]; then \ echo "Checking out Pygments..."; \ - svn checkout $(SVNROOT)/external/Pygments-1.5dev-20120930/pygments tools/pygments; \ + svn checkout $(SVNROOT)/external/Pygments-1.6/pygments tools/pygments; \ fi update: clean checkout -- Repository URL: http://hg.python.org/cpython From tjreedy at udel.edu Sat Jan 11 21:11:56 2014 From: tjreedy at udel.edu (Terry Reedy) Date: Sat, 11 Jan 2014 15:11:56 -0500 Subject: [Python-checkins] cpython (3.3): Update Sphinx toolchain. In-Reply-To: <3f1r8102P7z7LjX@mail.python.org> References: <3f1r8102P7z7LjX@mail.python.org> Message-ID: <52D1A58C.4020805@udel.edu> On 1/11/2014 2:04 PM, georg.brandl wrote: > http://hg.python.org/cpython/rev/87bdee4d633a > changeset: 88413:87bdee4d633a > branch: 3.3 > parent: 88410:05e84d3ecd1e > user: Georg Brandl > date: Sat Jan 11 20:04:19 2014 +0100 > summary: > Update Sphinx toolchain. > > files: > Doc/Makefile | 8 ++++---- > 1 files changed, 4 insertions(+), 4 deletions(-) > > > diff --git a/Doc/Makefile b/Doc/Makefile > --- a/Doc/Makefile > +++ b/Doc/Makefile > @@ -41,19 +41,19 @@ > checkout: > @if [ ! -d tools/sphinx ]; then \ > echo "Checking out Sphinx..."; \ > - svn checkout $(SVNROOT)/external/Sphinx-1.0.7/sphinx tools/sphinx; \ > + svn checkout $(SVNROOT)/external/Sphinx-1.2/sphinx tools/sphinx; \ > fi Doc/make.bat needs to be similarly updated. From python-checkins at python.org Sun Jan 12 07:22:32 2014 From: python-checkins at python.org (senthil.kumaran) Date: Sun, 12 Jan 2014 07:22:32 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Adding_test_co?= =?utf-8?q?verage_for_cgi=2EFieldStorage_based_on_the_scenario_mentioned_i?= =?utf-8?q?n?= Message-ID: <3f27Bw5M21z7Ljp@mail.python.org> http://hg.python.org/cpython/rev/2d6e7a5659f0 changeset: 88415:2d6e7a5659f0 branch: 2.7 parent: 88409:7dab4feec126 user: Senthil Kumaran date: Sat Jan 11 22:16:55 2014 -0800 summary: Adding test coverage for cgi.FieldStorage based on the scenario mentioned in issue #19097 files: Lib/test/test_cgi.py | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -5,6 +5,8 @@ import tempfile import unittest +from collections import namedtuple + class HackedSysModule: # The regression test will have real values in sys.argv, which # will completely confuse the test of the cgi module @@ -232,6 +234,14 @@ # as long as the chunksize is 1 << 16. self.assertTrue(f.numcalls > 2) + def test_fieldstorage_invalid(self): + fs = cgi.FieldStorage() + self.assertFalse(fs) + self.assertRaises(TypeError, bool(fs)) + self.assertEqual(list(fs), list(fs.keys())) + fs.list.append(namedtuple('MockFieldStorage', 'name')('fieldvalue')) + self.assertTrue(fs) + def test_fieldstorage_multipart(self): #Test basic FieldStorage multipart parsing env = {'REQUEST_METHOD':'POST', 'CONTENT_TYPE':'multipart/form-data; boundary=---------------------------721837373350705526688164684', 'CONTENT_LENGTH':'558'} -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 12 07:22:34 2014 From: python-checkins at python.org (senthil.kumaran) Date: Sun, 12 Jan 2014 07:22:34 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE5MDky?= =?utf-8?q?_-_Raise_a_correct_exception_when_cgi=2EFieldStorage_is_given_a?= =?utf-8?q?n?= Message-ID: <3f27By07XNz7LkH@mail.python.org> http://hg.python.org/cpython/rev/a3e49868cfd0 changeset: 88416:a3e49868cfd0 branch: 3.3 parent: 88413:87bdee4d633a user: Senthil Kumaran date: Sat Jan 11 22:20:16 2014 -0800 summary: Issue #19092 - Raise a correct exception when cgi.FieldStorage is given an invalid file-obj. Also use __bool__ to determine the bool of the FieldStorage object. files: Lib/cgi.py | 14 ++++++++++++-- Lib/test/test_cgi.py | 7 +++++++ Misc/NEWS | 3 +++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Lib/cgi.py b/Lib/cgi.py --- a/Lib/cgi.py +++ b/Lib/cgi.py @@ -32,10 +32,12 @@ # ======= from io import StringIO, BytesIO, TextIOWrapper +from collections import Mapping import sys import os import urllib.parse from email.parser import FeedParser +from email.message import Message from warnings import warn import html import locale @@ -472,18 +474,24 @@ self.qs_on_post = environ['QUERY_STRING'] if 'CONTENT_LENGTH' in environ: headers['content-length'] = environ['CONTENT_LENGTH'] + else: + if not (isinstance(headers, (Mapping, Message))): + raise TypeError("headers must be mapping or an instance of " + "email.message.Message") + self.headers = headers if fp is None: self.fp = sys.stdin.buffer # self.fp.read() must return bytes elif isinstance(fp, TextIOWrapper): self.fp = fp.buffer else: + if not (hasattr(fp, 'read') and hasattr(fp, 'readline')): + raise TypeError("fp must be file pointer") self.fp = fp self.encoding = encoding self.errors = errors - self.headers = headers if not isinstance(outerboundary, bytes): raise TypeError('outerboundary must be bytes, not %s' % type(outerboundary).__name__) @@ -636,7 +644,9 @@ """Dictionary style len(x) support.""" return len(self.keys()) - def __nonzero__(self): + def __bool__(self): + if self.list is None: + raise TypeError("Cannot be converted to bool.") return bool(self.list) def read_urlencoded(self): diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -137,6 +137,13 @@ fs.list.append(namedtuple('MockFieldStorage', 'name')('fieldvalue')) self.assertTrue(fs) + def test_fieldstorage_invalid(self): + self.assertRaises(TypeError, cgi.FieldStorage, "not-a-file-obj", + environ={"REQUEST_METHOD":"PUT"}) + self.assertRaises(TypeError, cgi.FieldStorage, "foo", "bar") + fs = cgi.FieldStorage(headers={'content-type':'text/plain'}) + self.assertRaises(TypeError, bool, fs) + def test_escape(self): # cgi.escape() is deprecated. with warnings.catch_warnings(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,9 @@ Library ------- +- Issue #19097: Raise the correct Exception when cgi.FieldStorage is given an + Invalid fileobj. + - Issue #20217: Fix build in SCHED_SPORADIC is defined. - Issue #13107: argparse and optparse no longer raises an exception when output -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 12 07:22:35 2014 From: python-checkins at python.org (senthil.kumaran) Date: Sun, 12 Jan 2014 07:22:35 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge_from_3=2E3?= Message-ID: <3f27Bz1nBPz7Lk3@mail.python.org> http://hg.python.org/cpython/rev/1638360eea41 changeset: 88417:1638360eea41 parent: 88414:90cd87f64632 parent: 88416:a3e49868cfd0 user: Senthil Kumaran date: Sat Jan 11 22:22:21 2014 -0800 summary: merge from 3.3 Issue #19092 - Raise a correct exception when cgi.FieldStorage is given an invalid file-obj. Also use __bool__ to determine the bool of the FieldStorage object. files: Lib/cgi.py | 14 ++++++++++++-- Lib/test/test_cgi.py | 7 +++++++ Misc/NEWS | 7 +++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Lib/cgi.py b/Lib/cgi.py --- a/Lib/cgi.py +++ b/Lib/cgi.py @@ -32,10 +32,12 @@ # ======= from io import StringIO, BytesIO, TextIOWrapper +from collections import Mapping import sys import os import urllib.parse from email.parser import FeedParser +from email.message import Message from warnings import warn import html import locale @@ -472,18 +474,24 @@ self.qs_on_post = environ['QUERY_STRING'] if 'CONTENT_LENGTH' in environ: headers['content-length'] = environ['CONTENT_LENGTH'] + else: + if not (isinstance(headers, (Mapping, Message))): + raise TypeError("headers must be mapping or an instance of " + "email.message.Message") + self.headers = headers if fp is None: self.fp = sys.stdin.buffer # self.fp.read() must return bytes elif isinstance(fp, TextIOWrapper): self.fp = fp.buffer else: + if not (hasattr(fp, 'read') and hasattr(fp, 'readline')): + raise TypeError("fp must be file pointer") self.fp = fp self.encoding = encoding self.errors = errors - self.headers = headers if not isinstance(outerboundary, bytes): raise TypeError('outerboundary must be bytes, not %s' % type(outerboundary).__name__) @@ -642,7 +650,9 @@ """Dictionary style len(x) support.""" return len(self.keys()) - def __nonzero__(self): + def __bool__(self): + if self.list is None: + raise TypeError("Cannot be converted to bool.") return bool(self.list) def read_urlencoded(self): diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -137,6 +137,13 @@ fs.list.append(namedtuple('MockFieldStorage', 'name')('fieldvalue')) self.assertTrue(fs) + def test_fieldstorage_invalid(self): + self.assertRaises(TypeError, cgi.FieldStorage, "not-a-file-obj", + environ={"REQUEST_METHOD":"PUT"}) + self.assertRaises(TypeError, cgi.FieldStorage, "foo", "bar") + fs = cgi.FieldStorage(headers={'content-type':'text/plain'}) + self.assertRaises(TypeError, bool, fs) + def test_escape(self): # cgi.escape() is deprecated. with warnings.catch_warnings(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,7 +25,14 @@ Library ------- +<<<<<<< local - Issue #20152: Ported Python/import.c over to Argument Clinic. +======= +- Issue #19097: Raise the correct Exception when cgi.FieldStorage is given an + Invalid fileobj. + +- Issue #20217: Fix build in SCHED_SPORADIC is defined. +>>>>>>> other - Issue #13107: argparse and optparse no longer raises an exception when output a help on environment with too small COLUMNS. Based on patch by -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 12 08:10:29 2014 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 Jan 2014 08:10:29 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogRG9jOiB1cGRhdGUg?= =?utf-8?q?Sphinx_toolchain_also_in_make=2Ebat?= Message-ID: <3f28GF2Flzz7Lkd@mail.python.org> http://hg.python.org/cpython/rev/2804f7dcc15d changeset: 88418:2804f7dcc15d branch: 3.3 parent: 88413:87bdee4d633a user: Georg Brandl date: Sun Jan 12 08:09:01 2014 +0100 summary: Doc: update Sphinx toolchain also in make.bat files: Doc/make.bat | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/make.bat b/Doc/make.bat --- a/Doc/make.bat +++ b/Doc/make.bat @@ -34,10 +34,10 @@ goto end :checkout -svn co %SVNROOT%/external/Sphinx-1.0.7/sphinx tools/sphinx -svn co %SVNROOT%/external/docutils-0.6/docutils tools/docutils -svn co %SVNROOT%/external/Jinja-2.3.1/jinja2 tools/jinja2 -svn co %SVNROOT%/external/Pygments-1.5dev-20120930/pygments tools/pygments +svn co %SVNROOT%/external/Sphinx-1.2/sphinx tools/sphinx +svn co %SVNROOT%/external/docutils-0.11/docutils tools/docutils +svn co %SVNROOT%/external/Jinja2-2.7.2/jinja2 tools/jinja2 +svn co %SVNROOT%/external/Pygments-1.6/pygments tools/pygments goto end :update -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 12 08:10:30 2014 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 Jan 2014 08:10:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuMyk6?= =?utf-8?q?_merge_heads?= Message-ID: <3f28GG44l7z7Lkg@mail.python.org> http://hg.python.org/cpython/rev/c057e8f067c5 changeset: 88419:c057e8f067c5 branch: 3.3 parent: 88418:2804f7dcc15d parent: 88416:a3e49868cfd0 user: Georg Brandl date: Sun Jan 12 08:10:39 2014 +0100 summary: merge heads files: Lib/cgi.py | 14 ++++++++++++-- Lib/test/test_cgi.py | 7 +++++++ Misc/NEWS | 3 +++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Lib/cgi.py b/Lib/cgi.py --- a/Lib/cgi.py +++ b/Lib/cgi.py @@ -32,10 +32,12 @@ # ======= from io import StringIO, BytesIO, TextIOWrapper +from collections import Mapping import sys import os import urllib.parse from email.parser import FeedParser +from email.message import Message from warnings import warn import html import locale @@ -472,18 +474,24 @@ self.qs_on_post = environ['QUERY_STRING'] if 'CONTENT_LENGTH' in environ: headers['content-length'] = environ['CONTENT_LENGTH'] + else: + if not (isinstance(headers, (Mapping, Message))): + raise TypeError("headers must be mapping or an instance of " + "email.message.Message") + self.headers = headers if fp is None: self.fp = sys.stdin.buffer # self.fp.read() must return bytes elif isinstance(fp, TextIOWrapper): self.fp = fp.buffer else: + if not (hasattr(fp, 'read') and hasattr(fp, 'readline')): + raise TypeError("fp must be file pointer") self.fp = fp self.encoding = encoding self.errors = errors - self.headers = headers if not isinstance(outerboundary, bytes): raise TypeError('outerboundary must be bytes, not %s' % type(outerboundary).__name__) @@ -636,7 +644,9 @@ """Dictionary style len(x) support.""" return len(self.keys()) - def __nonzero__(self): + def __bool__(self): + if self.list is None: + raise TypeError("Cannot be converted to bool.") return bool(self.list) def read_urlencoded(self): diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py --- a/Lib/test/test_cgi.py +++ b/Lib/test/test_cgi.py @@ -137,6 +137,13 @@ fs.list.append(namedtuple('MockFieldStorage', 'name')('fieldvalue')) self.assertTrue(fs) + def test_fieldstorage_invalid(self): + self.assertRaises(TypeError, cgi.FieldStorage, "not-a-file-obj", + environ={"REQUEST_METHOD":"PUT"}) + self.assertRaises(TypeError, cgi.FieldStorage, "foo", "bar") + fs = cgi.FieldStorage(headers={'content-type':'text/plain'}) + self.assertRaises(TypeError, bool, fs) + def test_escape(self): # cgi.escape() is deprecated. with warnings.catch_warnings(): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,9 @@ Library ------- +- Issue #19097: Raise the correct Exception when cgi.FieldStorage is given an + Invalid fileobj. + - Issue #20217: Fix build in SCHED_SPORADIC is defined. - Issue #13107: argparse and optparse no longer raises an exception when output -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 12 08:10:31 2014 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 Jan 2014 08:10:31 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge_with_3=2E3?= Message-ID: <3f28GH5q63z7Lkd@mail.python.org> http://hg.python.org/cpython/rev/a388bf1cc827 changeset: 88420:a388bf1cc827 parent: 88417:1638360eea41 parent: 88419:c057e8f067c5 user: Georg Brandl date: Sun Jan 12 08:10:52 2014 +0100 summary: merge with 3.3 files: Doc/make.bat | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/make.bat b/Doc/make.bat --- a/Doc/make.bat +++ b/Doc/make.bat @@ -34,10 +34,10 @@ goto end :checkout -svn co %SVNROOT%/external/Sphinx-1.0.7/sphinx tools/sphinx -svn co %SVNROOT%/external/docutils-0.6/docutils tools/docutils -svn co %SVNROOT%/external/Jinja-2.3.1/jinja2 tools/jinja2 -svn co %SVNROOT%/external/Pygments-1.5dev-20120930/pygments tools/pygments +svn co %SVNROOT%/external/Sphinx-1.2/sphinx tools/sphinx +svn co %SVNROOT%/external/docutils-0.11/docutils tools/docutils +svn co %SVNROOT%/external/Jinja2-2.7.2/jinja2 tools/jinja2 +svn co %SVNROOT%/external/Pygments-1.6/pygments tools/pygments goto end :update -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 12 08:21:03 2014 From: python-checkins at python.org (ethan.furman) Date: Sun, 12 Jan 2014 08:21:03 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue19995=3A_issue_deprec?= =?utf-8?q?ation_warning_for_non-integer_values_to_=25c=2C_=25o=2C_=25x=2C?= =?utf-8?b?ICVY?= Message-ID: <3f28VR5Tlvz7Ljj@mail.python.org> http://hg.python.org/cpython/rev/22e55bd5583c changeset: 88421:22e55bd5583c user: Ethan Furman date: Sat Jan 11 23:20:58 2014 -0800 summary: Issue19995: issue deprecation warning for non-integer values to %c, %o, %x, %X files: Lib/test/test_format.py | 5 ++++ Lib/test/test_unicode.py | 20 ++++++++++++++---- Misc/NEWS | 4 +- Objects/unicodeobject.c | 29 ++++++++++++++++++++++++++- 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py --- a/Lib/test/test_format.py +++ b/Lib/test/test_format.py @@ -142,6 +142,7 @@ testformat("%#+027.23X", big, "+0X0001234567890ABCDEF12345") # same, except no 0 flag testformat("%#+27.23X", big, " +0X001234567890ABCDEF12345") + testformat("%x", float(big), "123456_______________", 6) big = 0o12345670123456701234567012345670 # 32 octal digits testformat("%o", big, "12345670123456701234567012345670") testformat("%o", -big, "-12345670123456701234567012345670") @@ -181,6 +182,7 @@ testformat("%034.33o", big, "0012345670123456701234567012345670") # base marker shouldn't change that testformat("%0#34.33o", big, "0o012345670123456701234567012345670") + testformat("%o", float(big), "123456__________________________", 6) # Some small ints, in both Python int and flavors). testformat("%d", 42, "42") testformat("%d", -42, "-42") @@ -191,6 +193,7 @@ testformat("%#x", 1, "0x1") testformat("%#X", 1, "0X1") testformat("%#X", 1, "0X1") + testformat("%#x", 1.0, "0x1") testformat("%#o", 1, "0o1") testformat("%#o", 1, "0o1") testformat("%#o", 0, "0o0") @@ -207,10 +210,12 @@ testformat("%x", -0x42, "-42") testformat("%x", 0x42, "42") testformat("%x", -0x42, "-42") + testformat("%x", float(0x42), "42") testformat("%o", 0o42, "42") testformat("%o", -0o42, "-42") testformat("%o", 0o42, "42") testformat("%o", -0o42, "-42") + testformat("%o", float(0o42), "42") testformat("%r", "\u0378", "'\\u0378'") # non printable testformat("%a", "\u0378", "'\\u0378'") # non printable testformat("%r", "\u0374", "'\u0374'") # printable 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 @@ -1139,6 +1139,13 @@ self.value = float(value) def __int__(self): return int(self.value) + def check_depr(modifier, value): + with support.check_warnings( + ("", DeprecationWarning), + quiet=False, + ): + warnings.simplefilter('always') + modifier % value pi = PsuedoFloat(3.1415) letter_m = PsuedoInt(109) self.assertEqual('%x' % 42, '2a') @@ -1149,11 +1156,14 @@ self.assertEqual('%X' % letter_m, '6D') self.assertEqual('%o' % letter_m, '155') self.assertEqual('%c' % letter_m, 'm') - self.assertRaises(TypeError, '%x'.__mod__, pi) - self.assertRaises(TypeError, '%x'.__mod__, 3.14) - self.assertRaises(TypeError, '%X'.__mod__, 2.11) - self.assertRaises(TypeError, '%o'.__mod__, 1.79) - self.assertRaises(TypeError, '%c'.__mod__, pi) + for mod, value in ( + ('%x', pi), + ('%x', 3.14), + ('%X', 2.11), + ('%o', 1.79), + ('%c', pi), + ): + check_depr(mod, value) def test_formatting_with_enum(self): # issue18780 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -117,8 +117,8 @@ - Issue #19969: PyBytes_FromFormatV() now raises an OverflowError if "%c" argument is not in range [0; 255]. -- Issue #19995: %c, %o, %x, and %X now raise TypeError on non-integer input; - reworded docs to clarify that an integer type should define both __int__ +- Issue #19995: %c, %o, %x, and %X now issue a DeprecationWarning on non-integer + input; reworded docs to clarify that an integer type should define both __int__ and __index__. - Issue #19787: PyThread_set_key_value() now always set the value. In Python diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14004,11 +14004,24 @@ if (!PyNumber_Check(v)) goto wrongtype; + /* make sure number is a type of integer */ + /* if not, issue depracation warning for now */ if (!PyLong_Check(v)) { if (type == 'o' || type == 'x' || type == 'X') { iobj = PyNumber_Index(v); if (iobj == NULL) { - return -1; + PyErr_Clear(); + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "automatic int conversions have been deprecated", + 1)) { + return -1; + } + iobj = PyNumber_Long(v); + if (iobj == NULL ) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + goto wrongtype; + return -1; + } } } else { @@ -14090,10 +14103,22 @@ PyObject *iobj; long x; /* make sure number is a type of integer */ + /* if not, issue depracation warning for now */ if (!PyLong_Check(v)) { iobj = PyNumber_Index(v); if (iobj == NULL) { - goto onError; + PyErr_Clear(); + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "automatic int conversions have been deprecated", + 1)) { + return -1; + } + iobj = PyNumber_Long(v); + if (iobj == NULL ) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + goto onError; + return -1; + } } v = iobj; Py_DECREF(iobj); -- Repository URL: http://hg.python.org/cpython From ncoghlan at gmail.com Sun Jan 12 08:53:20 2014 From: ncoghlan at gmail.com (Nick Coghlan) Date: Sun, 12 Jan 2014 17:53:20 +1000 Subject: [Python-checkins] cpython (3.3): Issue #19092 - Raise a correct exception when cgi.FieldStorage is given an In-Reply-To: <3f27By07XNz7LkH@mail.python.org> References: <3f27By07XNz7LkH@mail.python.org> Message-ID: On 12 January 2014 16:22, senthil.kumaran wrote: > summary: > Issue #19092 - Raise a correct exception when cgi.FieldStorage is given an > invalid file-obj. Also use __bool__ to determine the bool of the FieldStorage > object. > Library > ------- > > +- Issue #19097: Raise the correct Exception when cgi.FieldStorage is given an > + Invalid fileobj. You may want to tweak the tracker so the comment ends up on the appropriate issue (#19092 is something else entirely) Cheers, Nick. -- Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia From solipsis at pitrou.net Sun Jan 12 09:46:40 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 12 Jan 2014 09:46:40 +0100 Subject: [Python-checkins] Daily reference leaks (90cd87f64632): sum=11 Message-ID: results for 90cd87f64632 on branch "default" -------------------------------------------- test_asyncio leaked [4, 0, 0] memory blocks, sum=4 test_audioop leaked [1, 1, 1] references, sum=3 test_site leaked [0, 0, 2] references, sum=2 test_site leaked [0, 0, 2] memory blocks, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogqBY8yW', '-x'] From python-checkins at python.org Sun Jan 12 11:03:03 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 12 Jan 2014 11:03:03 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fixed_incorrect_merge_in_1?= =?utf-8?q?638360eea41=2E?= Message-ID: <3f2D5M3ly9z7LjQ@mail.python.org> http://hg.python.org/cpython/rev/0a17b76ec4e4 changeset: 88422:0a17b76ec4e4 user: Serhiy Storchaka date: Sun Jan 12 12:01:13 2014 +0200 summary: Fixed incorrect merge in 1638360eea41. files: Misc/NEWS | 6 +----- 1 files changed, 1 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,14 +25,10 @@ Library ------- -<<<<<<< local -- Issue #20152: Ported Python/import.c over to Argument Clinic. -======= - Issue #19097: Raise the correct Exception when cgi.FieldStorage is given an Invalid fileobj. -- Issue #20217: Fix build in SCHED_SPORADIC is defined. ->>>>>>> other +- Issue #20152: Ported Python/import.c over to Argument Clinic. - Issue #13107: argparse and optparse no longer raises an exception when output a help on environment with too small COLUMNS. Based on patch by -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 12 11:16:30 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 12 Jan 2014 11:16:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMTM4?= =?utf-8?q?=3A_The_wsgiref=2Eapplication=5Furi=28=29_and_wsgiref=2Erequest?= =?utf-8?b?X3VyaSgp?= Message-ID: <3f2DNt6FSrz7Ljk@mail.python.org> http://hg.python.org/cpython/rev/29732b43ccf2 changeset: 88423:29732b43ccf2 branch: 3.3 parent: 88419:c057e8f067c5 user: Serhiy Storchaka date: Sun Jan 12 12:08:11 2014 +0200 summary: Issue #20138: The wsgiref.application_uri() and wsgiref.request_uri() functions now conform to PEP 3333 when handle non-ASCII URLs. files: Lib/test/test_wsgiref.py | 8 ++++++-- Lib/wsgiref/util.py | 4 ++-- Misc/NEWS | 3 +++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_wsgiref.py b/Lib/test/test_wsgiref.py --- a/Lib/test/test_wsgiref.py +++ b/Lib/test/test_wsgiref.py @@ -286,7 +286,7 @@ def testAppURIs(self): self.checkAppURI("http://127.0.0.1/") self.checkAppURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam") - self.checkAppURI("http://127.0.0.1/sp%C3%A4m", SCRIPT_NAME="/sp?m") + self.checkAppURI("http://127.0.0.1/sp%E4m", SCRIPT_NAME="/sp\xe4m") self.checkAppURI("http://spam.example.com:2071/", HTTP_HOST="spam.example.com:2071", SERVER_PORT="2071") self.checkAppURI("http://spam.example.com/", @@ -300,15 +300,19 @@ def testReqURIs(self): self.checkReqURI("http://127.0.0.1/") self.checkReqURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam") - self.checkReqURI("http://127.0.0.1/sp%C3%A4m", SCRIPT_NAME="/sp?m") + self.checkReqURI("http://127.0.0.1/sp%E4m", SCRIPT_NAME="/sp\xe4m") self.checkReqURI("http://127.0.0.1/spammity/spam", SCRIPT_NAME="/spammity", PATH_INFO="/spam") + self.checkReqURI("http://127.0.0.1/spammity/sp%E4m", + SCRIPT_NAME="/spammity", PATH_INFO="/sp\xe4m") self.checkReqURI("http://127.0.0.1/spammity/spam;ham", SCRIPT_NAME="/spammity", PATH_INFO="/spam;ham") self.checkReqURI("http://127.0.0.1/spammity/spam;cookie=1234,5678", SCRIPT_NAME="/spammity", PATH_INFO="/spam;cookie=1234,5678") self.checkReqURI("http://127.0.0.1/spammity/spam?say=ni", SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="say=ni") + self.checkReqURI("http://127.0.0.1/spammity/spam?s%E4y=ni", + SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="s%E4y=ni") self.checkReqURI("http://127.0.0.1/spammity/spam", 0, SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="say=ni") diff --git a/Lib/wsgiref/util.py b/Lib/wsgiref/util.py --- a/Lib/wsgiref/util.py +++ b/Lib/wsgiref/util.py @@ -57,14 +57,14 @@ if environ['SERVER_PORT'] != '80': url += ':' + environ['SERVER_PORT'] - url += quote(environ.get('SCRIPT_NAME') or '/') + url += quote(environ.get('SCRIPT_NAME') or '/', encoding='latin1') return url def request_uri(environ, include_query=True): """Return the full request URI, optionally including the query string""" url = application_uri(environ) from urllib.parse import quote - path_info = quote(environ.get('PATH_INFO',''),safe='/;=,') + path_info = quote(environ.get('PATH_INFO',''), safe='/;=,', encoding='latin1') if not environ.get('SCRIPT_NAME'): url += path_info[1:] else: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,9 @@ Library ------- +- Issue #20138: The wsgiref.application_uri() and wsgiref.request_uri() + functions now conform to PEP 3333 when handle non-ASCII URLs. + - Issue #19097: Raise the correct Exception when cgi.FieldStorage is given an Invalid fileobj. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 12 11:16:32 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 12 Jan 2014 11:16:32 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320138=3A_The_wsgiref=2Eapplication=5Furi=28=29_?= =?utf-8?q?and_wsgiref=2Erequest=5Furi=28=29?= Message-ID: <3f2DNw0gbrz7Ljp@mail.python.org> http://hg.python.org/cpython/rev/73781fe1daa2 changeset: 88424:73781fe1daa2 parent: 88422:0a17b76ec4e4 parent: 88423:29732b43ccf2 user: Serhiy Storchaka date: Sun Jan 12 12:09:38 2014 +0200 summary: Issue #20138: The wsgiref.application_uri() and wsgiref.request_uri() functions now conform to PEP 3333 when handle non-ASCII URLs. files: Lib/test/test_wsgiref.py | 8 ++++++-- Lib/wsgiref/util.py | 4 ++-- Misc/NEWS | 3 +++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_wsgiref.py b/Lib/test/test_wsgiref.py --- a/Lib/test/test_wsgiref.py +++ b/Lib/test/test_wsgiref.py @@ -286,7 +286,7 @@ def testAppURIs(self): self.checkAppURI("http://127.0.0.1/") self.checkAppURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam") - self.checkAppURI("http://127.0.0.1/sp%C3%A4m", SCRIPT_NAME="/sp?m") + self.checkAppURI("http://127.0.0.1/sp%E4m", SCRIPT_NAME="/sp\xe4m") self.checkAppURI("http://spam.example.com:2071/", HTTP_HOST="spam.example.com:2071", SERVER_PORT="2071") self.checkAppURI("http://spam.example.com/", @@ -300,15 +300,19 @@ def testReqURIs(self): self.checkReqURI("http://127.0.0.1/") self.checkReqURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam") - self.checkReqURI("http://127.0.0.1/sp%C3%A4m", SCRIPT_NAME="/sp?m") + self.checkReqURI("http://127.0.0.1/sp%E4m", SCRIPT_NAME="/sp\xe4m") self.checkReqURI("http://127.0.0.1/spammity/spam", SCRIPT_NAME="/spammity", PATH_INFO="/spam") + self.checkReqURI("http://127.0.0.1/spammity/sp%E4m", + SCRIPT_NAME="/spammity", PATH_INFO="/sp\xe4m") self.checkReqURI("http://127.0.0.1/spammity/spam;ham", SCRIPT_NAME="/spammity", PATH_INFO="/spam;ham") self.checkReqURI("http://127.0.0.1/spammity/spam;cookie=1234,5678", SCRIPT_NAME="/spammity", PATH_INFO="/spam;cookie=1234,5678") self.checkReqURI("http://127.0.0.1/spammity/spam?say=ni", SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="say=ni") + self.checkReqURI("http://127.0.0.1/spammity/spam?s%E4y=ni", + SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="s%E4y=ni") self.checkReqURI("http://127.0.0.1/spammity/spam", 0, SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="say=ni") diff --git a/Lib/wsgiref/util.py b/Lib/wsgiref/util.py --- a/Lib/wsgiref/util.py +++ b/Lib/wsgiref/util.py @@ -57,14 +57,14 @@ if environ['SERVER_PORT'] != '80': url += ':' + environ['SERVER_PORT'] - url += quote(environ.get('SCRIPT_NAME') or '/') + url += quote(environ.get('SCRIPT_NAME') or '/', encoding='latin1') return url def request_uri(environ, include_query=True): """Return the full request URI, optionally including the query string""" url = application_uri(environ) from urllib.parse import quote - path_info = quote(environ.get('PATH_INFO',''),safe='/;=,') + path_info = quote(environ.get('PATH_INFO',''), safe='/;=,', encoding='latin1') if not environ.get('SCRIPT_NAME'): url += path_info[1:] else: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,9 @@ Library ------- +- Issue #20138: The wsgiref.application_uri() and wsgiref.request_uri() + functions now conform to PEP 3333 when handle non-ASCII URLs. + - Issue #19097: Raise the correct Exception when cgi.FieldStorage is given an Invalid fileobj. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 12 11:16:33 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 12 Jan 2014 11:16:33 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIwMTM4?= =?utf-8?q?=3A_Backport_tests_for_handling_non-ASCII_URLs_in_the?= Message-ID: <3f2DNx27fsz7Lk1@mail.python.org> http://hg.python.org/cpython/rev/40fb60df4755 changeset: 88425:40fb60df4755 branch: 2.7 parent: 88415:2d6e7a5659f0 user: Serhiy Storchaka date: Sun Jan 12 12:11:47 2014 +0200 summary: Issue #20138: Backport tests for handling non-ASCII URLs in the wsgiref.application_uri() and wsgiref.request_uri() functions. files: Lib/test/test_wsgiref.py | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_wsgiref.py b/Lib/test/test_wsgiref.py --- a/Lib/test/test_wsgiref.py +++ b/Lib/test/test_wsgiref.py @@ -245,6 +245,7 @@ def testAppURIs(self): self.checkAppURI("http://127.0.0.1/") self.checkAppURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam") + self.checkAppURI("http://127.0.0.1/sp%E4m", SCRIPT_NAME="/sp\xe4m") self.checkAppURI("http://spam.example.com:2071/", HTTP_HOST="spam.example.com:2071", SERVER_PORT="2071") self.checkAppURI("http://spam.example.com/", @@ -258,14 +259,19 @@ def testReqURIs(self): self.checkReqURI("http://127.0.0.1/") self.checkReqURI("http://127.0.0.1/spam", SCRIPT_NAME="/spam") + self.checkReqURI("http://127.0.0.1/sp%E4m", SCRIPT_NAME="/sp\xe4m") self.checkReqURI("http://127.0.0.1/spammity/spam", SCRIPT_NAME="/spammity", PATH_INFO="/spam") + self.checkReqURI("http://127.0.0.1/spammity/sp%E4m", + SCRIPT_NAME="/spammity", PATH_INFO="/sp\xe4m") self.checkReqURI("http://127.0.0.1/spammity/spam;ham", SCRIPT_NAME="/spammity", PATH_INFO="/spam;ham") self.checkReqURI("http://127.0.0.1/spammity/spam;cookie=1234,5678", SCRIPT_NAME="/spammity", PATH_INFO="/spam;cookie=1234,5678") self.checkReqURI("http://127.0.0.1/spammity/spam?say=ni", SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="say=ni") + self.checkReqURI("http://127.0.0.1/spammity/spam?s%E4y=ni", + SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="s%E4y=ni") self.checkReqURI("http://127.0.0.1/spammity/spam", 0, SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="say=ni") -- Repository URL: http://hg.python.org/cpython From senthil at uthcode.com Sun Jan 12 16:00:56 2014 From: senthil at uthcode.com (Senthil Kumaran) Date: Sun, 12 Jan 2014 07:00:56 -0800 Subject: [Python-checkins] cpython (3.3): Issue #19092 - Raise a correct exception when cgi.FieldStorage is given an In-Reply-To: References: <3f27By07XNz7LkH@mail.python.org> Message-ID: On Sat, Jan 11, 2014 at 11:53 PM, Nick Coghlan wrote: > You may want to tweak the tracker so the comment ends up on the > appropriate issue (#19092 is something else entirely) > Yes. This was supposed to be #19097. My bad. -------------- next part -------------- An HTML attachment was scrubbed... URL: From python-checkins at python.org Sun Jan 12 17:42:30 2014 From: python-checkins at python.org (ethan.furman) Date: Sun, 12 Jan 2014 17:42:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue19995=3A_fixed_typo?= =?utf-8?q?=3B_switched_from_test=2Esupport=2Echeck=5Fwarnings_to_assertWa?= =?utf-8?q?rns?= Message-ID: <3f2NyG6NCxz7LlL@mail.python.org> http://hg.python.org/cpython/rev/cc8b21988efb changeset: 88426:cc8b21988efb parent: 88424:73781fe1daa2 user: Ethan Furman date: Sun Jan 12 08:42:35 2014 -0800 summary: Issue19995: fixed typo; switched from test.support.check_warnings to assertWarns files: Lib/test/test_unicode.py | 20 +++++--------------- Objects/unicodeobject.c | 4 ++-- 2 files changed, 7 insertions(+), 17 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 @@ -1139,13 +1139,6 @@ self.value = float(value) def __int__(self): return int(self.value) - def check_depr(modifier, value): - with support.check_warnings( - ("", DeprecationWarning), - quiet=False, - ): - warnings.simplefilter('always') - modifier % value pi = PsuedoFloat(3.1415) letter_m = PsuedoInt(109) self.assertEqual('%x' % 42, '2a') @@ -1156,14 +1149,11 @@ self.assertEqual('%X' % letter_m, '6D') self.assertEqual('%o' % letter_m, '155') self.assertEqual('%c' % letter_m, 'm') - for mod, value in ( - ('%x', pi), - ('%x', 3.14), - ('%X', 2.11), - ('%o', 1.79), - ('%c', pi), - ): - check_depr(mod, value) + self.assertWarns(DeprecationWarning, '%x'.__mod__, pi), + self.assertWarns(DeprecationWarning, '%x'.__mod__, 3.14), + self.assertWarns(DeprecationWarning, '%X'.__mod__, 2.11), + self.assertWarns(DeprecationWarning, '%o'.__mod__, 1.79), + self.assertWarns(DeprecationWarning, '%c'.__mod__, pi), def test_formatting_with_enum(self): # issue18780 diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14005,7 +14005,7 @@ goto wrongtype; /* make sure number is a type of integer */ - /* if not, issue depracation warning for now */ + /* if not, issue deprecation warning for now */ if (!PyLong_Check(v)) { if (type == 'o' || type == 'x' || type == 'X') { iobj = PyNumber_Index(v); @@ -14103,7 +14103,7 @@ PyObject *iobj; long x; /* make sure number is a type of integer */ - /* if not, issue depracation warning for now */ + /* if not, issue deprecation warning for now */ if (!PyLong_Check(v)) { iobj = PyNumber_Index(v); if (iobj == NULL) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 12 17:49:49 2014 From: python-checkins at python.org (larry.hastings) Date: Sun, 12 Jan 2014 17:49:49 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320196=3A_Fixed_a_?= =?utf-8?q?bug_where_Argument_Clinic_did_not_generate_correct?= Message-ID: <3f2P6j6j0qz7Lkh@mail.python.org> http://hg.python.org/cpython/rev/250b481a0d28 changeset: 88427:250b481a0d28 user: Larry Hastings date: Sun Jan 12 08:49:30 2014 -0800 summary: Issue #20196: Fixed a bug where Argument Clinic did not generate correct parsing code for functions with positional-only parameters where all arguments are optional. files: Misc/NEWS | 4 ++++ Tools/clinic/clinic.py | 6 ++++++ 2 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -72,6 +72,10 @@ Tools/Demos ----------- +- Issue #20196: Fixed a bug where Argument Clinic did not generate correct + parsing code for functions with positional-only parameters where all arguments + are optional. + - Issue #18960: 2to3 and the findnocoding.py script now ignore the source encoding declaration on the second line if the first line contains anything except a comment. diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -591,6 +591,12 @@ count_min = min(count_min, count) count_max = max(count_max, count) + if count == 0: + add(""" case 0: + break; +""") + continue + group_ids = {p.group for p in subset} # eliminate duplicates d = {} d['count'] = count -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 12 20:10:17 2014 From: python-checkins at python.org (larry.hastings) Date: Sun, 12 Jan 2014 20:10:17 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320214=3A_Fixed_a_?= =?utf-8?q?number_of_small_issues_and_documentation_errors_in?= Message-ID: <3f2SDn0Wy8z7Lk1@mail.python.org> http://hg.python.org/cpython/rev/3eee3967d03f changeset: 88428:3eee3967d03f user: Larry Hastings date: Sun Jan 12 11:09:57 2014 -0800 summary: Issue #20214: Fixed a number of small issues and documentation errors in Argument Clinic (see issue for details). files: Doc/howto/clinic.rst | 140 ++++++++++++++++++++++++---- Misc/NEWS | 3 + Modules/zlibmodule.c | 12 +- Tools/clinic/clinic.py | 138 +++++++++++++++++++++------- 4 files changed, 233 insertions(+), 60 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -109,6 +109,13 @@ support all of these scenarios. But these are advanced topics--let's do something simpler for your first function. + Also, if the function has multiple calls to :c:func:`PyArg_ParseTuple` + or :c:func:`PyArg_ParseTupleAndKeywords` where it supports different + types for the same argument, or if the function uses something besides + PyArg_Parse functions to parse its arguments, it probably + isn't suitable for conversion to Argument Clinic. Argument Clinic + doesn't support generic functions or polymorphic parameters. + 3. Add the following boilerplate above the function, creating our block:: /*[clinic input] @@ -170,6 +177,11 @@ Write a pickled representation of obj to the open file. [clinic start generated code]*/ + The name of the class and module should be the same as the one + seen by Python. Check the name defined in the :c:type:`PyModuleDef` + or :c:type:`PyTypeObject` as appropriate. + + 8. Declare each of the parameters to the function. Each parameter should get its own line. All the parameter lines should be @@ -455,6 +467,28 @@ Advanced Topics =============== +Now that you've had some experience working with Argument Clinic, it's time +for some advanced topics. + + +Symbolic default values +----------------------- + +The default value you provide for a parameter can't be any arbitrary +expression. Currently the following are explicitly supported: + +* Numeric constants (integer and float) +* String constants +* ``True``, ``False``, and ``None`` +* Simple symbolic constants like ``sys.maxsize``, which must + start with the name of the module + +In case you're curious, this is implemented in ``from_builtin()`` +in ``Lib/inspect.py``. + +(In the future, this may need to get even more elaborate, +to allow full expressions like ``CONSTANT - 1``.) + Renaming the C functions generated by Argument Clinic ----------------------------------------------------- @@ -479,6 +513,29 @@ and the impl function would now be named ``pickler_dumper_impl()``. +The NULL default value +---------------------- + +For string and object parameters, you can set them to ``None`` to indicate +that there is no default. However, that means the C variable will be +initialized to ``Py_None``. For convenience's sakes, there's a special +value called ``NULL`` for just this case: from Python's perspective it +behaves like a default value of ``None``, but the C variable is initialized +with ``NULL``. + + +Converting functions using PyArg_UnpackTuple +-------------------------------------------- + +To convert a function parsing its arguments with :c:func:`PyArg_UnpackTuple`, +simply write out all the arguments, specifying each as an ``object``. You +may specify the ``type`` argument to cast the type as appropriate. All +arguments should be marked positional-only (add a ``/`` on a line by itself +after the last argument). + +Currently the generated code will use :c:func:`PyArg_ParseTuple`, but this +will change soon. + Optional Groups --------------- @@ -570,8 +627,8 @@ to achieve your first port to Argument Clinic, the walkthrough above tells you to use "legacy converters". "Legacy converters" are a convenience, designed explicitly to make porting existing code to Argument Clinic -easier. And to be clear, their use is entirely acceptable when porting -code for Python 3.4. +easier. And to be clear, their use is acceptable when porting code for +Python 3.4. However, in the long term we probably want all our blocks to use Argument Clinic's real syntax for converters. Why? A couple @@ -585,8 +642,8 @@ restricted to what :c:func:`PyArg_ParseTuple` supports; this flexibility won't be available to parameters using legacy converters. -Therefore, if you don't mind a little extra effort, you should consider -using normal converters instead of legacy converters. +Therefore, if you don't mind a little extra effort, please use the normal +converters instead of legacy converters. In a nutshell, the syntax for Argument Clinic (non-legacy) converters looks like a Python function call. However, if there are no explicit @@ -597,12 +654,19 @@ All arguments to Argument Clinic converters are keyword-only. All Argument Clinic converters accept the following arguments: -``doc_default`` - If the parameter takes a default value, normally this value is also - provided in the ``inspect.Signature`` metadata, and displayed in the - docstring. ``doc_default`` lets you override the value used in these - two places: pass in a string representing the Python value you wish - to use in these two contexts. +``py_default`` + The default value for this parameter when defined in Python. + Specifically, the value that will be used in the ``inspect.Signature`` + string. + If a default value is specified for the parameter, defaults to + ``repr(default)``, else defaults to ``None``. + Specified as a string. + +``c_default`` + The default value for this parameter when defined in C. + Specifically, this will be the initializer for the variable declared + in the "parse function". + Specified as a string. ``required`` If a parameter takes a default value, Argument Clinic infers that the @@ -612,6 +676,9 @@ Clinic that this parameter is not optional, even if it has a default value. + (The need for ``required`` may be obviated by ``c_default``, which is + newer but arguably a better solution.) + ``annotation`` The annotation value for this parameter. Not currently supported, because PEP 8 mandates that the Python library may not use @@ -634,10 +701,11 @@ ``'et'`` ``str(encoding='name_of_encoding', types='bytes bytearray str')`` ``'f'`` ``float`` ``'h'`` ``short`` -``'H'`` ``unsigned_short`` +``'H'`` ``unsigned_short(bitwise=True)`` ``'i'`` ``int`` -``'I'`` ``unsigned_int`` -``'K'`` ``unsigned_PY_LONG_LONG`` +``'I'`` ``unsigned_int(bitwise=True)`` +``'k'`` ``unsigned_long(bitwise=True)`` +``'K'`` ``unsigned_PY_LONG_LONG(bitwise=True)`` ``'L'`` ``PY_LONG_LONG`` ``'n'`` ``Py_ssize_t`` ``'O!'`` ``object(subclass_of='&PySomething_Type')`` @@ -681,6 +749,14 @@ it accepts, along with the default value for each parameter. Just run ``Tools/clinic/clinic.py --converters`` to see the full list. +Py_buffer +--------- + +When using the ``Py_buffer`` converter +(or the ``'s*'``, ``'w*'``, ``'*y'``, or ``'z*'`` legacy converters) +note that the code Argument Clinic generates for you will automatically +call :c:func:`PyBuffer_Release` on the buffer for you. + Advanced converters ------------------- @@ -745,15 +821,26 @@ Currently Argument Clinic supports only a few return converters:: + bool int + unsigned int long + unsigned int + size_t Py_ssize_t + float + double DecodeFSDefault None of these take parameters. For the first three, return -1 to indicate error. For ``DecodeFSDefault``, the return type is ``char *``; return a NULL pointer to indicate an error. +(There's also an experimental ``NoneType`` converter, which lets you +return ``Py_None`` on success or ``NULL`` on failure, without having +to increment the reference count on ``Py_None``. I'm not sure it adds +enough clarity to be worth using.) + To see all the return converters Argument Clinic supports, along with their parameters (if any), just run ``Tools/clinic/clinic.py --converters`` for the full list. @@ -873,13 +960,6 @@ The Python default value for this parameter, as a Python value. Or the magic value ``unspecified`` if there is no default. -``doc_default`` - ``default`` as it should appear in the documentation, - as a string. - Or ``None`` if there is no default. - This string, when run through ``eval()``, should produce - a Python value. - ``py_default`` ``default`` as it should appear in Python code, as a string. @@ -951,6 +1031,26 @@ specifically the implementation of ``CReturnConverter`` and all its subclasses. +METH_O and METH_NOARGS +---------------------------------------------- + +To convert a function using ``METH_O``, make sure the function's +single argument is using the ``object`` converter, and mark the +arguments as positional-only:: + + /*[clinic input] + meth_o_sample + + argument: object + / + [clinic start generated code]*/ + + +To convert a function using ``METH_NOARGS``, just don't specify +any arguments. + +You can still use a self converter, a return converter, and specify +a ``type`` argument to the object converter for ``METH_O``. Using Argument Clinic in Python files ------------------------------------- diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -72,6 +72,9 @@ Tools/Demos ----------- +- Issue #20214: Fixed a number of small issues and documentation errors in + Argument Clinic (see issue for details). + - Issue #20196: Fixed a bug where Argument Clinic did not generate correct parsing code for functions with positional-only parameters where all arguments are optional. diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -198,7 +198,7 @@ zlib_compress(PyModuleDef *module, PyObject *args) { PyObject *return_value = NULL; - Py_buffer bytes = {NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL}; + Py_buffer bytes = {NULL, NULL}; int group_right_1 = 0; int level = 0; @@ -219,7 +219,7 @@ return_value = zlib_compress_impl(module, &bytes, group_right_1, level); /* Cleanup for bytes */ - if (bytes.buf) + if (bytes.obj) PyBuffer_Release(&bytes); return return_value; @@ -227,7 +227,7 @@ static PyObject * zlib_compress_impl(PyModuleDef *module, Py_buffer *bytes, int group_right_1, int level) -/*[clinic end generated code: checksum=9f055a396620bc1a8a13d74c3496249528b32b0d]*/ +/*[clinic end generated code: checksum=2c59af563a4595c5ecea4011701f482ae350aa5f]*/ { PyObject *ReturnVal = NULL; Byte *input, *output = NULL; @@ -789,7 +789,7 @@ zlib_Decompress_decompress(PyObject *self, PyObject *args) { PyObject *return_value = NULL; - Py_buffer data = {NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL}; + Py_buffer data = {NULL, NULL}; unsigned int max_length = 0; if (!PyArg_ParseTuple(args, @@ -800,7 +800,7 @@ exit: /* Cleanup for data */ - if (data.buf) + if (data.obj) PyBuffer_Release(&data); return return_value; @@ -808,7 +808,7 @@ static PyObject * zlib_Decompress_decompress_impl(compobject *self, Py_buffer *data, unsigned int max_length) -/*[clinic end generated code: checksum=5b1e4f9f1ef8eca55fff78356f9df0c81232ed3b]*/ +/*[clinic end generated code: checksum=e0058024c4a97b411d2e2197791b89fde175f76f]*/ { int err; unsigned int old_length, length = DEFAULTALLOC; diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -38,6 +38,7 @@ _empty = inspect._empty _void = inspect._void +NoneType = type(None) class Unspecified: def __repr__(self): @@ -678,8 +679,8 @@ c.render(p, data) positional = parameters[-1].kind == inspect.Parameter.POSITIONAL_ONLY - if has_option_groups: - assert positional + if has_option_groups and (not positional): + fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').") # now insert our "self" (or whatever) parameters # (we deliberately don't call render on self converters) @@ -1321,6 +1322,10 @@ # Or the magic value "unspecified" if there is no default. default = unspecified + # If not None, default must be isinstance() of this type. + # (You can also specify a tuple of types.) + default_type = None + # "default" as it should appear in the documentation, as a string. # Or None if there is no default. doc_default = None @@ -1387,12 +1392,21 @@ self.name = name if default is not unspecified: + if self.default_type and not isinstance(default, self.default_type): + if isinstance(self.default_type, type): + types_str = self.default_type.__name__ + else: + types_str = ', '.join((cls.__name__ for cls in self.default_type)) + fail("{}: default value {!r} for field {} is not of type {}".format( + self.__class__.__name__, default, name, types_str)) self.default = default self.py_default = py_default if py_default is not None else py_repr(default) self.doc_default = doc_default if doc_default is not None else self.py_default self.c_default = c_default if c_default is not None else c_repr(default) - elif doc_default is not None: - fail(function.fullname + " argument " + name + " specified a 'doc_default' without having a 'default'") + else: + self.py_default = py_default + self.doc_default = doc_default + self.c_default = c_default if annotation != unspecified: fail("The 'annotation' parameter is not currently permitted.") self.required = required @@ -1538,6 +1552,7 @@ class bool_converter(CConverter): type = 'int' + default_type = bool format_unit = 'p' c_ignored_default = '0' @@ -1547,12 +1562,19 @@ class char_converter(CConverter): type = 'char' + default_type = str format_unit = 'c' c_ignored_default = "'\0'" + def converter_init(self): + if len(self.default) != 1: + fail("char_converter: illegal default value " + repr(self.default)) + + @add_legacy_c_converter('B', bitwise=True) class byte_converter(CConverter): type = 'byte' + default_type = int format_unit = 'b' c_ignored_default = "'\0'" @@ -1562,11 +1584,13 @@ class short_converter(CConverter): type = 'short' + default_type = int format_unit = 'h' c_ignored_default = "0" class unsigned_short_converter(CConverter): type = 'unsigned short' + default_type = int format_unit = 'H' c_ignored_default = "0" @@ -1577,6 +1601,7 @@ @add_legacy_c_converter('C', types='str') class int_converter(CConverter): type = 'int' + default_type = int format_unit = 'i' c_ignored_default = "0" @@ -1588,6 +1613,7 @@ class unsigned_int_converter(CConverter): type = 'unsigned int' + default_type = int format_unit = 'I' c_ignored_default = "0" @@ -1597,11 +1623,13 @@ class long_converter(CConverter): type = 'long' + default_type = int format_unit = 'l' c_ignored_default = "0" class unsigned_long_converter(CConverter): type = 'unsigned long' + default_type = int format_unit = 'k' c_ignored_default = "0" @@ -1611,11 +1639,13 @@ class PY_LONG_LONG_converter(CConverter): type = 'PY_LONG_LONG' + default_type = int format_unit = 'L' c_ignored_default = "0" class unsigned_PY_LONG_LONG_converter(CConverter): type = 'unsigned PY_LONG_LONG' + default_type = int format_unit = 'K' c_ignored_default = "0" @@ -1625,23 +1655,27 @@ class Py_ssize_t_converter(CConverter): type = 'Py_ssize_t' + default_type = int format_unit = 'n' c_ignored_default = "0" class float_converter(CConverter): type = 'float' + default_type = float format_unit = 'f' c_ignored_default = "0.0" class double_converter(CConverter): type = 'double' + default_type = float format_unit = 'd' c_ignored_default = "0.0" class Py_complex_converter(CConverter): type = 'Py_complex' + default_type = complex format_unit = 'D' c_ignored_default = "{0.0, 0.0}" @@ -1650,10 +1684,16 @@ type = 'PyObject *' format_unit = 'O' - def converter_init(self, *, type=None, subclass_of=None): - if subclass_of: + def converter_init(self, *, converter=None, type=None, subclass_of=None): + if converter: + if subclass_of: + fail("object: Cannot pass in both 'converter' and 'subclass_of'") + self.format_unit = 'O&' + self.converter = converter + elif subclass_of: self.format_unit = 'O!' self.subclass_of = subclass_of + if type is not None: self.type = type @@ -1665,6 +1705,7 @@ @add_legacy_c_converter('z#', nullable=True, length=True) class str_converter(CConverter): type = 'const char *' + default_type = (str, Null, NoneType) format_unit = 's' def converter_init(self, *, encoding=None, types="str", @@ -1731,6 +1772,7 @@ class unicode_converter(CConverter): type = 'PyObject *' + default_type = (str, Null, NoneType) format_unit = 'U' @add_legacy_c_converter('u#', length=True) @@ -1738,6 +1780,7 @@ @add_legacy_c_converter('Z#', nullable=True, length=True) class Py_UNICODE_converter(CConverter): type = 'Py_UNICODE *' + default_type = (str, Null, NoneType) format_unit = 'u' def converter_init(self, *, nullable=False, length=False): @@ -1760,11 +1803,11 @@ type = 'Py_buffer' format_unit = 'y*' impl_by_reference = True - c_ignored_default = "{NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL}" + c_ignored_default = "{NULL, NULL}" def converter_init(self, *, types='bytes bytearray buffer', nullable=False): - if self.default != unspecified: - fail("There is no legal default value for Py_buffer ") + if self.default not in (unspecified, None): + fail("The only legal default value for Py_buffer is None.") self.c_default = self.c_ignored_default types = set(types.strip().split()) bytes_type = set(('bytes',)) @@ -1783,7 +1826,7 @@ fail('Py_buffer_converter: illegal combination of arguments (nullable=True)') elif types == (bytes_bytearray_buffer_type): format_unit = 'y*' - elif types == (bytearray_type | rwuffer_type): + elif types == (bytearray_type | rwbuffer_type): format_unit = 'w*' if not format_unit: fail("Py_buffer_converter: illegal combination of arguments") @@ -1792,7 +1835,7 @@ def cleanup(self): name = ensure_legal_c_identifier(self.name) - return "".join(["if (", name, ".buf)\n PyBuffer_Release(&", name, ");\n"]) + return "".join(["if (", name, ".obj)\n PyBuffer_Release(&", name, ");\n"]) class self_converter(CConverter): @@ -1895,34 +1938,59 @@ Py_INCREF(Py_None); '''.strip()) -class int_return_converter(CReturnConverter): +class bool_return_converter(CReturnConverter): type = 'int' def render(self, function, data): self.declare(data) self.err_occurred_if("_return_value == -1", data) + data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n') + +class long_return_converter(CReturnConverter): + type = 'long' + conversion_fn = 'PyLong_FromLong' + cast = '' + + def render(self, function, data): + self.declare(data) + self.err_occurred_if("_return_value == -1", data) data.return_conversion.append( - 'return_value = PyLong_FromLong((long)_return_value);\n') - - -class long_return_converter(CReturnConverter): - type = 'long' + ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n'))) + +class int_return_converter(long_return_converter): + type = 'int' + cast = '(long)' + +class unsigned_long_return_converter(long_return_converter): + type = 'unsigned long' + conversion_fn = 'PyLong_FromUnsignedLong' + +class unsigned_int_return_converter(unsigned_long_return_converter): + type = 'unsigned int' + cast = '(unsigned long)' + +class Py_ssize_t_return_converter(long_return_converter): + type = 'Py_ssize_t' + conversion_fn = 'PyLong_FromSsize_t' + +class size_t_return_converter(long_return_converter): + type = 'size_t' + conversion_fn = 'PyLong_FromSize_t' + + +class double_return_converter(CReturnConverter): + type = 'double' + cast = '' def render(self, function, data): self.declare(data) - self.err_occurred_if("_return_value == -1", data) + self.err_occurred_if("_return_value == -1.0", data) data.return_conversion.append( - 'return_value = PyLong_FromLong(_return_value);\n') - - -class Py_ssize_t_return_converter(CReturnConverter): - type = 'Py_ssize_t' - - def render(self, function, data): - self.declare(data) - self.err_occurred_if("_return_value == -1", data) - data.return_conversion.append( - 'return_value = PyLong_FromSsize_t(_return_value);\n') + 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n') + +class float_return_converter(double_return_converter): + type = 'float' + cast = '(double)' class DecodeFSDefault_return_converter(CReturnConverter): @@ -2341,6 +2409,10 @@ if isinstance(expr, ast.Name) and expr.id == 'NULL': value = NULL elif isinstance(expr, ast.Attribute): + c_default = kwargs.get("c_default") + if not (isinstance(c_default, str) and c_default): + fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.") + a = [] n = expr while isinstance(n, ast.Attribute): @@ -2350,11 +2422,8 @@ fail("Malformed default value (looked like a Python constant)") a.append(n.id) py_default = ".".join(reversed(a)) - value = None - c_default = kwargs.get("c_default") - if not (isinstance(c_default, str) and c_default): - fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.") kwargs["py_default"] = py_default + value = eval(py_default) else: value = ast.literal_eval(expr) else: @@ -2388,7 +2457,8 @@ if isinstance(annotation, ast.Name): return annotation.id, False, {} - assert isinstance(annotation, ast.Call) + if not isinstance(annotation, ast.Call): + fail("Annotations must be either a name, a function call, or a string.") name = annotation.func.id kwargs = {node.arg: ast.literal_eval(node.value) for node in annotation.keywords} -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 12 21:00:06 2014 From: python-checkins at python.org (victor.stinner) Date: Sun, 12 Jan 2014 21:00:06 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_460?= Message-ID: <3f2TLG0rB4z7Ljn@mail.python.org> http://hg.python.org/peps/rev/59126321c399 changeset: 5343:59126321c399 user: Victor Stinner date: Sun Jan 12 20:59:57 2014 +0100 summary: PEP 460 files: pep-0460.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0460.txt b/pep-0460.txt --- a/pep-0460.txt +++ b/pep-0460.txt @@ -2,7 +2,7 @@ Title: Add binary interpolation and formatting Version: $Revision$ Last-Modified: $Date$ -Author: Victor Stinner , Antoine Pitrou +Author: Antoine Pitrou Status: Draft Type: Standards Track Content-Type: text/x-rst -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun Jan 12 22:57:57 2014 From: python-checkins at python.org (larry.hastings) Date: Sun, 12 Jan 2014 22:57:57 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Minor_doc_fix_in_Clinic_ho?= =?utf-8?q?wto=2E?= Message-ID: <3f2WyF18Nyz7Ljn@mail.python.org> http://hg.python.org/cpython/rev/43e109ca9018 changeset: 88429:43e109ca9018 user: Larry Hastings date: Sun Jan 12 13:57:36 2014 -0800 summary: Minor doc fix in Clinic howto. files: Doc/howto/clinic.rst | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -753,9 +753,10 @@ --------- When using the ``Py_buffer`` converter -(or the ``'s*'``, ``'w*'``, ``'*y'``, or ``'z*'`` legacy converters) -note that the code Argument Clinic generates for you will automatically -call :c:func:`PyBuffer_Release` on the buffer for you. +(or the ``'s*'``, ``'w*'``, ``'*y'``, or ``'z*'`` legacy converters), +you *must* not call :c:func:`PyBuffer_Release` on the provided buffer. +Argument Clinic generates code that does it for you (in the parsing function). + Advanced converters -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 12 23:13:17 2014 From: python-checkins at python.org (larry.hastings) Date: Sun, 12 Jan 2014 23:13:17 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320228=3A_Argument?= =?utf-8?q?_Clinic_now_has_special_support_for_class_special?= Message-ID: <3f2XHx5gzDz7LmR@mail.python.org> http://hg.python.org/cpython/rev/bc5f257f5cc1 changeset: 88430:bc5f257f5cc1 user: Larry Hastings date: Sun Jan 12 14:12:59 2014 -0800 summary: Issue #20228: Argument Clinic now has special support for class special methods. files: Misc/NEWS | 3 + Modules/_pickle.c | 10 +- Tools/clinic/clinic.py | 127 ++++++++++++++++++++++++++-- 3 files changed, 121 insertions(+), 19 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -72,6 +72,9 @@ Tools/Demos ----------- +- Issue #20228: Argument Clinic now has special support for class special + methods. + - Issue #20214: Fixed a number of small issues and documentation errors in Argument Clinic (see issue for details). diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -4068,9 +4068,6 @@ "to map the new Python 3 names to the old module names used in Python\n" "2, so that the pickle data stream is readable with Python 2."); -#define _PICKLE_PICKLER___INIT___METHODDEF \ - {"__init__", (PyCFunction)_pickle_Pickler___init__, METH_VARARGS|METH_KEYWORDS, _pickle_Pickler___init____doc__}, - static PyObject * _pickle_Pickler___init___impl(PicklerObject *self, PyObject *file, PyObject *protocol, int fix_imports); @@ -4095,7 +4092,7 @@ static PyObject * _pickle_Pickler___init___impl(PicklerObject *self, PyObject *file, PyObject *protocol, int fix_imports) -/*[clinic end generated code: checksum=2b5ce6452544600478cf9f4b701ab9d9b5efbab9]*/ +/*[clinic end generated code: checksum=defa3d9e9f8b51fb257d4fdfca99db503db0e6df]*/ { _Py_IDENTIFIER(persistent_id); _Py_IDENTIFIER(dispatch_table); @@ -6637,9 +6634,6 @@ "respectively. The *encoding* can be \'bytes\' to read these 8-bit\n" "string instances as bytes objects."); -#define _PICKLE_UNPICKLER___INIT___METHODDEF \ - {"__init__", (PyCFunction)_pickle_Unpickler___init__, METH_VARARGS|METH_KEYWORDS, _pickle_Unpickler___init____doc__}, - static PyObject * _pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file, int fix_imports, const char *encoding, const char *errors); @@ -6665,7 +6659,7 @@ static PyObject * _pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file, int fix_imports, const char *encoding, const char *errors) -/*[clinic end generated code: checksum=9ce6783224e220573d42a94fe1bb7199d6f1c5a6]*/ +/*[clinic end generated code: checksum=26c1d4a06841a8e51d29a0c244ba7f4607ff358a]*/ { _Py_IDENTIFIER(persistent_load); diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -111,13 +111,16 @@ def is_legal_py_identifier(s): return all(is_legal_c_identifier(field) for field in s.split('.')) -# added "module", "self", "cls", and "null" just to be safe -# (clinic will generate variables with these names) +# though it's called c_keywords, really it's a list of parameter names +# that are okay in Python but aren't a good idea in C. so if they're used +# Argument Clinic will add "_value" to the end of the name in C. +# (We added "args", "type", "module", "self", "cls", and "null" +# just to be safe, even though they're not C keywords.) c_keywords = set(""" -asm auto break case char cls const continue default do double +args asm auto break case char cls const continue default do double else enum extern float for goto if inline int long module null register return self short signed sizeof static struct switch -typedef typeof union unsigned void volatile while +type typedef typeof union unsigned void volatile while """.strip().split()) def ensure_legal_c_identifier(s): @@ -392,11 +395,17 @@ @staticmethod def template_base(*args): - flags = '|'.join(f for f in args if f) - return """ + # HACK suppress methoddef define for METHOD_NEW and METHOD_INIT + base = """ PyDoc_STRVAR({c_basename}__doc__, {docstring}); - +""" + + if args[-1] == None: + return base + + flags = '|'.join(f for f in args if f) + return base + """ #define {methoddef_name} \\ {{"{name}", (PyCFunction){c_basename}, {methoddef_flags}, {c_basename}__doc__}}, """.replace('{methoddef_flags}', flags) @@ -650,7 +659,13 @@ name = full_name.rpartition('.')[2] template_dict['name'] = name - c_basename = f.c_basename or full_name.replace(".", "_") + if f.c_basename: + c_basename = f.c_basename + else: + fields = full_name.split(".") + if fields[-1] == '__new__': + fields.pop() + c_basename = "_".join(fields) template_dict['c_basename'] = c_basename methoddef_name = "{}_METHODDEF".format(c_basename.upper()) @@ -1171,8 +1186,81 @@ def __repr__(self): return "" - -DATA, CALLABLE, METHOD, STATIC_METHOD, CLASS_METHOD = range(5) +unsupported_special_methods = set(""" + +__abs__ +__add__ +__and__ +__bytes__ +__call__ +__complex__ +__delitem__ +__divmod__ +__eq__ +__float__ +__floordiv__ +__ge__ +__getattr__ +__getattribute__ +__getitem__ +__gt__ +__hash__ +__iadd__ +__iand__ +__idivmod__ +__ifloordiv__ +__ilshift__ +__imod__ +__imul__ +__index__ +__int__ +__invert__ +__ior__ +__ipow__ +__irshift__ +__isub__ +__iter__ +__itruediv__ +__ixor__ +__le__ +__len__ +__lshift__ +__lt__ +__mod__ +__mul__ +__neg__ +__new__ +__next__ +__or__ +__pos__ +__pow__ +__radd__ +__rand__ +__rdivmod__ +__repr__ +__rfloordiv__ +__rlshift__ +__rmod__ +__rmul__ +__ror__ +__round__ +__rpow__ +__rrshift__ +__rshift__ +__rsub__ +__rtruediv__ +__rxor__ +__setattr__ +__setitem__ +__str__ +__sub__ +__truediv__ +__xor__ + +""".strip().split()) + + +INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = range(6) class Function: """ @@ -1207,6 +1295,8 @@ @property def methoddef_flags(self): + if self.kind in (METHOD_INIT, METHOD_NEW): + return None flags = [] if self.kind == CLASS_METHOD: flags.append('METH_CLASS') @@ -1846,7 +1936,7 @@ type = "PyObject *" def converter_init(self, *, type=None): f = self.function - if f.kind == CALLABLE: + if f.kind in (CALLABLE, METHOD_INIT): if f.cls: self.name = "self" else: @@ -1858,6 +1948,9 @@ elif f.kind == CLASS_METHOD: self.name = "cls" self.type = "PyTypeObject *" + elif f.kind == METHOD_NEW: + self.name = "type" + self.type = "PyTypeObject *" if type: self.type = type @@ -2258,6 +2351,18 @@ function_name = fields.pop() module, cls = self.clinic._module_and_class(fields) + fields = full_name.split('.') + if fields[-1] == '__new__': + if (self.kind != CLASS_METHOD) or (not cls): + fail("__new__ must be a class method!") + self.kind = METHOD_NEW + elif fields[-1] == '__init__': + if (self.kind != CALLABLE) or (not cls): + fail("__init__ must be a normal method, not a class or static method!") + self.kind = METHOD_INIT + elif fields[-1] in unsupported_special_methods: + fail(fields[-1] + " should not be converted to Argument Clinic! (Yet.)") + if not module: fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".") self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 13 01:08:14 2014 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 13 Jan 2014 01:08:14 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE5MDgy?= =?utf-8?q?=3A_Working_SimpleXMLRPCServer_and_xmlrpclib_examples=2C_both_i?= =?utf-8?q?n?= Message-ID: <3f2ZrZ0NQPz7Lkt@mail.python.org> http://hg.python.org/cpython/rev/1730f4a97cbb changeset: 88431:1730f4a97cbb branch: 2.7 parent: 88425:40fb60df4755 user: Senthil Kumaran date: Sun Jan 12 16:04:08 2014 -0800 summary: Issue #19082: Working SimpleXMLRPCServer and xmlrpclib examples, both in modules and documentation. files: Doc/library/simplexmlrpcserver.rst | 32 ++++++++++++++++++ Lib/SimpleXMLRPCServer.py | 1 + Lib/xmlrpclib.py | 15 ++------ Misc/NEWS | 3 + 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/Doc/library/simplexmlrpcserver.rst b/Doc/library/simplexmlrpcserver.rst --- a/Doc/library/simplexmlrpcserver.rst +++ b/Doc/library/simplexmlrpcserver.rst @@ -197,6 +197,38 @@ # Print list of available methods print s.system.listMethods() +The following :class:`SimpleXMLRPCServer` example is included in the module +`Lib/SimpleXMLRPCServer.py`:: + + server = SimpleXMLRPCServer(("localhost", 8000)) + server.register_function(pow) + server.register_function(lambda x,y: x+y, 'add') + server.register_multicall_functions() + server.serve_forever() + +This demo server can be run from the command line as:: + + python -m SimpleXMLRPCServer + +Example client code which talks to the above server is included with +`Lib/xmlrpclib.py`:: + + server = ServerProxy("http://localhost:8000") + print server + multi = MultiCall(server) + multi.pow(2, 9) + multi.add(5, 1) + multi.add(24, 11) + try: + for response in multi(): + print response + except Error, v: + print "ERROR", v + +And the client can be invoked directly using the following command:: + + python -m xmlrpclib + CGIXMLRPCRequestHandler ----------------------- diff --git a/Lib/SimpleXMLRPCServer.py b/Lib/SimpleXMLRPCServer.py --- a/Lib/SimpleXMLRPCServer.py +++ b/Lib/SimpleXMLRPCServer.py @@ -704,4 +704,5 @@ server = SimpleXMLRPCServer(("localhost", 8000)) server.register_function(pow) server.register_function(lambda x,y: x+y, 'add') + server.register_multicall_functions() server.serve_forever() diff --git a/Lib/xmlrpclib.py b/Lib/xmlrpclib.py --- a/Lib/xmlrpclib.py +++ b/Lib/xmlrpclib.py @@ -1617,21 +1617,14 @@ if __name__ == "__main__": - # simple test program (from the XML-RPC specification) - - # server = ServerProxy("http://localhost:8000") # local server - server = ServerProxy("http://time.xmlrpc.com/RPC2") + server = ServerProxy("http://localhost:8000") print server - try: - print server.currentTime.getCurrentTime() - except Error, v: - print "ERROR", v - multi = MultiCall(server) - multi.currentTime.getCurrentTime() - multi.currentTime.getCurrentTime() + multi.pow(2, 9) + multi.add(5, 1) + multi.add(24, 11) try: for response in multi(): print response diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,6 +35,9 @@ Library ------- +- Issue #19082: Working SimpleXMLRPCServer and xmlrpclib examples, both in + modules and documentation. + - Issue #13107: argparse and optparse no longer raises an exception when output a help on environment with too small COLUMNS. Based on patch by Elazar Gershuni. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 13 01:08:15 2014 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 13 Jan 2014 01:08:15 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE5MDgy?= =?utf-8?q?=3A_Working_xmlrpc=2Eserver_and_xmlrpc=2Eclient_examples=2E_Bot?= =?utf-8?q?h_in_modules?= Message-ID: <3f2Zrb3Nplz7Llp@mail.python.org> http://hg.python.org/cpython/rev/72560f9bb2a2 changeset: 88432:72560f9bb2a2 branch: 3.3 parent: 88423:29732b43ccf2 user: Senthil Kumaran date: Sun Jan 12 16:06:58 2014 -0800 summary: Issue #19082: Working xmlrpc.server and xmlrpc.client examples. Both in modules and in documentation. files: Doc/library/xmlrpc.server.rst | 64 +++++++++++++++++++++++ Lib/xmlrpc/client.py | 10 +- Lib/xmlrpc/server.py | 14 +++++ Misc/NEWS | 3 + 4 files changed, 86 insertions(+), 5 deletions(-) diff --git a/Doc/library/xmlrpc.server.rst b/Doc/library/xmlrpc.server.rst --- a/Doc/library/xmlrpc.server.rst +++ b/Doc/library/xmlrpc.server.rst @@ -184,6 +184,70 @@ # Print list of available methods print(s.system.listMethods()) +The following example included in `Lib/xmlrpc/server.py` module shows a server +allowing dotted names and registering a multicall function. + +.. warning:: + + Enabling the *allow_dotted_names* option allows intruders to access your + module's global variables and may allow intruders to execute arbitrary code on + your machine. Only use this example only within a secure, closed network. + +:: + + import datetime + + class ExampleService: + def getData(self): + return '42' + + class currentTime: + @staticmethod + def getCurrentTime(): + return datetime.datetime.now() + + server = SimpleXMLRPCServer(("localhost", 8000)) + server.register_function(pow) + server.register_function(lambda x,y: x+y, 'add') + server.register_instance(ExampleService(), allow_dotted_names=True) + server.register_multicall_functions() + print('Serving XML-RPC on localhost port 8000') + try: + server.serve_forever() + except KeyboardInterrupt: + print("\nKeyboard interrupt received, exiting.") + server.server_close() + sys.exit(0) + +This ExampleService demo can be invoked from the command line:: + + python -m xmlrpc.server + + +The client that interacts with the above server is included in +`Lib/xmlrpc/client.py`:: + + server = ServerProxy("http://localhost:8000") + + try: + print(server.currentTime.getCurrentTime()) + except Error as v: + print("ERROR", v) + + multi = MultiCall(server) + multi.getData() + multi.pow(2,9) + multi.add(1,2) + try: + for response in multi(): + print(response) + except Error as v: + print("ERROR", v) + +This client which interacts with the demo XMLRPC server can be invoked as:: + + python -m xmlrpc.client + CGIXMLRPCRequestHandler ----------------------- diff --git a/Lib/xmlrpc/client.py b/Lib/xmlrpc/client.py --- a/Lib/xmlrpc/client.py +++ b/Lib/xmlrpc/client.py @@ -1460,18 +1460,18 @@ # simple test program (from the XML-RPC specification) - # server = ServerProxy("http://localhost:8000") # local server - server = ServerProxy("http://time.xmlrpc.com/RPC2") + # local server, available from Lib/xmlrpc/server.py + server = ServerProxy("http://localhost:8000") try: print(server.currentTime.getCurrentTime()) except Error as v: print("ERROR", v) - # The server at xmlrpc.com doesn't seem to support multicall anymore. multi = MultiCall(server) - multi.currentTime.getCurrentTime() - multi.currentTime.getCurrentTime() + multi.getData() + multi.pow(2,9) + multi.add(1,2) try: for response in multi(): print(response) diff --git a/Lib/xmlrpc/server.py b/Lib/xmlrpc/server.py --- a/Lib/xmlrpc/server.py +++ b/Lib/xmlrpc/server.py @@ -967,10 +967,24 @@ if __name__ == '__main__': + import datetime + + class ExampleService: + def getData(self): + return '42' + + class currentTime: + @staticmethod + def getCurrentTime(): + return datetime.datetime.now() + server = SimpleXMLRPCServer(("localhost", 8000)) server.register_function(pow) server.register_function(lambda x,y: x+y, 'add') + server.register_instance(ExampleService(), allow_dotted_names=True) + server.register_multicall_functions() print('Serving XML-RPC on localhost port 8000') + print('It is advisable to run this example server within a secure, closed network.') try: server.serve_forever() except KeyboardInterrupt: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,9 @@ Library ------- +- Issue #19082: Working xmlrpc.server and xmlrpc.client examples. Both in + modules and in documentation. Initial patch contributed by Vajrasky Kok. + - Issue #20138: The wsgiref.application_uri() and wsgiref.request_uri() functions now conform to PEP 3333 when handle non-ASCII URLs. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 13 01:08:16 2014 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 13 Jan 2014 01:08:16 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge_from_3=2E3?= Message-ID: <3f2Zrc62Xpz7Lm1@mail.python.org> http://hg.python.org/cpython/rev/bdf6c0135d39 changeset: 88433:bdf6c0135d39 parent: 88430:bc5f257f5cc1 parent: 88432:72560f9bb2a2 user: Senthil Kumaran date: Sun Jan 12 16:07:59 2014 -0800 summary: merge from 3.3 Issue #19082: Working xmlrpc.server and xmlrpc.client examples. Both in modules and in documentation. files: Doc/library/xmlrpc.server.rst | 64 +++++++++++++++++++++++ Lib/xmlrpc/client.py | 10 +- Lib/xmlrpc/server.py | 14 +++++ Misc/NEWS | 3 + 4 files changed, 86 insertions(+), 5 deletions(-) diff --git a/Doc/library/xmlrpc.server.rst b/Doc/library/xmlrpc.server.rst --- a/Doc/library/xmlrpc.server.rst +++ b/Doc/library/xmlrpc.server.rst @@ -184,6 +184,70 @@ # Print list of available methods print(s.system.listMethods()) +The following example included in `Lib/xmlrpc/server.py` module shows a server +allowing dotted names and registering a multicall function. + +.. warning:: + + Enabling the *allow_dotted_names* option allows intruders to access your + module's global variables and may allow intruders to execute arbitrary code on + your machine. Only use this example only within a secure, closed network. + +:: + + import datetime + + class ExampleService: + def getData(self): + return '42' + + class currentTime: + @staticmethod + def getCurrentTime(): + return datetime.datetime.now() + + server = SimpleXMLRPCServer(("localhost", 8000)) + server.register_function(pow) + server.register_function(lambda x,y: x+y, 'add') + server.register_instance(ExampleService(), allow_dotted_names=True) + server.register_multicall_functions() + print('Serving XML-RPC on localhost port 8000') + try: + server.serve_forever() + except KeyboardInterrupt: + print("\nKeyboard interrupt received, exiting.") + server.server_close() + sys.exit(0) + +This ExampleService demo can be invoked from the command line:: + + python -m xmlrpc.server + + +The client that interacts with the above server is included in +`Lib/xmlrpc/client.py`:: + + server = ServerProxy("http://localhost:8000") + + try: + print(server.currentTime.getCurrentTime()) + except Error as v: + print("ERROR", v) + + multi = MultiCall(server) + multi.getData() + multi.pow(2,9) + multi.add(1,2) + try: + for response in multi(): + print(response) + except Error as v: + print("ERROR", v) + +This client which interacts with the demo XMLRPC server can be invoked as:: + + python -m xmlrpc.client + CGIXMLRPCRequestHandler ----------------------- diff --git a/Lib/xmlrpc/client.py b/Lib/xmlrpc/client.py --- a/Lib/xmlrpc/client.py +++ b/Lib/xmlrpc/client.py @@ -1461,18 +1461,18 @@ # simple test program (from the XML-RPC specification) - # server = ServerProxy("http://localhost:8000") # local server - server = ServerProxy("http://time.xmlrpc.com/RPC2") + # local server, available from Lib/xmlrpc/server.py + server = ServerProxy("http://localhost:8000") try: print(server.currentTime.getCurrentTime()) except Error as v: print("ERROR", v) - # The server at xmlrpc.com doesn't seem to support multicall anymore. multi = MultiCall(server) - multi.currentTime.getCurrentTime() - multi.currentTime.getCurrentTime() + multi.getData() + multi.pow(2,9) + multi.add(1,2) try: for response in multi(): print(response) diff --git a/Lib/xmlrpc/server.py b/Lib/xmlrpc/server.py --- a/Lib/xmlrpc/server.py +++ b/Lib/xmlrpc/server.py @@ -960,10 +960,24 @@ if __name__ == '__main__': + import datetime + + class ExampleService: + def getData(self): + return '42' + + class currentTime: + @staticmethod + def getCurrentTime(): + return datetime.datetime.now() + server = SimpleXMLRPCServer(("localhost", 8000)) server.register_function(pow) server.register_function(lambda x,y: x+y, 'add') + server.register_instance(ExampleService(), allow_dotted_names=True) + server.register_multicall_functions() print('Serving XML-RPC on localhost port 8000') + print('It is advisable to run this example server within a secure, closed network.') try: server.serve_forever() except KeyboardInterrupt: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,9 @@ Library ------- +- Issue #19082: Working xmlrpc.server and xmlrpc.client examples. Both in + modules and in documentation. Initial patch contributed by Vajrasky Kok. + - Issue #20138: The wsgiref.application_uri() and wsgiref.request_uri() functions now conform to PEP 3333 when handle non-ASCII URLs. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 13 01:54:28 2014 From: python-checkins at python.org (larry.hastings) Date: Mon, 13 Jan 2014 01:54:28 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Updated_release_schedule_for_?= =?utf-8?q?3=2E4_to_reflect_slippage=2E?= Message-ID: <3f2bsw5xvSz7Ljn@mail.python.org> http://hg.python.org/peps/rev/dac600649bb2 changeset: 5344:dac600649bb2 user: Larry Hastings date: Sun Jan 12 16:54:19 2014 -0800 summary: Updated release schedule for 3.4 to reflect slippage. files: pep-0429.txt | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/pep-0429.txt b/pep-0429.txt --- a/pep-0429.txt +++ b/pep-0429.txt @@ -45,12 +45,18 @@ (Beta 1 is also "feature freeze"--no new features beyond this point.) -The anticipated schedule for future releases: +.. The anticipated schedule for future releases: + +These *were* the release dates for Python 3.4: - 3.4.0 candidate 1: January 19, 2014 - 3.4.0 candidate 2: February 2, 2014 - 3.4.0 final: February 23, 2014 +These release dates are no longer accurate; we plan to add a third beta, +and slip the whole schedule by several weeks. The details have not been +finalized--we'll update this release schedule once they are. + .. don't forget to update final date above as well These are the days we expect to release the software; -- Repository URL: http://hg.python.org/peps From solipsis at pitrou.net Mon Jan 13 09:51:08 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 13 Jan 2014 09:51:08 +0100 Subject: [Python-checkins] Daily reference leaks (bdf6c0135d39): sum=7 Message-ID: results for bdf6c0135d39 on branch "default" -------------------------------------------- test_asyncio leaked [4, 0, 0] memory blocks, sum=4 test_audioop leaked [1, 1, 1] references, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogv7PARZ', '-x'] From python-checkins at python.org Mon Jan 13 13:24:49 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 13 Jan 2014 13:24:49 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fixed_typo=2E?= Message-ID: <3f2vBT2jc1z7LjV@mail.python.org> http://hg.python.org/cpython/rev/de62e7a64346 changeset: 88434:de62e7a64346 branch: 2.7 parent: 88431:1730f4a97cbb user: Serhiy Storchaka date: Mon Jan 13 14:22:45 2014 +0200 summary: Fixed typo. files: Lib/lib-tk/test/test_ttk/test_widgets.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/lib-tk/test/test_ttk/test_widgets.py b/Lib/lib-tk/test/test_ttk/test_widgets.py --- a/Lib/lib-tk/test/test_ttk/test_widgets.py +++ b/Lib/lib-tk/test/test_ttk/test_widgets.py @@ -21,7 +21,7 @@ widget = self.create() self.assertEqual(widget['class'], '') errmsg='attempt to change read-only option' - if get_tk_patchlevel() < (8, 6, 0): # actually this was changen in 8.6b3 + if get_tk_patchlevel() < (8, 6, 0): # actually this was changed in 8.6b3 errmsg='Attempt to change read-only option' self.checkInvalidParam(widget, 'class', 'Foo', errmsg=errmsg) widget2 = self.create(class_='Foo') @@ -577,7 +577,7 @@ widget = self.create() self.assertEqual(str(widget['orient']), 'vertical') errmsg='attempt to change read-only option' - if get_tk_patchlevel() < (8, 6, 0): # actually this was changen in 8.6b3 + if get_tk_patchlevel() < (8, 6, 0): # actually this was changed in 8.6b3 errmsg='Attempt to change read-only option' self.checkInvalidParam(widget, 'orient', 'horizontal', errmsg=errmsg) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 13 13:24:50 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 13 Jan 2014 13:24:50 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Fixed_typo=2E?= Message-ID: <3f2vBV4VGyz7LjV@mail.python.org> http://hg.python.org/cpython/rev/206f134773da changeset: 88435:206f134773da branch: 3.3 parent: 88432:72560f9bb2a2 user: Serhiy Storchaka date: Mon Jan 13 14:23:18 2014 +0200 summary: Fixed typo. files: Lib/tkinter/test/test_ttk/test_widgets.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py --- a/Lib/tkinter/test/test_ttk/test_widgets.py +++ b/Lib/tkinter/test/test_ttk/test_widgets.py @@ -576,7 +576,7 @@ widget = self.create() self.assertEqual(str(widget['orient']), 'vertical') errmsg='attempt to change read-only option' - if get_tk_patchlevel() < (8, 6, 0): # actually this was changen in 8.6b3 + if get_tk_patchlevel() < (8, 6, 0): # actually this was changed in 8.6b3 errmsg='Attempt to change read-only option' self.checkInvalidParam(widget, 'orient', 'horizontal', errmsg=errmsg) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 13 13:24:51 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 13 Jan 2014 13:24:51 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Fixed_typo=2E?= Message-ID: <3f2vBW6HQjz7Ljl@mail.python.org> http://hg.python.org/cpython/rev/a707f3cc0e8e changeset: 88436:a707f3cc0e8e parent: 88433:bdf6c0135d39 parent: 88435:206f134773da user: Serhiy Storchaka date: Mon Jan 13 14:24:11 2014 +0200 summary: Fixed typo. files: Lib/tkinter/test/test_ttk/test_widgets.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/tkinter/test/test_ttk/test_widgets.py b/Lib/tkinter/test/test_ttk/test_widgets.py --- a/Lib/tkinter/test/test_ttk/test_widgets.py +++ b/Lib/tkinter/test/test_ttk/test_widgets.py @@ -576,7 +576,7 @@ widget = self.create() self.assertEqual(str(widget['orient']), 'vertical') errmsg='attempt to change read-only option' - if get_tk_patchlevel() < (8, 6, 0): # actually this was changen in 8.6b3 + if get_tk_patchlevel() < (8, 6, 0): # actually this was changed in 8.6b3 errmsg='Attempt to change read-only option' self.checkInvalidParam(widget, 'orient', 'horizontal', errmsg=errmsg) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 13 15:21:13 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 13 Jan 2014 15:21:13 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_fix_refleak_in_the_error_c?= =?utf-8?q?ase?= Message-ID: <3f2xmn1YY1z7LjR@mail.python.org> http://hg.python.org/cpython/rev/bbfef8dc0e91 changeset: 88437:bbfef8dc0e91 user: Benjamin Peterson date: Mon Jan 13 09:20:53 2014 -0500 summary: fix refleak in the error case files: Modules/audioop.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/audioop.c b/Modules/audioop.c --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -1505,7 +1505,7 @@ Py_ssize_t i; int size, step, valpred, delta, index, sign, vpdiff, diff; - PyObject *rv = NULL, *state, *str; + PyObject *rv = NULL, *state, *str = NULL; int outputbuffer = 0, bufferstep; if (!PyArg_ParseTuple(args, "y*iO:lin2adpcm", @@ -1605,8 +1605,8 @@ bufferstep = !bufferstep; } rv = Py_BuildValue("(O(ii))", str, valpred, index); - Py_DECREF(str); exit: + Py_XDECREF(str); PyBuffer_Release(&view); return rv; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 13 18:10:37 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 13 Jan 2014 18:10:37 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Test_the_open_?= =?utf-8?q?of_non-exitent_tarfile_in_all_modes=2E?= Message-ID: <3f31XF3LC9z7Ljg@mail.python.org> http://hg.python.org/cpython/rev/0ce2396a134b changeset: 88438:0ce2396a134b branch: 3.3 parent: 88435:206f134773da user: Serhiy Storchaka date: Mon Jan 13 19:07:33 2014 +0200 summary: Test the open of non-exitent tarfile in all modes. files: Lib/test/test_tarfile.py | 12 +++++++----- 1 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -232,6 +232,12 @@ finally: tar.close() + def test_non_existent_tarfile(self): + # Test for issue11513: prevent non-existent gzipped tarfiles raising + # multiple exceptions. + with self.assertRaisesRegex(FileNotFoundError, "xxx"): + tarfile.open("xxx", self.mode) + def test_null_tarfile(self): # Test for issue6123: Allow opening empty archives. # This test guarantees that tarfile.open() does not treat an empty @@ -444,11 +450,7 @@ test_fail_comp = None class GzipMiscReadTest(GzipTest, MiscReadTestBase, unittest.TestCase): - def test_non_existent_targz_file(self): - # Test for issue11513: prevent non-existent gzipped tarfiles raising - # multiple exceptions. - with self.assertRaisesRegex(FileNotFoundError, "xxx"): - tarfile.open("xxx", self.mode) + pass class Bz2MiscReadTest(Bz2Test, MiscReadTestBase, unittest.TestCase): def test_no_name_argument(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 13 18:10:39 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 13 Jan 2014 18:10:39 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Test_the_open_of_non-exite?= =?utf-8?q?nt_tarfile_in_all_modes=2E?= Message-ID: <3f31XH5f1nz7LkT@mail.python.org> http://hg.python.org/cpython/rev/3a4b0e4098e6 changeset: 88439:3a4b0e4098e6 parent: 88437:bbfef8dc0e91 user: Serhiy Storchaka date: Mon Jan 13 19:08:00 2014 +0200 summary: Test the open of non-exitent tarfile in all modes. files: Lib/test/test_tarfile.py | 12 +++++++----- 1 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -234,6 +234,12 @@ finally: tar.close() + def test_non_existent_tarfile(self): + # Test for issue11513: prevent non-existent gzipped tarfiles raising + # multiple exceptions. + with self.assertRaisesRegex(FileNotFoundError, "xxx"): + tarfile.open("xxx", self.mode) + def test_null_tarfile(self): # Test for issue6123: Allow opening empty archives. # This test guarantees that tarfile.open() does not treat an empty @@ -446,11 +452,7 @@ test_fail_comp = None class GzipMiscReadTest(GzipTest, MiscReadTestBase, unittest.TestCase): - def test_non_existent_targz_file(self): - # Test for issue11513: prevent non-existent gzipped tarfiles raising - # multiple exceptions. - with self.assertRaisesRegex(FileNotFoundError, "xxx"): - tarfile.open("xxx", self.mode) + pass class Bz2MiscReadTest(Bz2Test, MiscReadTestBase, unittest.TestCase): def test_no_name_argument(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 13 18:10:41 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 13 Jan 2014 18:10:41 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Backported_tes?= =?utf-8?q?t_for_the_open_of_non-existent_tarfile=2E?= Message-ID: <3f31XK15QXz7Ll3@mail.python.org> http://hg.python.org/cpython/rev/4eac22a9ae72 changeset: 88440:4eac22a9ae72 branch: 2.7 parent: 88434:de62e7a64346 user: Serhiy Storchaka date: Mon Jan 13 19:08:51 2014 +0200 summary: Backported test for the open of non-existent tarfile. files: Lib/test/test_tarfile.py | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -181,6 +181,14 @@ self.assertRaises(tarfile.ReadError, tarfile.open, tmpname, self.mode) self.assertRaises(tarfile.ReadError, tarfile.open, tmpname) + def test_non_existent_tarfile(self): + # Test for issue11513: prevent non-existent gzipped tarfiles raising + # multiple exceptions. + exctype = OSError if '|' in self.mode else IOError + with self.assertRaisesRegexp(exctype, "xxx") as ex: + tarfile.open("xxx", self.mode) + self.assertEqual(ex.exception.errno, errno.ENOENT) + def test_ignore_zeros(self): # Test TarFile's ignore_zeros option. if self.mode.endswith(":gz"): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 13 19:31:38 2014 From: python-checkins at python.org (r.david.murray) Date: Mon, 13 Jan 2014 19:31:38 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzIwMjA2LCAjNTgw?= =?utf-8?q?3=3A_more_efficient_algorithm_that_doesn=27t_truncate_output=2E?= Message-ID: <3f33Kk5wKQz7Ljr@mail.python.org> http://hg.python.org/cpython/rev/4c5b1932354b changeset: 88441:4c5b1932354b branch: 3.3 parent: 88438:0ce2396a134b user: R David Murray date: Mon Jan 13 13:19:21 2014 -0500 summary: #20206, #5803: more efficient algorithm that doesn't truncate output. This fixes an edge case (20206) where if the input ended in a character needing encoding but there was no newline on the string, the last byte of the encoded character would be dropped. The fix is to use a more efficient algorithm, provided by Serhiy Storchaka (5803), that does not have the bug. files: Lib/email/quoprimime.py | 134 +++++++---------- Lib/test/test_email/test_email.py | 5 + Misc/NEWS | 4 + 3 files changed, 65 insertions(+), 78 deletions(-) diff --git a/Lib/email/quoprimime.py b/Lib/email/quoprimime.py --- a/Lib/email/quoprimime.py +++ b/Lib/email/quoprimime.py @@ -53,8 +53,9 @@ # space-wise. Remember that headers and bodies have different sets of safe # characters. Initialize both maps with the full expansion, and then override # the safe bytes with the more compact form. -_QUOPRI_HEADER_MAP = dict((c, '=%02X' % c) for c in range(256)) -_QUOPRI_BODY_MAP = _QUOPRI_HEADER_MAP.copy() +_QUOPRI_MAP = ['=%02X' % c for c in range(256)] +_QUOPRI_HEADER_MAP = _QUOPRI_MAP[:] +_QUOPRI_BODY_MAP = _QUOPRI_MAP[:] # Safe header bytes which need no encoding. for c in b'-!*+/' + ascii_letters.encode('ascii') + digits.encode('ascii'): @@ -121,8 +122,7 @@ def quote(c): - return '=%02X' % ord(c) - + return _QUOPRI_MAP[ord(c)] def header_encode(header_bytes, charset='iso-8859-1'): @@ -140,67 +140,15 @@ if not header_bytes: return '' # Iterate over every byte, encoding if necessary. - encoded = [] - for octet in header_bytes: - encoded.append(_QUOPRI_HEADER_MAP[octet]) + encoded = header_bytes.decode('latin1').translate(_QUOPRI_HEADER_MAP) # Now add the RFC chrome to each encoded chunk and glue the chunks # together. - return '=?%s?q?%s?=' % (charset, EMPTYSTRING.join(encoded)) + return '=?%s?q?%s?=' % (charset, encoded) -class _body_accumulator(io.StringIO): - - def __init__(self, maxlinelen, eol, *args, **kw): - super().__init__(*args, **kw) - self.eol = eol - self.maxlinelen = self.room = maxlinelen - - def write_str(self, s): - """Add string s to the accumulated body.""" - self.write(s) - self.room -= len(s) - - def newline(self): - """Write eol, then start new line.""" - self.write_str(self.eol) - self.room = self.maxlinelen - - def write_soft_break(self): - """Write a soft break, then start a new line.""" - self.write_str('=') - self.newline() - - def write_wrapped(self, s, extra_room=0): - """Add a soft line break if needed, then write s.""" - if self.room < len(s) + extra_room: - self.write_soft_break() - self.write_str(s) - - def write_char(self, c, is_last_char): - if not is_last_char: - # Another character follows on this line, so we must leave - # extra room, either for it or a soft break, and whitespace - # need not be quoted. - self.write_wrapped(c, extra_room=1) - elif c not in ' \t': - # For this and remaining cases, no more characters follow, - # so there is no need to reserve extra room (since a hard - # break will immediately follow). - self.write_wrapped(c) - elif self.room >= 3: - # It's a whitespace character at end-of-line, and we have room - # for the three-character quoted encoding. - self.write(quote(c)) - elif self.room == 2: - # There's room for the whitespace character and a soft break. - self.write(c) - self.write_soft_break() - else: - # There's room only for a soft break. The quoted whitespace - # will be the only content on the subsequent line. - self.write_soft_break() - self.write(quote(c)) - +_QUOPRI_BODY_ENCODE_MAP = _QUOPRI_BODY_MAP[:] +for c in b'\r\n': + _QUOPRI_BODY_ENCODE_MAP[c] = chr(c) def body_encode(body, maxlinelen=76, eol=NL): """Encode with quoted-printable, wrapping at maxlinelen characters. @@ -226,26 +174,56 @@ if not body: return body - # The last line may or may not end in eol, but all other lines do. - last_has_eol = (body[-1] in '\r\n') + # quote speacial characters + body = body.translate(_QUOPRI_BODY_ENCODE_MAP) - # This accumulator will make it easier to build the encoded body. - encoded_body = _body_accumulator(maxlinelen, eol) + soft_break = '=' + eol + # leave space for the '=' at the end of a line + maxlinelen1 = maxlinelen - 1 - lines = body.splitlines() - last_line_no = len(lines) - 1 - for line_no, line in enumerate(lines): - last_char_index = len(line) - 1 - for i, c in enumerate(line): - if body_check(ord(c)): - c = quote(c) - encoded_body.write_char(c, i==last_char_index) - # Add an eol if input line had eol. All input lines have eol except - # possibly the last one. - if line_no < last_line_no or last_has_eol: - encoded_body.newline() + encoded_body = [] + append = encoded_body.append - return encoded_body.getvalue() + for line in body.splitlines(): + # break up the line into pieces no longer than maxlinelen - 1 + start = 0 + laststart = len(line) - 1 - maxlinelen + while start <= laststart: + stop = start + maxlinelen1 + # make sure we don't break up an escape sequence + if line[stop - 2] == '=': + append(line[start:stop - 1]) + start = stop - 2 + elif line[stop - 1] == '=': + append(line[start:stop]) + start = stop - 1 + else: + append(line[start:stop] + '=') + start = stop + + # handle rest of line, special case if line ends in whitespace + if line and line[-1] in ' \t': + room = start - laststart + if room >= 3: + # It's a whitespace character at end-of-line, and we have room + # for the three-character quoted encoding. + q = quote(line[-1]) + elif room == 2: + # There's room for the whitespace character and a soft break. + q = line[-1] + soft_break + else: + # There's room only for a soft break. The quoted whitespace + # will be the only content on the subsequent line. + q = soft_break + quote(line[-1]) + append(line[start:-1] + q) + else: + append(line[start:]) + + # add back final newline if present + if body[-1] in CRLF: + append('') + + return eol.join(encoded_body) diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -4216,6 +4216,11 @@ def test_encode_one_line_eol(self): self._test_encode('hello\n', 'hello\r\n', eol='\r\n') + def test_encode_one_line_eol_after_non_ascii(self): + # issue 20206; see changeset 0cf700464177 for why the encode/decode. + self._test_encode('hello\u03c5\n'.encode('utf-8').decode('latin1'), + 'hello=CF=85\r\n', eol='\r\n') + def test_encode_one_space(self): self._test_encode(' ', '=20') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,10 @@ Library ------- +- Issues #20206 and #5803: Fix edge case in email.quoprimime.encode where it + truncated lines ending in a character needing encoding but no newline by + using a more efficient algorithm that doesn't have the bug. + - Issue #19082: Working xmlrpc.server and xmlrpc.client examples. Both in modules and in documentation. Initial patch contributed by Vajrasky Kok. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 13 19:31:40 2014 From: python-checkins at python.org (r.david.murray) Date: Mon, 13 Jan 2014 19:31:40 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2320206=2C_=235803=3A_more_efficient_algorithm_th?= =?utf-8?q?at_doesn=27t_truncate_output=2E?= Message-ID: <3f33Km2Wfjz7LkM@mail.python.org> http://hg.python.org/cpython/rev/b6c3fc21286f changeset: 88442:b6c3fc21286f parent: 88439:3a4b0e4098e6 parent: 88441:4c5b1932354b user: R David Murray date: Mon Jan 13 13:30:13 2014 -0500 summary: Merge #20206, #5803: more efficient algorithm that doesn't truncate output. (No idea why test_tarfile is listed as changed...it isn't.) files: Lib/email/quoprimime.py | 134 +++++++---------- Lib/test/test_email/test_email.py | 5 + Misc/NEWS | 4 + 3 files changed, 65 insertions(+), 78 deletions(-) diff --git a/Lib/email/quoprimime.py b/Lib/email/quoprimime.py --- a/Lib/email/quoprimime.py +++ b/Lib/email/quoprimime.py @@ -53,8 +53,9 @@ # space-wise. Remember that headers and bodies have different sets of safe # characters. Initialize both maps with the full expansion, and then override # the safe bytes with the more compact form. -_QUOPRI_HEADER_MAP = dict((c, '=%02X' % c) for c in range(256)) -_QUOPRI_BODY_MAP = _QUOPRI_HEADER_MAP.copy() +_QUOPRI_MAP = ['=%02X' % c for c in range(256)] +_QUOPRI_HEADER_MAP = _QUOPRI_MAP[:] +_QUOPRI_BODY_MAP = _QUOPRI_MAP[:] # Safe header bytes which need no encoding. for c in b'-!*+/' + ascii_letters.encode('ascii') + digits.encode('ascii'): @@ -121,8 +122,7 @@ def quote(c): - return '=%02X' % ord(c) - + return _QUOPRI_MAP[ord(c)] def header_encode(header_bytes, charset='iso-8859-1'): @@ -140,67 +140,15 @@ if not header_bytes: return '' # Iterate over every byte, encoding if necessary. - encoded = [] - for octet in header_bytes: - encoded.append(_QUOPRI_HEADER_MAP[octet]) + encoded = header_bytes.decode('latin1').translate(_QUOPRI_HEADER_MAP) # Now add the RFC chrome to each encoded chunk and glue the chunks # together. - return '=?%s?q?%s?=' % (charset, EMPTYSTRING.join(encoded)) + return '=?%s?q?%s?=' % (charset, encoded) -class _body_accumulator(io.StringIO): - - def __init__(self, maxlinelen, eol, *args, **kw): - super().__init__(*args, **kw) - self.eol = eol - self.maxlinelen = self.room = maxlinelen - - def write_str(self, s): - """Add string s to the accumulated body.""" - self.write(s) - self.room -= len(s) - - def newline(self): - """Write eol, then start new line.""" - self.write_str(self.eol) - self.room = self.maxlinelen - - def write_soft_break(self): - """Write a soft break, then start a new line.""" - self.write_str('=') - self.newline() - - def write_wrapped(self, s, extra_room=0): - """Add a soft line break if needed, then write s.""" - if self.room < len(s) + extra_room: - self.write_soft_break() - self.write_str(s) - - def write_char(self, c, is_last_char): - if not is_last_char: - # Another character follows on this line, so we must leave - # extra room, either for it or a soft break, and whitespace - # need not be quoted. - self.write_wrapped(c, extra_room=1) - elif c not in ' \t': - # For this and remaining cases, no more characters follow, - # so there is no need to reserve extra room (since a hard - # break will immediately follow). - self.write_wrapped(c) - elif self.room >= 3: - # It's a whitespace character at end-of-line, and we have room - # for the three-character quoted encoding. - self.write(quote(c)) - elif self.room == 2: - # There's room for the whitespace character and a soft break. - self.write(c) - self.write_soft_break() - else: - # There's room only for a soft break. The quoted whitespace - # will be the only content on the subsequent line. - self.write_soft_break() - self.write(quote(c)) - +_QUOPRI_BODY_ENCODE_MAP = _QUOPRI_BODY_MAP[:] +for c in b'\r\n': + _QUOPRI_BODY_ENCODE_MAP[c] = chr(c) def body_encode(body, maxlinelen=76, eol=NL): """Encode with quoted-printable, wrapping at maxlinelen characters. @@ -226,26 +174,56 @@ if not body: return body - # The last line may or may not end in eol, but all other lines do. - last_has_eol = (body[-1] in '\r\n') + # quote speacial characters + body = body.translate(_QUOPRI_BODY_ENCODE_MAP) - # This accumulator will make it easier to build the encoded body. - encoded_body = _body_accumulator(maxlinelen, eol) + soft_break = '=' + eol + # leave space for the '=' at the end of a line + maxlinelen1 = maxlinelen - 1 - lines = body.splitlines() - last_line_no = len(lines) - 1 - for line_no, line in enumerate(lines): - last_char_index = len(line) - 1 - for i, c in enumerate(line): - if body_check(ord(c)): - c = quote(c) - encoded_body.write_char(c, i==last_char_index) - # Add an eol if input line had eol. All input lines have eol except - # possibly the last one. - if line_no < last_line_no or last_has_eol: - encoded_body.newline() + encoded_body = [] + append = encoded_body.append - return encoded_body.getvalue() + for line in body.splitlines(): + # break up the line into pieces no longer than maxlinelen - 1 + start = 0 + laststart = len(line) - 1 - maxlinelen + while start <= laststart: + stop = start + maxlinelen1 + # make sure we don't break up an escape sequence + if line[stop - 2] == '=': + append(line[start:stop - 1]) + start = stop - 2 + elif line[stop - 1] == '=': + append(line[start:stop]) + start = stop - 1 + else: + append(line[start:stop] + '=') + start = stop + + # handle rest of line, special case if line ends in whitespace + if line and line[-1] in ' \t': + room = start - laststart + if room >= 3: + # It's a whitespace character at end-of-line, and we have room + # for the three-character quoted encoding. + q = quote(line[-1]) + elif room == 2: + # There's room for the whitespace character and a soft break. + q = line[-1] + soft_break + else: + # There's room only for a soft break. The quoted whitespace + # will be the only content on the subsequent line. + q = soft_break + quote(line[-1]) + append(line[start:-1] + q) + else: + append(line[start:]) + + # add back final newline if present + if body[-1] in CRLF: + append('') + + return eol.join(encoded_body) diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -4246,6 +4246,11 @@ def test_encode_one_line_eol(self): self._test_encode('hello\n', 'hello\r\n', eol='\r\n') + def test_encode_one_line_eol_after_non_ascii(self): + # issue 20206; see changeset 0cf700464177 for why the encode/decode. + self._test_encode('hello\u03c5\n'.encode('utf-8').decode('latin1'), + 'hello=CF=85\r\n', eol='\r\n') + def test_encode_one_space(self): self._test_encode(' ', '=20') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,10 @@ Library ------- +- Issues #20206 and #5803: Fix edge case in email.quoprimime.encode where it + truncated lines ending in a character needing encoding but no newline by + using a more efficient algorithm that doesn't have the bug. + - Issue #19082: Working xmlrpc.server and xmlrpc.client examples. Both in modules and in documentation. Initial patch contributed by Vajrasky Kok. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 13 19:57:47 2014 From: python-checkins at python.org (r.david.murray) Date: Mon, 13 Jan 2014 19:57:47 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzIwMjM2OiBGaXgg?= =?utf-8?q?sphinx_markup=2E?= Message-ID: <3f33vv3vGCzQPC@mail.python.org> http://hg.python.org/cpython/rev/fb1dd44d1f76 changeset: 88443:fb1dd44d1f76 branch: 3.3 parent: 88441:4c5b1932354b user: R David Murray date: Mon Jan 13 13:51:17 2014 -0500 summary: #20236: Fix sphinx markup. files: Doc/library/xml.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/xml.rst b/Doc/library/xml.rst --- a/Doc/library/xml.rst +++ b/Doc/library/xml.rst @@ -95,7 +95,7 @@ content into the XML document. DTD retrieval - Some XML libraries like Python's mod:'xml.dom.pulldom' retrieve document type + Some XML libraries like Python's :mod:`xml.dom.pulldom` retrieve document type definitions from remote or local locations. The feature has similar implications as the external entity expansion issue. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 13 19:57:48 2014 From: python-checkins at python.org (r.david.murray) Date: Mon, 13 Jan 2014 19:57:48 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2320236=3A_Fix_sphinx_markup=2E?= Message-ID: <3f33vw6l27zQlC@mail.python.org> http://hg.python.org/cpython/rev/60163fc72017 changeset: 88444:60163fc72017 parent: 88442:b6c3fc21286f parent: 88443:fb1dd44d1f76 user: R David Murray date: Mon Jan 13 13:51:42 2014 -0500 summary: Merge #20236: Fix sphinx markup. files: Doc/library/xml.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/xml.rst b/Doc/library/xml.rst --- a/Doc/library/xml.rst +++ b/Doc/library/xml.rst @@ -95,7 +95,7 @@ content into the XML document. DTD retrieval - Some XML libraries like Python's mod:'xml.dom.pulldom' retrieve document type + Some XML libraries like Python's :mod:`xml.dom.pulldom` retrieve document type definitions from remote or local locations. The feature has similar implications as the external entity expansion issue. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 13 19:57:50 2014 From: python-checkins at python.org (r.david.murray) Date: Mon, 13 Jan 2014 19:57:50 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzIwMjM2OiBGaXgg?= =?utf-8?q?sphinx_markup=2E?= Message-ID: <3f33vy2987z7Lk7@mail.python.org> http://hg.python.org/cpython/rev/3481c6f36e55 changeset: 88445:3481c6f36e55 branch: 2.7 parent: 88440:4eac22a9ae72 user: R David Murray date: Mon Jan 13 13:54:54 2014 -0500 summary: #20236: Fix sphinx markup. files: Doc/library/xml.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/xml.rst b/Doc/library/xml.rst --- a/Doc/library/xml.rst +++ b/Doc/library/xml.rst @@ -94,7 +94,7 @@ content into the XML document. DTD retrieval - Some XML libraries like Python's mod:'xml.dom.pulldom' retrieve document type + Some XML libraries like Python's :mod:`xml.dom.pulldom` retrieve document type definitions from remote or local locations. The feature has similar implications as the external entity expansion issue. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 13 20:35:00 2014 From: python-checkins at python.org (ned.deily) Date: Mon, 13 Jan 2014 20:35:00 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320229=3A_Avoid_pl?= =?utf-8?q?istlib_deprecation_warning_in_platform=2Emac=5Fver=28=29=2E?= Message-ID: <3f34kr6CqTz7Ljy@mail.python.org> http://hg.python.org/cpython/rev/cd728dc893c9 changeset: 88446:cd728dc893c9 parent: 88444:60163fc72017 user: Ned Deily date: Mon Jan 13 11:34:19 2014 -0800 summary: Issue #20229: Avoid plistlib deprecation warning in platform.mac_ver(). files: Lib/platform.py | 3 ++- Misc/NEWS | 2 ++ 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/platform.py b/Lib/platform.py --- a/Lib/platform.py +++ b/Lib/platform.py @@ -649,7 +649,8 @@ except ImportError: return None - pl = plistlib.readPlist(fn) + with open(fn, 'rb') as f: + pl = plistlib.load(f) release = pl['ProductVersion'] versioninfo = ('', '', '') machine = os.uname().machine diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -65,6 +65,8 @@ - Issue #20072: Fixed multiple errors in tkinter with wantobjects is False. +- Issue #20229: Avoid plistlib deprecation warning in platform.mac_ver(). + IDLE ---- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 13 23:01:30 2014 From: python-checkins at python.org (vinay.sajip) Date: Mon, 13 Jan 2014 23:01:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMjQy?= =?utf-8?q?=3A_Fixed_basicConfig=28=29_format_strings_for_the_alternative_?= =?utf-8?q?formatting?= Message-ID: <3f37zt1Mxvz7Lk8@mail.python.org> http://hg.python.org/cpython/rev/e7fcf0d8008f changeset: 88447:e7fcf0d8008f branch: 3.3 parent: 88443:fb1dd44d1f76 user: Vinay Sajip date: Mon Jan 13 21:59:56 2014 +0000 summary: Issue #20242: Fixed basicConfig() format strings for the alternative formatting styles. files: Lib/logging/__init__.py | 17 ++++++++++------- Lib/test/test_logging.py | 16 ++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -388,10 +388,12 @@ def format(self, record): return self._tpl.substitute(**record.__dict__) +BASIC_FORMAT = "%(levelname)s:%(name)s:%(message)s" + _STYLES = { - '%': PercentStyle, - '{': StrFormatStyle, - '$': StringTemplateStyle + '%': (PercentStyle, BASIC_FORMAT), + '{': (StrFormatStyle, '{levelname}:{name}:{message}'), + '$': (StringTemplateStyle, '${levelname}:${name}:${message}'), } class Formatter(object): @@ -456,7 +458,7 @@ if style not in _STYLES: raise ValueError('Style must be one of: %s' % ','.join( _STYLES.keys())) - self._style = _STYLES[style](fmt) + self._style = _STYLES[style][0](fmt) self._fmt = self._style._fmt self.datefmt = datefmt @@ -1629,8 +1631,6 @@ # Configuration classes and functions #--------------------------------------------------------------------------- -BASIC_FORMAT = "%(levelname)s:%(name)s:%(message)s" - def basicConfig(**kwargs): """ Do basic configuration for the logging system. @@ -1704,9 +1704,12 @@ stream = kwargs.get("stream") h = StreamHandler(stream) handlers = [h] - fs = kwargs.get("format", BASIC_FORMAT) dfs = kwargs.get("datefmt", None) style = kwargs.get("style", '%') + if style not in _STYLES: + raise ValueError('Style must be one of: %s' % ','.join( + _STYLES.keys())) + fs = kwargs.get("format", _STYLES[style][1]) fmt = Formatter(fs, dfs, style) for h in handlers: if h.formatter is None: 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 @@ -3337,6 +3337,22 @@ # level is not explicitly set self.assertEqual(logging.root.level, self.original_logging_level) + def test_strformatstyle(self): + with captured_stdout() as output: + logging.basicConfig(stream=sys.stdout, style="{") + logging.error("Log an error") + sys.stdout.seek(0) + self.assertEqual(output.getvalue().strip(), + "ERROR:root:Log an error") + + def test_stringtemplatestyle(self): + with captured_stdout() as output: + logging.basicConfig(stream=sys.stdout, style="$") + logging.error("Log an error") + sys.stdout.seek(0) + self.assertEqual(output.getvalue().strip(), + "ERROR:root:Log an error") + def test_filename(self): logging.basicConfig(filename='test.log') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,9 @@ Library ------- +- Issue #20242: Fixed basicConfig() format strings for the alternative + formatting styles. Thanks to kespindler for the bug report and patch. + - Issues #20206 and #5803: Fix edge case in email.quoprimime.encode where it truncated lines ending in a character needing encoding but no newline by using a more efficient algorithm that doesn't have the bug. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 13 23:01:31 2014 From: python-checkins at python.org (vinay.sajip) Date: Mon, 13 Jan 2014 23:01:31 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Closes_=2320242=3A_Merged_fix_from_3=2E3=2E?= Message-ID: <3f37zv3K9hz7Lkp@mail.python.org> http://hg.python.org/cpython/rev/c1605d24fb35 changeset: 88448:c1605d24fb35 parent: 88446:cd728dc893c9 parent: 88447:e7fcf0d8008f user: Vinay Sajip date: Mon Jan 13 22:01:16 2014 +0000 summary: Closes #20242: Merged fix from 3.3. files: Lib/logging/__init__.py | 17 ++++++++++------- Lib/test/test_logging.py | 16 ++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -390,10 +390,12 @@ def format(self, record): return self._tpl.substitute(**record.__dict__) +BASIC_FORMAT = "%(levelname)s:%(name)s:%(message)s" + _STYLES = { - '%': PercentStyle, - '{': StrFormatStyle, - '$': StringTemplateStyle + '%': (PercentStyle, BASIC_FORMAT), + '{': (StrFormatStyle, '{levelname}:{name}:{message}'), + '$': (StringTemplateStyle, '${levelname}:${name}:${message}'), } class Formatter(object): @@ -458,7 +460,7 @@ if style not in _STYLES: raise ValueError('Style must be one of: %s' % ','.join( _STYLES.keys())) - self._style = _STYLES[style](fmt) + self._style = _STYLES[style][0](fmt) self._fmt = self._style._fmt self.datefmt = datefmt @@ -1643,8 +1645,6 @@ # Configuration classes and functions #--------------------------------------------------------------------------- -BASIC_FORMAT = "%(levelname)s:%(name)s:%(message)s" - def basicConfig(**kwargs): """ Do basic configuration for the logging system. @@ -1718,9 +1718,12 @@ stream = kwargs.get("stream") h = StreamHandler(stream) handlers = [h] - fs = kwargs.get("format", BASIC_FORMAT) dfs = kwargs.get("datefmt", None) style = kwargs.get("style", '%') + if style not in _STYLES: + raise ValueError('Style must be one of: %s' % ','.join( + _STYLES.keys())) + fs = kwargs.get("format", _STYLES[style][1]) fmt = Formatter(fs, dfs, style) for h in handlers: if h.formatter is None: 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 @@ -3517,6 +3517,22 @@ # level is not explicitly set self.assertEqual(logging.root.level, self.original_logging_level) + def test_strformatstyle(self): + with captured_stdout() as output: + logging.basicConfig(stream=sys.stdout, style="{") + logging.error("Log an error") + sys.stdout.seek(0) + self.assertEqual(output.getvalue().strip(), + "ERROR:root:Log an error") + + def test_stringtemplatestyle(self): + with captured_stdout() as output: + logging.basicConfig(stream=sys.stdout, style="$") + logging.error("Log an error") + sys.stdout.seek(0) + self.assertEqual(output.getvalue().strip(), + "ERROR:root:Log an error") + def test_filename(self): def cleanup(h1, h2, fn): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,9 @@ Library ------- +- Issue #20242: Fixed basicConfig() format strings for the alternative + formatting styles. Thanks to kespindler for the bug report and patch. + - Issues #20206 and #5803: Fix edge case in email.quoprimime.encode where it truncated lines ending in a character needing encoding but no newline by using a more efficient algorithm that doesn't have the bug. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 13 23:09:17 2014 From: python-checkins at python.org (zach.ware) Date: Mon, 13 Jan 2014 23:09:17 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Correct_a_typo=2E__Found_b?= =?utf-8?q?y_Lauri_Hakko_on_docs=40=2E?= Message-ID: <3f388s40Mpz7Ln7@mail.python.org> http://hg.python.org/cpython/rev/d2366d910386 changeset: 88449:d2366d910386 user: Zachary Ware date: Mon Jan 13 16:08:54 2014 -0600 summary: Correct a typo. Found by Lauri Hakko on docs at . files: Doc/whatsnew/3.4.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) 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 @@ -733,7 +733,7 @@ ---- :meth:`~http.server.BaseHTTPRequestHandler.send_error` now accepts an -optional additional *exaplain* parameter which can be used to provide an +optional additional *explain* parameter which can be used to provide an extended error description, overriding the hardcoded default if there is one. This extended error description will be formatted using the :attr:`~http.server.HTTP.error_message_format` attribute and sent as the body -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 03:39:49 2014 From: python-checkins at python.org (zach.ware) Date: Tue, 14 Jan 2014 03:39:49 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogRml4IHR5cG8uICBQ?= =?utf-8?q?ointed_out_by_Finn_Ellis_on_docs=40=2E?= Message-ID: <3f3G911LwQz7Lkf@mail.python.org> http://hg.python.org/cpython/rev/2631d33ee7fb changeset: 88450:2631d33ee7fb branch: 2.7 parent: 88445:3481c6f36e55 user: Zachary Ware date: Mon Jan 13 20:38:17 2014 -0600 summary: Fix typo. Pointed out by Finn Ellis on docs at . files: Doc/library/userdict.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/userdict.rst b/Doc/library/userdict.rst --- a/Doc/library/userdict.rst +++ b/Doc/library/userdict.rst @@ -128,7 +128,7 @@ A real Python list object used to store the contents of the :class:`UserList` class. -**Subclassing requirements:** Subclasses of :class:`UserList` are expect to +**Subclassing requirements:** Subclasses of :class:`UserList` are expected to offer a constructor which can be called with either no arguments or one argument. List operations which return a new sequence attempt to create an instance of the actual implementation class. To do so, it assumes that the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 03:39:50 2014 From: python-checkins at python.org (zach.ware) Date: Tue, 14 Jan 2014 03:39:50 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogRml4IHR5cG8u?= Message-ID: <3f3G9235qTz7Lkf@mail.python.org> http://hg.python.org/cpython/rev/ed1c27b68068 changeset: 88451:ed1c27b68068 branch: 3.3 parent: 88447:e7fcf0d8008f user: Zachary Ware date: Mon Jan 13 20:38:57 2014 -0600 summary: Fix typo. files: Doc/library/collections.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -1093,7 +1093,7 @@ A real :class:`list` object used to store the contents of the :class:`UserList` class. -**Subclassing requirements:** Subclasses of :class:`UserList` are expect to +**Subclassing requirements:** Subclasses of :class:`UserList` are expected to offer a constructor which can be called with either no arguments or one argument. List operations which return a new sequence attempt to create an instance of the actual implementation class. To do so, it assumes that the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 03:39:51 2014 From: python-checkins at python.org (zach.ware) Date: Tue, 14 Jan 2014 03:39:51 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_typo_fix=2E?= Message-ID: <3f3G93515Qz7Lmk@mail.python.org> http://hg.python.org/cpython/rev/753b8b4beee5 changeset: 88452:753b8b4beee5 parent: 88449:d2366d910386 parent: 88451:ed1c27b68068 user: Zachary Ware date: Mon Jan 13 20:39:21 2014 -0600 summary: Merge typo fix. files: Doc/library/collections.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -1085,7 +1085,7 @@ A real :class:`list` object used to store the contents of the :class:`UserList` class. -**Subclassing requirements:** Subclasses of :class:`UserList` are expect to +**Subclassing requirements:** Subclasses of :class:`UserList` are expected to offer a constructor which can be called with either no arguments or one argument. List operations which return a new sequence attempt to create an instance of the actual implementation class. To do so, it assumes that the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 05:15:07 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 14 Jan 2014 05:15:07 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_complain_when_?= =?utf-8?q?nbytes_=3E_buflen_to_fix_possible_buffer_overflow_=28closes_=23?= =?utf-8?q?20246=29?= Message-ID: <3f3JGz72KXz7Lkb@mail.python.org> http://hg.python.org/cpython/rev/87673659d8f7 changeset: 88453:87673659d8f7 branch: 2.7 parent: 88450:2631d33ee7fb user: Benjamin Peterson date: Mon Jan 13 22:59:38 2014 -0500 summary: complain when nbytes > buflen to fix possible buffer overflow (closes #20246) files: Lib/test/test_socket.py | 10 ++++++++++ Misc/ACKS | 1 + Misc/NEWS | 2 ++ Modules/socketmodule.c | 4 ++++ 4 files changed, 17 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 @@ -1620,6 +1620,16 @@ _testRecvFromIntoMemoryview = _testRecvFromIntoArray + def testRecvFromIntoSmallBuffer(self): + # See issue #20246. + buf = bytearray(8) + self.assertRaises(ValueError, self.cli_conn.recvfrom_into, buf, 1024) + + def _testRecvFromIntoSmallBuffer(self): + with test_support.check_py3k_warnings(): + buf = buffer(MSG*2048) + self.serv_conn.send(buf) + TIPC_STYPE = 2000 TIPC_LOWER = 200 diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -979,6 +979,7 @@ Christopher Smith Gregory P. Smith Roy Smith +Ryan Smith-Roberts Rafal Smotrzyk Dirk Soede Paul Sokolovsky diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,6 +35,8 @@ Library ------- +- Issue #20246: Fix buffer overflow in socket.recvfrom_into. + - Issue #19082: Working SimpleXMLRPCServer and xmlrpclib examples, both in modules and documentation. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -2742,6 +2742,10 @@ if (recvlen == 0) { /* If nbytes was not specified, use the buffer's length */ recvlen = buflen; + } else if (recvlen > buflen) { + PyErr_SetString(PyExc_ValueError, + "nbytes is greater than the length of the buffer"); + goto error; } readlen = sock_recvfrom_guts(s, buf.buf, recvlen, flags, &addr); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 05:15:09 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 14 Jan 2014 05:15:09 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDMuMSk6?= =?utf-8?q?_complain_when_nbytes_=3E_buflen_to_fix_possible_buffer_overflo?= =?utf-8?q?w_=28closes_=2320246=29?= Message-ID: <3f3JH11tMgz7Lln@mail.python.org> http://hg.python.org/cpython/rev/715fd3d8ac93 changeset: 88454:715fd3d8ac93 branch: 3.1 parent: 86777:b1ddcb220a7f parent: 88453:87673659d8f7 user: Benjamin Peterson date: Mon Jan 13 23:06:14 2014 -0500 summary: complain when nbytes > buflen to fix possible buffer overflow (closes #20246) files: Lib/test/test_socket.py | 8 ++++++++ Misc/ACKS | 1 + Misc/NEWS | 2 ++ Modules/socketmodule.c | 6 ++++++ 4 files changed, 17 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 @@ -1424,6 +1424,14 @@ buf = bytes(MSG) self.serv_conn.send(buf) + def testRecvFromIntoSmallBuffer(self): + # See issue #20246. + buf = bytearray(8) + self.assertRaises(ValueError, self.cli_conn.recvfrom_into, buf, 1024) + + def _testRecvFromIntoSmallBuffer(self): + self.serv_conn.send(MSG*2048) + TIPC_STYPE = 2000 TIPC_LOWER = 200 diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -757,6 +757,7 @@ Eric V. Smith Christopher Smith Gregory P. Smith +Ryan Smith-Roberts Rafal Smotrzyk Dirk Soede Paul Sokolovsky diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,8 @@ Library ------- +- Issue #20246: Fix buffer overflow in socket.recvfrom_into. + - Issue #19435: Fix directory traversal attack on CGIHttpRequestHandler. - Issue #14984: On POSIX systems, when netrc is called without a filename diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -2494,6 +2494,12 @@ if (recvlen == 0) { /* If nbytes was not specified, use the buffer's length */ recvlen = buflen; + } else if (recvlen > buflen) { + PyBuffer_Release(&pbuf); + Py_XDECREF(addr); + PyErr_SetString(PyExc_ValueError, + "nbytes is greater than the length of the buffer"); + return NULL; } readlen = sock_recvfrom_guts(s, buf, recvlen, flags, &addr); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 05:15:10 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 14 Jan 2014 05:15:10 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_complain_when_?= =?utf-8?q?nbytes_=3E_buflen_to_fix_possible_buffer_overflow_=28closes_=23?= =?utf-8?q?20246=29?= Message-ID: <3f3JH245mBz7LnB@mail.python.org> http://hg.python.org/cpython/rev/9c56217e5c79 changeset: 88455:9c56217e5c79 branch: 3.2 parent: 88123:2b5cd6d4d149 user: Benjamin Peterson date: Mon Jan 13 22:59:38 2014 -0500 summary: complain when nbytes > buflen to fix possible buffer overflow (closes #20246) files: Lib/test/test_socket.py | 8 ++++++++ Misc/ACKS | 1 + Misc/NEWS | 2 ++ Modules/socketmodule.c | 5 +++++ 4 files changed, 16 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 @@ -1968,6 +1968,14 @@ _testRecvFromIntoMemoryview = _testRecvFromIntoArray + def testRecvFromIntoSmallBuffer(self): + # See issue #20246. + buf = bytearray(8) + self.assertRaises(ValueError, self.cli_conn.recvfrom_into, buf, 1024) + + def _testRecvFromIntoSmallBuffer(self): + self.serv_conn.send(MSG*2048) + TIPC_STYPE = 2000 TIPC_LOWER = 200 diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1020,6 +1020,7 @@ Christopher Smith Gregory P. Smith Roy Smith +Ryan Smith-Roberts Rafal Smotrzyk Dirk Soede Paul Sokolovsky diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Library ------- +- Issue #20246: Fix buffer overflow in socket.recvfrom_into. + - Issue #12226: HTTPS is now used by default when connecting to PyPI. - Issue #19435: Fix directory traversal attack on CGIHttpRequestHandler. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -2598,6 +2598,11 @@ if (recvlen == 0) { /* If nbytes was not specified, use the buffer's length */ recvlen = buflen; + } else if (recvlen > buflen) { + PyBuffer_Release(&pbuf); + PyErr_SetString(PyExc_ValueError, + "nbytes is greater than the length of the buffer"); + return NULL; } readlen = sock_recvfrom_guts(s, buf, recvlen, flags, &addr); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 05:15:11 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 14 Jan 2014 05:15:11 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMyk6?= =?utf-8?q?_merge_3=2E2_=28=2320246=29?= Message-ID: <3f3JH36KMrz7Lmk@mail.python.org> http://hg.python.org/cpython/rev/7f176a45211f changeset: 88456:7f176a45211f branch: 3.3 parent: 88451:ed1c27b68068 parent: 88455:9c56217e5c79 user: Benjamin Peterson date: Mon Jan 13 23:12:55 2014 -0500 summary: merge 3.2 (#20246) files: Lib/test/test_socket.py | 8 ++++++++ Misc/ACKS | 1 + Misc/NEWS | 2 ++ Modules/socketmodule.c | 5 +++++ 4 files changed, 16 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 @@ -4538,6 +4538,14 @@ _testRecvFromIntoMemoryview = _testRecvFromIntoArray + def testRecvFromIntoSmallBuffer(self): + # See issue #20246. + buf = bytearray(8) + self.assertRaises(ValueError, self.cli_conn.recvfrom_into, buf, 1024) + + def _testRecvFromIntoSmallBuffer(self): + self.serv_conn.send(MSG*2048) + TIPC_STYPE = 2000 TIPC_LOWER = 200 diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1169,6 +1169,7 @@ Gregory P. Smith Mark Smith Roy Smith +Ryan Smith-Roberts Rafal Smotrzyk Eric Snow Dirk Soede diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -46,6 +46,8 @@ - Issue #20242: Fixed basicConfig() format strings for the alternative formatting styles. Thanks to kespindler for the bug report and patch. +- Issue #20246: Fix buffer overflow in socket.recvfrom_into. + - Issues #20206 and #5803: Fix edge case in email.quoprimime.encode where it truncated lines ending in a character needing encoding but no newline by using a more efficient algorithm that doesn't have the bug. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -2935,6 +2935,11 @@ if (recvlen == 0) { /* If nbytes was not specified, use the buffer's length */ recvlen = buflen; + } else if (recvlen > buflen) { + PyBuffer_Release(&pbuf); + PyErr_SetString(PyExc_ValueError, + "nbytes is greater than the length of the buffer"); + return NULL; } readlen = sock_recvfrom_guts(s, buf, recvlen, flags, &addr); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 05:15:13 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 14 Jan 2014 05:15:13 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbjogbWVyZ2UgMy4zICgjMjAyNDYp?= Message-ID: <3f3JH512Xdz7LnH@mail.python.org> http://hg.python.org/cpython/rev/ead74e54d68f changeset: 88457:ead74e54d68f parent: 88452:753b8b4beee5 user: Benjamin Peterson date: Mon Jan 13 23:14:42 2014 -0500 summary: merge 3.3 (#20246) files: Lib/test/test_socket.py | 8 ++++++++ Misc/ACKS | 1 + Misc/NEWS | 2 ++ Modules/socketmodule.c | 5 +++++ 4 files changed, 16 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 @@ -4683,6 +4683,14 @@ _testRecvFromIntoMemoryview = _testRecvFromIntoArray + def testRecvFromIntoSmallBuffer(self): + # See issue #20246. + buf = bytearray(8) + self.assertRaises(ValueError, self.cli_conn.recvfrom_into, buf, 1024) + + def _testRecvFromIntoSmallBuffer(self): + self.serv_conn.send(MSG*2048) + TIPC_STYPE = 2000 TIPC_LOWER = 200 diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1218,6 +1218,7 @@ Gregory P. Smith Mark Smith Roy Smith +Ryan Smith-Roberts Rafal Smotrzyk Eric Snow Dirk Soede diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -28,6 +28,8 @@ - Issue #20242: Fixed basicConfig() format strings for the alternative formatting styles. Thanks to kespindler for the bug report and patch. +- Issue #20246: Fix buffer overflow in socket.recvfrom_into. + - Issues #20206 and #5803: Fix edge case in email.quoprimime.encode where it truncated lines ending in a character needing encoding but no newline by using a more efficient algorithm that doesn't have the bug. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -2875,6 +2875,11 @@ if (recvlen == 0) { /* If nbytes was not specified, use the buffer's length */ recvlen = buflen; + } else if (recvlen > buflen) { + PyBuffer_Release(&pbuf); + PyErr_SetString(PyExc_ValueError, + "nbytes is greater than the length of the buffer"); + return NULL; } readlen = sock_recvfrom_guts(s, buf, recvlen, flags, &addr); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 05:15:14 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 14 Jan 2014 05:15:14 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4zICgjMjAyNDYp?= Message-ID: <3f3JH62tHJz7Ln9@mail.python.org> http://hg.python.org/cpython/rev/37ed85008f51 changeset: 88458:37ed85008f51 parent: 88457:ead74e54d68f parent: 88456:7f176a45211f user: Benjamin Peterson date: Mon Jan 13 23:14:58 2014 -0500 summary: merge 3.3 (#20246) files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 05:56:43 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 14 Jan 2014 05:56:43 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_correct_defaul?= =?utf-8?q?tdict_signature_in_docstring_=28closes_=2320250=29?= Message-ID: <3f3KBz31lKz7LkL@mail.python.org> http://hg.python.org/cpython/rev/d46bf7835b45 changeset: 88459:d46bf7835b45 branch: 3.3 parent: 88456:7f176a45211f user: Benjamin Peterson date: Mon Jan 13 23:56:05 2014 -0500 summary: correct defaultdict signature in docstring (closes #20250) Patch from Andrew Barnert. files: Modules/_collectionsmodule.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -1625,11 +1625,13 @@ } PyDoc_STRVAR(defdict_doc, -"defaultdict(default_factory) --> dict with default factory\n\ +"defaultdict(default_factory[, ...]) --> dict with default factory\n\ \n\ The default factory is called without arguments to produce\n\ a new value when a key is not present, in __getitem__ only.\n\ A defaultdict compares equal to a dict with the same items.\n\ +All remaining arguments are treated the same as if they were\n\ +passed to the dict constructor, including keyword arguments.\n\ "); /* See comment in xxsubtype.c */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 05:56:44 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 14 Jan 2014 05:56:44 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_correct_defaul?= =?utf-8?q?tdict_signature_in_docstring_=28closes_=2320250=29?= Message-ID: <3f3KC04TC0z7Lln@mail.python.org> http://hg.python.org/cpython/rev/950f1e83bb56 changeset: 88460:950f1e83bb56 branch: 2.7 parent: 88453:87673659d8f7 user: Benjamin Peterson date: Mon Jan 13 23:56:05 2014 -0500 summary: correct defaultdict signature in docstring (closes #20250) Patch from Andrew Barnert. files: Modules/_collectionsmodule.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -1612,11 +1612,13 @@ } PyDoc_STRVAR(defdict_doc, -"defaultdict(default_factory) --> dict with default factory\n\ +"defaultdict(default_factory[, ...]) --> dict with default factory\n\ \n\ The default factory is called without arguments to produce\n\ a new value when a key is not present, in __getitem__ only.\n\ A defaultdict compares equal to a dict with the same items.\n\ +All remaining arguments are treated the same as if they were\n\ +passed to the dict constructor, including keyword arguments.\n\ "); /* See comment in xxsubtype.c */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 05:56:45 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 14 Jan 2014 05:56:45 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4zICgjMjAyNTAp?= Message-ID: <3f3KC15sLMz7LmX@mail.python.org> http://hg.python.org/cpython/rev/49ae53150ee0 changeset: 88461:49ae53150ee0 parent: 88458:37ed85008f51 parent: 88459:d46bf7835b45 user: Benjamin Peterson date: Mon Jan 13 23:56:30 2014 -0500 summary: merge 3.3 (#20250) files: Modules/_collectionsmodule.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -1699,11 +1699,13 @@ } PyDoc_STRVAR(defdict_doc, -"defaultdict(default_factory) --> dict with default factory\n\ +"defaultdict(default_factory[, ...]) --> dict with default factory\n\ \n\ The default factory is called without arguments to produce\n\ a new value when a key is not present, in __getitem__ only.\n\ A defaultdict compares equal to a dict with the same items.\n\ +All remaining arguments are treated the same as if they were\n\ +passed to the dict constructor, including keyword arguments.\n\ "); /* See comment in xxsubtype.c */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 06:22:58 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 14 Jan 2014 06:22:58 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_remove_overly_?= =?utf-8?q?strict_assertion_=28closes_=2320251=29?= Message-ID: <3f3KnG6XsGz7LkL@mail.python.org> http://hg.python.org/cpython/rev/8712efe02dcc changeset: 88462:8712efe02dcc branch: 3.3 parent: 88459:d46bf7835b45 user: Benjamin Peterson date: Tue Jan 14 00:21:49 2014 -0500 summary: remove overly strict assertion (closes #20251) files: Modules/socketmodule.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -2924,7 +2924,6 @@ return NULL; buf = pbuf.buf; buflen = pbuf.len; - assert(buf != 0 && buflen > 0); if (recvlen < 0) { PyBuffer_Release(&pbuf); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 06:23:04 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 14 Jan 2014 06:23:04 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4zICgjMjAyNTEp?= Message-ID: <3f3KnN2Thrz7Ln0@mail.python.org> http://hg.python.org/cpython/rev/ab9556830560 changeset: 88463:ab9556830560 parent: 88461:49ae53150ee0 parent: 88462:8712efe02dcc user: Benjamin Peterson date: Tue Jan 14 00:22:50 2014 -0500 summary: merge 3.3 (#20251) files: Modules/socketmodule.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -2864,7 +2864,6 @@ return NULL; buf = pbuf.buf; buflen = pbuf.len; - assert(buf != 0 && buflen > 0); if (recvlen < 0) { PyBuffer_Release(&pbuf); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 06:29:14 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 14 Jan 2014 06:29:14 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_remove_overly_?= =?utf-8?q?strict_assertion_=28closes_=2320251=29?= Message-ID: <3f3KwV07xkz7Lln@mail.python.org> http://hg.python.org/cpython/rev/3881211cbb19 changeset: 88464:3881211cbb19 branch: 2.7 parent: 88460:950f1e83bb56 user: Benjamin Peterson date: Tue Jan 14 00:21:49 2014 -0500 summary: remove overly strict assertion (closes #20251) files: Modules/socketmodule.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -2732,7 +2732,6 @@ &recvlen, &flags)) return NULL; buflen = buf.len; - assert(buf.buf != 0 && buflen > 0); if (recvlen < 0) { PyErr_SetString(PyExc_ValueError, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 06:29:15 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 14 Jan 2014 06:29:15 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_add_test_for_?= =?utf-8?q?=2320251?= Message-ID: <3f3KwW26BYz7Ln0@mail.python.org> http://hg.python.org/cpython/rev/1885e1768ff9 changeset: 88465:1885e1768ff9 branch: 2.7 user: Benjamin Peterson date: Tue Jan 14 00:27:42 2014 -0500 summary: add test for #20251 files: Lib/test/test_socket.py | 7 +++++++ 1 files changed, 7 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 @@ -1630,6 +1630,13 @@ buf = buffer(MSG*2048) self.serv_conn.send(buf) + def testRecvFromIntoEmptyBuffer(self): + buf = bytearray() + self.cli_conn.recvfrom_into(buf) + self.cli_conn.recvfrom_into(buf, 0) + + _testRecvFromIntoEmptyBuffer = _testRecvFromIntoArray + TIPC_STYPE = 2000 TIPC_LOWER = 200 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 06:29:16 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 14 Jan 2014 06:29:16 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_add_test_for_?= =?utf-8?q?=2320251?= Message-ID: <3f3KwX4Wp9z7Ln2@mail.python.org> http://hg.python.org/cpython/rev/6ea64dcfb5e2 changeset: 88466:6ea64dcfb5e2 branch: 3.3 parent: 88462:8712efe02dcc user: Benjamin Peterson date: Tue Jan 14 00:27:42 2014 -0500 summary: add test for #20251 files: Lib/test/test_socket.py | 7 +++++++ 1 files changed, 7 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 @@ -4546,6 +4546,13 @@ def _testRecvFromIntoSmallBuffer(self): self.serv_conn.send(MSG*2048) + def testRecvFromIntoEmptyBuffer(self): + buf = bytearray() + self.cli_conn.recvfrom_into(buf) + self.cli_conn.recvfrom_into(buf, 0) + + _testRecvFromIntoEmptyBuffer = _testRecvFromIntoArray + TIPC_STYPE = 2000 TIPC_LOWER = 200 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 06:29:17 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 14 Jan 2014 06:29:17 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3f3KwY67PYz7Ln0@mail.python.org> http://hg.python.org/cpython/rev/d7c3cda62b5e changeset: 88467:d7c3cda62b5e parent: 88463:ab9556830560 parent: 88466:6ea64dcfb5e2 user: Benjamin Peterson date: Tue Jan 14 00:29:03 2014 -0500 summary: merge 3.3 files: Lib/test/test_socket.py | 7 +++++++ 1 files changed, 7 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 @@ -4691,6 +4691,13 @@ def _testRecvFromIntoSmallBuffer(self): self.serv_conn.send(MSG*2048) + def testRecvFromIntoEmptyBuffer(self): + buf = bytearray() + self.cli_conn.recvfrom_into(buf) + self.cli_conn.recvfrom_into(buf, 0) + + _testRecvFromIntoEmptyBuffer = _testRecvFromIntoArray + TIPC_STYPE = 2000 TIPC_LOWER = 200 -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue Jan 14 09:48:35 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 14 Jan 2014 09:48:35 +0100 Subject: [Python-checkins] Daily reference leaks (d2366d910386): sum=0 Message-ID: results for d2366d910386 on branch "default" -------------------------------------------- test_site leaked [0, -2, 2] references, sum=0 test_site leaked [0, -2, 2] memory blocks, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogt5DNVJ', '-x'] From python-checkins at python.org Tue Jan 14 12:27:25 2014 From: python-checkins at python.org (georg.brandl) Date: Tue, 14 Jan 2014 12:27:25 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_small_grammar_fix=2E?= Message-ID: <3f3Tsn6PYDzPFQ@mail.python.org> http://hg.python.org/cpython/rev/7b67ce011d4c changeset: 88468:7b67ce011d4c parent: 88417:1638360eea41 user: Georg Brandl date: Sun Jan 12 18:03:12 2014 +0100 summary: small grammar fix. files: Doc/library/select.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/select.rst b/Doc/library/select.rst --- a/Doc/library/select.rst +++ b/Doc/library/select.rst @@ -313,7 +313,7 @@ .. method:: epoll.modify(fd, eventmask) - Modify a register file descriptor. + Modify a registered file descriptor. .. method:: epoll.unregister(fd) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 12:27:27 2014 From: python-checkins at python.org (georg.brandl) Date: Tue, 14 Jan 2014 12:27:27 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogQ2xvc2VzICMyMDI1?= =?utf-8?q?8=3A_Sphinx_toolchain=3A_move_back_to_Jinja2_2=2E3=2E1_with_sup?= =?utf-8?q?port_for?= Message-ID: <3f3Tsq1G4kz7Lnk@mail.python.org> http://hg.python.org/cpython/rev/92fe1cd256f1 changeset: 88469:92fe1cd256f1 branch: 3.3 parent: 88466:6ea64dcfb5e2 user: Georg Brandl date: Tue Jan 14 12:00:45 2014 +0100 summary: Closes #20258: Sphinx toolchain: move back to Jinja2 2.3.1 with support for Py2.5. files: Doc/Makefile | 2 +- Doc/make.bat | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/Makefile b/Doc/Makefile --- a/Doc/Makefile +++ b/Doc/Makefile @@ -49,7 +49,7 @@ fi @if [ ! -d tools/jinja2 ]; then \ echo "Checking out Jinja..."; \ - svn checkout $(SVNROOT)/external/Jinja2-2.7.2/jinja2 tools/jinja2; \ + svn checkout $(SVNROOT)/external/Jinja-2.3.1/jinja2 tools/jinja2; \ fi @if [ ! -d tools/pygments ]; then \ echo "Checking out Pygments..."; \ diff --git a/Doc/make.bat b/Doc/make.bat --- a/Doc/make.bat +++ b/Doc/make.bat @@ -36,7 +36,7 @@ :checkout svn co %SVNROOT%/external/Sphinx-1.2/sphinx tools/sphinx svn co %SVNROOT%/external/docutils-0.11/docutils tools/docutils -svn co %SVNROOT%/external/Jinja2-2.7.2/jinja2 tools/jinja2 +svn co %SVNROOT%/external/Jinja-2.3.1/jinja2 tools/jinja2 svn co %SVNROOT%/external/Pygments-1.6/pygments tools/pygments goto end -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 12:27:28 2014 From: python-checkins at python.org (georg.brandl) Date: Tue, 14 Jan 2014 12:27:28 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge_with_3=2E3?= Message-ID: <3f3Tsr3LMfz7LnG@mail.python.org> http://hg.python.org/cpython/rev/a3cde638ede0 changeset: 88470:a3cde638ede0 parent: 88467:d7c3cda62b5e parent: 88469:92fe1cd256f1 user: Georg Brandl date: Tue Jan 14 12:27:21 2014 +0100 summary: merge with 3.3 files: Doc/Makefile | 2 +- Doc/make.bat | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/Makefile b/Doc/Makefile --- a/Doc/Makefile +++ b/Doc/Makefile @@ -49,7 +49,7 @@ fi @if [ ! -d tools/jinja2 ]; then \ echo "Checking out Jinja..."; \ - svn checkout $(SVNROOT)/external/Jinja2-2.7.2/jinja2 tools/jinja2; \ + svn checkout $(SVNROOT)/external/Jinja-2.3.1/jinja2 tools/jinja2; \ fi @if [ ! -d tools/pygments ]; then \ echo "Checking out Pygments..."; \ diff --git a/Doc/make.bat b/Doc/make.bat --- a/Doc/make.bat +++ b/Doc/make.bat @@ -36,7 +36,7 @@ :checkout svn co %SVNROOT%/external/Sphinx-1.2/sphinx tools/sphinx svn co %SVNROOT%/external/docutils-0.11/docutils tools/docutils -svn co %SVNROOT%/external/Jinja2-2.7.2/jinja2 tools/jinja2 +svn co %SVNROOT%/external/Jinja-2.3.1/jinja2 tools/jinja2 svn co %SVNROOT%/external/Pygments-1.6/pygments tools/pygments goto end -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 12:27:29 2014 From: python-checkins at python.org (georg.brandl) Date: Tue, 14 Jan 2014 12:27:29 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3f3Tss4wqyzPFQ@mail.python.org> http://hg.python.org/cpython/rev/513ad970a2aa changeset: 88471:513ad970a2aa parent: 88470:a3cde638ede0 parent: 88468:7b67ce011d4c user: Georg Brandl date: Tue Jan 14 12:27:44 2014 +0100 summary: merge files: Doc/library/select.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/select.rst b/Doc/library/select.rst --- a/Doc/library/select.rst +++ b/Doc/library/select.rst @@ -313,7 +313,7 @@ .. method:: epoll.modify(fd, eventmask) - Modify a register file descriptor. + Modify a registered file descriptor. .. method:: epoll.unregister(fd) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 14:15:11 2014 From: python-checkins at python.org (eric.smith) Date: Tue, 14 Jan 2014 14:15:11 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_typo_in_comment=2E?= Message-ID: <3f3XG75F46z7Lkb@mail.python.org> http://hg.python.org/cpython/rev/a3cd0859524d changeset: 88472:a3cd0859524d user: Eric V. Smith date: Tue Jan 14 08:15:03 2014 -0500 summary: Fix typo in comment. files: Objects/setobject.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -768,7 +768,7 @@ hash ^= ((h ^ 89869747UL) ^ (h << 16)) * 3644798167UL; } /* Make the final result spread-out in a different pattern - than the algorithem for tuples or other python objects. */ + than the algorithm for tuples or other python objects. */ hash = hash * 69069U + 907133923UL; if (hash == -1) hash = 590923713UL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 15:42:39 2014 From: python-checkins at python.org (zach.ware) Date: Tue, 14 Jan 2014 15:42:39 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogRml4IHR5cG8uICBG?= =?utf-8?q?ound_by_David_Pesta_on_docs=40=2E?= Message-ID: <3f3ZC326DzzPZD@mail.python.org> http://hg.python.org/cpython/rev/59c7a23d5549 changeset: 88473:59c7a23d5549 branch: 3.3 parent: 88469:92fe1cd256f1 user: Zachary Ware date: Tue Jan 14 08:40:53 2014 -0600 summary: Fix typo. Found by David Pesta on docs at . files: Doc/tutorial/introduction.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -74,7 +74,7 @@ >>> 5 * 3 + 2 # result * divisor + remainder 17 -With Python is possible to use the ``**`` operator to calculate powers [#]_:: +With Python, it is possible to use the ``**`` operator to calculate powers [#]_:: >>> 5 ** 2 # 5 squared 25 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 15:42:40 2014 From: python-checkins at python.org (zach.ware) Date: Tue, 14 Jan 2014 15:42:40 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_typo_fix=2E?= Message-ID: <3f3ZC44lqbz7Lnb@mail.python.org> http://hg.python.org/cpython/rev/1102ddea5c60 changeset: 88474:1102ddea5c60 parent: 88472:a3cd0859524d parent: 88473:59c7a23d5549 user: Zachary Ware date: Tue Jan 14 08:41:41 2014 -0600 summary: Merge typo fix. files: Doc/tutorial/introduction.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -74,7 +74,7 @@ >>> 5 * 3 + 2 # result * divisor + remainder 17 -With Python is possible to use the ``**`` operator to calculate powers [#]_:: +With Python, it is possible to use the ``**`` operator to calculate powers [#]_:: >>> 5 ** 2 # 5 squared 25 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 15:45:59 2014 From: python-checkins at python.org (zach.ware) Date: Tue, 14 Jan 2014 15:45:59 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogRml4IHR5cG8uICBG?= =?utf-8?q?ound_by_David_Pesta_on_docs=40=2E?= Message-ID: <3f3ZGv2sDYz7LpF@mail.python.org> http://hg.python.org/cpython/rev/3be65ed4fbe8 changeset: 88475:3be65ed4fbe8 branch: 3.3 parent: 88473:59c7a23d5549 user: Zachary Ware date: Tue Jan 14 08:44:49 2014 -0600 summary: Fix typo. Found by David Pesta on docs at . files: Doc/tutorial/introduction.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -58,7 +58,7 @@ The integer numbers (e.g. ``2``, ``4``, ``20``) have type :class:`int`, the ones with a fractional part (e.g. ``5.0``, ``1.6``) have type -:class:`float`. We will see more about numberic types later in the tutorial. +:class:`float`. We will see more about numeric types later in the tutorial. Division (``/``) always returns a float. To do :term:`floor division` and get an integer result (discarding any fractional result) you can use the ``//`` -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 15:46:00 2014 From: python-checkins at python.org (zach.ware) Date: Tue, 14 Jan 2014 15:46:00 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_typo_fix=2E?= Message-ID: <3f3ZGw4nCWz7Lnt@mail.python.org> http://hg.python.org/cpython/rev/e38225008f2e changeset: 88476:e38225008f2e parent: 88474:1102ddea5c60 parent: 88475:3be65ed4fbe8 user: Zachary Ware date: Tue Jan 14 08:45:38 2014 -0600 summary: Merge typo fix. files: Doc/tutorial/introduction.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -58,7 +58,7 @@ The integer numbers (e.g. ``2``, ``4``, ``20``) have type :class:`int`, the ones with a fractional part (e.g. ``5.0``, ``1.6``) have type -:class:`float`. We will see more about numberic types later in the tutorial. +:class:`float`. We will see more about numeric types later in the tutorial. Division (``/``) always returns a float. To do :term:`floor division` and get an integer result (discarding any fractional result) you can use the ``//`` -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 16:10:59 2014 From: python-checkins at python.org (zach.ware) Date: Tue, 14 Jan 2014 16:10:59 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMjUz?= =?utf-8?q?=3A_Fixed_a_typo_in_the_ipaddress_docs_that_advertised_an?= Message-ID: <3f3Zql5BGPz7LnK@mail.python.org> http://hg.python.org/cpython/rev/4f8ad9a4193f changeset: 88477:4f8ad9a4193f branch: 3.3 parent: 88475:3be65ed4fbe8 user: Zachary Ware date: Tue Jan 14 09:09:48 2014 -0600 summary: Issue #20253: Fixed a typo in the ipaddress docs that advertised an illegal attribute name. Found by INADA Naoki. files: Doc/library/ipaddress.rst | 4 ++-- Misc/NEWS | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst --- a/Doc/library/ipaddress.rst +++ b/Doc/library/ipaddress.rst @@ -405,7 +405,7 @@ The broadcast address for the network. Packets sent to the broadcast address should be received by every host on the network. - .. attribute:: host mask + .. attribute:: hostmask The host mask, as a string. @@ -561,7 +561,7 @@ .. attribute:: is_link_local .. attribute:: network_address .. attribute:: broadcast_address - .. attribute:: host mask + .. attribute:: hostmask .. attribute:: with_prefixlen .. attribute:: compressed .. attribute:: exploded diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -302,6 +302,9 @@ Documentation ------------- +- Issue #20253: Fixed a typo in the ipaddress docs that advertised an + illegal attribute name. Found by INADA Naoki. + - Issue #19963: Document that importlib.import_module() no longer requires importing parent packages separately. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 16:11:01 2014 From: python-checkins at python.org (zach.ware) Date: Tue, 14 Jan 2014 16:11:01 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Closes_=2320253=3A_Merge_typo_fix?= Message-ID: <3f3Zqn45tmz7LpW@mail.python.org> http://hg.python.org/cpython/rev/2f54b55fcbfa changeset: 88478:2f54b55fcbfa parent: 88476:e38225008f2e parent: 88477:4f8ad9a4193f user: Zachary Ware date: Tue Jan 14 09:10:33 2014 -0600 summary: Closes #20253: Merge typo fix files: Doc/library/ipaddress.rst | 4 ++-- Misc/NEWS | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst --- a/Doc/library/ipaddress.rst +++ b/Doc/library/ipaddress.rst @@ -414,7 +414,7 @@ The broadcast address for the network. Packets sent to the broadcast address should be received by every host on the network. - .. attribute:: host mask + .. attribute:: hostmask The host mask, as a string. @@ -570,7 +570,7 @@ .. attribute:: is_link_local .. attribute:: network_address .. attribute:: broadcast_address - .. attribute:: host mask + .. attribute:: hostmask .. attribute:: with_prefixlen .. attribute:: compressed .. attribute:: exploded diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -475,6 +475,9 @@ Documentation ------------- +- Issue #20253: Fixed a typo in the ipaddress docs that advertised an + illegal attribute name. Found by INADA Naoki. + - Issue #18840: Introduce the json module in the tutorial, and deemphasize the pickle module. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 20:04:02 2014 From: python-checkins at python.org (ethan.furman) Date: Tue, 14 Jan 2014 20:04:02 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_461=3A_Adding_=25_and_=7B?= =?utf-8?q?=7D_formatting_to_bytes?= Message-ID: <3f3h0f2kmPz7LjX@mail.python.org> http://hg.python.org/peps/rev/cd79c7fab1ff changeset: 5345:cd79c7fab1ff user: Ethan Furman date: Tue Jan 14 11:04:10 2014 -0800 summary: PEP 461: Adding % and {} formatting to bytes files: pep-0461.txt | 142 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 142 insertions(+), 0 deletions(-) diff --git a/pep-0461.txt b/pep-0461.txt new file mode 100644 --- /dev/null +++ b/pep-0461.txt @@ -0,0 +1,142 @@ +PEP: XXX +Title: Adding % and {} formatting to bytes +Version: $Revision$ +Last-Modified: $Date$ +Author: Ethan Furman +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 2014-01-13 +Python-Version: 3.5 +Post-History: 2014-01-13 +Resolution: + + +Abstract +======== + +This PEP proposes adding the % and {} formatting operations from str to bytes. + + +Proposed semantics for bytes formatting +======================================= + +%-interpolation +--------------- + +All the numeric formatting codes (such as %x, %o, %e, %f, %g, etc.) +will be supported, and will work as they do for str, including the +padding, justification and other related modifiers. + +Example:: + + >>> b'%4x' % 10 + b' a' + +%c will insert a single byte, either from an int in range(256), or from +a bytes argument of length 1. + +Example: + + >>> b'%c' % 48 + b'0' + + >>> b'%c' % b'a' + b'a' + +%s, because it is the most general, has the most convoluted resolution: + + - input type is bytes? + pass it straight through + + - input type is numeric? + use its __xxx__ [1] [2] method and ascii-encode it (strictly) + + - input type is something else? + use its __bytes__ method; if there isn't one, raise an exception [3] + +Examples: + + >>> b'%s' % b'abc' + b'abc' + + >>> b'%s' % 3.14 + b'3.14' + + >>> b'%s' % 'hello world!' + Traceback (most recent call last): + ... + TypeError: 'hello world' has no __bytes__ method, perhaps you need to encode it? + +.. note:: + + Because the str type does not have a __bytes__ method, attempts to + directly use 'a string' as a bytes interpolation value will raise an + exception. To use 'string' values, they must be encoded or otherwise + transformed into a bytes sequence:: + + 'a string'.encode('latin-1') + + +format +------ + +The format mini language will be used as-is, with the behaviors as listed +for %-interpolation. + + +Open Questions +============== + +For %s there has been some discussion of trying to use the buffer protocol +(Py_buffer) before trying __bytes__. This question should be answered before +the PEP is implemented. + + +Proposed variations +=================== + +It has been suggested to use %b for bytes instead of %s. + + - Rejected as %b does not exist in Python 2.x %-interpolation, which is + why we are using %s. + +It has been proposed to automatically use .encode('ascii','strict') for str +arguments to %s. + + - Rejected as this would lead to intermittent failures. Better to have the + operation always fail so the trouble-spot can be correctly fixed. + +It has been proposed to have %s return the ascii-encoded repr when the value +is a str (b'%s' % 'abc' --> b"'abc'"). + + - Rejected as this would lead to hard to debug failures far from the problem + site. Better to have the operation always fail so the trouble-spot can be + easily fixed. + + +Foot notes +========== + +.. [1] Not sure if this should be the numeric __str__ or the numeric __repr__, + or if there's any difference +.. [2] Any proper numeric class would then have to provide an ascii + representation of its value, either via __repr__ or __str__ (whichever + we choose in [1]). +.. [3] TypeError, ValueError, or UnicodeEncodeError? + + +Copyright +========= + +This document has been placed in the public domain. + + +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + coding: utf-8 + End: -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Jan 14 20:12:13 2014 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 14 Jan 2014 20:12:13 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Fill_in_PEP_number_=28461=29?= =?utf-8?q?=2E?= Message-ID: <3f3hB54YWRz7LqC@mail.python.org> http://hg.python.org/peps/rev/a25f48998ad3 changeset: 5346:a25f48998ad3 user: Guido van Rossum date: Tue Jan 14 11:12:09 2014 -0800 summary: Fill in PEP number (461). files: pep-0461.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0461.txt b/pep-0461.txt --- a/pep-0461.txt +++ b/pep-0461.txt @@ -1,4 +1,4 @@ -PEP: XXX +PEP: 460 Title: Adding % and {} formatting to bytes Version: $Revision$ Last-Modified: $Date$ -- Repository URL: http://hg.python.org/peps From brett at python.org Tue Jan 14 20:14:48 2014 From: brett at python.org (Brett Cannon) Date: Tue, 14 Jan 2014 14:14:48 -0500 Subject: [Python-checkins] peps: Fill in PEP number (461). In-Reply-To: <3f3hB54YWRz7LqC@mail.python.org> References: <3f3hB54YWRz7LqC@mail.python.org> Message-ID: I think this was supposed to be 461, not 460 =) On Tue, Jan 14, 2014 at 2:12 PM, guido.van.rossum < python-checkins at python.org> wrote: > http://hg.python.org/peps/rev/a25f48998ad3 > changeset: 5346:a25f48998ad3 > user: Guido van Rossum > date: Tue Jan 14 11:12:09 2014 -0800 > summary: > Fill in PEP number (461). > > files: > pep-0461.txt | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > > diff --git a/pep-0461.txt b/pep-0461.txt > --- a/pep-0461.txt > +++ b/pep-0461.txt > @@ -1,4 +1,4 @@ > -PEP: XXX > +PEP: 460 > Title: Adding % and {} formatting to bytes > Version: $Revision$ > Last-Modified: $Date$ > > -- > Repository URL: http://hg.python.org/peps > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > https://mail.python.org/mailman/listinfo/python-checkins > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From python-checkins at python.org Tue Jan 14 20:23:43 2014 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 14 Jan 2014 20:23:43 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Fill_in_the_*correct*_PEP_num?= =?utf-8?q?ber_=28461=29=2E?= Message-ID: <3f3hRM2D1vz7Lnq@mail.python.org> http://hg.python.org/peps/rev/33c4cefde2cb changeset: 5347:33c4cefde2cb user: Guido van Rossum date: Tue Jan 14 11:23:36 2014 -0800 summary: Fill in the *correct* PEP number (461). files: pep-0461.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0461.txt b/pep-0461.txt --- a/pep-0461.txt +++ b/pep-0461.txt @@ -1,4 +1,4 @@ -PEP: 460 +PEP: 461 Title: Adding % and {} formatting to bytes Version: $Revision$ Last-Modified: $Date$ -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Jan 14 20:52:07 2014 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 14 Jan 2014 20:52:07 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_improve_an_error_message_i?= =?utf-8?q?n_clinic?= Message-ID: <3f3j472PHDz7LjW@mail.python.org> http://hg.python.org/cpython/rev/5c7195a99b41 changeset: 88479:5c7195a99b41 user: Antoine Pitrou date: Tue Jan 14 20:52:01 2014 +0100 summary: improve an error message in clinic files: Tools/clinic/clinic.py | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -970,7 +970,10 @@ if self.verify: computed = compute_checksum(output) if checksum != computed: - fail("Checksum mismatch!\nExpected: {}\nComputed: {}".format(checksum, computed)) + fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n" + "Suggested fix: remove all generated code including " + "the end marker, or use the '-f' option." + .format(checksum, computed)) else: # put back output output_lines = output.splitlines(keepends=True) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 21:00:33 2014 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 14 Jan 2014 21:00:33 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Clinic-ize_the_crypt_modul?= =?utf-8?q?e=2E_Derby!?= Message-ID: <3f3jFs4zq7z7Ljb@mail.python.org> http://hg.python.org/cpython/rev/c4a67824bbb8 changeset: 88480:c4a67824bbb8 user: Antoine Pitrou date: Tue Jan 14 21:00:27 2014 +0100 summary: Clinic-ize the crypt module. Derby! files: Modules/_cryptmodule.c | 71 +++++++++++++++++++++++------ 1 files changed, 56 insertions(+), 15 deletions(-) diff --git a/Modules/_cryptmodule.c b/Modules/_cryptmodule.c --- a/Modules/_cryptmodule.c +++ b/Modules/_cryptmodule.c @@ -7,31 +7,72 @@ /* Module crypt */ +/*[clinic input] +module crypt +[clinic start generated code]*/ +/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ -static PyObject *crypt_crypt(PyObject *self, PyObject *args) + +/*[clinic input] +crypt.crypt + + word: 's' + salt: 's' + / + +Hash a *word* with the given *salt* and return the hashed password. + +*word* will usually be a user's password. *salt* (either a random 2 or 16 +character string, possibly prefixed with $digit$ to indicate the method) +will be used to perturb the encryption algorithm and produce distinct +results for a given *word*. + +[clinic start generated code]*/ + +PyDoc_STRVAR(crypt_crypt__doc__, +"crypt(word, salt)\n" +"Hash a *word* with the given *salt* and return the hashed password.\n" +"\n" +"*word* will usually be a user\'s password. *salt* (either a random 2 or 16\n" +"character string, possibly prefixed with $digit$ to indicate the method)\n" +"will be used to perturb the encryption algorithm and produce distinct\n" +"results for a given *word*."); + +#define CRYPT_CRYPT_METHODDEF \ + {"crypt", (PyCFunction)crypt_crypt, METH_VARARGS, crypt_crypt__doc__}, + +static PyObject * +crypt_crypt_impl(PyModuleDef *module, const char *word, const char *salt); + +static PyObject * +crypt_crypt(PyModuleDef *module, PyObject *args) { - char *word, *salt; + PyObject *return_value = NULL; + const char *word; + const char *salt; - if (!PyArg_ParseTuple(args, "ss:crypt", &word, &salt)) { - return NULL; - } + if (!PyArg_ParseTuple(args, + "ss:crypt", + &word, &salt)) + goto exit; + return_value = crypt_crypt_impl(module, word, salt); + +exit: + return return_value; +} + +static PyObject * +crypt_crypt_impl(PyModuleDef *module, const char *word, const char *salt) +/*[clinic end generated code: checksum=a137540bf6862f9935fc112b8bb1d62d6dd1ad02]*/ +{ /* On some platforms (AtheOS) crypt returns NULL for an invalid salt. Return None in that case. XXX Maybe raise an exception? */ return Py_BuildValue("s", crypt(word, salt)); - } -PyDoc_STRVAR(crypt_crypt__doc__, -"crypt(word, salt) -> string\n\ -word will usually be a user's password. salt is a 2-character string\n\ -which will be used to select one of 4096 variations of DES. The characters\n\ -in salt must be either \".\", \"/\", or an alphanumeric character. Returns\n\ -the hashed password as a string, which will be composed of characters from\n\ -the same alphabet as the salt."); - static PyMethodDef crypt_methods[] = { - {"crypt", crypt_crypt, METH_VARARGS, crypt_crypt__doc__}, + CRYPT_CRYPT_METHODDEF {NULL, NULL} /* sentinel */ }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 21:02:49 2014 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 14 Jan 2014 21:02:49 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Replace_assert_with_a_prop?= =?utf-8?q?er_error?= Message-ID: <3f3jJT1Qnvz7Ljr@mail.python.org> http://hg.python.org/cpython/rev/0bb3c098c64a changeset: 88481:0bb3c098c64a user: Antoine Pitrou date: Tue Jan 14 21:02:43 2014 +0100 summary: Replace assert with a proper error files: Tools/clinic/clinic.py | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2343,9 +2343,11 @@ fail("Badly-formed annotation for " + full_name + ": " + returns) try: name, legacy, kwargs = self.parse_converter(module.body[0].returns) - assert not legacy + if legacy: + fail("Legacy converter {!r} not allowed as a return converter" + .format(name)) if name not in return_converters: - fail("Error: No available return converter called " + repr(name)) + fail("No available return converter called " + repr(name)) return_converter = return_converters[name](**kwargs) except ValueError: fail("Badly-formed annotation for " + full_name + ": " + returns) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 23:04:06 2014 From: python-checkins at python.org (zach.ware) Date: Tue, 14 Jan 2014 23:04:06 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIwMjU1?= =?utf-8?q?=3A_Update_the_about_and_bugs_pages=2E?= Message-ID: <3f3m0Q3sRMz7Lqn@mail.python.org> http://hg.python.org/cpython/rev/74d138cfe564 changeset: 88482:74d138cfe564 branch: 2.7 parent: 88465:1885e1768ff9 user: Zachary Ware date: Tue Jan 14 16:01:32 2014 -0600 summary: Issue #20255: Update the about and bugs pages. files: Doc/about.rst | 12 +++++------- Doc/bugs.rst | 30 +++++++++++++++++++++--------- Misc/NEWS | 2 ++ 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/Doc/about.rst b/Doc/about.rst --- a/Doc/about.rst +++ b/Doc/about.rst @@ -7,14 +7,15 @@ document processor specifically written for the Python documentation. .. _reStructuredText: http://docutils.sf.net/rst.html -.. _Sphinx: http://sphinx.pocoo.org/ +.. _Sphinx: http://sphinx-doc.org/ .. In the online version of these documents, you can submit comments and suggest changes directly on the documentation pages. -Development of the documentation and its toolchain takes place on the -docs at python.org mailing list. We're always looking for volunteers wanting -to help with the docs, so feel free to send a mail there! +Development of the documentation and its toolchain is an entirely volunteer +effort, just like Python itself. If you want to contribute, please take a +look at the :ref:`reporting-bugs` page for information on how to do so. New +volunteers are always welcome! Many thanks go to: @@ -26,9 +27,6 @@ `_ project from which Sphinx got many good ideas. -See :ref:`reporting-bugs` for information how to report bugs in this -documentation, or Python itself. - Contributors to the Python Documentation ---------------------------------------- diff --git a/Doc/bugs.rst b/Doc/bugs.rst --- a/Doc/bugs.rst +++ b/Doc/bugs.rst @@ -13,15 +13,17 @@ ================== If you find a bug in this documentation or would like to propose an improvement, -please send an e-mail to docs at python.org describing the bug and where you found -it. If you have a suggestion how to fix it, include that as well. +please submit a bug report on the :ref:`tracker `. If you +have a suggestion how to fix it, include that as well. -docs at python.org is a mailing list run by volunteers; your request will be -noticed, even if it takes a while to be processed. +If you're short on time, you can also email your bug report to docs at python.org. +'docs@' is a mailing list run by volunteers; your request will be noticed, +though it may take a while to be processed. -Of course, if you want a more persistent record of your issue, you can use the -issue tracker for documentation bugs as well. +.. seealso:: + `Documentation bugs`_ on the Python issue tracker +.. _using-the-tracker: Using the Python issue tracker ============================== @@ -62,9 +64,6 @@ .. seealso:: - `Python Developer's Guide `_ - Detailed description of the issue workflow and developers tools. - `How to Report Bugs Effectively `_ Article which goes into some detail about how to create a useful bug report. This describes what kind of information is useful and why it is useful. @@ -73,3 +72,16 @@ Information about writing a good bug report. Some of this is specific to the Mozilla project, but describes general good practices. + +Getting started contributing to Python yourself +=============================================== + +Beyond just reporting bugs that you find, you are also welcome to submit +patches to fix them. You can find more information on how to get started +patching Python in the `Python Developer's Guide`_. If you have questions, +the `core-mentorship mailing list`_ is a friendly place to get answers to +any and all questions pertaining to the process of fixing issues in Python. + +.. _Documentation bugs: http://bugs.python.org/issue?@filter=status&@filter=components&components=4&status=1&@columns=id,activity,title,status&@sort=-activity +.. _Python Developer's Guide: http://docs.python.org/devguide/ +.. _core-mentorship mailing list: https://mail.python.org/mailman/listinfo/core-mentorship/ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -199,6 +199,8 @@ Documentation ------------- +- Issue #20255: Update the about and bugs pages. + - Issue #18840: Introduce the json module in the tutorial, and deemphasize the pickle module. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 23:04:07 2014 From: python-checkins at python.org (zach.ware) Date: Tue, 14 Jan 2014 23:04:07 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMjU1?= =?utf-8?q?=3A_Update_the_about_and_bugs_pages=2E?= Message-ID: <3f3m0R6v9Zz7Lqn@mail.python.org> http://hg.python.org/cpython/rev/956b8afdaa3e changeset: 88483:956b8afdaa3e branch: 3.3 parent: 88477:4f8ad9a4193f user: Zachary Ware date: Tue Jan 14 16:03:11 2014 -0600 summary: Issue #20255: Update the about and bugs pages. files: Doc/about.rst | 12 +++++------- Doc/bugs.rst | 30 +++++++++++++++++++++--------- Misc/NEWS | 2 ++ 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/Doc/about.rst b/Doc/about.rst --- a/Doc/about.rst +++ b/Doc/about.rst @@ -7,14 +7,15 @@ document processor specifically written for the Python documentation. .. _reStructuredText: http://docutils.sf.net/rst.html -.. _Sphinx: http://sphinx.pocoo.org/ +.. _Sphinx: http://sphinx-doc.org/ .. In the online version of these documents, you can submit comments and suggest changes directly on the documentation pages. -Development of the documentation and its toolchain takes place on the -docs at python.org mailing list. We're always looking for volunteers wanting -to help with the docs, so feel free to send a mail there! +Development of the documentation and its toolchain is an entirely volunteer +effort, just like Python itself. If you want to contribute, please take a +look at the :ref:`reporting-bugs` page for information on how to do so. New +volunteers are always welcome! Many thanks go to: @@ -26,9 +27,6 @@ `_ project from which Sphinx got many good ideas. -See :ref:`reporting-bugs` for information how to report bugs in this -documentation, or Python itself. - Contributors to the Python Documentation ---------------------------------------- diff --git a/Doc/bugs.rst b/Doc/bugs.rst --- a/Doc/bugs.rst +++ b/Doc/bugs.rst @@ -13,15 +13,17 @@ ================== If you find a bug in this documentation or would like to propose an improvement, -please send an e-mail to docs at python.org describing the bug and where you found -it. If you have a suggestion how to fix it, include that as well. +please submit a bug report on the :ref:`tracker `. If you +have a suggestion how to fix it, include that as well. -docs at python.org is a mailing list run by volunteers; your request will be -noticed, even if it takes a while to be processed. +If you're short on time, you can also email your bug report to docs at python.org. +'docs@' is a mailing list run by volunteers; your request will be noticed, +though it may take a while to be processed. -Of course, if you want a more persistent record of your issue, you can use the -issue tracker for documentation bugs as well. +.. seealso:: + `Documentation bugs`_ on the Python issue tracker +.. _using-the-tracker: Using the Python issue tracker ============================== @@ -62,9 +64,6 @@ .. seealso:: - `Python Developer's Guide `_ - Detailed description of the issue workflow and developers tools. - `How to Report Bugs Effectively `_ Article which goes into some detail about how to create a useful bug report. This describes what kind of information is useful and why it is useful. @@ -73,3 +72,16 @@ Information about writing a good bug report. Some of this is specific to the Mozilla project, but describes general good practices. + +Getting started contributing to Python yourself +=============================================== + +Beyond just reporting bugs that you find, you are also welcome to submit +patches to fix them. You can find more information on how to get started +patching Python in the `Python Developer's Guide`_. If you have questions, +the `core-mentorship mailing list`_ is a friendly place to get answers to +any and all questions pertaining to the process of fixing issues in Python. + +.. _Documentation bugs: http://bugs.python.org/issue?@filter=status&@filter=components&components=4&status=1&@columns=id,activity,title,status&@sort=-activity +.. _Python Developer's Guide: http://docs.python.org/devguide/ +.. _core-mentorship mailing list: https://mail.python.org/mailman/listinfo/core-mentorship/ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -302,6 +302,8 @@ Documentation ------------- +- Issue #20255: Update the about and bugs pages. + - Issue #20253: Fixed a typo in the ipaddress docs that advertised an illegal attribute name. Found by INADA Naoki. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 23:04:09 2014 From: python-checkins at python.org (zach.ware) Date: Tue, 14 Jan 2014 23:04:09 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320255=3A_Update_the_about_and_bugs_pages=2E?= Message-ID: <3f3m0T34lwz7Lqn@mail.python.org> http://hg.python.org/cpython/rev/26236308d58b changeset: 88484:26236308d58b parent: 88481:0bb3c098c64a parent: 88483:956b8afdaa3e user: Zachary Ware date: Tue Jan 14 16:03:51 2014 -0600 summary: Issue #20255: Update the about and bugs pages. files: Doc/about.rst | 12 +++++------- Doc/bugs.rst | 30 +++++++++++++++++++++--------- Misc/NEWS | 2 ++ 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/Doc/about.rst b/Doc/about.rst --- a/Doc/about.rst +++ b/Doc/about.rst @@ -7,14 +7,15 @@ document processor specifically written for the Python documentation. .. _reStructuredText: http://docutils.sf.net/rst.html -.. _Sphinx: http://sphinx.pocoo.org/ +.. _Sphinx: http://sphinx-doc.org/ .. In the online version of these documents, you can submit comments and suggest changes directly on the documentation pages. -Development of the documentation and its toolchain takes place on the -docs at python.org mailing list. We're always looking for volunteers wanting -to help with the docs, so feel free to send a mail there! +Development of the documentation and its toolchain is an entirely volunteer +effort, just like Python itself. If you want to contribute, please take a +look at the :ref:`reporting-bugs` page for information on how to do so. New +volunteers are always welcome! Many thanks go to: @@ -26,9 +27,6 @@ `_ project from which Sphinx got many good ideas. -See :ref:`reporting-bugs` for information how to report bugs in this -documentation, or Python itself. - Contributors to the Python Documentation ---------------------------------------- diff --git a/Doc/bugs.rst b/Doc/bugs.rst --- a/Doc/bugs.rst +++ b/Doc/bugs.rst @@ -13,15 +13,17 @@ ================== If you find a bug in this documentation or would like to propose an improvement, -please send an e-mail to docs at python.org describing the bug and where you found -it. If you have a suggestion how to fix it, include that as well. +please submit a bug report on the :ref:`tracker `. If you +have a suggestion how to fix it, include that as well. -docs at python.org is a mailing list run by volunteers; your request will be -noticed, even if it takes a while to be processed. +If you're short on time, you can also email your bug report to docs at python.org. +'docs@' is a mailing list run by volunteers; your request will be noticed, +though it may take a while to be processed. -Of course, if you want a more persistent record of your issue, you can use the -issue tracker for documentation bugs as well. +.. seealso:: + `Documentation bugs`_ on the Python issue tracker +.. _using-the-tracker: Using the Python issue tracker ============================== @@ -62,9 +64,6 @@ .. seealso:: - `Python Developer's Guide `_ - Detailed description of the issue workflow and developers tools. - `How to Report Bugs Effectively `_ Article which goes into some detail about how to create a useful bug report. This describes what kind of information is useful and why it is useful. @@ -73,3 +72,16 @@ Information about writing a good bug report. Some of this is specific to the Mozilla project, but describes general good practices. + +Getting started contributing to Python yourself +=============================================== + +Beyond just reporting bugs that you find, you are also welcome to submit +patches to fix them. You can find more information on how to get started +patching Python in the `Python Developer's Guide`_. If you have questions, +the `core-mentorship mailing list`_ is a friendly place to get answers to +any and all questions pertaining to the process of fixing issues in Python. + +.. _Documentation bugs: http://bugs.python.org/issue?@filter=status&@filter=components&components=4&status=1&@columns=id,activity,title,status&@sort=-activity +.. _Python Developer's Guide: http://docs.python.org/devguide/ +.. _core-mentorship mailing list: https://mail.python.org/mailman/listinfo/core-mentorship/ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -475,6 +475,8 @@ Documentation ------------- +- Issue #20255: Update the about and bugs pages. + - Issue #20253: Fixed a typo in the ipaddress docs that advertised an illegal attribute name. Found by INADA Naoki. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 14 23:49:04 2014 From: python-checkins at python.org (meador.inge) Date: Tue, 14 Jan 2014 23:49:04 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_minor_bug_in_dict=2E?= =?utf-8?b?X19jb250YWluc19fIGRvY3N0cmluZy4=?= Message-ID: <3f3n0J26FVz7Lr7@mail.python.org> http://hg.python.org/cpython/rev/f35b3a86ade3 changeset: 88485:f35b3a86ade3 user: Meador Inge date: Tue Jan 14 16:48:31 2014 -0600 summary: Fix minor bug in dict.__contains__ docstring. When dict got clinicized in 8fde1a2c94dc for Issue #16612 an erroneous trailing quote was left in the clinic docstring summary line. files: Objects/dictobject.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2172,19 +2172,19 @@ key: object / -True if D has a key k, else False" +True if D has a key k, else False. [clinic start generated code]*/ PyDoc_STRVAR(dict___contains____doc__, "__contains__(key)\n" -"True if D has a key k, else False\""); +"True if D has a key k, else False."); #define DICT___CONTAINS___METHODDEF \ {"__contains__", (PyCFunction)dict___contains__, METH_O|METH_COEXIST, dict___contains____doc__}, static PyObject * dict___contains__(PyObject *self, PyObject *key) -/*[clinic end generated code: checksum=3bbac5ce898ae630d9668fa1c8b3afb645ff22e8]*/ +/*[clinic end generated code: checksum=402ddb624ba1e4db764bfdfbbee6c1c59d1a11fa]*/ { register PyDictObject *mp = (PyDictObject *)self; Py_hash_t hash; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 15 00:10:27 2014 From: python-checkins at python.org (larry.hastings) Date: Wed, 15 Jan 2014 00:10:27 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Updated_PEP_429=2C_release_sc?= =?utf-8?q?hedule_for_3=2E4=3A_new_beta=2C_schedule_slippage=2E?= Message-ID: <3f3nSz0Jddz7LnB@mail.python.org> http://hg.python.org/peps/rev/5fa5b0bcf0cf changeset: 5348:5fa5b0bcf0cf user: Larry Hastings date: Tue Jan 14 15:10:09 2014 -0800 summary: Updated PEP 429, release schedule for 3.4: new beta, schedule slippage. files: pep-0429.txt | 23 ++++++++++++----------- 1 files changed, 12 insertions(+), 11 deletions(-) diff --git a/pep-0429.txt b/pep-0429.txt --- a/pep-0429.txt +++ b/pep-0429.txt @@ -19,7 +19,7 @@ .. Small features may be added up to the first beta release. Bugs may be fixed until the final release, - which is planned for February 2014. + which is planned for March 2014. Release Manager and Crew @@ -45,17 +45,12 @@ (Beta 1 is also "feature freeze"--no new features beyond this point.) -.. The anticipated schedule for future releases: +The anticipated schedule for future releases: -These *were* the release dates for Python 3.4: - -- 3.4.0 candidate 1: January 19, 2014 -- 3.4.0 candidate 2: February 2, 2014 -- 3.4.0 final: February 23, 2014 - -These release dates are no longer accurate; we plan to add a third beta, -and slip the whole schedule by several weeks. The details have not been -finalized--we'll update this release schedule once they are. +- 3.4.0 beta 3: January 25, 2014 +- 3.4.0 candidate 1: February 8, 2014 +- 3.4.0 candidate 2: February 22, 2014 +- 3.4.0 final: March 15, 2014 .. don't forget to update final date above as well @@ -66,6 +61,12 @@ for download on python.org depends on the schedules of the crew and the existence of any release-blocking issues. +Since posting the original schedule, we've added "beta 3" and slipped +the subsequent releases by three weeks. This is because of last-minute +changes due to adoption of "Argument Clinic". The extra beta will +give these changes extra time to mature. + + Features for 3.4 ================ -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Jan 15 00:15:45 2014 From: python-checkins at python.org (larry.hastings) Date: Wed, 15 Jan 2014 00:15:45 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Whoops=2C_had_an_off-by-one_e?= =?utf-8?q?rror_on_all_the_future_release_dates_for_3=2E4=2E?= Message-ID: <3f3nb52qD5z7LjM@mail.python.org> http://hg.python.org/peps/rev/53026124cec7 changeset: 5349:53026124cec7 user: Larry Hastings date: Tue Jan 14 15:15:32 2014 -0800 summary: Whoops, had an off-by-one error on all the future release dates for 3.4. files: pep-0429.txt | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pep-0429.txt b/pep-0429.txt --- a/pep-0429.txt +++ b/pep-0429.txt @@ -47,10 +47,10 @@ The anticipated schedule for future releases: -- 3.4.0 beta 3: January 25, 2014 -- 3.4.0 candidate 1: February 8, 2014 -- 3.4.0 candidate 2: February 22, 2014 -- 3.4.0 final: March 15, 2014 +- 3.4.0 beta 3: January 26, 2014 +- 3.4.0 candidate 1: February 9, 2014 +- 3.4.0 candidate 2: February 23, 2014 +- 3.4.0 final: March 16, 2014 .. don't forget to update final date above as well -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Jan 15 03:22:53 2014 From: python-checkins at python.org (ethan.furman) Date: Wed, 15 Jan 2014 03:22:53 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_461=3A_updates_to_=25s_an?= =?utf-8?q?d_Open_Questions?= Message-ID: <3f3sl13G5Jz7LkK@mail.python.org> http://hg.python.org/peps/rev/ded763368fae changeset: 5350:ded763368fae user: Ethan Furman date: Tue Jan 14 18:23:03 2014 -0800 summary: PEP 461: updates to %s and Open Questions files: pep-0461.txt | 26 ++++++++++++++++---------- 1 files changed, 16 insertions(+), 10 deletions(-) diff --git a/pep-0461.txt b/pep-0461.txt --- a/pep-0461.txt +++ b/pep-0461.txt @@ -44,13 +44,10 @@ >>> b'%c' % b'a' b'a' -%s, because it is the most general, has the most convoluted resolution: +%s is a restricted in what it will accept:: - - input type is bytes? - pass it straight through - - - input type is numeric? - use its __xxx__ [1] [2] method and ascii-encode it (strictly) + - input type supports Py_buffer? + use it to collect the necessary bytes - input type is something else? use its __bytes__ method; if there isn't one, raise an exception [3] @@ -61,7 +58,9 @@ b'abc' >>> b'%s' % 3.14 - b'3.14' + Traceback (most recent call last): + ... + TypeError: 3.14 has no __bytes__ method >>> b'%s' % 'hello world!' Traceback (most recent call last): @@ -77,6 +76,11 @@ 'a string'.encode('latin-1') +Unsupported % format codes +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +%r (which calls __repr__) is not supported + format ------ @@ -88,14 +92,16 @@ Open Questions ============== -For %s there has been some discussion of trying to use the buffer protocol -(Py_buffer) before trying __bytes__. This question should be answered before -the PEP is implemented. +Do we need no support all the numeric format codes? The floating point +exponential formats seem less appropriate, for example. Proposed variations =================== +It was suggested to let %s accept numbers, but since numbers have their own +format codes this idea was discarded. + It has been suggested to use %b for bytes instead of %s. - Rejected as %b does not exist in Python 2.x %-interpolation, which is -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Jan 15 07:23:10 2014 From: python-checkins at python.org (larry.hastings) Date: Wed, 15 Jan 2014 07:23:10 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320268=3A_Argument?= =?utf-8?q?_Clinic_now_supports_cloning_the_parameters?= Message-ID: <3f3z4G3K1rz7LjX@mail.python.org> http://hg.python.org/cpython/rev/565773aabafb changeset: 88486:565773aabafb user: Larry Hastings date: Tue Jan 14 22:22:41 2014 -0800 summary: Issue #20268: Argument Clinic now supports cloning the parameters and return converter from existing functions. files: Doc/howto/clinic.rst | 43 ++++++++++++++++++++++++++++ Misc/NEWS | 3 + Tools/clinic/clinic.py | 46 ++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 0 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -847,6 +847,49 @@ just run ``Tools/clinic/clinic.py --converters`` for the full list. +Cloning existing functions +-------------------------- + +If you have a number of functions that look similar, you may be able to +use Clinic's "clone" feature. When you clone an existing function, +you reuse: + +* its parameters, including + + * their names, + + * their converters, with all parameters, + + * their default values, + + * their per-parameter docstrings, + + * their *kind* (whether they're positional only, + positional or keyword, or keyword only), and + +* its return converter. + +The only thing not copied from the original function is its docstring; +the syntax allows you to specify a new docstring. + +Here's the syntax for cloning a function:: + + /*[clinic input] + module.class.new_function [as c_basename] = module.class.existing_function + + Docstring for new_function goes here. + [clinic start generated code]*/ + +(The functions can be in different modules or classes. I wrote +``module.class`` in the sample just to illustrate that you must +use the full path to *both* functions.) + +Sorry, there's no syntax for partially-cloning a function, or cloning a function +then modifying it. Cloning is an all-or nothing proposition. + +Also, the function you are cloning from must have been previously defined +in the current file. + Calling Python code ------------------- diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -86,6 +86,9 @@ Tools/Demos ----------- +- Issue #20268: Argument Clinic now supports cloning the parameters and + return converter of existing functions. + - Issue #20228: Argument Clinic now has special support for class special methods. diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2301,6 +2301,12 @@ # modulename.fnname [as c_basename] [-> return annotation] # square brackets denote optional syntax. # + # alternatively: + # modulename.fnname [as c_basename] = modulename.existing_fn_name + # clones the parameters and return converter from that + # function. you can't modify them. you must enter a + # new docstring. + # # (but we might find a directive first!) # # this line is permitted to start with whitespace. @@ -2319,6 +2325,45 @@ directive(*fields[1:]) return + # are we cloning? + before, equals, existing = line.rpartition('=') + if equals: + full_name, _, c_basename = before.partition(' as ') + full_name = full_name.strip() + c_basename = c_basename.strip() + existing = existing.strip() + if (is_legal_py_identifier(full_name) and + (not c_basename or is_legal_c_identifier(c_basename)) and + is_legal_py_identifier(existing)): + # we're cloning! + fields = [x.strip() for x in existing.split('.')] + function_name = fields.pop() + module, cls = self.clinic._module_and_class(fields) + + for existing_function in (cls or module).functions: + if existing_function.name == function_name: + break + else: + existing_function = None + if not existing_function: + fail("Couldn't find existing function " + repr(existing) + "!") + + fields = [x.strip() for x in full_name.split('.')] + function_name = fields.pop() + module, cls = self.clinic._module_and_class(fields) + + if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist): + fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)") + self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename, + return_converter=existing_function.return_converter, kind=existing_function.kind, coexist=existing_function.coexist) + + self.function.parameters = existing_function.parameters.copy() + + self.block.signatures.append(self.function) + (cls or module).functions.append(self.function) + self.next(self.state_function_docstring) + return + line, _, returns = line.partition('->') full_name, _, c_basename = line.partition(' as ') @@ -2373,6 +2418,7 @@ self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename, return_converter=return_converter, kind=self.kind, coexist=self.coexist) self.block.signatures.append(self.function) + (cls or module).functions.append(self.function) self.next(self.state_parameters_start) # Now entering the parameters section. The rules, formally stated: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 15 08:37:16 2014 From: python-checkins at python.org (larry.hastings) Date: Wed, 15 Jan 2014 08:37:16 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Minor_formatting_touchup_on_3?= =?utf-8?q?=2E4_release_schedule=2E?= Message-ID: <3f40jm5lXmz7LjR@mail.python.org> http://hg.python.org/peps/rev/c6db02089eb8 changeset: 5351:c6db02089eb8 user: Larry Hastings date: Tue Jan 14 23:37:00 2014 -0800 summary: Minor formatting touchup on 3.4 release schedule. files: pep-0429.txt | 6 ++---- 1 files changed, 2 insertions(+), 4 deletions(-) diff --git a/pep-0429.txt b/pep-0429.txt --- a/pep-0429.txt +++ b/pep-0429.txt @@ -75,13 +75,11 @@ * PEP 428, a "pathlib" module providing object-oriented filesystem paths * PEP 435, a standardized "enum" module -* PEP 436, a build enhancement that will help generate introspection - information for builtins +* PEP 436, a build enhancement that will help generate introspection information for builtins * PEP 442, improved semantics for object finalization * PEP 443, adding single-dispatch generic functions to the standard library * PEP 445, a new C API for implementing custom memory allocators -* PEP 446, changing file descriptors to not be inherited by default - in subprocesses +* PEP 446, changing file descriptors to not be inherited by default in subprocesses * PEP 450, a new "statistics" module * PEP 451, standardizing module metadata for Python's module import system * PEP 453, a bundled installer for the *pip* package manager -- Repository URL: http://hg.python.org/peps From solipsis at pitrou.net Wed Jan 15 09:47:46 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 15 Jan 2014 09:47:46 +0100 Subject: [Python-checkins] Daily reference leaks (f35b3a86ade3): sum=0 Message-ID: results for f35b3a86ade3 on branch "default" -------------------------------------------- test_site leaked [2, 0, -2] references, sum=0 test_site leaked [2, 0, -2] memory blocks, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogrYcRog', '-x'] From python-checkins at python.org Wed Jan 15 11:32:59 2014 From: python-checkins at python.org (ronald.oussoren) Date: Wed, 15 Jan 2014 11:32:59 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2314455=3A_Fix_some?= =?utf-8?q?_issues_with_plistlib?= Message-ID: <3f44cW44MQzRVl@mail.python.org> http://hg.python.org/cpython/rev/1a8149ba3000 changeset: 88487:1a8149ba3000 user: Ronald Oussoren date: Wed Jan 15 11:32:35 2014 +0100 summary: Issue #14455: Fix some issues with plistlib * Negative integer support in binary plists was broken * Better exception for invalid data * Fix the versionadded/versionchanged markup in the documentation * Add the interface cleanup to what's new for 3.4 files: Doc/library/plistlib.rst | 19 +- Doc/whatsnew/3.4.rst | 2 + Lib/plistlib.py | 22 +- Lib/test/test_plistlib.py | 156 +++++++---- Mac/Tools/plistlib_generate_testdata.py | 8 + Misc/NEWS | 2 + 6 files changed, 138 insertions(+), 71 deletions(-) diff --git a/Doc/library/plistlib.rst b/Doc/library/plistlib.rst --- a/Doc/library/plistlib.rst +++ b/Doc/library/plistlib.rst @@ -79,6 +79,8 @@ Load a plist from a bytes object. See :func:`load` for an explanation of the keyword arguments. + .. versionadded:: 3.4 + .. function:: dump(value, fp, \*, fmt=FMT_XML, sort_keys=True, skipkeys=False) @@ -102,8 +104,17 @@ A :exc:`TypeError` will be raised if the object is of an unsupported type or a container that contains objects of unsupported types. - .. versionchanged:: 3.4 - Added the *fmt*, *sort_keys* and *skipkeys* arguments. + An :exc:`OverflowError` will be raised for integer values that cannot + be represented in (binary) plist files. + + .. warning:: + + For compatibility with Apple's libraries it is possible to write + an integer in the range from 2 ** 63 upto (and including) 2 ** 64 + to binary plists, even though these will be read back as negative + values. + + .. versionadded: 3.4 .. function:: dumps(value, \*, fmt=FMT_XML, sort_keys=True, skipkeys=False) @@ -112,6 +123,7 @@ the documentation for :func:`dump` for an explanation of the keyword arguments of this function. + .. versionadded: 3.4 The following functions are deprecated: @@ -162,9 +174,6 @@ .. deprecated:: 3.4 Use :func:`dumps` instead. - .. versionchanged:: 3.4 - Added the *fmt*, *sort_keys* and *skipkeys* arguments. - The following classes are available: 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 @@ -132,6 +132,8 @@ a new :mod:`~email.message.Message` subclass (:class:`~email.contentmanager.EmailMessage`) that :ref:`simplify MIME handling ` (:issue:`18891`). +* :mod:`plistlib` has a cleaned up interface and support for binary + plist files (:issue:`14455`) CPython implementation improvements: diff --git a/Lib/plistlib.py b/Lib/plistlib.py --- a/Lib/plistlib.py +++ b/Lib/plistlib.py @@ -478,7 +478,10 @@ self.simple_element("false") elif isinstance(value, int): - self.simple_element("integer", "%d" % value) + if -1 << 63 <= value < 1 << 64: + self.simple_element("integer", "%d" % value) + else: + raise OverflowError(value) elif isinstance(value, float): self.simple_element("real", repr(value)) @@ -665,7 +668,8 @@ return b'' elif tokenH == 0x10: # int - return int.from_bytes(self._fp.read(1 << tokenL), 'big') + return int.from_bytes(self._fp.read(1 << tokenL), + 'big', signed=tokenL >= 3) elif token == 0x22: # real return struct.unpack('>f', self._fp.read(4))[0] @@ -871,14 +875,22 @@ self._fp.write(b'\x09') elif isinstance(value, int): - if value < 1 << 8: + if value < 0: + try: + self._fp.write(struct.pack('>Bq', 0x13, value)) + except struct.error: + raise OverflowError(value) + elif value < 1 << 8: self._fp.write(struct.pack('>BB', 0x10, value)) elif value < 1 << 16: self._fp.write(struct.pack('>BH', 0x11, value)) elif value < 1 << 32: self._fp.write(struct.pack('>BL', 0x12, value)) else: - self._fp.write(struct.pack('>BQ', 0x13, value)) + try: + self._fp.write(struct.pack('>BQ', 0x13, value)) + except struct.error: + raise OverflowError(value) elif isinstance(value, float): self._fp.write(struct.pack('>Bd', 0x23, value)) @@ -933,7 +945,7 @@ self._fp.write(struct.pack('>' + self._ref_format * s, *valRefs)) else: - raise InvalidFileException() + raise TypeError(value) def _is_fmt_binary(header): 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 @@ -7,6 +7,7 @@ import codecs import binascii import collections +import struct from test import support from io import BytesIO @@ -19,68 +20,74 @@ PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NU WVBFIHBsaXN0IFBVQkxJQyAiLS8vQXBwbGUvL0RURCBQTElTVCAxLjAvL0VO IiAiaHR0cDovL3d3dy5hcHBsZS5jb20vRFREcy9Qcm9wZXJ0eUxpc3QtMS4w - LmR0ZCI+CjxwbGlzdCB2ZXJzaW9uPSIxLjAiPgo8ZGljdD4KCTxrZXk+YURh - dGU8L2tleT4KCTxkYXRlPjIwMDQtMTAtMjZUMTA6MzM6MzNaPC9kYXRlPgoJ - PGtleT5hRGljdDwva2V5PgoJPGRpY3Q+CgkJPGtleT5hRmFsc2VWYWx1ZTwv - a2V5PgoJCTxmYWxzZS8+CgkJPGtleT5hVHJ1ZVZhbHVlPC9rZXk+CgkJPHRy - dWUvPgoJCTxrZXk+YVVuaWNvZGVWYWx1ZTwva2V5PgoJCTxzdHJpbmc+TcOk - c3NpZywgTWHDnzwvc3RyaW5nPgoJCTxrZXk+YW5vdGhlclN0cmluZzwva2V5 - PgoJCTxzdHJpbmc+Jmx0O2hlbGxvICZhbXA7ICdoaScgdGhlcmUhJmd0Ozwv - c3RyaW5nPgoJCTxrZXk+ZGVlcGVyRGljdDwva2V5PgoJCTxkaWN0PgoJCQk8 - a2V5PmE8L2tleT4KCQkJPGludGVnZXI+MTc8L2ludGVnZXI+CgkJCTxrZXk+ - Yjwva2V5PgoJCQk8cmVhbD4zMi41PC9yZWFsPgoJCQk8a2V5PmM8L2tleT4K - CQkJPGFycmF5PgoJCQkJPGludGVnZXI+MTwvaW50ZWdlcj4KCQkJCTxpbnRl - Z2VyPjI8L2ludGVnZXI+CgkJCQk8c3RyaW5nPnRleHQ8L3N0cmluZz4KCQkJ - PC9hcnJheT4KCQk8L2RpY3Q+Cgk8L2RpY3Q+Cgk8a2V5PmFGbG9hdDwva2V5 - PgoJPHJlYWw+MC41PC9yZWFsPgoJPGtleT5hTGlzdDwva2V5PgoJPGFycmF5 - PgoJCTxzdHJpbmc+QTwvc3RyaW5nPgoJCTxzdHJpbmc+Qjwvc3RyaW5nPgoJ - CTxpbnRlZ2VyPjEyPC9pbnRlZ2VyPgoJCTxyZWFsPjMyLjU8L3JlYWw+CgkJ - PGFycmF5PgoJCQk8aW50ZWdlcj4xPC9pbnRlZ2VyPgoJCQk8aW50ZWdlcj4y - PC9pbnRlZ2VyPgoJCQk8aW50ZWdlcj4zPC9pbnRlZ2VyPgoJCTwvYXJyYXk+ - Cgk8L2FycmF5PgoJPGtleT5hU3RyaW5nPC9rZXk+Cgk8c3RyaW5nPkRvb2Rh - aDwvc3RyaW5nPgoJPGtleT5hbkVtcHR5RGljdDwva2V5PgoJPGRpY3QvPgoJ - PGtleT5hbkVtcHR5TGlzdDwva2V5PgoJPGFycmF5Lz4KCTxrZXk+YW5JbnQ8 - L2tleT4KCTxpbnRlZ2VyPjcyODwvaW50ZWdlcj4KCTxrZXk+bmVzdGVkRGF0 - YTwva2V5PgoJPGFycmF5PgoJCTxkYXRhPgoJCVBHeHZkSE1nYjJZZ1ltbHVZ - WEo1SUdkMWJtcytBQUVDQXp4c2IzUnpJRzltSUdKcGJtRnllU0JuZFc1cgoJ - CVBnQUJBZ004Ykc5MGN5QnZaaUJpYVc1aGNua2daM1Z1YXo0QUFRSURQR3h2 - ZEhNZ2IyWWdZbWx1WVhKNQoJCUlHZDFibXMrQUFFQ0F6eHNiM1J6SUc5bUlH - SnBibUZ5ZVNCbmRXNXJQZ0FCQWdNOGJHOTBjeUJ2WmlCaQoJCWFXNWhjbmtn - WjNWdWF6NEFBUUlEUEd4dmRITWdiMllnWW1sdVlYSjVJR2QxYm1zK0FBRUNB - enhzYjNSegoJCUlHOW1JR0pwYm1GeWVTQm5kVzVyUGdBQkFnTThiRzkwY3lC - dlppQmlhVzVoY25rZ1ozVnVhejRBQVFJRAoJCVBHeHZkSE1nYjJZZ1ltbHVZ - WEo1SUdkMWJtcytBQUVDQXc9PQoJCTwvZGF0YT4KCTwvYXJyYXk+Cgk8a2V5 - PnNvbWVEYXRhPC9rZXk+Cgk8ZGF0YT4KCVBHSnBibUZ5ZVNCbmRXNXJQZz09 - Cgk8L2RhdGE+Cgk8a2V5PnNvbWVNb3JlRGF0YTwva2V5PgoJPGRhdGE+CglQ - R3h2ZEhNZ2IyWWdZbWx1WVhKNUlHZDFibXMrQUFFQ0F6eHNiM1J6SUc5bUlH - SnBibUZ5ZVNCbmRXNXJQZ0FCQWdNOAoJYkc5MGN5QnZaaUJpYVc1aGNua2da - M1Z1YXo0QUFRSURQR3h2ZEhNZ2IyWWdZbWx1WVhKNUlHZDFibXMrQUFFQ0F6 - eHMKCWIzUnpJRzltSUdKcGJtRnllU0JuZFc1clBnQUJBZ004Ykc5MGN5QnZa - aUJpYVc1aGNua2daM1Z1YXo0QUFRSURQR3h2CglkSE1nYjJZZ1ltbHVZWEo1 - SUdkMWJtcytBQUVDQXp4c2IzUnpJRzltSUdKcGJtRnllU0JuZFc1clBnQUJB - Z004Ykc5MAoJY3lCdlppQmlhVzVoY25rZ1ozVnVhejRBQVFJRFBHeHZkSE1n - YjJZZ1ltbHVZWEo1SUdkMWJtcytBQUVDQXc9PQoJPC9kYXRhPgoJPGtleT7D - hWJlbnJhYTwva2V5PgoJPHN0cmluZz5UaGF0IHdhcyBhIHVuaWNvZGUga2V5 - Ljwvc3RyaW5nPgo8L2RpY3Q+CjwvcGxpc3Q+Cg=='''), + LmR0ZCI+CjxwbGlzdCB2ZXJzaW9uPSIxLjAiPgo8ZGljdD4KCTxrZXk+YUJp + Z0ludDwva2V5PgoJPGludGVnZXI+OTIyMzM3MjAzNjg1NDc3NTc2NDwvaW50 + ZWdlcj4KCTxrZXk+YURhdGU8L2tleT4KCTxkYXRlPjIwMDQtMTAtMjZUMTA6 + MzM6MzNaPC9kYXRlPgoJPGtleT5hRGljdDwva2V5PgoJPGRpY3Q+CgkJPGtl + eT5hRmFsc2VWYWx1ZTwva2V5PgoJCTxmYWxzZS8+CgkJPGtleT5hVHJ1ZVZh + bHVlPC9rZXk+CgkJPHRydWUvPgoJCTxrZXk+YVVuaWNvZGVWYWx1ZTwva2V5 + PgoJCTxzdHJpbmc+TcOkc3NpZywgTWHDnzwvc3RyaW5nPgoJCTxrZXk+YW5v + dGhlclN0cmluZzwva2V5PgoJCTxzdHJpbmc+Jmx0O2hlbGxvICZhbXA7ICdo + aScgdGhlcmUhJmd0Ozwvc3RyaW5nPgoJCTxrZXk+ZGVlcGVyRGljdDwva2V5 + PgoJCTxkaWN0PgoJCQk8a2V5PmE8L2tleT4KCQkJPGludGVnZXI+MTc8L2lu + dGVnZXI+CgkJCTxrZXk+Yjwva2V5PgoJCQk8cmVhbD4zMi41PC9yZWFsPgoJ + CQk8a2V5PmM8L2tleT4KCQkJPGFycmF5PgoJCQkJPGludGVnZXI+MTwvaW50 + ZWdlcj4KCQkJCTxpbnRlZ2VyPjI8L2ludGVnZXI+CgkJCQk8c3RyaW5nPnRl + eHQ8L3N0cmluZz4KCQkJPC9hcnJheT4KCQk8L2RpY3Q+Cgk8L2RpY3Q+Cgk8 + a2V5PmFGbG9hdDwva2V5PgoJPHJlYWw+MC41PC9yZWFsPgoJPGtleT5hTGlz + dDwva2V5PgoJPGFycmF5PgoJCTxzdHJpbmc+QTwvc3RyaW5nPgoJCTxzdHJp + bmc+Qjwvc3RyaW5nPgoJCTxpbnRlZ2VyPjEyPC9pbnRlZ2VyPgoJCTxyZWFs + PjMyLjU8L3JlYWw+CgkJPGFycmF5PgoJCQk8aW50ZWdlcj4xPC9pbnRlZ2Vy + PgoJCQk8aW50ZWdlcj4yPC9pbnRlZ2VyPgoJCQk8aW50ZWdlcj4zPC9pbnRl + Z2VyPgoJCTwvYXJyYXk+Cgk8L2FycmF5PgoJPGtleT5hTmVnYXRpdmVCaWdJ + bnQ8L2tleT4KCTxpbnRlZ2VyPi04MDAwMDAwMDAwMDwvaW50ZWdlcj4KCTxr + ZXk+YU5lZ2F0aXZlSW50PC9rZXk+Cgk8aW50ZWdlcj4tNTwvaW50ZWdlcj4K + CTxrZXk+YVN0cmluZzwva2V5PgoJPHN0cmluZz5Eb29kYWg8L3N0cmluZz4K + CTxrZXk+YW5FbXB0eURpY3Q8L2tleT4KCTxkaWN0Lz4KCTxrZXk+YW5FbXB0 + eUxpc3Q8L2tleT4KCTxhcnJheS8+Cgk8a2V5PmFuSW50PC9rZXk+Cgk8aW50 + ZWdlcj43Mjg8L2ludGVnZXI+Cgk8a2V5Pm5lc3RlZERhdGE8L2tleT4KCTxh + cnJheT4KCQk8ZGF0YT4KCQlQR3h2ZEhNZ2IyWWdZbWx1WVhKNUlHZDFibXMr + QUFFQ0F6eHNiM1J6SUc5bUlHSnBibUZ5ZVNCbmRXNXIKCQlQZ0FCQWdNOGJH + OTBjeUJ2WmlCaWFXNWhjbmtnWjNWdWF6NEFBUUlEUEd4dmRITWdiMllnWW1s + dVlYSjUKCQlJR2QxYm1zK0FBRUNBenhzYjNSeklHOW1JR0pwYm1GeWVTQm5k + VzVyUGdBQkFnTThiRzkwY3lCdlppQmkKCQlhVzVoY25rZ1ozVnVhejRBQVFJ + RFBHeHZkSE1nYjJZZ1ltbHVZWEo1SUdkMWJtcytBQUVDQXp4c2IzUnoKCQlJ + RzltSUdKcGJtRnllU0JuZFc1clBnQUJBZ004Ykc5MGN5QnZaaUJpYVc1aGNu + a2daM1Z1YXo0QUFRSUQKCQlQR3h2ZEhNZ2IyWWdZbWx1WVhKNUlHZDFibXMr + QUFFQ0F3PT0KCQk8L2RhdGE+Cgk8L2FycmF5PgoJPGtleT5zb21lRGF0YTwv + a2V5PgoJPGRhdGE+CglQR0pwYm1GeWVTQm5kVzVyUGc9PQoJPC9kYXRhPgoJ + PGtleT5zb21lTW9yZURhdGE8L2tleT4KCTxkYXRhPgoJUEd4dmRITWdiMlln + WW1sdVlYSjVJR2QxYm1zK0FBRUNBenhzYjNSeklHOW1JR0pwYm1GeWVTQm5k + VzVyUGdBQkFnTTgKCWJHOTBjeUJ2WmlCaWFXNWhjbmtnWjNWdWF6NEFBUUlE + UEd4dmRITWdiMllnWW1sdVlYSjVJR2QxYm1zK0FBRUNBenhzCgliM1J6SUc5 + bUlHSnBibUZ5ZVNCbmRXNXJQZ0FCQWdNOGJHOTBjeUJ2WmlCaWFXNWhjbmtn + WjNWdWF6NEFBUUlEUEd4dgoJZEhNZ2IyWWdZbWx1WVhKNUlHZDFibXMrQUFF + Q0F6eHNiM1J6SUc5bUlHSnBibUZ5ZVNCbmRXNXJQZ0FCQWdNOGJHOTAKCWN5 + QnZaaUJpYVc1aGNua2daM1Z1YXo0QUFRSURQR3h2ZEhNZ2IyWWdZbWx1WVhK + NUlHZDFibXMrQUFFQ0F3PT0KCTwvZGF0YT4KCTxrZXk+w4ViZW5yYWE8L2tl + eT4KCTxzdHJpbmc+VGhhdCB3YXMgYSB1bmljb2RlIGtleS48L3N0cmluZz4K + PC9kaWN0Pgo8L3BsaXN0Pgo='''), plistlib.FMT_BINARY: binascii.a2b_base64(b''' - YnBsaXN0MDDcAQIDBAUGBwgJCgsMDQ4iIykqKywtLy4wVWFEYXRlVWFEaWN0 - VmFGbG9hdFVhTGlzdFdhU3RyaW5nW2FuRW1wdHlEaWN0W2FuRW1wdHlMaXN0 - VWFuSW50Wm5lc3RlZERhdGFYc29tZURhdGFcc29tZU1vcmVEYXRhZwDFAGIA - ZQBuAHIAYQBhM0GcuX30AAAA1Q8QERITFBUWFxhbYUZhbHNlVmFsdWVaYVRy - dWVWYWx1ZV1hVW5pY29kZVZhbHVlXWFub3RoZXJTdHJpbmdaZGVlcGVyRGlj - dAgJawBNAOQAcwBzAGkAZwAsACAATQBhAN9fEBU8aGVsbG8gJiAnaGknIHRo - ZXJlIT7TGRobHB0eUWFRYlFjEBEjQEBAAAAAAACjHyAhEAEQAlR0ZXh0Iz/g - AAAAAAAApSQlJh0nUUFRQhAMox8gKBADVkRvb2RhaNCgEQLYoS5PEPo8bG90 - cyBvZiBiaW5hcnkgZ3Vuaz4AAQIDPGxvdHMgb2YgYmluYXJ5IGd1bms+AAEC - Azxsb3RzIG9mIGJpbmFyeSBndW5rPgABAgM8bG90cyBvZiBiaW5hcnkgZ3Vu - az4AAQIDPGxvdHMgb2YgYmluYXJ5IGd1bms+AAECAzxsb3RzIG9mIGJpbmFy - eSBndW5rPgABAgM8bG90cyBvZiBiaW5hcnkgZ3Vuaz4AAQIDPGxvdHMgb2Yg - YmluYXJ5IGd1bms+AAECAzxsb3RzIG9mIGJpbmFyeSBndW5rPgABAgM8bG90 - cyBvZiBiaW5hcnkgZ3Vuaz4AAQIDTTxiaW5hcnkgZ3Vuaz5fEBdUaGF0IHdh - cyBhIHVuaWNvZGUga2V5LgAIACEAJwAtADQAOgBCAE4AWgBgAGsAdACBAJAA - mQCkALAAuwDJANcA4gDjAOQA+wETARoBHAEeASABIgErAS8BMQEzATgBQQFH - AUkBSwFNAVEBUwFaAVsBXAFfAWECXgJsAAAAAAAAAgEAAAAAAAAAMQAAAAAA - AAAAAAAAAAAAAoY='''), + YnBsaXN0MDDfEA8BAgMEBQYHCAkKCwwNDg8QERImJy0uLzAxMjM1NDZXYUJp + Z0ludFVhRGF0ZVVhRGljdFZhRmxvYXRVYUxpc3RfEA9hTmVnYXRpdmVCaWdJ + bnRcYU5lZ2F0aXZlSW50V2FTdHJpbmdbYW5FbXB0eURpY3RbYW5FbXB0eUxp + c3RVYW5JbnRabmVzdGVkRGF0YVhzb21lRGF0YVxzb21lTW9yZURhdGFnAMUA + YgBlAG4AcgBhAGETf////////9QzQZy5ffQAAADVExQVFhcYGRobHFthRmFs + c2VWYWx1ZVphVHJ1ZVZhbHVlXWFVbmljb2RlVmFsdWVdYW5vdGhlclN0cmlu + Z1pkZWVwZXJEaWN0CAlrAE0A5ABzAHMAaQBnACwAIABNAGEA318QFTxoZWxs + byAmICdoaScgdGhlcmUhPtMdHh8gISJRYVFiUWMQESNAQEAAAAAAAKMjJCUQ + ARACVHRleHQjP+AAAAAAAAClKCkqIStRQVFCEAyjIyQsEAMT////7V+g4AAT + //////////tWRG9vZGFo0KARAtihNE8Q+jxsb3RzIG9mIGJpbmFyeSBndW5r + PgABAgM8bG90cyBvZiBiaW5hcnkgZ3Vuaz4AAQIDPGxvdHMgb2YgYmluYXJ5 + IGd1bms+AAECAzxsb3RzIG9mIGJpbmFyeSBndW5rPgABAgM8bG90cyBvZiBi + aW5hcnkgZ3Vuaz4AAQIDPGxvdHMgb2YgYmluYXJ5IGd1bms+AAECAzxsb3Rz + IG9mIGJpbmFyeSBndW5rPgABAgM8bG90cyBvZiBiaW5hcnkgZ3Vuaz4AAQID + PGxvdHMgb2YgYmluYXJ5IGd1bms+AAECAzxsb3RzIG9mIGJpbmFyeSBndW5r + PgABAgNNPGJpbmFyeSBndW5rPl8QF1RoYXQgd2FzIGEgdW5pY29kZSBrZXku + AAgAKQAxADcAPQBEAEoAXABpAHEAfQCJAI8AmgCjALAAvwDIANEA3ADoAPMB + AQEPARoBGwEcATMBSwFSAVQBVgFYAVoBYwFnAWkBawFwAXkBfwGBAYMBhQGJ + AYsBlAGdAaQBpQGmAakBqwKoArYAAAAAAAACAQAAAAAAAAA3AAAAAAAAAAAA + AAAAAAAC0A=='''), } @@ -98,6 +105,9 @@ aList=["A", "B", 12, 32.5, [1, 2, 3]], aFloat = 0.5, anInt = 728, + aBigInt = 2 ** 63 - 44, + aNegativeInt = -5, + aNegativeBigInt = -80000000000, aDict=dict( anotherString="", aUnicodeValue='M\xe4ssig, Ma\xdf', @@ -133,6 +143,30 @@ self.assertRaises(AttributeError, plistlib.dump, pl, 'filename') self.assertRaises(AttributeError, plistlib.load, 'filename') + def test_invalid_type(self): + pl = [ object() ] + + for fmt in ALL_FORMATS: + with self.subTest(fmt=fmt): + self.assertRaises(TypeError, plistlib.dumps, pl, fmt=fmt) + + def test_int(self): + for pl in [0, 2**8-1, 2**8, 2**16-1, 2**16, 2**32-1, 2**32, + 2**63-1, 1, -2**63]: + for fmt in ALL_FORMATS: + with self.subTest(pl=pl, fmt=fmt): + data = plistlib.dumps(pl, fmt=fmt) + pl2 = plistlib.loads(data) + self.assertIsInstance(pl2, int) + self.assertEqual(pl, pl2) + data2 = plistlib.dumps(pl2, fmt=fmt) + self.assertEqual(data, data2) + + for fmt in ALL_FORMATS: + for pl in (2 ** 64 + 1, 2 ** 127-1, -2**64, -2 ** 127): + with self.subTest(pl=pl, fmt=fmt): + self.assertRaises(OverflowError, plistlib.dumps, + pl, fmt=fmt) def test_bytes(self): pl = self._create() diff --git a/Mac/Tools/plistlib_generate_testdata.py b/Mac/Tools/plistlib_generate_testdata.py --- a/Mac/Tools/plistlib_generate_testdata.py +++ b/Mac/Tools/plistlib_generate_testdata.py @@ -23,7 +23,13 @@ def main(): pl = OrderedDict() + # Note: pl is an OrderedDict to control the order + # of keys, and hence have some control on the structure + # of the output file. + # New keys should be added in alphabetical order. + seconds = datetime.datetime(2004, 10, 26, 10, 33, 33, tzinfo=datetime.timezone(datetime.timedelta(0))).timestamp() + pl[nsstr('aBigInt')] = 2 ** 63 - 44 pl[nsstr('aDate')] = NSDate.dateWithTimeIntervalSince1970_(seconds) pl[nsstr('aDict')] = d = OrderedDict() @@ -52,6 +58,8 @@ aa.append(2) aa.append(3) + pl[nsstr('aNegativeBigInt')] = -80000000000 + pl[nsstr('aNegativeInt')] = -5 pl[nsstr('aString')] = nsstr('Doodah') pl[nsstr('anEmptyDict')] = NSMutableDictionary.alloc().init() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -72,6 +72,8 @@ - Issue #20229: Avoid plistlib deprecation warning in platform.mac_ver(). +- Issue #14455: Fix some problems with the new binary plist support in plistlib. + IDLE ---- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 15 14:29:40 2014 From: python-checkins at python.org (vinay.sajip) Date: Wed, 15 Jan 2014 14:29:40 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Clarified_docu?= =?utf-8?q?mentation_note_on_module-level_convenience_functions=2E?= Message-ID: <3f48XN5NPsz7LjN@mail.python.org> http://hg.python.org/cpython/rev/84cf25da86e8 changeset: 88488:84cf25da86e8 branch: 2.7 parent: 88482:74d138cfe564 user: Vinay Sajip date: Wed Jan 15 13:27:58 2014 +0000 summary: Clarified documentation note on module-level convenience functions. files: Doc/library/logging.rst | 17 +++++++++-------- 1 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -852,14 +852,15 @@ Logs a message with level *level* on the root logger. The other arguments are interpreted as for :func:`debug`. - .. note:: The above module-level functions which delegate to the root - logger should *not* be used in threads, in versions of Python earlier - than 2.7.1 and 3.2, unless at least one handler has been added to the - root logger *before* the threads are started. These convenience functions - call :func:`basicConfig` to ensure that at least one handler is - available; in earlier versions of Python, this can (under rare - circumstances) lead to handlers being added multiple times to the root - logger, which can in turn lead to multiple messages for the same event. + .. note:: The above module-level convenience functions, which delegate to the + root logger, call :func:`basicConfig` to ensure that at least one handler + is available. Because of this, they should *not* be used in threads, + in versions of Python earlier than 2.7.1 and 3.2, unless at least one + handler has been added to the root logger *before* the threads are + started. In earlier versions of Python, due to a thread safety shortcoming + in :func:`basicConfig`, this can (under rare circumstances) lead to + handlers being added multiple times to the root logger, which can in turn + lead to multiple messages for the same event. .. function:: disable(lvl) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 15 14:29:42 2014 From: python-checkins at python.org (vinay.sajip) Date: Wed, 15 Jan 2014 14:29:42 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Clarified_docu?= =?utf-8?q?mentation_note_on_module-level_convenience_functions=2E?= Message-ID: <3f48XQ1225z7LjZ@mail.python.org> http://hg.python.org/cpython/rev/70aff086da6f changeset: 88489:70aff086da6f branch: 3.3 parent: 88483:956b8afdaa3e user: Vinay Sajip date: Wed Jan 15 13:28:39 2014 +0000 summary: Clarified documentation note on module-level convenience functions. files: Doc/library/logging.rst | 17 +++++++++-------- 1 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -1002,14 +1002,15 @@ Logs a message with level *level* on the root logger. The other arguments are interpreted as for :func:`debug`. - .. note:: The above module-level functions which delegate to the root - logger should *not* be used in threads, in versions of Python earlier - than 2.7.1 and 3.2, unless at least one handler has been added to the - root logger *before* the threads are started. These convenience functions - call :func:`basicConfig` to ensure that at least one handler is - available; in earlier versions of Python, this can (under rare - circumstances) lead to handlers being added multiple times to the root - logger, which can in turn lead to multiple messages for the same event. + .. note:: The above module-level convenience functions, which delegate to the + root logger, call :func:`basicConfig` to ensure that at least one handler + is available. Because of this, they should *not* be used in threads, + in versions of Python earlier than 2.7.1 and 3.2, unless at least one + handler has been added to the root logger *before* the threads are + started. In earlier versions of Python, due to a thread safety shortcoming + in :func:`basicConfig`, this can (under rare circumstances) lead to + handlers being added multiple times to the root logger, which can in turn + lead to multiple messages for the same event. .. function:: disable(lvl) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 15 14:29:43 2014 From: python-checkins at python.org (vinay.sajip) Date: Wed, 15 Jan 2014 14:29:43 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merged_documentation_update_from_3=2E3=2E?= Message-ID: <3f48XR34zQz7LkF@mail.python.org> http://hg.python.org/cpython/rev/73eab2d87cb6 changeset: 88490:73eab2d87cb6 parent: 88487:1a8149ba3000 parent: 88489:70aff086da6f user: Vinay Sajip date: Wed Jan 15 13:29:24 2014 +0000 summary: Merged documentation update from 3.3. files: Doc/library/logging.rst | 17 +++++++++-------- 1 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -1002,14 +1002,15 @@ Logs a message with level *level* on the root logger. The other arguments are interpreted as for :func:`debug`. - .. note:: The above module-level functions which delegate to the root - logger should *not* be used in threads, in versions of Python earlier - than 2.7.1 and 3.2, unless at least one handler has been added to the - root logger *before* the threads are started. These convenience functions - call :func:`basicConfig` to ensure that at least one handler is - available; in earlier versions of Python, this can (under rare - circumstances) lead to handlers being added multiple times to the root - logger, which can in turn lead to multiple messages for the same event. + .. note:: The above module-level convenience functions, which delegate to the + root logger, call :func:`basicConfig` to ensure that at least one handler + is available. Because of this, they should *not* be used in threads, + in versions of Python earlier than 2.7.1 and 3.2, unless at least one + handler has been added to the root logger *before* the threads are + started. In earlier versions of Python, due to a thread safety shortcoming + in :func:`basicConfig`, this can (under rare circumstances) lead to + handlers being added multiple times to the root logger, which can in turn + lead to multiple messages for the same event. .. function:: disable(lvl) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 15 16:10:00 2014 From: python-checkins at python.org (vinay.sajip) Date: Wed, 15 Jan 2014 16:10:00 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Added_cookbook?= =?utf-8?q?_entry_on_alternative_formatting_styles=2E?= Message-ID: <3f4Bm85D1Zz7LkS@mail.python.org> http://hg.python.org/cpython/rev/7c4f0c3dedaf changeset: 88491:7c4f0c3dedaf branch: 3.3 parent: 88489:70aff086da6f user: Vinay Sajip date: Wed Jan 15 15:09:05 2014 +0000 summary: Added cookbook entry on alternative formatting styles. files: Doc/howto/logging-cookbook.rst | 91 ++++++++++++++++++++++ Doc/howto/logging.rst | 2 +- Doc/library/logging.rst | 3 +- 3 files changed, 94 insertions(+), 2 deletions(-) diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -1829,3 +1829,94 @@ :class:`~logging.FileHandler` - for example, one of the rotating file handlers, or a different type of handler altogether. + +.. currentmodule:: logging + +.. _formatting-styles: + +Using particular formatting styles throughout your application +-------------------------------------------------------------- + +In Python 3.2, the :class:`~logging.Formatter` gained a ``style`` keyword +parameter which, while defaulting to ``%`` for backward compatibility, allowed +the specification of ``{`` or ``$`` to support the formatting approaches +supported by :meth:`str.format` and :class:`string.Template`. Note that this +governs the formatting of logging messages for final output to logs, and is +completely orthogonal to how an individual logging message is constructed. + +Logging calls (:meth:`~Logger.debug`, :meth:`~Logger.info` etc.) only take +positional parameters for the actual logging message itself, with keyword +parameters used only for determining options for how to handle the logging call +(e.g. the ``exc_info`` keyword parameter to indicate that traceback information +should be logged, or the ``extra`` keyword parameter to indicate additional +contextual information to be added to the log). So you cannot directly make +logging calls using :meth:`str.format` or :class:`string.Template` syntax, +because internally the logging package uses %-formatting to merge the format +string and the variable arguments. There would no changing this while preserving +backward compatibility, since all logging calls which are out there in existing +code will be using %-format strings. + +There have been suggestions to associate format styles with specific loggers, +but that approach also runs into backward compatibility problems because any +existing code could be using a given logger name and using %-formatting. + +For logging to work interoperably between any third-party libraries and your +code, decisions about formatting need to be made at the level of the +individual logging call. This opens up a couple of ways in which alternative +formatting styles can be accommodated. + + +Using LogRecord factories +^^^^^^^^^^^^^^^^^^^^^^^^^ + +In Python 3.2, along with the :class:`~logging.Formatter` changes mentioned +above, the logging package gained the ability to allow users to set their own +:class:`LogRecord` subclasses, using the :func:`setLogRecordFactory` function. +You can use this to set your own subclass of :class:`LogRecord`, which does the +Right Thing by overriding the :meth:`~LogRecord.getMessage` method. The base +class implementation of this method is where the ``msg % args`` formatting +happens, and where you can substitute your alternate formatting; however, you +should be careful to support all formatting styles and allow %-formatting as +the default, to ensure interoperability with other code. Care should also be +taken to call ``str(self.msg)``, just as the base implementation does. + +Refer to the reference documentation on :func:`setLogRecordFactory` and +:class:`LogRecord` for more information. + + +Using custom message objects +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There is another, perhaps simpler way that you can use {}- and $- formatting to +construct your individual log messages. You may recall (from +:ref:`arbitrary-object-messages`) that when logging you can use an arbitrary +object as a message format string, and that the logging package will call +:func:`str` on that object to get the actual format string. Consider the +following two classes:: + + class BraceMessage(object): + def __init__(self, fmt, *args, **kwargs): + self.fmt = fmt + self.args = args + self.kwargs = kwargs + + def __str__(self): + return self.fmt.format(*self.args, **self.kwargs) + + class DollarMessage(object): + def __init__(self, fmt, **kwargs): + self.fmt = fmt + self.kwargs = kwargs + + def __str__(self): + from string import Template + return Template(self.fmt).substitute(**self.kwargs) + +Either of these can be used in place of a format string, to allow {}- or +$-formatting to be used to build the actual "message" part which appears in the +formatted log output in place of ?%(message)s? or ?{message}? or ?$message?. +If you find it a little unwieldy to use the class names whenever you want to log +something, you can make it more palatable if you use an alias such as ``M`` or +``_`` for the message (or perhaps ``__``, if you are using ``_`` for +localization). + diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst --- a/Doc/howto/logging.rst +++ b/Doc/howto/logging.rst @@ -239,7 +239,7 @@ compatibility: the logging package pre-dates newer formatting options such as :meth:`str.format` and :class:`string.Template`. These newer formatting options *are* supported, but exploring them is outside the scope of this -tutorial. +tutorial: see :ref:`formatting-styles` for more information. Changing the format of displayed messages diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -500,7 +500,8 @@ The *style* parameter can be one of '%', '{' or '$' and determines how the format string will be merged with its data: using one of %-formatting, - :meth:`str.format` or :class:`string.Template`. + :meth:`str.format` or :class:`string.Template`. See :ref:`formatting-styles` + for more information on using {- and $-formatting for log messages. .. versionchanged:: 3.2 The *style* parameter was added. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 15 16:10:02 2014 From: python-checkins at python.org (vinay.sajip) Date: Wed, 15 Jan 2014 16:10:02 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merged_documentation_update_from_3=2E3=2E?= Message-ID: <3f4BmB1c5fz7Llq@mail.python.org> http://hg.python.org/cpython/rev/0056aaf42bf7 changeset: 88492:0056aaf42bf7 parent: 88490:73eab2d87cb6 parent: 88491:7c4f0c3dedaf user: Vinay Sajip date: Wed Jan 15 15:09:43 2014 +0000 summary: Merged documentation update from 3.3. files: Doc/howto/logging-cookbook.rst | 91 ++++++++++++++++++++++ Doc/howto/logging.rst | 2 +- Doc/library/logging.rst | 3 +- 3 files changed, 94 insertions(+), 2 deletions(-) diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -1827,3 +1827,94 @@ :class:`~logging.FileHandler` - for example, one of the rotating file handlers, or a different type of handler altogether. + +.. currentmodule:: logging + +.. _formatting-styles: + +Using particular formatting styles throughout your application +-------------------------------------------------------------- + +In Python 3.2, the :class:`~logging.Formatter` gained a ``style`` keyword +parameter which, while defaulting to ``%`` for backward compatibility, allowed +the specification of ``{`` or ``$`` to support the formatting approaches +supported by :meth:`str.format` and :class:`string.Template`. Note that this +governs the formatting of logging messages for final output to logs, and is +completely orthogonal to how an individual logging message is constructed. + +Logging calls (:meth:`~Logger.debug`, :meth:`~Logger.info` etc.) only take +positional parameters for the actual logging message itself, with keyword +parameters used only for determining options for how to handle the logging call +(e.g. the ``exc_info`` keyword parameter to indicate that traceback information +should be logged, or the ``extra`` keyword parameter to indicate additional +contextual information to be added to the log). So you cannot directly make +logging calls using :meth:`str.format` or :class:`string.Template` syntax, +because internally the logging package uses %-formatting to merge the format +string and the variable arguments. There would no changing this while preserving +backward compatibility, since all logging calls which are out there in existing +code will be using %-format strings. + +There have been suggestions to associate format styles with specific loggers, +but that approach also runs into backward compatibility problems because any +existing code could be using a given logger name and using %-formatting. + +For logging to work interoperably between any third-party libraries and your +code, decisions about formatting need to be made at the level of the +individual logging call. This opens up a couple of ways in which alternative +formatting styles can be accommodated. + + +Using LogRecord factories +^^^^^^^^^^^^^^^^^^^^^^^^^ + +In Python 3.2, along with the :class:`~logging.Formatter` changes mentioned +above, the logging package gained the ability to allow users to set their own +:class:`LogRecord` subclasses, using the :func:`setLogRecordFactory` function. +You can use this to set your own subclass of :class:`LogRecord`, which does the +Right Thing by overriding the :meth:`~LogRecord.getMessage` method. The base +class implementation of this method is where the ``msg % args`` formatting +happens, and where you can substitute your alternate formatting; however, you +should be careful to support all formatting styles and allow %-formatting as +the default, to ensure interoperability with other code. Care should also be +taken to call ``str(self.msg)``, just as the base implementation does. + +Refer to the reference documentation on :func:`setLogRecordFactory` and +:class:`LogRecord` for more information. + + +Using custom message objects +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There is another, perhaps simpler way that you can use {}- and $- formatting to +construct your individual log messages. You may recall (from +:ref:`arbitrary-object-messages`) that when logging you can use an arbitrary +object as a message format string, and that the logging package will call +:func:`str` on that object to get the actual format string. Consider the +following two classes:: + + class BraceMessage(object): + def __init__(self, fmt, *args, **kwargs): + self.fmt = fmt + self.args = args + self.kwargs = kwargs + + def __str__(self): + return self.fmt.format(*self.args, **self.kwargs) + + class DollarMessage(object): + def __init__(self, fmt, **kwargs): + self.fmt = fmt + self.kwargs = kwargs + + def __str__(self): + from string import Template + return Template(self.fmt).substitute(**self.kwargs) + +Either of these can be used in place of a format string, to allow {}- or +$-formatting to be used to build the actual "message" part which appears in the +formatted log output in place of ?%(message)s? or ?{message}? or ?$message?. +If you find it a little unwieldy to use the class names whenever you want to log +something, you can make it more palatable if you use an alias such as ``M`` or +``_`` for the message (or perhaps ``__``, if you are using ``_`` for +localization). + diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst --- a/Doc/howto/logging.rst +++ b/Doc/howto/logging.rst @@ -239,7 +239,7 @@ compatibility: the logging package pre-dates newer formatting options such as :meth:`str.format` and :class:`string.Template`. These newer formatting options *are* supported, but exploring them is outside the scope of this -tutorial. +tutorial: see :ref:`formatting-styles` for more information. Changing the format of displayed messages diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -500,7 +500,8 @@ The *style* parameter can be one of '%', '{' or '$' and determines how the format string will be merged with its data: using one of %-formatting, - :meth:`str.format` or :class:`string.Template`. + :meth:`str.format` or :class:`string.Template`. See :ref:`formatting-styles` + for more information on using {- and $-formatting for log messages. .. versionchanged:: 3.2 The *style* parameter was added. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 01:12:29 2014 From: python-checkins at python.org (ethan.furman) Date: Thu, 16 Jan 2014 01:12:29 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_461=3A_more_updates?= Message-ID: <3f4Qp51WzMz7Ljb@mail.python.org> http://hg.python.org/peps/rev/667deea26074 changeset: 5352:667deea26074 user: Ethan Furman date: Wed Jan 15 16:12:41 2014 -0800 summary: PEP 461: more updates files: pep-0461.txt | 77 ++++++++++++++++++++++++++++----------- 1 files changed, 55 insertions(+), 22 deletions(-) diff --git a/pep-0461.txt b/pep-0461.txt --- a/pep-0461.txt +++ b/pep-0461.txt @@ -8,14 +8,25 @@ Content-Type: text/x-rst Created: 2014-01-13 Python-Version: 3.5 -Post-History: 2014-01-13 +Post-History: 2014-01-14, 2014-01-15 Resolution: Abstract ======== -This PEP proposes adding the % and {} formatting operations from str to bytes. +This PEP proposes adding the % and {} formatting operations from str to bytes [1]. + + +Overriding Principles +===================== + +In order to avoid the problems of auto-conversion and value-generated exceptions, +all object checking will be done via isinstance, not by values contained in a +Unicode representation. In other words:: + + - duck-typing to allow/reject entry into a byte-stream + - no value generated errors Proposed semantics for bytes formatting @@ -26,7 +37,7 @@ All the numeric formatting codes (such as %x, %o, %e, %f, %g, etc.) will be supported, and will work as they do for str, including the -padding, justification and other related modifiers. +padding, justification and other related modifiers, except locale. Example:: @@ -44,13 +55,13 @@ >>> b'%c' % b'a' b'a' -%s is a restricted in what it will accept:: +%s is restricted in what it will accept:: - input type supports Py_buffer? use it to collect the necessary bytes - input type is something else? - use its __bytes__ method; if there isn't one, raise an exception [3] + use its __bytes__ method; if there isn't one, raise an exception [2] Examples: @@ -76,23 +87,49 @@ 'a string'.encode('latin-1') -Unsupported % format codes -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -%r (which calls __repr__) is not supported - - format ------ -The format mini language will be used as-is, with the behaviors as listed -for %-interpolation. +The format mini language codes, where they correspond with the %-interpolation codes, +will be used as-is, with three exceptions:: + + - !s is not supported, as {} can mean the default for both str and bytes, in both + Py2 and Py3. + - !b is supported, and new Py3k code can use it to be explicit. + - no other __format__ method will be called. + +Numeric Format Codes +-------------------- + +To properly handle int and float subclasses, int(), index(), and float() will be called on the +objects intended for (d, i, u), (b, o, x, X), and (e, E, f, F, g, G). + +Unsupported codes +----------------- + +%r (which calls __repr__), and %a (which calls ascii() on __repr__) are not supported. + +!r and !a are not supported. + +The n integer and float format code is not supported. Open Questions ============== -Do we need no support all the numeric format codes? The floating point +Currently non-numeric objects go through:: + + - Py_buffer + - __bytes__ + - failure + +Do we want to add a __format_bytes__ method in there? + + - Guaranteed to produce only ascii (as in b'10', not b'\x0a') + - Makes more sense than using __bytes__ to produce ascii output + - What if an object has both __bytes__ and __format_bytes__? + +Do we need to support all the numeric format codes? The floating point exponential formats seem less appropriate, for example. @@ -121,15 +158,11 @@ easily fixed. -Foot notes -========== +Footnotes +========= -.. [1] Not sure if this should be the numeric __str__ or the numeric __repr__, - or if there's any difference -.. [2] Any proper numeric class would then have to provide an ascii - representation of its value, either via __repr__ or __str__ (whichever - we choose in [1]). -.. [3] TypeError, ValueError, or UnicodeEncodeError? +.. [1] string.Template is not under consideration. +.. [2] TypeError, ValueError, or UnicodeEncodeError? Copyright -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Jan 16 01:38:52 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 16 Jan 2014 01:38:52 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Fix_a_typo_in_C?= =?utf-8?q?oroWrapper?= Message-ID: <3f4RNX2jrxzRxf@mail.python.org> http://hg.python.org/cpython/rev/429eb5f284dd changeset: 88493:429eb5f284dd user: Victor Stinner date: Thu Jan 16 01:38:24 2014 +0100 summary: asyncio: Fix a typo in CoroWrapper __slot__ => __slots__ files: Lib/asyncio/tasks.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -34,7 +34,7 @@ class CoroWrapper: """Wrapper for coroutine in _DEBUG mode.""" - __slot__ = ['gen', 'func'] + __slots__ = ['gen', 'func'] def __init__(self, gen, func): assert inspect.isgenerator(gen), gen -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 01:55:43 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 16 Jan 2014 01:55:43 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Fix_CoroWrapper?= =?utf-8?q?_=28fix_my_previous_commit=29?= Message-ID: <3f4Rlz1w3bzQPC@mail.python.org> http://hg.python.org/cpython/rev/f07161c4f3aa changeset: 88494:f07161c4f3aa user: Victor Stinner date: Thu Jan 16 01:55:29 2014 +0100 summary: asyncio: Fix CoroWrapper (fix my previous commit) Add __name__ and __doc__ to __slots__ files: Lib/asyncio/tasks.py | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -32,9 +32,7 @@ class CoroWrapper: - """Wrapper for coroutine in _DEBUG mode.""" - - __slots__ = ['gen', 'func'] + __slots__ = ['gen', 'func', '__name__', '__doc__'] def __init__(self, gen, func): assert inspect.isgenerator(gen), gen -- Repository URL: http://hg.python.org/cpython From tjreedy at udel.edu Thu Jan 16 03:49:14 2014 From: tjreedy at udel.edu (Terry Reedy) Date: Wed, 15 Jan 2014 21:49:14 -0500 Subject: [Python-checkins] peps: PEP 461: more updates In-Reply-To: <3f4Qp51WzMz7Ljb@mail.python.org> References: <3f4Qp51WzMz7Ljb@mail.python.org> Message-ID: <52D748AA.9000101@udel.edu> On 1/15/2014 7:12 PM, ethan.furman wrote: > PEP 461: more updates I embodied my idea of what bytes.format might do in concrete Python code. I recommend that you do the same for yours; it tends to focus the mind. class B(bytes): def format(self, *obs): ??? Prototyping syntax in CPython is a bit less graceful. I do not care much about the details of what might be added, as I have no current expectation of using it. What I do care about is that it be a) compatible with the Python 3 text and bytes model; b) useful enough to important projects, such as mercurial, to encourage Python 3 migration. I am confident that others will see to a). As for b), I suggest extracting test examples from, say, mercurial, as well as adding your own, and running them with your prototype functions. I think we have had enough theoretical discussion of this option versus that, and need to see how the choices work in practice. -- Terry From python-checkins at python.org Thu Jan 16 06:53:41 2014 From: python-checkins at python.org (georg.brandl) Date: Thu, 16 Jan 2014 06:53:41 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2320235=3A_Report_?= =?utf-8?q?file_and_line_on_unexpected_exceptions_in_Argument_Clinic=2E?= Message-ID: <3f4ZMn2JSjz7LjN@mail.python.org> http://hg.python.org/cpython/rev/acd31653e3b4 changeset: 88495:acd31653e3b4 user: Georg Brandl date: Thu Jan 16 06:53:54 2014 +0100 summary: Closes #20235: Report file and line on unexpected exceptions in Argument Clinic. files: Tools/clinic/clinic.py | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -21,6 +21,7 @@ import sys import tempfile import textwrap +import traceback # TODO: # @@ -1082,7 +1083,11 @@ assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name) self.parsers[dsl_name] = parsers[dsl_name](self) parser = self.parsers[dsl_name] - parser.parse(block) + try: + parser.parse(block) + except Exception: + fail('Exception raised during parsing:\n' + + traceback.format_exc().rstrip()) printer.print_block(block) return printer.f.getvalue() -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu Jan 16 09:47:07 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 16 Jan 2014 09:47:07 +0100 Subject: [Python-checkins] Daily reference leaks (f07161c4f3aa): sum=0 Message-ID: results for f07161c4f3aa on branch "default" -------------------------------------------- test_site leaked [2, 0, -2] references, sum=0 test_site leaked [2, 0, -2] memory blocks, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogJZ0llp', '-x'] From python-checkins at python.org Thu Jan 16 14:44:47 2014 From: python-checkins at python.org (stefan.krah) Date: Thu, 16 Jan 2014 14:44:47 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE5OTM2?= =?utf-8?q?=3A_Disable_shebang_lines_in_order_to_prevent_using_a_random?= Message-ID: <3f4mqM6yPvz7Lk8@mail.python.org> http://hg.python.org/cpython/rev/9062a8695c89 changeset: 88496:9062a8695c89 branch: 3.3 parent: 88491:7c4f0c3dedaf user: Stefan Krah date: Thu Jan 16 14:33:27 2014 +0100 summary: Issue #19936: Disable shebang lines in order to prevent using a random system python. files: Modules/_decimal/tests/bench.py | 2 -- Modules/_decimal/tests/deccheck.py | 2 -- Modules/_decimal/tests/randdec.py | 2 -- 3 files changed, 0 insertions(+), 6 deletions(-) diff --git a/Modules/_decimal/tests/bench.py b/Modules/_decimal/tests/bench.py --- a/Modules/_decimal/tests/bench.py +++ b/Modules/_decimal/tests/bench.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # # Copyright (C) 2001-2012 Python Software Foundation. All Rights Reserved. # Modified and extended by Stefan Krah. diff --git a/Modules/_decimal/tests/deccheck.py b/Modules/_decimal/tests/deccheck.py --- a/Modules/_decimal/tests/deccheck.py +++ b/Modules/_decimal/tests/deccheck.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # # Copyright (c) 2008-2012 Stefan Krah. All rights reserved. # diff --git a/Modules/_decimal/tests/randdec.py b/Modules/_decimal/tests/randdec.py --- a/Modules/_decimal/tests/randdec.py +++ b/Modules/_decimal/tests/randdec.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # # Copyright (c) 2008-2012 Stefan Krah. All rights reserved. # -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 14:44:49 2014 From: python-checkins at python.org (stefan.krah) Date: Thu, 16 Jan 2014 14:44:49 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgZnJvbSAzLjMu?= Message-ID: <3f4mqP1HQFz7LkT@mail.python.org> http://hg.python.org/cpython/rev/fd71616d5075 changeset: 88497:fd71616d5075 parent: 88495:acd31653e3b4 parent: 88496:9062a8695c89 user: Stefan Krah date: Thu Jan 16 14:43:22 2014 +0100 summary: Merge from 3.3. files: Modules/_decimal/tests/bench.py | 2 -- Modules/_decimal/tests/deccheck.py | 2 -- Modules/_decimal/tests/randdec.py | 2 -- 3 files changed, 0 insertions(+), 6 deletions(-) diff --git a/Modules/_decimal/tests/bench.py b/Modules/_decimal/tests/bench.py --- a/Modules/_decimal/tests/bench.py +++ b/Modules/_decimal/tests/bench.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # # Copyright (C) 2001-2012 Python Software Foundation. All Rights Reserved. # Modified and extended by Stefan Krah. diff --git a/Modules/_decimal/tests/deccheck.py b/Modules/_decimal/tests/deccheck.py --- a/Modules/_decimal/tests/deccheck.py +++ b/Modules/_decimal/tests/deccheck.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # # Copyright (c) 2008-2012 Stefan Krah. All rights reserved. # diff --git a/Modules/_decimal/tests/randdec.py b/Modules/_decimal/tests/randdec.py --- a/Modules/_decimal/tests/randdec.py +++ b/Modules/_decimal/tests/randdec.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # # Copyright (c) 2008-2012 Stefan Krah. All rights reserved. # -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 15:53:30 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 16 Jan 2014 15:53:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_update_pysqlit?= =?utf-8?q?e_website_=28closes_=2320278=29?= Message-ID: <3f4pLf4x9zzS4l@mail.python.org> http://hg.python.org/cpython/rev/b73b35d1c58d changeset: 88498:b73b35d1c58d branch: 3.3 parent: 88496:9062a8695c89 user: Benjamin Peterson date: Thu Jan 16 09:52:38 2014 -0500 summary: update pysqlite website (closes #20278) files: Doc/library/sqlite3.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -91,7 +91,7 @@ .. seealso:: - http://code.google.com/p/pysqlite/ + https://github.com/ghaering/pysqlite The pysqlite web page -- sqlite3 is developed externally under the name "pysqlite". -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 15:53:31 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 16 Jan 2014 15:53:31 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_update_pysqlit?= =?utf-8?q?e_website_=28closes_=2320278=29?= Message-ID: <3f4pLg6QwpzS4l@mail.python.org> http://hg.python.org/cpython/rev/40289a03569f changeset: 88499:40289a03569f branch: 2.7 parent: 88488:84cf25da86e8 user: Benjamin Peterson date: Thu Jan 16 09:52:38 2014 -0500 summary: update pysqlite website (closes #20278) files: Doc/library/sqlite3.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -97,7 +97,7 @@ .. seealso:: - http://code.google.com/p/pysqlite/ + https://github.com/ghaering/pysqlite The pysqlite web page -- sqlite3 is developed externally under the name "pysqlite". -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 15:53:33 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 16 Jan 2014 15:53:33 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4zICgjMjAyNzgp?= Message-ID: <3f4pLj0mqcz7Ln5@mail.python.org> http://hg.python.org/cpython/rev/e6ecbdb794a9 changeset: 88500:e6ecbdb794a9 parent: 88497:fd71616d5075 parent: 88498:b73b35d1c58d user: Benjamin Peterson date: Thu Jan 16 09:53:22 2014 -0500 summary: merge 3.3 (#20278) files: Doc/library/sqlite3.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -91,7 +91,7 @@ .. seealso:: - http://code.google.com/p/pysqlite/ + https://github.com/ghaering/pysqlite The pysqlite web page -- sqlite3 is developed externally under the name "pysqlite". -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 16:10:36 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 16 Jan 2014 16:10:36 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_linkify_chain?= =?utf-8?q?=2Efrom=5Fiterable_=28closes_=2320272=29?= Message-ID: <3f4pkN4XsJz7LnF@mail.python.org> http://hg.python.org/cpython/rev/aa88c8265e94 changeset: 88501:aa88c8265e94 branch: 3.3 parent: 88498:b73b35d1c58d user: Benjamin Peterson date: Thu Jan 16 10:10:13 2014 -0500 summary: linkify chain.from_iterable (closes #20272) files: Doc/library/itertools.rst | 32 +++++++++++++------------- 1 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -43,22 +43,22 @@ **Iterators terminating on the shortest input sequence:** -==================== ============================ ================================================= ============================================================= -Iterator Arguments Results Example -==================== ============================ ================================================= ============================================================= -:func:`accumulate` p [,func] p0, p0+p1, p0+p1+p2, ... ``accumulate([1,2,3,4,5]) --> 1 3 6 10 15`` -:func:`chain` p, q, ... p0, p1, ... plast, q0, q1, ... ``chain('ABC', 'DEF') --> A B C D E F`` -chain.from_iterable iterable p0, p1, ... plast, q0, q1, ... ``chain.from_iterable(['ABC', 'DEF']) --> A B C D E F`` -:func:`compress` data, selectors (d[0] if s[0]), (d[1] if s[1]), ... ``compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F`` -:func:`dropwhile` pred, seq seq[n], seq[n+1], starting when pred fails ``dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1`` -:func:`filterfalse` pred, seq elements of seq where pred(elem) is false ``filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8`` -:func:`groupby` iterable[, keyfunc] sub-iterators grouped by value of keyfunc(v) -:func:`islice` seq, [start,] stop [, step] elements from seq[start:stop:step] ``islice('ABCDEFG', 2, None) --> C D E F G`` -:func:`starmap` func, seq func(\*seq[0]), func(\*seq[1]), ... ``starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000`` -:func:`takewhile` pred, seq seq[0], seq[1], until pred fails ``takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4`` -:func:`tee` it, n it1, it2, ... itn splits one iterator into n -:func:`zip_longest` p, q, ... (p[0], q[0]), (p[1], q[1]), ... ``zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-`` -==================== ============================ ================================================= ============================================================= +============================ ============================ ================================================= ============================================================= +Iterator Arguments Results Example +============================ ============================ ================================================= ============================================================= +:func:`accumulate` p [,func] p0, p0+p1, p0+p1+p2, ... ``accumulate([1,2,3,4,5]) --> 1 3 6 10 15`` +:func:`chain` p, q, ... p0, p1, ... plast, q0, q1, ... ``chain('ABC', 'DEF') --> A B C D E F`` +:func:`chain.from_iterable` iterable p0, p1, ... plast, q0, q1, ... ``chain.from_iterable(['ABC', 'DEF']) --> A B C D E F`` +:func:`compress` data, selectors (d[0] if s[0]), (d[1] if s[1]), ... ``compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F`` +:func:`dropwhile` pred, seq seq[n], seq[n+1], starting when pred fails ``dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1`` +:func:`filterfalse` pred, seq elements of seq where pred(elem) is false ``filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8`` +:func:`groupby` iterable[, keyfunc] sub-iterators grouped by value of keyfunc(v) +:func:`islice` seq, [start,] stop [, step] elements from seq[start:stop:step] ``islice('ABCDEFG', 2, None) --> C D E F G`` +:func:`starmap` func, seq func(\*seq[0]), func(\*seq[1]), ... ``starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000`` +:func:`takewhile` pred, seq seq[0], seq[1], until pred fails ``takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4`` +:func:`tee` it, n it1, it2, ... itn splits one iterator into n +:func:`zip_longest` p, q, ... (p[0], q[0]), (p[1], q[1]), ... ``zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-`` +============================ ============================ ================================================= ============================================================= **Combinatoric generators:** -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 16:10:38 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 16 Jan 2014 16:10:38 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4zICgjMjAyNzIp?= Message-ID: <3f4pkQ0PzTz7LnZ@mail.python.org> http://hg.python.org/cpython/rev/58cac9967cf0 changeset: 88502:58cac9967cf0 parent: 88500:e6ecbdb794a9 parent: 88501:aa88c8265e94 user: Benjamin Peterson date: Thu Jan 16 10:10:26 2014 -0500 summary: merge 3.3 (#20272) files: Doc/library/itertools.rst | 32 +++++++++++++------------- 1 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -43,22 +43,22 @@ **Iterators terminating on the shortest input sequence:** -==================== ============================ ================================================= ============================================================= -Iterator Arguments Results Example -==================== ============================ ================================================= ============================================================= -:func:`accumulate` p [,func] p0, p0+p1, p0+p1+p2, ... ``accumulate([1,2,3,4,5]) --> 1 3 6 10 15`` -:func:`chain` p, q, ... p0, p1, ... plast, q0, q1, ... ``chain('ABC', 'DEF') --> A B C D E F`` -chain.from_iterable iterable p0, p1, ... plast, q0, q1, ... ``chain.from_iterable(['ABC', 'DEF']) --> A B C D E F`` -:func:`compress` data, selectors (d[0] if s[0]), (d[1] if s[1]), ... ``compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F`` -:func:`dropwhile` pred, seq seq[n], seq[n+1], starting when pred fails ``dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1`` -:func:`filterfalse` pred, seq elements of seq where pred(elem) is false ``filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8`` -:func:`groupby` iterable[, keyfunc] sub-iterators grouped by value of keyfunc(v) -:func:`islice` seq, [start,] stop [, step] elements from seq[start:stop:step] ``islice('ABCDEFG', 2, None) --> C D E F G`` -:func:`starmap` func, seq func(\*seq[0]), func(\*seq[1]), ... ``starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000`` -:func:`takewhile` pred, seq seq[0], seq[1], until pred fails ``takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4`` -:func:`tee` it, n it1, it2, ... itn splits one iterator into n -:func:`zip_longest` p, q, ... (p[0], q[0]), (p[1], q[1]), ... ``zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-`` -==================== ============================ ================================================= ============================================================= +============================ ============================ ================================================= ============================================================= +Iterator Arguments Results Example +============================ ============================ ================================================= ============================================================= +:func:`accumulate` p [,func] p0, p0+p1, p0+p1+p2, ... ``accumulate([1,2,3,4,5]) --> 1 3 6 10 15`` +:func:`chain` p, q, ... p0, p1, ... plast, q0, q1, ... ``chain('ABC', 'DEF') --> A B C D E F`` +:func:`chain.from_iterable` iterable p0, p1, ... plast, q0, q1, ... ``chain.from_iterable(['ABC', 'DEF']) --> A B C D E F`` +:func:`compress` data, selectors (d[0] if s[0]), (d[1] if s[1]), ... ``compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F`` +:func:`dropwhile` pred, seq seq[n], seq[n+1], starting when pred fails ``dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1`` +:func:`filterfalse` pred, seq elements of seq where pred(elem) is false ``filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8`` +:func:`groupby` iterable[, keyfunc] sub-iterators grouped by value of keyfunc(v) +:func:`islice` seq, [start,] stop [, step] elements from seq[start:stop:step] ``islice('ABCDEFG', 2, None) --> C D E F G`` +:func:`starmap` func, seq func(\*seq[0]), func(\*seq[1]), ... ``starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000`` +:func:`takewhile` pred, seq seq[0], seq[1], until pred fails ``takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4`` +:func:`tee` it, n it1, it2, ... itn splits one iterator into n +:func:`zip_longest` p, q, ... (p[0], q[0]), (p[1], q[1]), ... ``zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-`` +============================ ============================ ================================================= ============================================================= **Combinatoric generators:** -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 16:37:39 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 16 Jan 2014 16:37:39 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE5OTM2?= =?utf-8?q?=3A_Added_executable_bits_or_shebang_lines_to_Python_scripts_wh?= =?utf-8?q?ich?= Message-ID: <3f4qKb6GH5z7Lk3@mail.python.org> http://hg.python.org/cpython/rev/92fd0df03823 changeset: 88503:92fd0df03823 branch: 3.3 parent: 88496:9062a8695c89 user: Serhiy Storchaka date: Thu Jan 16 17:15:49 2014 +0200 summary: Issue #19936: Added executable bits or shebang lines to Python scripts which requires them. Disable executable bits and shebang lines in test and benchmark files in order to prevent using a random system python, and in source files of modules which don't provide command line interface. Fixed shebang line to use python3 executable in the unittestgui script. files: Lib/difflib.py | 2 -- Lib/http/cookies.py | 3 --- Lib/lib2to3/tests/data/different_encoding.py | 0 Lib/lib2to3/tests/data/false_encoding.py | 0 Lib/mailbox.py | 2 -- Lib/smtplib.py | 0 Lib/tarfile.py | 0 Lib/test/crashers/recursive_call.py | 0 Lib/test/curses_tests.py | 0 Lib/test/multibytecodec_support.py | 1 - Lib/test/test___future__.py | 1 - Lib/test/test_array.py | 1 - Lib/test/test_binhex.py | 1 - Lib/test/test_bz2.py | 1 - Lib/test/test_cmd.py | 1 - Lib/test/test_codecencodings_cn.py | 1 - Lib/test/test_codecencodings_hk.py | 1 - Lib/test/test_codecencodings_iso2022.py | 2 -- Lib/test/test_codecencodings_jp.py | 1 - Lib/test/test_codecencodings_kr.py | 1 - Lib/test/test_codecencodings_tw.py | 1 - Lib/test/test_codecmaps_cn.py | 1 - Lib/test/test_codecmaps_hk.py | 1 - Lib/test/test_codecmaps_jp.py | 1 - Lib/test/test_codecmaps_kr.py | 1 - Lib/test/test_codecmaps_tw.py | 1 - Lib/test/test_dbm.py | 1 - Lib/test/test_dbm_dumb.py | 1 - Lib/test/test_eof.py | 1 - Lib/test/test_errno.py | 1 - Lib/test/test_gzip.py | 1 - Lib/test/test_keywordonlyarg.py | 2 -- Lib/test/test_logging.py | 2 -- Lib/test/test_marshal.py | 2 -- Lib/test/test_multibytecodec.py | 1 - Lib/test/test_multiprocessing.py | 2 -- Lib/test/test_popen.py | 1 - Lib/test/test_random.py | 2 -- Lib/test/test_sched.py | 2 -- Lib/test/test_smtpnet.py | 2 -- Lib/test/test_socket.py | 2 -- Lib/test/test_support.py | 2 -- Lib/test/test_tcl.py | 2 -- Lib/test/test_urllib2_localnet.py | 2 -- Lib/test/test_urllib2net.py | 2 -- Lib/test/test_urllibnet.py | 2 -- Lib/test/test_urlparse.py | 2 -- Lib/test/test_userstring.py | 1 - Lib/test/test_with.py | 2 -- Lib/test/test_xmlrpc_net.py | 2 -- Lib/timeit.py | 0 Lib/token.py | 0 Lib/trace.py | 0 Lib/turtledemo/bytedesign.py | 0 Lib/turtledemo/clock.py | 0 Lib/turtledemo/forest.py | 0 Lib/turtledemo/fractalcurves.py | 0 Lib/turtledemo/lindenmayer.py | 0 Lib/turtledemo/minimal_hanoi.py | 0 Lib/turtledemo/paint.py | 0 Lib/turtledemo/peace.py | 0 Lib/turtledemo/penrose.py | 0 Lib/turtledemo/planet_and_moon.py | 0 Lib/turtledemo/tree.py | 0 Lib/turtledemo/two_canvases.py | 0 Lib/turtledemo/yinyang.py | 0 Lib/webbrowser.py | 0 Mac/Tools/bundlebuilder.py | 0 Misc/NEWS | 6 ++++++ Modules/_ctypes/libffi/generate-ios-source-and-headers.py | 0 Modules/_ctypes/libffi/generate-osx-source-and-headers.py | 0 Modules/_decimal/tests/bench.py | 0 Modules/_decimal/tests/deccheck.py | 0 Objects/typeslots.py | 0 Tools/gdb/libpython.py | 0 Tools/i18n/makelocalealias.py | 0 Tools/pybench/Setup.py | 0 Tools/pybench/clockres.py | 0 Tools/pybench/systimes.py | 0 Tools/scripts/run_tests.py | 0 Tools/ssl/make_ssl_data.py | 0 Tools/stringbench/stringbench.py | 0 Tools/unicode/comparecodecs.py | 0 Tools/unittestgui/unittestgui.py | 2 +- 84 files changed, 7 insertions(+), 66 deletions(-) diff --git a/Lib/difflib.py b/Lib/difflib.py --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -1,5 +1,3 @@ -#! /usr/bin/env python3 - """ Module difflib -- helpers for computing deltas between objects. diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py --- a/Lib/http/cookies.py +++ b/Lib/http/cookies.py @@ -1,6 +1,3 @@ -#!/usr/bin/env python3 -# - #### # Copyright 2000 by Timothy O'Malley # diff --git a/Lib/lib2to3/tests/data/different_encoding.py b/Lib/lib2to3/tests/data/different_encoding.py old mode 100644 new mode 100755 diff --git a/Lib/lib2to3/tests/data/false_encoding.py b/Lib/lib2to3/tests/data/false_encoding.py old mode 100644 new mode 100755 diff --git a/Lib/mailbox.py b/Lib/mailbox.py --- a/Lib/mailbox.py +++ b/Lib/mailbox.py @@ -1,5 +1,3 @@ -#! /usr/bin/env python3 - """Read/write support for Maildir, mbox, MH, Babyl, and MMDF mailboxes.""" # Notes for authors of new mailbox subclasses: diff --git a/Lib/smtplib.py b/Lib/smtplib.py old mode 100644 new mode 100755 diff --git a/Lib/tarfile.py b/Lib/tarfile.py old mode 100644 new mode 100755 diff --git a/Lib/test/crashers/recursive_call.py b/Lib/test/crashers/recursive_call.py old mode 100644 new mode 100755 diff --git a/Lib/test/curses_tests.py b/Lib/test/curses_tests.py old mode 100644 new mode 100755 diff --git a/Lib/test/multibytecodec_support.py b/Lib/test/multibytecodec_support.py --- a/Lib/test/multibytecodec_support.py +++ b/Lib/test/multibytecodec_support.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # multibytecodec_support.py # Common Unittest Routines for CJK codecs diff --git a/Lib/test/test___future__.py b/Lib/test/test___future__.py --- a/Lib/test/test___future__.py +++ b/Lib/test/test___future__.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python3 import unittest from test import support import __future__ diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py old mode 100755 new mode 100644 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python3 """Test the arraymodule. Roger E. Masse """ diff --git a/Lib/test/test_binhex.py b/Lib/test/test_binhex.py old mode 100755 new mode 100644 --- a/Lib/test/test_binhex.py +++ b/Lib/test/test_binhex.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python3 """Test script for the binhex C module Uses the mechanism of the python binhex module diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py --- a/Lib/test/test_bz2.py +++ b/Lib/test/test_bz2.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 from test import support from test.support import TESTFN, bigmemtest, _4G diff --git a/Lib/test/test_cmd.py b/Lib/test/test_cmd.py --- a/Lib/test/test_cmd.py +++ b/Lib/test/test_cmd.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 """ Test script for the 'cmd' module Original by Michael Schneider diff --git a/Lib/test/test_codecencodings_cn.py b/Lib/test/test_codecencodings_cn.py --- a/Lib/test/test_codecencodings_cn.py +++ b/Lib/test/test_codecencodings_cn.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecencodings_cn.py # Codec encoding tests for PRC encodings. diff --git a/Lib/test/test_codecencodings_hk.py b/Lib/test/test_codecencodings_hk.py --- a/Lib/test/test_codecencodings_hk.py +++ b/Lib/test/test_codecencodings_hk.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecencodings_hk.py # Codec encoding tests for HongKong encodings. diff --git a/Lib/test/test_codecencodings_iso2022.py b/Lib/test/test_codecencodings_iso2022.py --- a/Lib/test/test_codecencodings_iso2022.py +++ b/Lib/test/test_codecencodings_iso2022.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# # Codec encoding tests for ISO 2022 encodings. from test import support diff --git a/Lib/test/test_codecencodings_jp.py b/Lib/test/test_codecencodings_jp.py --- a/Lib/test/test_codecencodings_jp.py +++ b/Lib/test/test_codecencodings_jp.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecencodings_jp.py # Codec encoding tests for Japanese encodings. diff --git a/Lib/test/test_codecencodings_kr.py b/Lib/test/test_codecencodings_kr.py --- a/Lib/test/test_codecencodings_kr.py +++ b/Lib/test/test_codecencodings_kr.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecencodings_kr.py # Codec encoding tests for ROK encodings. diff --git a/Lib/test/test_codecencodings_tw.py b/Lib/test/test_codecencodings_tw.py --- a/Lib/test/test_codecencodings_tw.py +++ b/Lib/test/test_codecencodings_tw.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecencodings_tw.py # Codec encoding tests for ROC encodings. diff --git a/Lib/test/test_codecmaps_cn.py b/Lib/test/test_codecmaps_cn.py --- a/Lib/test/test_codecmaps_cn.py +++ b/Lib/test/test_codecmaps_cn.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecmaps_cn.py # Codec mapping tests for PRC encodings diff --git a/Lib/test/test_codecmaps_hk.py b/Lib/test/test_codecmaps_hk.py --- a/Lib/test/test_codecmaps_hk.py +++ b/Lib/test/test_codecmaps_hk.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecmaps_hk.py # Codec mapping tests for HongKong encodings diff --git a/Lib/test/test_codecmaps_jp.py b/Lib/test/test_codecmaps_jp.py --- a/Lib/test/test_codecmaps_jp.py +++ b/Lib/test/test_codecmaps_jp.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecmaps_jp.py # Codec mapping tests for Japanese encodings diff --git a/Lib/test/test_codecmaps_kr.py b/Lib/test/test_codecmaps_kr.py --- a/Lib/test/test_codecmaps_kr.py +++ b/Lib/test/test_codecmaps_kr.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecmaps_kr.py # Codec mapping tests for ROK encodings diff --git a/Lib/test/test_codecmaps_tw.py b/Lib/test/test_codecmaps_tw.py --- a/Lib/test/test_codecmaps_tw.py +++ b/Lib/test/test_codecmaps_tw.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecmaps_tw.py # Codec mapping tests for ROC encodings diff --git a/Lib/test/test_dbm.py b/Lib/test/test_dbm.py --- a/Lib/test/test_dbm.py +++ b/Lib/test/test_dbm.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python3 """Test script for the dbm.open function based on testdumbdbm.py""" import os diff --git a/Lib/test/test_dbm_dumb.py b/Lib/test/test_dbm_dumb.py --- a/Lib/test/test_dbm_dumb.py +++ b/Lib/test/test_dbm_dumb.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python3 """Test script for the dumbdbm module Original by Roger E. Masse """ diff --git a/Lib/test/test_eof.py b/Lib/test/test_eof.py --- a/Lib/test/test_eof.py +++ b/Lib/test/test_eof.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python3 """test script for a few new invalid token catches""" import unittest diff --git a/Lib/test/test_errno.py b/Lib/test/test_errno.py old mode 100755 new mode 100644 --- a/Lib/test/test_errno.py +++ b/Lib/test/test_errno.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python3 """Test the errno module Roger E. Masse """ 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 @@ -1,4 +1,3 @@ -#! /usr/bin/env python3 """Test script for the gzip module. """ diff --git a/Lib/test/test_keywordonlyarg.py b/Lib/test/test_keywordonlyarg.py --- a/Lib/test/test_keywordonlyarg.py +++ b/Lib/test/test_keywordonlyarg.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - """Unit tests for the keyword only argument specified in PEP 3102.""" __author__ = "Jiwon Seo" 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 @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# # Copyright 2001-2013 by Vinay Sajip. All Rights Reserved. # # Permission to use, copy, modify, and distribute this software and its diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - from test import support import array import io diff --git a/Lib/test/test_multibytecodec.py b/Lib/test/test_multibytecodec.py --- a/Lib/test/test_multibytecodec.py +++ b/Lib/test/test_multibytecodec.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_multibytecodec.py # Unit test for multibytecodec itself diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - # # Unit tests for the multiprocessing package # diff --git a/Lib/test/test_popen.py b/Lib/test/test_popen.py --- a/Lib/test/test_popen.py +++ b/Lib/test/test_popen.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python3 """Basic tests for os.popen() Particularly useful for platforms that fake popen. 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 @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - import unittest import random import time diff --git a/Lib/test/test_sched.py b/Lib/test/test_sched.py --- a/Lib/test/test_sched.py +++ b/Lib/test/test_sched.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - import queue import sched import time diff --git a/Lib/test/test_smtpnet.py b/Lib/test/test_smtpnet.py --- a/Lib/test/test_smtpnet.py +++ b/Lib/test/test_smtpnet.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - import unittest from test import support import smtplib 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 @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - import unittest from test import support from unittest.case import _ExpectedFailure diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - import importlib import shutil import sys diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - import unittest import sys import os 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 @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - import os import email import urllib.parse diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py --- a/Lib/test/test_urllib2net.py +++ b/Lib/test/test_urllib2net.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - import unittest from test import support from test.test_urllib2 import sanepathname2url diff --git a/Lib/test/test_urllibnet.py b/Lib/test/test_urllibnet.py --- a/Lib/test/test_urllibnet.py +++ b/Lib/test/test_urllibnet.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - import unittest from test import support diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py old mode 100755 new mode 100644 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -1,5 +1,3 @@ -#! /usr/bin/env python3 - from test import support import unittest import urllib.parse diff --git a/Lib/test/test_userstring.py b/Lib/test/test_userstring.py old mode 100755 new mode 100644 --- a/Lib/test/test_userstring.py +++ b/Lib/test/test_userstring.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # UserString is a wrapper around the native builtin string type. # UserString instances should behave similar to builtin string objects. diff --git a/Lib/test/test_with.py b/Lib/test/test_with.py --- a/Lib/test/test_with.py +++ b/Lib/test/test_with.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - """Unit tests for the with statement specified in PEP 343.""" diff --git a/Lib/test/test_xmlrpc_net.py b/Lib/test/test_xmlrpc_net.py --- a/Lib/test/test_xmlrpc_net.py +++ b/Lib/test/test_xmlrpc_net.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - import collections.abc import errno import socket diff --git a/Lib/timeit.py b/Lib/timeit.py old mode 100644 new mode 100755 diff --git a/Lib/token.py b/Lib/token.py old mode 100755 new mode 100644 diff --git a/Lib/trace.py b/Lib/trace.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/bytedesign.py b/Lib/turtledemo/bytedesign.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/clock.py b/Lib/turtledemo/clock.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/forest.py b/Lib/turtledemo/forest.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/fractalcurves.py b/Lib/turtledemo/fractalcurves.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/lindenmayer.py b/Lib/turtledemo/lindenmayer.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/minimal_hanoi.py b/Lib/turtledemo/minimal_hanoi.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/paint.py b/Lib/turtledemo/paint.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/peace.py b/Lib/turtledemo/peace.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/penrose.py b/Lib/turtledemo/penrose.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/planet_and_moon.py b/Lib/turtledemo/planet_and_moon.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/tree.py b/Lib/turtledemo/tree.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/two_canvases.py b/Lib/turtledemo/two_canvases.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/yinyang.py b/Lib/turtledemo/yinyang.py old mode 100644 new mode 100755 diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py old mode 100644 new mode 100755 diff --git a/Mac/Tools/bundlebuilder.py b/Mac/Tools/bundlebuilder.py old mode 100644 new mode 100755 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -334,6 +334,12 @@ Tools/Demos ----------- +- Issue #19936: Added executable bits or shebang lines to Python scripts which + requires them. Disable executable bits and shebang lines in test and + benchmark files in order to prevent using a random system python, and in + source files of modules which don't provide command line interface. Fixed + shebang line to use python3 executable in the unittestgui script. + - Issue #18960: 2to3 and the findnocoding.py script now ignore the source encoding declaration on the second line if the first line contains anything except a comment. diff --git a/Modules/_ctypes/libffi/generate-ios-source-and-headers.py b/Modules/_ctypes/libffi/generate-ios-source-and-headers.py old mode 100644 new mode 100755 diff --git a/Modules/_ctypes/libffi/generate-osx-source-and-headers.py b/Modules/_ctypes/libffi/generate-osx-source-and-headers.py old mode 100644 new mode 100755 diff --git a/Modules/_decimal/tests/bench.py b/Modules/_decimal/tests/bench.py old mode 100644 new mode 100755 diff --git a/Modules/_decimal/tests/deccheck.py b/Modules/_decimal/tests/deccheck.py old mode 100644 new mode 100755 diff --git a/Objects/typeslots.py b/Objects/typeslots.py old mode 100644 new mode 100755 diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py old mode 100644 new mode 100755 diff --git a/Tools/i18n/makelocalealias.py b/Tools/i18n/makelocalealias.py old mode 100644 new mode 100755 diff --git a/Tools/pybench/Setup.py b/Tools/pybench/Setup.py old mode 100644 new mode 100755 diff --git a/Tools/pybench/clockres.py b/Tools/pybench/clockres.py old mode 100644 new mode 100755 diff --git a/Tools/pybench/systimes.py b/Tools/pybench/systimes.py old mode 100644 new mode 100755 diff --git a/Tools/scripts/run_tests.py b/Tools/scripts/run_tests.py old mode 100755 new mode 100644 diff --git a/Tools/ssl/make_ssl_data.py b/Tools/ssl/make_ssl_data.py old mode 100644 new mode 100755 diff --git a/Tools/stringbench/stringbench.py b/Tools/stringbench/stringbench.py old mode 100755 new mode 100644 diff --git a/Tools/unicode/comparecodecs.py b/Tools/unicode/comparecodecs.py old mode 100644 new mode 100755 diff --git a/Tools/unittestgui/unittestgui.py b/Tools/unittestgui/unittestgui.py old mode 100644 new mode 100755 --- a/Tools/unittestgui/unittestgui.py +++ b/Tools/unittestgui/unittestgui.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ GUI framework and application for use with Python unit testing framework. Execute tests written using the framework provided by the 'unittest' module. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 16:37:41 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 16 Jan 2014 16:37:41 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuMyk6?= =?utf-8?q?_Merge_heads?= Message-ID: <3f4qKd2z2nz7LlQ@mail.python.org> http://hg.python.org/cpython/rev/1100f9824b2f changeset: 88504:1100f9824b2f branch: 3.3 parent: 88503:92fd0df03823 parent: 88501:aa88c8265e94 user: Serhiy Storchaka date: Thu Jan 16 17:20:02 2014 +0200 summary: Merge heads files: Doc/library/itertools.rst | 32 +++++++++++++------------- Doc/library/sqlite3.rst | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -43,22 +43,22 @@ **Iterators terminating on the shortest input sequence:** -==================== ============================ ================================================= ============================================================= -Iterator Arguments Results Example -==================== ============================ ================================================= ============================================================= -:func:`accumulate` p [,func] p0, p0+p1, p0+p1+p2, ... ``accumulate([1,2,3,4,5]) --> 1 3 6 10 15`` -:func:`chain` p, q, ... p0, p1, ... plast, q0, q1, ... ``chain('ABC', 'DEF') --> A B C D E F`` -chain.from_iterable iterable p0, p1, ... plast, q0, q1, ... ``chain.from_iterable(['ABC', 'DEF']) --> A B C D E F`` -:func:`compress` data, selectors (d[0] if s[0]), (d[1] if s[1]), ... ``compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F`` -:func:`dropwhile` pred, seq seq[n], seq[n+1], starting when pred fails ``dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1`` -:func:`filterfalse` pred, seq elements of seq where pred(elem) is false ``filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8`` -:func:`groupby` iterable[, keyfunc] sub-iterators grouped by value of keyfunc(v) -:func:`islice` seq, [start,] stop [, step] elements from seq[start:stop:step] ``islice('ABCDEFG', 2, None) --> C D E F G`` -:func:`starmap` func, seq func(\*seq[0]), func(\*seq[1]), ... ``starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000`` -:func:`takewhile` pred, seq seq[0], seq[1], until pred fails ``takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4`` -:func:`tee` it, n it1, it2, ... itn splits one iterator into n -:func:`zip_longest` p, q, ... (p[0], q[0]), (p[1], q[1]), ... ``zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-`` -==================== ============================ ================================================= ============================================================= +============================ ============================ ================================================= ============================================================= +Iterator Arguments Results Example +============================ ============================ ================================================= ============================================================= +:func:`accumulate` p [,func] p0, p0+p1, p0+p1+p2, ... ``accumulate([1,2,3,4,5]) --> 1 3 6 10 15`` +:func:`chain` p, q, ... p0, p1, ... plast, q0, q1, ... ``chain('ABC', 'DEF') --> A B C D E F`` +:func:`chain.from_iterable` iterable p0, p1, ... plast, q0, q1, ... ``chain.from_iterable(['ABC', 'DEF']) --> A B C D E F`` +:func:`compress` data, selectors (d[0] if s[0]), (d[1] if s[1]), ... ``compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F`` +:func:`dropwhile` pred, seq seq[n], seq[n+1], starting when pred fails ``dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1`` +:func:`filterfalse` pred, seq elements of seq where pred(elem) is false ``filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8`` +:func:`groupby` iterable[, keyfunc] sub-iterators grouped by value of keyfunc(v) +:func:`islice` seq, [start,] stop [, step] elements from seq[start:stop:step] ``islice('ABCDEFG', 2, None) --> C D E F G`` +:func:`starmap` func, seq func(\*seq[0]), func(\*seq[1]), ... ``starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000`` +:func:`takewhile` pred, seq seq[0], seq[1], until pred fails ``takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4`` +:func:`tee` it, n it1, it2, ... itn splits one iterator into n +:func:`zip_longest` p, q, ... (p[0], q[0]), (p[1], q[1]), ... ``zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-`` +============================ ============================ ================================================= ============================================================= **Combinatoric generators:** diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -91,7 +91,7 @@ .. seealso:: - http://code.google.com/p/pysqlite/ + https://github.com/ghaering/pysqlite The pysqlite web page -- sqlite3 is developed externally under the name "pysqlite". -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 16:37:43 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 16 Jan 2014 16:37:43 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2319936=3A_Added_executable_bits_or_shebang_lines?= =?utf-8?q?_to_Python_scripts_which?= Message-ID: <3f4qKg1Ck0z7Lk8@mail.python.org> http://hg.python.org/cpython/rev/83009d70bc9c changeset: 88505:83009d70bc9c parent: 88502:58cac9967cf0 parent: 88504:1100f9824b2f user: Serhiy Storchaka date: Thu Jan 16 17:33:23 2014 +0200 summary: Issue #19936: Added executable bits or shebang lines to Python scripts which requires them. Disable executable bits and shebang lines in test and benchmark files in order to prevent using a random system python, and in source files of modules which don't provide command line interface. Fixed shebang lines in the unittestgui and checkpip scripts. files: Lib/difflib.py | 2 -- Lib/http/cookies.py | 3 --- Lib/lib2to3/tests/data/different_encoding.py | 0 Lib/lib2to3/tests/data/false_encoding.py | 0 Lib/mailbox.py | 2 -- Lib/operator.py | 1 - Lib/smtplib.py | 0 Lib/tarfile.py | 0 Lib/test/_test_multiprocessing.py | 2 -- Lib/test/crashers/recursive_call.py | 0 Lib/test/curses_tests.py | 0 Lib/test/multibytecodec_support.py | 1 - Lib/test/ssltests.py | 0 Lib/test/test___future__.py | 1 - Lib/test/test_array.py | 1 - Lib/test/test_binhex.py | 1 - Lib/test/test_bz2.py | 1 - Lib/test/test_cmd.py | 1 - Lib/test/test_codecencodings_cn.py | 1 - Lib/test/test_codecencodings_hk.py | 1 - Lib/test/test_codecencodings_iso2022.py | 2 -- Lib/test/test_codecencodings_jp.py | 1 - Lib/test/test_codecencodings_kr.py | 1 - Lib/test/test_codecencodings_tw.py | 1 - Lib/test/test_codecmaps_cn.py | 1 - Lib/test/test_codecmaps_hk.py | 1 - Lib/test/test_codecmaps_jp.py | 1 - Lib/test/test_codecmaps_kr.py | 1 - Lib/test/test_codecmaps_tw.py | 1 - Lib/test/test_dbm.py | 1 - Lib/test/test_dbm_dumb.py | 1 - Lib/test/test_eof.py | 1 - Lib/test/test_errno.py | 1 - Lib/test/test_gzip.py | 1 - Lib/test/test_keywordonlyarg.py | 2 -- Lib/test/test_logging.py | 2 -- Lib/test/test_marshal.py | 2 -- Lib/test/test_multibytecodec.py | 1 - Lib/test/test_pathlib.py | 0 Lib/test/test_popen.py | 1 - Lib/test/test_random.py | 2 -- Lib/test/test_sched.py | 2 -- Lib/test/test_smtpnet.py | 2 -- Lib/test/test_socket.py | 2 -- Lib/test/test_support.py | 2 -- Lib/test/test_tcl.py | 2 -- Lib/test/test_urllib2_localnet.py | 2 -- Lib/test/test_urllib2net.py | 2 -- Lib/test/test_urllibnet.py | 2 -- Lib/test/test_urlparse.py | 2 -- Lib/test/test_userstring.py | 1 - Lib/test/test_with.py | 2 -- Lib/test/test_xmlrpc_net.py | 2 -- Lib/timeit.py | 0 Lib/token.py | 0 Lib/trace.py | 0 Lib/turtledemo/bytedesign.py | 0 Lib/turtledemo/clock.py | 0 Lib/turtledemo/forest.py | 0 Lib/turtledemo/fractalcurves.py | 0 Lib/turtledemo/lindenmayer.py | 0 Lib/turtledemo/minimal_hanoi.py | 0 Lib/turtledemo/paint.py | 0 Lib/turtledemo/peace.py | 0 Lib/turtledemo/penrose.py | 0 Lib/turtledemo/planet_and_moon.py | 0 Lib/turtledemo/tree.py | 0 Lib/turtledemo/two_canvases.py | 0 Lib/turtledemo/yinyang.py | 0 Lib/webbrowser.py | 0 Mac/Tools/bundlebuilder.py | 0 Mac/Tools/plistlib_generate_testdata.py | 0 Misc/NEWS | 6 ++++++ Modules/_ctypes/libffi/generate-ios-source-and-headers.py | 0 Modules/_ctypes/libffi/generate-osx-source-and-headers.py | 0 Modules/_decimal/tests/bench.py | 0 Modules/_decimal/tests/deccheck.py | 0 Objects/typeslots.py | 0 Tools/clinic/clinic_test.py | 2 -- Tools/gdb/libpython.py | 0 Tools/i18n/makelocalealias.py | 0 Tools/pybench/Setup.py | 0 Tools/pybench/clockres.py | 0 Tools/pybench/systimes.py | 0 Tools/scripts/analyze_dxp.py | 0 Tools/scripts/checkpip.py | 2 +- Tools/scripts/run_tests.py | 0 Tools/scripts/win_add2path.py | 0 Tools/ssl/make_ssl_data.py | 0 Tools/stringbench/stringbench.py | 0 Tools/unicode/comparecodecs.py | 0 Tools/unittestgui/unittestgui.py | 2 +- 92 files changed, 8 insertions(+), 70 deletions(-) diff --git a/Lib/difflib.py b/Lib/difflib.py --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -1,5 +1,3 @@ -#! /usr/bin/env python3 - """ Module difflib -- helpers for computing deltas between objects. diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py --- a/Lib/http/cookies.py +++ b/Lib/http/cookies.py @@ -1,6 +1,3 @@ -#!/usr/bin/env python3 -# - #### # Copyright 2000 by Timothy O'Malley # diff --git a/Lib/lib2to3/tests/data/different_encoding.py b/Lib/lib2to3/tests/data/different_encoding.py old mode 100644 new mode 100755 diff --git a/Lib/lib2to3/tests/data/false_encoding.py b/Lib/lib2to3/tests/data/false_encoding.py old mode 100644 new mode 100755 diff --git a/Lib/mailbox.py b/Lib/mailbox.py --- a/Lib/mailbox.py +++ b/Lib/mailbox.py @@ -1,5 +1,3 @@ -#! /usr/bin/env python3 - """Read/write support for Maildir, mbox, MH, Babyl, and MMDF mailboxes.""" # Notes for authors of new mailbox subclasses: diff --git a/Lib/operator.py b/Lib/operator.py --- a/Lib/operator.py +++ b/Lib/operator.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 """ Operator Interface diff --git a/Lib/smtplib.py b/Lib/smtplib.py old mode 100644 new mode 100755 diff --git a/Lib/tarfile.py b/Lib/tarfile.py old mode 100644 new mode 100755 diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - # # Unit tests for the multiprocessing package # diff --git a/Lib/test/crashers/recursive_call.py b/Lib/test/crashers/recursive_call.py old mode 100644 new mode 100755 diff --git a/Lib/test/curses_tests.py b/Lib/test/curses_tests.py old mode 100644 new mode 100755 diff --git a/Lib/test/multibytecodec_support.py b/Lib/test/multibytecodec_support.py --- a/Lib/test/multibytecodec_support.py +++ b/Lib/test/multibytecodec_support.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # multibytecodec_support.py # Common Unittest Routines for CJK codecs diff --git a/Lib/test/ssltests.py b/Lib/test/ssltests.py old mode 100755 new mode 100644 diff --git a/Lib/test/test___future__.py b/Lib/test/test___future__.py --- a/Lib/test/test___future__.py +++ b/Lib/test/test___future__.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python3 import unittest from test import support import __future__ diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py old mode 100755 new mode 100644 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python3 """Test the arraymodule. Roger E. Masse """ diff --git a/Lib/test/test_binhex.py b/Lib/test/test_binhex.py old mode 100755 new mode 100644 --- a/Lib/test/test_binhex.py +++ b/Lib/test/test_binhex.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python3 """Test script for the binhex C module Uses the mechanism of the python binhex module diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py --- a/Lib/test/test_bz2.py +++ b/Lib/test/test_bz2.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 from test import support from test.support import bigmemtest, _4G diff --git a/Lib/test/test_cmd.py b/Lib/test/test_cmd.py --- a/Lib/test/test_cmd.py +++ b/Lib/test/test_cmd.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 """ Test script for the 'cmd' module Original by Michael Schneider diff --git a/Lib/test/test_codecencodings_cn.py b/Lib/test/test_codecencodings_cn.py --- a/Lib/test/test_codecencodings_cn.py +++ b/Lib/test/test_codecencodings_cn.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecencodings_cn.py # Codec encoding tests for PRC encodings. diff --git a/Lib/test/test_codecencodings_hk.py b/Lib/test/test_codecencodings_hk.py --- a/Lib/test/test_codecencodings_hk.py +++ b/Lib/test/test_codecencodings_hk.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecencodings_hk.py # Codec encoding tests for HongKong encodings. diff --git a/Lib/test/test_codecencodings_iso2022.py b/Lib/test/test_codecencodings_iso2022.py --- a/Lib/test/test_codecencodings_iso2022.py +++ b/Lib/test/test_codecencodings_iso2022.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# # Codec encoding tests for ISO 2022 encodings. from test import support diff --git a/Lib/test/test_codecencodings_jp.py b/Lib/test/test_codecencodings_jp.py --- a/Lib/test/test_codecencodings_jp.py +++ b/Lib/test/test_codecencodings_jp.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecencodings_jp.py # Codec encoding tests for Japanese encodings. diff --git a/Lib/test/test_codecencodings_kr.py b/Lib/test/test_codecencodings_kr.py --- a/Lib/test/test_codecencodings_kr.py +++ b/Lib/test/test_codecencodings_kr.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecencodings_kr.py # Codec encoding tests for ROK encodings. diff --git a/Lib/test/test_codecencodings_tw.py b/Lib/test/test_codecencodings_tw.py --- a/Lib/test/test_codecencodings_tw.py +++ b/Lib/test/test_codecencodings_tw.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecencodings_tw.py # Codec encoding tests for ROC encodings. diff --git a/Lib/test/test_codecmaps_cn.py b/Lib/test/test_codecmaps_cn.py --- a/Lib/test/test_codecmaps_cn.py +++ b/Lib/test/test_codecmaps_cn.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecmaps_cn.py # Codec mapping tests for PRC encodings diff --git a/Lib/test/test_codecmaps_hk.py b/Lib/test/test_codecmaps_hk.py --- a/Lib/test/test_codecmaps_hk.py +++ b/Lib/test/test_codecmaps_hk.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecmaps_hk.py # Codec mapping tests for HongKong encodings diff --git a/Lib/test/test_codecmaps_jp.py b/Lib/test/test_codecmaps_jp.py --- a/Lib/test/test_codecmaps_jp.py +++ b/Lib/test/test_codecmaps_jp.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecmaps_jp.py # Codec mapping tests for Japanese encodings diff --git a/Lib/test/test_codecmaps_kr.py b/Lib/test/test_codecmaps_kr.py --- a/Lib/test/test_codecmaps_kr.py +++ b/Lib/test/test_codecmaps_kr.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecmaps_kr.py # Codec mapping tests for ROK encodings diff --git a/Lib/test/test_codecmaps_tw.py b/Lib/test/test_codecmaps_tw.py --- a/Lib/test/test_codecmaps_tw.py +++ b/Lib/test/test_codecmaps_tw.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_codecmaps_tw.py # Codec mapping tests for ROC encodings diff --git a/Lib/test/test_dbm.py b/Lib/test/test_dbm.py --- a/Lib/test/test_dbm.py +++ b/Lib/test/test_dbm.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python3 """Test script for the dbm.open function based on testdumbdbm.py""" import os diff --git a/Lib/test/test_dbm_dumb.py b/Lib/test/test_dbm_dumb.py --- a/Lib/test/test_dbm_dumb.py +++ b/Lib/test/test_dbm_dumb.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python3 """Test script for the dumbdbm module Original by Roger E. Masse """ diff --git a/Lib/test/test_eof.py b/Lib/test/test_eof.py --- a/Lib/test/test_eof.py +++ b/Lib/test/test_eof.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python3 """test script for a few new invalid token catches""" import unittest diff --git a/Lib/test/test_errno.py b/Lib/test/test_errno.py old mode 100755 new mode 100644 --- a/Lib/test/test_errno.py +++ b/Lib/test/test_errno.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python3 """Test the errno module Roger E. Masse """ 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 @@ -1,4 +1,3 @@ -#! /usr/bin/env python3 """Test script for the gzip module. """ diff --git a/Lib/test/test_keywordonlyarg.py b/Lib/test/test_keywordonlyarg.py --- a/Lib/test/test_keywordonlyarg.py +++ b/Lib/test/test_keywordonlyarg.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - """Unit tests for the keyword only argument specified in PEP 3102.""" __author__ = "Jiwon Seo" 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 @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# # Copyright 2001-2013 by Vinay Sajip. All Rights Reserved. # # Permission to use, copy, modify, and distribute this software and its diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - from test import support import array import io diff --git a/Lib/test/test_multibytecodec.py b/Lib/test/test_multibytecodec.py --- a/Lib/test/test_multibytecodec.py +++ b/Lib/test/test_multibytecodec.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # # test_multibytecodec.py # Unit test for multibytecodec itself diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py old mode 100755 new mode 100644 diff --git a/Lib/test/test_popen.py b/Lib/test/test_popen.py --- a/Lib/test/test_popen.py +++ b/Lib/test/test_popen.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python3 """Basic tests for os.popen() Particularly useful for platforms that fake popen. 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 @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - import unittest import unittest.mock import random diff --git a/Lib/test/test_sched.py b/Lib/test/test_sched.py --- a/Lib/test/test_sched.py +++ b/Lib/test/test_sched.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - import queue import sched import time diff --git a/Lib/test/test_smtpnet.py b/Lib/test/test_smtpnet.py --- a/Lib/test/test_smtpnet.py +++ b/Lib/test/test_smtpnet.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - import unittest from test import support import smtplib 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 @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - import unittest from test import support diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - import importlib import shutil import sys diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - import unittest import sys import os 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 @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - import os import email import urllib.parse diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py --- a/Lib/test/test_urllib2net.py +++ b/Lib/test/test_urllib2net.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - import unittest from test import support from test.test_urllib2 import sanepathname2url diff --git a/Lib/test/test_urllibnet.py b/Lib/test/test_urllibnet.py --- a/Lib/test/test_urllibnet.py +++ b/Lib/test/test_urllibnet.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - import unittest from test import support diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py old mode 100755 new mode 100644 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -1,5 +1,3 @@ -#! /usr/bin/env python3 - from test import support import unittest import urllib.parse diff --git a/Lib/test/test_userstring.py b/Lib/test/test_userstring.py old mode 100755 new mode 100644 --- a/Lib/test/test_userstring.py +++ b/Lib/test/test_userstring.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # UserString is a wrapper around the native builtin string type. # UserString instances should behave similar to builtin string objects. diff --git a/Lib/test/test_with.py b/Lib/test/test_with.py --- a/Lib/test/test_with.py +++ b/Lib/test/test_with.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - """Unit tests for the with statement specified in PEP 343.""" diff --git a/Lib/test/test_xmlrpc_net.py b/Lib/test/test_xmlrpc_net.py --- a/Lib/test/test_xmlrpc_net.py +++ b/Lib/test/test_xmlrpc_net.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - import collections.abc import errno import socket diff --git a/Lib/timeit.py b/Lib/timeit.py old mode 100644 new mode 100755 diff --git a/Lib/token.py b/Lib/token.py old mode 100755 new mode 100644 diff --git a/Lib/trace.py b/Lib/trace.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/bytedesign.py b/Lib/turtledemo/bytedesign.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/clock.py b/Lib/turtledemo/clock.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/forest.py b/Lib/turtledemo/forest.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/fractalcurves.py b/Lib/turtledemo/fractalcurves.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/lindenmayer.py b/Lib/turtledemo/lindenmayer.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/minimal_hanoi.py b/Lib/turtledemo/minimal_hanoi.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/paint.py b/Lib/turtledemo/paint.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/peace.py b/Lib/turtledemo/peace.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/penrose.py b/Lib/turtledemo/penrose.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/planet_and_moon.py b/Lib/turtledemo/planet_and_moon.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/tree.py b/Lib/turtledemo/tree.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/two_canvases.py b/Lib/turtledemo/two_canvases.py old mode 100644 new mode 100755 diff --git a/Lib/turtledemo/yinyang.py b/Lib/turtledemo/yinyang.py old mode 100644 new mode 100755 diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py old mode 100644 new mode 100755 diff --git a/Mac/Tools/bundlebuilder.py b/Mac/Tools/bundlebuilder.py old mode 100644 new mode 100755 diff --git a/Mac/Tools/plistlib_generate_testdata.py b/Mac/Tools/plistlib_generate_testdata.py old mode 100644 new mode 100755 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -88,6 +88,12 @@ Tools/Demos ----------- +- Issue #19936: Added executable bits or shebang lines to Python scripts which + requires them. Disable executable bits and shebang lines in test and + benchmark files in order to prevent using a random system python, and in + source files of modules which don't provide command line interface. Fixed + shebang lines in the unittestgui and checkpip scripts. + - Issue #20268: Argument Clinic now supports cloning the parameters and return converter of existing functions. diff --git a/Modules/_ctypes/libffi/generate-ios-source-and-headers.py b/Modules/_ctypes/libffi/generate-ios-source-and-headers.py old mode 100644 new mode 100755 diff --git a/Modules/_ctypes/libffi/generate-osx-source-and-headers.py b/Modules/_ctypes/libffi/generate-osx-source-and-headers.py old mode 100644 new mode 100755 diff --git a/Modules/_decimal/tests/bench.py b/Modules/_decimal/tests/bench.py old mode 100644 new mode 100755 diff --git a/Modules/_decimal/tests/deccheck.py b/Modules/_decimal/tests/deccheck.py old mode 100644 new mode 100755 diff --git a/Objects/typeslots.py b/Objects/typeslots.py old mode 100644 new mode 100755 diff --git a/Tools/clinic/clinic_test.py b/Tools/clinic/clinic_test.py --- a/Tools/clinic/clinic_test.py +++ b/Tools/clinic/clinic_test.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# # Argument Clinic # Copyright 2012-2013 by Larry Hastings. # Licensed to the PSF under a contributor agreement. diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py old mode 100644 new mode 100755 diff --git a/Tools/i18n/makelocalealias.py b/Tools/i18n/makelocalealias.py old mode 100644 new mode 100755 diff --git a/Tools/pybench/Setup.py b/Tools/pybench/Setup.py old mode 100644 new mode 100755 diff --git a/Tools/pybench/clockres.py b/Tools/pybench/clockres.py old mode 100644 new mode 100755 diff --git a/Tools/pybench/systimes.py b/Tools/pybench/systimes.py old mode 100644 new mode 100755 diff --git a/Tools/scripts/analyze_dxp.py b/Tools/scripts/analyze_dxp.py old mode 100755 new mode 100644 diff --git a/Tools/scripts/checkpip.py b/Tools/scripts/checkpip.py old mode 100644 new mode 100755 --- a/Tools/scripts/checkpip.py +++ b/Tools/scripts/checkpip.py @@ -1,4 +1,4 @@ -#/usr/bin/env python3 +#!/usr/bin/env python3 """ Checks that the version of the projects bundled in ensurepip are the latest versions available. diff --git a/Tools/scripts/run_tests.py b/Tools/scripts/run_tests.py old mode 100755 new mode 100644 diff --git a/Tools/scripts/win_add2path.py b/Tools/scripts/win_add2path.py old mode 100755 new mode 100644 diff --git a/Tools/ssl/make_ssl_data.py b/Tools/ssl/make_ssl_data.py old mode 100644 new mode 100755 diff --git a/Tools/stringbench/stringbench.py b/Tools/stringbench/stringbench.py old mode 100755 new mode 100644 diff --git a/Tools/unicode/comparecodecs.py b/Tools/unicode/comparecodecs.py old mode 100644 new mode 100755 diff --git a/Tools/unittestgui/unittestgui.py b/Tools/unittestgui/unittestgui.py old mode 100644 new mode 100755 --- a/Tools/unittestgui/unittestgui.py +++ b/Tools/unittestgui/unittestgui.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ GUI framework and application for use with Python unit testing framework. Execute tests written using the framework provided by the 'unittest' module. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 17:51:37 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 16 Jan 2014 17:51:37 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE5OTM2?= =?utf-8?q?=3A_Remove_executable_bits_from_C_source_files_and_several_forg?= =?utf-8?q?otten?= Message-ID: <3f4ryx2ntdz7Lkp@mail.python.org> http://hg.python.org/cpython/rev/085a0ea2015f changeset: 88506:085a0ea2015f branch: 3.3 parent: 88504:1100f9824b2f user: Serhiy Storchaka date: Thu Jan 16 18:48:45 2014 +0200 summary: Issue #19936: Remove executable bits from C source files and several forgotten test files. files: Lib/test/test_gzip.py | 0 Mac/PythonLauncher/FileSettings.h | 0 Mac/PythonLauncher/FileSettings.m | 0 Mac/PythonLauncher/MyDocument.h | 0 Mac/PythonLauncher/MyDocument.m | 0 Mac/PythonLauncher/main.m | 0 Modules/_decimal/tests/bench.py | 0 Modules/_decimal/tests/deccheck.py | 0 PC/msvcrtmodule.c | 0 Tools/test2to3/maintest.py | 0 10 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_gzip.py b/Lib/test/test_gzip.py old mode 100755 new mode 100644 diff --git a/Mac/PythonLauncher/FileSettings.h b/Mac/PythonLauncher/FileSettings.h old mode 100755 new mode 100644 diff --git a/Mac/PythonLauncher/FileSettings.m b/Mac/PythonLauncher/FileSettings.m old mode 100755 new mode 100644 diff --git a/Mac/PythonLauncher/MyDocument.h b/Mac/PythonLauncher/MyDocument.h old mode 100755 new mode 100644 diff --git a/Mac/PythonLauncher/MyDocument.m b/Mac/PythonLauncher/MyDocument.m old mode 100755 new mode 100644 diff --git a/Mac/PythonLauncher/main.m b/Mac/PythonLauncher/main.m old mode 100755 new mode 100644 diff --git a/Modules/_decimal/tests/bench.py b/Modules/_decimal/tests/bench.py old mode 100755 new mode 100644 diff --git a/Modules/_decimal/tests/deccheck.py b/Modules/_decimal/tests/deccheck.py old mode 100755 new mode 100644 diff --git a/PC/msvcrtmodule.c b/PC/msvcrtmodule.c old mode 100755 new mode 100644 diff --git a/Tools/test2to3/maintest.py b/Tools/test2to3/maintest.py old mode 100644 new mode 100755 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 17:51:38 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 16 Jan 2014 17:51:38 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2319936=3A_Remove_executable_bits_from_C_source_f?= =?utf-8?q?iles_and_several_forgotten?= Message-ID: <3f4ryy4M4Gz7LlV@mail.python.org> http://hg.python.org/cpython/rev/6baeee39195b changeset: 88507:6baeee39195b parent: 88505:83009d70bc9c parent: 88506:085a0ea2015f user: Serhiy Storchaka date: Thu Jan 16 18:50:53 2014 +0200 summary: Issue #19936: Remove executable bits from C source files and several forgotten test files. files: Mac/PythonLauncher/FileSettings.h | 0 Mac/PythonLauncher/FileSettings.m | 0 Mac/PythonLauncher/MyDocument.h | 0 Mac/PythonLauncher/MyDocument.m | 0 Mac/PythonLauncher/main.m | 0 Modules/_decimal/tests/bench.py | 0 Modules/_decimal/tests/deccheck.py | 0 PC/msvcrtmodule.c | 0 Tools/test2to3/maintest.py | 0 9 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Mac/PythonLauncher/FileSettings.h b/Mac/PythonLauncher/FileSettings.h old mode 100755 new mode 100644 diff --git a/Mac/PythonLauncher/FileSettings.m b/Mac/PythonLauncher/FileSettings.m old mode 100755 new mode 100644 diff --git a/Mac/PythonLauncher/MyDocument.h b/Mac/PythonLauncher/MyDocument.h old mode 100755 new mode 100644 diff --git a/Mac/PythonLauncher/MyDocument.m b/Mac/PythonLauncher/MyDocument.m old mode 100755 new mode 100644 diff --git a/Mac/PythonLauncher/main.m b/Mac/PythonLauncher/main.m old mode 100755 new mode 100644 diff --git a/Modules/_decimal/tests/bench.py b/Modules/_decimal/tests/bench.py old mode 100755 new mode 100644 diff --git a/Modules/_decimal/tests/deccheck.py b/Modules/_decimal/tests/deccheck.py old mode 100755 new mode 100644 diff --git a/PC/msvcrtmodule.c b/PC/msvcrtmodule.c old mode 100755 new mode 100644 diff --git a/Tools/test2to3/maintest.py b/Tools/test2to3/maintest.py old mode 100644 new mode 100755 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 18:00:12 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 16 Jan 2014 18:00:12 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE5OTM2?= =?utf-8?q?=3A_Added_executable_bits_or_shebang_lines_to_Python_scripts_wh?= =?utf-8?q?ich?= Message-ID: <3f4s8r5xxtz7LjT@mail.python.org> http://hg.python.org/cpython/rev/334116bb2939 changeset: 88508:334116bb2939 branch: 2.7 parent: 88499:40289a03569f user: Serhiy Storchaka date: Thu Jan 16 18:59:17 2014 +0200 summary: Issue #19936: Added executable bits or shebang lines to Python scripts which requires them. Disable executable bits and shebang lines in test and benchmark files in order to prevent using a random system python, and in source files of modules which don't provide command line interface. files: Demo/comparisons/patterns | 0 Demo/curses/ncurses.py | 0 Demo/curses/rain.py | 0 Demo/curses/tclock.py | 0 Demo/md5test/foo | 0 Demo/scripts/newslist.doc | 0 Demo/tix/bitmaps/about.xpm | 0 Demo/tix/bitmaps/bold.xbm | 0 Demo/tix/bitmaps/capital.xbm | 0 Demo/tix/bitmaps/centerj.xbm | 0 Demo/tix/bitmaps/combobox.xbm | 0 Demo/tix/bitmaps/combobox.xpm | 0 Demo/tix/bitmaps/combobox.xpm.1 | 0 Demo/tix/bitmaps/drivea.xbm | 0 Demo/tix/bitmaps/drivea.xpm | 0 Demo/tix/bitmaps/exit.xpm | 0 Demo/tix/bitmaps/filebox.xbm | 0 Demo/tix/bitmaps/filebox.xpm | 0 Demo/tix/bitmaps/italic.xbm | 0 Demo/tix/bitmaps/justify.xbm | 0 Demo/tix/bitmaps/leftj.xbm | 0 Demo/tix/bitmaps/netw.xbm | 0 Demo/tix/bitmaps/netw.xpm | 0 Demo/tix/bitmaps/optmenu.xpm | 0 Demo/tix/bitmaps/rightj.xbm | 0 Demo/tix/bitmaps/select.xpm | 0 Demo/tix/bitmaps/underline.xbm | 0 Demo/tkinter/guido/canvasevents.py | 0 Demo/tkinter/guido/newmenubardemo.py | 0 Demo/tkinter/guido/sortvisu.py | 0 Demo/turtle/tdemo_I_dontlike_tiltdemo.py | 0 Demo/turtle/tdemo_bytedesign.py | 0 Demo/turtle/tdemo_clock.py | 0 Demo/turtle/tdemo_fractalcurves.py | 0 Demo/turtle/tdemo_lindenmayer_indian.py | 0 Demo/turtle/tdemo_minimal_hanoi.py | 0 Demo/turtle/tdemo_paint.py | 0 Demo/turtle/tdemo_peace.py | 0 Demo/turtle/tdemo_penrose.py | 0 Demo/turtle/tdemo_planet_and_moon.py | 0 Demo/turtle/tdemo_tree.py | 0 Demo/turtle/tdemo_yinyang.py | 0 Demo/turtle/turtleDemo.py | 0 Demo/turtle/turtledemo_two_canvases.py | 0 Lib/Cookie.py | 3 --- Lib/bsddb/dbshelve.py | 1 - Lib/bsddb/test/test_dbtables.py | 2 -- Lib/difflib.py | 2 -- Lib/encodings/rot_13.py | 0 Lib/lib2to3/tests/data/different_encoding.py | 0 Lib/lib2to3/tests/data/false_encoding.py | 0 Lib/mailbox.py | 2 -- Lib/tarfile.py | 1 - Lib/test/crashers/recursive_call.py | 0 Lib/test/curses_tests.py | 0 Lib/test/test___future__.py | 1 - Lib/test/test_al.py | 1 - Lib/test/test_anydbm.py | 1 - Lib/test/test_array.py | 1 - Lib/test/test_binhex.py | 1 - Lib/test/test_bsddb.py | 1 - Lib/test/test_bz2.py | 1 - Lib/test/test_cd.py | 1 - Lib/test/test_cl.py | 1 - Lib/test/test_cmd.py | 1 - Lib/test/test_codecencodings_cn.py | 1 - Lib/test/test_codecencodings_hk.py | 1 - Lib/test/test_codecencodings_iso2022.py | 2 -- Lib/test/test_codecencodings_jp.py | 1 - Lib/test/test_codecencodings_kr.py | 1 - Lib/test/test_codecencodings_tw.py | 1 - Lib/test/test_codecmaps_cn.py | 1 - Lib/test/test_codecmaps_hk.py | 1 - Lib/test/test_codecmaps_jp.py | 1 - Lib/test/test_codecmaps_kr.py | 1 - Lib/test/test_codecmaps_tw.py | 1 - Lib/test/test_dl.py | 1 - Lib/test/test_dumbdbm.py | 1 - Lib/test/test_eof.py | 1 - Lib/test/test_errno.py | 1 - Lib/test/test_gl.py | 1 - Lib/test/test_gzip.py | 1 - Lib/test/test_imageop.py | 2 -- Lib/test/test_imgfile.py | 2 -- Lib/test/test_logging.py | 2 -- Lib/test/test_marshal.py | 1 - Lib/test/test_multibytecodec.py | 2 -- Lib/test/test_multibytecodec_support.py | 2 -- Lib/test/test_multiprocessing.py | 2 -- Lib/test/test_popen.py | 1 - Lib/test/test_popen2.py | 1 - Lib/test/test_random.py | 2 -- Lib/test/test_sets.py | 2 -- Lib/test/test_smtpnet.py | 2 -- Lib/test/test_socket.py | 2 -- Lib/test/test_tcl.py | 2 -- Lib/test/test_urllib2_localnet.py | 2 -- Lib/test/test_urllib2net.py | 2 -- Lib/test/test_urllibnet.py | 2 -- Lib/test/test_urlparse.py | 2 -- Lib/test/test_userstring.py | 1 - Lib/test/test_whichdb.py | 1 - Lib/test/test_with.py | 2 -- Lib/timeit.py | 0 Lib/token.py | 2 -- Lib/trace.py | 0 Lib/webbrowser.py | 0 Mac/Modules/carbonevt/_CarbonEvtmodule.c | 0 Mac/Modules/cg/CFMLateImport.c | 0 Mac/Modules/cg/CFMLateImport.h | 0 Mac/Modules/cg/CGStubLib.exp | 0 Mac/Modules/cg/CGStubLib.readme | 0 Mac/Modules/cg/_CGmodule.c | 0 Mac/PythonLauncher/FileSettings.h | 0 Mac/PythonLauncher/FileSettings.m | 0 Mac/PythonLauncher/MyDocument.h | 0 Mac/PythonLauncher/MyDocument.m | 0 Mac/PythonLauncher/main.m | 0 Mac/Tools/fixapplepython23.py | 0 Mac/scripts/buildpkg.py | 0 Mac/scripts/mkestrres-macerrors.h | 0 Mac/scripts/zappycfiles.py | 0 Misc/NEWS | 8 ++++++++ Modules/_ctypes/libffi/generate-ios-source-and-headers.py | 0 Modules/_ctypes/libffi/generate-osx-source-and-headers.py | 0 PC/msvcrtmodule.c | 0 Tools/gdb/libpython.py | 0 Tools/i18n/makelocalealias.py | 0 Tools/pybench/Setup.py | 0 Tools/pybench/clockres.py | 0 Tools/pybench/systimes.py | 0 Tools/scripts/svneol.py | 0 Tools/ssl/get-remote-certificate.py | 0 Tools/unicode/comparecodecs.py | 0 134 files changed, 8 insertions(+), 78 deletions(-) diff --git a/Demo/comparisons/patterns b/Demo/comparisons/patterns old mode 100755 new mode 100644 diff --git a/Demo/curses/ncurses.py b/Demo/curses/ncurses.py old mode 100644 new mode 100755 diff --git a/Demo/curses/rain.py b/Demo/curses/rain.py old mode 100644 new mode 100755 diff --git a/Demo/curses/tclock.py b/Demo/curses/tclock.py old mode 100644 new mode 100755 diff --git a/Demo/md5test/foo b/Demo/md5test/foo old mode 100755 new mode 100644 diff --git a/Demo/scripts/newslist.doc b/Demo/scripts/newslist.doc old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/about.xpm b/Demo/tix/bitmaps/about.xpm old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/bold.xbm b/Demo/tix/bitmaps/bold.xbm old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/capital.xbm b/Demo/tix/bitmaps/capital.xbm old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/centerj.xbm b/Demo/tix/bitmaps/centerj.xbm old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/combobox.xbm b/Demo/tix/bitmaps/combobox.xbm old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/combobox.xpm b/Demo/tix/bitmaps/combobox.xpm old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/combobox.xpm.1 b/Demo/tix/bitmaps/combobox.xpm.1 old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/drivea.xbm b/Demo/tix/bitmaps/drivea.xbm old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/drivea.xpm b/Demo/tix/bitmaps/drivea.xpm old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/exit.xpm b/Demo/tix/bitmaps/exit.xpm old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/filebox.xbm b/Demo/tix/bitmaps/filebox.xbm old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/filebox.xpm b/Demo/tix/bitmaps/filebox.xpm old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/italic.xbm b/Demo/tix/bitmaps/italic.xbm old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/justify.xbm b/Demo/tix/bitmaps/justify.xbm old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/leftj.xbm b/Demo/tix/bitmaps/leftj.xbm old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/netw.xbm b/Demo/tix/bitmaps/netw.xbm old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/netw.xpm b/Demo/tix/bitmaps/netw.xpm old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/optmenu.xpm b/Demo/tix/bitmaps/optmenu.xpm old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/rightj.xbm b/Demo/tix/bitmaps/rightj.xbm old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/select.xpm b/Demo/tix/bitmaps/select.xpm old mode 100755 new mode 100644 diff --git a/Demo/tix/bitmaps/underline.xbm b/Demo/tix/bitmaps/underline.xbm old mode 100755 new mode 100644 diff --git a/Demo/tkinter/guido/canvasevents.py b/Demo/tkinter/guido/canvasevents.py old mode 100644 new mode 100755 diff --git a/Demo/tkinter/guido/newmenubardemo.py b/Demo/tkinter/guido/newmenubardemo.py old mode 100644 new mode 100755 diff --git a/Demo/tkinter/guido/sortvisu.py b/Demo/tkinter/guido/sortvisu.py old mode 100644 new mode 100755 diff --git a/Demo/turtle/tdemo_I_dontlike_tiltdemo.py b/Demo/turtle/tdemo_I_dontlike_tiltdemo.py old mode 100644 new mode 100755 diff --git a/Demo/turtle/tdemo_bytedesign.py b/Demo/turtle/tdemo_bytedesign.py old mode 100644 new mode 100755 diff --git a/Demo/turtle/tdemo_clock.py b/Demo/turtle/tdemo_clock.py old mode 100644 new mode 100755 diff --git a/Demo/turtle/tdemo_fractalcurves.py b/Demo/turtle/tdemo_fractalcurves.py old mode 100644 new mode 100755 diff --git a/Demo/turtle/tdemo_lindenmayer_indian.py b/Demo/turtle/tdemo_lindenmayer_indian.py old mode 100644 new mode 100755 diff --git a/Demo/turtle/tdemo_minimal_hanoi.py b/Demo/turtle/tdemo_minimal_hanoi.py old mode 100644 new mode 100755 diff --git a/Demo/turtle/tdemo_paint.py b/Demo/turtle/tdemo_paint.py old mode 100644 new mode 100755 diff --git a/Demo/turtle/tdemo_peace.py b/Demo/turtle/tdemo_peace.py old mode 100644 new mode 100755 diff --git a/Demo/turtle/tdemo_penrose.py b/Demo/turtle/tdemo_penrose.py old mode 100644 new mode 100755 diff --git a/Demo/turtle/tdemo_planet_and_moon.py b/Demo/turtle/tdemo_planet_and_moon.py old mode 100644 new mode 100755 diff --git a/Demo/turtle/tdemo_tree.py b/Demo/turtle/tdemo_tree.py old mode 100644 new mode 100755 diff --git a/Demo/turtle/tdemo_yinyang.py b/Demo/turtle/tdemo_yinyang.py old mode 100644 new mode 100755 diff --git a/Demo/turtle/turtleDemo.py b/Demo/turtle/turtleDemo.py old mode 100644 new mode 100755 diff --git a/Demo/turtle/turtledemo_two_canvases.py b/Demo/turtle/turtledemo_two_canvases.py old mode 100644 new mode 100755 diff --git a/Lib/Cookie.py b/Lib/Cookie.py --- a/Lib/Cookie.py +++ b/Lib/Cookie.py @@ -1,6 +1,3 @@ -#!/usr/bin/env python -# - #### # Copyright 2000 by Timothy O'Malley # diff --git a/Lib/bsddb/dbshelve.py b/Lib/bsddb/dbshelve.py --- a/Lib/bsddb/dbshelve.py +++ b/Lib/bsddb/dbshelve.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python #------------------------------------------------------------------------ # Copyright (c) 1997-2001 by Total Control Software # All Rights Reserved diff --git a/Lib/bsddb/test/test_dbtables.py b/Lib/bsddb/test/test_dbtables.py --- a/Lib/bsddb/test/test_dbtables.py +++ b/Lib/bsddb/test/test_dbtables.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# #----------------------------------------------------------------------- # A test suite for the table interface built on bsddb.db #----------------------------------------------------------------------- diff --git a/Lib/difflib.py b/Lib/difflib.py --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -1,5 +1,3 @@ -#! /usr/bin/env python - """ Module difflib -- helpers for computing deltas between objects. diff --git a/Lib/encodings/rot_13.py b/Lib/encodings/rot_13.py old mode 100644 new mode 100755 diff --git a/Lib/lib2to3/tests/data/different_encoding.py b/Lib/lib2to3/tests/data/different_encoding.py old mode 100644 new mode 100755 diff --git a/Lib/lib2to3/tests/data/false_encoding.py b/Lib/lib2to3/tests/data/false_encoding.py old mode 100644 new mode 100755 diff --git a/Lib/mailbox.py b/Lib/mailbox.py --- a/Lib/mailbox.py +++ b/Lib/mailbox.py @@ -1,5 +1,3 @@ -#! /usr/bin/env python - """Read/write support for Maildir, mbox, MH, Babyl, and MMDF mailboxes.""" # Notes for authors of new mailbox subclasses: diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # -*- coding: iso-8859-1 -*- #------------------------------------------------------------------- # tarfile.py diff --git a/Lib/test/crashers/recursive_call.py b/Lib/test/crashers/recursive_call.py old mode 100644 new mode 100755 diff --git a/Lib/test/curses_tests.py b/Lib/test/curses_tests.py old mode 100644 new mode 100755 diff --git a/Lib/test/test___future__.py b/Lib/test/test___future__.py --- a/Lib/test/test___future__.py +++ b/Lib/test/test___future__.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python import unittest from test import test_support import __future__ diff --git a/Lib/test/test_al.py b/Lib/test/test_al.py old mode 100755 new mode 100644 --- a/Lib/test/test_al.py +++ b/Lib/test/test_al.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python """Whimpy test script for the al module Roger E. Masse """ diff --git a/Lib/test/test_anydbm.py b/Lib/test/test_anydbm.py --- a/Lib/test/test_anydbm.py +++ b/Lib/test/test_anydbm.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python """Test script for the anydbm module based on testdumbdbm.py """ diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py old mode 100755 new mode 100644 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python """Test the arraymodule. Roger E. Masse """ diff --git a/Lib/test/test_binhex.py b/Lib/test/test_binhex.py old mode 100755 new mode 100644 --- a/Lib/test/test_binhex.py +++ b/Lib/test/test_binhex.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python """Test script for the binhex C module Uses the mechanism of the python binhex module diff --git a/Lib/test/test_bsddb.py b/Lib/test/test_bsddb.py old mode 100755 new mode 100644 --- a/Lib/test/test_bsddb.py +++ b/Lib/test/test_bsddb.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python """Test script for the bsddb C module by Roger E. Masse Adapted to unittest format and expanded scope by Raymond Hettinger """ diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py --- a/Lib/test/test_bz2.py +++ b/Lib/test/test_bz2.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python from test import test_support from test.test_support import TESTFN, _4G, bigmemtest, import_module, findfile diff --git a/Lib/test/test_cd.py b/Lib/test/test_cd.py old mode 100755 new mode 100644 --- a/Lib/test/test_cd.py +++ b/Lib/test/test_cd.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python """Whimpy test script for the cd module Roger E. Masse """ diff --git a/Lib/test/test_cl.py b/Lib/test/test_cl.py old mode 100755 new mode 100644 --- a/Lib/test/test_cl.py +++ b/Lib/test/test_cl.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python """Whimpy test script for the cl module Roger E. Masse """ diff --git a/Lib/test/test_cmd.py b/Lib/test/test_cmd.py --- a/Lib/test/test_cmd.py +++ b/Lib/test/test_cmd.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python """ Test script for the 'cmd' module Original by Michael Schneider diff --git a/Lib/test/test_codecencodings_cn.py b/Lib/test/test_codecencodings_cn.py --- a/Lib/test/test_codecencodings_cn.py +++ b/Lib/test/test_codecencodings_cn.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # # test_codecencodings_cn.py # Codec encoding tests for PRC encodings. diff --git a/Lib/test/test_codecencodings_hk.py b/Lib/test/test_codecencodings_hk.py --- a/Lib/test/test_codecencodings_hk.py +++ b/Lib/test/test_codecencodings_hk.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # # test_codecencodings_hk.py # Codec encoding tests for HongKong encodings. diff --git a/Lib/test/test_codecencodings_iso2022.py b/Lib/test/test_codecencodings_iso2022.py --- a/Lib/test/test_codecencodings_iso2022.py +++ b/Lib/test/test_codecencodings_iso2022.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# # Codec encoding tests for ISO 2022 encodings. from test import test_support diff --git a/Lib/test/test_codecencodings_jp.py b/Lib/test/test_codecencodings_jp.py --- a/Lib/test/test_codecencodings_jp.py +++ b/Lib/test/test_codecencodings_jp.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # # test_codecencodings_jp.py # Codec encoding tests for Japanese encodings. diff --git a/Lib/test/test_codecencodings_kr.py b/Lib/test/test_codecencodings_kr.py --- a/Lib/test/test_codecencodings_kr.py +++ b/Lib/test/test_codecencodings_kr.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # # test_codecencodings_kr.py # Codec encoding tests for ROK encodings. diff --git a/Lib/test/test_codecencodings_tw.py b/Lib/test/test_codecencodings_tw.py --- a/Lib/test/test_codecencodings_tw.py +++ b/Lib/test/test_codecencodings_tw.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # # test_codecencodings_tw.py # Codec encoding tests for ROC encodings. diff --git a/Lib/test/test_codecmaps_cn.py b/Lib/test/test_codecmaps_cn.py --- a/Lib/test/test_codecmaps_cn.py +++ b/Lib/test/test_codecmaps_cn.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # # test_codecmaps_cn.py # Codec mapping tests for PRC encodings diff --git a/Lib/test/test_codecmaps_hk.py b/Lib/test/test_codecmaps_hk.py --- a/Lib/test/test_codecmaps_hk.py +++ b/Lib/test/test_codecmaps_hk.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # # test_codecmaps_hk.py # Codec mapping tests for HongKong encodings diff --git a/Lib/test/test_codecmaps_jp.py b/Lib/test/test_codecmaps_jp.py --- a/Lib/test/test_codecmaps_jp.py +++ b/Lib/test/test_codecmaps_jp.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # # test_codecmaps_jp.py # Codec mapping tests for Japanese encodings diff --git a/Lib/test/test_codecmaps_kr.py b/Lib/test/test_codecmaps_kr.py --- a/Lib/test/test_codecmaps_kr.py +++ b/Lib/test/test_codecmaps_kr.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # # test_codecmaps_kr.py # Codec mapping tests for ROK encodings diff --git a/Lib/test/test_codecmaps_tw.py b/Lib/test/test_codecmaps_tw.py --- a/Lib/test/test_codecmaps_tw.py +++ b/Lib/test/test_codecmaps_tw.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # # test_codecmaps_tw.py # Codec mapping tests for ROC encodings diff --git a/Lib/test/test_dl.py b/Lib/test/test_dl.py old mode 100755 new mode 100644 --- a/Lib/test/test_dl.py +++ b/Lib/test/test_dl.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python """Test dlmodule.c Roger E. Masse revised strategy by Barry Warsaw """ diff --git a/Lib/test/test_dumbdbm.py b/Lib/test/test_dumbdbm.py --- a/Lib/test/test_dumbdbm.py +++ b/Lib/test/test_dumbdbm.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python """Test script for the dumbdbm module Original by Roger E. Masse """ diff --git a/Lib/test/test_eof.py b/Lib/test/test_eof.py --- a/Lib/test/test_eof.py +++ b/Lib/test/test_eof.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python """test script for a few new invalid token catches""" import unittest diff --git a/Lib/test/test_errno.py b/Lib/test/test_errno.py old mode 100755 new mode 100644 --- a/Lib/test/test_errno.py +++ b/Lib/test/test_errno.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python """Test the errno module Roger E. Masse """ diff --git a/Lib/test/test_gl.py b/Lib/test/test_gl.py old mode 100755 new mode 100644 --- a/Lib/test/test_gl.py +++ b/Lib/test/test_gl.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python """Very simple test script for the SGI gl library extension module taken mostly from the documentation. Roger E. Masse 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 @@ -1,4 +1,3 @@ -#! /usr/bin/env python """Test script for the gzip module. """ diff --git a/Lib/test/test_imageop.py b/Lib/test/test_imageop.py old mode 100755 new mode 100644 --- a/Lib/test/test_imageop.py +++ b/Lib/test/test_imageop.py @@ -1,5 +1,3 @@ -#! /usr/bin/env python - """Test script for the imageop module. This has the side effect of partially testing the imgfile module as well. Roger E. Masse diff --git a/Lib/test/test_imgfile.py b/Lib/test/test_imgfile.py old mode 100755 new mode 100644 --- a/Lib/test/test_imgfile.py +++ b/Lib/test/test_imgfile.py @@ -1,5 +1,3 @@ -#! /usr/bin/env python - """Simple test script for imgfile.c Roger E. Masse """ 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 @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# # Copyright 2001-2013 by Vinay Sajip. All Rights Reserved. # # Permission to use, copy, modify, and distribute this software and its diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # -*- coding: iso-8859-1 -*- from test import test_support diff --git a/Lib/test/test_multibytecodec.py b/Lib/test/test_multibytecodec.py --- a/Lib/test/test_multibytecodec.py +++ b/Lib/test/test_multibytecodec.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# # test_multibytecodec.py # Unit test for multibytecodec itself # diff --git a/Lib/test/test_multibytecodec_support.py b/Lib/test/test_multibytecodec_support.py --- a/Lib/test/test_multibytecodec_support.py +++ b/Lib/test/test_multibytecodec_support.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -# # test_multibytecodec_support.py # Common Unittest Routines for CJK codecs # diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # # Unit tests for the multiprocessing package # diff --git a/Lib/test/test_popen.py b/Lib/test/test_popen.py --- a/Lib/test/test_popen.py +++ b/Lib/test/test_popen.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python """Basic tests for os.popen() Particularly useful for platforms that fake popen. diff --git a/Lib/test/test_popen2.py b/Lib/test/test_popen2.py --- a/Lib/test/test_popen2.py +++ b/Lib/test/test_popen2.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python """Test script for popen2.py""" import warnings 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 @@ -1,5 +1,3 @@ -#!/usr/bin/env python - import unittest import random import time diff --git a/Lib/test/test_sets.py b/Lib/test/test_sets.py --- a/Lib/test/test_sets.py +++ b/Lib/test/test_sets.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - import unittest, operator, copy, pickle, random from test import test_support diff --git a/Lib/test/test_smtpnet.py b/Lib/test/test_smtpnet.py --- a/Lib/test/test_smtpnet.py +++ b/Lib/test/test_smtpnet.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - import unittest from test import test_support import smtplib 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 @@ -1,5 +1,3 @@ -#!/usr/bin/env python - import unittest from test import test_support diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - import unittest import sys import os 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 @@ -1,5 +1,3 @@ -#!/usr/bin/env python - import urlparse import urllib2 import BaseHTTPServer diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py --- a/Lib/test/test_urllib2net.py +++ b/Lib/test/test_urllib2net.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - import unittest from test import test_support from test.test_urllib2 import sanepathname2url diff --git a/Lib/test/test_urllibnet.py b/Lib/test/test_urllibnet.py --- a/Lib/test/test_urllibnet.py +++ b/Lib/test/test_urllibnet.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - import unittest from test import test_support diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -1,5 +1,3 @@ -#! /usr/bin/env python - from test import test_support import unittest import urlparse diff --git a/Lib/test/test_userstring.py b/Lib/test/test_userstring.py old mode 100755 new mode 100644 --- a/Lib/test/test_userstring.py +++ b/Lib/test/test_userstring.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python # UserString is a wrapper around the native builtin string type. # UserString instances should behave similar to builtin string objects. diff --git a/Lib/test/test_whichdb.py b/Lib/test/test_whichdb.py --- a/Lib/test/test_whichdb.py +++ b/Lib/test/test_whichdb.py @@ -1,4 +1,3 @@ -#! /usr/bin/env python """Test script for the whichdb module based on test_anydbm.py """ diff --git a/Lib/test/test_with.py b/Lib/test/test_with.py --- a/Lib/test/test_with.py +++ b/Lib/test/test_with.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - """Unit tests for the with statement specified in PEP 343.""" diff --git a/Lib/timeit.py b/Lib/timeit.py old mode 100644 new mode 100755 diff --git a/Lib/token.py b/Lib/token.py old mode 100755 new mode 100644 --- a/Lib/token.py +++ b/Lib/token.py @@ -1,5 +1,3 @@ -#! /usr/bin/env python - """Token constants (from "token.h").""" # This file is automatically generated; please don't muck it up! diff --git a/Lib/trace.py b/Lib/trace.py old mode 100644 new mode 100755 diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py old mode 100644 new mode 100755 diff --git a/Mac/Modules/carbonevt/_CarbonEvtmodule.c b/Mac/Modules/carbonevt/_CarbonEvtmodule.c old mode 100755 new mode 100644 diff --git a/Mac/Modules/cg/CFMLateImport.c b/Mac/Modules/cg/CFMLateImport.c old mode 100755 new mode 100644 diff --git a/Mac/Modules/cg/CFMLateImport.h b/Mac/Modules/cg/CFMLateImport.h old mode 100755 new mode 100644 diff --git a/Mac/Modules/cg/CGStubLib.exp b/Mac/Modules/cg/CGStubLib.exp old mode 100755 new mode 100644 diff --git a/Mac/Modules/cg/CGStubLib.readme b/Mac/Modules/cg/CGStubLib.readme old mode 100755 new mode 100644 diff --git a/Mac/Modules/cg/_CGmodule.c b/Mac/Modules/cg/_CGmodule.c old mode 100755 new mode 100644 diff --git a/Mac/PythonLauncher/FileSettings.h b/Mac/PythonLauncher/FileSettings.h old mode 100755 new mode 100644 diff --git a/Mac/PythonLauncher/FileSettings.m b/Mac/PythonLauncher/FileSettings.m old mode 100755 new mode 100644 diff --git a/Mac/PythonLauncher/MyDocument.h b/Mac/PythonLauncher/MyDocument.h old mode 100755 new mode 100644 diff --git a/Mac/PythonLauncher/MyDocument.m b/Mac/PythonLauncher/MyDocument.m old mode 100755 new mode 100644 diff --git a/Mac/PythonLauncher/main.m b/Mac/PythonLauncher/main.m old mode 100755 new mode 100644 diff --git a/Mac/Tools/fixapplepython23.py b/Mac/Tools/fixapplepython23.py old mode 100644 new mode 100755 diff --git a/Mac/scripts/buildpkg.py b/Mac/scripts/buildpkg.py old mode 100644 new mode 100755 diff --git a/Mac/scripts/mkestrres-macerrors.h b/Mac/scripts/mkestrres-macerrors.h old mode 100755 new mode 100644 diff --git a/Mac/scripts/zappycfiles.py b/Mac/scripts/zappycfiles.py old mode 100644 new mode 100755 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -152,6 +152,14 @@ - Issue #19286: Directories in ``package_data`` are no longer added to the filelist, preventing failure outlined in the ticket. +Tools/Demos +----------- + +- Issue #19936: Added executable bits or shebang lines to Python scripts which + requires them. Disable executable bits and shebang lines in test and + benchmark files in order to prevent using a random system python, and in + source files of modules which don't provide command line interface. + IDLE ---- diff --git a/Modules/_ctypes/libffi/generate-ios-source-and-headers.py b/Modules/_ctypes/libffi/generate-ios-source-and-headers.py old mode 100644 new mode 100755 diff --git a/Modules/_ctypes/libffi/generate-osx-source-and-headers.py b/Modules/_ctypes/libffi/generate-osx-source-and-headers.py old mode 100644 new mode 100755 diff --git a/PC/msvcrtmodule.c b/PC/msvcrtmodule.c old mode 100755 new mode 100644 diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py old mode 100644 new mode 100755 diff --git a/Tools/i18n/makelocalealias.py b/Tools/i18n/makelocalealias.py old mode 100644 new mode 100755 diff --git a/Tools/pybench/Setup.py b/Tools/pybench/Setup.py old mode 100644 new mode 100755 diff --git a/Tools/pybench/clockres.py b/Tools/pybench/clockres.py old mode 100644 new mode 100755 diff --git a/Tools/pybench/systimes.py b/Tools/pybench/systimes.py old mode 100644 new mode 100755 diff --git a/Tools/scripts/svneol.py b/Tools/scripts/svneol.py old mode 100644 new mode 100755 diff --git a/Tools/ssl/get-remote-certificate.py b/Tools/ssl/get-remote-certificate.py old mode 100644 new mode 100755 diff --git a/Tools/unicode/comparecodecs.py b/Tools/unicode/comparecodecs.py old mode 100644 new mode 100755 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 18:58:10 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 16 Jan 2014 18:58:10 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_add_a_new_=22De?= =?utf-8?q?velop_with_asyncio=22_section_to_the_documentation?= Message-ID: <3f4tRk0rJ5z7Ljk@mail.python.org> http://hg.python.org/cpython/rev/a5bd41cae6df changeset: 88509:a5bd41cae6df parent: 88507:6baeee39195b user: Victor Stinner date: Thu Jan 16 18:58:01 2014 +0100 summary: asyncio: add a new "Develop with asyncio" section to the documentation files: Doc/library/asyncio-dev.rst | 210 +++++++++++++++++++++++ Doc/library/asyncio-task.rst | 8 + Doc/library/asyncio.rst | 1 + 3 files changed, 219 insertions(+), 0 deletions(-) diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst new file mode 100644 --- /dev/null +++ b/Doc/library/asyncio-dev.rst @@ -0,0 +1,210 @@ +.. currentmodule:: asyncio + +Develop with asyncio +==================== + +Asynchronous programming is different than classical "sequential" programming. +This page lists common traps and explain how to avoid them. + + +Handle correctly blocking functions +----------------------------------- + +Blocking functions should not be called directly. For example, if a function +blocks for 1 second, other tasks are delayed by 1 second which can have an +important impact on reactivity. + +For networking and subprocesses, the :mod:`asyncio` module provides high-level +APIs like :ref:`protocols `. + +An executor can be used to run a task in a different thread or even in a +different process, to not block the thread of the event loop. See the +:func:`BaseEventLoop.run_in_executor` function. + + +.. _asyncio-logger: + +Logger +------ + +.. data:: asyncio.logger.log + + :class:`logging.Logger` instance used by :mod:`asyncio` to log messages. + +The logger name is ``'asyncio'``. + +.. _asyncio-coroutine-not-scheduled: + +Detect coroutine objects never scheduled +---------------------------------------- + +When a coroutine function is called but not passed to :func:`async` or to the +:class:`Task` constructor, it is not scheduled and it is probably a bug. + +To detect such bug, set :data:`asyncio.tasks._DEBUG` to ``True``. When the +coroutine object is destroyed by the garbage collector, a log will be emitted +with the traceback where the coroutine function was called. See the +:ref:`asyncio logger `. + +The debug flag changes the behaviour of the :func:`coroutine` decorator. The +debug flag value is only when then coroutine function is defined, not when it +is called. Coroutine functions defined before the debug flag is set to +``True`` will not be tracked. For example, it is not possible to debug +coroutines defined in the :mod:`asyncio` module, because the module must be +imported before the flag value can be changed. + +Example with the bug:: + + import asyncio + asyncio.tasks._DEBUG = True + + @asyncio.coroutine + def test(): + print("never scheduled") + + test() + +Output in debug mode:: + + Coroutine 'test' defined at test.py:4 was never yielded from + +The fix is to call the :func:`async` function or create a :class:`Task` object +with this coroutine object. + + +Detect exceptions not consumed +------------------------------ + +Python usually calls :func:`sys.displayhook` on unhandled exceptions. If +:meth:`Future.set_exception` is called, but the exception is not consumed, +:func:`sys.displayhook` is not called. Instead, a log is emitted when the +future is deleted by the garbage collector, with the traceback where the +exception was raised. See the :ref:`asyncio logger `. + +Example of unhandled exception:: + + import asyncio + + @asyncio.coroutine + def bug(): + raise Exception("not consumed") + + loop = asyncio.get_event_loop() + asyncio.async(bug()) + loop.run_forever() + +Output:: + + Future/Task exception was never retrieved: + Traceback (most recent call last): + File "/usr/lib/python3.4/asyncio/tasks.py", line 279, in _step + result = next(coro) + File "/usr/lib/python3.4/asyncio/tasks.py", line 80, in coro + res = func(*args, **kw) + File "test.py", line 5, in bug + raise Exception("not consumed") + Exception: not consumed + +There are different options to fix this issue. The first option is to chain to +coroutine in another coroutine and use classic try/except:: + + @asyncio.coroutine + def handle_exception(): + try: + yield from bug() + except Exception: + print("exception consumed") + + loop = asyncio.get_event_loop() + asyncio.async(handle_exception()) + loop.run_forever() + +Another option is to use the :meth:`BaseEventLoop.run_until_complete` +function:: + + task = asyncio.async(bug()) + try: + loop.run_until_complete(task) + except Exception: + print("exception consumed") + +See also the :meth:`Future.exception` method. + + +Chain correctly coroutines +-------------------------- + +When a coroutine function calls other coroutine functions and tasks, they +should chained explicitly with ``yield from``. Otherwise, the execution is no +more guaranteed to be sequential. + +Example with different bugs using sleep to simulate slow operations:: + + import asyncio + + @asyncio.coroutine + def create(): + yield from asyncio.sleep(3.0) + print("(1) create file") + + @asyncio.coroutine + def write(): + yield from asyncio.sleep(1.0) + print("(2) write into file") + + @asyncio.coroutine + def close(): + print("(3) close file") + + @asyncio.coroutine + def test(): + asyncio.async(create()) + asyncio.async(write()) + asyncio.async(close()) + yield from asyncio.sleep(2.0) + loop.stop() + + loop = asyncio.get_event_loop() + asyncio.async(test()) + loop.run_forever() + print("Pending tasks at exit: %s" % asyncio.Task.all_tasks(loop)) + +Expected output:: + + (1) create file + (2) write into file + (3) close file + Pending tasks at exit: set() + +Actual output:: + + (3) close file + (2) write into file + Pending tasks at exit: {Task()} + +The loop stopped before the ``create()`` finished, ``close()`` has been called +before ``write()``, whereas coroutine functions were called in this order: +``create()``, ``write()``, ``close()``. + +To fix the example, tasks must be marked with ``yield from``:: + + @asyncio.coroutine + def test(): + yield from asyncio.async(create()) + yield from asyncio.async(write()) + yield from asyncio.async(close()) + yield from asyncio.sleep(2.0) + loop.stop() + +Or without ``asyncio.async()``:: + + @asyncio.coroutine + def test(): + yield from create() + yield from write() + yield from close() + yield from asyncio.sleep(2.0) + loop.stop() + +.. XXX: Document "poll xxx" log message? + 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 @@ -55,6 +55,14 @@ Coroutines (and tasks) can only run when the event loop is running. +.. decorator:: coroutine + + Decorator to mark coroutines. + + If the coroutine is not yielded from before it is destroyed, an error + message is logged. See :ref:`Detect coroutines never scheduled + `. + .. _asyncio-hello-world-coroutine: diff --git a/Doc/library/asyncio.rst b/Doc/library/asyncio.rst --- a/Doc/library/asyncio.rst +++ b/Doc/library/asyncio.rst @@ -48,6 +48,7 @@ asyncio-task.rst asyncio-protocol.rst asyncio-sync.rst + asyncio-dev.rst .. seealso:: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 19:30:36 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 16 Jan 2014 19:30:36 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio_doc=3A_replace_=22?= =?utf-8?q?coroutine=22_with_=22coroutine_object=22_or_=22coroutine_functi?= =?utf-8?b?b24i?= Message-ID: <3f4v981gg2z7LjR@mail.python.org> http://hg.python.org/cpython/rev/5ecc751b7cf8 changeset: 88510:5ecc751b7cf8 user: Victor Stinner date: Thu Jan 16 19:30:21 2014 +0100 summary: asyncio doc: replace "coroutine" with "coroutine object" or "coroutine function" files: Doc/library/asyncio-eventloop.rst | 16 ++++---- Doc/library/asyncio-protocol.rst | 14 +++--- Doc/library/asyncio-sync.rst | 16 ++++---- Doc/library/asyncio-task.rst | 34 ++++++++++-------- 4 files changed, 41 insertions(+), 39 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 @@ -158,7 +158,7 @@ *port*. *protocol_factory* must be a callable returning a :ref:`protocol ` instance. - This method returns a :ref:`coroutine ` which will try to + This method returns a :ref:`coroutine object ` which will try to establish the connection in the background. When successful, the coroutine returns a ``(transport, protocol)`` pair. @@ -219,7 +219,7 @@ .. method:: BaseEventLoop.create_server(protocol_factory, host=None, port=None, \*, family=socket.AF_UNSPEC, flags=socket.AI_PASSIVE, sock=None, backlog=100, ssl=None, reuse_address=None) - A :ref:`coroutine ` which creates a TCP server bound to host and + A :ref:`coroutine function ` which creates a TCP server bound to host and port. The return value is a :class:`AbstractServer` object which can be used to stop @@ -249,13 +249,13 @@ expire. If not specified will automatically be set to True on UNIX. - This method returns a :ref:`coroutine `. + This method returns a :ref:`coroutine object `. .. method:: BaseEventLoop.create_datagram_endpoint(protocol_factory, local_addr=None, remote_addr=None, \*, family=0, proto=0, flags=0) Create datagram connection. - This method returns a :ref:`coroutine `. + This method returns a :ref:`coroutine object `. @@ -280,7 +280,7 @@ XXX - This method returns a :ref:`coroutine `. + This method returns a :ref:`coroutine object `. See the constructor of the :class:`subprocess.Popen` class for parameters. @@ -288,7 +288,7 @@ XXX - This method returns a :ref:`coroutine `. + This method returns a :ref:`coroutine object `. See the constructor of the :class:`subprocess.Popen` class for parameters. @@ -301,7 +301,7 @@ Return pair (transport, protocol), where transport support :class:`ReadTransport` interface. - This method returns a :ref:`coroutine `. + This method returns a :ref:`coroutine object `. .. method:: BaseEventLoop.connect_write_pipe(protocol_factory, pipe) @@ -312,7 +312,7 @@ Return pair (transport, protocol), where transport support :class:`WriteTransport` interface. - This method returns a :ref:`coroutine `. + This method returns a :ref:`coroutine object `. Executor 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 @@ -320,19 +320,19 @@ XXX - This method returns a :ref:`coroutine `. + This method returns a :ref:`coroutine object `. .. method:: readline() XXX - This method returns a :ref:`coroutine `. + This method returns a :ref:`coroutine object `. .. method:: readexactly(n) XXX - This method returns a :ref:`coroutine `. + This method returns a :ref:`coroutine object `. @@ -550,7 +550,7 @@ :class:`StreamReaderProtocol` classes, just copy the code -- there's really nothing special here except some convenience.) - This function returns a :ref:`coroutine `. + This function returns a :ref:`coroutine object `. .. function:: start_server(client_connected_cb, host=None, port=None, *, loop=None, limit=_DEFAULT_LIMIT, **kwds) @@ -560,8 +560,8 @@ *client_reader*, *client_writer*. *client_reader* is a :class:`StreamReader` object, while *client_writer* is a :class:`StreamWriter` object. This parameter can either be a plain callback - function or a :ref:`coroutine `; if it is a coroutine, it will be - automatically converted into a :class:`Task`. + function or a :ref:`coroutine function `; if it is a coroutine + function, it will be automatically converted into a :class:`Task`. The rest of the arguments are all the usual arguments to :meth:`~BaseEventLoop.create_server()` except *protocol_factory*; most @@ -576,7 +576,7 @@ The return value is the same as :meth:`~BaseEventLoop.create_server()`, i.e. a :class:`AbstractServer` object which can be used to stop the service. - This function returns a :ref:`coroutine `. + This function returns a :ref:`coroutine object `. Protocol example: TCP echo server and client diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-sync.rst --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-sync.rst @@ -70,7 +70,7 @@ This method blocks until the lock is unlocked, then sets it to locked and returns ``True``. - This method returns a :ref:`coroutine `. + This method returns a :ref:`coroutine object `. .. method:: release() @@ -118,7 +118,7 @@ Otherwise, block until another coroutine calls :meth:`set` to set the flag to true, then return ``True``. - This method returns a :ref:`coroutine `. + This method returns a :ref:`coroutine object `. .. class:: Condition(\*, loop=None) @@ -166,7 +166,7 @@ condition variable in another coroutine. Once awakened, it re-acquires the lock and returns ``True``. - This method returns a :ref:`coroutine `. + This method returns a :ref:`coroutine object `. .. method:: wait_for(predicate) @@ -175,7 +175,7 @@ The predicate should be a callable which result will be interpreted as a boolean value. The final predicate value is the return value. - This method returns a :ref:`coroutine `. + This method returns a :ref:`coroutine object `. Semaphores @@ -205,7 +205,7 @@ until some other coroutine has called :meth:`release` to make it larger than ``0``, and then return ``True``. - This method returns a :ref:`coroutine `. + This method returns a :ref:`coroutine object `. .. method:: locked() @@ -261,7 +261,7 @@ If you yield from :meth:`get()`, wait until a item is available. - This method returns a :ref:`coroutine `. + This method returns a :ref:`coroutine object `. .. method:: get_nowait() @@ -277,7 +277,7 @@ If you yield from ``put()``, wait until a free slot is available before adding item. - This method returns a :ref:`coroutine `. + This method returns a :ref:`coroutine object `. .. method:: put_nowait(item) @@ -323,7 +323,7 @@ it is complete. When the count of unfinished tasks drops to zero, :meth:`join` unblocks. - This method returns a :ref:`coroutine `. + This method returns a :ref:`coroutine object `. .. method:: task_done() 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 @@ -19,7 +19,7 @@ different (though related) concepts: - The function that defines a coroutine (a function definition - decorated with ``asyncio.coroutine``). If disambiguation is needed + decorated with ``@asyncio.coroutine``). If disambiguation is needed we will call this a *coroutine function*. - The object obtained by calling a coroutine function. This object @@ -117,7 +117,7 @@ :align: center The "Task" is created by the :meth:`BaseEventLoop.run_until_complete` method -when it gets a coroutine instead of a task. +when it gets a coroutine object instead of a task. The diagram shows the control flow, it does not describe exactly how things work internally. For example, the sleep coroutine creates an internal future @@ -219,7 +219,8 @@ Example: Future with run_until_complete() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Example combining a :class:`Future` and a :ref:`coroutine `:: +Example combining a :class:`Future` and a :ref:`coroutine function +`:: import asyncio @@ -234,8 +235,8 @@ loop.run_until_complete(future) print(future.result()) -The coroutine is responsible of the computation (which takes 1 second) and -it stores the result into the future. The +The coroutine function is responsible of the computation (which takes 1 second) +and it stores the result into the future. The :meth:`~BaseEventLoop.run_until_complete` method waits for the completion of the future. @@ -273,9 +274,9 @@ the loop. .. note:: - The coroutine is only executed when the event loop starts running, so it is - possible to add a "done callback" to the future after creating the task - scheduling the coroutine. + The "slow_operation" coroutine object is only executed when the event loop + starts running, so it is possible to add a "done callback" to the future + after creating the task scheduling the coroutine object. @@ -284,7 +285,7 @@ .. class:: Task(coro, \*, loop=None) - A coroutine wrapped in a :class:`Future`. Subclass of :class:`Future`. + A coroutine object wrapped in a :class:`Future`. Subclass of :class:`Future`. .. classmethod:: all_tasks(loop=None) @@ -392,13 +393,14 @@ .. function:: async(coro_or_future, \*, loop=None) - Wrap a :ref:`coroutine ` in a future. + Wrap a :ref:`coroutine object ` in a future. If the argument is a :class:`Future`, it is returned directly. .. function:: gather(\*coros_or_futures, loop=None, return_exceptions=False) - Return a future aggregating results from the given coroutines or futures. + Return a future aggregating results from the given coroutine objects or + futures. 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 @@ -416,8 +418,8 @@ .. function:: sleep(delay, result=None, \*, loop=None) - Create a :ref:`coroutine ` that completes after a given time - (in seconds). + Create a :ref:`coroutine object ` that completes after a given + time (in seconds). .. function:: shield(arg, \*, loop=None) @@ -448,8 +450,8 @@ .. function:: wait(futures, \*, loop=None, timeout=None, return_when=ALL_COMPLETED) - Wait for the Futures and coroutines given by the sequence *futures* to - complete. Coroutines will be wrapped in Tasks. Returns two sets of + Wait for the Futures and coroutine objects given by the sequence *futures* + to complete. Coroutines will be wrapped in Tasks. Returns two sets of :class:`Future`: (done, pending). *timeout* can be used to control the maximum number of seconds to wait before @@ -477,7 +479,7 @@ | | futures finish or are cancelled. | +-----------------------------+----------------------------------------+ - This function returns a :ref:`coroutine `. + This function returns a :ref:`coroutine object `. Usage:: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 20:05:29 2014 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 16 Jan 2014 20:05:29 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Reincarnate_Cor?= =?utf-8?q?oWrapper=27s_docstring_as_a_comment=2E?= Message-ID: <3f4vxP2mhgz7LkT@mail.python.org> http://hg.python.org/cpython/rev/18a71ae9e715 changeset: 88511:18a71ae9e715 user: Guido van Rossum date: Thu Jan 16 11:05:23 2014 -0800 summary: asyncio: Reincarnate CoroWrapper's docstring as a comment. files: Lib/asyncio/tasks.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -32,6 +32,8 @@ class CoroWrapper: + # Wrapper for coroutine in _DEBUG mode. + __slots__ = ['gen', 'func', '__name__', '__doc__'] def __init__(self, gen, func): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 20:32:16 2014 From: python-checkins at python.org (larry.hastings) Date: Thu, 16 Jan 2014 20:32:16 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320226=3A_Major_im?= =?utf-8?q?provements_to_Argument_Clinic=2E?= Message-ID: <3f4wXJ33w2z7Ljn@mail.python.org> http://hg.python.org/cpython/rev/abf87e1fbc62 changeset: 88512:abf87e1fbc62 user: Larry Hastings date: Thu Jan 16 11:32:01 2014 -0800 summary: Issue #20226: Major improvements to Argument Clinic. * You may now specify an expression as the default value for a parameter! Example: "sys.maxsize - 1". This support is intentionally quite limited; you may only use values that can be represented as static C values. * Removed "doc_default", simplified support for "c_default" and "py_default". (I'm not sure we still even need "py_default", but I'm leaving it in for now in case a use presents itself.) * Parameter lines support a trailing '\\' as a line continuation character, allowing you to break up long lines. * The argument parsing code generated when supporting optional groups now uses PyTuple_GET_SIZE instead of PyTuple_GetSize, leading to a 850% speedup in parsing. (Just kidding, this is an unmeasurable difference.) * A bugfix for the recent regression where the generated prototype from pydoc for builtins would be littered with unreadable "="" default values for parameters that had no default value. * Converted some asserts into proper failure messages. * Many doc improvements and fixes. files: Doc/c-api/arg.rst | 2 + Doc/howto/clinic.rst | 261 ++++++++++++++++++++--- Lib/inspect.py | 87 ++++--- Lib/test/test_inspect.py | 5 +- Misc/NEWS | 3 + Modules/_cursesmodule.c | 4 +- Modules/_dbmmodule.c | 6 +- Modules/_opcode.c | 4 +- Modules/_testcapimodule.c | 4 +- Modules/posixmodule.c | 4 +- Modules/zlibmodule.c | 4 +- Tools/clinic/clinic.py | 250 +++++++++++++++------- Tools/clinic/clinic_test.py | 23 +- 13 files changed, 471 insertions(+), 186 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 @@ -294,6 +294,8 @@ the object pointer is stored. If the Python object does not have the required type, :exc:`TypeError` is raised. +.. _o_ampersand: + ``O&`` (object) [*converter*, *anything*] Convert a Python object to a C variable through a *converter* function. This takes two arguments: the first is a function, the second is the address of a C diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -127,6 +127,12 @@ margin, with no line wider than 80 characters. (Argument Clinic will preserve indents inside the docstring.) + If the old docstring had a first line that looked like a function + signature, throw that line away. (The docstring doesn't need it + anymore--when you use ``help()`` on your builtin in the future, + the first line will be built automatically based on the function's + signature.) + Sample:: /*[clinic input] @@ -196,6 +202,10 @@ name_of_parameter: converter = default_value + Argument Clinic's support for "default values" is quite sophisticated; + please see :ref:`the section below on default values ` + for more information. + Add a blank line below the parameters. What's a "converter"? It establishes both the type @@ -513,16 +523,6 @@ and the impl function would now be named ``pickler_dumper_impl()``. -The NULL default value ----------------------- - -For string and object parameters, you can set them to ``None`` to indicate -that there is no default. However, that means the C variable will be -initialized to ``Py_None``. For convenience's sakes, there's a special -value called ``NULL`` for just this case: from Python's perspective it -behaves like a default value of ``None``, but the C variable is initialized -with ``NULL``. - Converting functions using PyArg_UnpackTuple -------------------------------------------- @@ -654,35 +654,70 @@ All arguments to Argument Clinic converters are keyword-only. All Argument Clinic converters accept the following arguments: -``py_default`` - The default value for this parameter when defined in Python. - Specifically, the value that will be used in the ``inspect.Signature`` - string. - If a default value is specified for the parameter, defaults to - ``repr(default)``, else defaults to ``None``. - Specified as a string. + ``c_default`` + The default value for this parameter when defined in C. + Specifically, this will be the initializer for the variable declared + in the "parse function". See :ref:`the section on default values ` + for how to use this. + Specified as a string. -``c_default`` - The default value for this parameter when defined in C. - Specifically, this will be the initializer for the variable declared - in the "parse function". - Specified as a string. + ``annotation`` + The annotation value for this parameter. Not currently supported, + because PEP 8 mandates that the Python library may not use + annotations. -``required`` - If a parameter takes a default value, Argument Clinic infers that the - parameter is optional. However, you may want a parameter to take a - default value in C, but not behave in Python as if the parameter is - optional. Passing in ``required=True`` to a converter tells Argument - Clinic that this parameter is not optional, even if it has a default - value. +In addition, some converters accept additional arguments. Here is a list +of these arguments, along with their meanings: - (The need for ``required`` may be obviated by ``c_default``, which is - newer but arguably a better solution.) + ``bitwise`` + Only supported for unsigned integers. The native integer value of this + Python argument will be written to the parameter without any range checking, + even for negative values. -``annotation`` - The annotation value for this parameter. Not currently supported, - because PEP 8 mandates that the Python library may not use - annotations. + ``converter`` + Only supported by the ``object`` converter. Specifies the name of a + :ref:`C "converter function" ` + to use to convert this object to a native type. + + ``encoding`` + Only supported for strings. Specifies the encoding to use when converting + this string from a Python str (Unicode) value into a C ``char *`` value. + + ``length`` + Only supported for strings. If true, requests that the length of the + string be passed in to the impl function, just after the string parameter, + in a parameter named ``_length``. + + ``nullable`` + Only supported for strings. If true, this parameter may also be set to + ``None``, in which case the C parameter will be set to ``NULL``. + + ``subclass_of`` + Only supported for the ``object`` converter. Requires that the Python + value be a subclass of a Python type, as expressed in C. + + ``types`` + Only supported for the ``object`` (and ``self``) converter. Specifies + the C type that will be used to declare the variable. Default value is + ``"PyObject *"``. + + ``types`` + A string containing a list of Python types (and possibly pseudo-types); + this restricts the allowable Python argument to values of these types. + (This is not a general-purpose facility; as a rule it only supports + specific lists of types as shown in the legacy converter table.) + + ``zeroes`` + Only supported for strings. If true, embedded NUL bytes (``'\\0'``) are + permitted inside the value. + +Please note, not every possible combination of arguments will work. +Often these arguments are implemented internally by specific ``PyArg_ParseTuple`` +*format units*, with specific behavior. For example, currently you cannot +call ``str`` and pass in ``zeroes=True`` without also specifying an ``encoding``; +although it's perfectly reasonable to think this would work, these semantics don't +map to any existing format unit. So Argument Clinic doesn't support it. (Or, at +least, not yet.) Below is a table showing the mapping of legacy converters into real Argument Clinic converters. On the left is the legacy converter, @@ -720,9 +755,9 @@ ``'u'`` ``Py_UNICODE`` ``'U'`` ``unicode`` ``'w*'`` ``Py_buffer(types='bytearray rwbuffer')`` -``'y#'`` ``str(type='bytes', length=True)`` +``'y#'`` ``str(types='bytes', length=True)`` ``'Y'`` ``PyByteArrayObject`` -``'y'`` ``str(type='bytes')`` +``'y'`` ``str(types='bytes')`` ``'y*'`` ``Py_buffer`` ``'Z#'`` ``Py_UNICODE(nullable=True, length=True)`` ``'z#'`` ``str(nullable=True, length=True)`` @@ -789,6 +824,90 @@ hard-coded encoding strings for parameters whose format units start with ``e``. +.. _default_values: + +Parameter default values +------------------------ + +Default values for parameters can be any of a number of values. +At their simplest, they can be string, int, or float literals:: + + foo: str = "abc" + bar: int = 123 + bat: float = 45.6 + +They can also use any of Python's built-in constants:: + + yep: bool = True + nope: bool = False + nada: object = None + +There's also special support for a default value of ``NULL``, and +for simple expressions, documented in the following sections. + + +The ``NULL`` default value +-------------------------- + +For string and object parameters, you can set them to ``None`` to indicate +that there's no default. However, that means the C variable will be +initialized to ``Py_None``. For convenience's sakes, there's a special +value called ``NULL`` for just this reason: from Python's perspective it +behaves like a default value of ``None``, but the C variable is initialized +with ``NULL``. + +Expressions specified as default values +--------------------------------------- + +The default value for a parameter can be more than just a literal value. +It can be an entire expression, using math operators and looking up attributes +on objects. However, this support isn't exactly simple, because of some +non-obvious semantics. + +Consider the following example:: + + foo: Py_ssize_t = sys.maxsize - 1 + +``sys.maxsize`` can have different values on different platforms. Therefore +Argument Clinic can't simply evaluate that expression locally and hard-code it +in C. So it stores the default in such a way that it will get evaluated at +runtime, when the user asks for the function's signature. + +What namespace is available when the expression is evaluated? It's evaluated +in the context of the module the builtin came from. So, if your module has an +attribute called "``max_widgets``", you may simply use it:: + + foo: Py_ssize_t = max_widgets + +If the symbol isn't found in the current module, it fails over to looking in +``sys.modules``. That's how it can find ``sys.maxsize`` for example. (Since you +don't know in advance what modules the user will load into their interpreter, +it's best to restrict yourself to modules that are preloaded by Python itself.) + +Evaluating default values only at runtime means Argument Clinic can't compute +the correct equivalent C default value. So you need to tell it explicitly. +When you use an expression, you must also specify the equivalent expression +in C, using the ``c_default`` parameter to the converter:: + + foo: Py_ssize_t(c_default="PY_SSIZE_T_MAX - 1") = sys.maxsize - 1 + +Another complication: Argument Clinic can't know in advance whether or not the +expression you supply is valid. It parses it to make sure it looks legal, but +it can't *actually* know. You must be very careful when using expressions to +specify values that are guaranteed to be valid at runtime! + +Finally, because expressions must be representable as static C values, there +are many restrictions on legal expressions. Here's a list of Python features +you're not permitted to use: + +* Function calls. +* Inline if statements (``3 if foo else 5``). +* Automatic sequence unpacking (``*[1, 2, 3]``). +* List/set/dict comprehensions and generator expressions. +* Tuple/list/set/dict literals. + + + Using a return converter ------------------------ @@ -1096,7 +1215,73 @@ You can still use a self converter, a return converter, and specify a ``type`` argument to the object converter for ``METH_O``. -Using Argument Clinic in Python files +The #ifdef trick +---------------------------------------------- + +If you're converting a function that isn't available on all platforms, +there's a trick you can use to make life a little easier. The existing +code probably looks like this:: + + #ifdef HAVE_FUNCTIONNAME + static module_functionname(...) + { + ... + } + #endif /* HAVE_FUNCTIONNAME */ + +And then in the ``PyMethodDef`` structure at the bottom you'll have:: + + #ifdef HAVE_FUNCTIONNAME + {'functionname', ... }, + #endif /* HAVE_FUNCTIONNAME */ + +In this scenario, you should change the code to look like the following:: + + #ifdef HAVE_FUNCTIONNAME + /*[clinic input] + module.functionname + ... + [clinic start generated code]*/ + static module_functionname(...) + { + ... + } + #endif /* HAVE_FUNCTIONNAME */ + +Run Argument Clinic on the code in this state, then refresh the file in +your editor. Now you'll have the generated code, including the #define +for the ``PyMethodDef``, like so:: + + #ifdef HAVE_FUNCTIONNAME + /*[clinic input] + ... + [clinic start generated code]*/ + ... + #define MODULE_FUNCTIONNAME \ + {'functionname', ... }, + ... + /*[clinic end generated code: checksum=...]*/ + static module_functionname(...) + { + ... + } + #endif /* HAVE_FUNCTIONNAME */ + +Change the #endif at the bottom as follows:: + + #else + #define MODULE_FUNCTIONNAME + #endif /* HAVE_FUNCTIONNAME */ + +Now you can remove the #ifdefs around the ``PyMethodDef`` structure +at the end, and replace those three lines with ``MODULE_FUNCTIONNAME``. +If the function is available, the macro turns into the ``PyMethodDef`` +static value, including the trailing comma; if the function isn't +available, the macro turns into nothing. Perfect! + +(This is the preferred approach for optional functions; in the future, +Argument Clinic may generate the entire ``PyMethodDef`` structure.) + ------------------------------------- It's actually possible to use Argument Clinic to preprocess Python files. diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1954,6 +1954,8 @@ if not s: return None + Parameter = cls._parameter_cls + if s.endswith("/)"): kind = Parameter.POSITIONAL_ONLY s = s[:-2] + ')' @@ -1969,55 +1971,74 @@ if not isinstance(module, ast.Module): return None - # ast.FunctionDef f = module.body[0] parameters = [] empty = Parameter.empty invalid = object() - def parse_attribute(node): - if not isinstance(node.ctx, ast.Load): - return None + module = None + module_dict = {} + module_name = getattr(func, '__module__', None) + if module_name: + module = sys.modules.get(module_name, None) + if module: + module_dict = module.__dict__ + sys_module_dict = sys.modules - value = node.value - o = parse_node(value) - if o is invalid: - return invalid + def parse_name(node): + assert isinstance(node, ast.arg) + if node.annotation != None: + raise ValueError("Annotations are not currently supported") + return node.arg - if isinstance(value, ast.Name): - name = o - if name not in sys.modules: - return invalid - o = sys.modules[name] + def wrap_value(s): + try: + value = eval(s, module_dict) + except NameError: + try: + value = eval(s, sys_module_dict) + except NameError: + raise RuntimeError() - return getattr(o, node.attr, invalid) + if isinstance(value, str): + return ast.Str(value) + if isinstance(value, (int, float)): + return ast.Num(value) + if isinstance(value, bytes): + return ast.Bytes(value) + if value in (True, False, None): + return ast.NameConstant(value) + raise RuntimeError() - def parse_node(node): - if isinstance(node, ast.arg): - if node.annotation != None: - raise ValueError("Annotations are not currently supported") - return node.arg - if isinstance(node, ast.Num): - return node.n - if isinstance(node, ast.Str): - return node.s - if isinstance(node, ast.NameConstant): - return node.value - if isinstance(node, ast.Attribute): - return parse_attribute(node) - if isinstance(node, ast.Name): + class RewriteSymbolics(ast.NodeTransformer): + def visit_Attribute(self, node): + a = [] + n = node + while isinstance(n, ast.Attribute): + a.append(n.attr) + n = n.value + if not isinstance(n, ast.Name): + raise RuntimeError() + a.append(n.id) + value = ".".join(reversed(a)) + return wrap_value(value) + + def visit_Name(self, node): if not isinstance(node.ctx, ast.Load): - return invalid - return node.id - return invalid + raise ValueError() + return wrap_value(node.id) def p(name_node, default_node, default=empty): - name = parse_node(name_node) + name = parse_name(name_node) if name is invalid: return None if default_node: - o = parse_node(default_node) + try: + default_node = RewriteSymbolics().visit(default_node) + o = ast.literal_eval(default_node) + except ValueError: + o = invalid if o is invalid: return None default = o if o is not invalid else default diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1601,12 +1601,15 @@ self.assertTrue(isinstance(signature, inspect.Signature)) def p(name): return signature.parameters[name].default self.assertEqual(p('s'), 'avocado') + self.assertEqual(p('b'), b'bytes') self.assertEqual(p('d'), 3.14) self.assertEqual(p('i'), 35) - self.assertEqual(p('c'), sys.maxsize) self.assertEqual(p('n'), None) self.assertEqual(p('t'), True) self.assertEqual(p('f'), False) + self.assertEqual(p('local'), 3) + self.assertEqual(p('sys'), sys.maxsize) + self.assertEqual(p('exp'), sys.maxsize - 1) def test_signature_on_non_function(self): with self.assertRaisesRegex(TypeError, 'is not a callable object'): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -88,6 +88,9 @@ Tools/Demos ----------- +- Issue #20226: Argument Clinic now permits simple expressions + (e.g. "sys.maxsize - 1") as default values for parameters. + - Issue #19936: Added executable bits or shebang lines to Python scripts which requires them. Disable executable bits and shebang lines in test and benchmark files in order to prevent using a random system python, and in diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -618,7 +618,7 @@ int group_right_1 = 0; long attr = 0; - switch (PyTuple_Size(args)) { + switch (PyTuple_GET_SIZE(args)) { case 1: if (!PyArg_ParseTuple(args, "O:addch", &ch)) return NULL; @@ -650,7 +650,7 @@ static PyObject * curses_window_addch_impl(PyObject *self, int group_left_1, int x, int y, PyObject *ch, int group_right_1, long attr) -/*[clinic end generated code: checksum=44ed958b891cde91205e584c766e048f3999714f]*/ +/*[clinic end generated code: checksum=b073327add8197b6ba7fb96c87062422c8312954]*/ { PyCursesWindowObject *cwself = (PyCursesWindowObject *)self; int coordinates_group = group_left_1; diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c --- a/Modules/_dbmmodule.c +++ b/Modules/_dbmmodule.c @@ -297,7 +297,7 @@ int group_right_1 = 0; PyObject *default_value = NULL; - switch (PyTuple_Size(args)) { + switch (PyTuple_GET_SIZE(args)) { case 1: if (!PyArg_ParseTuple(args, "s#:get", &key, &key_length)) return NULL; @@ -318,7 +318,7 @@ static PyObject * dbm_dbm_get_impl(dbmobject *dp, const char *key, Py_ssize_clean_t key_length, int group_right_1, PyObject *default_value) -/*[clinic end generated code: checksum=28cf8928811bde51e535d67ae98ea039d79df717]*/ +/*[clinic end generated code: checksum=2c3209571267017f1b9abbd19e1b521849fd5d4a]*/ { datum dbm_key, val; @@ -450,7 +450,7 @@ flags: str="r" How to open the file. "r" for reading, "w" for writing, etc. - mode: int(doc_default="0o666") = 0o666 + mode: int(py_default="0o666") = 0o666 If creating a new file, the mode bits for the new file (e.g. os.O_RDWR). diff --git a/Modules/_opcode.c b/Modules/_opcode.c --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -39,7 +39,7 @@ int oparg = 0; int _return_value; - switch (PyTuple_Size(args)) { + switch (PyTuple_GET_SIZE(args)) { case 1: if (!PyArg_ParseTuple(args, "i:stack_effect", &opcode)) return NULL; @@ -64,7 +64,7 @@ static int _opcode_stack_effect_impl(PyModuleDef *module, int opcode, int group_right_1, int oparg) -/*[clinic end generated code: checksum=e880e62dc7b0de73403026eaf4f8074aa106358b]*/ +/*[clinic end generated code: checksum=47e76ec27523da4ab192713642d32482cd743aa4]*/ { int effect; if (HAS_ARG(opcode)) { diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2870,7 +2870,7 @@ ); PyDoc_STRVAR(docstring_with_signature_with_defaults, -"docstring_with_signature_with_defaults(s='avocado', d=3.14, i=35, c=sys.maxsize, n=None, t=True, f=False)\n" +"docstring_with_signature_with_defaults(s='avocado', b=b'bytes', d=3.14, i=35, n=None, t=True, f=False, local=the_number_three, sys=sys.maxsize, exp=sys.maxsize - 1)\n" "\n" "\n" "\n" @@ -3317,6 +3317,8 @@ Py_INCREF(&PyInstanceMethod_Type); PyModule_AddObject(m, "instancemethod", (PyObject *)&PyInstanceMethod_Type); + PyModule_AddIntConstant(m, "the_number_three", 3); + TestError = PyErr_NewException("_testcapi.error", NULL, NULL); Py_INCREF(TestError); PyModule_AddObject(m, "error", TestError); diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -2401,7 +2401,7 @@ /*[clinic input] -os.stat -> object(doc_default='stat_result') +os.stat path : path_t(allow_fd=True) Path to be examined; can be string, bytes, or open-file-descriptor int. @@ -2523,7 +2523,7 @@ #define OS_ACCESS_DIR_FD_CONVERTER dir_fd_unavailable #endif /*[clinic input] -os.access -> object(doc_default='True if granted, False otherwise') +os.access path: path_t(allow_fd=True) Path to be tested; can be string, bytes, or open-file-descriptor int. diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -202,7 +202,7 @@ int group_right_1 = 0; int level = 0; - switch (PyTuple_Size(args)) { + switch (PyTuple_GET_SIZE(args)) { case 1: if (!PyArg_ParseTuple(args, "y*:compress", &bytes)) return NULL; @@ -227,7 +227,7 @@ static PyObject * zlib_compress_impl(PyModuleDef *module, Py_buffer *bytes, int group_right_1, int level) -/*[clinic end generated code: checksum=2c59af563a4595c5ecea4011701f482ae350aa5f]*/ +/*[clinic end generated code: checksum=66c4d16d0b8b9dd423648d9ef00d6a89d3363665]*/ { PyObject *ReturnVal = NULL; Byte *input, *output = NULL; diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -55,6 +55,13 @@ NULL = Null() +class Unknown: + def __repr__(self): + return '' + +unknown = Unknown() + + def _text_accumulator(): text = [] def output(): @@ -197,7 +204,7 @@ accumulator = [] def flush(): if not accumulator: - raise ValueError('Malformed version string: ' + repr(s)) + raise ValueError('Unsupported version string: ' + repr(s)) version.append(int(''.join(accumulator))) accumulator.clear() @@ -596,7 +603,7 @@ count_min = sys.maxsize count_max = -1 - add("switch (PyTuple_Size(args)) {{\n") + add("switch (PyTuple_GET_SIZE(args)) {{\n") for subset in permute_optional_groups(left, required, right): count = len(subset) count_min = min(count_min, count) @@ -1069,6 +1076,7 @@ self.filename = filename self.modules = collections.OrderedDict() self.classes = collections.OrderedDict() + self.functions = [] global clinic clinic = self @@ -1343,29 +1351,7 @@ def is_keyword_only(self): return self.kind == inspect.Parameter.KEYWORD_ONLY -py_special_values = { - NULL: "None", -} - -def py_repr(o): - special = py_special_values.get(o) - if special: - return special - return repr(o) - - -c_special_values = { - NULL: "NULL", - None: "Py_None", -} - -def c_repr(o): - special = c_special_values.get(o) - if special: - return special - if isinstance(o, str): - return '"' + quoted_for_c_string(o) + '"' - return repr(o) + def add_c_converter(f, name=None): if not name: @@ -1407,8 +1393,7 @@ """ For the init function, self, name, function, and default must be keyword-or-positional parameters. All other - parameters (including "required" and "doc_default") - must be keyword-only. + parameters must be keyword-only. """ # The C type to use for this variable. @@ -1418,23 +1403,23 @@ # The Python default value for this parameter, as a Python value. # Or the magic value "unspecified" if there is no default. + # Or the magic value "unknown" if this value is a cannot be evaluated + # at Argument-Clinic-preprocessing time (but is presumed to be valid + # at runtime). default = unspecified # If not None, default must be isinstance() of this type. # (You can also specify a tuple of types.) default_type = None - # "default" as it should appear in the documentation, as a string. - # Or None if there is no default. - doc_default = None - - # "default" converted into a str for rendering into Python code. - py_default = None - # "default" converted into a C value, as a string. # Or None if there is no default. c_default = None + # "default" converted into a Python value, as a string. + # Or None if there is no default. + py_default = None + # The default value used to initialize the C variable when # there is no default, but not specifying a default may # result in an "uninitialized variable" warning. This can @@ -1485,12 +1470,12 @@ # Only used by format units ending with '#'. length = False - def __init__(self, name, function, default=unspecified, *, doc_default=None, c_default=None, py_default=None, required=False, annotation=unspecified, **kwargs): + def __init__(self, name, function, default=unspecified, *, c_default=None, py_default=None, annotation=unspecified, **kwargs): self.function = function self.name = name if default is not unspecified: - if self.default_type and not isinstance(default, self.default_type): + if self.default_type and not isinstance(default, (self.default_type, Unknown)): if isinstance(self.default_type, type): types_str = self.default_type.__name__ else: @@ -1498,23 +1483,19 @@ fail("{}: default value {!r} for field {} is not of type {}".format( self.__class__.__name__, default, name, types_str)) self.default = default - self.py_default = py_default if py_default is not None else py_repr(default) - self.doc_default = doc_default if doc_default is not None else self.py_default - self.c_default = c_default if c_default is not None else c_repr(default) - else: - self.py_default = py_default - self.doc_default = doc_default - self.c_default = c_default + + self.c_default = c_default + self.py_default = py_default + if annotation != unspecified: fail("The 'annotation' parameter is not currently permitted.") - self.required = required self.converter_init(**kwargs) def converter_init(self): pass def is_optional(self): - return (self.default is not unspecified) and (not self.required) + return (self.default is not unspecified) def render(self, parameter, data): """ @@ -1655,8 +1636,9 @@ c_ignored_default = '0' def converter_init(self): - self.default = bool(self.default) - self.c_default = str(int(self.default)) + if self.default is not unspecified: + self.default = bool(self.default) + self.c_default = str(int(self.default)) class char_converter(CConverter): type = 'char' @@ -1665,7 +1647,7 @@ c_ignored_default = "'\0'" def converter_init(self): - if len(self.default) != 1: + if isinstance(self.default, str) and (len(self.default) != 1): fail("char_converter: illegal default value " + repr(self.default)) @@ -1797,8 +1779,8 @@ @add_legacy_c_converter('s#', length=True) - at add_legacy_c_converter('y', type="bytes") - at add_legacy_c_converter('y#', type="bytes", length=True) + at add_legacy_c_converter('y', types="bytes") + at add_legacy_c_converter('y#', types="bytes", length=True) @add_legacy_c_converter('z', nullable=True) @add_legacy_c_converter('z#', nullable=True, length=True) class str_converter(CConverter): @@ -1993,8 +1975,8 @@ # Or the magic value "unspecified" if there is no default. default = None - def __init__(self, *, doc_default=None, **kwargs): - self.doc_default = doc_default + def __init__(self, *, py_default=None, **kwargs): + self.py_default = py_default try: self.return_converter_init(**kwargs) except TypeError as e: @@ -2212,6 +2194,7 @@ self.indent = IndentStack() self.kind = CALLABLE self.coexist = False + self.parameter_continuation = '' def directive_version(self, required): global version @@ -2244,15 +2227,18 @@ self.block.signatures.append(c) def at_classmethod(self): - assert self.kind is CALLABLE + if self.kind is not CALLABLE: + fail("Can't set @classmethod, function is not a normal callable") self.kind = CLASS_METHOD def at_staticmethod(self): - assert self.kind is CALLABLE + if self.kind is not CALLABLE: + fail("Can't set @staticmethod, function is not a normal callable") self.kind = STATIC_METHOD def at_coexist(self): - assert self.coexist == False + if self.coexist: + fail("Called @coexist twice!") self.coexist = True @@ -2503,6 +2489,7 @@ if not self.indent.infer(line): return self.next(self.state_function_docstring, line) + self.parameter_continuation = '' return self.next(self.state_parameter, line) @@ -2516,6 +2503,10 @@ p.group = -p.group def state_parameter(self, line): + if self.parameter_continuation: + line = self.parameter_continuation + ' ' + line.lstrip() + self.parameter_continuation = '' + if self.ignore_line(line): return @@ -2529,6 +2520,11 @@ # we indented, must be to new parameter docstring column return self.next(self.state_parameter_docstring_start, line) + line = line.rstrip() + if line.endswith('\\'): + self.parameter_continuation = line[:-1] + return + line = line.lstrip() if line in ('*', '/', '[', ']'): @@ -2547,48 +2543,123 @@ else: fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")") - ast_input = "def x({}): pass".format(line) + base, equals, default = line.rpartition('=') + if not equals: + base = default + default = None module = None try: + ast_input = "def x({}): pass".format(base) module = ast.parse(ast_input) except SyntaxError: - pass + try: + default = None + ast_input = "def x({}): pass".format(line) + module = ast.parse(ast_input) + except SyntaxError: + pass if not module: fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line) function_args = module.body[0].args parameter = function_args.args[0] - py_default = None - parameter_name = parameter.arg name, legacy, kwargs = self.parse_converter(parameter.annotation) - if function_args.defaults: - expr = function_args.defaults[0] - # mild hack: explicitly support NULL as a default value - if isinstance(expr, ast.Name) and expr.id == 'NULL': - value = NULL - elif isinstance(expr, ast.Attribute): + if not default: + value = unspecified + if 'py_default' in kwargs: + fail("You can't specify py_default without specifying a default value!") + else: + default = default.strip() + ast_input = "x = {}".format(default) + try: + module = ast.parse(ast_input) + + # blacklist of disallowed ast nodes + class DetectBadNodes(ast.NodeVisitor): + bad = False + def bad_node(self, node): + self.bad = True + + # inline function call + visit_Call = bad_node + # inline if statement ("x = 3 if y else z") + visit_IfExp = bad_node + + # comprehensions and generator expressions + visit_ListComp = visit_SetComp = bad_node + visit_DictComp = visit_GeneratorExp = bad_node + + # literals for advanced types + visit_Dict = visit_Set = bad_node + visit_List = visit_Tuple = bad_node + + # "starred": "a = [1, 2, 3]; *a" + visit_Starred = bad_node + + # allow ellipsis, for now + # visit_Ellipsis = bad_node + + blacklist = DetectBadNodes() + blacklist.visit(module) + if blacklist.bad: + fail("Unsupported expression as default value: " + repr(default)) + + expr = module.body[0].value + # mild hack: explicitly support NULL as a default value + if isinstance(expr, ast.Name) and expr.id == 'NULL': + value = NULL + py_default = 'None' + c_default = "NULL" + elif (isinstance(expr, ast.BinOp) or + (isinstance(expr, ast.UnaryOp) and not isinstance(expr.operand, ast.Num))): + c_default = kwargs.get("c_default") + if not (isinstance(c_default, str) and c_default): + fail("When you specify an expression (" + repr(default) + ") as your default value,\nyou MUST specify a valid c_default.") + py_default = default + value = unknown + elif isinstance(expr, ast.Attribute): + a = [] + n = expr + while isinstance(n, ast.Attribute): + a.append(n.attr) + n = n.value + if not isinstance(n, ast.Name): + fail("Unsupported default value " + repr(default) + " (looked like a Python constant)") + a.append(n.id) + py_default = ".".join(reversed(a)) + + c_default = kwargs.get("c_default") + if not (isinstance(c_default, str) and c_default): + fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.") + + try: + value = eval(py_default) + except NameError: + value = unknown + else: + value = ast.literal_eval(expr) + py_default = repr(value) + if isinstance(value, (bool, None.__class__)): + c_default = "Py_" + py_default + elif isinstance(value, str): + c_default = '"' + quoted_for_c_string(value) + '"' + else: + c_default = py_default + + except SyntaxError as e: + fail("Syntax error: " + repr(e.text)) + except (ValueError, AttributeError): + value = unknown c_default = kwargs.get("c_default") + py_default = default if not (isinstance(c_default, str) and c_default): fail("When you specify a named constant (" + repr(py_default) + ") as your default value,\nyou MUST specify a valid c_default.") - a = [] - n = expr - while isinstance(n, ast.Attribute): - a.append(n.attr) - n = n.value - if not isinstance(n, ast.Name): - fail("Malformed default value (looked like a Python constant)") - a.append(n.id) - py_default = ".".join(reversed(a)) - kwargs["py_default"] = py_default - value = eval(py_default) - else: - value = ast.literal_eval(expr) - else: - value = unspecified + kwargs.setdefault('c_default', c_default) + kwargs.setdefault('py_default', py_default) dict = legacy_converters if legacy else converters legacy_str = "legacy " if legacy else "" @@ -2777,7 +2848,7 @@ if p.converter.is_optional(): a.append('=') value = p.converter.default - a.append(p.converter.doc_default) + a.append(p.converter.py_default) s = fix_right_bracket_count(p.right_bracket_count) s += "".join(a) if add_comma: @@ -2788,9 +2859,18 @@ add(fix_right_bracket_count(0)) add(')') - # if f.return_converter.doc_default: + # PEP 8 says: + # + # The Python standard library will not use function annotations + # as that would result in a premature commitment to a particular + # annotation style. Instead, the annotations are left for users + # to discover and experiment with useful annotation styles. + # + # therefore this is commented out: + # + # if f.return_converter.py_default: # add(' -> ') - # add(f.return_converter.doc_default) + # add(f.return_converter.py_default) docstring_first_line = output() @@ -2998,8 +3078,8 @@ # print(" ", short_name + "".join(parameters)) print() - print("All converters also accept (doc_default=None, required=False, annotation=None).") - print("All return converters also accept (doc_default=None).") + print("All converters also accept (c_default=None, py_default=None, annotation=None).") + print("All return converters also accept (py_default=None).") sys.exit(0) if ns.make: diff --git a/Tools/clinic/clinic_test.py b/Tools/clinic/clinic_test.py --- a/Tools/clinic/clinic_test.py +++ b/Tools/clinic/clinic_test.py @@ -231,20 +231,20 @@ self._test_clinic(""" verbatim text here lah dee dah -/*[copy] +/*[copy input] def -[copy]*/ +[copy start generated code]*/ abc -/*[copy checksum: 03cfd743661f07975fa2f1220c5194cbaff48451]*/ +/*[copy end generated code: checksum=03cfd743661f07975fa2f1220c5194cbaff48451]*/ xyz """, """ verbatim text here lah dee dah -/*[copy] +/*[copy input] def -[copy]*/ +[copy start generated code]*/ def -/*[copy checksum: 7b18d017f89f61cf17d47f92749ea6930a3f1deb]*/ +/*[copy end generated code: checksum=7b18d017f89f61cf17d47f92749ea6930a3f1deb]*/ xyz """) @@ -292,17 +292,6 @@ p = function.parameters['path'] self.assertEqual(1, p.converter.args['allow_fd']) - def test_param_docstring(self): - function = self.parse_function(""" -module os -os.stat as os_stat_fn -> object(doc_default='stat_result') - - path: str - Path to be examined""") - p = function.parameters['path'] - self.assertEqual("Path to be examined", p.docstring) - self.assertEqual(function.return_converter.doc_default, 'stat_result') - def test_function_docstring(self): function = self.parse_function(""" module os -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 22:56:29 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 16 Jan 2014 22:56:29 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_fix_error_chec?= =?utf-8?q?k?= Message-ID: <3f4zkj52cMz7LjR@mail.python.org> http://hg.python.org/cpython/rev/6eed57083a37 changeset: 88513:6eed57083a37 branch: 2.7 parent: 88508:334116bb2939 user: Benjamin Peterson date: Thu Jan 16 16:56:22 2014 -0500 summary: fix error check files: Python/symtable.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/symtable.c b/Python/symtable.c --- a/Python/symtable.c +++ b/Python/symtable.c @@ -468,7 +468,7 @@ */ if (PyDict_SetItem(scope, name, w) < 0) goto error; - if (!PyDict_DelItem(free, name) < 0) + if (PyDict_DelItem(free, name) < 0) goto error; } success = 1; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 16 23:15:20 2014 From: python-checkins at python.org (larry.hastings) Date: Thu, 16 Jan 2014 23:15:20 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320226=3A_Added_te?= =?utf-8?q?sts_for_new_features_and_regressions=2E?= Message-ID: <3f508S0K7lz7LjW@mail.python.org> http://hg.python.org/cpython/rev/cd3fdf21a6e4 changeset: 88514:cd3fdf21a6e4 parent: 88512:abf87e1fbc62 user: Larry Hastings date: Thu Jan 16 14:15:03 2014 -0800 summary: Issue #20226: Added tests for new features and regressions. files: Lib/test/test_pydoc.py | 5 +++++ Tools/clinic/clinic_test.py | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -689,6 +689,11 @@ self.assertIsNone(pydoc.locate(name)) self.assertRaises(ImportError, pydoc.render_doc, name) + # test producing signatures from builtins + stat_sig = pydoc.render_doc(os.stat) + self.assertEqual(pydoc.plain(stat_sig).splitlines()[2], + 'stat(path, *, dir_fd=None, follow_symlinks=True)') + @unittest.skipUnless(threading, 'Threading required for this test.') class PydocServerTest(unittest.TestCase): diff --git a/Tools/clinic/clinic_test.py b/Tools/clinic/clinic_test.py --- a/Tools/clinic/clinic_test.py +++ b/Tools/clinic/clinic_test.py @@ -9,6 +9,7 @@ import collections import inspect from test import support +import sys import unittest from unittest import TestCase @@ -277,6 +278,20 @@ p = function.parameters['follow_symlinks'] self.assertEqual(True, p.default) + def test_param_with_continuations(self): + function = self.parse_function("module os\nos.access\n follow_symlinks: \\\n bool \\\n =\\\n True") + p = function.parameters['follow_symlinks'] + self.assertEqual(True, p.default) + + def test_param_default_expression(self): + function = self.parse_function("module os\nos.access\n follow_symlinks: int(c_default='MAXSIZE') = sys.maxsize") + p = function.parameters['follow_symlinks'] + self.assertEqual(sys.maxsize, p.default) + self.assertEqual("MAXSIZE", p.converter.c_default) + + s = self.parse_function_should_fail("module os\nos.access\n follow_symlinks: int = sys.maxsize") + self.assertEqual(s, "Error on line 0:\nWhen you specify a named constant ('sys.maxsize') as your default value,\nyou MUST specify a valid c_default.\n") + def test_param_no_docstring(self): function = self.parse_function(""" module os -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 17 08:28:58 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 17 Jan 2014 08:28:58 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIwMDg2?= =?utf-8?q?=3A_Restored_the_use_of_locale-independing_mapping_instead_of?= Message-ID: <3f5DRG5LDxz7Lk0@mail.python.org> http://hg.python.org/cpython/rev/bac50f54d357 changeset: 88515:bac50f54d357 branch: 2.7 parent: 88513:6eed57083a37 user: Serhiy Storchaka date: Fri Jan 17 09:27:56 2014 +0200 summary: Issue #20086: Restored the use of locale-independing mapping instead of locale-depending str.lower() in locale.normalize(). files: Lib/locale.py | 6 +++--- Lib/test/test_locale.py | 11 +++++++---- Misc/NEWS | 3 +++ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Lib/locale.py b/Lib/locale.py --- a/Lib/locale.py +++ b/Lib/locale.py @@ -379,7 +379,7 @@ # Normalize the locale name and extract the encoding and modifier if isinstance(localename, _unicode): localename = localename.encode('ascii') - code = localename.lower() + code = localename.translate(_ascii_lower_map) if ':' in code: # ':' is sometimes used as encoding delimiter. code = code.replace(':', '.') @@ -414,7 +414,7 @@ #print('lookup without modifier succeeded') if '@' not in code: return code + '@' + modifier - if code.split('@', 1)[1].lower() == modifier: + if code.split('@', 1)[1].translate(_ascii_lower_map) == modifier: return code #print('second lookup failed') @@ -439,7 +439,7 @@ if '@' not in code: return _replace_encoding(code, encoding) + '@' + modifier code, defmod = code.split('@', 1) - if defmod.lower() == modifier: + if defmod.translate(_ascii_lower_map) == modifier: return _replace_encoding(code, encoding) + '@' + defmod return localename diff --git a/Lib/test/test_locale.py b/Lib/test/test_locale.py --- a/Lib/test/test_locale.py +++ b/Lib/test/test_locale.py @@ -471,9 +471,13 @@ # Issue #1813: setting and getting the locale under a Turkish locale oldlocale = locale.getlocale() self.addCleanup(locale.setlocale, locale.LC_CTYPE, oldlocale) - try: - locale.setlocale(locale.LC_CTYPE, 'tr_TR') - except locale.Error: + for loc in ('tr_TR', 'tr_TR.UTF-8', 'tr_TR.ISO8859-9'): + try: + locale.setlocale(locale.LC_CTYPE, loc) + break + except locale.Error: + continue + else: # Unsupported locale on this system self.skipTest('test needs Turkish locale') loc = locale.getlocale() @@ -482,7 +486,6 @@ except Exception as e: self.fail("Failed to set locale %r (default locale is %r): %r" % (loc, oldlocale, e)) - print("set locale %r (default locale is %r)" % (loc, oldlocale)) self.assertEqual(loc, locale.getlocale()) def test_normalize_issue12752(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,6 +35,9 @@ Library ------- +- Issue #20086: Restored the use of locale-independing mapping instead of + locale-depending str.lower() in locale.normalize(). + - Issue #20246: Fix buffer overflow in socket.recvfrom_into. - Issue #19082: Working SimpleXMLRPCServer and xmlrpclib examples, both in -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Jan 17 09:47:20 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 17 Jan 2014 09:47:20 +0100 Subject: [Python-checkins] Daily reference leaks (cd3fdf21a6e4): sum=-4 Message-ID: results for cd3fdf21a6e4 on branch "default" -------------------------------------------- test_site leaked [-2, 0, 0] references, sum=-2 test_site leaked [-2, 0, 0] memory blocks, sum=-2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogsy47RL', '-x'] From python-checkins at python.org Fri Jan 17 10:31:13 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 17 Jan 2014 10:31:13 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_oops=2C_add_mis?= =?utf-8?q?sing_word_=3A-=29?= Message-ID: <3f5H8K4y1jz7LlW@mail.python.org> http://hg.python.org/cpython/rev/803461725570 changeset: 88516:803461725570 parent: 88514:cd3fdf21a6e4 user: Victor Stinner date: Fri Jan 17 10:31:02 2014 +0100 summary: asyncio: oops, add missing word :-) files: Doc/library/asyncio-dev.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 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 @@ -47,8 +47,8 @@ :ref:`asyncio logger `. The debug flag changes the behaviour of the :func:`coroutine` decorator. The -debug flag value is only when then coroutine function is defined, not when it -is called. Coroutine functions defined before the debug flag is set to +debug flag value is only used when then coroutine function is defined, not when +it is called. Coroutine functions defined before the debug flag is set to ``True`` will not be tracked. For example, it is not possible to debug coroutines defined in the :mod:`asyncio` module, because the module must be imported before the flag value can be changed. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 17 16:00:47 2014 From: python-checkins at python.org (zach.ware) Date: Fri, 17 Jan 2014 16:00:47 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMjY2?= =?utf-8?q?=3A_Update_parts_of_the_Windows_FAQ?= Message-ID: <3f5QSb3L3kz7Lkb@mail.python.org> http://hg.python.org/cpython/rev/c9706c13a005 changeset: 88517:c9706c13a005 branch: 3.3 parent: 88506:085a0ea2015f user: Zachary Ware date: Fri Jan 17 08:59:44 2014 -0600 summary: Issue #20266: Update parts of the Windows FAQ files: Doc/faq/windows.rst | 12 +++++++----- Misc/NEWS | 4 +++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Doc/faq/windows.rst b/Doc/faq/windows.rst --- a/Doc/faq/windows.rst +++ b/Doc/faq/windows.rst @@ -170,18 +170,20 @@ How do I make an executable from a Python script? ------------------------------------------------- -See http://www.py2exe.org/ for a distutils extension that allows you +See http://cx-freeze.sourceforge.net/ for a distutils extension that allows you to create console and GUI executables from Python code. +`py2exe `_, the most popular extension for building +Python 2.x-based executables, does not yet support Python 3 but a version that +does is in development. + Is a ``*.pyd`` file the same as a DLL? -------------------------------------- -.. XXX update for py3k (PyInit_foo) - Yes, .pyd files are dll's, but there are a few differences. If you have a DLL -named ``foo.pyd``, then it must have a function ``initfoo()``. You can then +named ``foo.pyd``, then it must have a function ``PyInit_foo()``. You can then write Python "import foo", and Python will search for foo.pyd (as well as -foo.py, foo.pyc) and if it finds it, will attempt to call ``initfoo()`` to +foo.py, foo.pyc) and if it finds it, will attempt to call ``PyInit_foo()`` to initialize it. You do not link your .exe with foo.lib, as that would cause Windows to require the DLL to be present. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -302,7 +302,9 @@ Documentation ------------- -- Issue #20255: Update the about and bugs pages. +- Issue #20266: Updated some parts of the Windows FAQ. + +- Issue #20255: Updated the about and bugs pages. - Issue #20253: Fixed a typo in the ipaddress docs that advertised an illegal attribute name. Found by INADA Naoki. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 17 16:00:48 2014 From: python-checkins at python.org (zach.ware) Date: Fri, 17 Jan 2014 16:00:48 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320266=3A_Merge_with_3=2E3?= Message-ID: <3f5QSc6lhNz7Lms@mail.python.org> http://hg.python.org/cpython/rev/3cb048463ea7 changeset: 88518:3cb048463ea7 parent: 88516:803461725570 parent: 88517:c9706c13a005 user: Zachary Ware date: Fri Jan 17 09:00:36 2014 -0600 summary: Issue #20266: Merge with 3.3 files: Doc/faq/windows.rst | 12 +++++++----- Misc/NEWS | 4 +++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Doc/faq/windows.rst b/Doc/faq/windows.rst --- a/Doc/faq/windows.rst +++ b/Doc/faq/windows.rst @@ -170,18 +170,20 @@ How do I make an executable from a Python script? ------------------------------------------------- -See http://www.py2exe.org/ for a distutils extension that allows you +See http://cx-freeze.sourceforge.net/ for a distutils extension that allows you to create console and GUI executables from Python code. +`py2exe `_, the most popular extension for building +Python 2.x-based executables, does not yet support Python 3 but a version that +does is in development. + Is a ``*.pyd`` file the same as a DLL? -------------------------------------- -.. XXX update for py3k (PyInit_foo) - Yes, .pyd files are dll's, but there are a few differences. If you have a DLL -named ``foo.pyd``, then it must have a function ``initfoo()``. You can then +named ``foo.pyd``, then it must have a function ``PyInit_foo()``. You can then write Python "import foo", and Python will search for foo.pyd (as well as -foo.py, foo.pyc) and if it finds it, will attempt to call ``initfoo()`` to +foo.py, foo.pyc) and if it finds it, will attempt to call ``PyInit_foo()`` to initialize it. You do not link your .exe with foo.lib, as that would cause Windows to require the DLL to be present. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -489,7 +489,9 @@ Documentation ------------- -- Issue #20255: Update the about and bugs pages. +- Issue #20266: Updated some parts of the Windows FAQ. + +- Issue #20255: Updated the about and bugs pages. - Issue #20253: Fixed a typo in the ipaddress docs that advertised an illegal attribute name. Found by INADA Naoki. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 17 16:31:43 2014 From: python-checkins at python.org (zach.ware) Date: Fri, 17 Jan 2014 16:31:43 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fix_some_typos?= =?utf-8?q?/grammar_in_current_sections_of_NEWS=2E?= Message-ID: <3f5R8H4nSjz7LnD@mail.python.org> http://hg.python.org/cpython/rev/23a760bdd4b1 changeset: 88519:23a760bdd4b1 branch: 2.7 parent: 88515:bac50f54d357 user: Zachary Ware date: Fri Jan 17 09:29:24 2014 -0600 summary: Fix some typos/grammar in current sections of NEWS. files: Misc/NEWS | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,8 +35,8 @@ Library ------- -- Issue #20086: Restored the use of locale-independing mapping instead of - locale-depending str.lower() in locale.normalize(). +- Issue #20086: Restored the use of locale-independent mapping instead of + locale-dependent str.lower() in locale.normalize(). - Issue #20246: Fix buffer overflow in socket.recvfrom_into. @@ -212,7 +212,7 @@ - Issue #20255: Update the about and bugs pages. -- Issue #18840: Introduce the json module in the tutorial, and deemphasize +- Issue #18840: Introduce the json module in the tutorial, and de-emphasize the pickle module. - Issue #19795: Improved markup of True/False constants. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 17 16:31:44 2014 From: python-checkins at python.org (zach.ware) Date: Fri, 17 Jan 2014 16:31:44 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Fix_some_typos?= =?utf-8?q?/grammar_in_current_sections_of_NEWS=2E?= Message-ID: <3f5R8J6GWqz7Lmh@mail.python.org> http://hg.python.org/cpython/rev/195793d5208d changeset: 88520:195793d5208d branch: 3.3 parent: 88517:c9706c13a005 user: Zachary Ware date: Fri Jan 17 09:30:03 2014 -0600 summary: Fix some typos/grammar in current sections of NEWS. files: Misc/NEWS | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -59,7 +59,7 @@ functions now conform to PEP 3333 when handle non-ASCII URLs. - Issue #19097: Raise the correct Exception when cgi.FieldStorage is given an - Invalid fileobj. + invalid fileobj. - Issue #20217: Fix build in SCHED_SPORADIC is defined. @@ -269,7 +269,7 @@ - Issue #19683: Removed empty tests from test_minidom. Patch by Ajitesh Gupta. -- Issue #19919: Fix flacky SSL test. connect_ex() sometimes returns +- Issue #19919: Fix flaky SSL test. connect_ex() sometimes returns EWOULDBLOCK on Windows or VMs hosted on Windows. - Issue #19912: Added tests for ntpath.splitunc(). @@ -312,7 +312,7 @@ - Issue #19963: Document that importlib.import_module() no longer requires importing parent packages separately. -- Issue #18840: Introduce the json module in the tutorial, and deemphasize +- Issue #18840: Introduce the json module in the tutorial, and de-emphasize the pickle module. - Issue #19845: Updated the Compiling Python on Windows section. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 17 16:31:46 2014 From: python-checkins at python.org (zach.ware) Date: Fri, 17 Jan 2014 16:31:46 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_typo/grammar_fixes_from_3=2E3=2E?= Message-ID: <3f5R8L0pdWz7LnZ@mail.python.org> http://hg.python.org/cpython/rev/c6cec8805322 changeset: 88521:c6cec8805322 parent: 88518:3cb048463ea7 parent: 88520:195793d5208d user: Zachary Ware date: Fri Jan 17 09:31:19 2014 -0600 summary: Merge typo/grammar fixes from 3.3. files: Misc/NEWS | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -41,7 +41,7 @@ functions now conform to PEP 3333 when handle non-ASCII URLs. - Issue #19097: Raise the correct Exception when cgi.FieldStorage is given an - Invalid fileobj. + invalid fileobj. - Issue #20152: Ported Python/import.c over to Argument Clinic. @@ -447,7 +447,7 @@ - Issue #19320: test_tcl no longer fails when wantobjects is false. -- Issue #19919: Fix flacky SSL test. connect_ex() sometimes returns +- Issue #19919: Fix flaky SSL test. connect_ex() sometimes returns EWOULDBLOCK on Windows or VMs hosted on Windows. - Issue #19912: Added tests for ntpath.splitunc(). @@ -496,7 +496,7 @@ - Issue #20253: Fixed a typo in the ipaddress docs that advertised an illegal attribute name. Found by INADA Naoki. -- Issue #18840: Introduce the json module in the tutorial, and deemphasize +- Issue #18840: Introduce the json module in the tutorial, and de-emphasize the pickle module. - Issue #19845: Updated the Compiling Python on Windows section. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 17 17:03:28 2014 From: python-checkins at python.org (brett.cannon) Date: Fri, 17 Jan 2014 17:03:28 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318394=3A_Document?= =?utf-8?q?_that_cgi=2EFieldStorage_now_cleans_up_after_its?= Message-ID: <3f5Rrw1CvSz7Lp3@mail.python.org> http://hg.python.org/cpython/rev/13d04a8713ad changeset: 88522:13d04a8713ad user: Brett Cannon date: Fri Jan 17 11:03:19 2014 -0500 summary: Issue #18394: Document that cgi.FieldStorage now cleans up after its 'file' attribute properly in Python 3.4. Thanks to Marcel Hellkamp for pointing out the oversight. files: Doc/library/cgi.rst | 13 ++++++++++--- Doc/whatsnew/3.4.rst | 7 +++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Doc/library/cgi.rst b/Doc/library/cgi.rst --- a/Doc/library/cgi.rst +++ b/Doc/library/cgi.rst @@ -142,9 +142,11 @@ method reads the entire file in memory as bytes. This may not be what you want. You can test for an uploaded file by testing either the :attr:`~FieldStorage.filename` attribute or the :attr:`~FieldStorage.file` -attribute. You can then read the data at leisure from the :attr:`!file` -attribute (the :func:`~io.RawIOBase.read` and :func:`~io.IOBase.readline` -methods will return bytes):: +attribute. You can then read the data from the :attr:`!file` +attribute before it is automatically closed as part of the garbage collection of +the :class:`FieldStorage` instance +(the :func:`~io.RawIOBase.read` and :func:`~io.IOBase.readline` methods will +return bytes):: fileitem = form["userfile"] if fileitem.file: @@ -176,6 +178,11 @@ A form submitted via POST that also has a query string will contain both :class:`FieldStorage` and :class:`MiniFieldStorage` items. +.. versionchanged:: 3.4 + The :attr:`~FieldStorage.file` attribute is automatically closed upon the + garbage collection of the creating :class:`FieldStorage` instance. + + Higher Level Interface ---------------------- 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 @@ -1560,6 +1560,13 @@ :issue:`18011`.) Note: this change was also inadvertently applied in Python 3.3.3. +* The :attr:`~cgi.FieldStorage.file` attribute is now automatically closed when + the creating :class:`cgi.FieldStorage` instance is garbage collected. If you + were pulling the file object out separately from the :class:`cgi.FieldStorage` + instance and not keeping the instance alive, then you should either store the + entire :class:`cgi.FieldStorage` instance or read the contents of the file + before the :class:`cgi.FieldStorage` instance is garbage collected. + Changes in the C API -------------------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 17 17:45:11 2014 From: python-checkins at python.org (brett.cannon) Date: Fri, 17 Jan 2014 17:45:11 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320208=3A_Clarify_?= =?utf-8?q?some_things_in_the_Python_porting_HOWTO=2E?= Message-ID: <3f5Sn33z4xz7LjS@mail.python.org> http://hg.python.org/cpython/rev/863b8e71cfee changeset: 88523:863b8e71cfee user: Brett Cannon date: Fri Jan 17 11:45:01 2014 -0500 summary: Issue #20208: Clarify some things in the Python porting HOWTO. Thanks to Rodrigo Bernardo Pimentel, Ond?ej ?ert?k, and Dmitry Shachnev for the feedback leading to the changes. files: Doc/howto/pyporting.rst | 20 +++++++++++--------- 1 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Doc/howto/pyporting.rst b/Doc/howto/pyporting.rst --- a/Doc/howto/pyporting.rst +++ b/Doc/howto/pyporting.rst @@ -151,15 +151,17 @@ ``from __future__ import unicode_literals`` ''''''''''''''''''''''''''''''''''''''''''' -If you choose not to use this future statement you should then mark all of your +If you choose to use this future statement then all string literals in +Python 2 will be assumed to be Unicode (as is already the case in Python 3). +If you choose not to use this future statement then you should mark all of your text strings with a ``u`` prefix and only support Python 3.3 or newer. But you are **strongly** advised to do one or the other (six_ provides a function in case you don't want to use the future statement **and** you want to support Python 3.2 or older). -Bytes literals -'''''''''''''' +Bytes/string literals +''''''''''''''''''''' This is a **very** important one. Prefix Python 2 strings that are meant to contain bytes with a ``b`` prefix to very clearly delineate @@ -504,12 +506,13 @@ Update ``map`` for imbalanced input sequences ''''''''''''''''''''''''''''''''''''''''''''' -With Python 2, ``map`` would pad input sequences of unequal length with -`None` values, returning a sequence as long as the longest input sequence. +With Python 2, when ``map`` was given more than one input sequence it would pad +the shorter sequences with `None` values, returning a sequence as long as the +longest input sequence. With Python 3, if the input sequences to ``map`` are of unequal length, ``map`` will stop at the termination of the shortest of the sequences. For full -compatibility with ``map`` from Python 2.x, also wrap the sequences in +compatibility with ``map`` from Python 2.x, wrap the sequence arguments in :func:`itertools.zip_longest`, e.g. ``map(func, *sequences)`` becomes ``list(map(func, itertools.zip_longest(*sequences)))``. @@ -518,9 +521,8 @@ When you run your application's test suite, run it using the ``-3`` flag passed to Python. This will cause various warnings to be raised during execution about -things that 2to3 cannot handle automatically (e.g., modules that have been -removed). Try to eliminate those warnings to make your code even more portable -to Python 3. +things that are semantic changes between Python 2 and 3. Try to eliminate those +warnings to make your code even more portable to Python 3. Alternative Approaches -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 17 18:06:38 2014 From: python-checkins at python.org (brett.cannon) Date: Fri, 17 Jan 2014 18:06:38 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issues_=2320194=2C20195=3A?= =?utf-8?q?_Add_missing_=3Adeprecated=3A_markers_to_some_module?= Message-ID: <3f5TFp123lz7Lnb@mail.python.org> http://hg.python.org/cpython/rev/30013dbb5bc2 changeset: 88524:30013dbb5bc2 user: Brett Cannon date: Fri Jan 17 12:06:28 2014 -0500 summary: Issues #20194,20195: Add missing :deprecated: markers to some module docs. files: Doc/library/formatter.rst | 1 + Doc/library/imp.rst | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Doc/library/formatter.rst b/Doc/library/formatter.rst --- a/Doc/library/formatter.rst +++ b/Doc/library/formatter.rst @@ -3,6 +3,7 @@ .. module:: formatter :synopsis: Generic output formatter and device interface. + :deprecated: .. deprecated:: 3.4 Due to lack of usage, the formatter module has been deprecated and is slated diff --git a/Doc/library/imp.rst b/Doc/library/imp.rst --- a/Doc/library/imp.rst +++ b/Doc/library/imp.rst @@ -1,13 +1,13 @@ :mod:`imp` --- Access the :ref:`import ` internals ================================================================ +.. module:: imp + :synopsis: Access the implementation of the import statement. + :deprecated: + .. deprecated:: 3.4 The :mod:`imp` package is pending deprecation in favor of :mod:`importlib`. -.. module:: imp - :synopsis: Access the implementation of the import statement. - - .. index:: statement: import This module provides an interface to the mechanisms used to implement the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 17 18:07:21 2014 From: python-checkins at python.org (ethan.furman) Date: Fri, 17 Jan 2014 18:07:21 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_461=3A_removed_=2Eformat?= =?utf-8?q?=3B_added_markup?= Message-ID: <3f5TGd4KHHz7LmW@mail.python.org> http://hg.python.org/peps/rev/2ea6712aa76a changeset: 5353:2ea6712aa76a user: Ethan Furman date: Fri Jan 17 09:07:32 2014 -0800 summary: PEP 461: removed .format; added markup files: pep-0461.txt | 120 +++++++++++++++++--------------------- 1 files changed, 53 insertions(+), 67 deletions(-) diff --git a/pep-0461.txt b/pep-0461.txt --- a/pep-0461.txt +++ b/pep-0461.txt @@ -1,5 +1,5 @@ PEP: 461 -Title: Adding % and {} formatting to bytes +Title: Adding % formatting to bytes Version: $Revision$ Last-Modified: $Date$ Author: Ethan Furman @@ -8,25 +8,23 @@ Content-Type: text/x-rst Created: 2014-01-13 Python-Version: 3.5 -Post-History: 2014-01-14, 2014-01-15 +Post-History: 2014-01-14, 2014-01-15, 2014-01-17 Resolution: Abstract ======== -This PEP proposes adding the % and {} formatting operations from str to bytes [1]. +This PEP proposes adding % formatting operations similar to Python 2's ``str`` +type to ``bytes`` [1]_ [2]_. Overriding Principles ===================== -In order to avoid the problems of auto-conversion and value-generated exceptions, -all object checking will be done via isinstance, not by values contained in a -Unicode representation. In other words:: - - - duck-typing to allow/reject entry into a byte-stream - - no value generated errors +In order to avoid the problems of auto-conversion and Unicode exceptions that +could plague Py2 code, all object checking will be done by duck-typing, not by +values contained in a Unicode representation [3]_. Proposed semantics for bytes formatting @@ -35,17 +33,23 @@ %-interpolation --------------- -All the numeric formatting codes (such as %x, %o, %e, %f, %g, etc.) -will be supported, and will work as they do for str, including the -padding, justification and other related modifiers, except locale. +All the numeric formatting codes (such as ``%x``, ``%o``, ``%e``, ``%f``, +``%g``, etc.) will be supported, and will work as they do for str, including +the padding, justification and other related modifiers. Example:: >>> b'%4x' % 10 b' a' -%c will insert a single byte, either from an int in range(256), or from -a bytes argument of length 1. + >>> '%#4x' % 10 + ' 0xa' + + >>> '%04X' % 10 + '000A' + +``%c`` will insert a single byte, either from an ``int`` in range(256), or from +a ``bytes`` argument of length 1, not from a ``str``. Example: @@ -55,13 +59,13 @@ >>> b'%c' % b'a' b'a' -%s is restricted in what it will accept:: +``%s`` is restricted in what it will accept:: - - input type supports Py_buffer? + - input type supports ``Py_buffer`` [4]_? use it to collect the necessary bytes - input type is something else? - use its __bytes__ method; if there isn't one, raise an exception [2] + use its ``__bytes__`` method [5]_ ; if there isn't one, raise a ``TypeError`` Examples: @@ -80,89 +84,71 @@ .. note:: - Because the str type does not have a __bytes__ method, attempts to - directly use 'a string' as a bytes interpolation value will raise an - exception. To use 'string' values, they must be encoded or otherwise - transformed into a bytes sequence:: + Because the ``str`` type does not have a ``__bytes__`` method, attempts to + directly use ``'a string'`` as a bytes interpolation value will raise an + exception. To use ``'string'`` values, they must be encoded or otherwise + transformed into a ``bytes`` sequence:: 'a string'.encode('latin-1') -format ------- - -The format mini language codes, where they correspond with the %-interpolation codes, -will be used as-is, with three exceptions:: - - - !s is not supported, as {} can mean the default for both str and bytes, in both - Py2 and Py3. - - !b is supported, and new Py3k code can use it to be explicit. - - no other __format__ method will be called. Numeric Format Codes -------------------- -To properly handle int and float subclasses, int(), index(), and float() will be called on the -objects intended for (d, i, u), (b, o, x, X), and (e, E, f, F, g, G). +To properly handle ``int`` and ``float`` subclasses, ``int()``, ``index()``, +and ``float()`` will be called on the objects intended for (``d``, ``i``, +``u``), (``b``, ``o``, ``x``, ``X``), and (``e``, ``E``, ``f``, ``F``, ``g``, +``G``). + Unsupported codes ----------------- -%r (which calls __repr__), and %a (which calls ascii() on __repr__) are not supported. - -!r and !a are not supported. - -The n integer and float format code is not supported. - - -Open Questions -============== - -Currently non-numeric objects go through:: - - - Py_buffer - - __bytes__ - - failure - -Do we want to add a __format_bytes__ method in there? - - - Guaranteed to produce only ascii (as in b'10', not b'\x0a') - - Makes more sense than using __bytes__ to produce ascii output - - What if an object has both __bytes__ and __format_bytes__? - -Do we need to support all the numeric format codes? The floating point -exponential formats seem less appropriate, for example. +``%r`` (which calls ``__repr__``), and ``%a`` (which calls ``ascii()`` on +``__repr__``) are not supported. Proposed variations =================== -It was suggested to let %s accept numbers, but since numbers have their own +It was suggested to let ``%s`` accept numbers, but since numbers have their own format codes this idea was discarded. -It has been suggested to use %b for bytes instead of %s. +It has been suggested to use ``%b`` for bytes instead of ``%s``. - - Rejected as %b does not exist in Python 2.x %-interpolation, which is - why we are using %s. + - Rejected as ``%b`` does not exist in Python 2.x %-interpolation, which is + why we are using ``%s``. -It has been proposed to automatically use .encode('ascii','strict') for str -arguments to %s. +It has been proposed to automatically use ``.encode('ascii','strict')`` for +``str`` arguments to ``%s``. - Rejected as this would lead to intermittent failures. Better to have the operation always fail so the trouble-spot can be correctly fixed. -It has been proposed to have %s return the ascii-encoded repr when the value -is a str (b'%s' % 'abc' --> b"'abc'"). +It has been proposed to have ``%s`` return the ascii-encoded repr when the +value is a ``str`` (b'%s' % 'abc' --> b"'abc'"). - Rejected as this would lead to hard to debug failures far from the problem site. Better to have the operation always fail so the trouble-spot can be easily fixed. +Originally this PEP also proposed adding format style formatting, but it +was decided that format and its related machinery were all strictly text +(aka ``str``) based, and it was dropped. + +Various new special methods were proposed, such as ``__ascii__``, +``__format_bytes__``, etc.; such methods are not needed at this time, but can +be visited again later if real-world use shows deficiencies with this solution. + Footnotes ========= -.. [1] string.Template is not under consideration. -.. [2] TypeError, ValueError, or UnicodeEncodeError? +.. [1] http://docs.python.org/2/library/stdtypes.html#string-formatting +.. [2] neither string.Template, format, nor str.format are under consideration. +.. [3] %c is not an exception as neither of its possible arguments are unicode. +.. [4] http://docs.python.org/3/c-api/buffer.html +.. [5] http://docs.python.org/3/reference/datamodel.html#object.__bytes__ Copyright -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri Jan 17 19:36:52 2014 From: python-checkins at python.org (vinay.sajip) Date: Fri, 17 Jan 2014 19:36:52 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Added_example_?= =?utf-8?q?to_recently_added_cookbook_entry=2E?= Message-ID: <3f5WFw3dQZz7LjN@mail.python.org> http://hg.python.org/cpython/rev/4d867dc0d5fb changeset: 88525:4d867dc0d5fb branch: 3.3 parent: 88520:195793d5208d user: Vinay Sajip date: Fri Jan 17 18:36:02 2014 +0000 summary: Added example to recently added cookbook entry. files: Doc/howto/logging-cookbook.rst | 28 ++++++++++++++++++++++ 1 files changed, 28 insertions(+), 0 deletions(-) diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -1920,3 +1920,31 @@ ``_`` for the message (or perhaps ``__``, if you are using ``_`` for localization). +Examples of this approach are given below. Firstly, formatting with +:meth:`str.format`:: + + >>> __ = BraceMessage + >>> print(__('Message with {0} {1}', 2, 'placeholders')) + Message with 2 placeholders + >>> class Point: pass + ... + >>> p = Point() + >>> p.x = 0.5 + >>> p.y = 0.5 + >>> print(__('Message with coordinates: ({point.x:.2f}, {point.y:.2f})', point=p)) + Message with coordinates: (0.50, 0.50) + +Secondly, formatting with :class:`string.Template`:: + + >>> __ = DollarMessage + >>> print(__('Message with $num $what', num=2, what='placeholders')) + Message with 2 placeholders + >>> + +One thing to note is that you pay no significant performance penalty with this +approach: the actual formatting happens not when you make the logging call, but +when (and if) the logged message is actually about to be output to a log by a +handler. So the only slightly unusual thing which might trip you up is that the +parentheses go around the format string and the arguments, not just the format +string. That?s because the __ notation is just syntax sugar for a constructor +call to one of the ``XXXMessage`` classes shown above. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 17 19:36:53 2014 From: python-checkins at python.org (vinay.sajip) Date: Fri, 17 Jan 2014 19:36:53 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merged_documentation_update_from_3=2E3=2E?= Message-ID: <3f5WFx5S4gz7LjN@mail.python.org> http://hg.python.org/cpython/rev/b62e881129a5 changeset: 88526:b62e881129a5 parent: 88524:30013dbb5bc2 parent: 88525:4d867dc0d5fb user: Vinay Sajip date: Fri Jan 17 18:36:41 2014 +0000 summary: Merged documentation update from 3.3. files: Doc/howto/logging-cookbook.rst | 28 ++++++++++++++++++++++ 1 files changed, 28 insertions(+), 0 deletions(-) diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -1918,3 +1918,31 @@ ``_`` for the message (or perhaps ``__``, if you are using ``_`` for localization). +Examples of this approach are given below. Firstly, formatting with +:meth:`str.format`:: + + >>> __ = BraceMessage + >>> print(__('Message with {0} {1}', 2, 'placeholders')) + Message with 2 placeholders + >>> class Point: pass + ... + >>> p = Point() + >>> p.x = 0.5 + >>> p.y = 0.5 + >>> print(__('Message with coordinates: ({point.x:.2f}, {point.y:.2f})', point=p)) + Message with coordinates: (0.50, 0.50) + +Secondly, formatting with :class:`string.Template`:: + + >>> __ = DollarMessage + >>> print(__('Message with $num $what', num=2, what='placeholders')) + Message with 2 placeholders + >>> + +One thing to note is that you pay no significant performance penalty with this +approach: the actual formatting happens not when you make the logging call, but +when (and if) the logged message is actually about to be output to a log by a +handler. So the only slightly unusual thing which might trip you up is that the +parentheses go around the format string and the arguments, not just the format +string. That?s because the __ notation is just syntax sugar for a constructor +call to one of the ``XXXMessage`` classes shown above. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 17 21:01:54 2014 From: python-checkins at python.org (gregory.p.smith) Date: Fri, 17 Jan 2014 21:01:54 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogc29ydCBvcy5saXN0?= =?utf-8?q?xattr_results_before_comparing_it_to_avoid_depending_on_the?= Message-ID: <3f5Y821Z4vz7Lm0@mail.python.org> http://hg.python.org/cpython/rev/38333fa7dfe4 changeset: 88527:38333fa7dfe4 branch: 3.3 parent: 88525:4d867dc0d5fb user: Gregory P. Smith date: Fri Jan 17 12:01:22 2014 -0800 summary: sort os.listxattr results before comparing it to avoid depending on the ordering of the directory information in the underlying filesystem. files: Lib/test/test_shutil.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -430,7 +430,7 @@ os.setxattr(src, 'user.foo', b'42') os.setxattr(src, 'user.bar', b'43') shutil._copyxattr(src, dst) - self.assertEqual(os.listxattr(src), os.listxattr(dst)) + self.assertEqual(sorted(os.listxattr(src)), sorted(os.listxattr(dst))) self.assertEqual( os.getxattr(src, 'user.foo'), os.getxattr(dst, 'user.foo')) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 17 21:01:55 2014 From: python-checkins at python.org (gregory.p.smith) Date: Fri, 17 Jan 2014 21:01:55 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_sort_os=2Elistxattr_results_before_comparing_it_to_avoid?= =?utf-8?q?_depending_on_the?= Message-ID: <3f5Y833cgVz7Lms@mail.python.org> http://hg.python.org/cpython/rev/63fc7af91752 changeset: 88528:63fc7af91752 parent: 88526:b62e881129a5 parent: 88527:38333fa7dfe4 user: Gregory P. Smith date: Fri Jan 17 12:01:40 2014 -0800 summary: sort os.listxattr results before comparing it to avoid depending on the ordering of the directory information in the underlying filesystem. files: Lib/test/test_shutil.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -431,7 +431,7 @@ os.setxattr(src, 'user.foo', b'42') os.setxattr(src, 'user.bar', b'43') shutil._copyxattr(src, dst) - self.assertEqual(os.listxattr(src), os.listxattr(dst)) + self.assertEqual(sorted(os.listxattr(src)), sorted(os.listxattr(dst))) self.assertEqual( os.getxattr(src, 'user.foo'), os.getxattr(dst, 'user.foo')) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 17 21:09:14 2014 From: python-checkins at python.org (gregory.p.smith) Date: Fri, 17 Jan 2014 21:09:14 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_avoid_a_compil?= =?utf-8?q?er_warning_about_assigning_const_char_*_to_char_*=2E?= Message-ID: <3f5YJV0wdCz7LnX@mail.python.org> http://hg.python.org/cpython/rev/64401c6656b5 changeset: 88529:64401c6656b5 branch: 3.3 parent: 88527:38333fa7dfe4 user: Gregory P. Smith date: Fri Jan 17 12:08:49 2014 -0800 summary: avoid a compiler warning about assigning const char * to char *. files: Modules/_ssl.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -1167,7 +1167,7 @@ goto fail0; PyTuple_SET_ITEM(retval, 0, v); } - cipher_protocol = SSL_CIPHER_get_version(current); + cipher_protocol = (char *) SSL_CIPHER_get_version(current); if (cipher_protocol == NULL) { Py_INCREF(Py_None); PyTuple_SET_ITEM(retval, 1, Py_None); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 17 21:09:15 2014 From: python-checkins at python.org (gregory.p.smith) Date: Fri, 17 Jan 2014 21:09:15 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_avoid_a_compiler_warning_about_assigning_const_char_*_to?= =?utf-8?q?_char_*=2E?= Message-ID: <3f5YJW2TdXz7Lp3@mail.python.org> http://hg.python.org/cpython/rev/725bc24f5492 changeset: 88530:725bc24f5492 parent: 88528:63fc7af91752 parent: 88529:64401c6656b5 user: Gregory P. Smith date: Fri Jan 17 12:09:05 2014 -0800 summary: avoid a compiler warning about assigning const char * to char *. files: Modules/_ssl.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -1381,7 +1381,7 @@ goto fail0; PyTuple_SET_ITEM(retval, 0, v); } - cipher_protocol = SSL_CIPHER_get_version(current); + cipher_protocol = (char *) SSL_CIPHER_get_version(current); if (cipher_protocol == NULL) { Py_INCREF(Py_None); PyTuple_SET_ITEM(retval, 1, Py_None); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 17 22:24:53 2014 From: python-checkins at python.org (zach.ware) Date: Fri, 17 Jan 2014 22:24:53 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMjY1?= =?utf-8?q?=3A_Updated_some_parts_of_the_Using_Windows_document=2E?= Message-ID: <3f5Zzn4H5Cz7LjN@mail.python.org> http://hg.python.org/cpython/rev/fc52b657bcd9 changeset: 88531:fc52b657bcd9 branch: 3.3 parent: 88529:64401c6656b5 user: Zachary Ware date: Fri Jan 17 15:23:42 2014 -0600 summary: Issue #20265: Updated some parts of the Using Windows document. Includes: -mention cx_Freeze instead of py2exe (at least until py2exe supports Python 3) -update ActivePython link -Remove mention of platforms that were never supported by Python 3 (Win9x, DOS) files: Doc/using/windows.rst | 23 ++++++++++------------- Misc/NEWS | 2 ++ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -24,10 +24,6 @@ earlier are no longer supported (due to the lack of users or developers). Check :pep:`11` for details on all unsupported platforms. -* Up to 2.5, Python was still compatible with Windows 95, 98 and ME (but already - raised a deprecation warning on installation). For Python 2.6 (and all - following releases), this support was dropped and new releases are just - expected to work on the Windows NT family. * `Windows CE `_ is still supported. * The `Cygwin `_ installer offers to install the `Python interpreter `_ as well; it is located under @@ -36,8 +32,8 @@ release/python>`_, `Maintainer releases `_) -See `Python for Windows (and DOS) `_ -for detailed information about platforms with precompiled installers. +See `Python for Windows `_ +for detailed information about platforms with pre-compiled installers. .. seealso:: @@ -64,7 +60,7 @@ additional functionality. The following is a list of popular versions and their key features: -`ActivePython `_ +`ActivePython `_ Installer with multi-platform compatibility, documentation, PyWin32 `Enthought Python Distribution `_ @@ -527,13 +523,14 @@ by David and Paul Boddie -Py2exe ------- +cx_Freeze +--------- -`Py2exe `_ is a :mod:`distutils` extension (see -:ref:`extending-distutils`) which wraps Python scripts into executable Windows -programs (:file:`{*}.exe` files). When you have done this, you can distribute -your application without requiring your users to install Python. +`cx_Freeze `_ is a :mod:`distutils` +extension (see :ref:`extending-distutils`) which wraps Python scripts into +executable Windows programs (:file:`{*}.exe` files). When you have done this, +you can distribute your application without requiring your users to install +Python. WConio diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -302,6 +302,8 @@ Documentation ------------- +- Issue #20265: Updated some parts of the Using Windows document. + - Issue #20266: Updated some parts of the Windows FAQ. - Issue #20255: Updated the about and bugs pages. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 17 22:24:54 2014 From: python-checkins at python.org (zach.ware) Date: Fri, 17 Jan 2014 22:24:54 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320265=3A_Merge_with_3=2E3?= Message-ID: <3f5Zzp6dRVz7Lns@mail.python.org> http://hg.python.org/cpython/rev/5a9171e70573 changeset: 88532:5a9171e70573 parent: 88530:725bc24f5492 parent: 88531:fc52b657bcd9 user: Zachary Ware date: Fri Jan 17 15:24:18 2014 -0600 summary: Issue #20265: Merge with 3.3 files: Doc/using/windows.rst | 23 ++++++++++------------- Misc/NEWS | 2 ++ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -24,10 +24,6 @@ earlier are no longer supported (due to the lack of users or developers). Check :pep:`11` for details on all unsupported platforms. -* Up to 2.5, Python was still compatible with Windows 95, 98 and ME (but already - raised a deprecation warning on installation). For Python 2.6 (and all - following releases), this support was dropped and new releases are just - expected to work on the Windows NT family. * `Windows CE `_ is still supported. * The `Cygwin `_ installer offers to install the `Python interpreter `_ as well; it is located under @@ -36,8 +32,8 @@ release/python>`_, `Maintainer releases `_) -See `Python for Windows (and DOS) `_ -for detailed information about platforms with precompiled installers. +See `Python for Windows `_ +for detailed information about platforms with pre-compiled installers. .. seealso:: @@ -64,7 +60,7 @@ additional functionality. The following is a list of popular versions and their key features: -`ActivePython `_ +`ActivePython `_ Installer with multi-platform compatibility, documentation, PyWin32 `Enthought Python Distribution `_ @@ -527,13 +523,14 @@ by David and Paul Boddie -Py2exe ------- +cx_Freeze +--------- -`Py2exe `_ is a :mod:`distutils` extension (see -:ref:`extending-distutils`) which wraps Python scripts into executable Windows -programs (:file:`{*}.exe` files). When you have done this, you can distribute -your application without requiring your users to install Python. +`cx_Freeze `_ is a :mod:`distutils` +extension (see :ref:`extending-distutils`) which wraps Python scripts into +executable Windows programs (:file:`{*}.exe` files). When you have done this, +you can distribute your application without requiring your users to install +Python. WConio diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -489,6 +489,8 @@ Documentation ------------- +- Issue #20265: Updated some parts of the Using Windows document. + - Issue #20266: Updated some parts of the Windows FAQ. - Issue #20255: Updated the about and bugs pages. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 02:47:56 2014 From: python-checkins at python.org (larry.hastings) Date: Sat, 18 Jan 2014 02:47:56 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320287=3A_Argument?= =?utf-8?q?_Clinic=27s_output_is_now_configurable=2C_allowing?= Message-ID: <3f5hqJ2k4nz7Lm0@mail.python.org> http://hg.python.org/cpython/rev/7f6712954d5d changeset: 88533:7f6712954d5d user: Larry Hastings date: Fri Jan 17 17:47:17 2014 -0800 summary: Issue #20287: Argument Clinic's output is now configurable, allowing delaying its output or even redirecting it to a separate file. files: Doc/howto/clinic.rst | 320 ++++++++- Misc/NEWS | 3 + Modules/_pickle.c | 70 +- Modules/_weakref.c | 3 +- Modules/zlibmodule.c | 8 +- Python/import.c | 32 +- Tools/clinic/clinic.py | 857 ++++++++++++++++++----- Tools/clinic/clinic_test.py | 29 + 8 files changed, 1047 insertions(+), 275 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -23,6 +23,58 @@ version of Argument Clinic that ships with CPython 3.5 *could* be totally incompatible and break all your code. +============================ +The Goals Of Argument Clinic +============================ + +Argument Clinic's primary goal +is to take over responsibility for all argument parsing code +inside CPython. This means that, when you convert a function +to work with Argument Clinic, that function should no longer +do any of its own argument parsing--the code generated by +Argument Clinic should be a "black box" to you, where CPython +calls in at the top, and your code gets called at the bottom, +with ``PyObject *args`` (and maybe ``PyObject *kwargs``) +magically converted into the C variables and types you need. + +In order for Argument Clinic to accomplish its primary goal, +it must be easy to use. Currently, working with CPython's +argument parsing library is a chore, requiring maintaining +redundant information in a surprising number of places. +When you use Argument Clinic, you don't have to repeat yourself. + +Obviously, no one would want to use Argument Clinic unless +it's solving a their problem without creating problems of +its own. +So Argument Clinic should generate correct code, and its +code should preferably be slower, and definitely should +not introduce a major speed regression. (Eventually Argument +Clinic should enable a major speedup--we should be able +to rewrite its code generator so it produces tailor-made +parsing code, rather than using the general-purpose functions +from the CPython code base, which would make for the fastest +argument parsing possible.) + +Additionally, Argument Clinic must be flexible enough to +work with any approach to argument parsing. Python has +some functions with some very strange parsing behaviors; +Argument Clinic's goal is to support all of them. + +Finally, the original motivation for Argument Clinic was +to provide introspection "signatures" for CPython builtins. +It used to be, the introspection query functions would throw +an exception if you passed in a builtin. With Argument +Clinic, that's a thing of the past! + +One idea you should keep in mind, as you work with +Argument Clinic: the more information you give it, the +better job it'll be able to do. +Argument Clinic is admittedly relatively simple right +now. But as it evolves it will get more sophisticated, +and it should be able to do many interesting and smart +things with all the information you give it. + + ======================== Basic Concepts And Usage ======================== @@ -84,7 +136,15 @@ ============================== The best way to get a sense of how Argument Clinic works is to -convert a function to work with it. Let's dive in! +convert a function to work with it. Here, then, are the bare +minimum steps you'd need to follow to convert a function to +work with Argument Clinic. Note that for code you plan to +check in to CPython, you really should take the conversion farther, +using some of the advanced concepts you'll see later on in +the document (like "return converters" and "self converters"). +But we'll keep it simple for this walkthrough so you can learn. + +Let's dive in! 0. Make sure you're working with a freshly updated checkout of the CPython trunk. @@ -1282,6 +1342,264 @@ (This is the preferred approach for optional functions; in the future, Argument Clinic may generate the entire ``PyMethodDef`` structure.) + +Changing and redirecting Clinic's output +---------------------------------------- + +It can be inconvenient to have Clinic's output interspersed with +your conventional hand-edited C code. Luckily, Clinic is configurable: +you can buffer up its output for printing later (or earlier!), or write +its output to a separate file. You can also add a prefix or suffix to +every line of Clinic's generated output. + +While changing Clinic's output in this manner can be a boon to readability, +it may result in Clinic code using types before they are defined, or +your code attempting to use Clinic-generated code befire it is defined. +These problems can be easily solved by rearranging the declarations in your file, +or moving where Clinic's generated code goes. (This is why the default behavior +of Clinic is to output everything into the current block; while many people +consider this hampers readability, it will never require rearranging your +code to fix definition-before-use problems.) + +Let's start with defining some terminology: + +*field* + A field, in this context, is a subsection of Clinic's output. + For example, the ``#define`` for the ``PyMethodDef`` structure + is a field, called ``methoddef_define``. Clinic has seven + different fields it can output per function definition:: + + docstring_prototype + docstring_definition + methoddef_define + impl_prototype + parser_prototype + parser_definition + impl_definition + + All the names are of the form ``"_"``, + where ``""`` is the semantic object represented (the parsing function, + the impl function, the docstring, or the methoddef structure) and ``""`` + represents what kind of statement the field is. Field names that end in + ``"_prototype"`` + represent forward declarations of that thing, without the actual body/data + of the thing; field names that end in ``"_definition"`` represent the actual + definition of the thing, with the body/data of the thing. (``"methoddef"`` + is special, it's the only one that ends with ``"_define"``, representing that + it's a preprocessor #define.) + +*destination* + A destination is a place Clinic can write output to. There are + five built-in destinations: + + ``block`` + The default destination: printed in the output section of + the current Clinic block. + + ``buffer`` + A text buffer where you can save text for later. Text sent + here is appended to the end of any exsiting text. It's an + error to have any text left in the buffer when Clinic finishes + processing a file. + + ``file`` + A separate "clinic file" that will be created automatically by Clinic. + The filename chosen for the file is ``{basename}.clinic{extension}``, + where ``basename`` and ``extension`` were assigned the output + from ``os.path.splitext()`` run on the current file. (Example: + the ``file`` destination for ``_pickle.c`` would be written to + ``_pickle.clinic.c``.) + + **Important: When using a** ``file`` **destination, you** + *must check in* **the generated file!** + + ``two-pass`` + A buffer like ``buffer``. However, a two-pass buffer can only + be written once, and it prints out all text sent to it during + all of processing, even from Clinic blocks *after* the + + ``suppress`` + The text is suppressed--thrown away. + + +Clinic defines five new directives that let you reconfigure its output. + +The first new directive is ``dump``:: + + dump + +This dumps the current contents of the named destination into the output of +the current block, and empties it. This only works with ``buffer`` and +``two-pass`` destinations. + +The second new directive is ``output``. The most basic form of ``output`` +is like this:: + + output + +This tells Clinic to output *field* to *destination*. ``output`` also +supports a special meta-destination, called ``everything``, which tells +Clinic to output *all* fields to that *destination*. + +``output`` has a number of other functions:: + + output push + output pop + output preset + + +``output push`` and ``output pop`` allow you to push and pop +configurations on an internal configuration stack, so that you +can temporarily modify the output configuration, then easily restore +the previous configuration. Simply push before your change to save +the current configuration, then pop when you wish to restore the +previous configuration. + +``output preset`` sets Clinic's output to one of several built-in +preset configurations, as follows: + + ``original`` + Clinic's starting configuration. + + Suppress the ``parser_prototype`` + and ``docstring_prototype``, write everything else to ``block``. + + ``file`` + Designed to write everything to the "clinic file" that it can. + You then ``#include`` this file near the top of your file. + You may need to rearrange your file to make this work, though + usually this just means creating forward declarations for various + ``typedef`` and ``PyTypeObject`` definitions. + + Suppress the ``parser_prototype`` + and ``docstring_prototype``, write the ``impl_definition`` to + ``block``, and write everything else to ``file``. + + ``buffer`` + Save up all most of the output from Clinic, to be written into + your file near the end. For Python files implementing modules + or builtin types, it's recommended that you dump the buffer + just above the static structures for your module or + builtin type; these are normally very near the end. Using + ``buffer`` may require even more editing than ``file``, if + your file has static ``PyMethodDef`` arrays defined in the + middle of the file. + + Suppress the ``parser_prototype``, ``impl_prototype``, + and ``docstring_prototype``, write the ``impl_definition`` to + ``block``, and write everything else to ``file``. + + ``two-pass`` + Similar to the ``buffer`` preset, but writes forward declarations to + the ``two-pass`` buffer, and definitions to the ``buffer``. + This is similar to the ``buffer`` preset, but may require + less editing than ``buffer``. Dump the ``two-pass`` buffer + near the top of your file, and dump the ``buffer`` near + the end just like you would when using the ``buffer`` preset. + + Suppresses the ``impl_prototype``, write the ``impl_definition`` + to ``block``, write ``docstring_prototype``, ``methoddef_define``, + and ``parser_prototype`` to ``two-pass``, write everything else + to ``buffer``. + + ``partial-buffer`` + Similar to the ``buffer`` preset, but writes more things to ``block``, + only writing the really big chunks of generated code to ``buffer``. + This avoids the definition-before-use problem of ``buffer`` completely, + at the small cost of having slightly more stuff in the block's output. + Dump the ``buffer`` near the end, just like you would when using + the ``buffer`` preset. + + Suppresses the ``impl_prototype``, write the ``docstring_definition`` + and ``parser_defintion`` to ``buffer``, write everything else to ``block``. + +The third new directive is ``destination``:: + + destination [...] + +This performs an operation on the destination named ``name``. + +There are two defined subcommands: ``new`` and ``clear``. + +The ``new`` subcommand works like this:: + + destination new + +This creates a new destination with name ```` and type ````. + +There are five destination types:: + + ``suppress`` + Throws the text away. + + ``block`` + Writes the text to the current block. This is what Clinic + originally did. + + ``buffer`` + A simple text buffer, like the "buffer" builtin destination above. + + ``file`` + A text file. The file destination takes an extra argument, + a template to use for building the filename, like so: + + destination new + + The template can use three strings internally that will be replaced + by bits of the filename: + + {filename} + The full filename. + {basename} + Everything up to but not including the last '.'. + {extension} + The last '.' and everything after it. + + If there are no periods in the filename, {basename} and {filename} + are the same, and {extension} is empty. "{basename}{extension}" + is always exactly the same as "{filename}"." + + ``two-pass`` + A two-pass buffer, like the "two-pass" builtin destination above. + + +The ``clear`` subcommand works like this:: + + destination clear + +It removes all the accumulated text up to this point in the destination. +(I don't know what you'd need this for, but I thought maybe it'd be +useful while someone's experimenting.) + +The fourth new directive is ``set``:: + + set line_prefix "string" + set line_suffix "string" + +``set`` lets you set two internal variables in Clinic. +``line_prefix`` is a string that will be prepended to every line of Clinic's output; +``line_suffix`` is a string that will be appended to every line of Clinic's output. + +Both of these suport two format strings: + + ``{block comment start}`` + Turns into the string ``/*``, the start-comment text sequence for C files. + + ``{block comment end}`` + Turns into the string ``*/``, the end-comment text sequence for C files. + +The final new directive is one you shouldn't need to use directly, +called ``preserve``:: + + preserve + +This tells Clinic that the current contents of the output should be kept, unmodifed. +This is used internally by Clinic when dumping output into ``file`` files; wrapping +it in a Clinic block lets Clinic use its existing checksum functionality to ensure +the file was not modified by hand before it gets overwritten. + + +Using Argument Clinic in Python files ------------------------------------- It's actually possible to use Argument Clinic to preprocess Python files. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -88,6 +88,9 @@ Tools/Demos ----------- +- Issue #20287: Argument Clinic's output is now configurable, allowing + delaying its output or even redirecting it to a separate file. + - Issue #20226: Argument Clinic now permits simple expressions (e.g. "sys.maxsize - 1") as default values for parameters. diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -3906,16 +3906,12 @@ static PyObject * _pickle_Pickler_clear_memo(PyObject *self, PyObject *Py_UNUSED(ignored)) { - PyObject *return_value = NULL; - - return_value = _pickle_Pickler_clear_memo_impl((PicklerObject *)self); - - return return_value; + return _pickle_Pickler_clear_memo_impl((PicklerObject *)self); } static PyObject * _pickle_Pickler_clear_memo_impl(PicklerObject *self) -/*[clinic end generated code: checksum=0574593b102fffb8e781d7bb9b536ceffc525ac1]*/ +/*[clinic end generated code: checksum=015cc3c5befea86cb08b9396938477bebbea4157]*/ { if (self->memo) PyMemoTable_Clear(self->memo); @@ -4191,16 +4187,12 @@ static PyObject * _pickle_PicklerMemoProxy_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) { - PyObject *return_value = NULL; - - return_value = _pickle_PicklerMemoProxy_clear_impl((PicklerMemoProxyObject *)self); - - return return_value; + return _pickle_PicklerMemoProxy_clear_impl((PicklerMemoProxyObject *)self); } static PyObject * _pickle_PicklerMemoProxy_clear_impl(PicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=c6ca252530ccb3ea2f4b33507b51b183f23b24c7]*/ +/*[clinic end generated code: checksum=bf8dd8c8688d0c0f7a2e59a804c47375b740f2f0]*/ { if (self->pickler->memo) PyMemoTable_Clear(self->pickler->memo); @@ -4228,16 +4220,12 @@ static PyObject * _pickle_PicklerMemoProxy_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) { - PyObject *return_value = NULL; - - return_value = _pickle_PicklerMemoProxy_copy_impl((PicklerMemoProxyObject *)self); - - return return_value; + return _pickle_PicklerMemoProxy_copy_impl((PicklerMemoProxyObject *)self); } static PyObject * _pickle_PicklerMemoProxy_copy_impl(PicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=808c4d5a37359ed5fb2efe81dbe5ff480719f470]*/ +/*[clinic end generated code: checksum=72d46879dc658adbd3d28b5c82dd8dcfa6b9b124]*/ { Py_ssize_t i; PyMemoTable *memo; @@ -4295,16 +4283,12 @@ static PyObject * _pickle_PicklerMemoProxy___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) { - PyObject *return_value = NULL; - - return_value = _pickle_PicklerMemoProxy___reduce___impl((PicklerMemoProxyObject *)self); - - return return_value; + return _pickle_PicklerMemoProxy___reduce___impl((PicklerMemoProxyObject *)self); } static PyObject * _pickle_PicklerMemoProxy___reduce___impl(PicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=2293152bdf53951a012d430767b608f5fb4213b5]*/ +/*[clinic end generated code: checksum=aad71c4d81d1ed8bf0d32362dd80a29b9f3b0d03]*/ { PyObject *reduce_value, *dict_args; PyObject *contents = _pickle_PicklerMemoProxy_copy_impl(self); @@ -6342,16 +6326,12 @@ static PyObject * _pickle_Unpickler_load(PyObject *self, PyObject *Py_UNUSED(ignored)) { - PyObject *return_value = NULL; - - return_value = _pickle_Unpickler_load_impl(self); - - return return_value; + return _pickle_Unpickler_load_impl(self); } static PyObject * _pickle_Unpickler_load_impl(PyObject *self) -/*[clinic end generated code: checksum=55f35fcaf034817e75c355ec50b7878577355899]*/ +/*[clinic end generated code: checksum=9477099fe6a90748c13ff1a6dd92ba7ab7a89602]*/ { UnpicklerObject *unpickler = (UnpicklerObject*)self; @@ -6417,8 +6397,8 @@ PyObject *module_name; PyObject *global_name; - if (!PyArg_ParseTuple(args, - "OO:find_class", + if (!PyArg_UnpackTuple(args, "find_class", + 2, 2, &module_name, &global_name)) goto exit; return_value = _pickle_Unpickler_find_class_impl((UnpicklerObject *)self, module_name, global_name); @@ -6429,7 +6409,7 @@ static PyObject * _pickle_Unpickler_find_class_impl(UnpicklerObject *self, PyObject *module_name, PyObject *global_name) -/*[clinic end generated code: checksum=1f353d13a32c9d94feb1466b3c2d0529a7e5650e]*/ +/*[clinic end generated code: checksum=15ed4836fd5860425fff9ea7855d4f1f4413c170]*/ { PyObject *global; PyObject *modules_dict; @@ -6752,16 +6732,12 @@ static PyObject * _pickle_UnpicklerMemoProxy_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) { - PyObject *return_value = NULL; - - return_value = _pickle_UnpicklerMemoProxy_clear_impl((UnpicklerMemoProxyObject *)self); - - return return_value; + return _pickle_UnpicklerMemoProxy_clear_impl((UnpicklerMemoProxyObject *)self); } static PyObject * _pickle_UnpicklerMemoProxy_clear_impl(UnpicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=e0f99c26d48444a3f58f598bec3190c66595fce7]*/ +/*[clinic end generated code: checksum=07adecee2181e5e268b2ff184360b1d88ad947f2]*/ { _Unpickler_MemoCleanup(self->unpickler); self->unpickler->memo = _Unpickler_NewMemo(self->unpickler->memo_size); @@ -6791,16 +6767,12 @@ static PyObject * _pickle_UnpicklerMemoProxy_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) { - PyObject *return_value = NULL; - - return_value = _pickle_UnpicklerMemoProxy_copy_impl((UnpicklerMemoProxyObject *)self); - - return return_value; + return _pickle_UnpicklerMemoProxy_copy_impl((UnpicklerMemoProxyObject *)self); } static PyObject * _pickle_UnpicklerMemoProxy_copy_impl(UnpicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=8c0ab91c0b694ea71a1774650898a760d1ab4765]*/ +/*[clinic end generated code: checksum=47b9f0cc12c5a54004252e1b4916822cdfa8a881]*/ { Py_ssize_t i; PyObject *new_memo = PyDict_New(); @@ -6851,16 +6823,12 @@ static PyObject * _pickle_UnpicklerMemoProxy___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) { - PyObject *return_value = NULL; - - return_value = _pickle_UnpicklerMemoProxy___reduce___impl((UnpicklerMemoProxyObject *)self); - - return return_value; + return _pickle_UnpicklerMemoProxy___reduce___impl((UnpicklerMemoProxyObject *)self); } static PyObject * _pickle_UnpicklerMemoProxy___reduce___impl(UnpicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=4ee76a65511291f0de2e9e63db395d2e5d6d8df6]*/ +/*[clinic end generated code: checksum=2f061bb9ecd9ee8500184c135148a131c46a3b88]*/ { PyObject *reduce_value; PyObject *constructor_args; diff --git a/Modules/_weakref.c b/Modules/_weakref.c --- a/Modules/_weakref.c +++ b/Modules/_weakref.c @@ -34,6 +34,7 @@ { PyObject *return_value = NULL; Py_ssize_t _return_value; + _return_value = _weakref_getweakrefcount_impl(module, object); if ((_return_value == -1) && PyErr_Occurred()) goto exit; @@ -45,7 +46,7 @@ static Py_ssize_t _weakref_getweakrefcount_impl(PyModuleDef *module, PyObject *object) -/*[clinic end generated code: checksum=436e8fbe0297434375f039d8c2d9fc3a9bbe773c]*/ +/*[clinic end generated code: checksum=744fa73ba68c0ee89567e9cb9bea11863270d516]*/ { PyWeakReference **list; diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -1047,16 +1047,12 @@ static PyObject * zlib_Compress_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) { - PyObject *return_value = NULL; - - return_value = zlib_Compress_copy_impl((compobject *)self); - - return return_value; + return zlib_Compress_copy_impl((compobject *)self); } static PyObject * zlib_Compress_copy_impl(compobject *self) -/*[clinic end generated code: checksum=2f454ee15be3bc53cfb4e845c3f891f68be4c8e4]*/ +/*[clinic end generated code: checksum=d57a7911deb7940e85a8d7e65af20b6e2df69000]*/ { compobject *retval = NULL; int err; diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -246,16 +246,12 @@ static PyObject * _imp_lock_held(PyModuleDef *module, PyObject *Py_UNUSED(ignored)) { - PyObject *return_value = NULL; - - return_value = _imp_lock_held_impl(module); - - return return_value; + return _imp_lock_held_impl(module); } static PyObject * _imp_lock_held_impl(PyModuleDef *module) -/*[clinic end generated code: checksum=c5858b257881f94dee95526229a8d1a57ccff158]*/ +/*[clinic end generated code: checksum=ede1cafb78eb22e3009602f684c8b780e2b82d62]*/ { #ifdef WITH_THREAD return PyBool_FromLong(import_lock_thread != -1); @@ -289,16 +285,12 @@ static PyObject * _imp_acquire_lock(PyModuleDef *module, PyObject *Py_UNUSED(ignored)) { - PyObject *return_value = NULL; - - return_value = _imp_acquire_lock_impl(module); - - return return_value; + return _imp_acquire_lock_impl(module); } static PyObject * _imp_acquire_lock_impl(PyModuleDef *module) -/*[clinic end generated code: checksum=badb56ed0079a6b902c9616fe068d572765b1863]*/ +/*[clinic end generated code: checksum=5b520b2416c5954a7cf0ed30955d68abe20b5868]*/ { #ifdef WITH_THREAD _PyImport_AcquireLock(); @@ -330,16 +322,12 @@ static PyObject * _imp_release_lock(PyModuleDef *module, PyObject *Py_UNUSED(ignored)) { - PyObject *return_value = NULL; - - return_value = _imp_release_lock_impl(module); - - return return_value; + return _imp_release_lock_impl(module); } static PyObject * _imp_release_lock_impl(PyModuleDef *module) -/*[clinic end generated code: checksum=f1c2a75e3136a113184e0af2a676d5f0b5b685b4]*/ +/*[clinic end generated code: checksum=efcd9d2923294c04371596e7f6d66a706d43fcac]*/ { #ifdef WITH_THREAD if (_PyImport_ReleaseLock() < 0) { @@ -1847,16 +1835,12 @@ static PyObject * _imp_extension_suffixes(PyModuleDef *module, PyObject *Py_UNUSED(ignored)) { - PyObject *return_value = NULL; - - return_value = _imp_extension_suffixes_impl(module); - - return return_value; + return _imp_extension_suffixes_impl(module); } static PyObject * _imp_extension_suffixes_impl(PyModuleDef *module) -/*[clinic end generated code: checksum=835921e67fd698e22e101eea64839d1ad62b6451]*/ +/*[clinic end generated code: checksum=82fb35d8429a429a4dc80c84b45b1aad73ff1de7]*/ { PyObject *list; const char *suffix; diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -16,12 +16,14 @@ import io import itertools import os +import pprint import re import shlex import sys import tempfile import textwrap import traceback +import uuid # TODO: # @@ -86,10 +88,13 @@ return append, output -def fail(*args, filename=None, line_number=None): +def warn_or_fail(fail=False, *args, filename=None, line_number=None): joined = " ".join([str(a) for a in args]) add, output = text_accumulator() - add("Error") + if fail: + add("Error") + else: + add("Warning") if clinic: if filename is None: filename = clinic.filename @@ -102,8 +107,15 @@ add(':\n') add(joined) print(output()) - sys.exit(-1) - + if fail: + sys.exit(-1) + + +def warn(*args, filename=None, line_number=None): + return warn_or_fail(False, *args, filename=filename, line_number=line_number) + +def fail(*args, filename=None, line_number=None): + return warn_or_fail(True, *args, filename=filename, line_number=line_number) def quoted_for_c_string(s): @@ -119,16 +131,14 @@ def is_legal_py_identifier(s): return all(is_legal_c_identifier(field) for field in s.split('.')) -# though it's called c_keywords, really it's a list of parameter names -# that are okay in Python but aren't a good idea in C. so if they're used -# Argument Clinic will add "_value" to the end of the name in C. -# (We added "args", "type", "module", "self", "cls", and "null" -# just to be safe, even though they're not C keywords.) +# identifiers that are okay in Python but aren't a good idea in C. +# so if they're used Argument Clinic will add "_value" to the end +# of the name in C. c_keywords = set(""" -args asm auto break case char cls const continue default do double +asm auto break case char cls const continue default do double else enum extern float for goto if inline int long module null register return self short signed sizeof static struct switch -type typedef typeof union unsigned void volatile while +typedef typeof union unsigned void volatile while """.strip().split()) def ensure_legal_c_identifier(s): @@ -190,6 +200,47 @@ return output()[:-1] +def indent_all_lines(s, prefix): + """ + Returns 's', with 'prefix' prepended to all lines. + + If the last line is empty, prefix is not prepended + to it. (If s is blank, returns s unchanged.) + + (textwrap.indent only adds to non-blank lines.) + """ + split = s.split('\n') + last = split.pop() + final = [] + for line in split: + final.append(prefix) + final.append(line) + final.append('\n') + if last: + final.append(prefix) + final.append(last) + return ''.join(final) + +def suffix_all_lines(s, suffix): + """ + Returns 's', with 'suffix' appended to all lines. + + If the last line is empty, suffix is not appended + to it. (If s is blank, returns s unchanged.) + """ + split = s.split('\n') + last = split.pop() + final = [] + for line in split: + final.append(line) + final.append(suffix) + final.append('\n') + if last: + final.append(last) + final.append(suffix) + return ''.join(final) + + def version_splitter(s): """Splits a version string into a tuple of integers. @@ -281,7 +332,7 @@ checksum_line = "" @abc.abstractmethod - def render(self, block): + def render(self, clinic, signatures): pass def validate(self): @@ -378,14 +429,14 @@ stop_line = "[{dsl_name} start generated code]*/" checksum_line = "/*[{dsl_name} end generated code: checksum={checksum}]*/" - def render(self, signatures): + def render(self, clinic, signatures): function = None for o in signatures: if isinstance(o, Function): if function: fail("You may specify at most one function per block.\nFound a block containing at least two:\n\t" + repr(function) + " and " + repr(o)) function = o - return self.render_function(function) + return self.render_function(clinic, function) def docstring_for_c_string(self, f): text, add, output = _text_accumulator() @@ -399,32 +450,91 @@ add('"') return ''.join(text) - impl_prototype_template = "{c_basename}_impl({impl_parameters})" - - @staticmethod - def template_base(*args): - # HACK suppress methoddef define for METHOD_NEW and METHOD_INIT - base = """ + + def output_templates(self, f): + parameters = list(f.parameters.values()) + converters = [p.converter for p in parameters] + + has_option_groups = parameters and (parameters[0].group or parameters[-1].group) + default_return_converter = (not f.return_converter or + f.return_converter.type == 'PyObject *') + + positional = parameters and (parameters[-1].kind == inspect.Parameter.POSITIONAL_ONLY) + all_boring_objects = False # yes, this will be false if there are 0 parameters, it's fine + first_optional = len(parameters) + for i, p in enumerate(parameters): + c = p.converter + if type(c) != object_converter: + break + if c.format_unit != 'O': + break + if p.default is not unspecified: + first_optional = min(first_optional, i) + else: + all_boring_objects = True + + meth_o = (len(parameters) == 1 and + parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY and + not converters[0].is_optional() and + isinstance(converters[0], object_converter) and + converters[0].format_unit == 'O') + + + # we have to set seven things before we're done: + # + # docstring_prototype + # docstring_definition + # impl_prototype + # methoddef_define + # parser_prototype + # parser_definition + # impl_definition + # + # since impl_prototype is always just impl_definition + ';' + # we just define impl_definition at the top + + docstring_prototype = "PyDoc_VAR({c_basename}__doc__);" + + docstring_definition = """ PyDoc_STRVAR({c_basename}__doc__, {docstring}); -""" - - if args[-1] == None: - return base - - flags = '|'.join(f for f in args if f) - return base + """ -#define {methoddef_name} \\ - {{"{name}", (PyCFunction){c_basename}, {methoddef_flags}, {c_basename}__doc__}}, -""".replace('{methoddef_flags}', flags) - - def meth_noargs_template(self, methoddef_flags=""): - return self.template_base("METH_NOARGS", methoddef_flags) + """ +""".strip() + + impl_definition = """ static {impl_return_type} -{impl_prototype}; - +{c_basename}_impl({impl_parameters})""".strip() + + impl_prototype = parser_prototype = parser_definition = None + + def meth_varargs(): + nonlocal flags + nonlocal parser_prototype + + flags = "METH_VARARGS" + + parser_prototype = """ +static PyObject * +{c_basename}({self_type}{self_name}, PyObject *args) +""".strip() + + if not parameters: + # no parameters, METH_NOARGS + + flags = "METH_NOARGS" + + parser_prototype = """ static PyObject * {c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored)) +""".strip() + + if default_return_converter: + parser_definition = parser_prototype + """ +{{ + return {c_basename}_impl({impl_arguments}); +}} +""".rstrip() + else: + parser_definition = parser_prototype + """ {{ PyObject *return_value = NULL; {declarations} @@ -437,28 +547,43 @@ {cleanup} return return_value; }} - -static {impl_return_type} -{impl_prototype} -""" - - def meth_o_template(self, methoddef_flags=""): - return self.template_base("METH_O", methoddef_flags) + """ +""".rstrip() + + elif meth_o: + if default_return_converter: + # maps perfectly to METH_O, doesn't need a return converter, + # so we skip the parse function and call + # directly into the impl function + + # SLIGHT HACK + # METH_O uses {impl_parameters} for the parser. + + flags = "METH_O" + + impl_definition = """ static PyObject * {c_basename}({impl_parameters}) -""" - - def meth_o_return_converter_template(self, methoddef_flags=""): - return self.template_base("METH_O", methoddef_flags) + """ -static {impl_return_type} -{impl_prototype}; - +""".strip() + + impl_prototype = parser_prototype = parser_definition = '' + + else: + # SLIGHT HACK + # METH_O uses {impl_parameters} for the parser. + + flags = "METH_O" + + parser_prototype = """ static PyObject * {c_basename}({impl_parameters}) +""".strip() + + parser_definition = parser_prototype + """ {{ PyObject *return_value = NULL; {declarations} {initializers} + _return_value = {c_basename}_impl({impl_arguments}); {return_conversion} @@ -466,18 +591,16 @@ {cleanup} return return_value; }} - -static {impl_return_type} -{impl_prototype} -""" - - def option_group_template(self, methoddef_flags=""): - return self.template_base("METH_VARARGS", methoddef_flags) + """ -static {impl_return_type} -{impl_prototype}; - -static PyObject * -{c_basename}({self_type}{self_name}, PyObject *args) +""".rstrip() + + elif has_option_groups: + # positional parameters with option groups + # (we have to generate lots of PyArg_ParseTuple calls + # in a big switch statement) + + meth_varargs() + + parser_definition = parser_prototype + """ {{ PyObject *return_value = NULL; {declarations} @@ -491,18 +614,79 @@ {cleanup} return return_value; }} - -static {impl_return_type} -{impl_prototype} -""" - - def keywords_template(self, methoddef_flags=""): - return self.template_base("METH_VARARGS|METH_KEYWORDS", methoddef_flags) + """ -static {impl_return_type} -{impl_prototype}; - +""".rstrip() + + elif positional and all_boring_objects: + # positional-only, but no option groups, + # and nothing but normal objects: + # PyArg_UnpackTuple! + + meth_varargs() + + # substitute in the min and max by hand right here + assert parameters + min_o = first_optional + max_o = len(parameters) + if isinstance(parameters[0].converter, self_converter): + min_o -= 1 + max_o -= 1 + min_o = str(min_o) + max_o = str(max_o) + + parser_definition = parser_prototype + """ +{{ + PyObject *return_value = NULL; + {declarations} + {initializers} + + if (!PyArg_UnpackTuple(args, "{name}", + {min}, {max}, + {parse_arguments})) + goto exit; + {return_value} = {c_basename}_impl({impl_arguments}); + {return_conversion} + +exit: + {cleanup} + return return_value; +}} +""".rstrip().replace('{min}', min_o).replace('{max}', max_o) + + elif positional: + # positional-only, but no option groups + # we only need one call to PyArg_ParseTuple + + meth_varargs() + + parser_definition = parser_prototype + """ +{{ + PyObject *return_value = NULL; + {declarations} + {initializers} + + if (!PyArg_ParseTuple(args, + "{format_units}:{name}", + {parse_arguments})) + goto exit; + {return_value} = {c_basename}_impl({impl_arguments}); + {return_conversion} + +exit: + {cleanup} + return return_value; +}} +""".rstrip() + + else: + # positional-or-keyword arguments + flags = "METH_VARARGS|METH_KEYWORDS" + + parser_prototype = """ static PyObject * {c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs) +""".strip() + + parser_definition = parser_prototype + """ {{ PyObject *return_value = NULL; static char *_keywords[] = {{{keywords}, NULL}}; @@ -516,42 +700,52 @@ {return_value} = {c_basename}_impl({impl_arguments}); {return_conversion} -{exit_label} +exit: {cleanup} return return_value; }} - -static {impl_return_type} -{impl_prototype} -""" - - def positional_only_template(self, methoddef_flags=""): - return self.template_base("METH_VARARGS", methoddef_flags) + """ -static {impl_return_type} -{impl_prototype}; - -static PyObject * -{c_basename}({self_type}{self_name}, PyObject *args) -{{ - PyObject *return_value = NULL; - {declarations} - {initializers} - - if (!PyArg_ParseTuple(args, - "{format_units}:{name}", - {parse_arguments})) - goto exit; - {return_value} = {c_basename}_impl({impl_arguments}); - {return_conversion} - -{exit_label} - {cleanup} - return return_value; -}} - -static {impl_return_type} -{impl_prototype} -""" +""".rstrip() + + if f.methoddef_flags: + assert flags + flags += '|' + f.methoddef_flags + + methoddef_define = """ +#define {methoddef_name} \\ + {{"{name}", (PyCFunction){c_basename}, {methoddef_flags}, {c_basename}__doc__}}, +""".strip().replace('{methoddef_flags}', flags) + + # parser_prototype mustn't be None, but it could be an empty string. + assert parser_prototype is not None + assert not parser_prototype.endswith(';') + + if parser_prototype: + parser_prototype += ';' + + assert impl_definition + if impl_prototype is None: + impl_prototype = impl_definition + ";" + + # __new__ and __init__ don't need methoddefs + if f.kind in (METHOD_NEW, METHOD_INIT): + methoddef_define = '' + + d = { + "docstring_prototype" : docstring_prototype, + "docstring_definition" : docstring_definition, + "impl_prototype" : impl_prototype, + "methoddef_define" : methoddef_define, + "parser_prototype" : parser_prototype, + "parser_definition" : parser_definition, + "impl_definition" : impl_definition, + } + + d2 = {} + for name, value in d.items(): + if value: + value = '\n' + value + '\n' + d2[name] = value + return d2 @staticmethod def group_to_variable_name(group): @@ -649,7 +843,7 @@ add("}}") template_dict['option_group_parsing'] = output() - def render_function(self, f): + def render_function(self, clinic, f): if not f: return "" @@ -705,6 +899,27 @@ if has_option_groups and (not positional): fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').") + # HACK + # when we're METH_O, but have a custom + # return converter, we use + # "impl_parameters" for the parsing + # function because that works better. + # but that means we must supress actually + # declaring the impl's parameters as variables + # in the parsing function. but since it's + # METH_O, we only have one anyway, so we don't + # have any problem finding it. + default_return_converter = (not f.return_converter or + f.return_converter.type == 'PyObject *') + if (len(parameters) == 1 and + parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY and + not converters[0].is_optional() and + isinstance(converters[0], object_converter) and + converters[0].format_unit == 'O' and + not default_return_converter): + + data.declarations.pop(0) + # now insert our "self" (or whatever) parameters # (we deliberately don't call render on self converters) stock_self = self_converter('self', f) @@ -731,63 +946,41 @@ template_dict['cleanup'] = "".join(data.cleanup) template_dict['return_value'] = data.return_value - template_dict['impl_prototype'] = self.impl_prototype_template.format_map(template_dict) - - default_return_converter = (not f.return_converter or - f.return_converter.type == 'PyObject *') - - if not parameters: - template = self.meth_noargs_template(f.methoddef_flags) - elif (len(parameters) == 1 and - parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY and - not converters[0].is_optional() and - isinstance(converters[0], object_converter) and - converters[0].format_unit == 'O'): - if default_return_converter: - template = self.meth_o_template(f.methoddef_flags) - else: - # HACK - # we're using "impl_parameters" for the - # non-impl function, because that works - # better for METH_O. but that means we - # must supress actually declaring the - # impl's parameters as variables in the - # non-impl. but since it's METH_O, we - # only have one anyway, so - # we don't have any problem finding it. - declarations_copy = list(data.declarations) - before, pyobject, after = declarations_copy[0].partition('PyObject *') - assert not before, "hack failed, see comment" - assert pyobject, "hack failed, see comment" - assert after and after[0].isalpha(), "hack failed, see comment" - del declarations_copy[0] - template_dict['declarations'] = "\n".join(declarations_copy) - template = self.meth_o_return_converter_template(f.methoddef_flags) - elif has_option_groups: + if has_option_groups: self.render_option_group_parsing(f, template_dict) - template = self.option_group_template(f.methoddef_flags) + + templates = self.output_templates(f) + + for name, destination in clinic.field_destinations.items(): + template = templates[name] + if has_option_groups: + template = linear_format(template, + option_group_parsing=template_dict['option_group_parsing']) template = linear_format(template, - option_group_parsing=template_dict['option_group_parsing']) - elif positional: - template = self.positional_only_template(f.methoddef_flags) - else: - template = self.keywords_template(f.methoddef_flags) - - template = linear_format(template, - declarations=template_dict['declarations'], - return_conversion=template_dict['return_conversion'], - initializers=template_dict['initializers'], - cleanup=template_dict['cleanup'], - ) - - # Only generate the "exit:" label - # if we have any gotos - need_exit_label = "goto exit;" in template - template = linear_format(template, - exit_label="exit:" if need_exit_label else '' - ) - - return template.format_map(template_dict) + declarations=template_dict['declarations'], + return_conversion=template_dict['return_conversion'], + initializers=template_dict['initializers'], + cleanup=template_dict['cleanup'], + ) + + # Only generate the "exit:" label + # if we have any gotos + need_exit_label = "goto exit;" in template + template = linear_format(template, + exit_label="exit:" if need_exit_label else '' + ) + + s = template.format_map(template_dict) + + if clinic.line_prefix: + s = indent_all_lines(s, clinic.line_prefix) + if clinic.line_suffix: + s = suffix_all_lines(s, clinic.line_suffix) + + destination.append(s) + + return clinic.get_destination('block').dump() + @contextlib.contextmanager @@ -889,19 +1082,27 @@ self.last_checksum_re = None self.last_dsl_name = None self.dsl_name = None + self.first_block = True def __iter__(self): return self def __next__(self): - if not self.input: - raise StopIteration - - if self.dsl_name: - return_value = self.parse_clinic_block(self.dsl_name) - self.dsl_name = None - return return_value - return self.parse_verbatim_block() + while True: + if not self.input: + raise StopIteration + + if self.dsl_name: + return_value = self.parse_clinic_block(self.dsl_name) + self.dsl_name = None + self.first_block = False + return return_value + block = self.parse_verbatim_block() + if self.first_block and not block.input: + continue + self.first_block = False + return block + def is_start_line(self, line): match = self.start_re.match(line.lstrip()) @@ -980,7 +1181,8 @@ if checksum != computed: fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n" "Suggested fix: remove all generated code including " - "the end marker, or use the '-f' option." + "the end marker,\n" + "or use the '-f' option." .format(checksum, computed)) else: # put back output @@ -1025,15 +1227,62 @@ write(self.language.stop_line.format(dsl_name=dsl_name)) write("\n") - output = block.output + output = ''.join(block.output) if output: + if not output.endswith('\n'): + output += '\n' write(output) - if not output.endswith('\n'): - write('\n') write(self.language.checksum_line.format(dsl_name=dsl_name, checksum=compute_checksum(output))) write("\n") + def write(self, text): + self.f.write(text) + + +class Destination: + def __init__(self, name, type, clinic, *args): + self.name = name + self.type = type + self.clinic = clinic + valid_types = ('buffer', 'file', 'suppress', 'two-pass') + if type not in valid_types: + fail("Invalid destination type " + repr(type) + " for " + name + " , must be " + ', '.join(valid_types)) + extra_arguments = 1 if type == "file" else 0 + if len(args) < extra_arguments: + fail("Not enough arguments for destination " + name + " new " + type) + if len(args) > extra_arguments: + fail("Too many arguments for destination " + name + " new " + type) + if type =='file': + d = {} + d['filename'] = filename = clinic.filename + d['basename'], d['extension'] = os.path.splitext(filename) + self.filename = args[0].format_map(d) + if type == 'two-pass': + self.id = None + + self.text, self.append, self._dump = _text_accumulator() + + def __repr__(self): + if self.type == 'file': + file_repr = " " + repr(self.filename) + else: + file_repr = '' + return "".join(("")) + + def clear(self): + if self.type != 'buffer': + fail("Can't clear destination" + self.name + " , it's not of type buffer") + self.text.clear() + + def dump(self): + if self.type == 'two-pass': + if self.id is None: + self.id = str(uuid.uuid4()) + return self.id + fail("You can only dump a two-pass buffer exactly once!") + return self._dump() + # maps strings to Language objects. # "languages" maps the name of the language ("C", "Python"). @@ -1066,11 +1315,51 @@ return_converters = {} class Clinic: + + presets_text = """ +preset original +everything block +docstring_prototype suppress +parser_prototype suppress + +preset file +everything file +docstring_prototype suppress +parser_prototype suppress +impl_definition block + +preset buffer +everything buffer +docstring_prototype suppress +impl_prototype suppress +parser_prototype suppress +impl_definition block + +preset partial-buffer +everything buffer +docstring_prototype block +impl_prototype suppress +methoddef_define block +parser_prototype block +impl_definition block + +preset two-pass +everything buffer +docstring_prototype two-pass +impl_prototype suppress +methoddef_define two-pass +parser_prototype two-pass +impl_definition block + +""" + def __init__(self, language, printer=None, *, verify=True, filename=None): # maps strings to Parser objects. # (instantiated from the "parsers" global.) self.parsers = {} self.language = language + if printer: + fail("Custom printers are broken right now") self.printer = printer or BlockPrinter(language) self.verify = verify self.filename = filename @@ -1078,9 +1367,66 @@ self.classes = collections.OrderedDict() self.functions = [] + self.line_prefix = self.line_suffix = '' + + self.destinations = {} + self.add_destination("block", "buffer") + self.add_destination("suppress", "suppress") + self.add_destination("buffer", "buffer") + self.add_destination("two-pass", "two-pass") + if filename: + self.add_destination("file", "file", "{basename}.clinic{extension}") + + d = self.destinations.get + self.field_destinations = collections.OrderedDict(( + ('docstring_prototype', d('suppress')), + ('docstring_definition', d('block')), + ('methoddef_define', d('block')), + ('impl_prototype', d('block')), + ('parser_prototype', d('suppress')), + ('parser_definition', d('block')), + ('impl_definition', d('block')), + )) + + self.field_destinations_stack = [] + + self.presets = {} + preset = None + for line in self.presets_text.strip().split('\n'): + line = line.strip() + if not line: + continue + name, value = line.split() + if name == 'preset': + self.presets[value] = preset = collections.OrderedDict() + continue + + destination = self.get_destination(value) + + if name == 'everything': + for name in self.field_destinations: + preset[name] = destination + continue + + assert name in self.field_destinations + preset[name] = destination + global clinic clinic = self + def get_destination(self, name, default=unspecified): + d = self.destinations.get(name) + if not d: + if default is not unspecified: + return default + fail("Destination does not exist: " + repr(name)) + return d + + def add_destination(self, name, type, *args): + if name in self.destinations: + fail("Destination already exists: " + repr(name)) + self.destinations[name] = Destination(name, type, self, *args) + def parse(self, input): printer = self.printer self.block_parser = BlockParser(input, self.language, verify=self.verify) @@ -1097,7 +1443,66 @@ fail('Exception raised during parsing:\n' + traceback.format_exc().rstrip()) printer.print_block(block) - return printer.f.getvalue() + + second_pass_replacements = {} + + for name, destination in self.destinations.items(): + if destination.type == 'suppress': + continue + output = destination._dump() + + if destination.type == 'two-pass': + if destination.id: + second_pass_replacements[destination.id] = output + elif output: + fail("Two-pass buffer " + repr(name) + " not empty at end of file!") + continue + + if output: + + block = Block("", dsl_name="clinic", output=output) + + if destination.type == 'buffer': + block.input = "dump " + name + "\n" + warn("Destination buffer " + repr(name) + " not empty at end of file, emptying.") + printer.write("\n") + printer.print_block(block) + continue + + if destination.type == 'file': + try: + with open(destination.filename, "rt") as f: + parser_2 = BlockParser(f.read(), language=self.language) + blocks = list(parser_2) + if (len(blocks) != 1) or (blocks[0].input != 'preserve\n'): + fail("Modified destination file " + repr(destination.filename) + ", not overwriting!") + except FileNotFoundError: + pass + + block.input = 'preserve\n' + printer_2 = BlockPrinter(self.language) + printer_2.print_block(block) + with open(destination.filename, "wt") as f: + f.write(printer_2.f.getvalue()) + continue + text = printer.f.getvalue() + + if second_pass_replacements: + printer_2 = BlockPrinter(self.language) + parser_2 = BlockParser(text, self.language) + changed = False + for block in parser_2: + if block.dsl_name: + for id, replacement in second_pass_replacements.items(): + if id in block.output: + changed = True + block.output = block.output.replace(id, replacement) + printer_2.print_block(block) + if changed: + text = printer_2.f.getvalue() + + return text + def _module_and_class(self, fields): """ @@ -2195,6 +2600,7 @@ self.kind = CALLABLE self.coexist = False self.parameter_continuation = '' + self.preserve_output = False def directive_version(self, required): global version @@ -2226,6 +2632,77 @@ module.classes[name] = c self.block.signatures.append(c) + def directive_set(self, name, value): + if name not in ("line_prefix", "line_suffix"): + fail("unknown variable", repr(name)) + + value = value.format_map({ + 'block comment start': '/*', + 'block comment end': '*/', + }) + + self.clinic.__dict__[name] = value + + def directive_destination(self, name, command, *args): + if command is 'new': + self.clinic.add_destination(name, command, *args) + return + + if command is 'clear': + self.clinic.get_destination(name).clear() + fail("unknown destination command", repr(command)) + + + def directive_output(self, field, destination=''): + fd = self.clinic.field_destinations + + if field == "preset": + preset = self.clinic.presets.get(destination) + if not preset: + fail("Unknown preset " + repr(destination) + "!") + fd.update(preset) + return + + if field == "push": + self.clinic.field_destinations_stack.append(fd.copy()) + return + + if field == "pop": + if not self.clinic.field_destinations_stack: + fail("Can't 'output pop', stack is empty!") + previous_fd = self.clinic.field_destinations_stack.pop() + fd.update(previous_fd) + return + + # secret command for debugging! + if field == "print": + self.block.output.append(pprint.pformat(fd)) + self.block.output.append('\n') + return + + d = self.clinic.get_destination(destination) + + if field == "everything": + for name in list(fd): + fd[name] = d + return + + if field not in fd: + fail("Invalid field " + repr(field) + ", must be one of:\n " + ", ".join(valid_fields)) + fd[field] = d + + def directive_dump(self, name): + self.block.output.append(self.clinic.get_destination(name).dump()) + + def directive_print(self, *args): + self.block.output.append(' '.join(args)) + self.block.output.append('\n') + + def directive_preserve(self): + if self.preserve_output: + fail("Can't have preserve twice in one block!") + self.preserve_output = True + def at_classmethod(self): if self.kind is not CALLABLE: fail("Can't set @classmethod, function is not a normal callable") @@ -2241,10 +2718,11 @@ fail("Called @coexist twice!") self.coexist = True - def parse(self, block): self.reset() self.block = block + self.saved_output = self.block.output + block.output = [] block_start = self.clinic.block_parser.line_number lines = block.input.split('\n') for line_number, line in enumerate(lines, self.clinic.block_parser.block_start_line_number): @@ -2255,7 +2733,12 @@ self.next(self.state_terminal) self.state(None) - block.output = self.clinic.language.render(block.signatures) + block.output.extend(self.clinic.language.render(clinic, block.signatures)) + + if self.preserve_output: + if block.output: + fail("'preserve' only works for blocks that don't produce any output!") + block.output = self.saved_output @staticmethod def ignore_line(line): @@ -2313,7 +2796,10 @@ directive_name = fields[0] directive = self.directives.get(directive_name, None) if directive: - directive(*fields[1:]) + try: + directive(*fields[1:]) + except TypeError as e: + fail(str(e)) return # are we cloning? @@ -2439,8 +2925,6 @@ # with X spaces such that F < X < P. (As before, F is the indent # of the function declaration.) # - ############## - # # Also, currently Argument Clinic places the following restrictions on groups: # * Each group must contain at least one parameter. # * Each group may contain at most one group, which must be the furthest @@ -2680,6 +3164,9 @@ kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group) + + if parameter_name in self.function.parameters: + fail("You can't have two parameters named " + repr(parameter_name) + "!") self.function.parameters[parameter_name] = p def parse_converter(self, annotation): @@ -3063,20 +3550,6 @@ s = parameter_name parameters.append(s) print(' {}({})'.format(short_name, ', '.join(parameters))) - # add_comma = False - # for parameter_name, parameter in signature.parameters.items(): - # if parameter.kind == inspect.Parameter.KEYWORD_ONLY: - # if add_comma: - # parameters.append(', ') - # else: - # add_comma = True - # s = parameter_name - # if parameter.default != inspect.Parameter.empty: - # s += '=' + repr(parameter.default) - # parameters.append(s) - # parameters.append(')') - - # print(" ", short_name + "".join(parameters)) print() print("All converters also accept (c_default=None, py_default=None, annotation=None).") print("All return converters also accept (py_default=None).") diff --git a/Tools/clinic/clinic_test.py b/Tools/clinic/clinic_test.py --- a/Tools/clinic/clinic_test.py +++ b/Tools/clinic/clinic_test.py @@ -34,6 +34,9 @@ def get(self, name, default): return self.used_converters.setdefault(name, FakeConverterFactory(name)) +clinic.Clinic.presets_text = '' +c = clinic.Clinic(language='C') + class FakeClinic: def __init__(self): self.converters = FakeConvertersDict() @@ -44,6 +47,32 @@ self.modules = collections.OrderedDict() clinic.clinic = self self.name = "FakeClinic" + self.line_prefix = self.line_suffix = '' + self.destinations = {} + self.add_destination("block", "buffer") + self.add_destination("file", "buffer") + self.add_destination("suppress", "suppress") + d = self.destinations.get + self.field_destinations = collections.OrderedDict(( + ('docstring_prototype', d('suppress')), + ('docstring_definition', d('block')), + ('methoddef_define', d('block')), + ('impl_prototype', d('block')), + ('parser_prototype', d('suppress')), + ('parser_definition', d('block')), + ('impl_definition', d('block')), + )) + + def get_destination(self, name): + d = self.destinations.get(name) + if not d: + sys.exit("Destination does not exist: " + repr(name)) + return d + + def add_destination(self, name, type, *args): + if name in self.destinations: + sys.exit("Destination already exists: " + repr(name)) + self.destinations[name] = clinic.Destination(name, type, self, *args) def is_directive(self, name): return name == "module" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 06:49:38 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 18 Jan 2014 06:49:38 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_describe_type_?= =?utf-8?q?of_Popen_streams_=28closes_=2317814=29?= Message-ID: <3f5pBB4b69z7LjW@mail.python.org> http://hg.python.org/cpython/rev/946257d3c648 changeset: 88534:946257d3c648 branch: 3.3 parent: 88531:fc52b657bcd9 user: Benjamin Peterson date: Sat Jan 18 00:45:56 2014 -0500 summary: describe type of Popen streams (closes #17814) Patch more or less by Nikolaus Rath. files: Doc/library/subprocess.rst | 24 ++++++++++++++++-------- 1 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -705,21 +705,29 @@ .. attribute:: Popen.stdin - If the *stdin* argument was :data:`PIPE`, this attribute is a :term:`file - object` that provides input to the child process. Otherwise, it is ``None``. + If the *stdin* argument was :data:`PIPE`, this attribute is a writeable + stream object as returned by :func:`open`. If the *universal_newlines* + argument was ``True``, the stream is a text stream, otherwise it is a byte + stream. If the *stdin* argument was not :data:`PIPE`, this attribute is + ``None``. .. attribute:: Popen.stdout - If the *stdout* argument was :data:`PIPE`, this attribute is a :term:`file - object` that provides output from the child process. Otherwise, it is ``None``. - + If the *stdout* argument was :data:`PIPE`, this attribute is a readable + stream object as returned by :func:`open`. Reading from the stream provides + output from the child process. If the *universal_newlines* argument was + ``True``, the stream is a text stream, otherwise it is a byte stream. If the + *stdout* argument was not :data:`PIPE`, this attribute is ``None``. + .. attribute:: Popen.stderr - If the *stderr* argument was :data:`PIPE`, this attribute is a :term:`file - object` that provides error output from the child process. Otherwise, it is - ``None``. + If the *stderr* argument was :data:`PIPE`, this attribute is a readable + stream object as returned by :func:`open`. Reading from the stream provides + error output from the child process. If the *universal_newlines* argument was + ``True``, the stream is a text stream, otherwise it is a byte stream. If the + *stderr* argument was not :data:`PIPE`, this attribute is ``None``. .. attribute:: Popen.pid -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 06:49:39 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 18 Jan 2014 06:49:39 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4zICgjMTc4MTQp?= Message-ID: <3f5pBC5zhfz7LnD@mail.python.org> http://hg.python.org/cpython/rev/1a7d416c57ff changeset: 88535:1a7d416c57ff parent: 88533:7f6712954d5d parent: 88534:946257d3c648 user: Benjamin Peterson date: Sat Jan 18 00:46:49 2014 -0500 summary: merge 3.3 (#17814) files: Doc/library/subprocess.rst | 24 ++++++++++++++++-------- 1 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -715,21 +715,29 @@ .. attribute:: Popen.stdin - If the *stdin* argument was :data:`PIPE`, this attribute is a :term:`file - object` that provides input to the child process. Otherwise, it is ``None``. + If the *stdin* argument was :data:`PIPE`, this attribute is a writeable + stream object as returned by :func:`open`. If the *universal_newlines* + argument was ``True``, the stream is a text stream, otherwise it is a byte + stream. If the *stdin* argument was not :data:`PIPE`, this attribute is + ``None``. .. attribute:: Popen.stdout - If the *stdout* argument was :data:`PIPE`, this attribute is a :term:`file - object` that provides output from the child process. Otherwise, it is ``None``. - + If the *stdout* argument was :data:`PIPE`, this attribute is a readable + stream object as returned by :func:`open`. Reading from the stream provides + output from the child process. If the *universal_newlines* argument was + ``True``, the stream is a text stream, otherwise it is a byte stream. If the + *stdout* argument was not :data:`PIPE`, this attribute is ``None``. + .. attribute:: Popen.stderr - If the *stderr* argument was :data:`PIPE`, this attribute is a :term:`file - object` that provides error output from the child process. Otherwise, it is - ``None``. + If the *stderr* argument was :data:`PIPE`, this attribute is a readable + stream object as returned by :func:`open`. Reading from the stream provides + error output from the child process. If the *universal_newlines* argument was + ``True``, the stream is a text stream, otherwise it is a byte stream. If the + *stderr* argument was not :data:`PIPE`, this attribute is ``None``. .. attribute:: Popen.pid -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 06:49:41 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 18 Jan 2014 06:49:41 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_link_to_builti?= =?utf-8?q?n_open_not_io=2Eopen?= Message-ID: <3f5pBF0N9sz7Lm0@mail.python.org> http://hg.python.org/cpython/rev/dc044725cd10 changeset: 88536:dc044725cd10 branch: 3.3 parent: 88534:946257d3c648 user: Benjamin Peterson date: Sat Jan 18 00:47:00 2014 -0500 summary: link to builtin open not io.open files: Doc/library/subprocess.rst | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -434,12 +434,12 @@ untrusted input. See the warning under :ref:`frequently-used-arguments` for details. - *bufsize* will be supplied as the corresponding argument to the :meth:`io.open` - function when creating the stdin/stdout/stderr pipe file objects: - :const:`0` means unbuffered (read and write are one system call and can return short), - :const:`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. + *bufsize* will be supplied as the corresponding argument to the :func:`open` + function when creating the stdin/stdout/stderr pipe file objects: :const:`0` + means unbuffered (read and write are one system call and can return short), + :const:`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. .. versionchanged:: 3.3.1 *bufsize* now defaults to -1 to enable buffering by default to match the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 06:49:42 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 18 Jan 2014 06:49:42 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3f5pBG23FYz7Lnb@mail.python.org> http://hg.python.org/cpython/rev/0d3783d50f6a changeset: 88537:0d3783d50f6a parent: 88535:1a7d416c57ff parent: 88536:dc044725cd10 user: Benjamin Peterson date: Sat Jan 18 00:47:06 2014 -0500 summary: merge 3.3 files: Doc/library/subprocess.rst | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -444,12 +444,12 @@ untrusted input. See the warning under :ref:`frequently-used-arguments` for details. - *bufsize* will be supplied as the corresponding argument to the :meth:`io.open` - function when creating the stdin/stdout/stderr pipe file objects: - :const:`0` means unbuffered (read and write are one system call and can return short), - :const:`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. + *bufsize* will be supplied as the corresponding argument to the :func:`open` + function when creating the stdin/stdout/stderr pipe file objects: :const:`0` + means unbuffered (read and write are one system call and can return short), + :const:`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. .. versionchanged:: 3.3.1 *bufsize* now defaults to -1 to enable buffering by default to match the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 06:49:43 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 18 Jan 2014 06:49:43 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_rm_extra_white?= =?utf-8?q?space?= Message-ID: <3f5pBH3rTYz7Lp7@mail.python.org> http://hg.python.org/cpython/rev/eb91a9450eb1 changeset: 88538:eb91a9450eb1 branch: 3.3 parent: 88536:dc044725cd10 user: Benjamin Peterson date: Sat Jan 18 00:49:04 2014 -0500 summary: rm extra whitespace files: Doc/library/subprocess.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -719,7 +719,7 @@ output from the child process. If the *universal_newlines* argument was ``True``, the stream is a text stream, otherwise it is a byte stream. If the *stdout* argument was not :data:`PIPE`, this attribute is ``None``. - + .. attribute:: Popen.stderr -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 06:49:44 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 18 Jan 2014 06:49:44 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3f5pBJ5TKfz7LpN@mail.python.org> http://hg.python.org/cpython/rev/da8e8e28a616 changeset: 88539:da8e8e28a616 parent: 88537:0d3783d50f6a parent: 88538:eb91a9450eb1 user: Benjamin Peterson date: Sat Jan 18 00:49:30 2014 -0500 summary: merge 3.3 files: Doc/library/subprocess.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -729,7 +729,7 @@ output from the child process. If the *universal_newlines* argument was ``True``, the stream is a text stream, otherwise it is a byte stream. If the *stdout* argument was not :data:`PIPE`, this attribute is ``None``. - + .. attribute:: Popen.stderr -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 09:26:47 2014 From: python-checkins at python.org (larry.hastings) Date: Sat, 18 Jan 2014 09:26:47 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320292=3A_Small_bu?= =?utf-8?q?g_fix_for_Argument_Clinic_supporting_format_units?= Message-ID: <3f5sgW5Glgz7LjW@mail.python.org> http://hg.python.org/cpython/rev/949acdd43b45 changeset: 88540:949acdd43b45 user: Larry Hastings date: Sat Jan 18 00:26:16 2014 -0800 summary: Issue #20292: Small bug fix for Argument Clinic supporting format units for strings with explicit encodings. files: Tools/clinic/clinic.py | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -126,6 +126,10 @@ s = s.replace(old, new) return s +def c_repr(s): + return '"' + s + '"' + + is_legal_c_identifier = re.compile('^[A-Za-z_][A-Za-z0-9_]*$').match def is_legal_py_identifier(s): @@ -3129,7 +3133,7 @@ if isinstance(value, (bool, None.__class__)): c_default = "Py_" + py_default elif isinstance(value, str): - c_default = '"' + quoted_for_c_string(value) + '"' + c_default = c_repr(value) else: c_default = py_default -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat Jan 18 09:46:59 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 18 Jan 2014 09:46:59 +0100 Subject: [Python-checkins] Daily reference leaks (7f6712954d5d): sum=8 Message-ID: results for 7f6712954d5d on branch "default" -------------------------------------------- test_asyncio leaked [0, 0, 4] memory blocks, sum=4 test_site leaked [0, 2, 0] references, sum=2 test_site leaked [0, 2, 0] memory blocks, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogIez8zD', '-x'] From python-checkins at python.org Sat Jan 18 10:09:08 2014 From: python-checkins at python.org (larry.hastings) Date: Sat, 18 Jan 2014 10:09:08 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Doc_improvements_for_Clini?= =?utf-8?q?c_howto_=22Goals=22_section=2E?= Message-ID: <3f5tcN62k0z7Ljg@mail.python.org> http://hg.python.org/cpython/rev/32f9e0ae23f7 changeset: 88541:32f9e0ae23f7 user: Larry Hastings date: Sat Jan 18 01:08:50 2014 -0800 summary: Doc improvements for Clinic howto "Goals" section. files: Doc/howto/clinic.rst | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -44,16 +44,16 @@ When you use Argument Clinic, you don't have to repeat yourself. Obviously, no one would want to use Argument Clinic unless -it's solving a their problem without creating problems of +it's solving their problem--and without creating new problems of its own. -So Argument Clinic should generate correct code, and its -code should preferably be slower, and definitely should -not introduce a major speed regression. (Eventually Argument -Clinic should enable a major speedup--we should be able -to rewrite its code generator so it produces tailor-made -parsing code, rather than using the general-purpose functions -from the CPython code base, which would make for the fastest -argument parsing possible.) +So it's paramount that Argument Clinic generate correct code. +It'd be nice if the code was faster, too, but at the very least +it should not introduce a major speed regression. (Eventually Argument +Clinic *should* make a major speedup possible--we could +rewrite its code generator to produce tailor-made argument +parsing code, rather than calling the general-purpose CPython +argument parsing library. That would make for the fastest +argument parsing possible!) Additionally, Argument Clinic must be flexible enough to work with any approach to argument parsing. Python has -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 14:43:41 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 18 Jan 2014 14:43:41 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIwMjQ1?= =?utf-8?q?=3A_The_open_functions_in_the_tarfile_module_now_correctly_hand?= =?utf-8?q?le?= Message-ID: <3f60j92d5HzQQk@mail.python.org> http://hg.python.org/cpython/rev/8edb892f4d69 changeset: 88542:8edb892f4d69 branch: 2.7 parent: 88519:23a760bdd4b1 user: Serhiy Storchaka date: Sat Jan 18 15:35:19 2014 +0200 summary: Issue #20245: The open functions in the tarfile module now correctly handle empty mode. files: Lib/tarfile.py | 15 ++++++++------- Lib/test/test_tarfile.py | 14 ++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1508,10 +1508,11 @@ can be determined, `mode' is overridden by `fileobj's mode. `fileobj' is not closed, when TarFile is closed. """ - if len(mode) > 1 or mode not in "raw": + modes = {"r": "rb", "a": "r+b", "w": "wb"} + if mode not in modes: raise ValueError("mode must be 'r', 'a' or 'w'") self.mode = mode - self._mode = {"r": "rb", "a": "r+b", "w": "wb"}[mode] + self._mode = modes[mode] if not fileobj: if self.mode == "a" and not os.path.exists(name): @@ -1681,7 +1682,7 @@ filemode = filemode or "r" comptype = comptype or "tar" - if filemode not in "rw": + if filemode not in ("r", "w"): raise ValueError("mode must be 'r' or 'w'") t = cls(name, filemode, @@ -1690,7 +1691,7 @@ t._extfileobj = False return t - elif mode in "aw": + elif mode in ("a", "w"): return cls.taropen(name, mode, fileobj, **kwargs) raise ValueError("undiscernible mode") @@ -1699,7 +1700,7 @@ def taropen(cls, name, mode="r", fileobj=None, **kwargs): """Open uncompressed tar archive name for reading or writing. """ - if len(mode) > 1 or mode not in "raw": + if mode not in ("r", "a", "w"): raise ValueError("mode must be 'r', 'a' or 'w'") return cls(name, mode, fileobj, **kwargs) @@ -1708,7 +1709,7 @@ """Open gzip compressed tar archive name for reading or writing. Appending is not allowed. """ - if len(mode) > 1 or mode not in "rw": + if mode not in ("r", "w"): raise ValueError("mode must be 'r' or 'w'") try: @@ -1734,7 +1735,7 @@ """Open bzip2 compressed tar archive name for reading or writing. Appending is not allowed. """ - if len(mode) > 1 or mode not in "rw": + if mode not in ("r", "w"): raise ValueError("mode must be 'r' or 'w'.") try: 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 @@ -213,6 +213,7 @@ class MiscReadTest(CommonReadTest): + taropen = tarfile.TarFile.taropen def test_no_name_argument(self): fobj = open(self.tarname, "rb") @@ -233,6 +234,17 @@ tar = tarfile.open(fileobj=fobj, mode=self.mode) self.assertEqual(tar.name, None) + def test_illegal_mode_arg(self): + with open(tmpname, 'wb'): + pass + self.addCleanup(os.unlink, tmpname) + with self.assertRaisesRegexp(ValueError, 'mode must be '): + tar = self.taropen(tmpname, 'q') + with self.assertRaisesRegexp(ValueError, 'mode must be '): + tar = self.taropen(tmpname, 'rw') + with self.assertRaisesRegexp(ValueError, 'mode must be '): + tar = self.taropen(tmpname, '') + def test_fileobj_with_offset(self): # Skip the first member and store values from the second member # of the testtar. @@ -1543,6 +1555,7 @@ class GzipMiscReadTest(MiscReadTest): tarname = gzipname mode = "r:gz" + taropen = tarfile.TarFile.gzopen class GzipUstarReadTest(UstarReadTest): tarname = gzipname mode = "r:gz" @@ -1558,6 +1571,7 @@ class Bz2MiscReadTest(MiscReadTest): tarname = bz2name mode = "r:bz2" + taropen = tarfile.TarFile.bz2open class Bz2UstarReadTest(UstarReadTest): tarname = bz2name mode = "r:bz2" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,6 +35,9 @@ Library ------- +- Issue #20245: The open functions in the tarfile module now correctly handle + empty mode. + - Issue #20086: Restored the use of locale-independent mapping instead of locale-dependent str.lower() in locale.normalize(). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 14:43:42 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 18 Jan 2014 14:43:42 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMjQ1?= =?utf-8?q?=3A_The_open_functions_in_the_tarfile_module_now_correctly_hand?= =?utf-8?q?le?= Message-ID: <3f60jB5nCJz7Lks@mail.python.org> http://hg.python.org/cpython/rev/8ef1fd952410 changeset: 88543:8ef1fd952410 branch: 3.3 parent: 88538:eb91a9450eb1 user: Serhiy Storchaka date: Sat Jan 18 15:35:37 2014 +0200 summary: Issue #20245: The open functions in the tarfile module now correctly handle empty mode. files: Lib/tarfile.py | 15 ++++++++------- Lib/test/test_tarfile.py | 14 ++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1429,10 +1429,11 @@ can be determined, `mode' is overridden by `fileobj's mode. `fileobj' is not closed, when TarFile is closed. """ - if len(mode) > 1 or mode not in "raw": + modes = {"r": "rb", "a": "r+b", "w": "wb"} + if mode not in modes: raise ValueError("mode must be 'r', 'a' or 'w'") self.mode = mode - self._mode = {"r": "rb", "a": "r+b", "w": "wb"}[mode] + self._mode = modes[mode] if not fileobj: if self.mode == "a" and not os.path.exists(name): @@ -1588,7 +1589,7 @@ filemode = filemode or "r" comptype = comptype or "tar" - if filemode not in "rw": + if filemode not in ("r", "w"): raise ValueError("mode must be 'r' or 'w'") stream = _Stream(name, filemode, comptype, fileobj, bufsize) @@ -1600,7 +1601,7 @@ t._extfileobj = False return t - elif mode in "aw": + elif mode in ("a", "w"): return cls.taropen(name, mode, fileobj, **kwargs) raise ValueError("undiscernible mode") @@ -1609,7 +1610,7 @@ def taropen(cls, name, mode="r", fileobj=None, **kwargs): """Open uncompressed tar archive name for reading or writing. """ - if len(mode) > 1 or mode not in "raw": + if mode not in ("r", "a", "w"): raise ValueError("mode must be 'r', 'a' or 'w'") return cls(name, mode, fileobj, **kwargs) @@ -1618,7 +1619,7 @@ """Open gzip compressed tar archive name for reading or writing. Appending is not allowed. """ - if len(mode) > 1 or mode not in "rw": + if mode not in ("r", "w"): raise ValueError("mode must be 'r' or 'w'") try: @@ -1649,7 +1650,7 @@ """Open bzip2 compressed tar archive name for reading or writing. Appending is not allowed. """ - if len(mode) > 1 or mode not in "rw": + if mode not in ("r", "w"): raise ValueError("mode must be 'r' or 'w'.") try: 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 @@ -41,6 +41,7 @@ tarname = tarname suffix = '' open = io.FileIO + taropen = tarfile.TarFile.taropen @property def mode(self): @@ -51,18 +52,21 @@ tarname = gzipname suffix = 'gz' open = gzip.GzipFile if gzip else None + taropen = tarfile.TarFile.gzopen @support.requires_bz2 class Bz2Test: tarname = bz2name suffix = 'bz2' open = bz2.BZ2File if bz2 else None + taropen = tarfile.TarFile.bz2open @support.requires_lzma class LzmaTest: tarname = xzname suffix = 'xz' open = lzma.LZMAFile if lzma else None + taropen = tarfile.TarFile.xzopen class ReadTest(TarTest): @@ -287,6 +291,16 @@ with tarfile.open(fileobj=fobj, mode=self.mode) as tar: self.assertEqual(tar.name, None) + def test_illegal_mode_arg(self): + with open(tmpname, 'wb'): + pass + with self.assertRaisesRegex(ValueError, 'mode must be '): + tar = self.taropen(tmpname, 'q') + with self.assertRaisesRegex(ValueError, 'mode must be '): + tar = self.taropen(tmpname, 'rw') + with self.assertRaisesRegex(ValueError, 'mode must be '): + tar = self.taropen(tmpname, '') + def test_fileobj_with_offset(self): # Skip the first member and store values from the second member # of the testtar. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,9 @@ Library ------- +- Issue #20245: The open functions in the tarfile module now correctly handle + empty mode. + - Issue #20242: Fixed basicConfig() format strings for the alternative formatting styles. Thanks to kespindler for the bug report and patch. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 14:43:44 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 18 Jan 2014 14:43:44 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320245=3A_The_open_functions_in_the_tarfile_modu?= =?utf-8?q?le_now_correctly_handle?= Message-ID: <3f60jD1wh5z7Lp4@mail.python.org> http://hg.python.org/cpython/rev/7a2db897a1b6 changeset: 88544:7a2db897a1b6 parent: 88541:32f9e0ae23f7 parent: 88543:8ef1fd952410 user: Serhiy Storchaka date: Sat Jan 18 15:37:21 2014 +0200 summary: Issue #20245: The open functions in the tarfile module now correctly handle empty mode. files: Lib/tarfile.py | 15 ++++++++------- Lib/test/test_tarfile.py | 14 ++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1405,10 +1405,11 @@ can be determined, `mode' is overridden by `fileobj's mode. `fileobj' is not closed, when TarFile is closed. """ - if len(mode) > 1 or mode not in "raw": + modes = {"r": "rb", "a": "r+b", "w": "wb"} + if mode not in modes: raise ValueError("mode must be 'r', 'a' or 'w'") self.mode = mode - self._mode = {"r": "rb", "a": "r+b", "w": "wb"}[mode] + self._mode = modes[mode] if not fileobj: if self.mode == "a" and not os.path.exists(name): @@ -1564,7 +1565,7 @@ filemode = filemode or "r" comptype = comptype or "tar" - if filemode not in "rw": + if filemode not in ("r", "w"): raise ValueError("mode must be 'r' or 'w'") stream = _Stream(name, filemode, comptype, fileobj, bufsize) @@ -1576,7 +1577,7 @@ t._extfileobj = False return t - elif mode in "aw": + elif mode in ("a", "w"): return cls.taropen(name, mode, fileobj, **kwargs) raise ValueError("undiscernible mode") @@ -1585,7 +1586,7 @@ def taropen(cls, name, mode="r", fileobj=None, **kwargs): """Open uncompressed tar archive name for reading or writing. """ - if len(mode) > 1 or mode not in "raw": + if mode not in ("r", "a", "w"): raise ValueError("mode must be 'r', 'a' or 'w'") return cls(name, mode, fileobj, **kwargs) @@ -1594,7 +1595,7 @@ """Open gzip compressed tar archive name for reading or writing. Appending is not allowed. """ - if len(mode) > 1 or mode not in "rw": + if mode not in ("r", "w"): raise ValueError("mode must be 'r' or 'w'") try: @@ -1625,7 +1626,7 @@ """Open bzip2 compressed tar archive name for reading or writing. Appending is not allowed. """ - if len(mode) > 1 or mode not in "rw": + if mode not in ("r", "w"): raise ValueError("mode must be 'r' or 'w'.") try: 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 @@ -43,6 +43,7 @@ tarname = tarname suffix = '' open = io.FileIO + taropen = tarfile.TarFile.taropen @property def mode(self): @@ -53,18 +54,21 @@ tarname = gzipname suffix = 'gz' open = gzip.GzipFile if gzip else None + taropen = tarfile.TarFile.gzopen @support.requires_bz2 class Bz2Test: tarname = bz2name suffix = 'bz2' open = bz2.BZ2File if bz2 else None + taropen = tarfile.TarFile.bz2open @support.requires_lzma class LzmaTest: tarname = xzname suffix = 'xz' open = lzma.LZMAFile if lzma else None + taropen = tarfile.TarFile.xzopen class ReadTest(TarTest): @@ -289,6 +293,16 @@ with tarfile.open(fileobj=fobj, mode=self.mode) as tar: self.assertEqual(tar.name, None) + def test_illegal_mode_arg(self): + with open(tmpname, 'wb'): + pass + with self.assertRaisesRegex(ValueError, 'mode must be '): + tar = self.taropen(tmpname, 'q') + with self.assertRaisesRegex(ValueError, 'mode must be '): + tar = self.taropen(tmpname, 'rw') + with self.assertRaisesRegex(ValueError, 'mode must be '): + tar = self.taropen(tmpname, '') + def test_fileobj_with_offset(self): # Skip the first member and store values from the second member # of the testtar. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,9 @@ Library ------- +- Issue #20245: The open functions in the tarfile module now correctly handle + empty mode. + - Issue #20242: Fixed basicConfig() format strings for the alternative formatting styles. Thanks to kespindler for the bug report and patch. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 14:56:28 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 18 Jan 2014 14:56:28 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMjM4?= =?utf-8?q?=3A_TarFile_opened_with_external_fileobj_and_=22w=3Agz=22_mode_?= =?utf-8?q?didn=27t?= Message-ID: <3f60zw0Ybtz7LjM@mail.python.org> http://hg.python.org/cpython/rev/5c69332dc3b0 changeset: 88545:5c69332dc3b0 branch: 3.3 parent: 88543:8ef1fd952410 user: Serhiy Storchaka date: Sat Jan 18 15:53:05 2014 +0200 summary: Issue #20238: TarFile opened with external fileobj and "w:gz" mode didn't write complete output on close. files: Lib/tarfile.py | 2 +- Lib/test/test_tarfile.py | 6 ++++++ Misc/NEWS | 3 +++ 3 files changed, 10 insertions(+), 1 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1642,7 +1642,7 @@ if not extfileobj and fileobj is not None: fileobj.close() raise - t._extfileobj = extfileobj + t._extfileobj = False return t @classmethod 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 @@ -855,6 +855,12 @@ tar.addfile(tarfile.TarInfo("foo")) tar.close() self.assertFalse(fobj.closed, "external fileobjs must never closed") + # Issue #20238: Incomplete gzip output with mode="w:gz" + data = fobj.getvalue() + del tar + support.gc_collect() + self.assertFalse(fobj.closed) + self.assertEqual(data, fobj.getvalue()) class WriteTest(WriteTestBase, unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,9 @@ Library ------- +- Issue #20238: TarFile opened with external fileobj and "w:gz" mode didn't + write complete output on close. + - Issue #20245: The open functions in the tarfile module now correctly handle empty mode. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 14:56:29 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 18 Jan 2014 14:56:29 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320238=3A_TarFile_opened_with_external_fileobj_a?= =?utf-8?b?bmQgInc6Z3oiIG1vZGUgZGlkbid0?= Message-ID: <3f60zx2Fzcz7LkG@mail.python.org> http://hg.python.org/cpython/rev/e154b93f3857 changeset: 88546:e154b93f3857 parent: 88544:7a2db897a1b6 parent: 88545:5c69332dc3b0 user: Serhiy Storchaka date: Sat Jan 18 15:53:39 2014 +0200 summary: Issue #20238: TarFile opened with external fileobj and "w:gz" mode didn't write complete output on close. files: Lib/tarfile.py | 2 +- Lib/test/test_tarfile.py | 6 ++++++ Misc/NEWS | 3 +++ 3 files changed, 10 insertions(+), 1 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1618,7 +1618,7 @@ if not extfileobj and fileobj is not None: fileobj.close() raise - t._extfileobj = extfileobj + t._extfileobj = False return t @classmethod 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 @@ -857,6 +857,12 @@ tar.addfile(tarfile.TarInfo("foo")) tar.close() self.assertFalse(fobj.closed, "external fileobjs must never closed") + # Issue #20238: Incomplete gzip output with mode="w:gz" + data = fobj.getvalue() + del tar + support.gc_collect() + self.assertFalse(fobj.closed) + self.assertEqual(data, fobj.getvalue()) class WriteTest(WriteTestBase, unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,9 @@ Library ------- +- Issue #20238: TarFile opened with external fileobj and "w:gz" mode didn't + write complete output on close. + - Issue #20245: The open functions in the tarfile module now correctly handle empty mode. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 14:56:30 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 18 Jan 2014 14:56:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Backported_tes?= =?utf-8?q?t_for_issue_=2320238=2E?= Message-ID: <3f60zy3YvWz7Lpg@mail.python.org> http://hg.python.org/cpython/rev/f7381f1bf1ec changeset: 88547:f7381f1bf1ec branch: 2.7 parent: 88542:8edb892f4d69 user: Serhiy Storchaka date: Sat Jan 18 15:54:32 2014 +0200 summary: Backported test for issue #20238. files: Lib/test/test_tarfile.py | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -657,6 +657,12 @@ tar.addfile(tarfile.TarInfo("foo")) tar.close() self.assertTrue(fobj.closed is False, "external fileobjs must never closed") + # Issue #20238: Incomplete gzip output with mode="w:gz" + data = fobj.getvalue() + del tar + test_support.gc_collect() + self.assertFalse(fobj.closed) + self.assertEqual(data, fobj.getvalue()) class WriteTest(WriteTestBase): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 15:31:43 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 18 Jan 2014 15:31:43 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIwMjQz?= =?utf-8?q?=3A_TarFile_no_longer_raise_ReadError_when_opened_in_write_mode?= =?utf-8?q?=2E?= Message-ID: <3f61mb2TTqz7Ljg@mail.python.org> http://hg.python.org/cpython/rev/61b6accbca9f changeset: 88548:61b6accbca9f branch: 2.7 user: Serhiy Storchaka date: Sat Jan 18 16:14:00 2014 +0200 summary: Issue #20243: TarFile no longer raise ReadError when opened in write mode. files: Lib/tarfile.py | 8 ++++++-- Lib/test/test_tarfile.py | 16 ++++++++++++++++ Misc/NEWS | 2 ++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1726,7 +1726,9 @@ gzip.GzipFile(name, mode, compresslevel, fileobj), **kwargs) except IOError: - raise ReadError("not a gzip file") + if mode == 'r': + raise ReadError("not a gzip file") + raise t._extfileobj = False return t @@ -1751,7 +1753,9 @@ try: t = cls.taropen(name, mode, fileobj, **kwargs) except (IOError, EOFError): - raise ReadError("not a bzip2 file") + if mode == 'r': + raise ReadError("not a bzip2 file") + raise t._extfileobj = False return t 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 @@ -979,6 +979,22 @@ os.unlink(temparchive) shutil.rmtree(tempdir) + def test_open_nonwritable_fileobj(self): + for exctype in IOError, EOFError, RuntimeError: + class BadFile(StringIO.StringIO): + first = True + def write(self, data): + if self.first: + self.first = False + raise exctype + + f = BadFile() + with self.assertRaises(exctype): + tar = tarfile.open(tmpname, self.mode, fileobj=f, + format=tarfile.PAX_FORMAT, + pax_headers={'non': 'empty'}) + self.assertFalse(f.closed) + class StreamWriteTest(WriteTestBase): mode = "w|" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,6 +35,8 @@ Library ------- +- Issue #20243: TarFile no longer raise ReadError when opened in write mode. + - Issue #20245: The open functions in the tarfile module now correctly handle empty mode. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 15:31:44 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 18 Jan 2014 15:31:44 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMjQz?= =?utf-8?q?=3A_TarFile_no_longer_raise_ReadError_when_opened_in_write_mode?= =?utf-8?q?=2E?= Message-ID: <3f61mc4SCKz7LkL@mail.python.org> http://hg.python.org/cpython/rev/2f3b47b63f91 changeset: 88549:2f3b47b63f91 branch: 3.3 parent: 88545:5c69332dc3b0 user: Serhiy Storchaka date: Sat Jan 18 16:14:10 2014 +0200 summary: Issue #20243: TarFile no longer raise ReadError when opened in write mode. files: Lib/tarfile.py | 29 +++++++++++++++++---------- Lib/test/test_tarfile.py | 16 +++++++++++++++ Misc/NEWS | 2 + 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1628,19 +1628,22 @@ except (ImportError, AttributeError): raise CompressionError("gzip module is not available") - extfileobj = fileobj is not None try: fileobj = gzip.GzipFile(name, mode + "b", compresslevel, fileobj) + except OSError: + if fileobj is not None and mode == 'r': + raise ReadError("not a gzip file") + raise + + try: t = cls.taropen(name, mode, fileobj, **kwargs) - except IOError: - if not extfileobj and fileobj is not None: - fileobj.close() - if fileobj is None: - raise - raise ReadError("not a gzip file") + except OSError: + fileobj.close() + if mode == 'r': + raise ReadError("not a gzip file") + raise except: - if not extfileobj and fileobj is not None: - fileobj.close() + fileobj.close() raise t._extfileobj = False return t @@ -1665,7 +1668,9 @@ t = cls.taropen(name, mode, fileobj, **kwargs) except (IOError, EOFError): fileobj.close() - raise ReadError("not a bzip2 file") + if mode == 'r': + raise ReadError("not a bzip2 file") + raise t._extfileobj = False return t @@ -1688,7 +1693,9 @@ t = cls.taropen(name, mode, fileobj, **kwargs) except (lzma.LZMAError, EOFError): fileobj.close() - raise ReadError("not an lzma file") + if mode == 'r': + raise ReadError("not an lzma file") + raise t._extfileobj = False return t 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 @@ -1155,6 +1155,22 @@ finally: os.chdir(cwd) + def test_open_nonwritable_fileobj(self): + for exctype in OSError, EOFError, RuntimeError: + class BadFile(io.BytesIO): + first = True + def write(self, data): + if self.first: + self.first = False + raise exctype + + f = BadFile() + with self.assertRaises(exctype): + tar = tarfile.open(tmpname, self.mode, fileobj=f, + format=tarfile.PAX_FORMAT, + pax_headers={'non': 'empty'}) + self.assertFalse(f.closed) + class GzipWriteTest(GzipTest, WriteTest): pass diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,8 @@ Library ------- +- Issue #20243: TarFile no longer raise ReadError when opened in write mode. + - Issue #20238: TarFile opened with external fileobj and "w:gz" mode didn't write complete output on close. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 15:31:45 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 18 Jan 2014 15:31:45 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320243=3A_TarFile_no_longer_raise_ReadError_when?= =?utf-8?q?_opened_in_write_mode=2E?= Message-ID: <3f61md6Rlrz7LkG@mail.python.org> http://hg.python.org/cpython/rev/40a5c7547c3d changeset: 88550:40a5c7547c3d parent: 88546:e154b93f3857 parent: 88549:2f3b47b63f91 user: Serhiy Storchaka date: Sat Jan 18 16:14:49 2014 +0200 summary: Issue #20243: TarFile no longer raise ReadError when opened in write mode. files: Lib/tarfile.py | 27 +++++++++++++++++---------- Lib/test/test_tarfile.py | 16 ++++++++++++++++ Misc/NEWS | 2 ++ 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1604,19 +1604,22 @@ except (ImportError, AttributeError): raise CompressionError("gzip module is not available") - extfileobj = fileobj is not None try: fileobj = gzip.GzipFile(name, mode + "b", compresslevel, fileobj) + except OSError: + if fileobj is not None and mode == 'r': + raise ReadError("not a gzip file") + raise + + try: t = cls.taropen(name, mode, fileobj, **kwargs) except OSError: - if not extfileobj and fileobj is not None: - fileobj.close() - if fileobj is None: - raise - raise ReadError("not a gzip file") + fileobj.close() + if mode == 'r': + raise ReadError("not a gzip file") + raise except: - if not extfileobj and fileobj is not None: - fileobj.close() + fileobj.close() raise t._extfileobj = False return t @@ -1641,7 +1644,9 @@ t = cls.taropen(name, mode, fileobj, **kwargs) except (OSError, EOFError): fileobj.close() - raise ReadError("not a bzip2 file") + if mode == 'r': + raise ReadError("not a bzip2 file") + raise t._extfileobj = False return t @@ -1664,7 +1669,9 @@ t = cls.taropen(name, mode, fileobj, **kwargs) except (lzma.LZMAError, EOFError): fileobj.close() - raise ReadError("not an lzma file") + if mode == 'r': + raise ReadError("not an lzma file") + raise t._extfileobj = False return t 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 @@ -1157,6 +1157,22 @@ finally: os.chdir(cwd) + def test_open_nonwritable_fileobj(self): + for exctype in OSError, EOFError, RuntimeError: + class BadFile(io.BytesIO): + first = True + def write(self, data): + if self.first: + self.first = False + raise exctype + + f = BadFile() + with self.assertRaises(exctype): + tar = tarfile.open(tmpname, self.mode, fileobj=f, + format=tarfile.PAX_FORMAT, + pax_headers={'non': 'empty'}) + self.assertFalse(f.closed) + class GzipWriteTest(GzipTest, WriteTest): pass diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,8 @@ Library ------- +- Issue #20243: TarFile no longer raise ReadError when opened in write mode. + - Issue #20238: TarFile opened with external fileobj and "w:gz" mode didn't write complete output on close. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 15:31:47 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 18 Jan 2014 15:31:47 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMjQ0?= =?utf-8?q?=3A_Fixed_possible_file_leaks_when_unexpected_error_raised_in?= Message-ID: <3f61mg18XXz7Lpg@mail.python.org> http://hg.python.org/cpython/rev/05d186a1a367 changeset: 88551:05d186a1a367 branch: 3.3 parent: 88549:2f3b47b63f91 user: Serhiy Storchaka date: Sat Jan 18 16:28:08 2014 +0200 summary: Issue #20244: Fixed possible file leaks when unexpected error raised in tarfile open functions. files: Lib/tarfile.py | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1671,6 +1671,9 @@ if mode == 'r': raise ReadError("not a bzip2 file") raise + except: + fileobj.close() + raise t._extfileobj = False return t @@ -1696,6 +1699,9 @@ if mode == 'r': raise ReadError("not an lzma file") raise + except: + fileobj.close() + raise t._extfileobj = False return t -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 15:31:48 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 18 Jan 2014 15:31:48 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320244=3A_Fixed_possible_file_leaks_when_unexpec?= =?utf-8?q?ted_error_raised_in?= Message-ID: <3f61mh2xCRz7Lph@mail.python.org> http://hg.python.org/cpython/rev/0386cde12657 changeset: 88552:0386cde12657 parent: 88550:40a5c7547c3d parent: 88551:05d186a1a367 user: Serhiy Storchaka date: Sat Jan 18 16:28:37 2014 +0200 summary: Issue #20244: Fixed possible file leaks when unexpected error raised in tarfile open functions. files: Lib/tarfile.py | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1647,6 +1647,9 @@ if mode == 'r': raise ReadError("not a bzip2 file") raise + except: + fileobj.close() + raise t._extfileobj = False return t @@ -1672,6 +1675,9 @@ if mode == 'r': raise ReadError("not an lzma file") raise + except: + fileobj.close() + raise t._extfileobj = False return t -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 17:32:10 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 18 Jan 2014 17:32:10 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIwMjcw?= =?utf-8?q?=3A_urllib_and_urlparse_now_support_empty_ports=2E?= Message-ID: <3f64RZ6Vchz7Ljn@mail.python.org> http://hg.python.org/cpython/rev/a4a51a0d4575 changeset: 88553:a4a51a0d4575 branch: 2.7 parent: 88548:61b6accbca9f user: Serhiy Storchaka date: Sat Jan 18 18:30:09 2014 +0200 summary: Issue #20270: urllib and urlparse now support empty ports. files: Lib/test/test_urllib.py | 20 ++++++++++++++++++++ Lib/test/test_urlparse.py | 10 ++++++++++ Lib/urllib.py | 19 +++++++++++-------- Lib/urlparse.py | 9 +++++---- Misc/NEWS | 2 ++ 5 files changed, 48 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -789,6 +789,26 @@ self.assertEqual(('user 2', 'ab'),urllib.splitpasswd('user 2:ab')) self.assertEqual(('user+1', 'a+b'),urllib.splitpasswd('user+1:a+b')) + def test_splitport(self): + splitport = urllib.splitport + self.assertEqual(splitport('parrot:88'), ('parrot', '88')) + self.assertEqual(splitport('parrot'), ('parrot', None)) + self.assertEqual(splitport('parrot:'), ('parrot', None)) + self.assertEqual(splitport('127.0.0.1'), ('127.0.0.1', None)) + self.assertEqual(splitport('parrot:cheese'), ('parrot:cheese', None)) + + def test_splitnport(self): + splitnport = urllib.splitnport + self.assertEqual(splitnport('parrot:88'), ('parrot', 88)) + self.assertEqual(splitnport('parrot'), ('parrot', -1)) + self.assertEqual(splitnport('parrot', 55), ('parrot', 55)) + self.assertEqual(splitnport('parrot:'), ('parrot', -1)) + self.assertEqual(splitnport('parrot:', 55), ('parrot', 55)) + self.assertEqual(splitnport('127.0.0.1'), ('127.0.0.1', -1)) + self.assertEqual(splitnport('127.0.0.1', 55), ('127.0.0.1', 55)) + self.assertEqual(splitnport('parrot:cheese'), ('parrot', None)) + self.assertEqual(splitnport('parrot:cheese', 55), ('parrot', None)) + class URLopener_Tests(unittest.TestCase): """Testcase to test the open method of URLopener class.""" diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -362,6 +362,16 @@ ('http://[::12.34.56.78]/foo/', '::12.34.56.78', None), ('http://[::ffff:12.34.56.78]/foo/', '::ffff:12.34.56.78', None), + ('http://Test.python.org:/foo/', 'test.python.org', None), + ('http://12.34.56.78:/foo/', '12.34.56.78', None), + ('http://[::1]:/foo/', '::1', None), + ('http://[dead:beef::1]:/foo/', 'dead:beef::1', None), + ('http://[dead:beef::]:/foo/', 'dead:beef::', None), + ('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]:/foo/', + 'dead:beef:cafe:5417:affe:8fa3:deaf:feed', None), + ('http://[::12.34.56.78]:/foo/', '::12.34.56.78', None), + ('http://[::ffff:12.34.56.78]:/foo/', + '::ffff:12.34.56.78', None), ]: urlparsed = urlparse.urlparse(url) self.assertEqual((urlparsed.hostname, urlparsed.port) , (hostname, port)) diff --git a/Lib/urllib.py b/Lib/urllib.py --- a/Lib/urllib.py +++ b/Lib/urllib.py @@ -1125,10 +1125,13 @@ global _portprog if _portprog is None: import re - _portprog = re.compile('^(.*):([0-9]+)$') + _portprog = re.compile('^(.*):([0-9]*)$') match = _portprog.match(host) - if match: return match.group(1, 2) + if match: + host, port = match.groups() + if port: + return host, port return host, None _nportprog = None @@ -1145,12 +1148,12 @@ match = _nportprog.match(host) if match: host, port = match.group(1, 2) - try: - if not port: raise ValueError, "no digits" - nport = int(port) - except ValueError: - nport = None - return host, nport + if port: + try: + nport = int(port) + except ValueError: + nport = None + return host, nport return host, defport _queryprog = None diff --git a/Lib/urlparse.py b/Lib/urlparse.py --- a/Lib/urlparse.py +++ b/Lib/urlparse.py @@ -109,10 +109,11 @@ netloc = self.netloc.split('@')[-1].split(']')[-1] if ':' in netloc: port = netloc.split(':')[1] - port = int(port, 10) - # verify legal port - if (0 <= port <= 65535): - return port + if port: + port = int(port, 10) + # verify legal port + if (0 <= port <= 65535): + return port return None from collections import namedtuple diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,6 +35,8 @@ Library ------- +- Issue #20270: urllib and urlparse now support empty ports. + - Issue #20243: TarFile no longer raise ReadError when opened in write mode. - Issue #20245: The open functions in the tarfile module now correctly handle -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 17:32:12 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 18 Jan 2014 17:32:12 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMjcw?= =?utf-8?q?=3A_urllib=2Eurlparse_now_supports_empty_ports=2E?= Message-ID: <3f64Rc23FGz7Lk1@mail.python.org> http://hg.python.org/cpython/rev/52edc7087c81 changeset: 88554:52edc7087c81 branch: 3.3 parent: 88551:05d186a1a367 user: Serhiy Storchaka date: Sat Jan 18 18:30:33 2014 +0200 summary: Issue #20270: urllib.urlparse now supports empty ports. files: Lib/test/test_urlparse.py | 38 +++++++++++++++++++------- Lib/urllib/parse.py | 31 ++++++++++++--------- Misc/NEWS | 2 + 3 files changed, 47 insertions(+), 24 deletions(-) diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -394,6 +394,16 @@ ('http://[::12.34.56.78]/foo/', '::12.34.56.78', None), ('http://[::ffff:12.34.56.78]/foo/', '::ffff:12.34.56.78', None), + ('http://Test.python.org:/foo/', 'test.python.org', None), + ('http://12.34.56.78:/foo/', '12.34.56.78', None), + ('http://[::1]:/foo/', '::1', None), + ('http://[dead:beef::1]:/foo/', 'dead:beef::1', None), + ('http://[dead:beef::]:/foo/', 'dead:beef::', None), + ('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]:/foo/', + 'dead:beef:cafe:5417:affe:8fa3:deaf:feed', None), + ('http://[::12.34.56.78]:/foo/', '::12.34.56.78', None), + ('http://[::ffff:12.34.56.78]:/foo/', + '::ffff:12.34.56.78', None), ] def _encode(t): return t[0].encode('ascii'), t[1].encode('ascii'), t[2] @@ -739,17 +749,25 @@ errors="ignore") self.assertEqual(result, [('key', '\u0141-')]) + def test_splitport(self): + splitport = urllib.parse.splitport + self.assertEqual(splitport('parrot:88'), ('parrot', '88')) + self.assertEqual(splitport('parrot'), ('parrot', None)) + self.assertEqual(splitport('parrot:'), ('parrot', None)) + self.assertEqual(splitport('127.0.0.1'), ('127.0.0.1', None)) + self.assertEqual(splitport('parrot:cheese'), ('parrot:cheese', None)) + def test_splitnport(self): - # Normal cases are exercised by other tests; ensure that we also - # catch cases with no port specified. (testcase ensuring coverage) - result = urllib.parse.splitnport('parrot:88') - self.assertEqual(result, ('parrot', 88)) - result = urllib.parse.splitnport('parrot') - self.assertEqual(result, ('parrot', -1)) - result = urllib.parse.splitnport('parrot', 55) - self.assertEqual(result, ('parrot', 55)) - result = urllib.parse.splitnport('parrot:') - self.assertEqual(result, ('parrot', None)) + splitnport = urllib.parse.splitnport + self.assertEqual(splitnport('parrot:88'), ('parrot', 88)) + self.assertEqual(splitnport('parrot'), ('parrot', -1)) + self.assertEqual(splitnport('parrot', 55), ('parrot', 55)) + self.assertEqual(splitnport('parrot:'), ('parrot', -1)) + self.assertEqual(splitnport('parrot:', 55), ('parrot', 55)) + self.assertEqual(splitnport('127.0.0.1'), ('127.0.0.1', -1)) + self.assertEqual(splitnport('127.0.0.1', 55), ('127.0.0.1', 55)) + self.assertEqual(splitnport('parrot:cheese'), ('parrot', None)) + self.assertEqual(splitnport('parrot:cheese', 55), ('parrot', None)) def test_splitquery(self): # Normal cases are exercised by other tests; ensure that we also diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -182,10 +182,10 @@ _, have_open_br, bracketed = hostinfo.partition('[') if have_open_br: hostname, _, port = bracketed.partition(']') - _, have_port, port = port.partition(':') + _, _, port = port.partition(':') else: - hostname, have_port, port = hostinfo.partition(':') - if not have_port: + hostname, _, port = hostinfo.partition(':') + if not port: port = None return hostname, port @@ -212,10 +212,10 @@ _, have_open_br, bracketed = hostinfo.partition(b'[') if have_open_br: hostname, _, port = bracketed.partition(b']') - _, have_port, port = port.partition(b':') + _, _, port = port.partition(b':') else: - hostname, have_port, port = hostinfo.partition(b':') - if not have_port: + hostname, _, port = hostinfo.partition(b':') + if not port: port = None return hostname, port @@ -903,10 +903,13 @@ global _portprog if _portprog is None: import re - _portprog = re.compile('^(.*):([0-9]+)$') + _portprog = re.compile('^(.*):([0-9]*)$') match = _portprog.match(host) - if match: return match.group(1, 2) + if match: + host, port = match.groups() + if port: + return host, port return host, None _nportprog = None @@ -923,12 +926,12 @@ match = _nportprog.match(host) if match: host, port = match.group(1, 2) - try: - if not port: raise ValueError("no digits") - nport = int(port) - except ValueError: - nport = None - return host, nport + if port: + try: + nport = int(port) + except ValueError: + nport = None + return host, nport return host, defport _queryprog = None diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,8 @@ Library ------- +- Issue #20270: urllib.urlparse now supports empty ports. + - Issue #20243: TarFile no longer raise ReadError when opened in write mode. - Issue #20238: TarFile opened with external fileobj and "w:gz" mode didn't -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 17:32:13 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 18 Jan 2014 17:32:13 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320270=3A_urllib=2Eurlparse_now_supports_empty_p?= =?utf-8?q?orts=2E?= Message-ID: <3f64Rd520mz7LkB@mail.python.org> http://hg.python.org/cpython/rev/1469c4fde8cd changeset: 88555:1469c4fde8cd parent: 88552:0386cde12657 parent: 88554:52edc7087c81 user: Serhiy Storchaka date: Sat Jan 18 18:31:41 2014 +0200 summary: Issue #20270: urllib.urlparse now supports empty ports. files: Lib/test/test_urlparse.py | 38 +++++++++++++++++++------- Lib/urllib/parse.py | 31 ++++++++++++--------- Misc/NEWS | 2 + 3 files changed, 47 insertions(+), 24 deletions(-) diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -394,6 +394,16 @@ ('http://[::12.34.56.78]/foo/', '::12.34.56.78', None), ('http://[::ffff:12.34.56.78]/foo/', '::ffff:12.34.56.78', None), + ('http://Test.python.org:/foo/', 'test.python.org', None), + ('http://12.34.56.78:/foo/', '12.34.56.78', None), + ('http://[::1]:/foo/', '::1', None), + ('http://[dead:beef::1]:/foo/', 'dead:beef::1', None), + ('http://[dead:beef::]:/foo/', 'dead:beef::', None), + ('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]:/foo/', + 'dead:beef:cafe:5417:affe:8fa3:deaf:feed', None), + ('http://[::12.34.56.78]:/foo/', '::12.34.56.78', None), + ('http://[::ffff:12.34.56.78]:/foo/', + '::ffff:12.34.56.78', None), ] def _encode(t): return t[0].encode('ascii'), t[1].encode('ascii'), t[2] @@ -739,17 +749,25 @@ errors="ignore") self.assertEqual(result, [('key', '\u0141-')]) + def test_splitport(self): + splitport = urllib.parse.splitport + self.assertEqual(splitport('parrot:88'), ('parrot', '88')) + self.assertEqual(splitport('parrot'), ('parrot', None)) + self.assertEqual(splitport('parrot:'), ('parrot', None)) + self.assertEqual(splitport('127.0.0.1'), ('127.0.0.1', None)) + self.assertEqual(splitport('parrot:cheese'), ('parrot:cheese', None)) + def test_splitnport(self): - # Normal cases are exercised by other tests; ensure that we also - # catch cases with no port specified. (testcase ensuring coverage) - result = urllib.parse.splitnport('parrot:88') - self.assertEqual(result, ('parrot', 88)) - result = urllib.parse.splitnport('parrot') - self.assertEqual(result, ('parrot', -1)) - result = urllib.parse.splitnport('parrot', 55) - self.assertEqual(result, ('parrot', 55)) - result = urllib.parse.splitnport('parrot:') - self.assertEqual(result, ('parrot', None)) + splitnport = urllib.parse.splitnport + self.assertEqual(splitnport('parrot:88'), ('parrot', 88)) + self.assertEqual(splitnport('parrot'), ('parrot', -1)) + self.assertEqual(splitnport('parrot', 55), ('parrot', 55)) + self.assertEqual(splitnport('parrot:'), ('parrot', -1)) + self.assertEqual(splitnport('parrot:', 55), ('parrot', 55)) + self.assertEqual(splitnport('127.0.0.1'), ('127.0.0.1', -1)) + self.assertEqual(splitnport('127.0.0.1', 55), ('127.0.0.1', 55)) + self.assertEqual(splitnport('parrot:cheese'), ('parrot', None)) + self.assertEqual(splitnport('parrot:cheese', 55), ('parrot', None)) def test_splitquery(self): # Normal cases are exercised by other tests; ensure that we also diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -182,10 +182,10 @@ _, have_open_br, bracketed = hostinfo.partition('[') if have_open_br: hostname, _, port = bracketed.partition(']') - _, have_port, port = port.partition(':') + _, _, port = port.partition(':') else: - hostname, have_port, port = hostinfo.partition(':') - if not have_port: + hostname, _, port = hostinfo.partition(':') + if not port: port = None return hostname, port @@ -212,10 +212,10 @@ _, have_open_br, bracketed = hostinfo.partition(b'[') if have_open_br: hostname, _, port = bracketed.partition(b']') - _, have_port, port = port.partition(b':') + _, _, port = port.partition(b':') else: - hostname, have_port, port = hostinfo.partition(b':') - if not have_port: + hostname, _, port = hostinfo.partition(b':') + if not port: port = None return hostname, port @@ -898,10 +898,13 @@ """splitport('host:port') --> 'host', 'port'.""" global _portprog if _portprog is None: - _portprog = re.compile('^(.*):([0-9]+)$') + _portprog = re.compile('^(.*):([0-9]*)$') match = _portprog.match(host) - if match: return match.group(1, 2) + if match: + host, port = match.groups() + if port: + return host, port return host, None _nportprog = None @@ -917,12 +920,12 @@ match = _nportprog.match(host) if match: host, port = match.group(1, 2) - try: - if not port: raise ValueError("no digits") - nport = int(port) - except ValueError: - nport = None - return host, nport + if port: + try: + nport = int(port) + except ValueError: + nport = None + return host, nport return host, defport _queryprog = None diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,8 @@ Library ------- +- Issue #20270: urllib.urlparse now supports empty ports. + - Issue #20243: TarFile no longer raise ReadError when opened in write mode. - Issue #20238: TarFile opened with external fileobj and "w:gz" mode didn't -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 21:02:57 2014 From: python-checkins at python.org (r.david.murray) Date: Sat, 18 Jan 2014 21:02:57 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE5ODU1OiByZXN0?= =?utf-8?q?ore_use_of_LC=5FALL=2C_not_LC=5FMESSAGES?= Message-ID: <3f696n70Zgz7LjW@mail.python.org> http://hg.python.org/cpython/rev/9fe32328a573 changeset: 88556:9fe32328a573 branch: 2.7 parent: 88553:a4a51a0d4575 user: R David Murray date: Sat Jan 18 14:55:09 2014 -0500 summary: #19855: restore use of LC_ALL, not LC_MESSAGES I didn't realize LC_ALL was an override, and I should have. I tried to make a test, but it is not clear that the LC variables actually affect the strings that uuid is using to parse the command output. files: Lib/uuid.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/uuid.py b/Lib/uuid.py --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -305,9 +305,9 @@ return None try: - # LC_MESSAGES to get English output, 2>/dev/null to + # LC_ALL to ensure English output, 2>/dev/null to # prevent output on stderr - cmd = 'LC_MESSAGES=C %s %s 2>/dev/null' % (executable, args) + cmd = 'LC_ALL=C %s %s 2>/dev/null' % (executable, args) with os.popen(cmd) as pipe: for line in pipe: words = line.lower().split() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 21:02:59 2014 From: python-checkins at python.org (r.david.murray) Date: Sat, 18 Jan 2014 21:02:59 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE5ODU1OiByZXN0?= =?utf-8?q?ore_use_of_LC=5FALL=2C_not_LC=5FMESSAGES?= Message-ID: <3f696q1pKMz7Ljw@mail.python.org> http://hg.python.org/cpython/rev/706354c4d8f5 changeset: 88557:706354c4d8f5 branch: 3.3 parent: 88554:52edc7087c81 user: R David Murray date: Sat Jan 18 14:56:10 2014 -0500 summary: #19855: restore use of LC_ALL, not LC_MESSAGES I didn't realize LC_ALL was an override, and I should have. I tried to make a test, but it is not clear that the LC variables actually affect the strings that uuid is using to parse the command output. files: Lib/uuid.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/uuid.py b/Lib/uuid.py --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -321,9 +321,9 @@ return None try: - # LC_MESSAGES to get English output, 2>/dev/null to + # LC_ALL to ensure English output, 2>/dev/null to # prevent output on stderr - cmd = 'LC_MESSAGES=C %s %s 2>/dev/null' % (executable, args) + cmd = 'LC_ALL=C %s %s 2>/dev/null' % (executable, args) with os.popen(cmd) as pipe: for line in pipe: words = line.lower().split() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 21:03:00 2014 From: python-checkins at python.org (r.david.murray) Date: Sat, 18 Jan 2014 21:03:00 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2319855=3A_restore_use_of_LC=5FALL=2C_not_LC=5FME?= =?utf-8?q?SSAGES?= Message-ID: <3f696r3XHsz7Lkg@mail.python.org> http://hg.python.org/cpython/rev/418212180bf1 changeset: 88558:418212180bf1 parent: 88555:1469c4fde8cd parent: 88557:706354c4d8f5 user: R David Murray date: Sat Jan 18 15:02:00 2014 -0500 summary: Merge #19855: restore use of LC_ALL, not LC_MESSAGES files: Lib/uuid.py | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/uuid.py b/Lib/uuid.py --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -321,9 +321,10 @@ return None try: - # LC_MESSAGES to get English output, 2>/dev/null to - # prevent output on stderr - cmd = 'LC_MESSAGES=C %s %s 2>/dev/null' % (executable, args) + # LC_ALL to ensure English output, 2>/dev/null to prevent output on + # stderr (Note: we don't have an example where the words we search for + # are actually localized, but in theory some system could do so.) + cmd = 'LC_ALL=C %s %s 2>/dev/null' % (executable, args) with os.popen(cmd) as pipe: for line in pipe: words = line.lower().split() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 23:19:12 2014 From: python-checkins at python.org (stefan.krah) Date: Sat, 18 Jan 2014 23:19:12 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_test_failures_=28--wit?= =?utf-8?q?hout-doc-strings=29=2E?= Message-ID: <3f6D805NNsz7Ljl@mail.python.org> http://hg.python.org/cpython/rev/f8845f2d4c83 changeset: 88559:f8845f2d4c83 user: Stefan Krah date: Sat Jan 18 23:18:39 2014 +0100 summary: Fix test failures (--without-doc-strings). files: Lib/test/test_pydoc.py | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -21,7 +21,7 @@ from test.support import ( TESTFN, rmtree, reap_children, reap_threads, captured_output, captured_stdout, - captured_stderr, unlink + captured_stderr, unlink, requires_docstrings ) from test import pydoc_mod @@ -689,6 +689,8 @@ self.assertIsNone(pydoc.locate(name)) self.assertRaises(ImportError, pydoc.render_doc, name) + @requires_docstrings + def test_builtin_signatures(self): # test producing signatures from builtins stat_sig = pydoc.render_doc(os.stat) self.assertEqual(pydoc.plain(stat_sig).splitlines()[2], -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 18 23:38:47 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 18 Jan 2014 23:38:47 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Use_correct_C_type_in_byte?= =?utf-8?q?=5Fconverter=2E?= Message-ID: <3f6DZb6wnwz7Ljl@mail.python.org> http://hg.python.org/cpython/rev/967f368b7f75 changeset: 88560:967f368b7f75 user: Serhiy Storchaka date: Sun Jan 19 00:38:36 2014 +0200 summary: Use correct C type in byte_converter. files: Tools/clinic/clinic.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2062,7 +2062,7 @@ @add_legacy_c_converter('B', bitwise=True) class byte_converter(CConverter): - type = 'byte' + type = 'unsigned char' default_type = int format_unit = 'b' c_ignored_default = "'\0'" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 19 03:51:22 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 19 Jan 2014 03:51:22 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_fix_handling_o?= =?utf-8?q?f_100-continue_status_code_=28closes_=2318574=29?= Message-ID: <3f6LB210qcz7LjY@mail.python.org> http://hg.python.org/cpython/rev/093ab6c02ff4 changeset: 88561:093ab6c02ff4 branch: 3.3 parent: 88557:706354c4d8f5 user: Benjamin Peterson date: Sat Jan 18 21:50:18 2014 -0500 summary: fix handling of 100-continue status code (closes #18574) files: Lib/http/server.py | 2 +- Lib/test/test_httpservers.py | 6 ++++-- Misc/NEWS | 3 +++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Lib/http/server.py b/Lib/http/server.py --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -355,7 +355,7 @@ """ self.send_response_only(100) - self.flush_headers() + self.end_headers() return True def handle_one_request(self): diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -563,7 +563,8 @@ def test_with_continue_1_1(self): result = self.send_typical_request(b'GET / HTTP/1.1\r\nExpect: 100-continue\r\n\r\n') self.assertEqual(result[0], b'HTTP/1.1 100 Continue\r\n') - self.assertEqual(result[1], b'HTTP/1.1 200 OK\r\n') + self.assertEqual(result[1], b'\r\n') + self.assertEqual(result[2], b'HTTP/1.1 200 OK\r\n') self.verify_expected_headers(result[2:-1]) self.verify_get_called() self.assertEqual(result[-1], b'Data\r\n') @@ -631,7 +632,8 @@ self.assertNotEqual(_readAndReseek(output), b'') result = _readAndReseek(output).split(b'\r\n') self.assertEqual(result[0], b'HTTP/1.1 100 Continue') - self.assertEqual(result[1], b'HTTP/1.1 200 OK') + self.assertEqual(result[1], b'') + self.assertEqual(result[2], b'HTTP/1.1 200 OK') def test_with_continue_rejected(self): usual_handler = self.handler # Save to avoid breaking any subsequent tests. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,9 @@ Library ------- +- Issue #18574: Fixed handling of 100-continue reply from server in + http.client.HTTPConnection. Patch by Nikolaus Rath. + - Issue #20270: urllib.urlparse now supports empty ports. - Issue #20243: TarFile no longer raise ReadError when opened in write mode. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 19 03:51:23 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 19 Jan 2014 03:51:23 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_add_Nikolaus_R?= =?utf-8?q?ath_to_ACKS?= Message-ID: <3f6LB32mP6z7Ljl@mail.python.org> http://hg.python.org/cpython/rev/9c2d679bf279 changeset: 88562:9c2d679bf279 branch: 3.3 user: Benjamin Peterson date: Sat Jan 18 21:50:35 2014 -0500 summary: add Nikolaus Rath to ACKS 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 @@ -1004,6 +1004,7 @@ Jeff Ramnani Brodie Rao Antti Rasinen +Nikolaus Rath Sridhar Ratnakumar Ysj Ray Eric S. Raymond -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 19 03:51:24 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 19 Jan 2014 03:51:24 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_add_Nikolaus_R?= =?utf-8?q?ath_to_ACKS?= Message-ID: <3f6LB44lkTz7Ljg@mail.python.org> http://hg.python.org/cpython/rev/b67ab0a2fbc8 changeset: 88563:b67ab0a2fbc8 branch: 2.7 parent: 88556:9fe32328a573 user: Benjamin Peterson date: Sat Jan 18 21:50:35 2014 -0500 summary: add Nikolaus Rath to ACKS 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 @@ -839,6 +839,7 @@ Jeff Ramnani Brodie Rao Antti Rasinen +Nikolaus Rath Sridhar Ratnakumar Eric S. Raymond Edward K. Ream -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 19 03:51:25 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 19 Jan 2014 03:51:25 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4zICgjMTg1NzQp?= Message-ID: <3f6LB56nfRz7Lk4@mail.python.org> http://hg.python.org/cpython/rev/20a2597d6653 changeset: 88564:20a2597d6653 parent: 88560:967f368b7f75 parent: 88562:9c2d679bf279 user: Benjamin Peterson date: Sat Jan 18 21:51:11 2014 -0500 summary: merge 3.3 (#18574) files: Lib/http/server.py | 2 +- Lib/test/test_httpservers.py | 6 ++++-- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Lib/http/server.py b/Lib/http/server.py --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -355,7 +355,7 @@ """ self.send_response_only(100) - self.flush_headers() + self.end_headers() return True def handle_one_request(self): diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -584,7 +584,8 @@ def test_with_continue_1_1(self): result = self.send_typical_request(b'GET / HTTP/1.1\r\nExpect: 100-continue\r\n\r\n') self.assertEqual(result[0], b'HTTP/1.1 100 Continue\r\n') - self.assertEqual(result[1], b'HTTP/1.1 200 OK\r\n') + self.assertEqual(result[1], b'\r\n') + self.assertEqual(result[2], b'HTTP/1.1 200 OK\r\n') self.verify_expected_headers(result[2:-1]) self.verify_get_called() self.assertEqual(result[-1], b'Data\r\n') @@ -652,7 +653,8 @@ self.assertNotEqual(_readAndReseek(output), b'') result = _readAndReseek(output).split(b'\r\n') self.assertEqual(result[0], b'HTTP/1.1 100 Continue') - self.assertEqual(result[1], b'HTTP/1.1 200 OK') + self.assertEqual(result[1], b'') + self.assertEqual(result[2], b'HTTP/1.1 200 OK') def test_with_continue_rejected(self): usual_handler = self.handler # Save to avoid breaking any subsequent tests. diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1052,6 +1052,7 @@ Brodie Rao Senko Rasic Antti Rasinen +Nikolaus Rath Sridhar Ratnakumar Ysj Ray Eric S. Raymond diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,9 @@ Library ------- +- Issue #18574: Fixed handling of 100-continue reply from server in + http.client.HTTPConnection. Patch by Nikolaus Rath. + - Issue #20270: urllib.urlparse now supports empty ports. - Issue #20243: TarFile no longer raise ReadError when opened in write mode. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 19 04:32:13 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 19 Jan 2014 04:32:13 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_correct_news_e?= =?utf-8?q?ntry_for_=2318574?= Message-ID: <3f6M591c3vz7LjT@mail.python.org> http://hg.python.org/cpython/rev/d00ed6e7a823 changeset: 88565:d00ed6e7a823 branch: 3.3 parent: 88562:9c2d679bf279 user: Benjamin Peterson date: Sat Jan 18 22:31:27 2014 -0500 summary: correct news entry for #18574 files: Misc/NEWS | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,8 +43,8 @@ Library ------- -- Issue #18574: Fixed handling of 100-continue reply from server in - http.client.HTTPConnection. Patch by Nikolaus Rath. +- Issue #18574: Added missing newline in 100-Continue reply from + http.server.BaseHTTPRequestHandler. Patch by Nikolaus Rath. - Issue #20270: urllib.urlparse now supports empty ports. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 19 04:32:14 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 19 Jan 2014 04:32:14 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4zICgjMTg1NzQp?= Message-ID: <3f6M5B3b38z7Ljg@mail.python.org> http://hg.python.org/cpython/rev/cf0678c3b735 changeset: 88566:cf0678c3b735 parent: 88564:20a2597d6653 parent: 88565:d00ed6e7a823 user: Benjamin Peterson date: Sat Jan 18 22:32:05 2014 -0500 summary: merge 3.3 (#18574) files: Misc/NEWS | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,8 +25,8 @@ Library ------- -- Issue #18574: Fixed handling of 100-continue reply from server in - http.client.HTTPConnection. Patch by Nikolaus Rath. +- Issue #18574: Added missing newline in 100-Continue reply from + http.server.BaseHTTPRequestHandler. Patch by Nikolaus Rath. - Issue #20270: urllib.urlparse now supports empty ports. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 19 04:57:56 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 19 Jan 2014 04:57:56 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_improve_descri?= =?utf-8?q?ption_of_buffers_argument_for_readv/writev_=28closes_=2317811?= =?utf-8?q?=29?= Message-ID: <3f6Mfr1Qyzz7Ljb@mail.python.org> http://hg.python.org/cpython/rev/8b413f813a13 changeset: 88567:8b413f813a13 branch: 3.3 parent: 88565:d00ed6e7a823 user: Benjamin Peterson date: Sat Jan 18 22:54:59 2014 -0500 summary: improve description of buffers argument for readv/writev (closes #17811) Patch by Nikolaus Rath. files: Doc/library/os.rst | 20 ++++++++++++-------- Modules/posixmodule.c | 16 ++++++++++------ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1019,10 +1019,13 @@ .. function:: readv(fd, buffers) - Read from a file descriptor into a number of writable buffers. *buffers* is - an arbitrary sequence of writable buffers. Returns the total number of bytes - read. - + Read from a file descriptor *fd* into a number of mutable :term:`bytes-like + objects ` *buffers*. :func:`~os.readv` will transfer data + into each buffer until it is full and then move on to the next buffer in the + sequence to hold the rest of the data. :func:`~os.readv` returns the total + number of bytes read (which may be less than the total capacity of all the + objects). + Availability: Unix. .. versionadded:: 3.3 @@ -1071,10 +1074,11 @@ .. function:: writev(fd, buffers) - Write the contents of *buffers* to file descriptor *fd*, where *buffers* - is an arbitrary sequence of buffers. - Returns the total number of bytes written. - + Write the contents of *buffers* to file descriptor *fd*. *buffers* must be a + sequence of :term:`bytes-like objects `. + :func:`~os.writev` writes the contents of each object to the file descriptor + and returns the total number of bytes written. + Availability: Unix. .. versionadded:: 3.3 diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -8100,9 +8100,12 @@ #ifdef HAVE_READV PyDoc_STRVAR(posix_readv__doc__, "readv(fd, buffers) -> bytesread\n\n\ -Read from a file descriptor into a number of writable buffers. buffers\n\ -is an arbitrary sequence of writable buffers.\n\ -Returns the total number of bytes read."); +Read from a file descriptor fd into a number of mutable, bytes-like\n\ +objects (\"buffers\"). readv will transfer data into each buffer\n\ +until it is full and then move on to the next buffer in the sequence\n\ +to hold the rest of the data.\n\n\ +readv returns the total number of bytes read (which may be less than\n\ +the total capacity of all the buffers."); static PyObject * posix_readv(PyObject *self, PyObject *args) @@ -8465,9 +8468,10 @@ #ifdef HAVE_WRITEV PyDoc_STRVAR(posix_writev__doc__, "writev(fd, buffers) -> byteswritten\n\n\ -Write the contents of buffers to a file descriptor, where buffers is an\n\ -arbitrary sequence of buffers.\n\ -Returns the total bytes written."); +Write the contents of *buffers* to file descriptor *fd*. *buffers*\n\ +must be a sequence of bytes-like objects.\n\n\ +writev writes the contents of each object to the file descriptor\n\ +and returns the total number of bytes written."); static PyObject * posix_writev(PyObject *self, PyObject *args) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 19 04:57:57 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 19 Jan 2014 04:57:57 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4zICgjMTc4MTEp?= Message-ID: <3f6Mfs3Qcnz7Ljv@mail.python.org> http://hg.python.org/cpython/rev/4d56006133f1 changeset: 88568:4d56006133f1 parent: 88566:cf0678c3b735 parent: 88567:8b413f813a13 user: Benjamin Peterson date: Sat Jan 18 22:57:05 2014 -0500 summary: merge 3.3 (#17811) files: Doc/library/os.rst | 16 ++++++++++------ Modules/posixmodule.c | 16 ++++++++++------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1103,9 +1103,12 @@ .. function:: readv(fd, buffers) - Read from a file descriptor into a number of writable buffers. *buffers* is - an arbitrary sequence of writable buffers. Returns the total number of bytes - read. + Read from a file descriptor *fd* into a number of mutable :term:`bytes-like + objects ` *buffers*. :func:`~os.readv` will transfer data + into each buffer until it is full and then move on to the next buffer in the + sequence to hold the rest of the data. :func:`~os.readv` returns the total + number of bytes read (which may be less than the total capacity of all the + objects). Availability: Unix. @@ -1155,9 +1158,10 @@ .. function:: writev(fd, buffers) - Write the contents of *buffers* to file descriptor *fd*, where *buffers* - is an arbitrary sequence of buffers. - Returns the total number of bytes written. + Write the contents of *buffers* to file descriptor *fd*. *buffers* must be a + sequence of :term:`bytes-like objects `. + :func:`~os.writev` writes the contents of each object to the file descriptor + and returns the total number of bytes written. Availability: Unix. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -8061,9 +8061,12 @@ #ifdef HAVE_READV PyDoc_STRVAR(posix_readv__doc__, "readv(fd, buffers) -> bytesread\n\n\ -Read from a file descriptor into a number of writable buffers. buffers\n\ -is an arbitrary sequence of writable buffers.\n\ -Returns the total number of bytes read."); +Read from a file descriptor fd into a number of mutable, bytes-like\n\ +objects (\"buffers\"). readv will transfer data into each buffer\n\ +until it is full and then move on to the next buffer in the sequence\n\ +to hold the rest of the data.\n\n\ +readv returns the total number of bytes read (which may be less than\n\ +the total capacity of all the buffers."); static PyObject * posix_readv(PyObject *self, PyObject *args) @@ -8457,9 +8460,10 @@ #ifdef HAVE_WRITEV PyDoc_STRVAR(posix_writev__doc__, "writev(fd, buffers) -> byteswritten\n\n\ -Write the contents of buffers to a file descriptor, where buffers is an\n\ -arbitrary sequence of buffers.\n\ -Returns the total bytes written."); +Write the contents of *buffers* to file descriptor *fd*. *buffers*\n\ +must be a sequence of bytes-like objects.\n\n\ +writev writes the contents of each object to the file descriptor\n\ +and returns the total number of bytes written."); static PyObject * posix_writev(PyObject *self, PyObject *args) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 19 06:54:38 2014 From: python-checkins at python.org (larry.hastings) Date: Sun, 19 Jan 2014 06:54:38 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320299=3A_Argument?= =?utf-8?q?_Clinic_custom_converters_may_now_change_the_default?= Message-ID: <3f6QFV6td7zSVp@mail.python.org> http://hg.python.org/cpython/rev/8f11493cf727 changeset: 88569:8f11493cf727 user: Larry Hastings date: Sat Jan 18 21:54:15 2014 -0800 summary: Issue #20299: Argument Clinic custom converters may now change the default value of c_default and py_default with a class member. files: Misc/NEWS | 3 +++ Tools/clinic/clinic.py | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -101,6 +101,9 @@ Tools/Demos ----------- +- Issue #20299: Argument Clinic custom converters may now change the default + value of c_default and py_default with a class member. + - Issue #20287: Argument Clinic's output is now configurable, allowing delaying its output or even redirecting it to a separate file. diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1893,8 +1893,10 @@ self.__class__.__name__, default, name, types_str)) self.default = default - self.c_default = c_default - self.py_default = py_default + if c_default: + self.c_default = c_default + if py_default: + self.py_default = py_default if annotation != unspecified: fail("The 'annotation' parameter is not currently permitted.") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 19 08:50:48 2014 From: python-checkins at python.org (larry.hastings) Date: Sun, 19 Jan 2014 08:50:48 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320294=3A_Argument?= =?utf-8?q?_Clinic_now_supports_argument_parsing_for_=5F=5Fnew=5F=5F_and?= Message-ID: <3f6SqX2VQYzSYt@mail.python.org> http://hg.python.org/cpython/rev/2e32462e4832 changeset: 88570:2e32462e4832 user: Larry Hastings date: Sat Jan 18 23:50:21 2014 -0800 summary: Issue #20294: Argument Clinic now supports argument parsing for __new__ and __init__ functions. files: Doc/howto/clinic.rst | 23 +- Include/modsupport.h | 1 + Misc/NEWS | 3 + Modules/_pickle.c | 78 +-- Python/getargs.c | 21 +- Tools/clinic/clinic.py | 506 +++++++++++++++++----------- 6 files changed, 379 insertions(+), 253 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -784,8 +784,8 @@ on the right is the text you'd replace it with. ========= ================================================================================= -``'B'`` ``byte(bitwise=True)`` -``'b'`` ``byte`` +``'B'`` ``unsigned_char(bitwise=True)`` +``'b'`` ``unsigned_char`` ``'c'`` ``char`` ``'C'`` ``int(types='str')`` ``'d'`` ``double`` @@ -1275,6 +1275,25 @@ You can still use a self converter, a return converter, and specify a ``type`` argument to the object converter for ``METH_O``. +tp_new and tp_init functions +---------------------------------------------- + +You can convert ``tp_new`` and ``tp_init`` +functions. Just name them ``__new__`` or +``__init__`` as appropriate. Notes: + +* The function name generated for ``__new__`` doesn't end in ``__new__`` + like it would by default. It's just the name of the class, converted + into a valid C identifier. + +* No ``PyMethodDef`` ``#define`` is generated for these functions. + +* ``__init__`` functions return ``int``, not ``PyObject *``. + +* Argument Clinic supports any signature for these functions, even though + the parsing function is required to always take ``args`` and ``kwargs`` + objects. + The #ifdef trick ---------------------------------------------- diff --git a/Include/modsupport.h b/Include/modsupport.h --- a/Include/modsupport.h +++ b/Include/modsupport.h @@ -36,6 +36,7 @@ #endif #ifndef Py_LIMITED_API PyAPI_FUNC(int) _PyArg_NoKeywords(const char *funcname, PyObject *kw); +PyAPI_FUNC(int) _PyArg_NoPositional(const char *funcname, PyObject *args); PyAPI_FUNC(int) PyArg_VaParse(PyObject *, const char *, va_list); PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *, diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -101,6 +101,9 @@ Tools/Demos ----------- +- Issue #20294: Argument Clinic now supports argument parsing for __new__ and + __init__ functions. + - Issue #20299: Argument Clinic custom converters may now change the default value of c_default and py_default with a class member. diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -4064,13 +4064,13 @@ "to map the new Python 3 names to the old module names used in Python\n" "2, so that the pickle data stream is readable with Python 2."); -static PyObject * +static int _pickle_Pickler___init___impl(PicklerObject *self, PyObject *file, PyObject *protocol, int fix_imports); -static PyObject * +static int _pickle_Pickler___init__(PyObject *self, PyObject *args, PyObject *kwargs) { - PyObject *return_value = NULL; + int return_value = -1; static char *_keywords[] = {"file", "protocol", "fix_imports", NULL}; PyObject *file; PyObject *protocol = NULL; @@ -4086,9 +4086,9 @@ return return_value; } -static PyObject * +static int _pickle_Pickler___init___impl(PicklerObject *self, PyObject *file, PyObject *protocol, int fix_imports) -/*[clinic end generated code: checksum=defa3d9e9f8b51fb257d4fdfca99db503db0e6df]*/ +/*[clinic end generated code: checksum=10c8ea05194d08108471163d8202cf5e12975544]*/ { _Py_IDENTIFIER(persistent_id); _Py_IDENTIFIER(dispatch_table); @@ -4098,16 +4098,16 @@ (void)Pickler_clear(self); if (_Pickler_SetProtocol(self, protocol, fix_imports) < 0) - return NULL; + return -1; if (_Pickler_SetOutputStream(self, file) < 0) - return NULL; + return -1; /* memo and output_buffer may have already been created in _Pickler_New */ if (self->memo == NULL) { self->memo = PyMemoTable_New(); if (self->memo == NULL) - return NULL; + return -1; } self->output_len = 0; if (self->output_buffer == NULL) { @@ -4115,7 +4115,7 @@ self->output_buffer = PyBytes_FromStringAndSize(NULL, self->max_output_len); if (self->output_buffer == NULL) - return NULL; + return -1; } self->fast = 0; @@ -4126,31 +4126,20 @@ self->pers_func = _PyObject_GetAttrId((PyObject *)self, &PyId_persistent_id); if (self->pers_func == NULL) - return NULL; + return -1; } self->dispatch_table = NULL; if (_PyObject_HasAttrId((PyObject *)self, &PyId_dispatch_table)) { self->dispatch_table = _PyObject_GetAttrId((PyObject *)self, &PyId_dispatch_table); if (self->dispatch_table == NULL) - return NULL; - } - - Py_RETURN_NONE; -} - -/* Wrap the Clinic generated signature to slot it in tp_init. */ -static int -Pickler_init(PyObject *self, PyObject *args, PyObject *kwargs) -{ - PyObject *result = _pickle_Pickler___init__(self, args, kwargs); - if (result == NULL) { - return -1; - } - Py_DECREF(result); + return -1; + } + return 0; } + /* Define a proxy object for the Pickler's internal memo object. This is to * avoid breaking code like: * pickler.memo.clear() @@ -4543,7 +4532,7 @@ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ - Pickler_init, /*tp_init*/ + _pickle_Pickler___init__, /*tp_init*/ PyType_GenericAlloc, /*tp_alloc*/ PyType_GenericNew, /*tp_new*/ PyObject_GC_Del, /*tp_free*/ @@ -6614,13 +6603,13 @@ "respectively. The *encoding* can be \'bytes\' to read these 8-bit\n" "string instances as bytes objects."); -static PyObject * +static int _pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file, int fix_imports, const char *encoding, const char *errors); -static PyObject * +static int _pickle_Unpickler___init__(PyObject *self, PyObject *args, PyObject *kwargs) { - PyObject *return_value = NULL; + int return_value = -1; static char *_keywords[] = {"file", "fix_imports", "encoding", "errors", NULL}; PyObject *file; int fix_imports = 1; @@ -6637,9 +6626,9 @@ return return_value; } -static PyObject * +static int _pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file, int fix_imports, const char *encoding, const char *errors) -/*[clinic end generated code: checksum=26c1d4a06841a8e51d29a0c244ba7f4607ff358a]*/ +/*[clinic end generated code: checksum=6936e9188104e45b1b15e1c11fe77b3965409471]*/ { _Py_IDENTIFIER(persistent_load); @@ -6648,20 +6637,20 @@ (void)Unpickler_clear(self); if (_Unpickler_SetInputStream(self, file) < 0) - return NULL; + return -1; if (_Unpickler_SetInputEncoding(self, encoding, errors) < 0) - return NULL; + return -1; self->fix_imports = fix_imports; if (self->fix_imports == -1) - return NULL; + return -1; if (_PyObject_HasAttrId((PyObject *)self, &PyId_persistent_load)) { self->pers_func = _PyObject_GetAttrId((PyObject *)self, &PyId_persistent_load); if (self->pers_func == NULL) - return NULL; + return 1; } else { self->pers_func = NULL; @@ -6669,30 +6658,19 @@ self->stack = (Pdata *)Pdata_New(); if (self->stack == NULL) - return NULL; + return 1; self->memo_size = 32; self->memo = _Unpickler_NewMemo(self->memo_size); if (self->memo == NULL) - return NULL; + return -1; self->proto = 0; - Py_RETURN_NONE; -} - -/* Wrap the Clinic generated signature to slot it in tp_init. */ -static int -Unpickler_init(PyObject *self, PyObject *args, PyObject *kwargs) -{ - PyObject *result = _pickle_Unpickler___init__(self, args, kwargs); - if (result == NULL) { - return -1; - } - Py_DECREF(result); return 0; } + /* Define a proxy object for the Unpickler's internal memo object. This is to * avoid breaking code like: * unpickler.memo.clear() @@ -7096,7 +7074,7 @@ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ - Unpickler_init, /*tp_init*/ + _pickle_Unpickler___init__, /*tp_init*/ PyType_GenericAlloc, /*tp_alloc*/ PyType_GenericNew, /*tp_new*/ PyObject_GC_Del, /*tp_free*/ diff --git a/Python/getargs.c b/Python/getargs.c --- a/Python/getargs.c +++ b/Python/getargs.c @@ -1805,7 +1805,7 @@ /* For type constructors that don't take keyword args * - * Sets a TypeError and returns 0 if the kwds dict is + * Sets a TypeError and returns 0 if the args/kwargs is * not empty, returns 1 otherwise */ int @@ -1824,6 +1824,25 @@ funcname); return 0; } + + +int +_PyArg_NoPositional(const char *funcname, PyObject *args) +{ + if (args == NULL) + return 1; + if (!PyTuple_CheckExact(args)) { + PyErr_BadInternalCall(); + return 0; + } + if (PyTuple_GET_SIZE(args) == 0) + return 1; + + PyErr_Format(PyExc_TypeError, "%s does not take positional arguments", + funcname); + return 0; +} + #ifdef __cplusplus }; #endif diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -169,6 +169,8 @@ themselves. (This line is the "source line".) * If the substitution text is empty, the source line is removed in the output. + * If the field is not recognized, the original line + is passed unmodified through to the output. * If the substitution text is not empty: * Each line of the substituted text is indented by the indent of the source line. @@ -454,6 +456,182 @@ add('"') return ''.join(text) + _templates = {} + # the templates will be run through str.format(), + # so actual curly-braces need to be doubled up. + templates_source = """ +__________________________________________________ + +docstring_prototype + +PyDoc_VAR({c_basename}__doc__); +__________________________________________________ + +docstring_definition + +PyDoc_STRVAR({c_basename}__doc__, +{docstring}); +__________________________________________________ + +impl_definition + +static {impl_return_type} +{c_basename}_impl({impl_parameters}) +__________________________________________________ + +parser_prototype_noargs + +static PyObject * +{c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored)) +__________________________________________________ + +parser_prototype_meth_o + +# SLIGHT HACK +# METH_O uses {impl_parameters} for the parser! + +static PyObject * +{c_basename}({impl_parameters}) +__________________________________________________ + +parser_prototype_varargs + +static PyObject * +{c_basename}({self_type}{self_name}, PyObject *args) +__________________________________________________ + +parser_prototype_keyword + +static PyObject * +{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs) +__________________________________________________ + +parser_prototype_init + +static int +{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs) +__________________________________________________ + +parser_definition_simple_no_parsing + +{{ + return {c_basename}_impl({impl_arguments}); +}} +__________________________________________________ + +parser_definition_start + +{{ + {return_value_declaration} + {declarations} + {initializers} +{empty line} +__________________________________________________ + +parser_definition_end + + {return_conversion} + +{exit_label} + {cleanup} + return return_value; +}} +__________________________________________________ + +parser_definition_impl_call + + {return_value} = {c_basename}_impl({impl_arguments}); +__________________________________________________ + +parser_definition_unpack_tuple + + if (!PyArg_UnpackTuple(args, "{name}", + {unpack_min}, {unpack_max}, + {parse_arguments})) + goto exit; +__________________________________________________ + +parser_definition_parse_tuple + + if (!PyArg_ParseTuple(args, + "{format_units}:{name}", + {parse_arguments})) + goto exit; +__________________________________________________ + +parser_definition_option_groups + {option_group_parsing} + +__________________________________________________ + +parser_definition_parse_tuple_and_keywords + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "{format_units}:{name}", _keywords, + {parse_arguments})) + goto exit; +__________________________________________________ + +parser_definition_no_positional + + if (!_PyArg_NoPositional("{name}", args)) + goto exit; + +__________________________________________________ + +parser_definition_no_keywords + + if (!_PyArg_NoKeywords("{name}", kwargs)) + goto exit; + +__________________________________________________ + +methoddef_define + +#define {methoddef_name} \\ + {{"{name}", (PyCFunction){c_basename}, {methoddef_flags}, {c_basename}__doc__}}, +__________________________________________________ +""".rstrip() + + title = '' + buffer = [] + line = None + for line in templates_source.split('\n'): + line = line.rstrip() + if line.startswith('# '): + # comment + continue + if line.startswith("_____"): + if not buffer: + continue + assert title not in _templates, "defined template twice: " + repr(title) + buffer = '\n'.join(buffer).rstrip() + buffer = buffer.replace('{empty line}', '') + _templates[title] = buffer + buffer = [] + title = '' + continue + if not title: + if not line: + continue + title = line + continue + if not (line or buffer): + # throw away leading blank lines + continue + buffer.append(line) + + assert not title, 'ensure templates_source ends with ______ (still adding to ' + repr(title) + ")" + + del templates_source + del title + del buffer + del line + + # for name, value in _templates.items(): + # print(name + ":") + # pprint.pprint(value) + # print() def output_templates(self, f): parameters = list(f.parameters.values()) @@ -477,12 +655,14 @@ else: all_boring_objects = True + new_or_init = f.kind in (METHOD_NEW, METHOD_INIT) + meth_o = (len(parameters) == 1 and parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY and not converters[0].is_optional() and isinstance(converters[0], object_converter) and - converters[0].format_unit == 'O') - + converters[0].format_unit == 'O' and + not new_or_init) # we have to set seven things before we're done: # @@ -493,246 +673,144 @@ # parser_prototype # parser_definition # impl_definition - # - # since impl_prototype is always just impl_definition + ';' - # we just define impl_definition at the top - - docstring_prototype = "PyDoc_VAR({c_basename}__doc__);" - - docstring_definition = """ -PyDoc_STRVAR({c_basename}__doc__, -{docstring}); -""".strip() - - impl_definition = """ -static {impl_return_type} -{c_basename}_impl({impl_parameters})""".strip() - + + templates = self._templates + + return_value_declaration = "PyObject *return_value = NULL;" + + methoddef_define = templates['methoddef_define'] + docstring_prototype = templates['docstring_prototype'] + docstring_definition = templates['docstring_definition'] + impl_definition = templates['impl_definition'] impl_prototype = parser_prototype = parser_definition = None - def meth_varargs(): - nonlocal flags - nonlocal parser_prototype - - flags = "METH_VARARGS" - - parser_prototype = """ -static PyObject * -{c_basename}({self_type}{self_name}, PyObject *args) -""".strip() + parser_body_fields = None + def parser_body(prototype, *fields): + nonlocal parser_body_fields + add, output = text_accumulator() + add(prototype) + parser_body_fields = fields + fields = list(fields) + fields.insert(0, 'parser_definition_start') + fields.append('parser_definition_impl_call') + fields.append('parser_definition_end') + for field in fields: + add('\n') + add(templates[field]) + return output() + + def insert_keywords(s): + return linear_format(s, declarations="static char *_keywords[] = {{{keywords}, NULL}};\n{declarations}") if not parameters: # no parameters, METH_NOARGS flags = "METH_NOARGS" - parser_prototype = """ -static PyObject * -{c_basename}({self_type}{self_name}, PyObject *Py_UNUSED(ignored)) -""".strip() + parser_prototype = templates['parser_prototype_noargs'] + parser_definition = parser_prototype if default_return_converter: - parser_definition = parser_prototype + """ -{{ - return {c_basename}_impl({impl_arguments}); -}} -""".rstrip() + parser_definition = parser_prototype + '\n' + templates['parser_definition_simple_no_parsing'] else: - parser_definition = parser_prototype + """ -{{ - PyObject *return_value = NULL; - {declarations} - {initializers} - - {return_value} = {c_basename}_impl({impl_arguments}); - {return_conversion} - -{exit_label} - {cleanup} - return return_value; -}} -""".rstrip() + parser_definition = parser_body(parser_prototype) elif meth_o: + flags = "METH_O" + # impl_definition = templates['parser_prototype_meth_o'] + if default_return_converter: - # maps perfectly to METH_O, doesn't need a return converter, - # so we skip the parse function and call - # directly into the impl function - - # SLIGHT HACK - # METH_O uses {impl_parameters} for the parser. - - flags = "METH_O" - - impl_definition = """ -static PyObject * -{c_basename}({impl_parameters}) -""".strip() - + # maps perfectly to METH_O, doesn't need a return converter. + # so we skip making a parse function + # and call directly into the impl function. impl_prototype = parser_prototype = parser_definition = '' - + impl_definition = templates['parser_prototype_meth_o'] else: - # SLIGHT HACK - # METH_O uses {impl_parameters} for the parser. - - flags = "METH_O" - - parser_prototype = """ -static PyObject * -{c_basename}({impl_parameters}) -""".strip() - - parser_definition = parser_prototype + """ -{{ - PyObject *return_value = NULL; - {declarations} - {initializers} - - _return_value = {c_basename}_impl({impl_arguments}); - {return_conversion} - -{exit_label} - {cleanup} - return return_value; -}} -""".rstrip() + parser_prototype = templates['parser_prototype_meth_o'] + parser_definition = parser_body(parser_prototype) elif has_option_groups: # positional parameters with option groups # (we have to generate lots of PyArg_ParseTuple calls # in a big switch statement) - meth_varargs() - - parser_definition = parser_prototype + """ -{{ - PyObject *return_value = NULL; - {declarations} - {initializers} - - {option_group_parsing} - {return_value} = {c_basename}_impl({impl_arguments}); - {return_conversion} - -{exit_label} - {cleanup} - return return_value; -}} -""".rstrip() + flags = "METH_VARARGS" + parser_prototype = templates['parser_prototype_varargs'] + + parser_definition = parser_body(parser_prototype, 'parser_definition_option_groups') elif positional and all_boring_objects: # positional-only, but no option groups, # and nothing but normal objects: # PyArg_UnpackTuple! - meth_varargs() - - # substitute in the min and max by hand right here - assert parameters - min_o = first_optional - max_o = len(parameters) - if isinstance(parameters[0].converter, self_converter): - min_o -= 1 - max_o -= 1 - min_o = str(min_o) - max_o = str(max_o) - - parser_definition = parser_prototype + """ -{{ - PyObject *return_value = NULL; - {declarations} - {initializers} - - if (!PyArg_UnpackTuple(args, "{name}", - {min}, {max}, - {parse_arguments})) - goto exit; - {return_value} = {c_basename}_impl({impl_arguments}); - {return_conversion} - -exit: - {cleanup} - return return_value; -}} -""".rstrip().replace('{min}', min_o).replace('{max}', max_o) + flags = "METH_VARARGS" + parser_prototype = templates['parser_prototype_varargs'] + + parser_definition = parser_body(parser_prototype, 'parser_definition_unpack_tuple') elif positional: # positional-only, but no option groups # we only need one call to PyArg_ParseTuple - meth_varargs() - - parser_definition = parser_prototype + """ -{{ - PyObject *return_value = NULL; - {declarations} - {initializers} - - if (!PyArg_ParseTuple(args, - "{format_units}:{name}", - {parse_arguments})) - goto exit; - {return_value} = {c_basename}_impl({impl_arguments}); - {return_conversion} - -exit: - {cleanup} - return return_value; -}} -""".rstrip() + flags = "METH_VARARGS" + parser_prototype = templates['parser_prototype_varargs'] + + parser_definition = parser_body(parser_prototype, 'parser_definition_parse_tuple') else: # positional-or-keyword arguments flags = "METH_VARARGS|METH_KEYWORDS" - parser_prototype = """ -static PyObject * -{c_basename}({self_type}{self_name}, PyObject *args, PyObject *kwargs) -""".strip() - - parser_definition = parser_prototype + """ -{{ - PyObject *return_value = NULL; - static char *_keywords[] = {{{keywords}, NULL}}; - {declarations} - {initializers} - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "{format_units}:{name}", _keywords, - {parse_arguments})) - goto exit; - {return_value} = {c_basename}_impl({impl_arguments}); - {return_conversion} - -exit: - {cleanup} - return return_value; -}} -""".rstrip() + parser_prototype = templates['parser_prototype_keyword'] + + parser_definition = parser_body(parser_prototype, 'parser_definition_parse_tuple_and_keywords') + parser_definition = insert_keywords(parser_definition) + + + if new_or_init: + methoddef_define = '' + + if f.kind == METHOD_NEW: + parser_prototype = templates['parser_prototype_keyword'] + else: + return_value_declaration = "int return_value = -1;" + parser_prototype = templates['parser_prototype_init'] + + fields = list(parser_body_fields) + parses_positional = 'METH_NOARGS' not in flags + parses_keywords = 'METH_KEYWORDS' in flags + if parses_keywords: + assert parses_positional + + if not parses_keywords: + fields.insert(0, 'parser_definition_no_keywords') + if not parses_positional: + fields.insert(0, 'parser_definition_no_positional') + + parser_definition = parser_body(parser_prototype, *fields) + if parses_keywords: + parser_definition = insert_keywords(parser_definition) + if f.methoddef_flags: - assert flags flags += '|' + f.methoddef_flags - methoddef_define = """ -#define {methoddef_name} \\ - {{"{name}", (PyCFunction){c_basename}, {methoddef_flags}, {c_basename}__doc__}}, -""".strip().replace('{methoddef_flags}', flags) - - # parser_prototype mustn't be None, but it could be an empty string. + methoddef_define = methoddef_define.replace('{methoddef_flags}', flags) + + # add ';' to the end of parser_prototype and impl_prototype + # (they mustn't be None, but they could be an empty string.) assert parser_prototype is not None - assert not parser_prototype.endswith(';') - if parser_prototype: + assert not parser_prototype.endswith(';') parser_prototype += ';' - assert impl_definition if impl_prototype is None: - impl_prototype = impl_definition + ";" - - # __new__ and __init__ don't need methoddefs - if f.kind in (METHOD_NEW, METHOD_INIT): - methoddef_define = '' + impl_prototype = impl_definition + if impl_prototype: + impl_prototype += ";" + + parser_definition = parser_definition.replace("{return_value_declaration}", return_value_declaration) d = { "docstring_prototype" : docstring_prototype, @@ -744,8 +822,11 @@ "impl_definition" : impl_definition, } + # make sure we didn't forget to assign something, + # and wrap each non-empty value in \n's d2 = {} for name, value in d.items(): + assert value is not None, "got a None value for template " + repr(name) if value: value = '\n' + value + '\n' d2[name] = value @@ -881,12 +962,17 @@ positional = has_option_groups = False + first_optional = len(parameters) + if parameters: last_group = 0 - for p in parameters: + for i, p in enumerate(parameters): c = p.converter + if p.default is not unspecified: + first_optional = min(first_optional, i) + # insert group variable group = p.group if last_group != group: @@ -950,6 +1036,10 @@ template_dict['cleanup'] = "".join(data.cleanup) template_dict['return_value'] = data.return_value + # used by unpack tuple + template_dict['unpack_min'] = str(first_optional) + template_dict['unpack_max'] = str(len(parameters)) + if has_option_groups: self.render_option_group_parsing(f, template_dict) @@ -2063,7 +2153,7 @@ @add_legacy_c_converter('B', bitwise=True) -class byte_converter(CConverter): +class unsigned_char_converter(CConverter): type = 'unsigned char' default_type = int format_unit = 'b' @@ -2073,6 +2163,8 @@ if bitwise: self.format_unit = 'B' +class byte_converter(unsigned_char_converter): pass + class short_converter(CConverter): type = 'short' default_type = int @@ -2455,6 +2547,16 @@ type = 'int' cast = '(long)' +class init_return_converter(long_return_converter): + """ + Special return converter for __init__ functions. + """ + type = 'int' + cast = '(long)' + + def render(self, function, data): + pass + class unsigned_long_return_converter(long_return_converter): type = 'unsigned long' conversion_fn = 'PyLong_FromUnsignedLong' @@ -2858,9 +2960,8 @@ if c_basename and not is_legal_c_identifier(c_basename): fail("Illegal C basename: {}".format(c_basename)) - if not returns: - return_converter = CReturnConverter() - else: + return_converter = None + if returns: ast_input = "def x() -> {}: pass".format(returns) module = None try: @@ -2893,9 +2994,14 @@ if (self.kind != CALLABLE) or (not cls): fail("__init__ must be a normal method, not a class or static method!") self.kind = METHOD_INIT + if not return_converter: + return_converter = init_return_converter() elif fields[-1] in unsupported_special_methods: fail(fields[-1] + " should not be converted to Argument Clinic! (Yet.)") + if not return_converter: + return_converter = CReturnConverter() + if not module: fail("Undefined module used in declaration of " + repr(full_name.strip()) + ".") self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename, -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun Jan 19 09:47:09 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 19 Jan 2014 09:47:09 +0100 Subject: [Python-checkins] Daily reference leaks (967f368b7f75): sum=51 Message-ID: results for 967f368b7f75 on branch "default" -------------------------------------------- test_multiprocessing_fork leaked [0, 38, 0] references, sum=38 test_multiprocessing_fork leaked [0, 17, 0] memory blocks, sum=17 test_site leaked [0, 0, -2] references, sum=-2 test_site leaked [0, 0, -2] memory blocks, sum=-2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog46k5vA', '-x'] From python-checkins at python.org Sun Jan 19 11:28:00 2014 From: python-checkins at python.org (larry.hastings) Date: Sun, 19 Jan 2014 11:28:00 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320300=3A_Fix_exce?= =?utf-8?q?ption_when_setting_conversion_class_member_=22default=22?= Message-ID: <3f6XJw4MWtz7LjM@mail.python.org> http://hg.python.org/cpython/rev/cc53c49d38c8 changeset: 88571:cc53c49d38c8 user: Larry Hastings date: Sun Jan 19 02:27:34 2014 -0800 summary: Issue #20300: Fix exception when setting conversion class member "default" to None. files: Tools/clinic/clinic.py | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -3446,8 +3446,10 @@ a = [p.name] if p.converter.is_optional(): a.append('=') - value = p.converter.default - a.append(p.converter.py_default) + value = p.converter.py_default + if not value: + value = str(p.converter.default) + a.append(value) s = fix_right_bracket_count(p.right_bracket_count) s += "".join(a) if add_comma: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 19 12:01:52 2014 From: python-checkins at python.org (larry.hastings) Date: Sun, 19 Jan 2014 12:01:52 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Improve_fix_for_issue_=232?= =?utf-8?q?0300=2E?= Message-ID: <3f6Y402Df9z7Ljt@mail.python.org> http://hg.python.org/cpython/rev/d0e2437136f5 changeset: 88572:d0e2437136f5 user: Larry Hastings date: Sun Jan 19 03:01:23 2014 -0800 summary: Improve fix for issue #20300. files: Tools/clinic/clinic.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -3448,7 +3448,7 @@ a.append('=') value = p.converter.py_default if not value: - value = str(p.converter.default) + value = repr(p.converter.default) a.append(value) s = fix_right_bracket_count(p.right_bracket_count) s += "".join(a) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 20 06:12:33 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 20 Jan 2014 06:12:33 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_document_that_?= =?utf-8?q?a_new_Python_thread_context_is_created_in_ctypes_callbacks?= Message-ID: <3f71GT5J31z7LjP@mail.python.org> http://hg.python.org/cpython/rev/f4eade5df217 changeset: 88573:f4eade5df217 branch: 3.3 parent: 88567:8b413f813a13 user: Benjamin Peterson date: Mon Jan 20 00:09:53 2014 -0500 summary: document that a new Python thread context is created in ctypes callbacks (closes #6627) Patch by Nikolaus Rath. files: Doc/library/ctypes.rst | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1022,12 +1022,18 @@ 1 5 7 33 99 >>> -**Important note for callback functions:** +**Important notes for callback functions:** Make sure you keep references to :func:`CFUNCTYPE` objects as long as they are used from C code. :mod:`ctypes` doesn't, and if you don't, they may be garbage collected, crashing your program when a callback is made. +Also, note that if the callback function is called in a thread created outside +of Python's control (e.g. by the foreign code that calls the callback), ctypes +creates a new dummy Python thread on every invocation. This behavior is correct +for most purposes, but it means that values stored with `threading.local` will +*not* survive across different callbacks, even when those calls are made from +the same C thread. .. _ctypes-accessing-values-exported-from-dlls: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 20 06:12:34 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 20 Jan 2014 06:12:34 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_put_notes_in_a?= =?utf-8?q?_=2E=2Enote_section?= Message-ID: <3f71GV6jmLz7Lk3@mail.python.org> http://hg.python.org/cpython/rev/a6f748f40da6 changeset: 88574:a6f748f40da6 branch: 3.3 user: Benjamin Peterson date: Mon Jan 20 00:10:23 2014 -0500 summary: put notes in a ..note section files: Doc/library/ctypes.rst | 24 ++++++++++++------------ 1 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1022,18 +1022,18 @@ 1 5 7 33 99 >>> -**Important notes for callback functions:** - -Make sure you keep references to :func:`CFUNCTYPE` objects as long as they are -used from C code. :mod:`ctypes` doesn't, and if you don't, they may be garbage -collected, crashing your program when a callback is made. - -Also, note that if the callback function is called in a thread created outside -of Python's control (e.g. by the foreign code that calls the callback), ctypes -creates a new dummy Python thread on every invocation. This behavior is correct -for most purposes, but it means that values stored with `threading.local` will -*not* survive across different callbacks, even when those calls are made from -the same C thread. +.. note:: + + Make sure you keep references to :func:`CFUNCTYPE` objects as long as they + are used from C code. :mod:`ctypes` doesn't, and if you don't, they may be + garbage collected, crashing your program when a callback is made. + + Also, note that if the callback function is called in a thread created + outside of Python's control (e.g. by the foreign code that calls the + callback), ctypes creates a new dummy Python thread on every invocation. This + behavior is correct for most purposes, but it means that values stored with + `threading.local` will *not* survive across different callbacks, even when + those calls are made from the same C thread. .. _ctypes-accessing-values-exported-from-dlls: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 20 06:12:36 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 20 Jan 2014 06:12:36 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_document_that_?= =?utf-8?q?a_new_Python_thread_context_is_created_in_ctypes_callbacks?= Message-ID: <3f71GX0zZHz7Ljw@mail.python.org> http://hg.python.org/cpython/rev/9cd2d7a3f9f2 changeset: 88575:9cd2d7a3f9f2 branch: 2.7 parent: 88563:b67ab0a2fbc8 user: Benjamin Peterson date: Mon Jan 20 00:09:53 2014 -0500 summary: document that a new Python thread context is created in ctypes callbacks (closes #6627) Patch by Nikolaus Rath. files: Doc/library/ctypes.rst | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1080,12 +1080,18 @@ 1 5 7 33 99 >>> -**Important note for callback functions:** +**Important notes for callback functions:** Make sure you keep references to CFUNCTYPE objects as long as they are used from C code. :mod:`ctypes` doesn't, and if you don't, they may be garbage collected, crashing your program when a callback is made. +Also, note that if the callback function is called in a thread created outside +of Python's control (e.g. by the foreign code that calls the callback), ctypes +creates a new dummy Python thread on every invocation. This behavior is correct +for most purposes, but it means that values stored with `threading.local` will +*not* survive across different callbacks, even when those calls are made from +the same C thread. .. _ctypes-accessing-values-exported-from-dlls: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 20 06:12:37 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 20 Jan 2014 06:12:37 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_put_notes_in_a?= =?utf-8?q?_=2E=2Enote_section?= Message-ID: <3f71GY2hl6z7Lkc@mail.python.org> http://hg.python.org/cpython/rev/ece986f680d5 changeset: 88576:ece986f680d5 branch: 2.7 user: Benjamin Peterson date: Mon Jan 20 00:10:23 2014 -0500 summary: put notes in a ..note section files: Doc/library/ctypes.rst | 24 ++++++++++++------------ 1 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1080,18 +1080,18 @@ 1 5 7 33 99 >>> -**Important notes for callback functions:** - -Make sure you keep references to CFUNCTYPE objects as long as they are used from -C code. :mod:`ctypes` doesn't, and if you don't, they may be garbage collected, -crashing your program when a callback is made. - -Also, note that if the callback function is called in a thread created outside -of Python's control (e.g. by the foreign code that calls the callback), ctypes -creates a new dummy Python thread on every invocation. This behavior is correct -for most purposes, but it means that values stored with `threading.local` will -*not* survive across different callbacks, even when those calls are made from -the same C thread. +.. note:: + + Make sure you keep references to :func:`CFUNCTYPE` objects as long as they + are used from C code. :mod:`ctypes` doesn't, and if you don't, they may be + garbage collected, crashing your program when a callback is made. + + Also, note that if the callback function is called in a thread created + outside of Python's control (e.g. by the foreign code that calls the + callback), ctypes creates a new dummy Python thread on every invocation. This + behavior is correct for most purposes, but it means that values stored with + `threading.local` will *not* survive across different callbacks, even when + those calls are made from the same C thread. .. _ctypes-accessing-values-exported-from-dlls: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 20 06:12:38 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 20 Jan 2014 06:12:38 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4zICgjNjYyNyk=?= Message-ID: <3f71GZ4NXzz7Lks@mail.python.org> http://hg.python.org/cpython/rev/fd647825475a changeset: 88577:fd647825475a parent: 88572:d0e2437136f5 parent: 88574:a6f748f40da6 user: Benjamin Peterson date: Mon Jan 20 00:12:24 2014 -0500 summary: merge 3.3 (#6627) files: Doc/library/ctypes.rst | 18 ++++++++++++------ 1 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1022,12 +1022,18 @@ 1 5 7 33 99 >>> -**Important note for callback functions:** - -Make sure you keep references to :func:`CFUNCTYPE` objects as long as they are -used from C code. :mod:`ctypes` doesn't, and if you don't, they may be garbage -collected, crashing your program when a callback is made. - +.. note:: + + Make sure you keep references to :func:`CFUNCTYPE` objects as long as they + are used from C code. :mod:`ctypes` doesn't, and if you don't, they may be + garbage collected, crashing your program when a callback is made. + + Also, note that if the callback function is called in a thread created + outside of Python's control (e.g. by the foreign code that calls the + callback), ctypes creates a new dummy Python thread on every invocation. This + behavior is correct for most purposes, but it means that values stored with + `threading.local` will *not* survive across different callbacks, even when + those calls are made from the same C thread. .. _ctypes-accessing-values-exported-from-dlls: -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon Jan 20 09:50:32 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 20 Jan 2014 09:50:32 +0100 Subject: [Python-checkins] Daily reference leaks (d0e2437136f5): sum=2999 Message-ID: results for d0e2437136f5 on branch "default" -------------------------------------------- test_asyncio leaked [0, 4, 0] memory blocks, sum=4 test_site leaked [0, 0, -2] references, sum=-2 test_site leaked [0, 0, -2] memory blocks, sum=-2 test_urllib2net leaked [0, 0, 1590] references, sum=1590 test_urllib2net leaked [0, 0, 1409] memory blocks, sum=1409 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogOEyvJL', '-x'] From python-checkins at python.org Mon Jan 20 10:11:28 2014 From: python-checkins at python.org (gregory.p.smith) Date: Mon, 20 Jan 2014 10:11:28 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_the_unittest_to_run_pr?= =?utf-8?q?operly_when_the_working_directory_has?= Message-ID: <3f76Z86Drvz7LjX@mail.python.org> http://hg.python.org/cpython/rev/1e06e905b0e1 changeset: 88578:1e06e905b0e1 user: Gregory P. Smith date: Mon Jan 20 01:10:33 2014 -0800 summary: Fix the unittest to run properly when the working directory has additional bits set (such as the setgid or sticky bits). files: Lib/test/test_pathlib.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1549,7 +1549,7 @@ self.assertTrue(p.is_dir()) if os.name != 'nt': # the directory's permissions follow the mode argument - self.assertEqual(stat.S_IMODE(p.stat().st_mode), 0o555 & mode) + self.assertEqual(stat.S_IMODE(p.stat().st_mode), 0o7555 & mode) # the parent's permissions follow the default process settings self.assertEqual(stat.S_IMODE(p.parent.stat().st_mode), mode) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 20 10:11:30 2014 From: python-checkins at python.org (gregory.p.smith) Date: Mon, 20 Jan 2014 10:11:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fixes_Issue_=2320165=3A_Th?= =?utf-8?q?e_unittest_module_no_longer_considers_tests_marked_with?= Message-ID: <3f76ZB17q4z7LkC@mail.python.org> http://hg.python.org/cpython/rev/1e75ab9fd760 changeset: 88579:1e75ab9fd760 user: Gregory P. Smith date: Mon Jan 20 01:11:18 2014 -0800 summary: Fixes Issue #20165: The unittest module no longer considers tests marked with @expectedFailure successful if they pass. files: Doc/library/unittest.rst | 4 ++++ Lib/unittest/result.py | 11 ++++++++--- Lib/unittest/test/test_skipping.py | 4 ++-- Misc/NEWS | 3 +++ 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1772,6 +1772,10 @@ Return ``True`` if all tests run so far have passed, otherwise returns ``False``. + .. versionchanged:: 3.4 + Returns ``False`` if there were any :attr:`unexpectedSuccesses` + from tests marked with the :func:`expectedFailure` decorator. + .. method:: stop() diff --git a/Lib/unittest/result.py b/Lib/unittest/result.py --- a/Lib/unittest/result.py +++ b/Lib/unittest/result.py @@ -156,11 +156,16 @@ self.unexpectedSuccesses.append(test) def wasSuccessful(self): - "Tells whether or not this result was a success" - return len(self.failures) == len(self.errors) == 0 + """Tells whether or not this result was a success.""" + # The hasattr check is for test_result's OldResult test. That + # way this method works on objects that lack the attribute. + # (where would such result intances come from? old stored pickles?) + return ((len(self.failures) == len(self.errors) == 0) and + (not hasattr(self, 'unexpectedSuccesses') or + len(self.unexpectedSuccesses) == 0)) def stop(self): - "Indicates that the tests should be aborted" + """Indicates that the tests should be aborted.""" self.shouldStop = True def _exc_info_to_string(self, err, test): diff --git a/Lib/unittest/test/test_skipping.py b/Lib/unittest/test/test_skipping.py --- a/Lib/unittest/test/test_skipping.py +++ b/Lib/unittest/test/test_skipping.py @@ -158,7 +158,7 @@ ['startTest', 'addUnexpectedSuccess', 'stopTest']) self.assertFalse(result.failures) self.assertEqual(result.unexpectedSuccesses, [test]) - self.assertTrue(result.wasSuccessful()) + self.assertFalse(result.wasSuccessful()) def test_unexpected_success_subtests(self): # Success in all subtests counts as the unexpected success of @@ -182,7 +182,7 @@ 'addUnexpectedSuccess', 'stopTest']) self.assertFalse(result.failures) self.assertEqual(result.unexpectedSuccesses, [test]) - self.assertTrue(result.wasSuccessful()) + self.assertFalse(result.wasSuccessful()) def test_skip_doesnt_run_setup(self): class Foo(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,9 @@ Library ------- +- Issue #20165: The unittest module no longer considers tests marked with + @expectedFailure successful if they pass. + - Issue #18574: Added missing newline in 100-Continue reply from http.server.BaseHTTPRequestHandler. Patch by Nikolaus Rath. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 20 15:36:47 2014 From: python-checkins at python.org (stefan.krah) Date: Mon, 20 Jan 2014 15:36:47 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE5MDM2?= =?utf-8?q?=3A_Including_locale=2Eh_should_not_depend_on_HAVE=5FLANGINFO?= =?utf-8?b?X0gu?= Message-ID: <3f7FnW5Cjzz7LjM@mail.python.org> http://hg.python.org/cpython/rev/f82b6ec1ae6e changeset: 88580:f82b6ec1ae6e branch: 3.3 parent: 88574:a6f748f40da6 user: Stefan Krah date: Mon Jan 20 15:31:08 2014 +0100 summary: Issue #19036: Including locale.h should not depend on HAVE_LANGINFO_H. files: Misc/ACKS | 1 + Python/fileutils.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -545,6 +545,7 @@ Nadav Horesh Alon Horev Jan Hosang +Alan Hourihane Ken Howard Brad Howes Mike Hoy diff --git a/Python/fileutils.c b/Python/fileutils.c --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -1,11 +1,12 @@ #include "Python.h" #include "osdefs.h" +#include + #ifdef MS_WINDOWS # include #endif #ifdef HAVE_LANGINFO_H -#include #include #endif -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 20 15:36:49 2014 From: python-checkins at python.org (stefan.krah) Date: Mon, 20 Jan 2014 15:36:49 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgZnJvbSAzLjMu?= Message-ID: <3f7FnY17wtz7LjX@mail.python.org> http://hg.python.org/cpython/rev/a37aa98c6318 changeset: 88581:a37aa98c6318 parent: 88579:1e75ab9fd760 parent: 88580:f82b6ec1ae6e user: Stefan Krah date: Mon Jan 20 15:35:38 2014 +0100 summary: Merge from 3.3. files: Misc/ACKS | 1 + Python/fileutils.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -562,6 +562,7 @@ Nadav Horesh Alon Horev Jan Hosang +Alan Hourihane Ken Howard Brad Howes Mike Hoy diff --git a/Python/fileutils.c b/Python/fileutils.c --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -1,11 +1,12 @@ #include "Python.h" #include "osdefs.h" +#include + #ifdef MS_WINDOWS # include #endif #ifdef HAVE_LANGINFO_H -#include #include #endif -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 20 15:59:19 2014 From: python-checkins at python.org (eli.bendersky) Date: Mon, 20 Jan 2014 15:59:19 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Explain_the_=27result=27_a?= =?utf-8?q?rgument_in_asyncio=2Esleep?= Message-ID: <3f7GHW0ZF9zSjK@mail.python.org> http://hg.python.org/cpython/rev/cc7d480a2bb0 changeset: 88582:cc7d480a2bb0 user: Eli Bendersky date: Mon Jan 20 06:59:23 2014 -0800 summary: Explain the 'result' argument in asyncio.sleep files: Doc/library/asyncio-task.rst | 3 ++- 1 files changed, 2 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 @@ -419,7 +419,8 @@ .. function:: sleep(delay, result=None, \*, loop=None) Create a :ref:`coroutine object ` that completes after a given - time (in seconds). + time (in seconds). If *result* is provided, it is produced to the caller + when the coroutine completes. .. function:: shield(arg, \*, loop=None) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 20 16:02:17 2014 From: python-checkins at python.org (eli.bendersky) Date: Mon, 20 Jan 2014 16:02:17 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Clarify_what_the_loop_argu?= =?utf-8?q?ments_means_for_functions_listed_in_18=2E5=2E2=2E5?= Message-ID: <3f7GLx0z6Rz7LjM@mail.python.org> http://hg.python.org/cpython/rev/84869a6d6403 changeset: 88583:84869a6d6403 user: Eli Bendersky date: Mon Jan 20 07:02:22 2014 -0800 summary: Clarify what the loop arguments means for functions listed in 18.5.2.5 files: Doc/library/asyncio-task.rst | 6 ++++++ 1 files changed, 6 insertions(+), 0 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,6 +374,12 @@ Task functions -------------- +.. note:: + + In the functions below, the optional *loop* argument allows to explicitly set + the event loop object used by the underlying task or coroutine. If it's + not provided, the default event loop is used. + .. function:: as_completed(fs, \*, loop=None, timeout=None) Return an iterator whose values, when waited for, are :class:`Future` -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 20 16:51:26 2014 From: python-checkins at python.org (eli.bendersky) Date: Mon, 20 Jan 2014 16:51:26 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Formatting_=26_rst_link_ma?= =?utf-8?q?rkup_fixes?= Message-ID: <3f7HRf4BBhz7LjX@mail.python.org> http://hg.python.org/cpython/rev/cafdd5973974 changeset: 88584:cafdd5973974 user: Eli Bendersky date: Mon Jan 20 07:51:31 2014 -0800 summary: Formatting & rst link markup fixes files: Doc/library/asyncio-protocol.rst | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) 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 @@ -532,10 +532,11 @@ .. function:: open_connection(host=None, port=None, *, loop=None, limit=_DEFAULT_LIMIT, **kwds) - A wrapper for create_connection() returning a (reader, writer) pair. + A wrapper for :meth:`~BaseEventLoop.create_connection()` returning a (reader, + writer) pair. - The reader returned is a StreamReader instance; the writer is a - :class:`Transport`. + The reader returned is a :class:`StreamReader` instance; the writer is a + transport. The arguments are all the usual arguments to :meth:`BaseEventLoop.create_connection` except *protocol_factory*; most -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 20 17:13:26 2014 From: python-checkins at python.org (eli.bendersky) Date: Mon, 20 Jan 2014 17:13:26 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_grammar_and_add_markup?= Message-ID: <3f7Hx23l6gz7LjM@mail.python.org> http://hg.python.org/cpython/rev/d51d6f1f9db8 changeset: 88585:d51d6f1f9db8 user: Eli Bendersky date: Mon Jan 20 08:13:31 2014 -0800 summary: Fix grammar and add markup files: Doc/library/asyncio-dev.rst | 11 ++++++----- 1 files changed, 6 insertions(+), 5 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 @@ -4,7 +4,7 @@ ==================== Asynchronous programming is different than classical "sequential" programming. -This page lists common traps and explain how to avoid them. +This page lists common traps and explains how to avoid them. Handle correctly blocking functions @@ -131,14 +131,15 @@ See also the :meth:`Future.exception` method. -Chain correctly coroutines +Chain coroutines correctly -------------------------- When a coroutine function calls other coroutine functions and tasks, they -should chained explicitly with ``yield from``. Otherwise, the execution is no -more guaranteed to be sequential. +should be chained explicitly with ``yield from``. Otherwise, the execution is +not guaranteed to be sequential. -Example with different bugs using sleep to simulate slow operations:: +Example with different bugs using :func:`asyncio.sleep` to simulate slow +operations:: import asyncio -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 20 20:35:41 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 20 Jan 2014 20:35:41 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMzE1?= =?utf-8?q?=3A_Removed_support_for_backward_compatibility_with_early_2=2Ex?= Message-ID: <3f7NQP35T5z7LkQ@mail.python.org> http://hg.python.org/cpython/rev/5f754f1e3194 changeset: 88586:5f754f1e3194 branch: 3.3 parent: 88580:f82b6ec1ae6e user: Serhiy Storchaka date: Mon Jan 20 21:29:31 2014 +0200 summary: Issue #20315: Removed support for backward compatibility with early 2.x versions. files: Lib/configparser.py | 17 ----------------- Lib/modulefinder.py | 29 +---------------------------- Lib/optparse.py | 10 ++-------- Modules/_lsprof.c | 12 ------------ Modules/_tkinter.c | 14 -------------- Modules/gcmodule.c | 14 -------------- 6 files changed, 3 insertions(+), 93 deletions(-) diff --git a/Lib/configparser.py b/Lib/configparser.py --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -144,23 +144,6 @@ class Error(Exception): """Base class for ConfigParser exceptions.""" - def _get_message(self): - """Getter for 'message'; needed only to override deprecation in - BaseException. - """ - return self.__message - - def _set_message(self, value): - """Setter for 'message'; needed only to override deprecation in - BaseException. - """ - self.__message = value - - # BaseException.message has been deprecated since Python 2.6. To prevent - # DeprecationWarning from popping up over this pre-existing attribute, use - # a new property that takes lookup precedence. - message = property(_get_message, _set_message) - def __init__(self, msg=''): self.message = msg Exception.__init__(self, msg) diff --git a/Lib/modulefinder.py b/Lib/modulefinder.py --- a/Lib/modulefinder.py +++ b/Lib/modulefinder.py @@ -332,30 +332,6 @@ fullname = name + "." + sub self._add_badmodule(fullname, caller) - def scan_opcodes(self, co, - unpack = struct.unpack): - # Scan the code, and yield 'interesting' opcode combinations - # Version for Python 2.4 and older - code = co.co_code - names = co.co_names - consts = co.co_consts - while code: - c = code[0] - if c in STORE_OPS: - oparg, = unpack('= HAVE_ARGUMENT: - code = code[3:] - else: - code = code[1:] - def scan_opcodes_25(self, co, unpack = struct.unpack): # Scan the code, and yield 'interesting' opcode combinations @@ -387,10 +363,7 @@ def scan_code(self, co, m): code = co.co_code - if sys.version_info >= (2, 5): - scanner = self.scan_opcodes_25 - else: - scanner = self.scan_opcodes + scanner = self.scan_opcodes_25 for what, args in scanner(co): if what == "store": name, = args diff --git a/Lib/optparse.py b/Lib/optparse.py --- a/Lib/optparse.py +++ b/Lib/optparse.py @@ -645,14 +645,8 @@ self.type = "string" else: # Allow type objects or builtin type conversion functions - # (int, str, etc.) as an alternative to their names. (The - # complicated check of builtins is only necessary for - # Python 2.1 and earlier, and is short-circuited by the - # first check on modern Pythons.) - import builtins - if ( isinstance(self.type, type) or - (hasattr(self.type, "__name__") and - getattr(builtins, self.type.__name__, None) is self.type) ): + # (int, str, etc.) as an alternative to their names. + if isinstance(self.type, type): self.type = self.type.__name__ if self.type == "str": diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -455,7 +455,6 @@ PyTrace_RETURN event will be generated, so we don't need to handle it. */ -#ifdef PyTrace_C_CALL /* not defined in Python <= 2.3 */ /* the Python function 'frame' is issuing a call to the built-in function 'arg' */ case PyTrace_C_CALL: @@ -477,7 +476,6 @@ ((PyCFunctionObject *)arg)->m_ml); } break; -#endif default: break; @@ -667,13 +665,7 @@ if (nvalue == 0) pObj->flags &= ~POF_BUILTINS; else if (nvalue > 0) { -#ifndef PyTrace_C_CALL - PyErr_SetString(PyExc_ValueError, - "builtins=True requires Python >= 2.4"); - return -1; -#else pObj->flags |= POF_BUILTINS; -#endif } return 0; } @@ -771,11 +763,7 @@ PyObject *timer = NULL; double timeunit = 0.0; int subcalls = 1; -#ifdef PyTrace_C_CALL int builtins = 1; -#else - int builtins = 0; -#endif static char *kwlist[] = {"timer", "timeunit", "subcalls", "builtins", 0}; diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -33,20 +33,6 @@ #include #endif -/* Allow using this code in Python 2.[12] */ -#ifndef PyDoc_STRVAR -#define PyDoc_STRVAR(name,str) static char name[] = str -#endif - -#ifndef PyMODINIT_FUNC -#define PyMODINIT_FUNC void -#endif - -#ifndef PyBool_Check -#define PyBool_Check(o) 0 -#define PyBool_FromLong PyLong_FromLong -#endif - #define CHECK_SIZE(size, elemsize) \ ((size_t)(size) <= Py_MAX((size_t)INT_MAX, UINT_MAX / (size_t)(elemsize))) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1534,13 +1534,6 @@ _PyObject_GC_TRACK(op); } -/* for binary compatibility with 2.2 */ -void -_PyObject_GC_Track(PyObject *op) -{ - PyObject_GC_Track(op); -} - void PyObject_GC_UnTrack(void *op) { @@ -1551,13 +1544,6 @@ _PyObject_GC_UNTRACK(op); } -/* for binary compatibility with 2.2 */ -void -_PyObject_GC_UnTrack(PyObject *op) -{ - PyObject_GC_UnTrack(op); -} - PyObject * _PyObject_GC_Malloc(size_t basicsize) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 20 20:35:42 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 20 Jan 2014 20:35:42 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320315=3A_Removed_support_for_backward_compatibi?= =?utf-8?q?lity_with_early_2=2Ex?= Message-ID: <3f7NQQ5rFfz7LkV@mail.python.org> http://hg.python.org/cpython/rev/ede054eb3dc1 changeset: 88587:ede054eb3dc1 parent: 88585:d51d6f1f9db8 parent: 88586:5f754f1e3194 user: Serhiy Storchaka date: Mon Jan 20 21:35:06 2014 +0200 summary: Issue #20315: Removed support for backward compatibility with early 2.x versions. Removed backward compatibility alias curses.window.nooutrefresh which should be removed in 2.3. files: Lib/configparser.py | 17 ----------- Lib/modulefinder.py | 29 +------------------ Lib/optparse.py | 10 +----- Lib/test/_test_multiprocessing.py | 3 - Modules/_cursesmodule.c | 2 - Modules/_lsprof.c | 12 ------- Modules/_tkinter.c | 14 --------- Modules/gcmodule.c | 14 --------- 8 files changed, 3 insertions(+), 98 deletions(-) diff --git a/Lib/configparser.py b/Lib/configparser.py --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -144,23 +144,6 @@ class Error(Exception): """Base class for ConfigParser exceptions.""" - def _get_message(self): - """Getter for 'message'; needed only to override deprecation in - BaseException. - """ - return self.__message - - def _set_message(self, value): - """Setter for 'message'; needed only to override deprecation in - BaseException. - """ - self.__message = value - - # BaseException.message has been deprecated since Python 2.6. To prevent - # DeprecationWarning from popping up over this pre-existing attribute, use - # a new property that takes lookup precedence. - message = property(_get_message, _set_message) - def __init__(self, msg=''): self.message = msg Exception.__init__(self, msg) diff --git a/Lib/modulefinder.py b/Lib/modulefinder.py --- a/Lib/modulefinder.py +++ b/Lib/modulefinder.py @@ -335,30 +335,6 @@ fullname = name + "." + sub self._add_badmodule(fullname, caller) - def scan_opcodes(self, co, - unpack = struct.unpack): - # Scan the code, and yield 'interesting' opcode combinations - # Version for Python 2.4 and older - code = co.co_code - names = co.co_names - consts = co.co_consts - while code: - c = code[0] - if c in STORE_OPS: - oparg, = unpack('= HAVE_ARGUMENT: - code = code[3:] - else: - code = code[1:] - def scan_opcodes_25(self, co, unpack = struct.unpack): # Scan the code, and yield 'interesting' opcode combinations @@ -390,10 +366,7 @@ def scan_code(self, co, m): code = co.co_code - if sys.version_info >= (2, 5): - scanner = self.scan_opcodes_25 - else: - scanner = self.scan_opcodes + scanner = self.scan_opcodes_25 for what, args in scanner(co): if what == "store": name, = args diff --git a/Lib/optparse.py b/Lib/optparse.py --- a/Lib/optparse.py +++ b/Lib/optparse.py @@ -645,14 +645,8 @@ self.type = "string" else: # Allow type objects or builtin type conversion functions - # (int, str, etc.) as an alternative to their names. (The - # complicated check of builtins is only necessary for - # Python 2.1 and earlier, and is short-circuited by the - # first check on modern Pythons.) - import builtins - if ( isinstance(self.type, type) or - (hasattr(self.type, "__name__") and - getattr(builtins, self.type.__name__, None) is self.type) ): + # (int, str, etc.) as an alternative to their names. + if isinstance(self.type, type): self.type = self.type.__name__ if self.type == "str": diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -695,9 +695,6 @@ def test_task_done(self): queue = self.JoinableQueue() - if sys.version_info < (2, 5) and not hasattr(queue, 'task_done'): - self.skipTest("requires 'queue.task_done()' method") - workers = [self.Process(target=self._test_task_done, args=(queue,)) for i in range(4)] diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -2087,8 +2087,6 @@ {"nodelay", (PyCFunction)PyCursesWindow_nodelay, METH_VARARGS}, {"notimeout", (PyCFunction)PyCursesWindow_notimeout, METH_VARARGS}, {"noutrefresh", (PyCFunction)PyCursesWindow_NoOutRefresh, METH_VARARGS}, - /* Backward compatibility alias -- remove in Python 2.3 */ - {"nooutrefresh", (PyCFunction)PyCursesWindow_NoOutRefresh, METH_VARARGS}, {"overlay", (PyCFunction)PyCursesWindow_Overlay, METH_VARARGS}, {"overwrite", (PyCFunction)PyCursesWindow_Overwrite, METH_VARARGS}, diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -451,7 +451,6 @@ PyTrace_RETURN event will be generated, so we don't need to handle it. */ -#ifdef PyTrace_C_CALL /* not defined in Python <= 2.3 */ /* the Python function 'frame' is issuing a call to the built-in function 'arg' */ case PyTrace_C_CALL: @@ -473,7 +472,6 @@ ((PyCFunctionObject *)arg)->m_ml); } break; -#endif default: break; @@ -663,13 +661,7 @@ if (nvalue == 0) pObj->flags &= ~POF_BUILTINS; else if (nvalue > 0) { -#ifndef PyTrace_C_CALL - PyErr_SetString(PyExc_ValueError, - "builtins=True requires Python >= 2.4"); - return -1; -#else pObj->flags |= POF_BUILTINS; -#endif } return 0; } @@ -767,11 +759,7 @@ PyObject *timer = NULL; double timeunit = 0.0; int subcalls = 1; -#ifdef PyTrace_C_CALL int builtins = 1; -#else - int builtins = 0; -#endif static char *kwlist[] = {"timer", "timeunit", "subcalls", "builtins", 0}; diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -33,20 +33,6 @@ #include #endif -/* Allow using this code in Python 2.[12] */ -#ifndef PyDoc_STRVAR -#define PyDoc_STRVAR(name,str) static char name[] = str -#endif - -#ifndef PyMODINIT_FUNC -#define PyMODINIT_FUNC void -#endif - -#ifndef PyBool_Check -#define PyBool_Check(o) 0 -#define PyBool_FromLong PyLong_FromLong -#endif - #define CHECK_SIZE(size, elemsize) \ ((size_t)(size) <= Py_MAX((size_t)INT_MAX, UINT_MAX / (size_t)(elemsize))) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1693,13 +1693,6 @@ _PyObject_GC_TRACK(op); } -/* for binary compatibility with 2.2 */ -void -_PyObject_GC_Track(PyObject *op) -{ - PyObject_GC_Track(op); -} - void PyObject_GC_UnTrack(void *op) { @@ -1710,13 +1703,6 @@ _PyObject_GC_UNTRACK(op); } -/* for binary compatibility with 2.2 */ -void -_PyObject_GC_UnTrack(PyObject *op) -{ - PyObject_GC_UnTrack(op); -} - PyObject * _PyObject_GC_Malloc(size_t basicsize) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 20 20:45:52 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 20 Jan 2014 20:45:52 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?release=3A_kill_all_pycs_with_prejudi?= =?utf-8?b?Y2UgKCMyMDMxNik=?= Message-ID: <3f7Nf80B4Tz7Ljq@mail.python.org> http://hg.python.org/release/rev/9272f4fd7689 changeset: 68:9272f4fd7689 user: Benjamin Peterson date: Mon Jan 20 14:45:47 2014 -0500 summary: kill all pycs with prejudice (#20316) files: release.py | 11 ++++++----- 1 files changed, 6 insertions(+), 5 deletions(-) diff --git a/release.py b/release.py --- a/release.py +++ b/release.py @@ -272,7 +272,7 @@ # Remove files we don't want to ship in tarballs. print('Removing VCS .*ignore, .hg*, and the hgtouch.pyc we JUST CREATED') for name in ('.hgignore', '.hgeol', '.hgtags', '.hgtouch', - '.bzrignore', '.gitignore', 'Tools/hg/hgtouch.pyc'): + '.bzrignore', '.gitignore'): try: os.unlink(name) except OSError: @@ -291,10 +291,11 @@ shutil.rmtree('tools/jinja2', ignore_errors=True) shutil.rmtree('tools/pygments', ignore_errors=True) shutil.rmtree('tools/sphinx', ignore_errors=True) - for dirpath, dirnames, filenames in os.walk('.'): - for filename in filenames: - if filename.endswith('.pyc'): - os.remove(os.path.join(dirpath, filename)) + + with changed_dir(archivename): + print('Zapping pycs') + run_cmd(["find . -depth -name '__pycache__' -exec rm -rf {} ';'"]) + run_cmd(["find . -name '*.py[co]' -exec rm -f {} ';'"]) os.mkdir('src') with changed_dir('src'): -- Repository URL: http://hg.python.org/release From python-checkins at python.org Mon Jan 20 21:09:25 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 20 Jan 2014 21:09:25 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?release=3A_update_print_statement?= Message-ID: <3f7P9K1gwYz7LjT@mail.python.org> http://hg.python.org/release/rev/a6c570a7ac8f changeset: 69:a6c570a7ac8f user: Benjamin Peterson date: Mon Jan 20 15:06:09 2014 -0500 summary: update print statement files: release.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/release.py b/release.py --- a/release.py +++ b/release.py @@ -270,7 +270,7 @@ os.utime(name, None) # Remove files we don't want to ship in tarballs. - print('Removing VCS .*ignore, .hg*, and the hgtouch.pyc we JUST CREATED') + print('Removing VCS .*ignore, .hg*') for name in ('.hgignore', '.hgeol', '.hgtags', '.hgtouch', '.bzrignore', '.gitignore'): try: -- Repository URL: http://hg.python.org/release From python-checkins at python.org Mon Jan 20 21:14:06 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 20 Jan 2014 21:14:06 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIwMjYy?= =?utf-8?q?=3A_Warnings_are_raised_now_when_duplicate_names_are_added_in_t?= =?utf-8?q?he?= Message-ID: <3f7PGk0lzTz7LlJ@mail.python.org> http://hg.python.org/cpython/rev/208fa45672c2 changeset: 88588:208fa45672c2 branch: 2.7 parent: 88576:ece986f680d5 user: Serhiy Storchaka date: Mon Jan 20 21:57:09 2014 +0200 summary: Issue #20262: Warnings are raised now when duplicate names are added in the ZIP file or too long ZIP file comment is truncated. files: Lib/test/test_zipfile.py | 9 ++++++--- Lib/zipfile.py | 12 ++++++------ Misc/NEWS | 3 +++ 3 files changed, 15 insertions(+), 9 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 @@ -19,7 +19,7 @@ from unittest import skipUnless from test.test_support import TESTFN, TESTFN_UNICODE, TESTFN_ENCODING, \ - run_unittest, findfile, unlink + run_unittest, findfile, unlink, check_warnings try: TESTFN_UNICODE.encode(TESTFN_ENCODING) except (UnicodeError, TypeError): @@ -148,7 +148,9 @@ # Create the ZIP archive with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: zipfp.writestr("name", "foo") - zipfp.writestr("name", "bar") + with check_warnings(('', UserWarning)): + zipfp.writestr("name", "bar") + self.assertEqual(zipfp.namelist(), ["name"] * 2) with zipfile.ZipFile(TESTFN2, "r") as zipfp: infos = zipfp.infolist() @@ -1035,7 +1037,8 @@ # check a comment that is too long is truncated with zipfile.ZipFile(TESTFN, mode="w") as zipf: - zipf.comment = comment2 + 'oops' + with check_warnings(('', UserWarning)): + zipf.comment = comment2 + 'oops' zipf.writestr("foo.txt", "O, for a Muse of Fire!") with zipfile.ZipFile(TESTFN, mode="r") as zipf: self.assertEqual(zipf.comment, comment2) diff --git a/Lib/zipfile.py b/Lib/zipfile.py --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -922,10 +922,10 @@ @comment.setter def comment(self, comment): # check for valid comment length - if len(comment) >= ZIP_MAX_COMMENT: - if self.debug: - print('Archive comment is too long; truncating to %d bytes' - % ZIP_MAX_COMMENT) + if len(comment) > ZIP_MAX_COMMENT: + import warnings + warnings.warn('Archive comment is too long; truncating to %d bytes' + % ZIP_MAX_COMMENT, stacklevel=2) comment = comment[:ZIP_MAX_COMMENT] self._comment = comment self._didModify = True @@ -1088,8 +1088,8 @@ def _writecheck(self, zinfo): """Check for errors before writing a file to the archive.""" if zinfo.filename in self.NameToInfo: - if self.debug: # Warning for duplicate names - print "Duplicate name:", zinfo.filename + import warnings + warnings.warn('Duplicate name: %r' % zinfo.filename, stacklevel=3) if self.mode not in ("w", "a"): raise RuntimeError, 'write() requires mode "w" or "a"' if not self.fp: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,6 +35,9 @@ Library ------- +- Issue #20262: Warnings are raised now when duplicate names are added in the + ZIP file or too long ZIP file comment is truncated. + - Issue #20270: urllib and urlparse now support empty ports. - Issue #20243: TarFile no longer raise ReadError when opened in write mode. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 20 21:14:07 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 20 Jan 2014 21:14:07 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMjYy?= =?utf-8?q?=3A_Warnings_are_raised_now_when_duplicate_names_are_added_in_t?= =?utf-8?q?he?= Message-ID: <3f7PGl2lBdz7LjT@mail.python.org> http://hg.python.org/cpython/rev/9fda6658c01a changeset: 88589:9fda6658c01a branch: 3.3 parent: 88586:5f754f1e3194 user: Serhiy Storchaka date: Mon Jan 20 21:57:40 2014 +0200 summary: Issue #20262: Warnings are raised now when duplicate names are added in the ZIP file or too long ZIP file comment is truncated. files: Lib/test/test_zipfile.py | 7 +++++-- Lib/zipfile.py | 12 ++++++------ Misc/NEWS | 3 +++ 3 files changed, 14 insertions(+), 8 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 @@ -844,7 +844,9 @@ # Create the ZIP archive with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: zipfp.writestr("name", "foo") - zipfp.writestr("name", "bar") + with self.assertWarns(UserWarning): + zipfp.writestr("name", "bar") + self.assertEqual(zipfp.namelist(), ["name"] * 2) with zipfile.ZipFile(TESTFN2, "r") as zipfp: infos = zipfp.infolist() @@ -1150,7 +1152,8 @@ # check a comment that is too long is truncated with zipfile.ZipFile(TESTFN, mode="w") as zipf: - zipf.comment = comment2 + b'oops' + with self.assertWarns(UserWarning): + zipf.comment = comment2 + b'oops' zipf.writestr("foo.txt", "O, for a Muse of Fire!") with zipfile.ZipFile(TESTFN, mode="r") as zipfr: self.assertEqual(zipfr.comment, comment2) diff --git a/Lib/zipfile.py b/Lib/zipfile.py --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -1102,10 +1102,10 @@ if not isinstance(comment, bytes): raise TypeError("comment: expected bytes, got %s" % type(comment)) # check for valid comment length - if len(comment) >= ZIP_MAX_COMMENT: - if self.debug: - print('Archive comment is too long; truncating to %d bytes' - % ZIP_MAX_COMMENT) + if len(comment) > ZIP_MAX_COMMENT: + import warnings + warnings.warn('Archive comment is too long; truncating to %d bytes' + % ZIP_MAX_COMMENT, stacklevel=2) comment = comment[:ZIP_MAX_COMMENT] self._comment = comment self._didModify = True @@ -1290,8 +1290,8 @@ def _writecheck(self, zinfo): """Check for errors before writing a file to the archive.""" if zinfo.filename in self.NameToInfo: - if self.debug: # Warning for duplicate names - print("Duplicate name:", zinfo.filename) + import warnings + warnings.warn('Duplicate name: %r' % zinfo.filename, stacklevel=3) if self.mode not in ("w", "a"): raise RuntimeError('write() requires mode "w" or "a"') if not self.fp: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,9 @@ Library ------- +- Issue #20262: Warnings are raised now when duplicate names are added in the + ZIP file or too long ZIP file comment is truncated. + - Issue #18574: Added missing newline in 100-Continue reply from http.server.BaseHTTPRequestHandler. Patch by Nikolaus Rath. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 20 21:14:08 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 20 Jan 2014 21:14:08 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320262=3A_Warnings_are_raised_now_when_duplicate?= =?utf-8?q?_names_are_added_in_the?= Message-ID: <3f7PGm52yLz7Lk4@mail.python.org> http://hg.python.org/cpython/rev/f7cebf727bc6 changeset: 88590:f7cebf727bc6 parent: 88587:ede054eb3dc1 parent: 88589:9fda6658c01a user: Serhiy Storchaka date: Mon Jan 20 21:59:33 2014 +0200 summary: Issue #20262: Warnings are raised now when duplicate names are added in the ZIP file or too long ZIP file comment is truncated. files: Lib/test/test_zipfile.py | 9 ++++++--- Lib/zipfile.py | 12 ++++++------ Misc/NEWS | 3 +++ 3 files changed, 15 insertions(+), 9 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 @@ -646,7 +646,7 @@ self.assertTrue('SyntaxError' not in reportStr) # then check that the filter works on individual files - with captured_stdout() as reportSIO: + with captured_stdout() as reportSIO, self.assertWarns(UserWarning): zipfp.writepy(packagedir, filterfunc=lambda fn: 'bad' not in fn) reportStr = reportSIO.getvalue() @@ -896,7 +896,9 @@ # Create the ZIP archive with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: zipfp.writestr("name", "foo") - zipfp.writestr("name", "bar") + with self.assertWarns(UserWarning): + zipfp.writestr("name", "bar") + self.assertEqual(zipfp.namelist(), ["name"] * 2) with zipfile.ZipFile(TESTFN2, "r") as zipfp: infos = zipfp.infolist() @@ -1213,7 +1215,8 @@ # check a comment that is too long is truncated with zipfile.ZipFile(TESTFN, mode="w") as zipf: - zipf.comment = comment2 + b'oops' + with self.assertWarns(UserWarning): + zipf.comment = comment2 + b'oops' zipf.writestr("foo.txt", "O, for a Muse of Fire!") with zipfile.ZipFile(TESTFN, mode="r") as zipfr: self.assertEqual(zipfr.comment, comment2) diff --git a/Lib/zipfile.py b/Lib/zipfile.py --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -1104,10 +1104,10 @@ if not isinstance(comment, bytes): raise TypeError("comment: expected bytes, got %s" % type(comment)) # check for valid comment length - if len(comment) >= ZIP_MAX_COMMENT: - if self.debug: - print('Archive comment is too long; truncating to %d bytes' - % ZIP_MAX_COMMENT) + if len(comment) > ZIP_MAX_COMMENT: + import warnings + warnings.warn('Archive comment is too long; truncating to %d bytes' + % ZIP_MAX_COMMENT, stacklevel=2) comment = comment[:ZIP_MAX_COMMENT] self._comment = comment self._didModify = True @@ -1296,8 +1296,8 @@ def _writecheck(self, zinfo): """Check for errors before writing a file to the archive.""" if zinfo.filename in self.NameToInfo: - if self.debug: # Warning for duplicate names - print("Duplicate name:", zinfo.filename) + import warnings + warnings.warn('Duplicate name: %r' % zinfo.filename, stacklevel=3) if self.mode not in ("w", "a"): raise RuntimeError('write() requires mode "w" or "a"') if not self.fp: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,9 @@ Library ------- +- Issue #20262: Warnings are raised now when duplicate names are added in the + ZIP file or too long ZIP file comment is truncated. + - Issue #20165: The unittest module no longer considers tests marked with @expectedFailure successful if they pass. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 20 23:56:57 2014 From: python-checkins at python.org (victor.stinner) Date: Mon, 20 Jan 2014 23:56:57 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Close_=2320275=3A_Optimize?= =?utf-8?q?_BaseEventLoop=2E=5Frun=5Fonce=28=29?= Message-ID: <3f7Std361lz7Lkc@mail.python.org> http://hg.python.org/cpython/rev/8bb2c3ae9402 changeset: 88591:8bb2c3ae9402 user: Victor Stinner date: Mon Jan 20 23:56:40 2014 +0100 summary: Close #20275: Optimize BaseEventLoop._run_once() Logger.log() is "slow", logger.isEnabledFor() is faster and the logger is disabled in most cases. A microbenchmark executing 100,000 dummy tasks is 22% faster with this change. files: Lib/asyncio/base_events.py | 19 +++++++++++-------- 1 files changed, 11 insertions(+), 8 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 @@ -610,15 +610,18 @@ timeout = min(timeout, deadline) # TODO: Instrumentation only in debug mode? - t0 = self.time() - event_list = self._selector.select(timeout) - t1 = self.time() - argstr = '' if timeout is None else ' {:.3f}'.format(timeout) - if t1-t0 >= 1: - level = logging.INFO + if logger.isEnabledFor(logging.INFO): + t0 = self.time() + event_list = self._selector.select(timeout) + t1 = self.time() + argstr = '' if timeout is None else ' {:.3f}'.format(timeout) + if t1-t0 >= 1: + level = logging.INFO + else: + level = logging.DEBUG + logger.log(level, 'poll%s took %.3f seconds', argstr, t1-t0) else: - level = logging.DEBUG - logger.log(level, 'poll%s took %.3f seconds', argstr, t1-t0) + event_list = self._selector.select(timeout) self._process_events(event_list) # Handle 'later' callbacks that are ready. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 01:43:10 2014 From: python-checkins at python.org (victor.stinner) Date: Tue, 21 Jan 2014 01:43:10 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMzEx?= =?utf-8?q?=3A_select=2Eepoll=2Epoll=28=29_now_rounds_the_timeout_away_fro?= =?utf-8?q?m_zero=2C?= Message-ID: <3f7WFB3XHBz7Ljk@mail.python.org> http://hg.python.org/cpython/rev/033137c12d88 changeset: 88592:033137c12d88 branch: 3.3 parent: 88589:9fda6658c01a user: Victor Stinner date: Tue Jan 21 01:41:00 2014 +0100 summary: Issue #20311: select.epoll.poll() now rounds the timeout away from zero, instead of rounding towards zero. For example, a timeout of one microsecond is now rounded to one millisecond, instead of being rounded to zero. files: Lib/test/test_epoll.py | 11 +++++++++++ Misc/NEWS | 4 ++++ Modules/selectmodule.c | 4 +++- 3 files changed, 18 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_epoll.py b/Lib/test/test_epoll.py --- a/Lib/test/test_epoll.py +++ b/Lib/test/test_epoll.py @@ -46,6 +46,17 @@ self.serverSocket.listen(1) self.connections = [self.serverSocket] + def test_timeout_rounding(self): + # epoll_wait() has a resolution of 1 millisecond, check if the timeout + # is correctly rounded to the upper bound + epoll = select.epoll() + self.addCleanup(epoll.close) + for timeout in (1e-2, 1e-3, 1e-4): + t0 = time.perf_counter() + epoll.poll(timeout) + dt = time.perf_counter() - t0 + self.assertGreaterEqual(dt, timeout) + def tearDown(self): for skt in self.connections: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,10 @@ Library ------- +- Issue #20311: select.epoll.poll() now rounds the timeout away from zero, + instead of rounding towards zero. For example, a timeout of one microsecond + is now rounded to one millisecond, instead of being rounded to zero. + - Issue #20262: Warnings are raised now when duplicate names are added in the ZIP file or too long ZIP file comment is truncated. diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -1379,7 +1379,9 @@ return NULL; } else { - timeout = (int)(dtimeout * 1000.0); + /* epoll_wait() has a resolution of 1 millisecond, round away from zero + to wait *at least* dtimeout seconds. */ + timeout = (int)ceil(dtimeout * 1000.0); } if (maxevents == -1) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 01:43:11 2014 From: python-checkins at python.org (victor.stinner) Date: Tue, 21 Jan 2014 01:43:11 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogKE1lcmdlIDMuMykgSXNzdWUgIzIwMzExOiBzZWxlY3QuZXBvbGwucG9s?= =?utf-8?q?l=28=29_now_rounds_the_timeout_away_from?= Message-ID: <3f7WFC5CjPz7Lk3@mail.python.org> http://hg.python.org/cpython/rev/02f9db3e684e changeset: 88593:02f9db3e684e parent: 88591:8bb2c3ae9402 parent: 88592:033137c12d88 user: Victor Stinner date: Tue Jan 21 01:42:11 2014 +0100 summary: (Merge 3.3) Issue #20311: select.epoll.poll() now rounds the timeout away from zero, instead of rounding towards zero. For example, a timeout of one microsecond is now rounded to one millisecond, instead of being rounded to zero. files: Lib/test/test_epoll.py | 11 +++++++++++ Misc/NEWS | 4 ++++ Modules/selectmodule.c | 4 +++- 3 files changed, 18 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_epoll.py b/Lib/test/test_epoll.py --- a/Lib/test/test_epoll.py +++ b/Lib/test/test_epoll.py @@ -47,6 +47,17 @@ self.serverSocket.listen(1) self.connections = [self.serverSocket] + def test_timeout_rounding(self): + # epoll_wait() has a resolution of 1 millisecond, check if the timeout + # is correctly rounded to the upper bound + epoll = select.epoll() + self.addCleanup(epoll.close) + for timeout in (1e-2, 1e-3, 1e-4): + t0 = time.perf_counter() + epoll.poll(timeout) + dt = time.perf_counter() - t0 + self.assertGreaterEqual(dt, timeout) + def tearDown(self): for skt in self.connections: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,10 @@ Library ------- +- Issue #20311: select.epoll.poll() now rounds the timeout away from zero, + instead of rounding towards zero. For example, a timeout of one microsecond + is now rounded to one millisecond, instead of being rounded to zero. + - Issue #20262: Warnings are raised now when duplicate names are added in the ZIP file or too long ZIP file comment is truncated. diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -1458,7 +1458,9 @@ return NULL; } else { - timeout = (int)(dtimeout * 1000.0); + /* epoll_wait() has a resolution of 1 millisecond, round away from zero + to wait *at least* dtimeout seconds. */ + timeout = (int)ceil(dtimeout * 1000.0); } if (maxevents == -1) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 01:49:20 2014 From: python-checkins at python.org (victor.stinner) Date: Tue, 21 Jan 2014 01:49:20 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320311=3A_selector?= =?utf-8?q?=2EPollSelector=2Eselect=28=29_now_rounds_the_timeout_away_from?= Message-ID: <3f7WNJ4GsBz7LjQ@mail.python.org> http://hg.python.org/cpython/rev/e042ea77a152 changeset: 88594:e042ea77a152 user: Victor Stinner date: Tue Jan 21 01:48:28 2014 +0100 summary: Issue #20311: selector.PollSelector.select() now rounds the timeout away from zero, instead of rounding towards zero. For example, a timeout of one microsecond is now rounded to one millisecond, instead of being rounded to zero. Move also a test in test_epoll which was moved by my previous merge. files: Lib/selectors.py | 8 +++++++- Lib/test/test_epoll.py | 23 +++++++++++------------ Lib/test/test_selectors.py | 18 +++++++++++++++++- Misc/NEWS | 5 +++++ 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/Lib/selectors.py b/Lib/selectors.py --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -8,6 +8,7 @@ from abc import ABCMeta, abstractmethod from collections import namedtuple, Mapping import functools +import math import select import sys @@ -351,7 +352,12 @@ return key def select(self, timeout=None): - timeout = None if timeout is None else max(int(1000 * timeout), 0) + if timeout is None: + timeout = None + elif timeout < 0: + timeout = 0 + else: + timeout = int(math.ceil(timeout * 1000.0)) ready = [] try: fd_event_list = self._poll.poll(timeout) diff --git a/Lib/test/test_epoll.py b/Lib/test/test_epoll.py --- a/Lib/test/test_epoll.py +++ b/Lib/test/test_epoll.py @@ -47,18 +47,6 @@ self.serverSocket.listen(1) self.connections = [self.serverSocket] - def test_timeout_rounding(self): - # epoll_wait() has a resolution of 1 millisecond, check if the timeout - # is correctly rounded to the upper bound - epoll = select.epoll() - self.addCleanup(epoll.close) - for timeout in (1e-2, 1e-3, 1e-4): - t0 = time.perf_counter() - epoll.poll(timeout) - dt = time.perf_counter() - t0 - self.assertGreaterEqual(dt, timeout) - - def tearDown(self): for skt in self.connections: skt.close() @@ -266,6 +254,17 @@ self.addCleanup(epoll.close) self.assertEqual(os.get_inheritable(epoll.fileno()), False) + def test_timeout_rounding(self): + # epoll_wait() has a resolution of 1 millisecond, check if the timeout + # is correctly rounded to the upper bound + epoll = select.epoll() + self.addCleanup(epoll.close) + for timeout in (1e-2, 1e-3, 1e-4): + t0 = time.perf_counter() + epoll.poll(timeout) + dt = time.perf_counter() - t0 + self.assertGreaterEqual(dt, timeout) + def test_main(): support.run_unittest(TestEPoll) 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,7 +5,7 @@ import signal import socket from test import support -from time import sleep +from time import sleep, perf_counter import unittest import unittest.mock try: @@ -363,6 +363,22 @@ self.assertFalse(s.select(2)) self.assertLess(time() - t, 2.5) + def test_timeout_rounding(self): + # Issue #20311: Timeout must be rounded away from zero to wait *at + # least* timeout seconds. For example, epoll_wait() has a resolution of + # 1 ms (10^-3), epoll.select(0.0001) must wait 1 ms, not 0 ms. + s = self.SELECTOR() + self.addCleanup(s.close) + + rd, wr = self.make_socketpair() + s.register(rd, selectors.EVENT_READ) + + for timeout in (1e-2, 1e-3, 1e-4): + t0 = perf_counter() + s.select(timeout) + dt = perf_counter() - t0 + self.assertGreaterEqual(dt, timeout) + class ScalableSelectorMixIn: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,11 @@ Library ------- +- Issue #20311: selector.PollSelector.select() now rounds the timeout away from + zero, instead of rounding towards zero. For example, a timeout of one + microsecond is now rounded to one millisecond, instead of being rounded to + zero. + - Issue #20311: select.epoll.poll() now rounds the timeout away from zero, instead of rounding towards zero. For example, a timeout of one microsecond is now rounded to one millisecond, instead of being rounded to zero. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 02:38:50 2014 From: python-checkins at python.org (victor.stinner) Date: Tue, 21 Jan 2014 02:38:50 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMzEx?= =?utf-8?q?=3A_Try_to_fix_the_unit_test=2C_use_time=2Emonotonic=28=29_inst?= =?utf-8?q?ead_of?= Message-ID: <3f7XTQ5zXRz7LjW@mail.python.org> http://hg.python.org/cpython/rev/e1619465c49d changeset: 88595:e1619465c49d branch: 3.3 parent: 88592:033137c12d88 user: Victor Stinner date: Tue Jan 21 02:37:41 2014 +0100 summary: Issue #20311: Try to fix the unit test, use time.monotonic() instead of time.perf_counter() Move also the unit test at the end. files: Lib/test/test_epoll.py | 24 ++++++++++++------------ 1 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_epoll.py b/Lib/test/test_epoll.py --- a/Lib/test/test_epoll.py +++ b/Lib/test/test_epoll.py @@ -46,18 +46,6 @@ self.serverSocket.listen(1) self.connections = [self.serverSocket] - def test_timeout_rounding(self): - # epoll_wait() has a resolution of 1 millisecond, check if the timeout - # is correctly rounded to the upper bound - epoll = select.epoll() - self.addCleanup(epoll.close) - for timeout in (1e-2, 1e-3, 1e-4): - t0 = time.perf_counter() - epoll.poll(timeout) - dt = time.perf_counter() - t0 - self.assertGreaterEqual(dt, timeout) - - def tearDown(self): for skt in self.connections: skt.close() @@ -229,6 +217,18 @@ server.close() ep.unregister(fd) + def test_timeout_rounding(self): + # epoll_wait() has a resolution of 1 millisecond, check if the timeout + # is correctly rounded to the upper bound + epoll = select.epoll() + self.addCleanup(epoll.close) + for timeout in (1e-2, 1e-3, 1e-4): + t0 = time.monotonic() + epoll.poll(timeout) + dt = time.monotonic() - t0 + self.assertGreaterEqual(dt, timeout) + + def test_main(): support.run_unittest(TestEPoll) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 02:38:52 2014 From: python-checkins at python.org (victor.stinner) Date: Tue, 21 Jan 2014 02:38:52 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_=28Merge_3=2E3=29_Issue_=2320311=3A_Try_to_fix_the_unit_?= =?utf-8?q?test=2C_use_time=2Emonotonic=28=29?= Message-ID: <3f7XTS0HTxz7Lk3@mail.python.org> http://hg.python.org/cpython/rev/26c54e9a933b changeset: 88596:26c54e9a933b parent: 88594:e042ea77a152 parent: 88595:e1619465c49d user: Victor Stinner date: Tue Jan 21 02:38:33 2014 +0100 summary: (Merge 3.3) Issue #20311: Try to fix the unit test, use time.monotonic() instead of time.perf_counter() files: Lib/test/test_epoll.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_epoll.py b/Lib/test/test_epoll.py --- a/Lib/test/test_epoll.py +++ b/Lib/test/test_epoll.py @@ -260,9 +260,9 @@ epoll = select.epoll() self.addCleanup(epoll.close) for timeout in (1e-2, 1e-3, 1e-4): - t0 = time.perf_counter() + t0 = time.monotonic() epoll.poll(timeout) - dt = time.perf_counter() - t0 + dt = time.monotonic() - t0 self.assertGreaterEqual(dt, timeout) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 02:54:01 2014 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 21 Jan 2014 02:54:01 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_the_description_of_pic?= =?utf-8?q?kle_protocol_numbers?= Message-ID: <3f7Xpx4R5rz7LjW@mail.python.org> http://hg.python.org/cpython/rev/0bcf1669912a changeset: 88597:0bcf1669912a user: Antoine Pitrou date: Tue Jan 21 02:39:54 2014 +0100 summary: Fix the description of pickle protocol numbers files: Doc/library/pickle.rst | 39 ++++++++++-------------------- 1 files changed, 13 insertions(+), 26 deletions(-) diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -116,7 +116,9 @@ generated by :mod:`pickle`. :mod:`pickletools` source code has extensive comments about opcodes used by pickle protocols. -There are currently 4 different protocols which can be used for pickling. +There are currently 5 different protocols which can be used for pickling. +The higher the protocol used, the more recent the version of Python needed +to read the pickle produced. * Protocol version 0 is the original "human-readable" protocol and is backwards compatible with earlier versions of Python. @@ -184,13 +186,10 @@ Write a pickled representation of *obj* to the open :term:`file object` *file*. This is equivalent to ``Pickler(file, protocol).dump(obj)``. - The optional *protocol* argument tells the pickler to use the given - protocol; supported protocols are 0, 1, 2, 3. The default protocol is 3; a - backward-incompatible protocol designed for Python 3. - - Specifying a negative protocol version selects the highest protocol version - supported. The higher the protocol used, the more recent the version of - Python needed to read the pickle produced. + The optional *protocol* argument, an integer, tells the pickler to use + the given protocol; supported protocols are 0 to :data:`HIGHEST_PROTOCOL`. + If not specified, the default is :data:`DEFAULT_PROTOCOL`. If a negative + number is specified, :data:`HIGHEST_PROTOCOL` is selected. The *file* argument must have a write() method that accepts a single bytes argument. It can thus be an on-disk file opened for binary writing, a @@ -206,17 +205,8 @@ Return the pickled representation of the object as a :class:`bytes` object, instead of writing it to a file. - The optional *protocol* argument tells the pickler to use the given - protocol; supported protocols are 0, 1, 2, 3 and 4. The default protocol - is 3; a backward-incompatible protocol designed for Python 3. - - Specifying a negative protocol version selects the highest protocol version - supported. The higher the protocol used, the more recent the version of - Python needed to read the pickle produced. - - If *fix_imports* is true and *protocol* is less than 3, pickle will try to - map the new Python 3 names to the old module names used in Python 2, so - that the pickle data stream is readable with Python 2. + Arguments *protocol* and *fix_imports* have the same meaning as in + :func:`dump`. .. function:: load(file, \*, fix_imports=True, encoding="ASCII", errors="strict") @@ -292,13 +282,10 @@ This takes a binary file for writing a pickle data stream. - The optional *protocol* argument tells the pickler to use the given - protocol; supported protocols are 0, 1, 2, 3 and 4. The default protocol - is 3; a backward-incompatible protocol designed for Python 3. - - Specifying a negative protocol version selects the highest protocol version - supported. The higher the protocol used, the more recent the version of - Python needed to read the pickle produced. + The optional *protocol* argument, an integer, tells the pickler to use + the given protocol; supported protocols are 0 to :data:`HIGHEST_PROTOCOL`. + If not specified, the default is :data:`DEFAULT_PROTOCOL`. If a negative + number is specified, :data:`HIGHEST_PROTOCOL` is selected. The *file* argument must have a write() method that accepts a single bytes argument. It can thus be an on-disk file opened for binary writing, a -- Repository URL: http://hg.python.org/cpython From root at python.org Tue Jan 21 05:51:44 2014 From: root at python.org (Cron Daemon) Date: Tue, 21 Jan 2014 05:51:44 +0100 Subject: [Python-checkins] Cron /home/docs/build-devguide (failed) Message-ID: killed! From python-checkins at python.org Tue Jan 21 06:02:38 2014 From: python-checkins at python.org (terry.reedy) Date: Tue, 21 Jan 2014 06:02:38 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMjIy?= =?utf-8?q?=3A_file_is_no_longer_a_builtin_in_3=2Ex=2E?= Message-ID: <3f7d0Z4rCWz7LjR@mail.python.org> http://hg.python.org/cpython/rev/36c9a233ebf0 changeset: 88598:36c9a233ebf0 branch: 3.3 parent: 88595:e1619465c49d user: Terry Jan Reedy date: Tue Jan 21 00:01:51 2014 -0500 summary: Issue #20222: file is no longer a builtin in 3.x. files: Doc/library/unittest.mock-examples.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst --- a/Doc/library/unittest.mock-examples.rst +++ b/Doc/library/unittest.mock-examples.rst @@ -462,7 +462,7 @@ we are only interested in the return value from the final call to `start_call` so we don't have much configuration to do. Let's assume the object it returns is 'file-like', so we'll ensure that our response object -uses the builtin `file` as its `spec`. +uses the builtin `open` as its `spec`. To do this we create a mock instance as our mock backend and create a mock response object for it. To set the response as the return value for that final @@ -474,7 +474,7 @@ method to directly set the return value for us: >>> something = Something() - >>> mock_response = Mock(spec=file) + >>> mock_response = Mock(spec=open) >>> mock_backend = Mock() >>> config = {'get_endpoint.return_value.create_call.return_value.start_call.return_value': mock_response} >>> mock_backend.configure_mock(**config) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 06:02:39 2014 From: python-checkins at python.org (terry.reedy) Date: Tue, 21 Jan 2014 06:02:39 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E3?= Message-ID: <3f7d0b6dCbz7Lkl@mail.python.org> http://hg.python.org/cpython/rev/0376c5103a03 changeset: 88599:0376c5103a03 parent: 88597:0bcf1669912a parent: 88598:36c9a233ebf0 user: Terry Jan Reedy date: Tue Jan 21 00:02:17 2014 -0500 summary: Merge with 3.3 files: Doc/library/unittest.mock-examples.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst --- a/Doc/library/unittest.mock-examples.rst +++ b/Doc/library/unittest.mock-examples.rst @@ -476,7 +476,7 @@ we are only interested in the return value from the final call to `start_call` so we don't have much configuration to do. Let's assume the object it returns is 'file-like', so we'll ensure that our response object -uses the builtin `file` as its `spec`. +uses the builtin `open` as its `spec`. To do this we create a mock instance as our mock backend and create a mock response object for it. To set the response as the return value for that final @@ -488,7 +488,7 @@ method to directly set the return value for us: >>> something = Something() - >>> mock_response = Mock(spec=file) + >>> mock_response = Mock(spec=open) >>> mock_backend = Mock() >>> config = {'get_endpoint.return_value.create_call.return_value.start_call.return_value': mock_response} >>> mock_backend.configure_mock(**config) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 06:31:31 2014 From: python-checkins at python.org (terry.reedy) Date: Tue, 21 Jan 2014 06:31:31 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIwMTIy?= =?utf-8?q?=3A_Idlelib=3A_Move_tests_in_3=2Ex_CallTips=2Epy_to_test=5Fcall?= =?utf-8?q?tips=2Epy=2E?= Message-ID: <3f7ddv08ldz7Ljp@mail.python.org> http://hg.python.org/cpython/rev/f6f2d9d04cd0 changeset: 88600:f6f2d9d04cd0 branch: 2.7 parent: 88588:208fa45672c2 user: Terry Jan Reedy date: Tue Jan 21 00:26:10 2014 -0500 summary: Issue #20122: Idlelib: Move tests in 3.x CallTips.py to test_calltips.py. For 2.7 backport, fix get_arg_spec as needed to make expanded tests pass. files: Lib/idlelib/CallTips.py | 67 +------ Lib/idlelib/idle_test/test_calltips.py | 102 ++++++++++++- 2 files changed, 114 insertions(+), 55 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -143,10 +143,15 @@ fob = lambda: None else: arg_offset = 1 - elif type(ob)==types.MethodType: + elif type(ob) == types.MethodType: # bit of a hack for methods - turn it into a function - # but we drop the "self" param. + # and drop the "self" param for bound methods fob = ob.im_func + if ob.im_self: + arg_offset = 1 + elif type(ob.__call__) == types.MethodType: + # a callable class instance + fob = ob.__call__.im_func arg_offset = 1 else: fob = ob @@ -159,13 +164,16 @@ defaults = [""] * (len(real_args) - len(defaults)) + defaults items = map(lambda arg, dflt: arg + dflt, real_args, defaults) if fob.func_code.co_flags & 0x4: - items.append("...") + items.append("*args") if fob.func_code.co_flags & 0x8: - items.append("***") + items.append("**kwds") arg_text = ", ".join(items) arg_text = "(%s)" % re.sub("(?", arg_text) # See if we can use the docstring - doc = getattr(ob, "__doc__", "") + if isinstance(ob.__call__, types.MethodType): + doc = ob.__call__.__doc__ + else: + doc = getattr(ob, "__doc__", "") if doc: doc = doc.lstrip() pos = doc.find("\n") @@ -176,53 +184,6 @@ arg_text += doc[:pos] return arg_text -################################################# -# -# Test code -# -if __name__=='__main__': - - def t1(): "()" - def t2(a, b=None): "(a, b=None)" - def t3(a, *args): "(a, ...)" - def t4(*args): "(...)" - def t5(a, *args): "(a, ...)" - def t6(a, b=None, *args, **kw): "(a, b=None, ..., ***)" - def t7((a, b), c, (d, e)): "(, c, )" - - class TC(object): - "(ai=None, ...)" - def __init__(self, ai=None, *b): "(ai=None, ...)" - def t1(self): "()" - def t2(self, ai, b=None): "(ai, b=None)" - def t3(self, ai, *args): "(ai, ...)" - def t4(self, *args): "(...)" - def t5(self, ai, *args): "(ai, ...)" - def t6(self, ai, b=None, *args, **kw): "(ai, b=None, ..., ***)" - def t7(self, (ai, b), c, (d, e)): "(, c, )" - - def test(tests): - ct = CallTips() - failed=[] - for t in tests: - expected = t.__doc__ + "\n" + t.__doc__ - name = t.__name__ - # exercise fetch_tip(), not just get_arg_text() - try: - qualified_name = "%s.%s" % (t.im_class.__name__, name) - except AttributeError: - qualified_name = name - arg_text = ct.fetch_tip(qualified_name) - if arg_text != expected: - failed.append(t) - fmt = "%s - expected %s, but got %s" - print fmt % (t.__name__, expected, get_arg_text(t)) - print "%d of %d tests failed" % (len(failed), len(tests)) - - tc = TC() - tests = (t1, t2, t3, t4, t5, t6, t7, - TC, tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6, tc.t7) - - # test(tests) +if __name__ == '__main__': from unittest import main main('idlelib.idle_test.test_calltips', verbosity=2, exit=False) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -1,6 +1,104 @@ import unittest import idlelib.CallTips as ct -CTi = ct.CallTips() +CTi = ct.CallTips() # needed for get_entity test in 2.7 +import types + + +# Test Class TC is used in multiple get_argspec test methods +class TC(object): + 'doc' + tip = "(ai=None, *args)" + def __init__(self, ai=None, *b): 'doc' + __init__.tip = "(self, ai=None, *args)" + def t1(self): 'doc' + t1.tip = "(self)" + def t2(self, ai, b=None): 'doc' + t2.tip = "(self, ai, b=None)" + def t3(self, ai, *args): 'doc' + t3.tip = "(self, ai, *args)" + def t4(self, *args): 'doc' + t4.tip = "(self, *args)" + def t5(self, ai, b=None, *args, **kw): 'doc' + t5.tip = "(self, ai, b=None, *args, **kwds)" + def t6(no, self): 'doc' + t6.tip = "(no, self)" + def __call__(self, ci): 'doc' + __call__.tip = "(self, ci)" + # attaching .tip to wrapped methods does not work + @classmethod + def cm(cls, a): 'doc' + @staticmethod + def sm(b): 'doc' + +tc = TC() + +signature = ct.get_arg_text # 2.7 and 3.x use different functions +class Get_signatureTest(unittest.TestCase): + + def test_builtins(self): + # 2.7 puts '()\n' where 3.x does not, other minor differences + + # Python class that inherits builtin methods + class List(list): "List() doc" + # Simulate builtin with no docstring for default argspec test + class SB: __call__ = None + + def gtest(obj, out): + self.assertEqual(signature(obj), out) + + gtest(list, "()\nlist() -> new empty list") + gtest(List, '()\n' + List.__doc__) + gtest(list.__new__, + 'T.__new__(S, ...) -> a new object with type S, a subtype of T') + gtest(list.__init__, + 'x.__init__(...) initializes x; see help(type(x)) for signature') + append_doc = "L.append(object) -- append object to end" + gtest(list.append, append_doc) + gtest([].append, append_doc) + gtest(List.append, append_doc) + + gtest(types.MethodType, '()\ninstancemethod(function, instance, class)') + gtest(SB(), '') + + + def test_functions(self): + def t1(): 'doc' + t1.tip = "()" + def t2(a, b=None): 'doc' + t2.tip = "(a, b=None)" + def t3(a, *args): 'doc' + t3.tip = "(a, *args)" + def t4(*args): 'doc' + t4.tip = "(*args)" + def t5(a, b=None, *args, **kwds): 'doc' + t5.tip = "(a, b=None, *args, **kwds)" + + for func in (t1, t2, t3, t4, t5, TC): + self.assertEqual(signature(func), func.tip + '\ndoc') + + def test_methods(self): + for meth in (TC.t1, TC.t2, TC.t3, TC.t4, TC.t5, TC.t6, TC.__call__): + self.assertEqual(signature(meth), meth.tip + "\ndoc") + self.assertEqual(signature(TC.cm), "(a)\ndoc") + self.assertEqual(signature(TC.sm), "(b)\ndoc") + + def test_bound_methods(self): + # test that first parameter is correctly removed from argspec + for meth, mtip in ((tc.t1, "()"), (tc.t4, "(*args)"), (tc.t6, "(self)"), + (TC.cm, "(a)"),): + self.assertEqual(signature(meth), mtip + "\ndoc") + self.assertEqual(signature(tc), "(ci)\ndoc") + + def test_no_docstring(self): + def nd(s): pass + TC.nd = nd + self.assertEqual(signature(nd), "(s)") + self.assertEqual(signature(TC.nd), "(s)") + self.assertEqual(signature(tc.nd), "()") + + def test_non_callables(self): + for obj in (0, 0.0, '0', b'0', [], {}): + self.assertEqual(signature(obj), '') class Get_entityTest(unittest.TestCase): # In 3.x, get_entity changed from 'instance method' to module function @@ -14,7 +112,7 @@ def test_paramtuple_float(self): # 18539: (a,b) becomes '.0' in code object; change that but not float def f((a,b), c=0.0): pass - self.assertEqual(ct.get_arg_text(f), '(, c=0.0)') + self.assertEqual(signature(f), '(, c=0.0)') if __name__ == '__main__': unittest.main(verbosity=2, exit=False) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 06:31:32 2014 From: python-checkins at python.org (terry.reedy) Date: Tue, 21 Jan 2014 06:31:32 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMTIy?= =?utf-8?q?=3A_Idlelib=3A_Move_tests_in_CallTips=2Epy_to_test=5Fcalltips?= =?utf-8?q?=2Epy=2E?= Message-ID: <3f7ddw2cYJz7Llr@mail.python.org> http://hg.python.org/cpython/rev/7befcc353d40 changeset: 88601:7befcc353d40 branch: 3.3 parent: 88598:36c9a233ebf0 user: Terry Jan Reedy date: Tue Jan 21 00:26:21 2014 -0500 summary: Issue #20122: Idlelib: Move tests in CallTips.py to test_calltips.py. files: Lib/idlelib/CallTips.py | 105 ------------- Lib/idlelib/idle_test/test_calltips.py | 100 ++++++++++++ 2 files changed, 100 insertions(+), 105 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -159,111 +159,6 @@ argspec = _default_callable_argspec return argspec -################################################# -# -# Test code tests CallTips.fetch_tip, get_entity, and get_argspec - -def main(): - # Putting expected in docstrings results in doubled tips for test - def t1(): "()" - def t2(a, b=None): "(a, b=None)" - def t3(a, *args): "(a, *args)" - def t4(*args): "(*args)" - def t5(a, b=None, *args, **kw): "(a, b=None, *args, **kw)" - - class TC(object): - "(ai=None, *b)" - def __init__(self, ai=None, *b): "(self, ai=None, *b)" - def t1(self): "(self)" - def t2(self, ai, b=None): "(self, ai, b=None)" - def t3(self, ai, *args): "(self, ai, *args)" - def t4(self, *args): "(self, *args)" - def t5(self, ai, b=None, *args, **kw): "(self, ai, b=None, *args, **kw)" - def t6(no, self): "(no, self)" - @classmethod - def cm(cls, a): "(cls, a)" - @staticmethod - def sm(b): "(b)" - def __call__(self, ci): "(self, ci)" - - tc = TC() - - # Python classes that inherit builtin methods - class Int(int): "Int(x[, base]) -> integer" - class List(list): "List() -> new empty list" - # Simulate builtin with no docstring for default argspec test - class SB: __call__ = None - - __main__.__dict__.update(locals()) # required for get_entity eval() - - num_tests = num_fail = 0 - tip = CallTips().fetch_tip - - def test(expression, expected): - nonlocal num_tests, num_fail - num_tests += 1 - argspec = tip(expression) - if argspec != expected: - num_fail += 1 - fmt = "%s - expected\n%r\n - but got\n%r" - print(fmt % (expression, expected, argspec)) - - def test_builtins(): - # if first line of a possibly multiline compiled docstring changes, - # must change corresponding test string - test('int', "int(x=0) -> integer") - test('Int', Int.__doc__) - test('types.MethodType', "method(function, instance)") - test('list', "list() -> new empty list") - test('List', List.__doc__) - test('list.__new__', - 'T.__new__(S, ...) -> a new object with type S, a subtype of T') - test('list.__init__', - 'x.__init__(...) initializes x; see help(type(x)) for signature') - append_doc = "L.append(object) -> None -- append object to end" - test('list.append', append_doc) - test('[].append', append_doc) - test('List.append', append_doc) - test('SB()', _default_callable_argspec) - - def test_funcs(): - for func in (t1, t2, t3, t4, t5, TC,): - fdoc = func.__doc__ - test(func.__name__, fdoc + "\n" + fdoc) - for func in (TC.t1, TC.t2, TC.t3, TC.t4, TC.t5, TC.t6, TC.sm, - TC.__call__): - fdoc = func.__doc__ - test('TC.'+func.__name__, fdoc + "\n" + fdoc) - fdoc = TC.cm.__func__.__doc__ - test('TC.cm.__func__', fdoc + "\n" + fdoc) - - def test_methods(): - # test that first parameter is correctly removed from argspec - # using _first_param re to calculate expected masks re errors - for meth, mdoc in ((tc.t1, "()"), (tc.t4, "(*args)"), (tc.t6, "(self)"), - (TC.cm, "(a)"),): - test('tc.'+meth.__name__, mdoc + "\n" + meth.__doc__) - test('tc', "(ci)" + "\n" + tc.__call__.__doc__) - # directly test that re works to delete unicode parameter name - uni = "(A\u0391\u0410\u05d0\u0627\u0905\u1e00\u3042, a)" # various As - assert _first_param.sub('', uni) == '(a)' - - def test_non_callables(): - # expression evaluates, but not to a callable - for expr in ('0', '0.0' 'num_tests', b'num_tests', '[]', '{}'): - test(expr, '') - # expression does not evaluate, but raises an exception - for expr in ('1a', 'xyx', 'num_tests.xyz', '[int][1]', '{0:int}[1]'): - test(expr, '') - - test_builtins() - test_funcs() - test_non_callables() - test_methods() - - print("%d of %d tests failed" % (num_fail, num_tests)) - if __name__ == '__main__': - #main() from unittest import main main('idlelib.idle_test.test_calltips', verbosity=2, exit=False) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -1,5 +1,105 @@ import unittest import idlelib.CallTips as ct +import types + + +# Test Class TC is used in multiple get_argspec test methods +class TC(): + 'doc' + tip = "(ai=None, *b)" + def __init__(self, ai=None, *b): 'doc' + __init__.tip = "(self, ai=None, *b)" + def t1(self): 'doc' + t1.tip = "(self)" + def t2(self, ai, b=None): 'doc' + t2.tip = "(self, ai, b=None)" + def t3(self, ai, *args): 'doc' + t3.tip = "(self, ai, *args)" + def t4(self, *args): 'doc' + t4.tip = "(self, *args)" + def t5(self, ai, b=None, *args, **kw): 'doc' + t5.tip = "(self, ai, b=None, *args, **kw)" + def t6(no, self): 'doc' + t6.tip = "(no, self)" + def __call__(self, ci): 'doc' + __call__.tip = "(self, ci)" + # attaching .tip to wrapped methods does not work + @classmethod + def cm(cls, a): 'doc' + @staticmethod + def sm(b): 'doc' + +tc = TC() + +signature = ct.get_argspec # 2.7 and 3.x use different functions +class Get_signatureTest(unittest.TestCase): + + def test_builtins(self): + # Python class that inherits builtin methods + class List(list): "List() doc" + # Simulate builtin with no docstring for default argspec test + class SB: __call__ = None + + def gtest(obj, out): + self.assertEqual(signature(obj), out) + + gtest(list, "list() -> new empty list") + gtest(List, List.__doc__) + gtest(list.__new__, + 'T.__new__(S, ...) -> a new object with type S, a subtype of T') + gtest(list.__init__, + 'x.__init__(...) initializes x; see help(type(x)) for signature') + append_doc = "L.append(object) -> None -- append object to end" + gtest(list.append, append_doc) + gtest([].append, append_doc) + gtest(List.append, append_doc) + + gtest(types.MethodType, "method(function, instance)") + gtest(SB(), ct._default_callable_argspec) + + def test_functions(self): + def t1(): 'doc' + t1.tip = "()" + def t2(a, b=None): 'doc' + t2.tip = "(a, b=None)" + def t3(a, *args): 'doc' + t3.tip = "(a, *args)" + def t4(*args): 'doc' + t4.tip = "(*args)" + def t5(a, b=None, *args, **kw): 'doc' + t5.tip = "(a, b=None, *args, **kw)" + + for func in (t1, t2, t3, t4, t5, TC): + self.assertEqual(signature(func), func.tip + '\ndoc') + + def test_methods(self): + for meth in (TC.t1, TC.t2, TC.t3, TC.t4, TC.t5, TC.t6, TC.__call__): + self.assertEqual(signature(meth), meth.tip + "\ndoc") + self.assertEqual(signature(TC.cm), "(a)\ndoc") + self.assertEqual(signature(TC.sm), "(b)\ndoc") + + def test_bound_methods(self): + # test that first parameter is correctly removed from argspec + # using _first_param re to calculate expected masks re errors + for meth, mtip in ((tc.t1, "()"), (tc.t4, "(*args)"), (tc.t6, "(self)"), + (TC.cm, "(a)"),): + self.assertEqual(signature(meth), mtip + "\ndoc") + self.assertEqual(signature(tc), "(ci)\ndoc") + # directly test that re works to delete first parameter even when it + # non-ascii chars, such as various forms of A. + uni = "(A\u0391\u0410\u05d0\u0627\u0905\u1e00\u3042, a)" + assert ct._first_param.sub('', uni) == '(a)' + + def test_no_docstring(self): + def nd(s): pass + TC.nd = nd + self.assertEqual(signature(nd), "(s)") + self.assertEqual(signature(TC.nd), "(s)") + self.assertEqual(signature(tc.nd), "()") + + def test_non_callables(self): + for obj in (0, 0.0, '0', b'0', [], {}): + self.assertEqual(signature(obj), '') class Get_entityTest(unittest.TestCase): def test_bad_entity(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 06:31:33 2014 From: python-checkins at python.org (terry.reedy) Date: Tue, 21 Jan 2014 06:31:33 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E3?= Message-ID: <3f7ddx6CTjz7Llk@mail.python.org> http://hg.python.org/cpython/rev/5b497ccfd4af changeset: 88602:5b497ccfd4af parent: 88599:0376c5103a03 parent: 88601:7befcc353d40 user: Terry Jan Reedy date: Tue Jan 21 00:26:49 2014 -0500 summary: Merge with 3.3 files: Lib/idlelib/CallTips.py | 105 ------------- Lib/idlelib/idle_test/test_calltips.py | 100 ++++++++++++ 2 files changed, 100 insertions(+), 105 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -159,111 +159,6 @@ argspec = _default_callable_argspec return argspec -################################################# -# -# Test code tests CallTips.fetch_tip, get_entity, and get_argspec - -def main(): - # Putting expected in docstrings results in doubled tips for test - def t1(): "()" - def t2(a, b=None): "(a, b=None)" - def t3(a, *args): "(a, *args)" - def t4(*args): "(*args)" - def t5(a, b=None, *args, **kw): "(a, b=None, *args, **kw)" - - class TC(object): - "(ai=None, *b)" - def __init__(self, ai=None, *b): "(self, ai=None, *b)" - def t1(self): "(self)" - def t2(self, ai, b=None): "(self, ai, b=None)" - def t3(self, ai, *args): "(self, ai, *args)" - def t4(self, *args): "(self, *args)" - def t5(self, ai, b=None, *args, **kw): "(self, ai, b=None, *args, **kw)" - def t6(no, self): "(no, self)" - @classmethod - def cm(cls, a): "(cls, a)" - @staticmethod - def sm(b): "(b)" - def __call__(self, ci): "(self, ci)" - - tc = TC() - - # Python classes that inherit builtin methods - class Int(int): "Int(x[, base]) -> integer" - class List(list): "List() -> new empty list" - # Simulate builtin with no docstring for default argspec test - class SB: __call__ = None - - __main__.__dict__.update(locals()) # required for get_entity eval() - - num_tests = num_fail = 0 - tip = CallTips().fetch_tip - - def test(expression, expected): - nonlocal num_tests, num_fail - num_tests += 1 - argspec = tip(expression) - if argspec != expected: - num_fail += 1 - fmt = "%s - expected\n%r\n - but got\n%r" - print(fmt % (expression, expected, argspec)) - - def test_builtins(): - # if first line of a possibly multiline compiled docstring changes, - # must change corresponding test string - test('int', "int(x=0) -> integer") - test('Int', Int.__doc__) - test('types.MethodType', "method(function, instance)") - test('list', "list() -> new empty list") - test('List', List.__doc__) - test('list.__new__', - 'T.__new__(S, ...) -> a new object with type S, a subtype of T') - test('list.__init__', - 'x.__init__(...) initializes x; see help(type(x)) for signature') - append_doc = "L.append(object) -> None -- append object to end" - test('list.append', append_doc) - test('[].append', append_doc) - test('List.append', append_doc) - test('SB()', _default_callable_argspec) - - def test_funcs(): - for func in (t1, t2, t3, t4, t5, TC,): - fdoc = func.__doc__ - test(func.__name__, fdoc + "\n" + fdoc) - for func in (TC.t1, TC.t2, TC.t3, TC.t4, TC.t5, TC.t6, TC.sm, - TC.__call__): - fdoc = func.__doc__ - test('TC.'+func.__name__, fdoc + "\n" + fdoc) - fdoc = TC.cm.__func__.__doc__ - test('TC.cm.__func__', fdoc + "\n" + fdoc) - - def test_methods(): - # test that first parameter is correctly removed from argspec - # using _first_param re to calculate expected masks re errors - for meth, mdoc in ((tc.t1, "()"), (tc.t4, "(*args)"), (tc.t6, "(self)"), - (TC.cm, "(a)"),): - test('tc.'+meth.__name__, mdoc + "\n" + meth.__doc__) - test('tc', "(ci)" + "\n" + tc.__call__.__doc__) - # directly test that re works to delete unicode parameter name - uni = "(A\u0391\u0410\u05d0\u0627\u0905\u1e00\u3042, a)" # various As - assert _first_param.sub('', uni) == '(a)' - - def test_non_callables(): - # expression evaluates, but not to a callable - for expr in ('0', '0.0' 'num_tests', b'num_tests', '[]', '{}'): - test(expr, '') - # expression does not evaluate, but raises an exception - for expr in ('1a', 'xyx', 'num_tests.xyz', '[int][1]', '{0:int}[1]'): - test(expr, '') - - test_builtins() - test_funcs() - test_non_callables() - test_methods() - - print("%d of %d tests failed" % (num_fail, num_tests)) - if __name__ == '__main__': - #main() from unittest import main main('idlelib.idle_test.test_calltips', verbosity=2, exit=False) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -1,5 +1,105 @@ import unittest import idlelib.CallTips as ct +import types + + +# Test Class TC is used in multiple get_argspec test methods +class TC(): + 'doc' + tip = "(ai=None, *b)" + def __init__(self, ai=None, *b): 'doc' + __init__.tip = "(self, ai=None, *b)" + def t1(self): 'doc' + t1.tip = "(self)" + def t2(self, ai, b=None): 'doc' + t2.tip = "(self, ai, b=None)" + def t3(self, ai, *args): 'doc' + t3.tip = "(self, ai, *args)" + def t4(self, *args): 'doc' + t4.tip = "(self, *args)" + def t5(self, ai, b=None, *args, **kw): 'doc' + t5.tip = "(self, ai, b=None, *args, **kw)" + def t6(no, self): 'doc' + t6.tip = "(no, self)" + def __call__(self, ci): 'doc' + __call__.tip = "(self, ci)" + # attaching .tip to wrapped methods does not work + @classmethod + def cm(cls, a): 'doc' + @staticmethod + def sm(b): 'doc' + +tc = TC() + +signature = ct.get_argspec # 2.7 and 3.x use different functions +class Get_signatureTest(unittest.TestCase): + + def test_builtins(self): + # Python class that inherits builtin methods + class List(list): "List() doc" + # Simulate builtin with no docstring for default argspec test + class SB: __call__ = None + + def gtest(obj, out): + self.assertEqual(signature(obj), out) + + gtest(list, "list() -> new empty list") + gtest(List, List.__doc__) + gtest(list.__new__, + 'T.__new__(S, ...) -> a new object with type S, a subtype of T') + gtest(list.__init__, + 'x.__init__(...) initializes x; see help(type(x)) for signature') + append_doc = "L.append(object) -> None -- append object to end" + gtest(list.append, append_doc) + gtest([].append, append_doc) + gtest(List.append, append_doc) + + gtest(types.MethodType, "method(function, instance)") + gtest(SB(), ct._default_callable_argspec) + + def test_functions(self): + def t1(): 'doc' + t1.tip = "()" + def t2(a, b=None): 'doc' + t2.tip = "(a, b=None)" + def t3(a, *args): 'doc' + t3.tip = "(a, *args)" + def t4(*args): 'doc' + t4.tip = "(*args)" + def t5(a, b=None, *args, **kw): 'doc' + t5.tip = "(a, b=None, *args, **kw)" + + for func in (t1, t2, t3, t4, t5, TC): + self.assertEqual(signature(func), func.tip + '\ndoc') + + def test_methods(self): + for meth in (TC.t1, TC.t2, TC.t3, TC.t4, TC.t5, TC.t6, TC.__call__): + self.assertEqual(signature(meth), meth.tip + "\ndoc") + self.assertEqual(signature(TC.cm), "(a)\ndoc") + self.assertEqual(signature(TC.sm), "(b)\ndoc") + + def test_bound_methods(self): + # test that first parameter is correctly removed from argspec + # using _first_param re to calculate expected masks re errors + for meth, mtip in ((tc.t1, "()"), (tc.t4, "(*args)"), (tc.t6, "(self)"), + (TC.cm, "(a)"),): + self.assertEqual(signature(meth), mtip + "\ndoc") + self.assertEqual(signature(tc), "(ci)\ndoc") + # directly test that re works to delete first parameter even when it + # non-ascii chars, such as various forms of A. + uni = "(A\u0391\u0410\u05d0\u0627\u0905\u1e00\u3042, a)" + assert ct._first_param.sub('', uni) == '(a)' + + def test_no_docstring(self): + def nd(s): pass + TC.nd = nd + self.assertEqual(signature(nd), "(s)") + self.assertEqual(signature(TC.nd), "(s)") + self.assertEqual(signature(tc.nd), "()") + + def test_non_callables(self): + for obj in (0, 0.0, '0', b'0', [], {}): + self.assertEqual(signature(obj), '') class Get_entityTest(unittest.TestCase): def test_bad_entity(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 06:31:35 2014 From: python-checkins at python.org (terry.reedy) Date: Tue, 21 Jan 2014 06:31:35 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIxMjIy?= =?utf-8?q?=3A_Whitespace?= Message-ID: <3f7ddz0rBfz7Llk@mail.python.org> http://hg.python.org/cpython/rev/649a3e6ce92e changeset: 88603:649a3e6ce92e branch: 2.7 parent: 88600:f6f2d9d04cd0 user: Terry Jan Reedy date: Tue Jan 21 00:31:07 2014 -0500 summary: Issue #21222: Whitespace files: Lib/idlelib/idle_test/test_calltips.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -88,7 +88,7 @@ (TC.cm, "(a)"),): self.assertEqual(signature(meth), mtip + "\ndoc") self.assertEqual(signature(tc), "(ci)\ndoc") - + def test_no_docstring(self): def nd(s): pass TC.nd = nd -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 09:10:25 2014 From: python-checkins at python.org (terry.reedy) Date: Tue, 21 Jan 2014 09:10:25 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE2NjU1?= =?utf-8?q?=3A_Explain_why_Idle=27s_test=5Fcalltips_has_=27fragile=27_test?= =?utf-8?q?s_of_builtins=2E?= Message-ID: <3f7j9F2Pkcz7Ljk@mail.python.org> http://hg.python.org/cpython/rev/779e5511d803 changeset: 88604:779e5511d803 branch: 2.7 user: Terry Jan Reedy date: Tue Jan 21 03:07:43 2014 -0500 summary: Issue #16655: Explain why Idle's test_calltips has 'fragile' tests of builtins. I do not expect a problem in 2.7, but backported this anyway, 'in case'. files: Lib/idlelib/idle_test/test_calltips.py | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -34,6 +34,13 @@ signature = ct.get_arg_text # 2.7 and 3.x use different functions class Get_signatureTest(unittest.TestCase): + # The signature function must return a string, even if blank. + # Test a variety of objects to be sure that none cause it to raise + # (quite aside from getting as correct an answer as possible). + # The tests of builtins may break if the docstrings change, + # but a red buildbot is better than a user crash (as has happened). + # For a simple mismatch, change the expected output to the actual. + def test_builtins(self): # 2.7 puts '()\n' where 3.x does not, other minor differences -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 09:10:26 2014 From: python-checkins at python.org (terry.reedy) Date: Tue, 21 Jan 2014 09:10:26 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE2NjU1?= =?utf-8?q?=3A_Explain_why_Idle=27s_test=5Fcalltips_has_=27fragile=27_test?= =?utf-8?q?s_of_builtins=2E?= Message-ID: <3f7j9G4Zmhz7LlL@mail.python.org> http://hg.python.org/cpython/rev/4a505a901b2e changeset: 88605:4a505a901b2e branch: 3.3 parent: 88601:7befcc353d40 user: Terry Jan Reedy date: Tue Jan 21 03:07:51 2014 -0500 summary: Issue #16655: Explain why Idle's test_calltips has 'fragile' tests of builtins. files: Lib/idlelib/idle_test/test_calltips.py | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -33,8 +33,16 @@ signature = ct.get_argspec # 2.7 and 3.x use different functions class Get_signatureTest(unittest.TestCase): + # The signature function must return a string, even if blank. + # Test a variety of objects to be sure that none cause it to raise + # (quite aside from getting as correct an answer as possible). + # The tests of builtins may break if inspect or the docstrings change, + # but a red buildbot is better than a user crash (as has happened). + # For a simple mismatch, change the expected output to the actual. def test_builtins(self): + # These test will break if + # Python class that inherits builtin methods class List(list): "List() doc" # Simulate builtin with no docstring for default argspec test -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 09:10:28 2014 From: python-checkins at python.org (terry.reedy) Date: Tue, 21 Jan 2014 09:10:28 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2316655=3A_Explain_why_Idle=27s_test=5Fcalltips_h?= =?utf-8?q?as_=27fragile=27_tests_of_builtins=2E?= Message-ID: <3f7j9J012bz7LlL@mail.python.org> http://hg.python.org/cpython/rev/c4a2d0538441 changeset: 88606:c4a2d0538441 parent: 88602:5b497ccfd4af parent: 88605:4a505a901b2e user: Terry Jan Reedy date: Tue Jan 21 03:10:01 2014 -0500 summary: Issue #16655: Explain why Idle's test_calltips has 'fragile' tests of builtins. Pending Clinic/inspect changes will probably require change to this file. files: Lib/idlelib/idle_test/test_calltips.py | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -33,8 +33,16 @@ signature = ct.get_argspec # 2.7 and 3.x use different functions class Get_signatureTest(unittest.TestCase): + # The signature function must return a string, even if blank. + # Test a variety of objects to be sure that none cause it to raise + # (quite aside from getting as correct an answer as possible). + # The tests of builtins may break if inspect or the docstrings change, + # but a red buildbot is better than a user crash (as has happened). + # For a simple mismatch, change the expected output to the actual. def test_builtins(self): + # These test will break if + # Python class that inherits builtin methods class List(list): "List() doc" # Simulate builtin with no docstring for default argspec test -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue Jan 21 09:39:28 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 21 Jan 2014 09:39:28 +0100 Subject: [Python-checkins] Daily reference leaks (0bcf1669912a): sum=8 Message-ID: results for 0bcf1669912a on branch "default" -------------------------------------------- test_asyncio leaked [4, 0, 0] memory blocks, sum=4 test_site leaked [2, 0, 0] references, sum=2 test_site leaked [2, 0, 0] memory blocks, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogRqt59_', '-x'] From python-checkins at python.org Tue Jan 21 17:49:58 2014 From: python-checkins at python.org (victor.stinner) Date: Tue, 21 Jan 2014 17:49:58 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_selectors=3A_add_a_comment?= =?utf-8?q?_to_explain_why_and_how_poll_timeout_is_rounded?= Message-ID: <3f7whk0jw6z7LjQ@mail.python.org> http://hg.python.org/cpython/rev/b81293d895d6 changeset: 88607:b81293d895d6 user: Victor Stinner date: Tue Jan 21 17:49:41 2014 +0100 summary: selectors: add a comment to explain why and how poll timeout is rounded files: Lib/selectors.py | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/selectors.py b/Lib/selectors.py --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -354,10 +354,12 @@ def select(self, timeout=None): if timeout is None: timeout = None - elif timeout < 0: + elif timeout <= 0: timeout = 0 else: - timeout = int(math.ceil(timeout * 1000.0)) + # poll() has a resolution of 1 millisecond, round away from + # zero to wait *at least* timeout seconds. + timeout = int(math.ceil(timeout * 1e3)) ready = [] try: fd_event_list = self._poll.poll(timeout) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 19:20:48 2014 From: python-checkins at python.org (georg.brandl) Date: Tue, 21 Jan 2014 19:20:48 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_fix_deprecated?= =?utf-8?q?-removed_directive_with_sphinx_1=2E2?= Message-ID: <3f7yjX5HDFz7LjR@mail.python.org> http://hg.python.org/cpython/rev/5d1324b20804 changeset: 88608:5d1324b20804 branch: 3.3 parent: 88605:4a505a901b2e user: Georg Brandl date: Tue Jan 21 19:20:31 2014 +0100 summary: fix deprecated-removed directive with sphinx 1.2 files: Doc/tools/sphinxext/pyspecific.py | 32 +++++++++++---- Doc/tools/sphinxext/static/basic.css | 2 +- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Doc/tools/sphinxext/pyspecific.py b/Doc/tools/sphinxext/pyspecific.py --- a/Doc/tools/sphinxext/pyspecific.py +++ b/Doc/tools/sphinxext/pyspecific.py @@ -5,7 +5,7 @@ Sphinx extension with Python doc-specific markup. - :copyright: 2008-2013 by Georg Brandl. + :copyright: 2008-2014 by Georg Brandl. :license: Python license. """ @@ -145,8 +145,6 @@ from sphinx.locale import versionlabels from sphinx.util.compat import Directive -versionlabels['deprecated-removed'] = \ - 'Deprecated since version %s, will be removed in version %s' class DeprecatedRemoved(Directive): has_content = True @@ -155,24 +153,40 @@ final_argument_whitespace = True option_spec = {} + _label = 'Deprecated since version %s, will be removed in version %s' + def run(self): node = addnodes.versionmodified() node.document = self.state.document node['type'] = 'deprecated-removed' version = (self.arguments[0], self.arguments[1]) node['version'] = version + text = self._label % version if len(self.arguments) == 3: inodes, messages = self.state.inline_text(self.arguments[2], self.lineno+1) - node.extend(inodes) - if self.content: - self.state.nested_parse(self.content, self.content_offset, node) - ret = [node] + messages + para = nodes.paragraph(self.arguments[2], '', *inodes) + node.append(para) else: - ret = [node] + messages = [] + if self.content: + self.state.nested_parse(self.content, self.content_offset, node) + if len(node): + if isinstance(node[0], nodes.paragraph) and node[0].rawsource: + content = nodes.inline(node[0].rawsource, translatable=True) + content.source = node[0].source + content.line = node[0].line + content += node[0].children + node[0].replace_self(nodes.paragraph('', '', content)) + node[0].insert(0, nodes.inline('', '%s: ' % text, + classes=['versionmodified'])) + else: + para = nodes.paragraph('', '', + nodes.inline('', '%s.' % text, classes=['versionmodified'])) + node.append(para) env = self.state.document.settings.env env.note_versionchange('deprecated', version[0], node, self.lineno) - return ret + return [node] + messages # Support for including Misc/NEWS diff --git a/Doc/tools/sphinxext/static/basic.css b/Doc/tools/sphinxext/static/basic.css --- a/Doc/tools/sphinxext/static/basic.css +++ b/Doc/tools/sphinxext/static/basic.css @@ -342,7 +342,7 @@ padding: 7px; } -div.deprecated p { +div.deprecated p, div.deprecated-removed p { margin-bottom: 0; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 19:20:50 2014 From: python-checkins at python.org (georg.brandl) Date: Tue, 21 Jan 2014 19:20:50 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge_with_3=2E3?= Message-ID: <3f7yjZ08Bnz7LjR@mail.python.org> http://hg.python.org/cpython/rev/7a76781e619d changeset: 88609:7a76781e619d parent: 88607:b81293d895d6 parent: 88608:5d1324b20804 user: Georg Brandl date: Tue Jan 21 19:20:58 2014 +0100 summary: merge with 3.3 files: Doc/tools/sphinxext/pyspecific.py | 32 +++++++++++---- Doc/tools/sphinxext/static/basic.css | 2 +- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Doc/tools/sphinxext/pyspecific.py b/Doc/tools/sphinxext/pyspecific.py --- a/Doc/tools/sphinxext/pyspecific.py +++ b/Doc/tools/sphinxext/pyspecific.py @@ -5,7 +5,7 @@ Sphinx extension with Python doc-specific markup. - :copyright: 2008-2013 by Georg Brandl. + :copyright: 2008-2014 by Georg Brandl. :license: Python license. """ @@ -145,8 +145,6 @@ from sphinx.locale import versionlabels from sphinx.util.compat import Directive -versionlabels['deprecated-removed'] = \ - 'Deprecated since version %s, will be removed in version %s' class DeprecatedRemoved(Directive): has_content = True @@ -155,24 +153,40 @@ final_argument_whitespace = True option_spec = {} + _label = 'Deprecated since version %s, will be removed in version %s' + def run(self): node = addnodes.versionmodified() node.document = self.state.document node['type'] = 'deprecated-removed' version = (self.arguments[0], self.arguments[1]) node['version'] = version + text = self._label % version if len(self.arguments) == 3: inodes, messages = self.state.inline_text(self.arguments[2], self.lineno+1) - node.extend(inodes) - if self.content: - self.state.nested_parse(self.content, self.content_offset, node) - ret = [node] + messages + para = nodes.paragraph(self.arguments[2], '', *inodes) + node.append(para) else: - ret = [node] + messages = [] + if self.content: + self.state.nested_parse(self.content, self.content_offset, node) + if len(node): + if isinstance(node[0], nodes.paragraph) and node[0].rawsource: + content = nodes.inline(node[0].rawsource, translatable=True) + content.source = node[0].source + content.line = node[0].line + content += node[0].children + node[0].replace_self(nodes.paragraph('', '', content)) + node[0].insert(0, nodes.inline('', '%s: ' % text, + classes=['versionmodified'])) + else: + para = nodes.paragraph('', '', + nodes.inline('', '%s.' % text, classes=['versionmodified'])) + node.append(para) env = self.state.document.settings.env env.note_versionchange('deprecated', version[0], node, self.lineno) - return ret + return [node] + messages # Support for including Misc/NEWS diff --git a/Doc/tools/sphinxext/static/basic.css b/Doc/tools/sphinxext/static/basic.css --- a/Doc/tools/sphinxext/static/basic.css +++ b/Doc/tools/sphinxext/static/basic.css @@ -342,7 +342,7 @@ padding: 7px; } -div.deprecated p { +div.deprecated p, div.deprecated-removed p { margin-bottom: 0; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 20:13:03 2014 From: python-checkins at python.org (georg.brandl) Date: Tue, 21 Jan 2014 20:13:03 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fix_markup_err?= =?utf-8?b?b3Iu?= Message-ID: <3f7zsq1VHTz7LjT@mail.python.org> http://hg.python.org/cpython/rev/6faddc895867 changeset: 88610:6faddc895867 branch: 2.7 parent: 88604:779e5511d803 user: Georg Brandl date: Tue Jan 21 19:21:18 2014 +0100 summary: Fix markup error. files: Doc/library/hashlib.rst | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst --- a/Doc/library/hashlib.rst +++ b/Doc/library/hashlib.rst @@ -110,7 +110,6 @@ m.update(b)`` is equivalent to ``m.update(a+b)``. .. versionchanged:: 2.7 - The Python GIL is released to allow other threads to run while hash updates on data larger than 2048 bytes is taking place when using hash algorithms supplied by OpenSSL. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 20:50:24 2014 From: python-checkins at python.org (zach.ware) Date: Tue, 21 Jan 2014 20:50:24 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMzAx?= =?utf-8?q?=3A_Mention_the_correct_KEY=5F*_value_as_the_default?= Message-ID: <3f80hw6q5Sz7LkF@mail.python.org> http://hg.python.org/cpython/rev/da35a4e724e5 changeset: 88611:da35a4e724e5 branch: 3.3 parent: 88608:5d1324b20804 user: Zachary Ware date: Tue Jan 21 13:49:22 2014 -0600 summary: Issue #20301: Mention the correct KEY_* value as the default for 'access' in winreg.DeleteKeyEx. Already correct in the docs function signature and docstring. Noticed by Justin Foo. files: Doc/library/winreg.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/winreg.rst b/Doc/library/winreg.rst --- a/Doc/library/winreg.rst +++ b/Doc/library/winreg.rst @@ -146,7 +146,7 @@ *reserved* is a reserved integer, and must be zero. The default is zero. *access* is an integer that specifies an access mask that describes the desired - security access for the key. Default is :const:`KEY_ALL_ACCESS`. See + security access for the key. Default is :const:`KEY_WOW64_64KEY`. See :ref:`Access Rights ` for other allowed values. *This method can not delete keys with subkeys.* -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 20:50:26 2014 From: python-checkins at python.org (zach.ware) Date: Tue, 21 Jan 2014 20:50:26 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320301=3A_Merge_with_3=2E3?= Message-ID: <3f80hy2jYPz7LmN@mail.python.org> http://hg.python.org/cpython/rev/3baee069c5ff changeset: 88612:3baee069c5ff parent: 88609:7a76781e619d parent: 88611:da35a4e724e5 user: Zachary Ware date: Tue Jan 21 13:50:13 2014 -0600 summary: Issue #20301: Merge with 3.3 files: Doc/library/winreg.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/winreg.rst b/Doc/library/winreg.rst --- a/Doc/library/winreg.rst +++ b/Doc/library/winreg.rst @@ -146,7 +146,7 @@ *reserved* is a reserved integer, and must be zero. The default is zero. *access* is an integer that specifies an access mask that describes the desired - security access for the key. Default is :const:`KEY_ALL_ACCESS`. See + security access for the key. Default is :const:`KEY_WOW64_64KEY`. See :ref:`Access Rights ` for other allowed values. *This method can not delete keys with subkeys.* -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 20:55:50 2014 From: python-checkins at python.org (victor.stinner) Date: Tue, 21 Jan 2014 20:55:50 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320024=3A_Py=5FBui?= =?utf-8?q?ldValue=28=29_now_saves/restores_the_current_exception_before?= Message-ID: <3f80qB4yhpz7Llk@mail.python.org> http://hg.python.org/cpython/rev/29b4eb47f65e changeset: 88613:29b4eb47f65e user: Victor Stinner date: Tue Jan 21 20:52:17 2014 +0100 summary: Issue #20024: Py_BuildValue() now saves/restores the current exception before building an item if the build of a previous item failed. files: Python/modsupport.c | 12 +++++++++++- 1 files changed, 11 insertions(+), 1 deletions(-) diff --git a/Python/modsupport.c b/Python/modsupport.c --- a/Python/modsupport.c +++ b/Python/modsupport.c @@ -161,7 +161,17 @@ /* Note that we can't bail immediately on error as this will leak refcounts on any 'N' arguments. */ for (i = 0; i < n; i++) { - PyObject *w = do_mkvalue(p_format, p_va, flags); + PyObject *w; + + if (itemfailed) { + PyObject *exception, *value, *tb; + PyErr_Fetch(&exception, &value, &tb); + w = do_mkvalue(p_format, p_va, flags); + PyErr_Restore(exception, value, tb); + } + else { + w = do_mkvalue(p_format, p_va, flags); + } if (w == NULL) { itemfailed = 1; Py_INCREF(Py_None); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 21:01:06 2014 From: python-checkins at python.org (victor.stinner) Date: Tue, 21 Jan 2014 21:01:06 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320311=3A_EpollSel?= =?utf-8?q?ector_now_also_rounds_the_timeout_towards_zero=2C_as?= Message-ID: <3f80xG0zbwz7Ljk@mail.python.org> http://hg.python.org/cpython/rev/7ce7295393c2 changeset: 88614:7ce7295393c2 user: Victor Stinner date: Tue Jan 21 21:00:47 2014 +0100 summary: Issue #20311: EpollSelector now also rounds the timeout towards zero, as PollSelector. This change is not really required in Python 3.4, since select.epoll.poll() now rounds also correctly the timeout. But Guido van Rossum prefers to have exactly the same selectors.py file in CPython and Tulip projects: "it's not harmful". files: Lib/selectors.py | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Lib/selectors.py b/Lib/selectors.py --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -411,7 +411,14 @@ return key def select(self, timeout=None): - timeout = -1 if timeout is None else max(timeout, 0) + if timeout is None: + timeout = -1 + elif timeout <= 0: + timeout = 0 + else: + # epoll_wait() has a resolution of 1 millisecond, round away + # from zero to wait *at least* timeout seconds. + timeout = math.ceil(timeout * 1e3) * 1e-3 max_ev = len(self._fd_to_key) ready = [] try: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 21:30:34 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 21 Jan 2014 21:30:34 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIzODI6?= =?utf-8?q?_SyntaxError_cursor_=22=5E=22_now_is_written_at_correct_positio?= =?utf-8?q?n_in_most?= Message-ID: <3f81bG08gyz7Ljk@mail.python.org> http://hg.python.org/cpython/rev/eb7565c212f1 changeset: 88615:eb7565c212f1 branch: 3.3 parent: 88611:da35a4e724e5 user: Serhiy Storchaka date: Tue Jan 21 22:26:52 2014 +0200 summary: Issue #2382: SyntaxError cursor "^" now is written at correct position in most cases when multibyte characters are in line (before "^"). This still not works correctly with wide East Asian characters. files: Lib/test/test_exceptions.py | 13 +++++++++++++ Lib/test/test_traceback.py | 9 +++++++++ Misc/NEWS | 4 ++++ Python/pythonrun.c | 14 ++++++++++++-- 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -148,6 +148,19 @@ ckmsg(s, "'continue' not properly in loop") ckmsg("continue\n", "'continue' not properly in loop") + def testSyntaxErrorOffset(self): + def check(src, lineno, offset): + with self.assertRaises(SyntaxError) as cm: + compile(src, '', 'exec') + self.assertEqual(cm.exception.lineno, lineno) + self.assertEqual(cm.exception.offset, offset) + + check('def fact(x):\n\treturn x!\n', 2, 10) + check('1 +\n', 1, 4) + check('def spam():\n print(1)\n print(2)', 3, 10) + check('Python = "Python" +', 1, 20) + check('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', 1, 20) + @cpython_only def testSettingException(self): # test that setting an exception at the C level works even if the 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 @@ -32,6 +32,9 @@ def syntax_error_bad_indentation(self): compile("def spam():\n print(1)\n print(2)", "?", "exec") + def syntax_error_with_caret_non_ascii(self): + compile('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', "?", "exec") + def test_caret(self): err = self.get_exception_format(self.syntax_error_with_caret, SyntaxError) @@ -46,6 +49,12 @@ self.assertTrue(err[2].count('\n') == 1) # and no additional newline self.assertTrue(err[1].find("+") == err[2].find("^")) # in the right place + err = self.get_exception_format(self.syntax_error_with_caret_non_ascii, + SyntaxError) + self.assertIn("^", err[2]) # third line has caret + self.assertTrue(err[2].count('\n') == 1) # and no additional newline + self.assertTrue(err[1].find("+") == err[2].find("^")) # in the right place + def test_nocaret(self): exc = SyntaxError("error", ("x.py", 23, None, "bad syntax")) err = traceback.format_exception_only(SyntaxError, exc) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #2382: SyntaxError cursor "^" is now written at correct position in most + cases when multibyte characters are in line (before "^"). This still not + works correctly with wide East Asian characters. + - Issue #18960: The first line of Python script could be executed twice when the source encoding was specified on the second line. Now the source encoding declaration on the second line isn't effective if the first line contains diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -2226,6 +2226,7 @@ PyObject *v, *w, *errtype, *errtext; PyObject *msg_obj = NULL; char *msg = NULL; + int offset = err->offset; errtype = PyExc_SyntaxError; switch (err->error) { @@ -2310,11 +2311,20 @@ errtext = Py_None; Py_INCREF(Py_None); } else { - errtext = PyUnicode_DecodeUTF8(err->text, strlen(err->text), + errtext = PyUnicode_DecodeUTF8(err->text, err->offset, "replace"); + if (errtext != NULL) { + Py_ssize_t len = strlen(err->text); + offset = (int)PyUnicode_GET_LENGTH(errtext); + if (len != err->offset) { + Py_DECREF(errtext); + errtext = PyUnicode_DecodeUTF8(err->text, len, + "replace"); + } + } } v = Py_BuildValue("(OiiN)", err->filename, - err->lineno, err->offset, errtext); + err->lineno, offset, errtext); if (v != NULL) { if (msg_obj) w = Py_BuildValue("(OO)", msg_obj, v); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 21:30:35 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 21 Jan 2014 21:30:35 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=232382=3A_SyntaxError_cursor_=22=5E=22_now_is_wri?= =?utf-8?q?tten_at_correct_position_in_most?= Message-ID: <3f81bH45QPz7Ll5@mail.python.org> http://hg.python.org/cpython/rev/ea34b2b0b8ae changeset: 88616:ea34b2b0b8ae parent: 88614:7ce7295393c2 parent: 88615:eb7565c212f1 user: Serhiy Storchaka date: Tue Jan 21 22:29:47 2014 +0200 summary: Issue #2382: SyntaxError cursor "^" now is written at correct position in most cases when multibyte characters are in line (before "^"). This still not works correctly with wide East Asian characters. files: Lib/test/test_exceptions.py | 13 +++++++++++++ Lib/test/test_traceback.py | 9 +++++++++ Misc/NEWS | 4 ++++ Python/pythonrun.c | 14 ++++++++++++-- 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -148,6 +148,19 @@ ckmsg(s, "'continue' not properly in loop") ckmsg("continue\n", "'continue' not properly in loop") + def testSyntaxErrorOffset(self): + def check(src, lineno, offset): + with self.assertRaises(SyntaxError) as cm: + compile(src, '', 'exec') + self.assertEqual(cm.exception.lineno, lineno) + self.assertEqual(cm.exception.offset, offset) + + check('def fact(x):\n\treturn x!\n', 2, 10) + check('1 +\n', 1, 4) + check('def spam():\n print(1)\n print(2)', 3, 10) + check('Python = "Python" +', 1, 20) + check('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', 1, 20) + @cpython_only def testSettingException(self): # test that setting an exception at the C level works even if the 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 @@ -32,6 +32,9 @@ def syntax_error_bad_indentation(self): compile("def spam():\n print(1)\n print(2)", "?", "exec") + def syntax_error_with_caret_non_ascii(self): + compile('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', "?", "exec") + def test_caret(self): err = self.get_exception_format(self.syntax_error_with_caret, SyntaxError) @@ -46,6 +49,12 @@ self.assertTrue(err[2].count('\n') == 1) # and no additional newline self.assertTrue(err[1].find("+") == err[2].find("^")) # in the right place + err = self.get_exception_format(self.syntax_error_with_caret_non_ascii, + SyntaxError) + self.assertIn("^", err[2]) # third line has caret + self.assertTrue(err[2].count('\n') == 1) # and no additional newline + self.assertTrue(err[1].find("+") == err[2].find("^")) # in the right place + def test_nocaret(self): exc = SyntaxError("error", ("x.py", 23, None, "bad syntax")) err = traceback.format_exception_only(SyntaxError, exc) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #2382: SyntaxError cursor "^" is now written at correct position in most + cases when multibyte characters are in line (before "^"). This still not + works correctly with wide East Asian characters. + - Issue #18960: The first line of Python script could be executed twice when the source encoding was specified on the second line. Now the source encoding declaration on the second line isn't effective if the first line contains diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -2470,6 +2470,7 @@ PyObject *v, *w, *errtype, *errtext; PyObject *msg_obj = NULL; char *msg = NULL; + int offset = err->offset; errtype = PyExc_SyntaxError; switch (err->error) { @@ -2554,11 +2555,20 @@ errtext = Py_None; Py_INCREF(Py_None); } else { - errtext = PyUnicode_DecodeUTF8(err->text, strlen(err->text), + errtext = PyUnicode_DecodeUTF8(err->text, err->offset, "replace"); + if (errtext != NULL) { + Py_ssize_t len = strlen(err->text); + offset = (int)PyUnicode_GET_LENGTH(errtext); + if (len != err->offset) { + Py_DECREF(errtext); + errtext = PyUnicode_DecodeUTF8(err->text, len, + "replace"); + } + } } v = Py_BuildValue("(OiiN)", err->filename, - err->lineno, err->offset, errtext); + err->lineno, offset, errtext); if (v != NULL) { if (msg_obj) w = Py_BuildValue("(OO)", msg_obj, v); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 21:37:37 2014 From: python-checkins at python.org (terry.reedy) Date: Tue, 21 Jan 2014 21:37:37 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE2NjMw?= =?utf-8?q?=3A_Make_Idle_calltips_work_even_when_=5F=5Fgetattr=5F=5F_raise?= =?utf-8?q?s=2E?= Message-ID: <3f81lP531gz7Lk1@mail.python.org> http://hg.python.org/cpython/rev/d55d1cbf5f9a changeset: 88617:d55d1cbf5f9a branch: 2.7 parent: 88610:6faddc895867 user: Terry Jan Reedy date: Tue Jan 21 15:36:36 2014 -0500 summary: Issue #16630: Make Idle calltips work even when __getattr__ raises. Initial patch by Roger Serwy. files: Lib/idlelib/CallTips.py | 100 ++++++------ Lib/idlelib/idle_test/test_calltips.py | 19 +- 2 files changed, 66 insertions(+), 53 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -134,56 +134,60 @@ """Get a string describing the arguments for the given object, only if it is callable.""" arg_text = "" - if ob is not None and hasattr(ob, '__call__'): - arg_offset = 0 - if type(ob) in (types.ClassType, types.TypeType): - # Look for the highest __init__ in the class chain. - fob = _find_constructor(ob) - if fob is None: - fob = lambda: None - else: - arg_offset = 1 - elif type(ob) == types.MethodType: - # bit of a hack for methods - turn it into a function - # and drop the "self" param for bound methods - fob = ob.im_func - if ob.im_self: - arg_offset = 1 - elif type(ob.__call__) == types.MethodType: - # a callable class instance - fob = ob.__call__.im_func + try: + ob_call = ob.__call__ + except BaseException: + return arg_text + + arg_offset = 0 + if type(ob) in (types.ClassType, types.TypeType): + # Look for the highest __init__ in the class chain. + fob = _find_constructor(ob) + if fob is None: + fob = lambda: None + else: arg_offset = 1 - else: - fob = ob - # Try to build one for Python defined functions - if type(fob) in [types.FunctionType, types.LambdaType]: - argcount = fob.func_code.co_argcount - real_args = fob.func_code.co_varnames[arg_offset:argcount] - defaults = fob.func_defaults or [] - defaults = list(map(lambda name: "=%s" % repr(name), defaults)) - defaults = [""] * (len(real_args) - len(defaults)) + defaults - items = map(lambda arg, dflt: arg + dflt, real_args, defaults) - if fob.func_code.co_flags & 0x4: - items.append("*args") - if fob.func_code.co_flags & 0x8: - items.append("**kwds") - arg_text = ", ".join(items) - arg_text = "(%s)" % re.sub("(?", arg_text) - # See if we can use the docstring - if isinstance(ob.__call__, types.MethodType): - doc = ob.__call__.__doc__ - else: - doc = getattr(ob, "__doc__", "") - if doc: - doc = doc.lstrip() - pos = doc.find("\n") - if pos < 0 or pos > 70: - pos = 70 - if arg_text: - arg_text += "\n" - arg_text += doc[:pos] + elif type(ob) == types.MethodType: + # bit of a hack for methods - turn it into a function + # and drop the "self" param for bound methods + fob = ob.im_func + if ob.im_self: + arg_offset = 1 + elif type(ob_call) == types.MethodType: + # a callable class instance + fob = ob_call.im_func + arg_offset = 1 + else: + fob = ob + # Try to build one for Python defined functions + if type(fob) in [types.FunctionType, types.LambdaType]: + argcount = fob.func_code.co_argcount + real_args = fob.func_code.co_varnames[arg_offset:argcount] + defaults = fob.func_defaults or [] + defaults = list(map(lambda name: "=%s" % repr(name), defaults)) + defaults = [""] * (len(real_args) - len(defaults)) + defaults + items = map(lambda arg, dflt: arg + dflt, real_args, defaults) + if fob.func_code.co_flags & 0x4: + items.append("*args") + if fob.func_code.co_flags & 0x8: + items.append("**kwds") + arg_text = ", ".join(items) + arg_text = "(%s)" % re.sub("(?", arg_text) + # See if we can use the docstring + if isinstance(ob_call, types.MethodType): + doc = ob_call.__doc__ + else: + doc = getattr(ob, "__doc__", "") + if doc: + doc = doc.lstrip() + pos = doc.find("\n") + if pos < 0 or pos > 70: + pos = 70 + if arg_text: + arg_text += "\n" + arg_text += doc[:pos] return arg_text if __name__ == '__main__': from unittest import main - main('idlelib.idle_test.test_calltips', verbosity=2, exit=False) + main('idlelib.idle_test.test_calltips', verbosity=2) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -3,6 +3,7 @@ CTi = ct.CallTips() # needed for get_entity test in 2.7 import types +default_tip = '' # Test Class TC is used in multiple get_argspec test methods class TC(object): @@ -41,7 +42,6 @@ # but a red buildbot is better than a user crash (as has happened). # For a simple mismatch, change the expected output to the actual. - def test_builtins(self): # 2.7 puts '()\n' where 3.x does not, other minor differences @@ -65,8 +65,7 @@ gtest(List.append, append_doc) gtest(types.MethodType, '()\ninstancemethod(function, instance, class)') - gtest(SB(), '') - + gtest(SB(), default_tip) def test_functions(self): def t1(): 'doc' @@ -92,9 +91,8 @@ def test_bound_methods(self): # test that first parameter is correctly removed from argspec for meth, mtip in ((tc.t1, "()"), (tc.t4, "(*args)"), (tc.t6, "(self)"), - (TC.cm, "(a)"),): + (tc.__call__, '(ci)'), (tc, '(ci)'), (TC.cm, "(a)"),): self.assertEqual(signature(meth), mtip + "\ndoc") - self.assertEqual(signature(tc), "(ci)\ndoc") def test_no_docstring(self): def nd(s): pass @@ -103,6 +101,17 @@ self.assertEqual(signature(TC.nd), "(s)") self.assertEqual(signature(tc.nd), "()") + def test_attribute_exception(self): + class NoCall(object): + def __getattr__(self, name): + raise BaseException + class Call(NoCall): + def __call__(self, ci): + pass + for meth, mtip in ((NoCall, '()'), (Call, '()'), + (NoCall(), ''), (Call(), '(ci)')): + self.assertEqual(signature(meth), mtip) + def test_non_callables(self): for obj in (0, 0.0, '0', b'0', [], {}): self.assertEqual(signature(obj), '') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 21:37:39 2014 From: python-checkins at python.org (terry.reedy) Date: Tue, 21 Jan 2014 21:37:39 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE2NjMw?= =?utf-8?q?=3A_Make_Idle_calltips_work_even_when_=5F=5Fgetattr=5F=5F_raise?= =?utf-8?q?s=2E?= Message-ID: <3f81lR1Zn8z7Lm7@mail.python.org> http://hg.python.org/cpython/rev/2fe0b2dcc98c changeset: 88618:2fe0b2dcc98c branch: 3.3 parent: 88615:eb7565c212f1 user: Terry Jan Reedy date: Tue Jan 21 15:36:51 2014 -0500 summary: Issue #16630: Make Idle calltips work even when __getattr__ raises. Initial patch by Roger Serwy. files: Lib/idlelib/CallTips.py | 62 +++++++------ Lib/idlelib/idle_test/test_calltips.py | 24 ++++- 2 files changed, 50 insertions(+), 36 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -118,47 +118,49 @@ # The following are used in both get_argspec and tests _first_param = re.compile('(?<=\()\w*\,?\s*') -_default_callable_argspec = "No docstring, see docs." +_default_callable_argspec = "See source or doc" def get_argspec(ob): - '''Return a string describing the arguments and return of a callable object. + '''Return a string describing the signature of a callable object, or ''. For Python-coded functions and methods, the first line is introspected. Delete 'self' parameter for classes (.__init__) and bound methods. The last line is the first line of the doc string. For builtins, this typically includes the arguments in addition to the return value. - ''' argspec = "" - if hasattr(ob, '__call__'): - if isinstance(ob, type): - fob = getattr(ob, '__init__', None) - elif isinstance(ob.__call__, types.MethodType): - fob = ob.__call__ - else: - fob = ob - if isinstance(fob, (types.FunctionType, types.MethodType)): - argspec = inspect.formatargspec(*inspect.getfullargspec(fob)) - if (isinstance(ob, (type, types.MethodType)) or - isinstance(ob.__call__, types.MethodType)): - argspec = _first_param.sub("", argspec) + try: + ob_call = ob.__call__ + except BaseException: + return argspec + if isinstance(ob, type): + fob = ob.__init__ + elif isinstance(ob_call, types.MethodType): + fob = ob_call + else: + fob = ob + if isinstance(fob, (types.FunctionType, types.MethodType)): + argspec = inspect.formatargspec(*inspect.getfullargspec(fob)) + if (isinstance(ob, (type, types.MethodType)) or + isinstance(ob_call, types.MethodType)): + argspec = _first_param.sub("", argspec) - if isinstance(ob.__call__, types.MethodType): - doc = ob.__call__.__doc__ - else: - doc = getattr(ob, "__doc__", "") - if doc: - doc = doc.lstrip() - pos = doc.find("\n") - if pos < 0 or pos > 70: - pos = 70 - if argspec: - argspec += "\n" - argspec += doc[:pos] - if not argspec: - argspec = _default_callable_argspec + if isinstance(ob_call, types.MethodType): + doc = ob_call.__doc__ + else: + doc = getattr(ob, "__doc__", "") + if doc: + doc = doc.lstrip() + pos = doc.find("\n") + if pos < 0 or pos > 70: + pos = 70 + if argspec: + argspec += "\n" + argspec += doc[:pos] + if not argspec: + argspec = _default_callable_argspec return argspec if __name__ == '__main__': from unittest import main - main('idlelib.idle_test.test_calltips', verbosity=2, exit=False) + main('idlelib.idle_test.test_calltips', verbosity=2) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -2,6 +2,7 @@ import idlelib.CallTips as ct import types +default_tip = ct._default_callable_argspec # Test Class TC is used in multiple get_argspec test methods class TC(): @@ -63,7 +64,7 @@ gtest(List.append, append_doc) gtest(types.MethodType, "method(function, instance)") - gtest(SB(), ct._default_callable_argspec) + gtest(SB(), default_tip) def test_functions(self): def t1(): 'doc' @@ -88,13 +89,13 @@ def test_bound_methods(self): # test that first parameter is correctly removed from argspec - # using _first_param re to calculate expected masks re errors for meth, mtip in ((tc.t1, "()"), (tc.t4, "(*args)"), (tc.t6, "(self)"), - (TC.cm, "(a)"),): + (tc.__call__, '(ci)'), (tc, '(ci)'), (TC.cm, "(a)"),): self.assertEqual(signature(meth), mtip + "\ndoc") - self.assertEqual(signature(tc), "(ci)\ndoc") - # directly test that re works to delete first parameter even when it - # non-ascii chars, such as various forms of A. + + def test_non_ascii_name(self): + # test that re works to delete a first parameter name that + # includes non-ascii chars, such as various forms of A. uni = "(A\u0391\u0410\u05d0\u0627\u0905\u1e00\u3042, a)" assert ct._first_param.sub('', uni) == '(a)' @@ -105,6 +106,17 @@ self.assertEqual(signature(TC.nd), "(s)") self.assertEqual(signature(tc.nd), "()") + def test_attribute_exception(self): + class NoCall: + def __getattr__(self, name): + raise BaseException + class Call(NoCall): + def __call__(self, ci): + pass + for meth, mtip in ((NoCall, default_tip), (Call, default_tip), + (NoCall(), ''), (Call(), '(ci)')): + self.assertEqual(signature(meth), mtip) + def test_non_callables(self): for obj in (0, 0.0, '0', b'0', [], {}): self.assertEqual(signature(obj), '') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 21:37:40 2014 From: python-checkins at python.org (terry.reedy) Date: Tue, 21 Jan 2014 21:37:40 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E3?= Message-ID: <3f81lS5GrKz7LkF@mail.python.org> http://hg.python.org/cpython/rev/60a954a018b9 changeset: 88619:60a954a018b9 parent: 88616:ea34b2b0b8ae parent: 88618:2fe0b2dcc98c user: Terry Jan Reedy date: Tue Jan 21 15:37:16 2014 -0500 summary: Merge with 3.3 files: Lib/idlelib/CallTips.py | 62 +++++++------ Lib/idlelib/idle_test/test_calltips.py | 24 ++++- 2 files changed, 50 insertions(+), 36 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -118,47 +118,49 @@ # The following are used in both get_argspec and tests _first_param = re.compile('(?<=\()\w*\,?\s*') -_default_callable_argspec = "No docstring, see docs." +_default_callable_argspec = "See source or doc" def get_argspec(ob): - '''Return a string describing the arguments and return of a callable object. + '''Return a string describing the signature of a callable object, or ''. For Python-coded functions and methods, the first line is introspected. Delete 'self' parameter for classes (.__init__) and bound methods. The last line is the first line of the doc string. For builtins, this typically includes the arguments in addition to the return value. - ''' argspec = "" - if hasattr(ob, '__call__'): - if isinstance(ob, type): - fob = getattr(ob, '__init__', None) - elif isinstance(ob.__call__, types.MethodType): - fob = ob.__call__ - else: - fob = ob - if isinstance(fob, (types.FunctionType, types.MethodType)): - argspec = inspect.formatargspec(*inspect.getfullargspec(fob)) - if (isinstance(ob, (type, types.MethodType)) or - isinstance(ob.__call__, types.MethodType)): - argspec = _first_param.sub("", argspec) + try: + ob_call = ob.__call__ + except BaseException: + return argspec + if isinstance(ob, type): + fob = ob.__init__ + elif isinstance(ob_call, types.MethodType): + fob = ob_call + else: + fob = ob + if isinstance(fob, (types.FunctionType, types.MethodType)): + argspec = inspect.formatargspec(*inspect.getfullargspec(fob)) + if (isinstance(ob, (type, types.MethodType)) or + isinstance(ob_call, types.MethodType)): + argspec = _first_param.sub("", argspec) - if isinstance(ob.__call__, types.MethodType): - doc = ob.__call__.__doc__ - else: - doc = getattr(ob, "__doc__", "") - if doc: - doc = doc.lstrip() - pos = doc.find("\n") - if pos < 0 or pos > 70: - pos = 70 - if argspec: - argspec += "\n" - argspec += doc[:pos] - if not argspec: - argspec = _default_callable_argspec + if isinstance(ob_call, types.MethodType): + doc = ob_call.__doc__ + else: + doc = getattr(ob, "__doc__", "") + if doc: + doc = doc.lstrip() + pos = doc.find("\n") + if pos < 0 or pos > 70: + pos = 70 + if argspec: + argspec += "\n" + argspec += doc[:pos] + if not argspec: + argspec = _default_callable_argspec return argspec if __name__ == '__main__': from unittest import main - main('idlelib.idle_test.test_calltips', verbosity=2, exit=False) + main('idlelib.idle_test.test_calltips', verbosity=2) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -2,6 +2,7 @@ import idlelib.CallTips as ct import types +default_tip = ct._default_callable_argspec # Test Class TC is used in multiple get_argspec test methods class TC(): @@ -63,7 +64,7 @@ gtest(List.append, append_doc) gtest(types.MethodType, "method(function, instance)") - gtest(SB(), ct._default_callable_argspec) + gtest(SB(), default_tip) def test_functions(self): def t1(): 'doc' @@ -88,13 +89,13 @@ def test_bound_methods(self): # test that first parameter is correctly removed from argspec - # using _first_param re to calculate expected masks re errors for meth, mtip in ((tc.t1, "()"), (tc.t4, "(*args)"), (tc.t6, "(self)"), - (TC.cm, "(a)"),): + (tc.__call__, '(ci)'), (tc, '(ci)'), (TC.cm, "(a)"),): self.assertEqual(signature(meth), mtip + "\ndoc") - self.assertEqual(signature(tc), "(ci)\ndoc") - # directly test that re works to delete first parameter even when it - # non-ascii chars, such as various forms of A. + + def test_non_ascii_name(self): + # test that re works to delete a first parameter name that + # includes non-ascii chars, such as various forms of A. uni = "(A\u0391\u0410\u05d0\u0627\u0905\u1e00\u3042, a)" assert ct._first_param.sub('', uni) == '(a)' @@ -105,6 +106,17 @@ self.assertEqual(signature(TC.nd), "(s)") self.assertEqual(signature(tc.nd), "()") + def test_attribute_exception(self): + class NoCall: + def __getattr__(self, name): + raise BaseException + class Call(NoCall): + def __call__(self, ci): + pass + for meth, mtip in ((NoCall, default_tip), (Call, default_tip), + (NoCall(), ''), (Call(), '(ci)')): + self.assertEqual(signature(meth), mtip) + def test_non_callables(self): for obj in (0, 0.0, '0', b'0', [], {}): self.assertEqual(signature(obj), '') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 22:24:07 2014 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 21 Jan 2014 22:24:07 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Fix_formatting=2E?= Message-ID: <3f82n33tgDz7LkB@mail.python.org> http://hg.python.org/peps/rev/761e18fca78e changeset: 5354:761e18fca78e user: Antoine Pitrou date: Tue Jan 21 22:24:03 2014 +0100 summary: Fix formatting. files: pep-0461.txt | 27 +++++++++++++-------------- 1 files changed, 13 insertions(+), 14 deletions(-) diff --git a/pep-0461.txt b/pep-0461.txt --- a/pep-0461.txt +++ b/pep-0461.txt @@ -59,15 +59,15 @@ >>> b'%c' % b'a' b'a' -``%s`` is restricted in what it will accept:: +``%s`` is restricted in what it will accept: - - input type supports ``Py_buffer`` [4]_? - use it to collect the necessary bytes +- input type supports ``Py_buffer`` [4]_? + use it to collect the necessary bytes - - input type is something else? - use its ``__bytes__`` method [5]_ ; if there isn't one, raise a ``TypeError`` +- input type is something else? + use its ``__bytes__`` method [5]_ ; if there isn't one, raise a ``TypeError`` -Examples: +Examples:: >>> b'%s' % b'abc' b'abc' @@ -83,7 +83,6 @@ TypeError: 'hello world' has no __bytes__ method, perhaps you need to encode it? .. note:: - Because the ``str`` type does not have a ``__bytes__`` method, attempts to directly use ``'a string'`` as a bytes interpolation value will raise an exception. To use ``'string'`` values, they must be encoded or otherwise @@ -116,21 +115,21 @@ It has been suggested to use ``%b`` for bytes instead of ``%s``. - - Rejected as ``%b`` does not exist in Python 2.x %-interpolation, which is - why we are using ``%s``. +- Rejected as ``%b`` does not exist in Python 2.x %-interpolation, which is + why we are using ``%s``. It has been proposed to automatically use ``.encode('ascii','strict')`` for ``str`` arguments to ``%s``. - - Rejected as this would lead to intermittent failures. Better to have the - operation always fail so the trouble-spot can be correctly fixed. +- Rejected as this would lead to intermittent failures. Better to have the + operation always fail so the trouble-spot can be correctly fixed. It has been proposed to have ``%s`` return the ascii-encoded repr when the value is a ``str`` (b'%s' % 'abc' --> b"'abc'"). - - Rejected as this would lead to hard to debug failures far from the problem - site. Better to have the operation always fail so the trouble-spot can be - easily fixed. +- Rejected as this would lead to hard to debug failures far from the problem + site. Better to have the operation always fail so the trouble-spot can be + easily fixed. Originally this PEP also proposed adding format style formatting, but it was decided that format and its related machinery were all strictly text -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Jan 21 23:07:02 2014 From: python-checkins at python.org (stefan.krah) Date: Tue, 21 Jan 2014 23:07:02 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMjQ2?= =?utf-8?q?=3A_Fix_test_failures_on_FreeBSD=2E_Patch_by_Ryan_Smith-Roberts?= =?utf-8?q?=2E?= Message-ID: <3f83kZ5ZfJz7Lm1@mail.python.org> http://hg.python.org/cpython/rev/5c4f4db8107c changeset: 88620:5c4f4db8107c branch: 3.3 parent: 88618:2fe0b2dcc98c user: Stefan Krah date: Tue Jan 21 22:58:40 2014 +0100 summary: Issue #20246: Fix test failures on FreeBSD. Patch by Ryan Smith-Roberts. files: Lib/test/test_socket.py | 2 +- 1 files changed, 1 insertions(+), 1 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 @@ -4542,7 +4542,7 @@ self.assertRaises(ValueError, self.cli_conn.recvfrom_into, buf, 1024) def _testRecvFromIntoSmallBuffer(self): - self.serv_conn.send(MSG*2048) + self.serv_conn.send(MSG) def testRecvFromIntoEmptyBuffer(self): buf = bytearray() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 23:07:04 2014 From: python-checkins at python.org (stefan.krah) Date: Tue, 21 Jan 2014 23:07:04 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320246=3A_Fix_test_failures_on_FreeBSD=2E_Patch_?= =?utf-8?q?by_Ryan_Smith-Roberts=2E?= Message-ID: <3f83kc0LrGz7LmN@mail.python.org> http://hg.python.org/cpython/rev/9bbc3cc8ff4c changeset: 88621:9bbc3cc8ff4c parent: 88619:60a954a018b9 parent: 88620:5c4f4db8107c user: Stefan Krah date: Tue Jan 21 22:59:57 2014 +0100 summary: Issue #20246: Fix test failures on FreeBSD. Patch by Ryan Smith-Roberts. files: Lib/test/test_socket.py | 2 +- 1 files changed, 1 insertions(+), 1 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 @@ -4687,7 +4687,7 @@ self.assertRaises(ValueError, self.cli_conn.recvfrom_into, buf, 1024) def _testRecvFromIntoSmallBuffer(self): - self.serv_conn.send(MSG*2048) + self.serv_conn.send(MSG) def testRecvFromIntoEmptyBuffer(self): buf = bytearray() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 21 23:07:05 2014 From: python-checkins at python.org (stefan.krah) Date: Tue, 21 Jan 2014 23:07:05 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIwMjQ2?= =?utf-8?q?=3A_Fix_test_failures_on_FreeBSD=2E_Patch_by_Ryan_Smith-Roberts?= =?utf-8?q?=2E?= Message-ID: <3f83kd27r4z7Ln1@mail.python.org> http://hg.python.org/cpython/rev/b6c5a37b221f changeset: 88622:b6c5a37b221f branch: 2.7 parent: 88617:d55d1cbf5f9a user: Stefan Krah date: Tue Jan 21 23:05:52 2014 +0100 summary: Issue #20246: Fix test failures on FreeBSD. Patch by Ryan Smith-Roberts. files: Lib/test/test_socket.py | 2 +- 1 files changed, 1 insertions(+), 1 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 @@ -1625,7 +1625,7 @@ def _testRecvFromIntoSmallBuffer(self): with test_support.check_py3k_warnings(): - buf = buffer(MSG*2048) + buf = buffer(MSG) self.serv_conn.send(buf) def testRecvFromIntoEmptyBuffer(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 22 00:31:06 2014 From: python-checkins at python.org (r.david.murray) Date: Wed, 22 Jan 2014 00:31:06 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_whatsnew=3A_smtpd_*map*_ar?= =?utf-8?q?gument=2C_new_ssl_functions/methods=2E?= Message-ID: <3f85bZ4FHsz7Lk1@mail.python.org> http://hg.python.org/cpython/rev/ca99518092a5 changeset: 88623:ca99518092a5 parent: 88621:9bbc3cc8ff4c user: R David Murray date: Tue Jan 21 18:30:42 2014 -0500 summary: whatsnew: smtpd *map* argument, new ssl functions/methods. Fleshed out Christian's placeholder for the new ssl methods. files: Doc/whatsnew/3.4.rst | 27 +++++++++++++++++++++++---- 1 files changed, 23 insertions(+), 4 deletions(-) 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 @@ -974,6 +974,16 @@ (Contributed by Filip Gruszczy?ski in :issue:`13896`.) +smtpd +----- + +The :class:`~smtpd.SMTPServer` and :class:`~smtpd.SMTPChannel` classes now +accept a *map* keyword argument, which if specified is passed in to +:class:`asynchat.async_chat` as its *map* argument. This allows an application +to avoid affecting the global socket map. (Contributed by Vinay Sajip in +:issue:`11959`.) + + smtplib ------- @@ -1019,10 +1029,19 @@ Python is linked with OpenSSL 1.0.1 or later. (Contributed by Michele Orr? and Antoine Pitrou in :issue:`16692`) -New diagnostic functions :func:`~ssl.get_default_verify_paths`, -:meth:`~ssl.SSLContext.cert_store_stats` and -:meth:`~ssl.SSLContext.get_ca_certs` (Contributed by Christian Heimes -in :issue:`18143` and :issue:`18147`) +New function :func:`~ssl.get_default_verify_paths` returns +a named tuple of the paths and environment variables that the +:meth:`~ssl.SSLContext.set_default_verify_paths` method uses to set +OpenSSL's default ``cafile`` and ``capath``. This can be an aid in +debugging default verification issues. (Contributed by Christian Heimes +in :issue:`18143`.) + +:class:`~ssl.SSLContext` has a new method, +:meth:`~ssl.SSLContext.cert_store_stats`, that reports the number of loaded +``X.509`` certs, ``X.509 CA`` certs, and certificate revocation lists (``crl``\ +s), as well as a :meth:`~ssl.SSLContext.get_ca_certs` method that returns a +list of the loaded ``CA`` certificates. (Contributed by Christian Heimes in +and :issue:`18147`.) Add :func:`ssl.enum_cert_store` to retrieve certificates and CRL from Windows' cert store. (Contributed by Christian Heimes in :issue:`17134`.) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 22 01:12:08 2014 From: python-checkins at python.org (florent.xicluna) Date: Wed, 22 Jan 2014 01:12:08 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3ODI1?= =?utf-8?q?=3A_Cursor_=5E_is_correctly_positioned_for_SyntaxError_and?= Message-ID: <3f86Vw0V75z7Lny@mail.python.org> http://hg.python.org/cpython/rev/6d1372237607 changeset: 88624:6d1372237607 branch: 3.3 parent: 88620:5c4f4db8107c user: Florent Xicluna date: Wed Jan 22 01:11:43 2014 +0100 summary: Issue #17825: Cursor ^ is correctly positioned for SyntaxError and IndentationError. files: Lib/test/test_traceback.py | 18 ++++++++++++++---- Lib/traceback.py | 7 ++++--- Misc/NEWS | 3 +++ 3 files changed, 21 insertions(+), 7 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 @@ -35,6 +35,9 @@ def syntax_error_with_caret_non_ascii(self): compile('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', "?", "exec") + def syntax_error_bad_indentation2(self): + compile(" print(2)", "?", "exec") + def test_caret(self): err = self.get_exception_format(self.syntax_error_with_caret, SyntaxError) @@ -46,14 +49,14 @@ err = self.get_exception_format(self.syntax_error_with_caret_2, SyntaxError) self.assertIn("^", err[2]) # third line has caret - self.assertTrue(err[2].count('\n') == 1) # and no additional newline - self.assertTrue(err[1].find("+") == err[2].find("^")) # in the right place + self.assertEqual(err[2].count('\n'), 1) # and no additional newline + self.assertEqual(err[1].find("+"), err[2].find("^")) # in the right place err = self.get_exception_format(self.syntax_error_with_caret_non_ascii, SyntaxError) self.assertIn("^", err[2]) # third line has caret - self.assertTrue(err[2].count('\n') == 1) # and no additional newline - self.assertTrue(err[1].find("+") == err[2].find("^")) # in the right place + self.assertEqual(err[2].count('\n'), 1) # and no additional newline + self.assertEqual(err[1].find("+"), err[2].find("^")) # in the right place def test_nocaret(self): exc = SyntaxError("error", ("x.py", 23, None, "bad syntax")) @@ -69,6 +72,13 @@ self.assertIn("^", err[2]) self.assertEqual(err[1].find(")"), err[2].find("^")) + err = self.get_exception_format(self.syntax_error_bad_indentation2, + IndentationError) + self.assertEqual(len(err), 4) + self.assertEqual(err[1].strip(), "print(2)") + self.assertIn("^", err[2]) + self.assertEqual(err[1].find("p"), err[2].find("^")) + def test_base_exception(self): # Test that exceptions derived from BaseException are formatted right e = KeyboardInterrupt() diff --git a/Lib/traceback.py b/Lib/traceback.py --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -227,11 +227,12 @@ if badline is not None: lines.append(' %s\n' % badline.strip()) if offset is not None: - caretspace = badline.rstrip('\n')[:offset].lstrip() + caretspace = badline.rstrip('\n') + offset = min(len(caretspace), offset) - 1 + caretspace = caretspace[:offset].lstrip() # non-space whitespace (likes tabs) must be kept for alignment caretspace = ((c.isspace() and c or ' ') for c in caretspace) - # only three spaces to account for offset1 == pos 0 - lines.append(' %s^\n' % ''.join(caretspace)) + lines.append(' %s^\n' % ''.join(caretspace)) msg = value.msg or "" lines.append("%s: %s\n" % (stype, msg)) return lines diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #17825: Cursor "^" is correctly positioned for SyntaxError and + IndentationError. + - Issue #2382: SyntaxError cursor "^" is now written at correct position in most cases when multibyte characters are in line (before "^"). This still not works correctly with wide East Asian characters. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 22 01:17:10 2014 From: python-checkins at python.org (florent.xicluna) Date: Wed, 22 Jan 2014 01:17:10 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317825=3A_Cursor_=5E_is_correctly_positioned_for?= =?utf-8?q?_SyntaxError_and?= Message-ID: <3f86ck6B9Bz7LjR@mail.python.org> http://hg.python.org/cpython/rev/aeb204b8f6c4 changeset: 88625:aeb204b8f6c4 parent: 88623:ca99518092a5 parent: 88624:6d1372237607 user: Florent Xicluna date: Wed Jan 22 01:16:25 2014 +0100 summary: Issue #17825: Cursor ^ is correctly positioned for SyntaxError and IndentationError. files: Lib/test/test_traceback.py | 18 ++++++++++++++---- Lib/traceback.py | 7 ++++--- Misc/NEWS | 3 +++ 3 files changed, 21 insertions(+), 7 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 @@ -35,6 +35,9 @@ def syntax_error_with_caret_non_ascii(self): compile('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', "?", "exec") + def syntax_error_bad_indentation2(self): + compile(" print(2)", "?", "exec") + def test_caret(self): err = self.get_exception_format(self.syntax_error_with_caret, SyntaxError) @@ -46,14 +49,14 @@ err = self.get_exception_format(self.syntax_error_with_caret_2, SyntaxError) self.assertIn("^", err[2]) # third line has caret - self.assertTrue(err[2].count('\n') == 1) # and no additional newline - self.assertTrue(err[1].find("+") == err[2].find("^")) # in the right place + self.assertEqual(err[2].count('\n'), 1) # and no additional newline + self.assertEqual(err[1].find("+"), err[2].find("^")) # in the right place err = self.get_exception_format(self.syntax_error_with_caret_non_ascii, SyntaxError) self.assertIn("^", err[2]) # third line has caret - self.assertTrue(err[2].count('\n') == 1) # and no additional newline - self.assertTrue(err[1].find("+") == err[2].find("^")) # in the right place + self.assertEqual(err[2].count('\n'), 1) # and no additional newline + self.assertEqual(err[1].find("+"), err[2].find("^")) # in the right place def test_nocaret(self): exc = SyntaxError("error", ("x.py", 23, None, "bad syntax")) @@ -69,6 +72,13 @@ self.assertIn("^", err[2]) self.assertEqual(err[1].find(")"), err[2].find("^")) + err = self.get_exception_format(self.syntax_error_bad_indentation2, + IndentationError) + self.assertEqual(len(err), 4) + self.assertEqual(err[1].strip(), "print(2)") + self.assertIn("^", err[2]) + self.assertEqual(err[1].find("p"), err[2].find("^")) + def test_base_exception(self): # Test that exceptions derived from BaseException are formatted right e = KeyboardInterrupt() diff --git a/Lib/traceback.py b/Lib/traceback.py --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -224,11 +224,12 @@ if badline is not None: yield ' {}\n'.format(badline.strip()) if offset is not None: - caretspace = badline.rstrip('\n')[:offset].lstrip() + caretspace = badline.rstrip('\n') + offset = min(len(caretspace), offset) - 1 + caretspace = caretspace[:offset].lstrip() # non-space whitespace (likes tabs) must be kept for alignment caretspace = ((c.isspace() and c or ' ') for c in caretspace) - # only three spaces to account for offset1 == pos 0 - yield ' {}^\n'.format(''.join(caretspace)) + yield ' {}^\n'.format(''.join(caretspace)) msg = value.msg or "" yield "{}: {}\n".format(stype, msg) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #17825: Cursor "^" is correctly positioned for SyntaxError and + IndentationError. + - Issue #2382: SyntaxError cursor "^" is now written at correct position in most cases when multibyte characters are in line (before "^"). This still not works correctly with wide East Asian characters. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 22 01:34:14 2014 From: python-checkins at python.org (florent.xicluna) Date: Wed, 22 Jan 2014 01:34:14 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3ODI1?= =?utf-8?q?=3A_Cursor_=5E_is_correctly_positioned_for_SyntaxError_and?= Message-ID: <3f870Q3JYMz7LjR@mail.python.org> http://hg.python.org/cpython/rev/0041be34edbf changeset: 88626:0041be34edbf branch: 2.7 parent: 88622:b6c5a37b221f user: Florent Xicluna date: Wed Jan 22 01:33:59 2014 +0100 summary: Issue #17825: Cursor ^ is correctly positioned for SyntaxError and IndentationError. files: Lib/test/test_traceback.py | 10 ++++++++++ Lib/traceback.py | 7 ++++--- Misc/NEWS | 3 +++ 3 files changed, 17 insertions(+), 3 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 @@ -35,6 +35,9 @@ def syntax_error_bad_indentation(self): compile("def spam():\n print 1\n print 2", "?", "exec") + def syntax_error_bad_indentation2(self): + compile(" print(2)", "?", "exec") + def test_caret(self): err = self.get_exception_format(self.syntax_error_with_caret, SyntaxError) @@ -111,6 +114,13 @@ os.unlink(os.path.join(testdir, f)) os.rmdir(testdir) + err = self.get_exception_format(self.syntax_error_bad_indentation2, + IndentationError) + self.assertEqual(len(err), 4) + self.assertEqual(err[1].strip(), "print(2)") + self.assertIn("^", err[2]) + self.assertEqual(err[1].find("p"), err[2].find("^")) + def test_base_exception(self): # Test that exceptions derived from BaseException are formatted right e = KeyboardInterrupt() diff --git a/Lib/traceback.py b/Lib/traceback.py --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -189,11 +189,12 @@ if badline is not None: lines.append(' %s\n' % badline.strip()) if offset is not None: - caretspace = badline.rstrip('\n')[:offset].lstrip() + caretspace = badline.rstrip('\n') + offset = min(len(caretspace), offset) - 1 + caretspace = caretspace[:offset].lstrip() # non-space whitespace (likes tabs) must be kept for alignment caretspace = ((c.isspace() and c or ' ') for c in caretspace) - # only three spaces to account for offset1 == pos 0 - lines.append(' %s^\n' % ''.join(caretspace)) + lines.append(' %s^\n' % ''.join(caretspace)) value = msg lines.append(_format_final_exc_line(stype, value)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,9 @@ Core and Builtins ----------------- +- Issue #17825: Cursor "^" is correctly positioned for SyntaxError and + IndentationError. + - Issue #19081: When a zipimport .zip file in sys.path being imported from is modified during the lifetime of the Python process after zipimport has already cached the zip's table of contents we detect this and recover -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 22 02:45:59 2014 From: python-checkins at python.org (terry.reedy) Date: Wed, 22 Jan 2014 02:45:59 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE2NjM4?= =?utf-8?q?=3A_Include_up_to_5_docstring_header_lines_=28before_first_blan?= =?utf-8?q?k=29_in?= Message-ID: <3f88bC6Znmz7Lmk@mail.python.org> http://hg.python.org/cpython/rev/6b62c923c0ef changeset: 88627:6b62c923c0ef branch: 2.7 user: Terry Jan Reedy date: Tue Jan 21 20:45:03 2014 -0500 summary: Issue #16638: Include up to 5 docstring header lines (before first blank) in Idle calltips. This is needed for builtins, such 3.x bytes (which is why 5). Based on patch by Serhiy Storchaka. files: Lib/idlelib/CallTips.py | 40 +++++++++---- Lib/idlelib/idle_test/test_calltips.py | 15 ++++- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -130,14 +130,24 @@ if rc is not None: return rc return None +# The following are used in get_arg_text +_MAX_COLS = 79 +_MAX_LINES = 5 # enough for bytes + def get_arg_text(ob): - """Get a string describing the arguments for the given object, - only if it is callable.""" - arg_text = "" + '''Return a string describing the signature of a callable object, or ''. + + For Python-coded functions and methods, the first line is introspected. + Delete 'self' parameter for classes (.__init__) and bound methods. + The next lines are the first lines of the doc string up to the first + empty line or _MAX_LINES. For builtins, this typically includes + the arguments in addition to the return value. + ''' + argspec = "" try: ob_call = ob.__call__ except BaseException: - return arg_text + return argspec arg_offset = 0 if type(ob) in (types.ClassType, types.TypeType): @@ -171,22 +181,24 @@ items.append("*args") if fob.func_code.co_flags & 0x8: items.append("**kwds") - arg_text = ", ".join(items) - arg_text = "(%s)" % re.sub("(?", arg_text) + argspec = ", ".join(items) + argspec = "(%s)" % re.sub("(?", argspec) # See if we can use the docstring if isinstance(ob_call, types.MethodType): doc = ob_call.__doc__ else: doc = getattr(ob, "__doc__", "") if doc: - doc = doc.lstrip() - pos = doc.find("\n") - if pos < 0 or pos > 70: - pos = 70 - if arg_text: - arg_text += "\n" - arg_text += doc[:pos] - return arg_text + lines = [argspec] if argspec else [] + for line in doc.split('\n', 5)[:_MAX_LINES]: + line = line.strip() + if not line: + break + if len(line) > _MAX_COLS: + line = line[: _MAX_COLS - 3] + '...' + lines.append(line) + argspec = '\n'.join(lines) + return argspec if __name__ == '__main__': from unittest import main diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -53,7 +53,6 @@ def gtest(obj, out): self.assertEqual(signature(obj), out) - gtest(list, "()\nlist() -> new empty list") gtest(List, '()\n' + List.__doc__) gtest(list.__new__, 'T.__new__(S, ...) -> a new object with type S, a subtype of T') @@ -67,6 +66,20 @@ gtest(types.MethodType, '()\ninstancemethod(function, instance, class)') gtest(SB(), default_tip) + def test_multiline_docstring(self): + # Test fewer lines than max. + self.assertEqual(signature(list), + "()\nlist() -> new empty list\n" + "list(iterable) -> new list initialized from iterable's items") + + # Test max lines and line (currently) too long. + def f(): + pass + s = 'a\nb\nc\nd\n' + f.__doc__ = s + 300 * 'e' + 'f' + self.assertEqual(signature(f), + '()\n' + s + (ct._MAX_COLS - 3) * 'e' + '...') + def test_functions(self): def t1(): 'doc' t1.tip = "()" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 22 02:46:01 2014 From: python-checkins at python.org (terry.reedy) Date: Wed, 22 Jan 2014 02:46:01 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE2NjM4?= =?utf-8?q?=3A_Include_up_to_5_docstring_header_lines_=28before_first_blan?= =?utf-8?q?k=29_in?= Message-ID: <3f88bF2RHTz7LnB@mail.python.org> http://hg.python.org/cpython/rev/5b6c3760714e changeset: 88628:5b6c3760714e branch: 3.3 parent: 88624:6d1372237607 user: Terry Jan Reedy date: Tue Jan 21 20:45:17 2014 -0500 summary: Issue #16638: Include up to 5 docstring header lines (before first blank) in Idle calltips. This is needed for builtins, such bytes (which is why 5). Based on patch by Serhiy Storchaka. files: Lib/idlelib/CallTips.py | 26 ++++++++----- Lib/idlelib/idle_test/test_calltips.py | 22 +++++++++-- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -116,17 +116,21 @@ # exception, especially if user classes are involved. return None -# The following are used in both get_argspec and tests +# The following are used in get_argspec and some in tests +_MAX_COLS = 79 +_MAX_LINES = 5 # enough for bytes _first_param = re.compile('(?<=\()\w*\,?\s*') _default_callable_argspec = "See source or doc" + def get_argspec(ob): '''Return a string describing the signature of a callable object, or ''. For Python-coded functions and methods, the first line is introspected. Delete 'self' parameter for classes (.__init__) and bound methods. - The last line is the first line of the doc string. For builtins, this typically - includes the arguments in addition to the return value. + The next lines are the first lines of the doc string up to the first + empty line or _MAX_LINES. For builtins, this typically includes + the arguments in addition to the return value. ''' argspec = "" try: @@ -150,13 +154,15 @@ else: doc = getattr(ob, "__doc__", "") if doc: - doc = doc.lstrip() - pos = doc.find("\n") - if pos < 0 or pos > 70: - pos = 70 - if argspec: - argspec += "\n" - argspec += doc[:pos] + lines = [argspec] if argspec else [] + for line in doc.split('\n', 5)[:_MAX_LINES]: + line = line.strip() + if not line: + break + if len(line) > _MAX_COLS: + line = line[: _MAX_COLS - 3] + '...' + lines.append(line) + argspec = '\n'.join(lines) if not argspec: argspec = _default_callable_argspec return argspec diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -42,17 +42,15 @@ # For a simple mismatch, change the expected output to the actual. def test_builtins(self): - # These test will break if # Python class that inherits builtin methods class List(list): "List() doc" - # Simulate builtin with no docstring for default argspec test + # Simulate builtin with no docstring for default tip test class SB: __call__ = None def gtest(obj, out): self.assertEqual(signature(obj), out) - gtest(list, "list() -> new empty list") gtest(List, List.__doc__) gtest(list.__new__, 'T.__new__(S, ...) -> a new object with type S, a subtype of T') @@ -66,6 +64,21 @@ gtest(types.MethodType, "method(function, instance)") gtest(SB(), default_tip) + def test_multiline_docstring(self): + # Test fewer lines than max. + self.assertEqual(signature(list), + "list() -> new empty list\n" + "list(iterable) -> new list initialized from iterable's items") + + # Test max lines and line (currently) too long. + self.assertEqual(signature(bytes), +"bytes(iterable_of_ints) -> bytes\n" +"bytes(string, encoding[, errors]) -> bytes\n" +"bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer\n" +#bytes(int) -> bytes object of size given by the parameter initialized with null bytes +"bytes(int) -> bytes object of size given by the parameter initialized with n...\n" +"bytes() -> empty bytes object") + def test_functions(self): def t1(): 'doc' t1.tip = "()" @@ -100,7 +113,8 @@ assert ct._first_param.sub('', uni) == '(a)' def test_no_docstring(self): - def nd(s): pass + def nd(s): + pass TC.nd = nd self.assertEqual(signature(nd), "(s)") self.assertEqual(signature(TC.nd), "(s)") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 22 02:46:02 2014 From: python-checkins at python.org (terry.reedy) Date: Wed, 22 Jan 2014 02:46:02 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E3?= Message-ID: <3f88bG4wqYz7Lnl@mail.python.org> http://hg.python.org/cpython/rev/544dc911c29e changeset: 88629:544dc911c29e parent: 88625:aeb204b8f6c4 parent: 88628:5b6c3760714e user: Terry Jan Reedy date: Tue Jan 21 20:45:38 2014 -0500 summary: Merge with 3.3 files: Lib/idlelib/CallTips.py | 26 ++++++++----- Lib/idlelib/idle_test/test_calltips.py | 22 +++++++++-- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -116,17 +116,21 @@ # exception, especially if user classes are involved. return None -# The following are used in both get_argspec and tests +# The following are used in get_argspec and some in tests +_MAX_COLS = 79 +_MAX_LINES = 5 # enough for bytes _first_param = re.compile('(?<=\()\w*\,?\s*') _default_callable_argspec = "See source or doc" + def get_argspec(ob): '''Return a string describing the signature of a callable object, or ''. For Python-coded functions and methods, the first line is introspected. Delete 'self' parameter for classes (.__init__) and bound methods. - The last line is the first line of the doc string. For builtins, this typically - includes the arguments in addition to the return value. + The next lines are the first lines of the doc string up to the first + empty line or _MAX_LINES. For builtins, this typically includes + the arguments in addition to the return value. ''' argspec = "" try: @@ -150,13 +154,15 @@ else: doc = getattr(ob, "__doc__", "") if doc: - doc = doc.lstrip() - pos = doc.find("\n") - if pos < 0 or pos > 70: - pos = 70 - if argspec: - argspec += "\n" - argspec += doc[:pos] + lines = [argspec] if argspec else [] + for line in doc.split('\n', 5)[:_MAX_LINES]: + line = line.strip() + if not line: + break + if len(line) > _MAX_COLS: + line = line[: _MAX_COLS - 3] + '...' + lines.append(line) + argspec = '\n'.join(lines) if not argspec: argspec = _default_callable_argspec return argspec diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -42,17 +42,15 @@ # For a simple mismatch, change the expected output to the actual. def test_builtins(self): - # These test will break if # Python class that inherits builtin methods class List(list): "List() doc" - # Simulate builtin with no docstring for default argspec test + # Simulate builtin with no docstring for default tip test class SB: __call__ = None def gtest(obj, out): self.assertEqual(signature(obj), out) - gtest(list, "list() -> new empty list") gtest(List, List.__doc__) gtest(list.__new__, 'T.__new__(S, ...) -> a new object with type S, a subtype of T') @@ -66,6 +64,21 @@ gtest(types.MethodType, "method(function, instance)") gtest(SB(), default_tip) + def test_multiline_docstring(self): + # Test fewer lines than max. + self.assertEqual(signature(list), + "list() -> new empty list\n" + "list(iterable) -> new list initialized from iterable's items") + + # Test max lines and line (currently) too long. + self.assertEqual(signature(bytes), +"bytes(iterable_of_ints) -> bytes\n" +"bytes(string, encoding[, errors]) -> bytes\n" +"bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer\n" +#bytes(int) -> bytes object of size given by the parameter initialized with null bytes +"bytes(int) -> bytes object of size given by the parameter initialized with n...\n" +"bytes() -> empty bytes object") + def test_functions(self): def t1(): 'doc' t1.tip = "()" @@ -100,7 +113,8 @@ assert ct._first_param.sub('', uni) == '(a)' def test_no_docstring(self): - def nd(s): pass + def nd(s): + pass TC.nd = nd self.assertEqual(signature(nd), "(s)") self.assertEqual(signature(TC.nd), "(s)") -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 22 03:13:48 2014 From: python-checkins at python.org (terry.reedy) Date: Wed, 22 Jan 2014 03:13:48 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIwODE4?= =?utf-8?q?=3A_Remove_code_from_idlelib=2ECallTipWindow=2Eshowtip_that_is_?= =?utf-8?q?now?= Message-ID: <3f89CJ0K7Rz7Ln4@mail.python.org> http://hg.python.org/cpython/rev/c28e07377b03 changeset: 88630:c28e07377b03 branch: 2.7 parent: 88627:6b62c923c0ef user: Terry Jan Reedy date: Tue Jan 21 21:12:13 2014 -0500 summary: Issue #20818: Remove code from idlelib.CallTipWindow.showtip that is now completely redundant. After 16638 patch, CallTips.get_argspec trims over-long signature strings as well as docstring lines. files: Lib/idlelib/CallTipWindow.py | 8 +------- 1 files changed, 1 insertions(+), 7 deletions(-) diff --git a/Lib/idlelib/CallTipWindow.py b/Lib/idlelib/CallTipWindow.py --- a/Lib/idlelib/CallTipWindow.py +++ b/Lib/idlelib/CallTipWindow.py @@ -48,13 +48,7 @@ def showtip(self, text, parenleft, parenright): """Show the calltip, bind events which will close it and reposition it. """ - # truncate overly long calltip - if len(text) >= 79: - textlines = text.splitlines() - for i, line in enumerate(textlines): - if len(line) > 79: - textlines[i] = line[:75] + ' ...' - text = '\n'.join(textlines) + # Only called in CallTips, where lines are truncated self.text = text if self.tipwindow or not self.text: return -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 22 03:13:49 2014 From: python-checkins at python.org (terry.reedy) Date: Wed, 22 Jan 2014 03:13:49 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwODE4?= =?utf-8?q?=3A_Remove_code_from_idlelib=2ECallTipWindow=2Eshowtip_that_is_?= =?utf-8?q?now?= Message-ID: <3f89CK2xXBz7Lnt@mail.python.org> http://hg.python.org/cpython/rev/1b89fd73c625 changeset: 88631:1b89fd73c625 branch: 3.3 parent: 88628:5b6c3760714e user: Terry Jan Reedy date: Tue Jan 21 21:12:24 2014 -0500 summary: Issue #20818: Remove code from idlelib.CallTipWindow.showtip that is now completely redundant. After 16638 patch, CallTips.get_argspec trims over-long signature strings as well as docstring lines. files: Lib/idlelib/CallTipWindow.py | 8 +------- 1 files changed, 1 insertions(+), 7 deletions(-) diff --git a/Lib/idlelib/CallTipWindow.py b/Lib/idlelib/CallTipWindow.py --- a/Lib/idlelib/CallTipWindow.py +++ b/Lib/idlelib/CallTipWindow.py @@ -48,13 +48,7 @@ def showtip(self, text, parenleft, parenright): """Show the calltip, bind events which will close it and reposition it. """ - # truncate overly long calltip - if len(text) >= 79: - textlines = text.splitlines() - for i, line in enumerate(textlines): - if len(line) > 79: - textlines[i] = line[:75] + ' ...' - text = '\n'.join(textlines) + # Only called in CallTips, where lines are truncated self.text = text if self.tipwindow or not self.text: return -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 22 03:13:51 2014 From: python-checkins at python.org (terry.reedy) Date: Wed, 22 Jan 2014 03:13:51 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E3?= Message-ID: <3f89CM2zzkz7Lpw@mail.python.org> http://hg.python.org/cpython/rev/eb3cb6495f22 changeset: 88632:eb3cb6495f22 parent: 88629:544dc911c29e parent: 88631:1b89fd73c625 user: Terry Jan Reedy date: Tue Jan 21 21:13:25 2014 -0500 summary: Merge with 3.3 files: Lib/idlelib/CallTipWindow.py | 8 +------- 1 files changed, 1 insertions(+), 7 deletions(-) diff --git a/Lib/idlelib/CallTipWindow.py b/Lib/idlelib/CallTipWindow.py --- a/Lib/idlelib/CallTipWindow.py +++ b/Lib/idlelib/CallTipWindow.py @@ -48,13 +48,7 @@ def showtip(self, text, parenleft, parenright): """Show the calltip, bind events which will close it and reposition it. """ - # truncate overly long calltip - if len(text) >= 79: - textlines = text.splitlines() - for i, line in enumerate(textlines): - if len(line) > 79: - textlines[i] = line[:75] + ' ...' - text = '\n'.join(textlines) + # Only called in CallTips, where lines are truncated self.text = text if self.tipwindow or not self.text: return -- Repository URL: http://hg.python.org/cpython From tjreedy at udel.edu Wed Jan 22 03:21:02 2014 From: tjreedy at udel.edu (Terry Reedy) Date: Tue, 21 Jan 2014 21:21:02 -0500 Subject: [Python-checkins] cpython (2.7): Issue #20818: Remove code from idlelib.CallTipWindow.showtip that is now In-Reply-To: <3f89CJ0K7Rz7Ln4@mail.python.org> References: <3f89CJ0K7Rz7Ln4@mail.python.org> Message-ID: <52DF2B0E.10708@udel.edu> On 1/21/2014 9:13 PM, terry.reedy wrote: > http://hg.python.org/cpython/rev/c28e07377b03 > changeset: 88630:c28e07377b03 > branch: 2.7 > parent: 88627:6b62c923c0ef > user: Terry Jan Reedy > date: Tue Jan 21 21:12:13 2014 -0500 > summary: > Issue #20818: #20338 - I have no idea how I mis-entered and missed this. From tjreedy at udel.edu Wed Jan 22 03:23:42 2014 From: tjreedy at udel.edu (Terry Reedy) Date: Tue, 21 Jan 2014 21:23:42 -0500 Subject: [Python-checkins] cpython (3.3): Issue #20818: Remove code from idlelib.CallTipWindow.showtip that is now In-Reply-To: <3f89CK2xXBz7Lnt@mail.python.org> References: <3f89CK2xXBz7Lnt@mail.python.org> Message-ID: <52DF2BAE.5010800@udel.edu> On 1/21/2014 9:13 PM, terry.reedy wrote: > http://hg.python.org/cpython/rev/1b89fd73c625 > changeset: 88631:1b89fd73c625 > branch: 3.3 > parent: 88628:5b6c3760714e > user: Terry Jan Reedy > date: Tue Jan 21 21:12:24 2014 -0500 > summary: > Issue #20818: Issue # 20338 Remove code from idlelib.CallTipWindow.showtip that is now > completely redundant. After 16638 patch, CallTips.get_argspec trims over-long > signature strings as well as docstring lines. > > files: > Lib/idlelib/CallTipWindow.py | 8 +------- > 1 files changed, 1 insertions(+), 7 deletions(-) > > > diff --git a/Lib/idlelib/CallTipWindow.py b/Lib/idlelib/CallTipWindow.py > --- a/Lib/idlelib/CallTipWindow.py > +++ b/Lib/idlelib/CallTipWindow.py > @@ -48,13 +48,7 @@ > def showtip(self, text, parenleft, parenright): > """Show the calltip, bind events which will close it and reposition it. > """ > - # truncate overly long calltip > - if len(text) >= 79: > - textlines = text.splitlines() > - for i, line in enumerate(textlines): > - if len(line) > 79: > - textlines[i] = line[:75] + ' ...' > - text = '\n'.join(textlines) > + # Only called in CallTips, where lines are truncated > self.text = text > if self.tipwindow or not self.text: > return > > > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > https://mail.python.org/mailman/listinfo/python-checkins > From python-checkins at python.org Wed Jan 22 06:07:49 2014 From: python-checkins at python.org (zach.ware) Date: Wed, 22 Jan 2014 06:07:49 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Argument_Clinic=3A_make_?= =?utf-8?q?=27destination=27_directive_work=2E?= Message-ID: <3f8F454y3yz7LnY@mail.python.org> http://hg.python.org/cpython/rev/fbc31e0b0c77 changeset: 88633:fbc31e0b0c77 user: Zachary Ware date: Tue Jan 21 23:07:12 2014 -0600 summary: Argument Clinic: make 'destination' directive work. files: Tools/clinic/clinic.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2752,11 +2752,11 @@ self.clinic.__dict__[name] = value def directive_destination(self, name, command, *args): - if command is 'new': - self.clinic.add_destination(name, command, *args) + if command == 'new': + self.clinic.add_destination(name, *args) return - if command is 'clear': + if command == 'clear': self.clinic.get_destination(name).clear() fail("unknown destination command", repr(command)) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed Jan 22 09:40:46 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 22 Jan 2014 09:40:46 +0100 Subject: [Python-checkins] Daily reference leaks (eb3cb6495f22): sum=-1 Message-ID: results for eb3cb6495f22 on branch "default" -------------------------------------------- test_httplib leaked [0, 0, -1] references, sum=-1 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogjwkTZD', '-x'] From python-checkins at python.org Wed Jan 22 12:06:13 2014 From: python-checkins at python.org (larry.hastings) Date: Wed, 22 Jan 2014 12:06:13 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Two_minor_Argument_Clinic_?= =?utf-8?q?bugfixes=3A_use_the_name_of_the_class_in_the?= Message-ID: <3f8P1d63Stz7LqP@mail.python.org> http://hg.python.org/cpython/rev/9bbb64e91913 changeset: 88634:9bbb64e91913 user: Larry Hastings date: Wed Jan 22 03:05:49 2014 -0800 summary: Two minor Argument Clinic bugfixes: use the name of the class in the docstring for __new__ and __init__, and always use "goto exit" instead of returning "NULL" for failure to parse (as _new__ and __init__ return ints). files: Modules/_cursesmodule.c | 13 +++++++------ Modules/_dbmmodule.c | 9 +++++---- Modules/_opcode.c | 8 ++++---- Modules/_pickle.c | 8 ++++---- Modules/zlibmodule.c | 9 +++++---- Tools/clinic/clinic.py | 10 +++++++--- 6 files changed, 32 insertions(+), 25 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -621,36 +621,37 @@ switch (PyTuple_GET_SIZE(args)) { case 1: if (!PyArg_ParseTuple(args, "O:addch", &ch)) - return NULL; + goto exit; break; case 2: if (!PyArg_ParseTuple(args, "Ol:addch", &ch, &attr)) - return NULL; + goto exit; group_right_1 = 1; break; case 3: if (!PyArg_ParseTuple(args, "iiO:addch", &x, &y, &ch)) - return NULL; + goto exit; group_left_1 = 1; break; case 4: if (!PyArg_ParseTuple(args, "iiOl:addch", &x, &y, &ch, &attr)) - return NULL; + goto exit; group_right_1 = 1; group_left_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "curses.window.addch requires 1 to 4 arguments"); - return NULL; + goto exit; } return_value = curses_window_addch_impl(self, group_left_1, x, y, ch, group_right_1, attr); +exit: return return_value; } static PyObject * curses_window_addch_impl(PyObject *self, int group_left_1, int x, int y, PyObject *ch, int group_right_1, long attr) -/*[clinic end generated code: checksum=b073327add8197b6ba7fb96c87062422c8312954]*/ +/*[clinic end generated code: checksum=53d44d79791b30950972b3256bdd464f7426bf82]*/ { PyCursesWindowObject *cwself = (PyCursesWindowObject *)self; int coordinates_group = group_left_1; diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c --- a/Modules/_dbmmodule.c +++ b/Modules/_dbmmodule.c @@ -300,25 +300,26 @@ switch (PyTuple_GET_SIZE(args)) { case 1: if (!PyArg_ParseTuple(args, "s#:get", &key, &key_length)) - return NULL; + goto exit; break; case 2: if (!PyArg_ParseTuple(args, "s#O:get", &key, &key_length, &default_value)) - return NULL; + goto exit; group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "dbm.dbm.get requires 1 to 2 arguments"); - return NULL; + goto exit; } return_value = dbm_dbm_get_impl((dbmobject *)self, key, key_length, group_right_1, default_value); +exit: return return_value; } static PyObject * dbm_dbm_get_impl(dbmobject *dp, const char *key, Py_ssize_clean_t key_length, int group_right_1, PyObject *default_value) -/*[clinic end generated code: checksum=2c3209571267017f1b9abbd19e1b521849fd5d4a]*/ +/*[clinic end generated code: checksum=ca8bf63ec226e71d3cf390749777f7d5b7361478]*/ { datum dbm_key, val; diff --git a/Modules/_opcode.c b/Modules/_opcode.c --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -42,16 +42,16 @@ switch (PyTuple_GET_SIZE(args)) { case 1: if (!PyArg_ParseTuple(args, "i:stack_effect", &opcode)) - return NULL; + goto exit; break; case 2: if (!PyArg_ParseTuple(args, "ii:stack_effect", &opcode, &oparg)) - return NULL; + goto exit; group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_opcode.stack_effect requires 1 to 2 arguments"); - return NULL; + goto exit; } _return_value = _opcode_stack_effect_impl(module, opcode, group_right_1, oparg); if ((_return_value == -1) && PyErr_Occurred()) @@ -64,7 +64,7 @@ static int _opcode_stack_effect_impl(PyModuleDef *module, int opcode, int group_right_1, int oparg) -/*[clinic end generated code: checksum=47e76ec27523da4ab192713642d32482cd743aa4]*/ +/*[clinic end generated code: checksum=58fb4f1b174fc92f783dc945ca712fb752a6c283]*/ { int effect; if (HAS_ARG(opcode)) { diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -4044,7 +4044,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_pickle_Pickler___init____doc__, -"__init__(file, protocol=None, fix_imports=True)\n" +"Pickler(file, protocol=None, fix_imports=True)\n" "This takes a binary file for writing a pickle data stream.\n" "\n" "The optional *protocol* argument tells the pickler to use the given\n" @@ -4088,7 +4088,7 @@ static int _pickle_Pickler___init___impl(PicklerObject *self, PyObject *file, PyObject *protocol, int fix_imports) -/*[clinic end generated code: checksum=10c8ea05194d08108471163d8202cf5e12975544]*/ +/*[clinic end generated code: checksum=d10dfb463511430b4faad9fca07627041a35b96e]*/ { _Py_IDENTIFIER(persistent_id); _Py_IDENTIFIER(dispatch_table); @@ -6581,7 +6581,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_pickle_Unpickler___init____doc__, -"__init__(file, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" +"Unpickler(file, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" "This takes a binary file for reading a pickle data stream.\n" "\n" "The protocol version of the pickle is detected automatically, so no\n" @@ -6628,7 +6628,7 @@ static int _pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file, int fix_imports, const char *encoding, const char *errors) -/*[clinic end generated code: checksum=6936e9188104e45b1b15e1c11fe77b3965409471]*/ +/*[clinic end generated code: checksum=eb1a2cfc7b6f97c33980cff3d3b97d184a382f02]*/ { _Py_IDENTIFIER(persistent_load); diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -205,19 +205,20 @@ switch (PyTuple_GET_SIZE(args)) { case 1: if (!PyArg_ParseTuple(args, "y*:compress", &bytes)) - return NULL; + goto exit; break; case 2: if (!PyArg_ParseTuple(args, "y*i:compress", &bytes, &level)) - return NULL; + goto exit; group_right_1 = 1; break; default: PyErr_SetString(PyExc_TypeError, "zlib.compress requires 1 to 2 arguments"); - return NULL; + goto exit; } return_value = zlib_compress_impl(module, &bytes, group_right_1, level); +exit: /* Cleanup for bytes */ if (bytes.obj) PyBuffer_Release(&bytes); @@ -227,7 +228,7 @@ static PyObject * zlib_compress_impl(PyModuleDef *module, Py_buffer *bytes, int group_right_1, int level) -/*[clinic end generated code: checksum=66c4d16d0b8b9dd423648d9ef00d6a89d3363665]*/ +/*[clinic end generated code: checksum=74648f97e6b9d3cc9cd568d47262d462bded7ed0]*/ { PyObject *ReturnVal = NULL; Byte *input, *output = NULL; diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -913,7 +913,7 @@ s = """ case {count}: if (!PyArg_ParseTuple(args, "{format_units}:{name}", {parse_arguments})) - return NULL; + goto exit; {group_booleans} break; """[1:] @@ -924,7 +924,7 @@ add(" default:\n") s = ' PyErr_SetString(PyExc_TypeError, "{} requires {} to {} arguments");\n' add(s.format(f.full_name, count_min, count_max)) - add(' return NULL;\n') + add(' goto exit;\n') add("}}") template_dict['option_group_parsing'] = output() @@ -3401,7 +3401,11 @@ ## docstring first line ## - add(f.name) + if f.kind in (METHOD_NEW, METHOD_INIT): + assert f.cls + add(f.cls.name) + else: + add(f.name) add('(') # populate "right_bracket_count" field for every parameter -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 22 12:27:00 2014 From: python-checkins at python.org (victor.stinner) Date: Wed, 22 Jan 2014 12:27:00 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Cleanup_logging?= =?utf-8?q?_in_BaseEventLoop=2E=5Frun=5Fonce=28=29?= Message-ID: <3f8PTc0DfRz7Lln@mail.python.org> http://hg.python.org/cpython/rev/a62072cf50a2 changeset: 88635:a62072cf50a2 user: Victor Stinner date: Wed Jan 22 12:26:01 2014 +0100 summary: asyncio: Cleanup logging in BaseEventLoop._run_once() logger.log() is now responsible to format the timeout. It might be faster if the log is disabled for DEBUG level, but it's also more readable and fix an issue with Python 2.6 in the Trollius project. files: Lib/asyncio/base_events.py | 7 +++++-- 1 files changed, 5 insertions(+), 2 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 @@ -614,12 +614,15 @@ t0 = self.time() event_list = self._selector.select(timeout) t1 = self.time() - argstr = '' if timeout is None else ' {:.3f}'.format(timeout) if t1-t0 >= 1: level = logging.INFO else: level = logging.DEBUG - logger.log(level, 'poll%s took %.3f seconds', argstr, t1-t0) + if timeout is not None: + logger.log(level, 'poll %.3f took %.3f seconds', + timeout, t1-t0) + else: + logger.log(level, 'poll took %.3f seconds', t1-t0) else: event_list = self._selector.select(timeout) self._process_events(event_list) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 22 13:19:02 2014 From: python-checkins at python.org (stefan.krah) Date: Wed, 22 Jan 2014 13:19:02 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fix_test_failu?= =?utf-8?q?res_--without-threads=2E?= Message-ID: <3f8Qdf53x3z7LkJ@mail.python.org> http://hg.python.org/cpython/rev/d8af233da629 changeset: 88636:d8af233da629 branch: 2.7 parent: 88630:c28e07377b03 user: Stefan Krah date: Wed Jan 22 13:18:09 2014 +0100 summary: Fix test failures --without-threads. files: Lib/test/test_nntplib.py | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_nntplib.py b/Lib/test/test_nntplib.py --- a/Lib/test/test_nntplib.py +++ b/Lib/test/test_nntplib.py @@ -1,7 +1,13 @@ import socket -import threading import nntplib import time +import unittest + +try: + import threading +except ImportError: + threading = None + from unittest import TestCase from test import test_support @@ -41,6 +47,7 @@ self.evt.wait() + at unittest.skipUnless(threading, 'threading required') class ServerTests(BaseServerTest): evil = False @@ -49,6 +56,7 @@ nntp.sock.close() + at unittest.skipUnless(threading, 'threading required') class EvilServerTests(BaseServerTest): evil = True -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 22 13:33:31 2014 From: python-checkins at python.org (nick.coghlan) Date: Wed, 22 Jan 2014 13:33:31 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMzE3?= =?utf-8?q?=3A_Don=27t_create_a_reference_loop_in_ExitStack?= Message-ID: <3f8QyM4yFTz7LjM@mail.python.org> http://hg.python.org/cpython/rev/b3c2472c12a1 changeset: 88637:b3c2472c12a1 branch: 3.3 parent: 88631:1b89fd73c625 user: Nick Coghlan date: Wed Jan 22 22:24:46 2014 +1000 summary: Issue #20317: Don't create a reference loop in ExitStack files: Lib/contextlib.py | 10 +++++++++- Lib/test/test_contextlib.py | 23 +++++++++++++++++++++++ Misc/NEWS | 6 ++++++ 3 files changed, 38 insertions(+), 1 deletions(-) diff --git a/Lib/contextlib.py b/Lib/contextlib.py --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -231,11 +231,19 @@ # we were actually nesting multiple with statements frame_exc = sys.exc_info()[1] def _fix_exception_context(new_exc, old_exc): + # Context isn't what we want, so find the end of the chain while 1: exc_context = new_exc.__context__ - if exc_context in (None, frame_exc): + if exc_context is old_exc: + # Context is already set correctly (see issue 20317) + return + if exc_context is None or exc_context is frame_exc: break + details = id(new_exc), id(old_exc), id(exc_context) + raise Exception(str(details)) new_exc = exc_context + # Change the end of the chain to point to the exception + # we expect it to reference new_exc.__context__ = old_exc # Callbacks are invoked in LIFO order to match the behaviour of diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py --- a/Lib/test/test_contextlib.py +++ b/Lib/test/test_contextlib.py @@ -600,6 +600,29 @@ else: self.fail("Expected KeyError, but no exception was raised") + def test_exit_exception_with_correct_context(self): + # http://bugs.python.org/issue20317 + @contextmanager + def gets_the_context_right(): + try: + yield 6 + finally: + 1 / 0 + + # The contextmanager already fixes the context, so prior to the + # fix, ExitStack would try to fix it *again* and get into an + # infinite self-referential loop + try: + with ExitStack() as stack: + stack.enter_context(gets_the_context_right()) + stack.enter_context(gets_the_context_right()) + stack.enter_context(gets_the_context_right()) + except ZeroDivisionError as exc: + self.assertIsInstance(exc.__context__, ZeroDivisionError) + self.assertIsInstance(exc.__context__.__context__, ZeroDivisionError) + self.assertIsNone(exc.__context__.__context__.__context__) + + def test_body_exception_suppress(self): def suppress_exc(*exc_details): return True diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -50,6 +50,12 @@ Library ------- +- Issue #20317: ExitStack.__exit__ could create a self-referential loop if an + exception raised by a cleanup operation already had its context set + correctly (for example, by the @contextmanager decorator). The infinite + loop this caused is now avoided by checking if the expected context is + already set before trying to fix it. + - Issue #20311: select.epoll.poll() now rounds the timeout away from zero, instead of rounding towards zero. For example, a timeout of one microsecond is now rounded to one millisecond, instead of being rounded to zero. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 22 14:05:04 2014 From: python-checkins at python.org (nick.coghlan) Date: Wed, 22 Jan 2014 14:05:04 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2320317_from_3=2E3?= Message-ID: <3f8Rfm1jnxz7LjV@mail.python.org> http://hg.python.org/cpython/rev/46c3ea358784 changeset: 88638:46c3ea358784 parent: 88635:a62072cf50a2 parent: 88637:b3c2472c12a1 user: Nick Coghlan date: Wed Jan 22 23:04:37 2014 +1000 summary: Merge #20317 from 3.3 files: Lib/contextlib.py | 10 +++++++++- Lib/test/test_contextlib.py | 23 +++++++++++++++++++++++ Misc/NEWS | 6 ++++++ 3 files changed, 38 insertions(+), 1 deletions(-) diff --git a/Lib/contextlib.py b/Lib/contextlib.py --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -298,11 +298,19 @@ # we were actually nesting multiple with statements frame_exc = sys.exc_info()[1] def _fix_exception_context(new_exc, old_exc): + # Context isn't what we want, so find the end of the chain while 1: exc_context = new_exc.__context__ - if exc_context in (None, frame_exc): + if exc_context is old_exc: + # Context is already set correctly (see issue 20317) + return + if exc_context is None or exc_context is frame_exc: break + details = id(new_exc), id(old_exc), id(exc_context) + raise Exception(str(details)) new_exc = exc_context + # Change the end of the chain to point to the exception + # we expect it to reference new_exc.__context__ = old_exc # Callbacks are invoked in LIFO order to match the behaviour of diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py --- a/Lib/test/test_contextlib.py +++ b/Lib/test/test_contextlib.py @@ -626,6 +626,29 @@ else: self.fail("Expected KeyError, but no exception was raised") + def test_exit_exception_with_correct_context(self): + # http://bugs.python.org/issue20317 + @contextmanager + def gets_the_context_right(): + try: + yield 6 + finally: + 1 / 0 + + # The contextmanager already fixes the context, so prior to the + # fix, ExitStack would try to fix it *again* and get into an + # infinite self-referential loop + try: + with ExitStack() as stack: + stack.enter_context(gets_the_context_right()) + stack.enter_context(gets_the_context_right()) + stack.enter_context(gets_the_context_right()) + except ZeroDivisionError as exc: + self.assertIsInstance(exc.__context__, ZeroDivisionError) + self.assertIsInstance(exc.__context__.__context__, ZeroDivisionError) + self.assertIsNone(exc.__context__.__context__.__context__) + + def test_body_exception_suppress(self): def suppress_exc(*exc_details): return True diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,6 +37,12 @@ microsecond is now rounded to one millisecond, instead of being rounded to zero. +- Issue #20317: ExitStack.__exit__ could create a self-referential loop if an + exception raised by a cleanup operation already had its context set + correctly (for example, by the @contextmanager decorator). The infinite + loop this caused is now avoided by checking if the expected context is + already set before trying to fix it. + - Issue #20311: select.epoll.poll() now rounds the timeout away from zero, instead of rounding towards zero. For example, a timeout of one microsecond is now rounded to one millisecond, instead of being rounded to zero. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 22 14:49:34 2014 From: python-checkins at python.org (larry.hastings) Date: Wed, 22 Jan 2014 14:49:34 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Doc_fixes_for_Argument_Cli?= =?utf-8?q?nic=2E?= Message-ID: <3f8Sf66kSYz7LjV@mail.python.org> http://hg.python.org/cpython/rev/9a98ff4a2290 changeset: 88639:9a98ff4a2290 user: Larry Hastings date: Wed Jan 22 05:49:11 2014 -0800 summary: Doc fixes for Argument Clinic. files: Doc/howto/clinic.rst | 24 ++++++++++++++++++------ 1 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -626,6 +626,15 @@ They can be to the left or the right of the required arguments. They can *only* be used with positional-only parameters. +.. note:: Optional groups are *only* intended for use when converting + functions that make multiple calls to :c:func:`PyArg_ParseTuple`! + Functions that use *any* other approach for parsing arguments + should *almost never* be converted to Argument Clinic using + optional groups. Functions using optional groups currently + cannot have accurate sigantures in Python, because Python just + doesn't understand the concept. Please avoid using optional + groups wherever possible. + To specify an optional group, add a ``[`` on a line by itself before the parameters you wish to group together, and a ``]`` on a line by itself after these parameters. As an example, here's how ``curses.window.addch`` @@ -1278,9 +1287,8 @@ tp_new and tp_init functions ---------------------------------------------- -You can convert ``tp_new`` and ``tp_init`` -functions. Just name them ``__new__`` or -``__init__`` as appropriate. Notes: +You can convert ``tp_new`` and ``tp_init`` functions. Just name +them ``__new__`` or ``__init__`` as appropriate. Notes: * The function name generated for ``__new__`` doesn't end in ``__new__`` like it would by default. It's just the name of the class, converted @@ -1290,9 +1298,13 @@ * ``__init__`` functions return ``int``, not ``PyObject *``. -* Argument Clinic supports any signature for these functions, even though - the parsing function is required to always take ``args`` and ``kwargs`` - objects. +* Use the docstring as the class docstring. + +* Although ``__new__`` and ``__init__`` functions must always + accept both the ``args`` and ``kwargs`` objects, when converting + you may specify any signature for these functions that you like. + (If your function doesn't support keywords, the parsing function + generated will throw an exception if it receives any.) The #ifdef trick ---------------------------------------------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 22 23:48:46 2014 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 22 Jan 2014 23:48:46 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Change_the_definition_of_wait?= =?utf-8?q?=5Ffor=28=29_to_a_more_useful_one=2E?= Message-ID: <3f8hcG3KKTz7Ljl@mail.python.org> http://hg.python.org/peps/rev/bcd20b88eada changeset: 5355:bcd20b88eada user: Guido van Rossum date: Wed Jan 22 14:48:12 2014 -0800 summary: Change the definition of wait_for() to a more useful one. (This is a change in the spec. But I don't recall we ever seriously discussed this part of the spec, and the new behavior is more useful and more intuitive. See discussion started by Gustavo Carneiro in http://code.google.com/p/tulip/issues/detail?id=107 .) files: pep-3156.txt | 9 ++++----- 1 files changed, 4 insertions(+), 5 deletions(-) diff --git a/pep-3156.txt b/pep-3156.txt --- a/pep-3156.txt +++ b/pep-3156.txt @@ -1582,11 +1582,10 @@ your ``for`` loop may not make progress (since you are not allowing other tasks to run). -- ``asyncio.wait_for(f, timeout)``. This is a convenience to wait for a - single coroutine or Future with a timeout. It is a simple wrapper - around ``asyncio.wait()`` with a single item in the first argument, - returning the result or raising the exception if it is completed - within the timeout, raising ``TimeoutError`` otherwise. +- ``asyncio.wait_for(f, timeout)``. This is a convenience to wait for + a single coroutine or Future with a timeout. When a timeout occurs, + it cancels the task and raises TimeoutError. To avoid the task + cancellation, wrap it in shield(). - ``asyncio.gather(f1, f2, ...)``. Returns a Future which waits until all arguments (Futures or coroutines) are done and return a list of -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Jan 23 01:13:25 2014 From: python-checkins at python.org (richard.oudkerk) Date: Thu, 23 Jan 2014 01:13:25 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE0NTQ4?= =?utf-8?q?=3A_Make_multiprocessing_finalizers_check_pid_before?= Message-ID: <3f8kTx3HDkz7LjP@mail.python.org> http://hg.python.org/cpython/rev/751371dd4d1c changeset: 88640:751371dd4d1c branch: 2.7 parent: 88636:d8af233da629 user: Richard Oudkerk date: Thu Jan 23 00:11:04 2014 +0000 summary: Issue #14548: Make multiprocessing finalizers check pid before running to cope with possibility of gc running just after fork. (Backport from 3.x.) files: Lib/multiprocessing/util.py | 12 +++++++++--- Misc/NEWS | 4 ++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Lib/multiprocessing/util.py b/Lib/multiprocessing/util.py --- a/Lib/multiprocessing/util.py +++ b/Lib/multiprocessing/util.py @@ -32,6 +32,7 @@ # SUCH DAMAGE. # +import os import itertools import weakref import atexit @@ -184,6 +185,7 @@ self._args = args self._kwargs = kwargs or {} self._key = (exitpriority, _finalizer_counter.next()) + self._pid = os.getpid() _finalizer_registry[self._key] = self @@ -196,9 +198,13 @@ except KeyError: sub_debug('finalizer no longer registered') else: - sub_debug('finalizer calling %s with args %s and kwargs %s', - self._callback, self._args, self._kwargs) - res = self._callback(*self._args, **self._kwargs) + if self._pid != os.getpid(): + sub_debug('finalizer ignored because different process') + res = None + else: + sub_debug('finalizer calling %s with args %s and kwargs %s', + self._callback, self._args, self._kwargs) + res = self._callback(*self._args, **self._kwargs) self._weakref = self._callback = self._args = \ self._kwargs = self._key = None return res diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -38,6 +38,10 @@ Library ------- +- Issue #14548: Make multiprocessing finalizers check pid before + running to cope with possibility of gc running just after fork. + (Backport from 3.x.) + - Issue #20262: Warnings are raised now when duplicate names are added in the ZIP file or too long ZIP file comment is truncated. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 06:40:12 2014 From: python-checkins at python.org (terry.reedy) Date: Thu, 23 Jan 2014 06:40:12 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3Mzkw?= =?utf-8?q?=3A_Add_Python_version_to_Idle_editor_window_title_bar=2E?= Message-ID: <3f8sl010xLz7Lk7@mail.python.org> http://hg.python.org/cpython/rev/bcfbab86f49a changeset: 88641:bcfbab86f49a branch: 2.7 user: Terry Jan Reedy date: Thu Jan 23 00:36:37 2014 -0500 summary: Issue #17390: Add Python version to Idle editor window title bar. Original patches by Edmond Burnett and Kent Johnson. files: Lib/idlelib/EditorWindow.py | 6 +++++- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 3 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -1,5 +1,6 @@ import sys import os +from platform import python_version import re import imp from Tkinter import * @@ -965,11 +966,14 @@ self.undo.reset_undo() def short_title(self): + pyversion = "Python " + python_version() + ": " filename = self.io.filename if filename: filename = os.path.basename(filename) + else: + filename = "Untitled" # return unicode string to display non-ASCII chars correctly - return self._filename_to_unicode(filename) + return pyversion + self._filename_to_unicode(filename) def long_title(self): # return unicode string to display non-ASCII chars correctly diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -145,6 +145,7 @@ Dick Bulterman Bill Bumgarner Jimmy Burgett +Edmond Burnett Tommy Burnette Roger Burnham Alastair Burt diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -183,6 +183,9 @@ IDLE ---- +- Issue #17390: Add Python version to Idle editor window title bar. + Original patches by Edmond Burnett and Kent Johnson. + - Issue #20058: sys.stdin.readline() in IDLE now always returns only one line. - Issue #19481: print() of unicode, str or bytearray subclass instance in IDLE -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 06:40:13 2014 From: python-checkins at python.org (terry.reedy) Date: Thu, 23 Jan 2014 06:40:13 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3Mzkw?= =?utf-8?q?=3A_Add_Python_version_to_Idle_editor_window_title_bar=2E?= Message-ID: <3f8sl12v3cz7LkS@mail.python.org> http://hg.python.org/cpython/rev/b26db63bb931 changeset: 88642:b26db63bb931 branch: 3.3 parent: 88637:b3c2472c12a1 user: Terry Jan Reedy date: Thu Jan 23 00:36:46 2014 -0500 summary: Issue #17390: Add Python version to Idle editor window title bar. Original patches by Edmond Burnett and Kent Johnson. files: Lib/idlelib/EditorWindow.py | 6 +++++- Misc/NEWS | 3 +++ 2 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -1,6 +1,7 @@ import importlib import importlib.abc import os +from platform import python_version import re import string import sys @@ -955,11 +956,14 @@ self.undo.reset_undo() def short_title(self): + pyversion = "Python " + python_version() + ": " filename = self.io.filename if filename: filename = os.path.basename(filename) + else: + filename = "Untitled" # return unicode string to display non-ASCII chars correctly - return self._filename_to_unicode(filename) + return pyversion + self._filename_to_unicode(filename) def long_title(self): # return unicode string to display non-ASCII chars correctly diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -274,6 +274,9 @@ IDLE ---- +--Issue #17390: Add Python version to Idle editor window title bar. + Original patches by Edmond Burnett and Kent Johnson. + - Issue #18960: IDLE now ignores the source encoding declaration on the second line if the first line contains anything except a comment. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 06:40:14 2014 From: python-checkins at python.org (terry.reedy) Date: Thu, 23 Jan 2014 06:40:14 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E3?= Message-ID: <3f8sl24p80z7Ljv@mail.python.org> http://hg.python.org/cpython/rev/aa1ad9e2f978 changeset: 88643:aa1ad9e2f978 parent: 88639:9a98ff4a2290 parent: 88642:b26db63bb931 user: Terry Jan Reedy date: Thu Jan 23 00:39:11 2014 -0500 summary: Merge with 3.3 files: Lib/idlelib/EditorWindow.py | 6 +++++- Misc/NEWS | 3 +++ 2 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -1,6 +1,7 @@ import importlib import importlib.abc import os +from platform import python_version import re import string import sys @@ -955,11 +956,14 @@ self.undo.reset_undo() def short_title(self): + pyversion = "Python " + python_version() + ": " filename = self.io.filename if filename: filename = os.path.basename(filename) + else: + filename = "Untitled" # return unicode string to display non-ASCII chars correctly - return self._filename_to_unicode(filename) + return pyversion + self._filename_to_unicode(filename) def long_title(self): # return unicode string to display non-ASCII chars correctly diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -118,6 +118,9 @@ IDLE ---- +--Issue #17390: Add Python version to Idle editor window title bar. + Original patches by Edmond Burnett and Kent Johnson. + - Issue #18960: IDLE now ignores the source encoding declaration on the second line if the first line contains anything except a comment. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 08:59:09 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 23 Jan 2014 08:59:09 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogQWRkZWQgdGVzdF91?= =?utf-8?q?ser=5Fcommand_in_test=5Ftcl=2E?= Message-ID: <3f8wqK1fvjz7LjM@mail.python.org> http://hg.python.org/cpython/rev/43f9295f6b99 changeset: 88644:43f9295f6b99 branch: 2.7 parent: 88641:bcfbab86f49a user: Serhiy Storchaka date: Thu Jan 23 09:42:46 2014 +0200 summary: Added test_user_command in test_tcl. It tests the convertion Tcl values to Python values when Tcl calls a command implemented on Python. Currently all values are passed as strings. files: Lib/test/test_tcl.py | 28 ++++++++++++++++++++++++++++ 1 files changed, 28 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -204,6 +204,34 @@ self.assertEqual(passValue((1, '2', (3.4,))), (1, '2', (3.4,)) if self.wantobjects else '1 2 3.4') + def test_user_command(self): + result = [] + def testfunc(arg): + result.append(arg) + return arg + self.interp.createcommand('testfunc', testfunc) + def check(value, expected): + del result[:] + self.assertEqual(self.interp.call('testfunc', value), expected) + self.assertEqual(result, [expected]) + + check(True, '1') + check(False, '0') + check('string', 'string') + check('string\xbd', 'string\xbd') + check('string\u20ac', 'string\u20ac') + for i in (0, 1, -1, 2**31-1, -2**31): + check(i, str(i)) + for f in (0.0, 1.0, -1.0, 1/3, + sys.float_info.min, sys.float_info.max, + -sys.float_info.min, -sys.float_info.max): + check(f, repr(f)) + check(float('nan'), 'NaN') + check(float('inf'), 'Inf') + check(-float('inf'), '-Inf') + check((), '') + check((1, (2,), (3, 4), '5 6', ()), '1 2 {3 4} {5 6} {}') + def test_splitlist(self): splitlist = self.interp.tk.splitlist call = self.interp.tk.call -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 08:59:10 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 23 Jan 2014 08:59:10 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogQWRkZWQgdGVzdF91?= =?utf-8?q?ser=5Fcommand_in_test=5Ftcl=2E?= Message-ID: <3f8wqL392cz7LjM@mail.python.org> http://hg.python.org/cpython/rev/f141c325a820 changeset: 88645:f141c325a820 branch: 3.3 parent: 88642:b26db63bb931 user: Serhiy Storchaka date: Thu Jan 23 09:44:05 2014 +0200 summary: Added test_user_command in test_tcl. It tests the convertion Tcl values to Python values when Tcl calls a command implemented on Python. Currently all values are passed as strings. files: Lib/test/test_tcl.py | 28 ++++++++++++++++++++++++++++ 1 files changed, 28 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -192,6 +192,34 @@ self.assertEqual(passValue((1, '2', (3.4,))), (1, '2', (3.4,)) if self.wantobjects else '1 2 3.4') + def test_user_command(self): + result = None + def testfunc(arg): + nonlocal result + result = arg + return arg + self.interp.createcommand('testfunc', testfunc) + def check(value, expected): + self.assertEqual(self.interp.call('testfunc', value), expected) + self.assertEqual(result, expected) + + check(True, '1') + check(False, '0') + check('string', 'string') + check('string\xbd', 'string\xbd') + check('string\u20ac', 'string\u20ac') + for i in (0, 1, -1, 2**31-1, -2**31): + check(i, str(i)) + for f in (0.0, 1.0, -1.0, 1/3, + sys.float_info.min, sys.float_info.max, + -sys.float_info.min, -sys.float_info.max): + check(f, str(f)) + check(float('nan'), 'NaN') + check(float('inf'), 'Inf') + check(-float('inf'), '-Inf') + check((), '') + check((1, (2,), (3, 4), '5 6', ()), '1 2 {3 4} {5 6} {}') + def test_splitlist(self): splitlist = self.interp.tk.splitlist call = self.interp.tk.call -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 08:59:11 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 23 Jan 2014 08:59:11 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Added_test=5Fuser=5Fcommand_in_test=5Ftcl=2E?= Message-ID: <3f8wqM4ymxz7LkK@mail.python.org> http://hg.python.org/cpython/rev/89b738e3d0c9 changeset: 88646:89b738e3d0c9 parent: 88643:aa1ad9e2f978 parent: 88645:f141c325a820 user: Serhiy Storchaka date: Thu Jan 23 09:49:42 2014 +0200 summary: Added test_user_command in test_tcl. It tests the convertion Tcl values to Python values when Tcl calls a command implemented on Python. Currently all values are passed as strings. files: Lib/test/test_tcl.py | 28 ++++++++++++++++++++++++++++ 1 files changed, 28 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -192,6 +192,34 @@ self.assertEqual(passValue((1, '2', (3.4,))), (1, '2', (3.4,)) if self.wantobjects else '1 2 3.4') + def test_user_command(self): + result = None + def testfunc(arg): + nonlocal result + result = arg + return arg + self.interp.createcommand('testfunc', testfunc) + def check(value, expected): + self.assertEqual(self.interp.call('testfunc', value), expected) + self.assertEqual(result, expected) + + check(True, '1') + check(False, '0') + check('string', 'string') + check('string\xbd', 'string\xbd') + check('string\u20ac', 'string\u20ac') + for i in (0, 1, -1, 2**31-1, -2**31): + check(i, str(i)) + for f in (0.0, 1.0, -1.0, 1/3, + sys.float_info.min, sys.float_info.max, + -sys.float_info.min, -sys.float_info.max): + check(f, str(f)) + check(float('nan'), 'NaN') + check(float('inf'), 'Inf') + check(-float('inf'), '-Inf') + check((), '') + check((1, (2,), (3, 4), '5 6', ()), '1 2 {3 4} {5 6} {}') + def test_splitlist(self): splitlist = self.interp.tk.splitlist call = self.interp.tk.call -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu Jan 23 09:38:33 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 23 Jan 2014 09:38:33 +0100 Subject: [Python-checkins] Daily reference leaks (9a98ff4a2290): sum=0 Message-ID: results for 9a98ff4a2290 on branch "default" -------------------------------------------- test_site leaked [2, -2, 0] references, sum=0 test_site leaked [2, -2, 0] memory blocks, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflognmruNi', '-x'] From python-checkins at python.org Thu Jan 23 09:42:25 2014 From: python-checkins at python.org (georg.brandl) Date: Thu, 23 Jan 2014 09:42:25 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?devguide=3A_Add_Yury=2E?= Message-ID: <3f8xnF3cSLz7Lk5@mail.python.org> http://hg.python.org/devguide/rev/aca153e57ef0 changeset: 659:aca153e57ef0 user: Georg Brandl date: Thu Jan 23 09:43:06 2014 +0100 summary: Add Yury. files: developers.rst | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/developers.rst b/developers.rst --- a/developers.rst +++ b/developers.rst @@ -24,6 +24,9 @@ Permissions History ------------------- +- Yury Selivanov was given push privileges on Jan 23 2014 by GFB, for "inspect" + module and general contributions, on recommendation by Nick Coghlan. + - Donald Stufft was given push privileges on Aug 14 2013 by BAC, for PEP editing, on the recommendation of Nick Coghlan. -- Repository URL: http://hg.python.org/devguide From root at python.org Thu Jan 23 09:45:04 2014 From: root at python.org (Cron Daemon) Date: Thu, 23 Jan 2014 09:45:04 +0100 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: Could not find platform independent libraries Could not find platform dependent libraries Consider setting $PYTHONHOME to [:] 'import site' failed; use -v for traceback Traceback (most recent call last): File "/data/hg/sphinx-env/bin/sphinx-build", line 5, in from pkg_resources import load_entry_point ImportError: No module named pkg_resources From python-checkins at python.org Thu Jan 23 10:04:02 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 23 Jan 2014 10:04:02 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Try_to_fix_tes?= =?utf-8?q?t=5Fuser=5Fcommand_on_OpenSolaris_where_floats_can_have_differe?= =?utf-8?q?nt?= Message-ID: <3f8yGB3MQ7z7LjW@mail.python.org> http://hg.python.org/cpython/rev/5f91500b3b02 changeset: 88647:5f91500b3b02 branch: 2.7 parent: 88644:43f9295f6b99 user: Serhiy Storchaka date: Thu Jan 23 11:03:02 2014 +0200 summary: Try to fix test_user_command on OpenSolaris where floats can have different string representation in Tcl and Python. files: Lib/test/test_tcl.py | 16 ++++++++++------ 1 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -210,10 +210,14 @@ result.append(arg) return arg self.interp.createcommand('testfunc', testfunc) - def check(value, expected): + def check(value, expected, conv=lambda x: x): del result[:] - self.assertEqual(self.interp.call('testfunc', value), expected) - self.assertEqual(result, [expected]) + r = self.interp.call('testfunc', value) + self.assertEqual(len(result), 1) + self.assertIsInstance(result[0], str) + self.assertEqual(conv(result[0]), expected) + self.assertIsInstance(r, str) + self.assertEqual(conv(r), expected) check(True, '1') check(False, '0') @@ -225,10 +229,10 @@ for f in (0.0, 1.0, -1.0, 1/3, sys.float_info.min, sys.float_info.max, -sys.float_info.min, -sys.float_info.max): - check(f, repr(f)) + check(f, f, conv=float) + check(float('inf'), float('inf'), conv=float) + check(-float('inf'), -float('inf'), conv=float) check(float('nan'), 'NaN') - check(float('inf'), 'Inf') - check(-float('inf'), '-Inf') check((), '') check((1, (2,), (3, 4), '5 6', ()), '1 2 {3 4} {5 6} {}') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 10:21:02 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 23 Jan 2014 10:21:02 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Fix_open=5Fconn?= =?utf-8?q?ection=28=29_documentation=2C_writer_is_a_StreamWriter?= Message-ID: <3f8ydp1XzJz7Lkt@mail.python.org> http://hg.python.org/cpython/rev/dcfbce47c024 changeset: 88648:dcfbce47c024 parent: 88646:89b738e3d0c9 user: Victor Stinner date: Thu Jan 23 10:20:18 2014 +0100 summary: asyncio: Fix open_connection() documentation, writer is a StreamWriter files: Doc/library/asyncio-protocol.rst | 6 +++--- Lib/asyncio/streams.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) 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 @@ -535,8 +535,8 @@ A wrapper for :meth:`~BaseEventLoop.create_connection()` returning a (reader, writer) pair. - The reader returned is a :class:`StreamReader` instance; the writer is a - transport. + The reader returned is a :class:`StreamReader` instance; the writer is + a :class:`StreamWriter` instance. The arguments are all the usual arguments to :meth:`BaseEventLoop.create_connection` except *protocol_factory*; most @@ -545,7 +545,7 @@ Additional optional keyword arguments are *loop* (to set the event loop instance to use) and *limit* (to set the buffer limit passed to the - StreamReader). + :class:`StreamReader`). (If you want to customize the :class:`StreamReader` and/or :class:`StreamReaderProtocol` classes, just copy the code -- there's really diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -21,7 +21,7 @@ """A wrapper for create_connection() returning a (reader, writer) pair. The reader returned is a StreamReader instance; the writer is a - Transport. + StreamWriter. The arguments are all the usual arguments to create_connection() except protocol_factory; most common are positional host and port, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 11:05:10 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 23 Jan 2014 11:05:10 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio_doc=3A_move_stream?= =?utf-8?q?_classes_to_their_own_class?= Message-ID: <3f8zck4ZGwz7Lk0@mail.python.org> http://hg.python.org/cpython/rev/90c49a2684ba changeset: 88649:90c49a2684ba user: Victor Stinner date: Thu Jan 23 10:54:57 2014 +0100 summary: asyncio doc: move stream classes to their own class files: Doc/library/asyncio-protocol.rst | 103 +++++++++++++----- 1 files changed, 74 insertions(+), 29 deletions(-) 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 @@ -1,8 +1,8 @@ .. currentmodule:: asyncio -++++++++++++++++++++++++ -Transports and protocols -++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++ +Transports, streams and protocols ++++++++++++++++++++++++++++++++++ .. _transport: @@ -228,6 +228,53 @@ stop the subprocess. +Streams +======= + +StreamReader +------------ + +.. class:: StreamReader(limit=_DEFAULT_LIMIT, loop=None) + + .. method:: exception() + + Get the exception. + + .. method:: feed_eof() + + XXX + + .. method:: feed_data(data) + + XXX + + .. method:: set_exception(exc) + + Set the exception. + + .. method:: set_transport(transport) + + Set the transport. + + .. method:: read(n=-1) + + XXX + + This method returns a :ref:`coroutine object `. + + .. method:: readline() + + XXX + + This method returns a :ref:`coroutine object `. + + .. method:: readexactly(n) + + XXX + + This method returns a :ref:`coroutine object `. + + StreamWriter ------------ @@ -291,48 +338,46 @@ see :meth:`WriteTransport.write_eof`. -StreamReader ------------- +StreamReaderProtocol +-------------------- -.. class:: StreamReader(limit=_DEFAULT_LIMIT, loop=None) +.. class:: StreamReaderProtocol(stream_reader, client_connected_cb=None, loop=None) - .. method:: exception() + Trivial helper class to adapt between :class:`Protocol` and + :class:`StreamReader`. Sublclass of :class:`Protocol`. - Get the exception. + *stream_reader* is a :class:`StreamReader` instance, *client_connected_cb* + is an optional function called with (stream_reader, stream_writer) when a + connection is made, *loop* is the event loop instance to use. - .. method:: feed_eof() + (This is a helper class instead of making :class:`StreamReader` itself a + :class:`Protocol` subclass, because the :class:`StreamReader` has other + potential uses, and to prevent the user of the :class:`StreamReader` to + accidentally call inappropriate methods of the protocol.) - XXX + .. method:: connection_made(transport) - .. method:: feed_data(data) + XXX - XXX + .. method:: connection_lost(exc) - .. method:: set_exception(exc) + XXX - Set the exception. + .. method:: data_received(data) - .. method:: set_transport(transport) + XXX - Set the transport. + .. method:: eof_received() - .. method:: read(n=-1) + XXX - XXX + .. method:: pause_writing() - This method returns a :ref:`coroutine object `. + XXX - .. method:: readline() + .. method:: resume_writing() - XXX - - This method returns a :ref:`coroutine object `. - - .. method:: readexactly(n) - - XXX - - This method returns a :ref:`coroutine object `. + XXX -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 11:05:12 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 23 Jan 2014 11:05:12 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio_doc=3A_link_create?= =?utf-8?q?=5Fconnection=28=29_to_open=5Fconnection=28=29_and_create=5Fser?= =?utf-8?b?dmVyKCk=?= Message-ID: <3f8zcm0BGkz7Lk0@mail.python.org> http://hg.python.org/cpython/rev/ccc91994da20 changeset: 88650:ccc91994da20 user: Victor Stinner date: Thu Jan 23 11:02:09 2014 +0100 summary: asyncio doc: link create_connection() to open_connection() and create_server() to start_server() Rename also the "Network functions" section to "Stream functions" and move it to the Stream section. files: Doc/library/asyncio-eventloop.rst | 10 + Doc/library/asyncio-protocol.rst | 106 +++++++++--------- 2 files changed, 63 insertions(+), 53 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 @@ -213,6 +213,11 @@ to bind the socket to locally. The *local_host* and *local_port* are looked up using getaddrinfo(), similarly to *host* and *port*. + .. seealso:: + + The :func:`open_connection` function can be used to get a pair of + (:class:`StreamReader`, :class:`StreamWriter`) instead of a protocol. + Creating listening connections ------------------------------ @@ -251,6 +256,11 @@ This method returns a :ref:`coroutine object `. + .. seealso:: + + The function :func:`start_server` creates a (:class:`StreamReader`, + :class:`StreamWriter`) pair and calls back a function with this pair. + .. method:: BaseEventLoop.create_datagram_endpoint(protocol_factory, local_addr=None, remote_addr=None, \*, family=0, proto=0, flags=0) Create datagram connection. 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 @@ -231,6 +231,59 @@ Streams ======= +Stream functions +---------------- + +.. function:: open_connection(host=None, port=None, *, loop=None, limit=_DEFAULT_LIMIT, **kwds) + + A wrapper for :meth:`~BaseEventLoop.create_connection()` returning a (reader, + writer) pair. + + The reader returned is a :class:`StreamReader` instance; the writer is + a :class:`StreamWriter` instance. + + The arguments are all the usual arguments to + :meth:`BaseEventLoop.create_connection` except *protocol_factory*; most + common are positional host and port, with various optional keyword arguments + following. + + Additional optional keyword arguments are *loop* (to set the event loop + instance to use) and *limit* (to set the buffer limit passed to the + :class:`StreamReader`). + + (If you want to customize the :class:`StreamReader` and/or + :class:`StreamReaderProtocol` classes, just copy the code -- there's really + nothing special here except some convenience.) + + This function returns a :ref:`coroutine object `. + +.. function:: start_server(client_connected_cb, host=None, port=None, *, loop=None, limit=_DEFAULT_LIMIT, **kwds) + + Start a socket server, call back for each client connected. + + The first parameter, *client_connected_cb*, takes two parameters: + *client_reader*, *client_writer*. *client_reader* is a + :class:`StreamReader` object, while *client_writer* is a + :class:`StreamWriter` object. This parameter can either be a plain callback + function or a :ref:`coroutine function `; if it is a coroutine + function, it will be automatically converted into a :class:`Task`. + + The rest of the arguments are all the usual arguments to + :meth:`~BaseEventLoop.create_server()` except *protocol_factory*; most + common are positional host and port, with various optional keyword arguments + following. The return value is the same as + :meth:`~BaseEventLoop.create_server()`. + + Additional optional keyword arguments are *loop* (to set the event loop + instance to use) and *limit* (to set the buffer limit passed to the + :class:`StreamReader`). + + The return value is the same as :meth:`~BaseEventLoop.create_server()`, i.e. + a :class:`AbstractServer` object which can be used to stop the service. + + This function returns a :ref:`coroutine object `. + + StreamReader ------------ @@ -572,59 +625,6 @@ Coroutine to wait until service is closed. -Network functions -================= - -.. function:: open_connection(host=None, port=None, *, loop=None, limit=_DEFAULT_LIMIT, **kwds) - - A wrapper for :meth:`~BaseEventLoop.create_connection()` returning a (reader, - writer) pair. - - The reader returned is a :class:`StreamReader` instance; the writer is - a :class:`StreamWriter` instance. - - The arguments are all the usual arguments to - :meth:`BaseEventLoop.create_connection` except *protocol_factory*; most - common are positional host and port, with various optional keyword arguments - following. - - Additional optional keyword arguments are *loop* (to set the event loop - instance to use) and *limit* (to set the buffer limit passed to the - :class:`StreamReader`). - - (If you want to customize the :class:`StreamReader` and/or - :class:`StreamReaderProtocol` classes, just copy the code -- there's really - nothing special here except some convenience.) - - This function returns a :ref:`coroutine object `. - -.. function:: start_server(client_connected_cb, host=None, port=None, *, loop=None, limit=_DEFAULT_LIMIT, **kwds) - - Start a socket server, call back for each client connected. - - The first parameter, *client_connected_cb*, takes two parameters: - *client_reader*, *client_writer*. *client_reader* is a - :class:`StreamReader` object, while *client_writer* is a - :class:`StreamWriter` object. This parameter can either be a plain callback - function or a :ref:`coroutine function `; if it is a coroutine - function, it will be automatically converted into a :class:`Task`. - - The rest of the arguments are all the usual arguments to - :meth:`~BaseEventLoop.create_server()` except *protocol_factory*; most - common are positional host and port, with various optional keyword arguments - following. The return value is the same as - :meth:`~BaseEventLoop.create_server()`. - - Additional optional keyword arguments are *loop* (to set the event loop - instance to use) and *limit* (to set the buffer limit passed to the - :class:`StreamReader`). - - The return value is the same as :meth:`~BaseEventLoop.create_server()`, i.e. - a :class:`AbstractServer` object which can be used to stop the service. - - This function returns a :ref:`coroutine object `. - - Protocol example: TCP echo server and client ============================================ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 11:05:13 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 23 Jan 2014 11:05:13 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio_doc=3A_Move_stream?= =?utf-8?q?s_to_their_own_dedicated_page?= Message-ID: <3f8zcn4HX8z7Ll6@mail.python.org> http://hg.python.org/cpython/rev/95b3f5d152f0 changeset: 88651:95b3f5d152f0 user: Victor Stinner date: Thu Jan 23 11:05:01 2014 +0100 summary: asyncio doc: Move streams to their own dedicated page files: Doc/library/asyncio-protocol.rst | 212 +------- Doc/library/asyncio-protocol.rst | 508 +------------------ Doc/library/asyncio.rst | 1 + 3 files changed, 10 insertions(+), 711 deletions(-) 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 @@ -1,8 +1,8 @@ .. currentmodule:: asyncio -+++++++++++++++++++++++++++++++++ -Transports, streams and protocols -+++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++ +Transports and protocols ++++++++++++++++++++++++++ .. _transport: @@ -228,212 +228,6 @@ stop the subprocess. -Streams -======= - -Stream functions ----------------- - -.. function:: open_connection(host=None, port=None, *, loop=None, limit=_DEFAULT_LIMIT, **kwds) - - A wrapper for :meth:`~BaseEventLoop.create_connection()` returning a (reader, - writer) pair. - - The reader returned is a :class:`StreamReader` instance; the writer is - a :class:`StreamWriter` instance. - - The arguments are all the usual arguments to - :meth:`BaseEventLoop.create_connection` except *protocol_factory*; most - common are positional host and port, with various optional keyword arguments - following. - - Additional optional keyword arguments are *loop* (to set the event loop - instance to use) and *limit* (to set the buffer limit passed to the - :class:`StreamReader`). - - (If you want to customize the :class:`StreamReader` and/or - :class:`StreamReaderProtocol` classes, just copy the code -- there's really - nothing special here except some convenience.) - - This function returns a :ref:`coroutine object `. - -.. function:: start_server(client_connected_cb, host=None, port=None, *, loop=None, limit=_DEFAULT_LIMIT, **kwds) - - Start a socket server, call back for each client connected. - - The first parameter, *client_connected_cb*, takes two parameters: - *client_reader*, *client_writer*. *client_reader* is a - :class:`StreamReader` object, while *client_writer* is a - :class:`StreamWriter` object. This parameter can either be a plain callback - function or a :ref:`coroutine function `; if it is a coroutine - function, it will be automatically converted into a :class:`Task`. - - The rest of the arguments are all the usual arguments to - :meth:`~BaseEventLoop.create_server()` except *protocol_factory*; most - common are positional host and port, with various optional keyword arguments - following. The return value is the same as - :meth:`~BaseEventLoop.create_server()`. - - Additional optional keyword arguments are *loop* (to set the event loop - instance to use) and *limit* (to set the buffer limit passed to the - :class:`StreamReader`). - - The return value is the same as :meth:`~BaseEventLoop.create_server()`, i.e. - a :class:`AbstractServer` object which can be used to stop the service. - - This function returns a :ref:`coroutine object `. - - -StreamReader ------------- - -.. class:: StreamReader(limit=_DEFAULT_LIMIT, loop=None) - - .. method:: exception() - - Get the exception. - - .. method:: feed_eof() - - XXX - - .. method:: feed_data(data) - - XXX - - .. method:: set_exception(exc) - - Set the exception. - - .. method:: set_transport(transport) - - Set the transport. - - .. method:: read(n=-1) - - XXX - - This method returns a :ref:`coroutine object `. - - .. method:: readline() - - XXX - - This method returns a :ref:`coroutine object `. - - .. method:: readexactly(n) - - XXX - - This method returns a :ref:`coroutine object `. - - -StreamWriter ------------- - -.. class:: StreamWriter(transport, protocol, reader, loop) - - Wraps a Transport. - - This exposes :meth:`write`, :meth:`writelines`, :meth:`can_write_eof()`, - :meth:`write_eof`, :meth:`get_extra_info` and :meth:`close`. It adds - :meth:`drain` which returns an optional :class:`Future` on which you can - wait for flow control. It also adds a transport attribute which references - the :class:`Transport` directly. - - .. attribute:: transport - - Transport. - - .. method:: close() - - Close the transport: see :meth:`BaseTransport.close`. - - .. method:: drain() - - This method has an unusual return value. - - The intended use is to write:: - - w.write(data) - yield from w.drain() - - When there's nothing to wait for, :meth:`drain()` returns ``()``, and the - yield-from continues immediately. When the transport buffer is full (the - protocol is paused), :meth:`drain` creates and returns a - :class:`Future` and the yield-from will block until - that Future is completed, which will happen when the buffer is - (partially) drained and the protocol is resumed. - - .. method:: get_extra_info(name, default=None) - - Return optional transport information: see - :meth:`BaseTransport.get_extra_info`. - - .. method:: write(data) - - Write some *data* bytes to the transport: see - :meth:`WriteTransport.write`. - - .. method:: writelines(data) - - Write a list (or any iterable) of data bytes to the transport: - see :meth:`WriteTransport.writelines`. - - .. method:: can_write_eof() - - Return :const:`True` if the transport supports :meth:`write_eof`, - :const:`False` if not. See :meth:`WriteTransport.can_write_eof`. - - .. method:: write_eof() - - Close the write end of the transport after flushing buffered data: - see :meth:`WriteTransport.write_eof`. - - -StreamReaderProtocol --------------------- - -.. class:: StreamReaderProtocol(stream_reader, client_connected_cb=None, loop=None) - - Trivial helper class to adapt between :class:`Protocol` and - :class:`StreamReader`. Sublclass of :class:`Protocol`. - - *stream_reader* is a :class:`StreamReader` instance, *client_connected_cb* - is an optional function called with (stream_reader, stream_writer) when a - connection is made, *loop* is the event loop instance to use. - - (This is a helper class instead of making :class:`StreamReader` itself a - :class:`Protocol` subclass, because the :class:`StreamReader` has other - potential uses, and to prevent the user of the :class:`StreamReader` to - accidentally call inappropriate methods of the protocol.) - - .. method:: connection_made(transport) - - XXX - - .. method:: connection_lost(exc) - - XXX - - .. method:: data_received(data) - - XXX - - .. method:: eof_received() - - XXX - - .. method:: pause_writing() - - XXX - - .. method:: resume_writing() - - XXX - - - .. _protocol: Protocols diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-stream.rst copy from Doc/library/asyncio-protocol.rst copy to Doc/library/asyncio-stream.rst --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-stream.rst @@ -1,238 +1,11 @@ .. currentmodule:: asyncio -+++++++++++++++++++++++++++++++++ -Transports, streams and protocols -+++++++++++++++++++++++++++++++++ - -.. _transport: - -Transports -========== - -Transports are classed provided by :mod:`asyncio` in order to abstract -various kinds of communication channels. You generally won't instantiate -a transport yourself; instead, you will call a :class:`BaseEventLoop` method -which will create the transport and try to initiate the underlying -communication channel, calling you back when it succeeds. - -Once the communication channel is established, a transport is always -paired with a :ref:`protocol ` instance. The protocol can -then call the transport's methods for various purposes. - -:mod:`asyncio` currently implements transports for TCP, UDP, SSL, and -subprocess pipes. The methods available on a transport depend on -the transport's kind. - - -BaseTransport -------------- - -.. class:: BaseTransport - - Base class for transports. - - .. method:: close(self) - - Close the transport. If the transport has a buffer for outgoing - data, buffered data will be flushed asynchronously. No more data - will be received. After all buffered data is flushed, the - protocol's :meth:`connection_lost` method will be called with - :const:`None` as its argument. - - - .. method:: get_extra_info(name, default=None) - - Return optional transport information. *name* is a string representing - the piece of transport-specific information to get, *default* is the - value to return if the information doesn't exist. - - This method allows transport implementations to easily expose - channel-specific information. - - * socket: - - - ``'peername'``: the remote address to which the socket is connected, - result of :meth:`socket.socket.getpeername` (``None`` on error) - - ``'socket'``: :class:`socket.socket` instance - - ``'sockname'``: the socket's own address, - result of :meth:`socket.socket.getsockname` - - * SSL socket: - - - ``'compression'``: the compression algorithm being used as a string, - or ``None`` if the connection isn't compressed; result of - :meth:`ssl.SSLSocket.compression` - - ``'cipher'``: a three-value tuple containing the name of the cipher - being used, the version of the SSL protocol that defines its use, and - the number of secret bits being used; result of - :meth:`ssl.SSLSocket.cipher` - - ``'peercert'``: peer certificate; result of - :meth:`ssl.SSLSocket.getpeercert` - - ``'sslcontext'``: :class:`ssl.SSLContext` instance - - * pipe: - - - ``'pipe'``: pipe object - - * subprocess: - - - ``'subprocess'``: :class:`subprocess.Popen` instance - - -ReadTransport -------------- - -.. class:: ReadTransport - - Interface for read-only transports. - - .. method:: pause_reading() - - Pause the receiving end of the transport. No data will be passed to - the protocol's :meth:`data_received` method until meth:`resume_reading` - is called. - - .. method:: resume_reading() - - Resume the receiving end. The protocol's :meth:`data_received` method - will be called once again if some data is available for reading. - - -WriteTransport --------------- - -.. class:: WriteTransport - - Interface for write-only transports. - - .. method:: abort() - - Close the transport immediately, without waiting for pending operations - to complete. Buffered data will be lost. No more data will be received. - The protocol's :meth:`connection_lost` method will eventually be - called with :const:`None` as its argument. - - .. method:: can_write_eof() - - Return :const:`True` if the transport supports :meth:`write_eof`, - :const:`False` if not. - - .. method:: get_write_buffer_size() - - Return the current size of the output buffer used by the transport. - - .. method:: set_write_buffer_limits(high=None, low=None) - - Set the *high*- and *low*-water limits for write flow control. - - These two values control when call the protocol's - :meth:`pause_writing` and :meth:`resume_writing` methods are called. - If specified, the low-water limit must be less than or equal to the - high-water limit. Neither *high* nor *low* can be negative. - - The defaults are implementation-specific. If only the - high-water limit is given, the low-water limit defaults to a - implementation-specific value less than or equal to the - high-water limit. Setting *high* to zero forces *low* to zero as - well, and causes :meth:`pause_writing` to be called whenever the - buffer becomes non-empty. Setting *low* to zero causes - :meth:`resume_writing` to be called only once the buffer is empty. - Use of zero for either limit is generally sub-optimal as it - reduces opportunities for doing I/O and computation - concurrently. - - .. method:: write(data) - - Write some *data* bytes to the transport. - - This method does not block; it buffers the data and arranges for it - to be sent out asynchronously. - - .. method:: writelines(list_of_data) - - Write a list (or any iterable) of data bytes to the transport. - This is functionally equivalent to calling :meth:`write` on each - element yielded by the iterable, but may be implemented more efficiently. - - .. method:: write_eof() - - Close the write end of the transport after flushing buffered data. - Data may still be received. - - This method can raise :exc:`NotImplementedError` if the transport - (e.g. SSL) doesn't support half-closes. - - -DatagramTransport ------------------ - -.. method:: DatagramTransport.sendto(data, addr=None) - - Send the *data* bytes to the remote peer given by *addr* (a - transport-dependent target address). If *addr* is :const:`None`, the - data is sent to the target address given on transport creation. - - This method does not block; it buffers the data and arranges for it - to be sent out asynchronously. - -.. method:: DatagramTransport.abort() - - Close the transport immediately, without waiting for pending operations - to complete. Buffered data will be lost. No more data will be received. - The protocol's :meth:`connection_lost` method will eventually be - called with :const:`None` as its argument. - - -BaseSubprocessTransport ------------------------ - -.. class:: BaseSubprocessTransport - - .. method:: get_pid() - - Return the subprocess process id as an integer. - - .. method:: get_pipe_transport(fd) - - Return the transport for the communication pipe correspondong to the - integer file descriptor *fd*. The return value can be a readable or - writable streaming transport, depending on the *fd*. If *fd* doesn't - correspond to a pipe belonging to this transport, :const:`None` is - returned. - - .. method:: get_returncode() - - Return the subprocess returncode as an integer or :const:`None` - if it hasn't returned, similarly to the - :attr:`subprocess.Popen.returncode` attribute. - - .. method:: kill(self) - - Kill the subprocess, as in :meth:`subprocess.Popen.kill` - - On POSIX systems, the function sends SIGKILL to the subprocess. - On Windows, this method is an alias for :meth:`terminate`. - - .. method:: send_signal(signal) - - Send the *signal* number to the subprocess, as in - :meth:`subprocess.Popen.send_signal`. - - .. method:: terminate() - - Ask the subprocess to stop, as in :meth:`subprocess.Popen.terminate`. - This method is an alias for the :meth:`close` method. - - On POSIX systems, this method sends SIGTERM to the subprocess. - On Windows, the Windows API function TerminateProcess() is called to - stop the subprocess. - - ++++++++ Streams -======= ++++++++ Stream functions ----------------- +================ .. function:: open_connection(host=None, port=None, *, loop=None, limit=_DEFAULT_LIMIT, **kwds) @@ -285,7 +58,7 @@ StreamReader ------------- +============ .. class:: StreamReader(limit=_DEFAULT_LIMIT, loop=None) @@ -329,7 +102,7 @@ StreamWriter ------------- +============ .. class:: StreamWriter(transport, protocol, reader, loop) @@ -392,7 +165,7 @@ StreamReaderProtocol --------------------- +==================== .. class:: StreamReaderProtocol(stream_reader, client_connected_cb=None, loop=None) @@ -432,272 +205,3 @@ XXX - - -.. _protocol: - -Protocols -========= - -:mod:`asyncio` provides base classes that you can subclass to implement -your network protocols. Those classes are used in conjunction with -:ref:`transports ` (see below): the protocol parses incoming -data and asks for the writing of outgoing data, while the transport is -responsible for the actual I/O and buffering. - -When subclassing a protocol class, it is recommended you override certain -methods. Those methods are callbacks: they will be called by the transport -on certain events (for example when some data is received); you shouldn't -call them yourself, unless you are implementing a transport. - -.. note:: - All callbacks have default implementations, which are empty. Therefore, - you only need to implement the callbacks for the events in which you - are interested. - - -Protocol classes ----------------- - -.. class:: Protocol - - The base class for implementing streaming protocols (for use with - e.g. TCP and SSL transports). - -.. class:: DatagramProtocol - - The base class for implementing datagram protocols (for use with - e.g. UDP transports). - -.. class:: SubprocessProtocol - - The base class for implementing protocols communicating with child - processes (through a set of unidirectional pipes). - - -Connection callbacks --------------------- - -These callbacks may be called on :class:`Protocol` and -:class:`SubprocessProtocol` instances: - -.. method:: BaseProtocol.connection_made(transport) - - Called when a connection is made. - - The *transport* argument is the transport representing the - connection. You are responsible for storing it somewhere - (e.g. as an attribute) if you need to. - -.. method:: BaseProtocol.connection_lost(exc) - - Called when the connection is lost or closed. - - The argument is either an exception object or :const:`None`. - The latter means a regular EOF is received, or the connection was - aborted or closed by this side of the connection. - -:meth:`connection_made` and :meth:`connection_lost` are called exactly once -per successful connection. All other callbacks will be called between those -two methods, which allows for easier resource management in your protocol -implementation. - -The following callbacks may be called only on :class:`SubprocessProtocol` -instances: - -.. method:: SubprocessProtocol.pipe_data_received(fd, data) - - Called when the child process writes data into its stdout or stderr pipe. - *fd* is the integer file descriptor of the pipe. *data* is a non-empty - bytes object containing the data. - -.. method:: SubprocessProtocol.pipe_connection_lost(fd, exc) - - Called when one of the pipes communicating with the child process - is closed. *fd* is the integer file descriptor that was closed. - -.. method:: SubprocessProtocol.process_exited() - - Called when the child process has exited. - - -Streaming protocols -------------------- - -The following callbacks are called on :class:`Protocol` instances: - -.. method:: Protocol.data_received(data) - - Called when some data is received. *data* is a non-empty bytes object - containing the incoming data. - - .. note:: - Whether the data is buffered, chunked or reassembled depends on - the transport. In general, you shouldn't rely on specific semantics - and instead make your parsing generic and flexible enough. However, - data is always received in the correct order. - -.. method:: Protocol.eof_received() - - Calls when the other end signals it won't send any more data - (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 - 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. - - .. note:: - Some transports such as SSL don't support half-closed connections, - in which case returning true from this method will not prevent closing - the connection. - -:meth:`data_received` can be called an arbitrary number of times during -a connection. However, :meth:`eof_received` is called at most once -and, if called, :meth:`data_received` won't be called after it. - -Datagram protocols ------------------- - -The following callbacks are called on :class:`DatagramProtocol` instances. - -.. method:: DatagramProtocol.datagram_received(data, addr) - - Called when a datagram is received. *data* is a bytes object containing - the incoming data. *addr* is the address of the peer sending the data; - the exact format depends on the transport. - -.. method:: DatagramProtocol.error_received(exc) - - Called when a previous send or receive operation raises an - :class:`OSError`. *exc* is the :class:`OSError` instance. - - This method is called in rare conditions, when the transport (e.g. UDP) - detects that a datagram couldn't be delivered to its recipient. - In many conditions though, undeliverable datagrams will be silently - dropped. - - -Flow control callbacks ----------------------- - -These callbacks may be called on :class:`Protocol` and -:class:`SubprocessProtocol` instances: - -.. method:: BaseProtocol.pause_writing() - - Called when the transport's buffer goes over the high-water mark. - -.. method:: BaseProtocol.resume_writing() - - Called when the transport's buffer drains below the low-water mark. - - -:meth:`pause_writing` and :meth:`resume_writing` calls are paired -- -:meth:`pause_writing` is called once when the buffer goes strictly over -the high-water mark (even if subsequent writes increases the buffer size -even more), and eventually :meth:`resume_writing` is called once when the -buffer size reaches the low-water mark. - -.. note:: - If the buffer size equals the high-water mark, - :meth:`pause_writing` is not called -- it must go strictly over. - Conversely, :meth:`resume_writing` is called when the buffer size is - equal or lower than the low-water mark. These end conditions - are important to ensure that things go as expected when either - mark is zero. - - -Server ------- - -.. class:: AbstractServer - - Abstract server returned by :func:`BaseEventLoop.create_server`. - - .. method:: close() - - Stop serving. This leaves existing connections open. - - .. method:: wait_closed() - - Coroutine to wait until service is closed. - - -Protocol example: TCP echo server and client -============================================ - -Echo client ------------ - -TCP echo client example, send data and wait until the connection is closed:: - - import asyncio - - class EchoClient(asyncio.Protocol): - message = 'This is the message. It will be echoed.' - - def connection_made(self, transport): - transport.write(self.message.encode()) - print('data sent: {}'.format(self.message)) - - def data_received(self, data): - print('data received: {}'.format(data.decode())) - - def connection_lost(self, exc): - print('server closed the connection') - asyncio.get_event_loop().stop() - - loop = asyncio.get_event_loop() - coro = loop.create_connection(EchoClient, '127.0.0.1', 8888) - loop.run_until_complete(coro) - loop.run_forever() - loop.close() - -The event loop is running twice. The -:meth:`~BaseEventLoop.run_until_complete` method is preferred in this short -example to raise an exception if the server is not listening, instead of -having to write a short coroutine to handle the exception and stop the -running loop. At :meth:`~BaseEventLoop.run_until_complete` exit, the loop is -no more running, so there is no need to stop the loop in case of an error. - -Echo server ------------ - -TCP echo server example, send back received data and close the connection:: - - import asyncio - - class EchoServer(asyncio.Protocol): - def connection_made(self, transport): - peername = transport.get_extra_info('peername') - print('connection from {}'.format(peername)) - self.transport = transport - - def data_received(self, data): - print('data received: {}'.format(data.decode())) - self.transport.write(data) - - # close the socket - self.transport.close() - - loop = asyncio.get_event_loop() - coro = loop.create_server(EchoServer, '127.0.0.1', 8888) - server = loop.run_until_complete(coro) - print('serving on {}'.format(server.sockets[0].getsockname())) - - try: - loop.run_forever() - except KeyboardInterrupt: - print("exit") - finally: - server.close() - loop.close() - -:meth:`Transport.close` can be called immediately after -:meth:`WriteTransport.write` even if data are not sent yet on the socket: both -methods are asynchronous. ``yield from`` is not needed because these transport -methods don't return coroutines. - - diff --git a/Doc/library/asyncio.rst b/Doc/library/asyncio.rst --- a/Doc/library/asyncio.rst +++ b/Doc/library/asyncio.rst @@ -47,6 +47,7 @@ asyncio-eventloop.rst asyncio-task.rst asyncio-protocol.rst + asyncio-stream.rst asyncio-sync.rst asyncio-dev.rst -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 11:25:57 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 23 Jan 2014 11:25:57 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio_doc=3A_add_an_clie?= =?utf-8?q?nt_example_using_streams?= Message-ID: <3f904j58Cgz7LlT@mail.python.org> http://hg.python.org/cpython/rev/8fe59931b64d changeset: 88652:8fe59931b64d user: Victor Stinner date: Thu Jan 23 11:25:48 2014 +0100 summary: asyncio doc: add an client example using streams files: Doc/library/asyncio-stream.rst | 35 ++++++++++++++++++++++ 1 files changed, 35 insertions(+), 0 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 @@ -205,3 +205,38 @@ XXX + +Example +======= + +Simple example querying HTTP headers of the URL passed on the command line:: + + import asyncio + import urllib.parse + import sys + + @asyncio.coroutine + def print_http_headers(url): + url = urllib.parse.urlsplit(url) + reader, writer = yield from asyncio.open_connection(url.hostname, 80) + query = ('HEAD {url.path} HTTP/1.0\r\n' + 'Host: {url.hostname}\r\n' + '\r\n').format(url=url) + writer.write(query.encode('latin-1')) + while True: + line = yield from reader.readline() + if not line: + break + line = line.decode('latin1').rstrip() + if line: + print('HTTP header> %s' % line) + + url = sys.argv[1] + loop = asyncio.get_event_loop() + task = asyncio.async(print_http_headers(url)) + loop.run_until_complete(task) + +Usage:: + + python example.py http://example.com/path/page.html + -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 13:38:52 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 23 Jan 2014 13:38:52 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Other_attempt_?= =?utf-8?q?to_fix_test=5Fuser=5Fcommand_on_OpenSolaris=2E?= Message-ID: <3f93243xCbz7Ljm@mail.python.org> http://hg.python.org/cpython/rev/3f8d0d68d30c changeset: 88653:3f8d0d68d30c branch: 2.7 parent: 88647:5f91500b3b02 user: Serhiy Storchaka date: Thu Jan 23 14:38:44 2014 +0200 summary: Other attempt to fix test_user_command on OpenSolaris. files: Lib/test/test_tcl.py | 24 +++++++++++++++--------- 1 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -210,14 +210,19 @@ result.append(arg) return arg self.interp.createcommand('testfunc', testfunc) - def check(value, expected, conv=lambda x: x): + def check(value, expected, eq=self.assertEqual): del result[:] r = self.interp.call('testfunc', value) self.assertEqual(len(result), 1) self.assertIsInstance(result[0], str) - self.assertEqual(conv(result[0]), expected) + eq(result[0], expected) self.assertIsInstance(r, str) - self.assertEqual(conv(r), expected) + eq(r, expected) + def float_eq(actual, expected): + self.assertAlmostEqual(float(actual), float(expected)) + def nan_eq(actual, expected): + actual = float(actual) + self.assertNotEqual(actual, actual) check(True, '1') check(False, '0') @@ -226,13 +231,14 @@ check('string\u20ac', 'string\u20ac') for i in (0, 1, -1, 2**31-1, -2**31): check(i, str(i)) - for f in (0.0, 1.0, -1.0, 1/3, - sys.float_info.min, sys.float_info.max, + for f in (0.0, 1.0, -1.0): + check(f, repr(f)) + for f in (1/3.0, sys.float_info.min, sys.float_info.max, -sys.float_info.min, -sys.float_info.max): - check(f, f, conv=float) - check(float('inf'), float('inf'), conv=float) - check(-float('inf'), -float('inf'), conv=float) - check(float('nan'), 'NaN') + check(f, f, eq=float_eq) + check(float('inf'), 'Inf', eq=float_eq) + check(-float('inf'), '-Inf', eq=float_eq) + check(float('nan'), 'NaN', eq=nan_eq) check((), '') check((1, (2,), (3, 4), '5 6', ()), '1 2 {3 4} {5 6} {}') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 15:07:36 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 23 Jan 2014 15:07:36 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320311=3A_add_debu?= =?utf-8?q?g_help_in_test=5Fselectors?= Message-ID: <3f950S2p39z7Ljf@mail.python.org> http://hg.python.org/cpython/rev/3637ccf9516a changeset: 88654:3637ccf9516a parent: 88652:8fe59931b64d user: Victor Stinner date: Thu Jan 23 15:07:26 2014 +0100 summary: Issue #20311: add debug help in test_selectors files: Lib/test/test_selectors.py | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) 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,7 +5,7 @@ import signal import socket from test import support -from time import sleep, perf_counter +from time import sleep, perf_counter, get_clock_info import unittest import unittest.mock try: @@ -377,7 +377,10 @@ t0 = perf_counter() s.select(timeout) dt = perf_counter() - t0 - self.assertGreaterEqual(dt, timeout) + clock = get_clock_info('perf_counter') + self.assertGreaterEqual(dt, timeout, + "%.30f < %.30f ; clock=%s" + % (dt, timeout, clock)) class ScalableSelectorMixIn: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 15:08:49 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 23 Jan 2014 15:08:49 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Third_attempt_?= =?utf-8?q?to_fix_test=5Fuser=5Fcommand_on_OpenSolaris=2E?= Message-ID: <3f951s2ywTz7Ljf@mail.python.org> http://hg.python.org/cpython/rev/f28b60141c5c changeset: 88655:f28b60141c5c branch: 2.7 parent: 88653:3f8d0d68d30c user: Serhiy Storchaka date: Thu Jan 23 16:08:35 2014 +0200 summary: Third attempt to fix test_user_command on OpenSolaris. files: Lib/test/test_tcl.py | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -219,7 +219,9 @@ self.assertIsInstance(r, str) eq(r, expected) def float_eq(actual, expected): - self.assertAlmostEqual(float(actual), float(expected)) + expected = float(expected) + self.assertAlmostEqual(float(actual), expected, + delta=abs(expected) * 1e-10) def nan_eq(actual, expected): actual = float(actual) self.assertNotEqual(actual, actual) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 15:24:46 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 23 Jan 2014 15:24:46 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE5OTM2?= =?utf-8?q?=3A_Restored_executable_bits_for_several_libffi_files=2E?= Message-ID: <3f95NG6JBGz7Lkv@mail.python.org> http://hg.python.org/cpython/rev/1cfce469642d changeset: 88656:1cfce469642d branch: 3.3 parent: 88645:f141c325a820 user: Serhiy Storchaka date: Thu Jan 23 16:22:55 2014 +0200 summary: Issue #19936: Restored executable bits for several libffi files. These files have shebangs and executable bits in the libffi distribution. files: Modules/_ctypes/libffi/build-ios.sh | 0 Modules/_ctypes/libffi/libtool-ldflags | 0 Modules/_ctypes/libffi/msvcc.sh | 0 Modules/_ctypes/libffi/src/arm/gentramp.sh | 0 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Modules/_ctypes/libffi/build-ios.sh b/Modules/_ctypes/libffi/build-ios.sh old mode 100644 new mode 100755 diff --git a/Modules/_ctypes/libffi/libtool-ldflags b/Modules/_ctypes/libffi/libtool-ldflags old mode 100644 new mode 100755 diff --git a/Modules/_ctypes/libffi/msvcc.sh b/Modules/_ctypes/libffi/msvcc.sh old mode 100644 new mode 100755 diff --git a/Modules/_ctypes/libffi/src/arm/gentramp.sh b/Modules/_ctypes/libffi/src/arm/gentramp.sh old mode 100644 new mode 100755 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 15:24:48 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 23 Jan 2014 15:24:48 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2319936=3A_Restored_executable_bits_for_several_l?= =?utf-8?q?ibffi_files=2E?= Message-ID: <3f95NJ10XBz7Ljf@mail.python.org> http://hg.python.org/cpython/rev/9adce4e25bdb changeset: 88657:9adce4e25bdb parent: 88654:3637ccf9516a parent: 88656:1cfce469642d user: Serhiy Storchaka date: Thu Jan 23 16:23:50 2014 +0200 summary: Issue #19936: Restored executable bits for several libffi files. These files have shebangs and executable bits in the libffi distribution. files: Modules/_ctypes/libffi/build-ios.sh | 0 Modules/_ctypes/libffi/libtool-ldflags | 0 Modules/_ctypes/libffi/msvcc.sh | 0 Modules/_ctypes/libffi/src/arm/gentramp.sh | 0 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Modules/_ctypes/libffi/build-ios.sh b/Modules/_ctypes/libffi/build-ios.sh old mode 100644 new mode 100755 diff --git a/Modules/_ctypes/libffi/libtool-ldflags b/Modules/_ctypes/libffi/libtool-ldflags old mode 100644 new mode 100755 diff --git a/Modules/_ctypes/libffi/msvcc.sh b/Modules/_ctypes/libffi/msvcc.sh old mode 100644 new mode 100755 diff --git a/Modules/_ctypes/libffi/src/arm/gentramp.sh b/Modules/_ctypes/libffi/src/arm/gentramp.sh old mode 100644 new mode 100755 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 15:50:16 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 23 Jan 2014 15:50:16 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogRml4ZWQgdGVzdF91?= =?utf-8?q?ser=5Fcommand_on_OpenSolaris_where_floats_can_have_different_st?= =?utf-8?q?ring?= Message-ID: <3f95xh1k1Cz7LjM@mail.python.org> http://hg.python.org/cpython/rev/fed5d501a179 changeset: 88658:fed5d501a179 branch: 3.3 parent: 88656:1cfce469642d user: Serhiy Storchaka date: Thu Jan 23 16:48:44 2014 +0200 summary: Fixed test_user_command on OpenSolaris where floats can have different string representation in Tcl and Python. files: Lib/test/test_tcl.py | 29 ++++++++++++++++++++--------- 1 files changed, 20 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -199,9 +199,19 @@ result = arg return arg self.interp.createcommand('testfunc', testfunc) - def check(value, expected): - self.assertEqual(self.interp.call('testfunc', value), expected) - self.assertEqual(result, expected) + def check(value, expected, eq=self.assertEqual): + r = self.interp.call('testfunc', value) + self.assertIsInstance(result, str) + eq(result, expected) + self.assertIsInstance(r, str) + eq(r, expected) + def float_eq(actual, expected): + expected = float(expected) + self.assertAlmostEqual(float(actual), expected, + delta=abs(expected) * 1e-10) + def nan_eq(actual, expected): + actual = float(actual) + self.assertNotEqual(actual, actual) check(True, '1') check(False, '0') @@ -210,13 +220,14 @@ check('string\u20ac', 'string\u20ac') for i in (0, 1, -1, 2**31-1, -2**31): check(i, str(i)) - for f in (0.0, 1.0, -1.0, 1/3, - sys.float_info.min, sys.float_info.max, + for f in (0.0, 1.0, -1.0): + check(f, repr(f)) + for f in (1/3.0, sys.float_info.min, sys.float_info.max, -sys.float_info.min, -sys.float_info.max): - check(f, str(f)) - check(float('nan'), 'NaN') - check(float('inf'), 'Inf') - check(-float('inf'), '-Inf') + check(f, f, eq=float_eq) + check(float('inf'), 'Inf', eq=float_eq) + check(-float('inf'), '-Inf', eq=float_eq) + check(float('nan'), 'NaN', eq=nan_eq) check((), '') check((1, (2,), (3, 4), '5 6', ()), '1 2 {3 4} {5 6} {}') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 15:50:17 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 23 Jan 2014 15:50:17 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Fixed_test=5Fuser=5Fcommand_on_OpenSolaris_where_floats_?= =?utf-8?q?can_have_different_string?= Message-ID: <3f95xj3Kxyz7Lkd@mail.python.org> http://hg.python.org/cpython/rev/ede0a342ed7e changeset: 88659:ede0a342ed7e parent: 88657:9adce4e25bdb parent: 88658:fed5d501a179 user: Serhiy Storchaka date: Thu Jan 23 16:49:22 2014 +0200 summary: Fixed test_user_command on OpenSolaris where floats can have different string representation in Tcl and Python. files: Lib/test/test_tcl.py | 29 ++++++++++++++++++++--------- 1 files changed, 20 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -199,9 +199,19 @@ result = arg return arg self.interp.createcommand('testfunc', testfunc) - def check(value, expected): - self.assertEqual(self.interp.call('testfunc', value), expected) - self.assertEqual(result, expected) + def check(value, expected, eq=self.assertEqual): + r = self.interp.call('testfunc', value) + self.assertIsInstance(result, str) + eq(result, expected) + self.assertIsInstance(r, str) + eq(r, expected) + def float_eq(actual, expected): + expected = float(expected) + self.assertAlmostEqual(float(actual), expected, + delta=abs(expected) * 1e-10) + def nan_eq(actual, expected): + actual = float(actual) + self.assertNotEqual(actual, actual) check(True, '1') check(False, '0') @@ -210,13 +220,14 @@ check('string\u20ac', 'string\u20ac') for i in (0, 1, -1, 2**31-1, -2**31): check(i, str(i)) - for f in (0.0, 1.0, -1.0, 1/3, - sys.float_info.min, sys.float_info.max, + for f in (0.0, 1.0, -1.0): + check(f, repr(f)) + for f in (1/3.0, sys.float_info.min, sys.float_info.max, -sys.float_info.min, -sys.float_info.max): - check(f, str(f)) - check(float('nan'), 'NaN') - check(float('inf'), 'Inf') - check(-float('inf'), '-Inf') + check(f, f, eq=float_eq) + check(float('inf'), 'Inf', eq=float_eq) + check(-float('inf'), '-Inf', eq=float_eq) + check(float('nan'), 'NaN', eq=nan_eq) check((), '') check((1, (2,), (3, 4), '5 6', ()), '1 2 {3 4} {5 6} {}') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 17:29:22 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 23 Jan 2014 17:29:22 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Close_=2320365=3A_Skip_tes?= =?utf-8?b?dF9hc3luY2lvLnRlc3RfZXZlbnRzLnRlc3RfcmVhZF9wdHlfb3V0cHV0KCkg?= =?utf-8?q?on_Mac_OS_X?= Message-ID: <3f98820JK2z7Ll6@mail.python.org> http://hg.python.org/cpython/rev/424564cffad0 changeset: 88660:424564cffad0 user: Victor Stinner date: Thu Jan 23 17:26:06 2014 +0100 summary: Close #20365: Skip test_asyncio.test_events.test_read_pty_output() on Mac OS X older than 10.9 (Maverick). kqueue doesn't support character devices (PTY) on Mac OS X older than 10.9. files: Lib/test/test_asyncio/test_events.py | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) 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 @@ -957,6 +957,9 @@ @unittest.skipUnless(sys.platform != 'win32', "Don't support pipes for Windows") + # kqueue doesn't support character devices (PTY) on Mac OS X older + # than 10.9 (Maverick) + @support.requires_mac_ver(10, 9) def test_read_pty_output(self): proto = None -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 17:41:42 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 23 Jan 2014 17:41:42 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio_=28Tulip_issue_110?= =?utf-8?q?=29=3A_StreamReader=2Eread=28=29_and_StreamReader=2Ereadline=28?= =?utf-8?q?=29_now?= Message-ID: <3f98QG0rTjz7LkF@mail.python.org> http://hg.python.org/cpython/rev/fca191908d24 changeset: 88661:fca191908d24 user: Victor Stinner date: Thu Jan 23 17:40:03 2014 +0100 summary: asyncio (Tulip issue 110): StreamReader.read() and StreamReader.readline() now raise a RuntimeError, instead of using an assertion, if another coroutine is already waiting for incoming data files: Lib/asyncio/streams.py | 21 ++++++++++++++------- 1 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -21,7 +21,7 @@ """A wrapper for create_connection() returning a (reader, writer) pair. The reader returned is a StreamReader instance; the writer is a - StreamWriter. + StreamWriter instance. The arguments are all the usual arguments to create_connection() except protocol_factory; most common are positional host and port, @@ -284,6 +284,16 @@ else: self._paused = True + def _create_waiter(self, func_name): + # StreamReader uses a future to link the protocol feed_data() method + # to a read coroutine. Running two read coroutines at the same time + # would have an unexpected behaviour. It would not possible to know + # which coroutine would get the next data. + if self._waiter is not None: + raise RuntimeError('%s() called while another coroutine is ' + 'already waiting for incoming data' % func_name) + return futures.Future(loop=self._loop) + @tasks.coroutine def readline(self): if self._exception is not None: @@ -318,8 +328,7 @@ break if not_enough: - assert self._waiter is None - self._waiter = futures.Future(loop=self._loop) + self._waiter = self._create_waiter('readline') try: yield from self._waiter finally: @@ -341,16 +350,14 @@ if n < 0: while not self._eof: - assert not self._waiter - self._waiter = futures.Future(loop=self._loop) + self._waiter = self._create_waiter('read') try: yield from self._waiter finally: self._waiter = None else: if not self._byte_count and not self._eof: - assert not self._waiter - self._waiter = futures.Future(loop=self._loop) + self._waiter = self._create_waiter('read') try: yield from self._waiter finally: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 17:41:43 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 23 Jan 2014 17:41:43 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_wait=5Ffor=28?= =?utf-8?q?=29_now_cancels_the_future_on_timeout=2E_Patch_written_by_Gusta?= =?utf-8?q?vo?= Message-ID: <3f98QH3jdkz7LkF@mail.python.org> http://hg.python.org/cpython/rev/c3e787c44885 changeset: 88662:c3e787c44885 user: Victor Stinner date: Thu Jan 23 17:40:59 2014 +0100 summary: asyncio: wait_for() now cancels the future on timeout. Patch written by Gustavo Carneiro. files: Lib/asyncio/tasks.py | 6 ++- Lib/test/test_asyncio/test_tasks.py | 31 ++++++++-------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -382,8 +382,9 @@ Coroutine will be wrapped in Task. - Returns result of the Future or coroutine. Raises TimeoutError when - timeout occurs. + Returns result of the Future or coroutine. When a timeout occurs, + it cancels the task and raises TimeoutError. To avoid the task + cancellation, wrap it in shield(). Usage: @@ -405,6 +406,7 @@ return fut.result() else: fut.remove_done_callback(cb) + fut.cancel() raise futures.TimeoutError() finally: timeout_handle.cancel() 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 @@ -355,30 +355,32 @@ when = yield 0 self.assertAlmostEqual(0.1, when) when = yield 0.1 - self.assertAlmostEqual(0.4, when) - yield 0.1 loop = test_utils.TestLoop(gen) self.addCleanup(loop.close) + foo_running = None + @tasks.coroutine def foo(): - yield from tasks.sleep(0.2, loop=loop) + nonlocal foo_running + foo_running = True + try: + yield from tasks.sleep(0.2, loop=loop) + finally: + foo_running = False return 'done' fut = tasks.Task(foo(), loop=loop) with self.assertRaises(futures.TimeoutError): loop.run_until_complete(tasks.wait_for(fut, 0.1, loop=loop)) + self.assertTrue(fut.done()) + # it should have been cancelled due to the timeout + self.assertTrue(fut.cancelled()) + self.assertAlmostEqual(0.1, loop.time()) + self.assertEqual(foo_running, False) - self.assertFalse(fut.done()) - self.assertAlmostEqual(0.1, loop.time()) - - # wait for result - res = loop.run_until_complete( - tasks.wait_for(fut, 0.3, loop=loop)) - self.assertEqual(res, 'done') - self.assertAlmostEqual(0.2, loop.time()) def test_wait_for_with_global_loop(self): @@ -406,11 +408,8 @@ events.set_event_loop(None) self.assertAlmostEqual(0.01, loop.time()) - self.assertFalse(fut.done()) - - # move forward to close generator - loop.advance_time(10) - loop.run_until_complete(fut) + self.assertTrue(fut.done()) + self.assertTrue(fut.cancelled()) def test_wait(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 23 18:05:40 2014 From: python-checkins at python.org (yury.selivanov) Date: Thu, 23 Jan 2014 18:05:40 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?devguide=3A_experts=3A_Add_myself_for?= =?utf-8?q?_the_inspect_module?= Message-ID: <3f98xw0LzPz7LjM@mail.python.org> http://hg.python.org/devguide/rev/1b1fd40a2756 changeset: 660:1b1fd40a2756 user: Yury Selivanov date: Thu Jan 23 12:04:44 2014 -0500 summary: experts: Add myself for the inspect module files: experts.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/experts.rst b/experts.rst --- a/experts.rst +++ b/experts.rst @@ -130,7 +130,7 @@ imghdr imp importlib brett.cannon -inspect +inspect yselivanov io pitrou, benjamin.peterson, stutzbach ipaddress pmoody, ncoghlan itertools rhettinger -- Repository URL: http://hg.python.org/devguide From root at python.org Thu Jan 23 18:10:05 2014 From: root at python.org (Cron Daemon) Date: Thu, 23 Jan 2014 18:10:05 +0100 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: Could not find platform independent libraries Could not find platform dependent libraries Consider setting $PYTHONHOME to [:] 'import site' failed; use -v for traceback Traceback (most recent call last): File "/data/hg/sphinx-env/bin/sphinx-build", line 5, in from pkg_resources import load_entry_point ImportError: No module named pkg_resources From python-checkins at python.org Fri Jan 24 06:33:38 2014 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 24 Jan 2014 06:33:38 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_use_new_readli?= =?utf-8?q?ne_function_types_=28closes_=2320374=29?= Message-ID: <3f9TXy42kFz7LjQ@mail.python.org> http://hg.python.org/cpython/rev/79b82ebc4fd1 changeset: 88663:79b82ebc4fd1 branch: 2.7 parent: 88655:f28b60141c5c user: Benjamin Peterson date: Fri Jan 24 00:32:12 2014 -0500 summary: use new readline function types (closes #20374) files: Misc/NEWS | 2 ++ Modules/readline.c | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -38,6 +38,8 @@ Library ------- +- Issue #20374: Fix build with GNU readline >= 6.3. + - Issue #14548: Make multiprocessing finalizers check pid before running to cope with possibility of gc running just after fork. (Backport from 3.x.) diff --git a/Modules/readline.c b/Modules/readline.c --- a/Modules/readline.c +++ b/Modules/readline.c @@ -911,12 +911,12 @@ rl_bind_key_in_map ('\t', rl_complete, emacs_meta_keymap); rl_bind_key_in_map ('\033', rl_complete, emacs_meta_keymap); /* Set our hook functions */ - rl_startup_hook = (Function *)on_startup_hook; + rl_startup_hook = (rl_hook_func_t *)on_startup_hook; #ifdef HAVE_RL_PRE_INPUT_HOOK - rl_pre_input_hook = (Function *)on_pre_input_hook; + rl_pre_input_hook = (rl_hook_func_t *)on_pre_input_hook; #endif /* Set our completion function */ - rl_attempted_completion_function = (CPPFunction *)flex_complete; + rl_attempted_completion_function = (rl_completion_func_t *)flex_complete; /* Set Python word break characters */ completer_word_break_characters = rl_completer_word_break_characters = -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 24 06:33:39 2014 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 24 Jan 2014 06:33:39 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_use_new_readli?= =?utf-8?q?ne_function_types_=28closes_=2320374=29?= Message-ID: <3f9TXz5sSJz7Ljg@mail.python.org> http://hg.python.org/cpython/rev/fb2259d9f6b4 changeset: 88664:fb2259d9f6b4 branch: 3.3 parent: 88658:fed5d501a179 user: Benjamin Peterson date: Fri Jan 24 00:32:12 2014 -0500 summary: use new readline function types (closes #20374) files: Misc/NEWS | 2 ++ Modules/readline.c | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -56,6 +56,8 @@ loop this caused is now avoided by checking if the expected context is already set before trying to fix it. +- Issue #20374: Fix build with GNU readline >= 6.3. + - Issue #20311: select.epoll.poll() now rounds the timeout away from zero, instead of rounding towards zero. For example, a timeout of one microsecond is now rounded to one millisecond, instead of being rounded to zero. diff --git a/Modules/readline.c b/Modules/readline.c --- a/Modules/readline.c +++ b/Modules/readline.c @@ -936,12 +936,12 @@ rl_bind_key_in_map ('\t', rl_complete, emacs_meta_keymap); rl_bind_key_in_map ('\033', rl_complete, emacs_meta_keymap); /* Set our hook functions */ - rl_startup_hook = (Function *)on_startup_hook; + rl_startup_hook = (rl_hook_func_t *)on_startup_hook; #ifdef HAVE_RL_PRE_INPUT_HOOK - rl_pre_input_hook = (Function *)on_pre_input_hook; + rl_pre_input_hook = (rl_hook_func_t *)on_pre_input_hook; #endif /* Set our completion function */ - rl_attempted_completion_function = (CPPFunction *)flex_complete; + rl_attempted_completion_function = (rl_completion_func_t *)flex_complete; /* Set Python word break characters */ completer_word_break_characters = rl_completer_word_break_characters = -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 24 06:33:41 2014 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 24 Jan 2014 06:33:41 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4zICgjMjAzNzQp?= Message-ID: <3f9TY10Gfqz7Ljr@mail.python.org> http://hg.python.org/cpython/rev/eb251e3624df changeset: 88665:eb251e3624df parent: 88662:c3e787c44885 parent: 88664:fb2259d9f6b4 user: Benjamin Peterson date: Fri Jan 24 00:33:25 2014 -0500 summary: merge 3.3 (#20374) files: Misc/NEWS | 2 ++ Modules/readline.c | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,8 @@ loop this caused is now avoided by checking if the expected context is already set before trying to fix it. +- Issue #20374: Fix build with GNU readline >= 6.3. + - Issue #20311: select.epoll.poll() now rounds the timeout away from zero, instead of rounding towards zero. For example, a timeout of one microsecond is now rounded to one millisecond, instead of being rounded to zero. diff --git a/Modules/readline.c b/Modules/readline.c --- a/Modules/readline.c +++ b/Modules/readline.c @@ -998,12 +998,12 @@ rl_bind_key_in_map ('\t', rl_complete, emacs_meta_keymap); rl_bind_key_in_map ('\033', rl_complete, emacs_meta_keymap); /* Set our hook functions */ - rl_startup_hook = (Function *)on_startup_hook; + rl_startup_hook = (rl_hook_func_t *)on_startup_hook; #ifdef HAVE_RL_PRE_INPUT_HOOK - rl_pre_input_hook = (Function *)on_pre_input_hook; + rl_pre_input_hook = (rl_hook_func_t *)on_pre_input_hook; #endif /* Set our completion function */ - rl_attempted_completion_function = (CPPFunction *)flex_complete; + rl_attempted_completion_function = (rl_completion_func_t *)flex_complete; /* Set Python word break characters */ completer_word_break_characters = rl_completer_word_break_characters = -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Jan 24 09:47:05 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 24 Jan 2014 09:47:05 +0100 Subject: [Python-checkins] Daily reference leaks (c3e787c44885): sum=0 Message-ID: results for c3e787c44885 on branch "default" -------------------------------------------- test_site leaked [-2, 0, 2] references, sum=0 test_site leaked [-2, 0, 2] memory blocks, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogJFFN1G', '-x'] From python-checkins at python.org Fri Jan 24 14:07:29 2014 From: python-checkins at python.org (nick.coghlan) Date: Fri, 24 Jan 2014 14:07:29 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgMjAzMTc6?= =?utf-8?q?_Remove_debugging_code_from_contextlib?= Message-ID: <3f9gcd43Xvz7Ljt@mail.python.org> http://hg.python.org/cpython/rev/b3eaeb4bdf84 changeset: 88666:b3eaeb4bdf84 branch: 3.3 parent: 88664:fb2259d9f6b4 user: Nick Coghlan date: Fri Jan 24 23:05:45 2014 +1000 summary: Issue 20317: Remove debugging code from contextlib - Alex J Burke noticed a debugging raise in the commit that fixed the original bug reported in issue 20317 - this showed that multiple iterations through the affected loop wasn't actually being tested files: Lib/contextlib.py | 4 +- Lib/test/test_contextlib.py | 58 ++++++++++++++++++++---- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/Lib/contextlib.py b/Lib/contextlib.py --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -231,7 +231,7 @@ # we were actually nesting multiple with statements frame_exc = sys.exc_info()[1] def _fix_exception_context(new_exc, old_exc): - # Context isn't what we want, so find the end of the chain + # Context may not be correct, so find the end of the chain while 1: exc_context = new_exc.__context__ if exc_context is old_exc: @@ -239,8 +239,6 @@ return if exc_context is None or exc_context is frame_exc: break - details = id(new_exc), id(old_exc), id(exc_context) - raise Exception(str(details)) new_exc = exc_context # Change the end of the chain to point to the exception # we expect it to reference diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py --- a/Lib/test/test_contextlib.py +++ b/Lib/test/test_contextlib.py @@ -603,24 +603,62 @@ def test_exit_exception_with_correct_context(self): # http://bugs.python.org/issue20317 @contextmanager - def gets_the_context_right(): + def gets_the_context_right(exc): try: - yield 6 + yield finally: - 1 / 0 + raise exc + + exc1 = Exception(1) + exc2 = Exception(2) + exc3 = Exception(3) + exc4 = Exception(4) # The contextmanager already fixes the context, so prior to the # fix, ExitStack would try to fix it *again* and get into an # infinite self-referential loop try: with ExitStack() as stack: - stack.enter_context(gets_the_context_right()) - stack.enter_context(gets_the_context_right()) - stack.enter_context(gets_the_context_right()) - except ZeroDivisionError as exc: - self.assertIsInstance(exc.__context__, ZeroDivisionError) - self.assertIsInstance(exc.__context__.__context__, ZeroDivisionError) - self.assertIsNone(exc.__context__.__context__.__context__) + stack.enter_context(gets_the_context_right(exc4)) + stack.enter_context(gets_the_context_right(exc3)) + stack.enter_context(gets_the_context_right(exc2)) + raise exc1 + except Exception as exc: + self.assertIs(exc, exc4) + self.assertIs(exc.__context__, exc3) + self.assertIs(exc.__context__.__context__, exc2) + self.assertIs(exc.__context__.__context__.__context__, exc1) + self.assertIsNone( + exc.__context__.__context__.__context__.__context__) + + def test_exit_exception_with_existing_context(self): + # Addresses a lack of test coverage discovered after checking in a + # fix for issue 20317 that still contained debugging code. + def raise_nested(inner_exc, outer_exc): + try: + raise inner_exc + finally: + raise outer_exc + exc1 = Exception(1) + exc2 = Exception(2) + exc3 = Exception(3) + exc4 = Exception(4) + exc5 = Exception(5) + try: + with ExitStack() as stack: + stack.callback(raise_nested, exc4, exc5) + stack.callback(raise_nested, exc2, exc3) + raise exc1 + except Exception as exc: + self.assertIs(exc, exc5) + self.assertIs(exc.__context__, exc4) + self.assertIs(exc.__context__.__context__, exc3) + self.assertIs(exc.__context__.__context__.__context__, exc2) + self.assertIs( + exc.__context__.__context__.__context__.__context__, exc1) + self.assertIsNone( + exc.__context__.__context__.__context__.__context__.__context__) + def test_body_exception_suppress(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 24 14:07:31 2014 From: python-checkins at python.org (nick.coghlan) Date: Fri, 24 Jan 2014 14:07:31 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_removal_of_issue_20317_debugging_code_from_3=2E3?= Message-ID: <3f9gcg0B06z7Ljw@mail.python.org> http://hg.python.org/cpython/rev/a0bf53afedfa changeset: 88667:a0bf53afedfa parent: 88665:eb251e3624df parent: 88666:b3eaeb4bdf84 user: Nick Coghlan date: Fri Jan 24 23:07:16 2014 +1000 summary: Merge removal of issue 20317 debugging code from 3.3 files: Lib/contextlib.py | 4 +- Lib/test/test_contextlib.py | 58 ++++++++++++++++++++---- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/Lib/contextlib.py b/Lib/contextlib.py --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -298,7 +298,7 @@ # we were actually nesting multiple with statements frame_exc = sys.exc_info()[1] def _fix_exception_context(new_exc, old_exc): - # Context isn't what we want, so find the end of the chain + # Context may not be correct, so find the end of the chain while 1: exc_context = new_exc.__context__ if exc_context is old_exc: @@ -306,8 +306,6 @@ return if exc_context is None or exc_context is frame_exc: break - details = id(new_exc), id(old_exc), id(exc_context) - raise Exception(str(details)) new_exc = exc_context # Change the end of the chain to point to the exception # we expect it to reference diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py --- a/Lib/test/test_contextlib.py +++ b/Lib/test/test_contextlib.py @@ -629,24 +629,62 @@ def test_exit_exception_with_correct_context(self): # http://bugs.python.org/issue20317 @contextmanager - def gets_the_context_right(): + def gets_the_context_right(exc): try: - yield 6 + yield finally: - 1 / 0 + raise exc + + exc1 = Exception(1) + exc2 = Exception(2) + exc3 = Exception(3) + exc4 = Exception(4) # The contextmanager already fixes the context, so prior to the # fix, ExitStack would try to fix it *again* and get into an # infinite self-referential loop try: with ExitStack() as stack: - stack.enter_context(gets_the_context_right()) - stack.enter_context(gets_the_context_right()) - stack.enter_context(gets_the_context_right()) - except ZeroDivisionError as exc: - self.assertIsInstance(exc.__context__, ZeroDivisionError) - self.assertIsInstance(exc.__context__.__context__, ZeroDivisionError) - self.assertIsNone(exc.__context__.__context__.__context__) + stack.enter_context(gets_the_context_right(exc4)) + stack.enter_context(gets_the_context_right(exc3)) + stack.enter_context(gets_the_context_right(exc2)) + raise exc1 + except Exception as exc: + self.assertIs(exc, exc4) + self.assertIs(exc.__context__, exc3) + self.assertIs(exc.__context__.__context__, exc2) + self.assertIs(exc.__context__.__context__.__context__, exc1) + self.assertIsNone( + exc.__context__.__context__.__context__.__context__) + + def test_exit_exception_with_existing_context(self): + # Addresses a lack of test coverage discovered after checking in a + # fix for issue 20317 that still contained debugging code. + def raise_nested(inner_exc, outer_exc): + try: + raise inner_exc + finally: + raise outer_exc + exc1 = Exception(1) + exc2 = Exception(2) + exc3 = Exception(3) + exc4 = Exception(4) + exc5 = Exception(5) + try: + with ExitStack() as stack: + stack.callback(raise_nested, exc4, exc5) + stack.callback(raise_nested, exc2, exc3) + raise exc1 + except Exception as exc: + self.assertIs(exc, exc5) + self.assertIs(exc.__context__, exc4) + self.assertIs(exc.__context__.__context__, exc3) + self.assertIs(exc.__context__.__context__.__context__, exc2) + self.assertIs( + exc.__context__.__context__.__context__.__context__, exc1) + self.assertIsNone( + exc.__context__.__context__.__context__.__context__.__context__) + def test_body_exception_suppress(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 24 15:17:46 2014 From: python-checkins at python.org (larry.hastings) Date: Fri, 24 Jan 2014 15:17:46 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320189=3A_Four_add?= =?utf-8?q?itional_builtin_types_=28PyTypeObject=2C?= Message-ID: <3f9j9k4Wl5z7LkT@mail.python.org> http://hg.python.org/cpython/rev/85710aa396ef changeset: 88668:85710aa396ef user: Larry Hastings date: Fri Jan 24 06:17:25 2014 -0800 summary: Issue #20189: Four additional builtin types (PyTypeObject, PyMethodDescr_Type, _PyMethodWrapper_Type, and PyWrapperDescr_Type) have been modified to provide introspection information for builtins. Also: many additional Lib, test suite, and Argument Clinic fixes. files: Doc/library/inspect.rst | 3 + Include/object.h | 3 + Lib/idlelib/idle_test/test_calltips.py | 15 +- Lib/inspect.py | 32 +- Lib/pydoc.py | 13 +- Lib/test/test_capi.py | 6 +- Lib/test/test_generators.py | 4 +- Lib/test/test_genexps.py | 4 +- Lib/test/test_inspect.py | 100 +- Lib/unittest/mock.py | 19 +- Misc/NEWS | 20 +- Modules/_cryptmodule.c | 4 +- Modules/_cursesmodule.c | 4 +- Modules/_datetimemodule.c | 14 +- Modules/_dbmmodule.c | 12 +- Modules/_opcode.c | 4 +- Modules/_pickle.c | 110 +- Modules/_sre.c | 8 +- Modules/_testcapimodule.c | 8 +- Modules/_weakref.c | 4 +- Modules/posixmodule.c | 12 +- Modules/unicodedata.c | 4 +- Modules/zlibmodule.c | 20 +- Objects/descrobject.c | 55 +- Objects/dictobject.c | 71 +- Objects/methodobject.c | 67 +- Objects/typeobject.c | 245 ++++- Objects/unicodeobject.c | 8 +- Python/bltinmodule.c | 2 +- Python/import.c | 48 +- Tools/clinic/clinic.py | 478 ++++++++---- 31 files changed, 870 insertions(+), 527 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -429,6 +429,9 @@ Accepts a wide range of python callables, from plain functions and classes to :func:`functools.partial` objects. + Raises :exc:`ValueError` if no signature can be provided, and + :exc:`TypeError` if that type of object is not supported. + .. note:: Some callables may not be introspectable in certain implementations of diff --git a/Include/object.h b/Include/object.h --- a/Include/object.h +++ b/Include/object.h @@ -492,6 +492,9 @@ PyAPI_FUNC(unsigned int) PyType_ClearCache(void); PyAPI_FUNC(void) PyType_Modified(PyTypeObject *); +PyAPI_FUNC(PyObject *) _PyType_GetDocFromInternalDoc(const char *name, const char *internal_doc); +PyAPI_FUNC(PyObject *) _PyType_GetTextSignatureFromInternalDoc(const char *name, const char *internal_doc); + /* Generic operations on objects */ struct _Py_Identifier; #ifndef Py_LIMITED_API diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -55,24 +55,27 @@ gtest(list.__new__, 'T.__new__(S, ...) -> a new object with type S, a subtype of T') gtest(list.__init__, - 'x.__init__(...) initializes x; see help(type(x)) for signature') + 'Initializes self. See help(type(self)) for accurate signature.') append_doc = "L.append(object) -> None -- append object to end" gtest(list.append, append_doc) gtest([].append, append_doc) gtest(List.append, append_doc) - gtest(types.MethodType, "method(function, instance)") + gtest(types.MethodType, "Create a bound instance method object.") gtest(SB(), default_tip) def test_multiline_docstring(self): # Test fewer lines than max. - self.assertEqual(signature(list), - "list() -> new empty list\n" - "list(iterable) -> new list initialized from iterable's items") + self.assertEqual(signature(dict), + "dict(mapping) -> new dictionary initialized from a mapping object's\n" + "(key, value) pairs\n" + "dict(iterable) -> new dictionary initialized as if via:\n" + "d = {}\n" + "for k, v in iterable:" + ) # Test max lines and line (currently) too long. self.assertEqual(signature(bytes), -"bytes(iterable_of_ints) -> bytes\n" "bytes(string, encoding[, errors]) -> bytes\n" "bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer\n" #bytes(int) -> bytes object of size given by the parameter initialized with null bytes diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1419,9 +1419,11 @@ _WrapperDescriptor = type(type.__call__) _MethodWrapper = type(all.__call__) +_ClassMethodWrapper = type(int.__dict__['from_bytes']) _NonUserDefinedCallables = (_WrapperDescriptor, _MethodWrapper, + _ClassMethodWrapper, types.BuiltinFunctionType) @@ -1443,6 +1445,13 @@ if not callable(obj): raise TypeError('{!r} is not a callable object'.format(obj)) + if (isinstance(obj, _NonUserDefinedCallables) or + ismethoddescriptor(obj) or + isinstance(obj, type)): + sig = Signature.from_builtin(obj) + if sig: + return sig + if isinstance(obj, types.MethodType): # In this case we skip the first parameter of the underlying # function (usually `self` or `cls`). @@ -1460,13 +1469,9 @@ if sig is not None: return sig - if isinstance(obj, types.FunctionType): return Signature.from_function(obj) - if isinstance(obj, types.BuiltinFunctionType): - return Signature.from_builtin(obj) - if isinstance(obj, functools.partial): sig = signature(obj.func) @@ -2033,7 +2038,7 @@ name = parse_name(name_node) if name is invalid: return None - if default_node: + if default_node and default_node is not _empty: try: default_node = RewriteSymbolics().visit(default_node) o = ast.literal_eval(default_node) @@ -2066,6 +2071,23 @@ kind = Parameter.VAR_KEYWORD p(f.args.kwarg, empty) + if parameters and (hasattr(func, '__self__') or + isinstance(func, _WrapperDescriptor,) or + ismethoddescriptor(func) + ): + name = parameters[0].name + if name not in ('self', 'module', 'type'): + pass + elif getattr(func, '__self__', None): + # strip off self (it's already been bound) + p = parameters.pop(0) + if not p.name in ('self', 'module', 'type'): + raise ValueError('Unexpected name ' + repr(p.name) + ', expected self/module/cls/type') + else: + # for builtins, self parameter is always positional-only! + p = parameters[0].replace(kind=Parameter.POSITIONAL_ONLY) + parameters[0] = p + return cls(parameters, return_annotation=cls.empty) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -925,7 +925,10 @@ anchor, name, reallink) argspec = None if inspect.isfunction(object) or inspect.isbuiltin(object): - signature = inspect.signature(object) + try: + signature = inspect.signature(object) + except (ValueError, TypeError): + signature = None if signature: argspec = str(signature) if realname == '': @@ -1319,8 +1322,12 @@ skipdocs = 1 title = self.bold(name) + ' = ' + realname argspec = None - if inspect.isfunction(object) or inspect.isbuiltin(object): - signature = inspect.signature(object) + + if inspect.isroutine(object): + try: + signature = inspect.signature(object) + except (ValueError, TypeError): + signature = None if signature: argspec = str(signature) if realname == '': 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 @@ -125,7 +125,7 @@ self.assertEqual(_testcapi.docstring_no_signature.__text_signature__, None) self.assertEqual(_testcapi.docstring_with_invalid_signature.__doc__, - "docstring_with_invalid_signature (boo)\n" + "docstring_with_invalid_signature (module, boo)\n" "\n" "This docstring has an invalid signature." ) @@ -133,12 +133,12 @@ self.assertEqual(_testcapi.docstring_with_signature.__doc__, "This docstring has a valid signature.") - self.assertEqual(_testcapi.docstring_with_signature.__text_signature__, "(sig)") + self.assertEqual(_testcapi.docstring_with_signature.__text_signature__, "(module, sig)") self.assertEqual(_testcapi.docstring_with_signature_and_extra_newlines.__doc__, "This docstring has a valid signature and some extra newlines.") self.assertEqual(_testcapi.docstring_with_signature_and_extra_newlines.__text_signature__, - "(parameter)") + "(module, parameter)") @unittest.skipUnless(threading, 'Threading required for this test.') diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -436,8 +436,8 @@ >>> [s for s in dir(i) if not s.startswith('_')] ['close', 'gi_code', 'gi_frame', 'gi_running', 'send', 'throw'] >>> from test.support import HAVE_DOCSTRINGS ->>> print(i.__next__.__doc__ if HAVE_DOCSTRINGS else 'x.__next__() <==> next(x)') -x.__next__() <==> next(x) +>>> print(i.__next__.__doc__ if HAVE_DOCSTRINGS else 'Implements next(self).') +Implements next(self). >>> iter(i) is i True >>> import types diff --git a/Lib/test/test_genexps.py b/Lib/test/test_genexps.py --- a/Lib/test/test_genexps.py +++ b/Lib/test/test_genexps.py @@ -222,8 +222,8 @@ True >>> from test.support import HAVE_DOCSTRINGS - >>> print(g.__next__.__doc__ if HAVE_DOCSTRINGS else 'x.__next__() <==> next(x)') - x.__next__() <==> next(x) + >>> print(g.__next__.__doc__ if HAVE_DOCSTRINGS else 'Implements next(self).') + Implements next(self). >>> import types >>> isinstance(g, types.GeneratorType) True diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1,21 +1,25 @@ +import _testcapi +import collections +import datetime +import functools +import importlib +import inspect +import io +import linecache +import os +from os.path import normcase +import _pickle import re +import shutil import sys import types +import unicodedata import unittest -import inspect -import linecache -import datetime -import collections -import os -import shutil -import functools -import importlib -from os.path import normcase + try: from concurrent.futures import ThreadPoolExecutor except ImportError: ThreadPoolExecutor = None -import _testcapi from test.support import run_unittest, TESTFN, DirsOnSysPath from test.support import MISSING_C_DOCSTRINGS @@ -23,8 +27,6 @@ from test import inspect_fodder as mod from test import inspect_fodder2 as mod2 -# C module for test_findsource_binary -import unicodedata # Functions tested in this suite: # ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode, @@ -1582,23 +1584,30 @@ ...)) def test_signature_on_unsupported_builtins(self): - with self.assertRaisesRegex(ValueError, 'not supported by signature'): - inspect.signature(type) - with self.assertRaisesRegex(ValueError, 'not supported by signature'): - # support for 'wrapper_descriptor' - inspect.signature(type.__call__) - with self.assertRaisesRegex(ValueError, 'not supported by signature'): - # support for 'method-wrapper' - inspect.signature(min.__call__) + with self.assertRaisesRegex(ValueError, 'no signature found'): + # min simply doesn't have a signature (yet) + inspect.signature(min) @unittest.skipIf(MISSING_C_DOCSTRINGS, "Signature information for builtins requires docstrings") def test_signature_on_builtins(self): - # min doesn't have a signature (yet) - self.assertEqual(inspect.signature(min), None) - - signature = inspect.signature(_testcapi.docstring_with_signature_with_defaults) - self.assertTrue(isinstance(signature, inspect.Signature)) + + def test_unbound_method(o): + """Use this to test unbound methods (things that should have a self)""" + signature = inspect.signature(o) + self.assertTrue(isinstance(signature, inspect.Signature)) + self.assertEqual(list(signature.parameters.values())[0].name, 'self') + return signature + + def test_callable(o): + """Use this to test bound methods or normal callables (things that don't expect self)""" + signature = inspect.signature(o) + self.assertTrue(isinstance(signature, inspect.Signature)) + if signature.parameters: + self.assertNotEqual(list(signature.parameters.values())[0].name, 'self') + return signature + + signature = test_callable(_testcapi.docstring_with_signature_with_defaults) def p(name): return signature.parameters[name].default self.assertEqual(p('s'), 'avocado') self.assertEqual(p('b'), b'bytes') @@ -1611,6 +1620,41 @@ self.assertEqual(p('sys'), sys.maxsize) self.assertEqual(p('exp'), sys.maxsize - 1) + test_callable(type) + test_callable(object) + + # normal method + # (PyMethodDescr_Type, "method_descriptor") + test_unbound_method(_pickle.Pickler.dump) + d = _pickle.Pickler(io.StringIO()) + test_callable(d.dump) + + # static method + test_callable(str.maketrans) + test_callable('abc'.maketrans) + + # class method + test_callable(dict.fromkeys) + test_callable({}.fromkeys) + + # wrapper around slot (PyWrapperDescr_Type, "wrapper_descriptor") + test_unbound_method(type.__call__) + test_unbound_method(int.__add__) + test_callable((3).__add__) + + # _PyMethodWrapper_Type + # support for 'method-wrapper' + test_callable(min.__call__) + + class ThisWorksNow: + __call__ = type + test_callable(ThisWorksNow()) + + + def test_signature_on_builtins_no_signature(self): + with self.assertRaisesRegex(ValueError, 'no signature found for builtin'): + inspect.signature(_testcapi.docstring_no_signature) + def test_signature_on_non_function(self): with self.assertRaisesRegex(TypeError, 'is not a callable object'): inspect.signature(42) @@ -1985,12 +2029,6 @@ ((('a', ..., ..., "positional_or_keyword"),), ...)) - class ToFail: - __call__ = type - with self.assertRaisesRegex(ValueError, "not supported by signature"): - inspect.signature(ToFail()) - - class Wrapped: pass Wrapped.__wrapped__ = lambda a: None diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -112,11 +112,24 @@ def _copy_func_details(func, funcopy): funcopy.__name__ = func.__name__ funcopy.__doc__ = func.__doc__ + try: + funcopy.__text_signature__ = func.__text_signature__ + except AttributeError: + pass # we explicitly don't copy func.__dict__ into this copy as it would # expose original attributes that should be mocked - funcopy.__module__ = func.__module__ - funcopy.__defaults__ = func.__defaults__ - funcopy.__kwdefaults__ = func.__kwdefaults__ + try: + funcopy.__module__ = func.__module__ + except AttributeError: + pass + try: + funcopy.__defaults__ = func.__defaults__ + except AttributeError: + pass + try: + funcopy.__kwdefaults__ = func.__kwdefaults__ + except AttributeError: + pass def _callable(obj): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #20189: Four additional builtin types (PyTypeObject, + PyMethodDescr_Type, _PyMethodWrapper_Type, and PyWrapperDescr_Type) + have been modified to provide introspection information for builtins. + - Issue #17825: Cursor "^" is correctly positioned for SyntaxError and IndentationError. @@ -32,6 +36,10 @@ Library ------- +- Issue #20189: unittest.mock now no longer assumes that any object for + which it could get an inspect.Signature is a callable written in Python. + Fix courtesy of Michael Foord. + - Issue #20311: selector.PollSelector.select() now rounds the timeout away from zero, instead of rounding towards zero. For example, a timeout of one microsecond is now rounded to one millisecond, instead of being rounded to @@ -122,7 +130,7 @@ --Issue #17390: Add Python version to Idle editor window title bar. Original patches by Edmond Burnett and Kent Johnson. - + - Issue #18960: IDLE now ignores the source encoding declaration on the second line if the first line contains anything except a comment. @@ -133,6 +141,16 @@ Tools/Demos ----------- +- Issue #20189: Argument Clinic now ensures that parser functions for + __new__ are always of type newfunc, the type of the tp_new slot. + Similarly, parser functions for __init__ are now always of type initproc, + the type of tp_init. + +- Issue #20189: Argument Clinic now suppresses the docstring for __new__ + and __init__ functions if no docstring is provided in the input. + +- Issue #20189: Argument Clinic now suppresses the "self" parameter in the + impl for @staticmethod functions. - Issue #20294: Argument Clinic now supports argument parsing for __new__ and __init__ functions. diff --git a/Modules/_cryptmodule.c b/Modules/_cryptmodule.c --- a/Modules/_cryptmodule.c +++ b/Modules/_cryptmodule.c @@ -30,7 +30,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(crypt_crypt__doc__, -"crypt(word, salt)\n" +"crypt(module, word, salt)\n" "Hash a *word* with the given *salt* and return the hashed password.\n" "\n" "*word* will usually be a user\'s password. *salt* (either a random 2 or 16\n" @@ -63,7 +63,7 @@ static PyObject * crypt_crypt_impl(PyModuleDef *module, const char *word, const char *salt) -/*[clinic end generated code: checksum=a137540bf6862f9935fc112b8bb1d62d6dd1ad02]*/ +/*[clinic end generated code: checksum=dbfe26a21eb335abefe6a0bbd0a682ea22b9adc0]*/ { /* On some platforms (AtheOS) crypt returns NULL for an invalid salt. Return None in that case. XXX Maybe raise an exception? */ diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -584,7 +584,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(curses_window_addch__doc__, -"addch([x, y,] ch, [attr])\n" +"addch(self, [x, y,] ch, [attr])\n" "Paint character ch at (y, x) with attributes attr.\n" "\n" " x\n" @@ -651,7 +651,7 @@ static PyObject * curses_window_addch_impl(PyObject *self, int group_left_1, int x, int y, PyObject *ch, int group_right_1, long attr) -/*[clinic end generated code: checksum=53d44d79791b30950972b3256bdd464f7426bf82]*/ +/*[clinic end generated code: checksum=f6eeada77a9ec085125f3a27e4a2095f2a4c50be]*/ { PyCursesWindowObject *cwself = (PyCursesWindowObject *)self; int coordinates_group = group_left_1; diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -4159,7 +4159,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(datetime_datetime_now__doc__, -"now(tz=None)\n" +"now(type, tz=None)\n" "Returns new datetime object representing current time local to tz.\n" "\n" " tz\n" @@ -4171,10 +4171,10 @@ {"now", (PyCFunction)datetime_datetime_now, METH_VARARGS|METH_KEYWORDS|METH_CLASS, datetime_datetime_now__doc__}, static PyObject * -datetime_datetime_now_impl(PyTypeObject *cls, PyObject *tz); +datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz); static PyObject * -datetime_datetime_now(PyTypeObject *cls, PyObject *args, PyObject *kwargs) +datetime_datetime_now(PyTypeObject *type, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; static char *_keywords[] = {"tz", NULL}; @@ -4184,15 +4184,15 @@ "|O:now", _keywords, &tz)) goto exit; - return_value = datetime_datetime_now_impl(cls, tz); + return_value = datetime_datetime_now_impl(type, tz); exit: return return_value; } static PyObject * -datetime_datetime_now_impl(PyTypeObject *cls, PyObject *tz) -/*[clinic end generated code: checksum=ca3d26a423b3f633b260c7622e303f0915a96f7c]*/ +datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz) +/*[clinic end generated code: checksum=a6d3ad2c0ab6389075289af3467f7b8eb13f5f5c]*/ { PyObject *self; @@ -4202,7 +4202,7 @@ if (check_tzinfo_subclass(tz) < 0) return NULL; - self = datetime_best_possible((PyObject *)cls, + self = datetime_best_possible((PyObject *)type, tz == Py_None ? localtime : gmtime, tz); if (self != NULL && tz != Py_None) { diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c --- a/Modules/_dbmmodule.c +++ b/Modules/_dbmmodule.c @@ -279,7 +279,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(dbm_dbm_get__doc__, -"get(key, [default])\n" +"get(self, key, [default])\n" "Return the value for key if present, otherwise default."); #define DBM_DBM_GET_METHODDEF \ @@ -289,7 +289,7 @@ dbm_dbm_get_impl(dbmobject *dp, const char *key, Py_ssize_clean_t key_length, int group_right_1, PyObject *default_value); static PyObject * -dbm_dbm_get(PyObject *self, PyObject *args) +dbm_dbm_get(dbmobject *dp, PyObject *args) { PyObject *return_value = NULL; const char *key; @@ -311,7 +311,7 @@ PyErr_SetString(PyExc_TypeError, "dbm.dbm.get requires 1 to 2 arguments"); goto exit; } - return_value = dbm_dbm_get_impl((dbmobject *)self, key, key_length, group_right_1, default_value); + return_value = dbm_dbm_get_impl(dp, key, key_length, group_right_1, default_value); exit: return return_value; @@ -319,7 +319,7 @@ static PyObject * dbm_dbm_get_impl(dbmobject *dp, const char *key, Py_ssize_clean_t key_length, int group_right_1, PyObject *default_value) -/*[clinic end generated code: checksum=ca8bf63ec226e71d3cf390749777f7d5b7361478]*/ +/*[clinic end generated code: checksum=31d5180d6b36f1eafea78ec4391adf3559916379]*/ { datum dbm_key, val; @@ -462,7 +462,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(dbmopen__doc__, -"open(filename, flags=\'r\', mode=0o666)\n" +"open(module, filename, flags=\'r\', mode=0o666)\n" "Return a database object.\n" "\n" " filename\n" @@ -499,7 +499,7 @@ static PyObject * dbmopen_impl(PyModuleDef *module, const char *filename, const char *flags, int mode) -/*[clinic end generated code: checksum=fb265f75641553ccd963f84c143b35c11f9121fc]*/ +/*[clinic end generated code: checksum=9efae7d3c3b67a365011bf4e463e918901ba6c79]*/ { int iflags; diff --git a/Modules/_opcode.c b/Modules/_opcode.c --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -21,7 +21,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_opcode_stack_effect__doc__, -"stack_effect(opcode, [oparg])\n" +"stack_effect(module, opcode, [oparg])\n" "Compute the stack effect of the opcode."); #define _OPCODE_STACK_EFFECT_METHODDEF \ @@ -64,7 +64,7 @@ static int _opcode_stack_effect_impl(PyModuleDef *module, int opcode, int group_right_1, int oparg) -/*[clinic end generated code: checksum=58fb4f1b174fc92f783dc945ca712fb752a6c283]*/ +/*[clinic end generated code: checksum=4689140ffda2494a123ea2593fb63445fb039774]*/ { int effect; if (HAS_ARG(opcode)) { diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -3889,7 +3889,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_pickle_Pickler_clear_memo__doc__, -"clear_memo()\n" +"clear_memo(self)\n" "Clears the pickler\'s \"memo\".\n" "\n" "The memo is the data structure that remembers which objects the\n" @@ -3904,14 +3904,14 @@ _pickle_Pickler_clear_memo_impl(PicklerObject *self); static PyObject * -_pickle_Pickler_clear_memo(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _pickle_Pickler_clear_memo_impl((PicklerObject *)self); +_pickle_Pickler_clear_memo(PicklerObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _pickle_Pickler_clear_memo_impl(self); } static PyObject * _pickle_Pickler_clear_memo_impl(PicklerObject *self) -/*[clinic end generated code: checksum=015cc3c5befea86cb08b9396938477bebbea4157]*/ +/*[clinic end generated code: checksum=17b1165d8dcae5a2e90b1703bf5cbbfc26114c5a]*/ { if (self->memo) PyMemoTable_Clear(self->memo); @@ -3931,7 +3931,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_pickle_Pickler_dump__doc__, -"dump(obj)\n" +"dump(self, obj)\n" "Write a pickled representation of the given object to the open file."); #define _PICKLE_PICKLER_DUMP_METHODDEF \ @@ -3939,7 +3939,7 @@ static PyObject * _pickle_Pickler_dump(PicklerObject *self, PyObject *obj) -/*[clinic end generated code: checksum=b72a69ec98737fabf66dae7c5a3210178bdbd3e6]*/ +/*[clinic end generated code: checksum=36db7f67c8bc05ca6f17b8ab57c54d64bfd0539e]*/ { /* Check whether the Pickler was initialized correctly (issue3664). Developers often forget to call __init__() in their subclasses, which @@ -4077,7 +4077,7 @@ int fix_imports = 1; if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O|Op:__init__", _keywords, + "O|Op:Pickler", _keywords, &file, &protocol, &fix_imports)) goto exit; return_value = _pickle_Pickler___init___impl((PicklerObject *)self, file, protocol, fix_imports); @@ -4088,7 +4088,7 @@ static int _pickle_Pickler___init___impl(PicklerObject *self, PyObject *file, PyObject *protocol, int fix_imports) -/*[clinic end generated code: checksum=d10dfb463511430b4faad9fca07627041a35b96e]*/ +/*[clinic end generated code: checksum=b055bf46cfb5b92c1863302d075246a68bd89153]*/ { _Py_IDENTIFIER(persistent_id); _Py_IDENTIFIER(dispatch_table); @@ -4164,7 +4164,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_pickle_PicklerMemoProxy_clear__doc__, -"clear()\n" +"clear(self)\n" "Remove all items from memo."); #define _PICKLE_PICKLERMEMOPROXY_CLEAR_METHODDEF \ @@ -4174,14 +4174,14 @@ _pickle_PicklerMemoProxy_clear_impl(PicklerMemoProxyObject *self); static PyObject * -_pickle_PicklerMemoProxy_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _pickle_PicklerMemoProxy_clear_impl((PicklerMemoProxyObject *)self); +_pickle_PicklerMemoProxy_clear(PicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _pickle_PicklerMemoProxy_clear_impl(self); } static PyObject * _pickle_PicklerMemoProxy_clear_impl(PicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=bf8dd8c8688d0c0f7a2e59a804c47375b740f2f0]*/ +/*[clinic end generated code: checksum=fb4a5ba40918b3eccc9bc1e9d6875cb2737127a9]*/ { if (self->pickler->memo) PyMemoTable_Clear(self->pickler->memo); @@ -4197,7 +4197,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_pickle_PicklerMemoProxy_copy__doc__, -"copy()\n" +"copy(self)\n" "Copy the memo to a new object."); #define _PICKLE_PICKLERMEMOPROXY_COPY_METHODDEF \ @@ -4207,14 +4207,14 @@ _pickle_PicklerMemoProxy_copy_impl(PicklerMemoProxyObject *self); static PyObject * -_pickle_PicklerMemoProxy_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _pickle_PicklerMemoProxy_copy_impl((PicklerMemoProxyObject *)self); +_pickle_PicklerMemoProxy_copy(PicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _pickle_PicklerMemoProxy_copy_impl(self); } static PyObject * _pickle_PicklerMemoProxy_copy_impl(PicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=72d46879dc658adbd3d28b5c82dd8dcfa6b9b124]*/ +/*[clinic end generated code: checksum=3d27d3005725f1828c9a92a38197811c54c64abb]*/ { Py_ssize_t i; PyMemoTable *memo; @@ -4260,7 +4260,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_pickle_PicklerMemoProxy___reduce____doc__, -"__reduce__()\n" +"__reduce__(self)\n" "Implement pickle support."); #define _PICKLE_PICKLERMEMOPROXY___REDUCE___METHODDEF \ @@ -4270,14 +4270,14 @@ _pickle_PicklerMemoProxy___reduce___impl(PicklerMemoProxyObject *self); static PyObject * -_pickle_PicklerMemoProxy___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _pickle_PicklerMemoProxy___reduce___impl((PicklerMemoProxyObject *)self); +_pickle_PicklerMemoProxy___reduce__(PicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _pickle_PicklerMemoProxy___reduce___impl(self); } static PyObject * _pickle_PicklerMemoProxy___reduce___impl(PicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=aad71c4d81d1ed8bf0d32362dd80a29b9f3b0d03]*/ +/*[clinic end generated code: checksum=2682cf8a3a5027def6328419001b086b047d47c8]*/ { PyObject *reduce_value, *dict_args; PyObject *contents = _pickle_PicklerMemoProxy_copy_impl(self); @@ -6299,7 +6299,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_pickle_Unpickler_load__doc__, -"load()\n" +"load(self)\n" "Load a pickle.\n" "\n" "Read a pickled object representation from the open file object given\n" @@ -6320,7 +6320,7 @@ static PyObject * _pickle_Unpickler_load_impl(PyObject *self) -/*[clinic end generated code: checksum=9477099fe6a90748c13ff1a6dd92ba7ab7a89602]*/ +/*[clinic end generated code: checksum=fb1119422c5e03045d690d1cd6c457f1ca4c585d]*/ { UnpicklerObject *unpickler = (UnpicklerObject*)self; @@ -6363,7 +6363,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_pickle_Unpickler_find_class__doc__, -"find_class(module_name, global_name)\n" +"find_class(self, module_name, global_name)\n" "Return an object from a specified module.\n" "\n" "If necessary, the module will be imported. Subclasses may override\n" @@ -6380,7 +6380,7 @@ _pickle_Unpickler_find_class_impl(UnpicklerObject *self, PyObject *module_name, PyObject *global_name); static PyObject * -_pickle_Unpickler_find_class(PyObject *self, PyObject *args) +_pickle_Unpickler_find_class(UnpicklerObject *self, PyObject *args) { PyObject *return_value = NULL; PyObject *module_name; @@ -6390,7 +6390,7 @@ 2, 2, &module_name, &global_name)) goto exit; - return_value = _pickle_Unpickler_find_class_impl((UnpicklerObject *)self, module_name, global_name); + return_value = _pickle_Unpickler_find_class_impl(self, module_name, global_name); exit: return return_value; @@ -6398,7 +6398,7 @@ static PyObject * _pickle_Unpickler_find_class_impl(UnpicklerObject *self, PyObject *module_name, PyObject *global_name) -/*[clinic end generated code: checksum=15ed4836fd5860425fff9ea7855d4f1f4413c170]*/ +/*[clinic end generated code: checksum=2b8d5398787c8ac7ea5d45f644433169e441003b]*/ { PyObject *global; PyObject *modules_dict; @@ -6617,7 +6617,7 @@ const char *errors = "strict"; if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O|$pss:__init__", _keywords, + "O|$pss:Unpickler", _keywords, &file, &fix_imports, &encoding, &errors)) goto exit; return_value = _pickle_Unpickler___init___impl((UnpicklerObject *)self, file, fix_imports, encoding, errors); @@ -6628,7 +6628,7 @@ static int _pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file, int fix_imports, const char *encoding, const char *errors) -/*[clinic end generated code: checksum=eb1a2cfc7b6f97c33980cff3d3b97d184a382f02]*/ +/*[clinic end generated code: checksum=a8a9dde29eb4ddd538b45099408ea77e01940692]*/ { _Py_IDENTIFIER(persistent_load); @@ -6698,7 +6698,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_pickle_UnpicklerMemoProxy_clear__doc__, -"clear()\n" +"clear(self)\n" "Remove all items from memo."); #define _PICKLE_UNPICKLERMEMOPROXY_CLEAR_METHODDEF \ @@ -6708,14 +6708,14 @@ _pickle_UnpicklerMemoProxy_clear_impl(UnpicklerMemoProxyObject *self); static PyObject * -_pickle_UnpicklerMemoProxy_clear(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _pickle_UnpicklerMemoProxy_clear_impl((UnpicklerMemoProxyObject *)self); +_pickle_UnpicklerMemoProxy_clear(UnpicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _pickle_UnpicklerMemoProxy_clear_impl(self); } static PyObject * _pickle_UnpicklerMemoProxy_clear_impl(UnpicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=07adecee2181e5e268b2ff184360b1d88ad947f2]*/ +/*[clinic end generated code: checksum=32f6ee47e44405dd587f768f3690d47947bb5a8e]*/ { _Unpickler_MemoCleanup(self->unpickler); self->unpickler->memo = _Unpickler_NewMemo(self->unpickler->memo_size); @@ -6733,7 +6733,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_pickle_UnpicklerMemoProxy_copy__doc__, -"copy()\n" +"copy(self)\n" "Copy the memo to a new object."); #define _PICKLE_UNPICKLERMEMOPROXY_COPY_METHODDEF \ @@ -6743,14 +6743,14 @@ _pickle_UnpicklerMemoProxy_copy_impl(UnpicklerMemoProxyObject *self); static PyObject * -_pickle_UnpicklerMemoProxy_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _pickle_UnpicklerMemoProxy_copy_impl((UnpicklerMemoProxyObject *)self); +_pickle_UnpicklerMemoProxy_copy(UnpicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _pickle_UnpicklerMemoProxy_copy_impl(self); } static PyObject * _pickle_UnpicklerMemoProxy_copy_impl(UnpicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=47b9f0cc12c5a54004252e1b4916822cdfa8a881]*/ +/*[clinic end generated code: checksum=ac3da80efc3b2548aa8b5c5358d0e82e615fce1d]*/ { Py_ssize_t i; PyObject *new_memo = PyDict_New(); @@ -6789,7 +6789,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_pickle_UnpicklerMemoProxy___reduce____doc__, -"__reduce__()\n" +"__reduce__(self)\n" "Implement pickling support."); #define _PICKLE_UNPICKLERMEMOPROXY___REDUCE___METHODDEF \ @@ -6799,14 +6799,14 @@ _pickle_UnpicklerMemoProxy___reduce___impl(UnpicklerMemoProxyObject *self); static PyObject * -_pickle_UnpicklerMemoProxy___reduce__(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _pickle_UnpicklerMemoProxy___reduce___impl((UnpicklerMemoProxyObject *)self); +_pickle_UnpicklerMemoProxy___reduce__(UnpicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _pickle_UnpicklerMemoProxy___reduce___impl(self); } static PyObject * _pickle_UnpicklerMemoProxy___reduce___impl(UnpicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=2f061bb9ecd9ee8500184c135148a131c46a3b88]*/ +/*[clinic end generated code: checksum=2373102b7c87d99ba4c4a56b6813d2c84dd61865]*/ { PyObject *reduce_value; PyObject *constructor_args; @@ -7115,7 +7115,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_pickle_dump__doc__, -"dump(obj, file, protocol=None, *, fix_imports=True)\n" +"dump(module, obj, file, protocol=None, *, fix_imports=True)\n" "Write a pickled representation of obj to the open file object file.\n" "\n" "This is equivalent to ``Pickler(file, protocol).dump(obj)``, but may\n" @@ -7166,7 +7166,7 @@ static PyObject * _pickle_dump_impl(PyModuleDef *module, PyObject *obj, PyObject *file, PyObject *protocol, int fix_imports) -/*[clinic end generated code: checksum=eb5c23e64da34477178230b704d2cc9c6b6650ea]*/ +/*[clinic end generated code: checksum=1d4ff873e13eb840ff275d716d8d4c5554af087c]*/ { PicklerObject *pickler = _Pickler_New(); @@ -7218,7 +7218,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_pickle_dumps__doc__, -"dumps(obj, protocol=None, *, fix_imports=True)\n" +"dumps(module, obj, protocol=None, *, fix_imports=True)\n" "Return the pickled representation of the object as a bytes object.\n" "\n" "The optional *protocol* argument tells the pickler to use the given\n" @@ -7260,7 +7260,7 @@ static PyObject * _pickle_dumps_impl(PyModuleDef *module, PyObject *obj, PyObject *protocol, int fix_imports) -/*[clinic end generated code: checksum=e9b915d61202a9692cb6c6718db74fe54fc9c4d1]*/ +/*[clinic end generated code: checksum=9c6c0291ef2d2b0856b7d4caecdcb7bad13a23b3]*/ { PyObject *result; PicklerObject *pickler = _Pickler_New(); @@ -7319,7 +7319,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_pickle_load__doc__, -"load(file, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" +"load(module, file, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" "Read and return an object from the pickle data stored in a file.\n" "\n" "This is equivalent to ``Unpickler(file).load()``, but may be more\n" @@ -7372,7 +7372,7 @@ static PyObject * _pickle_load_impl(PyModuleDef *module, PyObject *file, int fix_imports, const char *encoding, const char *errors) -/*[clinic end generated code: checksum=b41f06970e57acf2fd602e4b7f88e3f3e1e53087]*/ +/*[clinic end generated code: checksum=2b5b7e5e3a836cf1c53377ce9274a84a8bceef67]*/ { PyObject *result; UnpicklerObject *unpickler = _Unpickler_New(); @@ -7424,7 +7424,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_pickle_loads__doc__, -"loads(data, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" +"loads(module, data, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" "Read and return an object from the given pickle data.\n" "\n" "The protocol version of the pickle is detected automatically, so no\n" @@ -7468,7 +7468,7 @@ static PyObject * _pickle_loads_impl(PyModuleDef *module, PyObject *data, int fix_imports, const char *encoding, const char *errors) -/*[clinic end generated code: checksum=0663de43aca6c21508a777e29d98c9c3a6e7f72d]*/ +/*[clinic end generated code: checksum=7b21a75997c8f6636e4bf48c663b28f2bfd4eb6a]*/ { PyObject *result; UnpicklerObject *unpickler = _Unpickler_New(); diff --git a/Modules/_sre.c b/Modules/_sre.c --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -541,7 +541,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(pattern_match__doc__, -"match(pattern, pos=0, endpos=sys.maxsize)\n" +"match(self, pattern, pos=0, endpos=sys.maxsize)\n" "Matches zero or more characters at the beginning of the string."); #define PATTERN_MATCH_METHODDEF \ @@ -551,7 +551,7 @@ pattern_match_impl(PatternObject *self, PyObject *pattern, Py_ssize_t pos, Py_ssize_t endpos); static PyObject * -pattern_match(PyObject *self, PyObject *args, PyObject *kwargs) +pattern_match(PatternObject *self, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; static char *_keywords[] = {"pattern", "pos", "endpos", NULL}; @@ -563,7 +563,7 @@ "O|nn:match", _keywords, &pattern, &pos, &endpos)) goto exit; - return_value = pattern_match_impl((PatternObject *)self, pattern, pos, endpos); + return_value = pattern_match_impl(self, pattern, pos, endpos); exit: return return_value; @@ -571,7 +571,7 @@ static PyObject * pattern_match_impl(PatternObject *self, PyObject *pattern, Py_ssize_t pos, Py_ssize_t endpos) -/*[clinic end generated code: checksum=63e59c5f3019efe6c1f3acdec42b2d3595e14a09]*/ +/*[clinic end generated code: checksum=4a3865d13638cb7c13dcae1fe58c1a9c35071998]*/ { SRE_STATE state; Py_ssize_t status; diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2851,18 +2851,18 @@ ); PyDoc_STRVAR(docstring_with_invalid_signature, -"docstring_with_invalid_signature (boo)\n" +"docstring_with_invalid_signature (module, boo)\n" "\n" "This docstring has an invalid signature." ); PyDoc_STRVAR(docstring_with_signature, -"docstring_with_signature(sig)\n" +"docstring_with_signature(module, sig)\n" "This docstring has a valid signature." ); PyDoc_STRVAR(docstring_with_signature_and_extra_newlines, -"docstring_with_signature_and_extra_newlines(parameter)\n" +"docstring_with_signature_and_extra_newlines(module, parameter)\n" "\n" "\n" "\n" @@ -2870,7 +2870,7 @@ ); PyDoc_STRVAR(docstring_with_signature_with_defaults, -"docstring_with_signature_with_defaults(s='avocado', b=b'bytes', d=3.14, i=35, n=None, t=True, f=False, local=the_number_three, sys=sys.maxsize, exp=sys.maxsize - 1)\n" +"docstring_with_signature_with_defaults(module, s='avocado', b=b'bytes', d=3.14, i=35, n=None, t=True, f=False, local=the_number_three, sys=sys.maxsize, exp=sys.maxsize - 1)\n" "\n" "\n" "\n" diff --git a/Modules/_weakref.c b/Modules/_weakref.c --- a/Modules/_weakref.c +++ b/Modules/_weakref.c @@ -20,7 +20,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_weakref_getweakrefcount__doc__, -"getweakrefcount(object)\n" +"getweakrefcount(module, object)\n" "Return the number of weak references to \'object\'."); #define _WEAKREF_GETWEAKREFCOUNT_METHODDEF \ @@ -46,7 +46,7 @@ static Py_ssize_t _weakref_getweakrefcount_impl(PyModuleDef *module, PyObject *object) -/*[clinic end generated code: checksum=744fa73ba68c0ee89567e9cb9bea11863270d516]*/ +/*[clinic end generated code: checksum=dd8ba0730babf263d3db78d260ea7eacf6eb3735]*/ { PyWeakReference **list; diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -2430,7 +2430,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(os_stat__doc__, -"stat(path, *, dir_fd=None, follow_symlinks=True)\n" +"stat(module, path, *, dir_fd=None, follow_symlinks=True)\n" "Perform a stat system call on the given path.\n" "\n" " path\n" @@ -2481,7 +2481,7 @@ static PyObject * os_stat_impl(PyModuleDef *module, path_t *path, int dir_fd, int follow_symlinks) -/*[clinic end generated code: checksum=85a71ad602e89f8e280118da976f70cd2f9abdf1]*/ +/*[clinic end generated code: checksum=09cc91b4947f9e3b9335c8be998bb7c56f7f8b40]*/ { return posix_do_stat("stat", path, dir_fd, follow_symlinks); } @@ -2562,7 +2562,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(os_access__doc__, -"access(path, mode, *, dir_fd=None, effective_ids=False, follow_symlinks=True)\n" +"access(module, path, mode, *, dir_fd=None, effective_ids=False, follow_symlinks=True)\n" "Use the real uid/gid to test for access to a path.\n" "\n" " path\n" @@ -2622,7 +2622,7 @@ static PyObject * os_access_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd, int effective_ids, int follow_symlinks) -/*[clinic end generated code: checksum=636e835c36562a2fc11acab75314634127fdf769]*/ +/*[clinic end generated code: checksum=6483a51e1fee83da4f8e41cbc8054a701cfed1c5]*/ { PyObject *return_value = NULL; @@ -2718,7 +2718,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(os_ttyname__doc__, -"ttyname(fd)\n" +"ttyname(module, fd)\n" "Return the name of the terminal device connected to \'fd\'.\n" "\n" " fd\n" @@ -2752,7 +2752,7 @@ static char * os_ttyname_impl(PyModuleDef *module, int fd) -/*[clinic end generated code: checksum=0f368134dc0a7f21f25185e2e6bacf7675fb473a]*/ +/*[clinic end generated code: checksum=11bbb8b7969155f54bb8a1ec35ac1ebdfd4b0fec]*/ { char *ret; diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -129,7 +129,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(unicodedata_UCD_decimal__doc__, -"decimal(unichr, default=None)\n" +"decimal(self, unichr, default=None)\n" "Converts a Unicode character into its equivalent decimal value.\n" "\n" "Returns the decimal value assigned to the Unicode character unichr\n" @@ -161,7 +161,7 @@ static PyObject * unicodedata_UCD_decimal_impl(PyObject *self, PyUnicodeObject *unichr, PyObject *default_value) -/*[clinic end generated code: checksum=73edde0e9cd5913ea174c4fa81504369761b7426]*/ +/*[clinic end generated code: checksum=01826b179d497d8fd3842c56679ecbd4faddaa95]*/ { PyUnicodeObject *v = (PyUnicodeObject *)unichr; int have_old = 0; diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -180,7 +180,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(zlib_compress__doc__, -"compress(bytes, [level])\n" +"compress(module, bytes, [level])\n" "Returns compressed string.\n" "\n" " bytes\n" @@ -228,7 +228,7 @@ static PyObject * zlib_compress_impl(PyModuleDef *module, Py_buffer *bytes, int group_right_1, int level) -/*[clinic end generated code: checksum=74648f97e6b9d3cc9cd568d47262d462bded7ed0]*/ +/*[clinic end generated code: checksum=ce8d4c0a17ecd79c3ffcc032dcdf8ac6830ded1e]*/ { PyObject *ReturnVal = NULL; Byte *input, *output = NULL; @@ -766,7 +766,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(zlib_Decompress_decompress__doc__, -"decompress(data, max_length=0)\n" +"decompress(self, data, max_length=0)\n" "Return a string containing the decompressed version of the data.\n" "\n" " data\n" @@ -787,7 +787,7 @@ zlib_Decompress_decompress_impl(compobject *self, Py_buffer *data, unsigned int max_length); static PyObject * -zlib_Decompress_decompress(PyObject *self, PyObject *args) +zlib_Decompress_decompress(compobject *self, PyObject *args) { PyObject *return_value = NULL; Py_buffer data = {NULL, NULL}; @@ -797,7 +797,7 @@ "y*|O&:decompress", &data, uint_converter, &max_length)) goto exit; - return_value = zlib_Decompress_decompress_impl((compobject *)self, &data, max_length); + return_value = zlib_Decompress_decompress_impl(self, &data, max_length); exit: /* Cleanup for data */ @@ -809,7 +809,7 @@ static PyObject * zlib_Decompress_decompress_impl(compobject *self, Py_buffer *data, unsigned int max_length) -/*[clinic end generated code: checksum=e0058024c4a97b411d2e2197791b89fde175f76f]*/ +/*[clinic end generated code: checksum=b7fd2e3b23430f57f5a84817189575bc46464901]*/ { int err; unsigned int old_length, length = DEFAULTALLOC; @@ -1036,7 +1036,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(zlib_Compress_copy__doc__, -"copy()\n" +"copy(self)\n" "Return a copy of the compression object."); #define ZLIB_COMPRESS_COPY_METHODDEF \ @@ -1046,14 +1046,14 @@ zlib_Compress_copy_impl(compobject *self); static PyObject * -zlib_Compress_copy(PyObject *self, PyObject *Py_UNUSED(ignored)) +zlib_Compress_copy(compobject *self, PyObject *Py_UNUSED(ignored)) { - return zlib_Compress_copy_impl((compobject *)self); + return zlib_Compress_copy_impl(self); } static PyObject * zlib_Compress_copy_impl(compobject *self) -/*[clinic end generated code: checksum=d57a7911deb7940e85a8d7e65af20b6e2df69000]*/ +/*[clinic end generated code: checksum=7aa841ad51297eb83250f511a76872e88fdc737e]*/ { compobject *retval = NULL; int err; diff --git a/Objects/descrobject.c b/Objects/descrobject.c --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -353,11 +353,17 @@ static PyObject * method_get_doc(PyMethodDescrObject *descr, void *closure) { - if (descr->d_method->ml_doc == NULL) { - Py_INCREF(Py_None); - return Py_None; - } - return PyUnicode_FromString(descr->d_method->ml_doc); + const char *name = descr->d_method->ml_name; + const char *doc = descr->d_method->ml_doc; + return _PyType_GetDocFromInternalDoc(name, doc); +} + +static PyObject * +method_get_text_signature(PyMethodDescrObject *descr, void *closure) +{ + const char *name = descr->d_method->ml_name; + const char *doc = descr->d_method->ml_doc; + return _PyType_GetTextSignatureFromInternalDoc(name, doc); } static PyObject * @@ -425,6 +431,7 @@ static PyGetSetDef method_getset[] = { {"__doc__", (getter)method_get_doc}, {"__qualname__", (getter)descr_get_qualname}, + {"__text_signature__", (getter)method_get_text_signature}, {0} }; @@ -463,16 +470,23 @@ static PyObject * wrapperdescr_get_doc(PyWrapperDescrObject *descr, void *closure) { - if (descr->d_base->doc == NULL) { - Py_INCREF(Py_None); - return Py_None; - } - return PyUnicode_FromString(descr->d_base->doc); + const char *name = descr->d_base->name; + const char *doc = descr->d_base->doc; + return _PyType_GetDocFromInternalDoc(name, doc); +} + +static PyObject * +wrapperdescr_get_text_signature(PyWrapperDescrObject *descr, void *closure) +{ + const char *name = descr->d_base->name; + const char *doc = descr->d_base->doc; + return _PyType_GetTextSignatureFromInternalDoc(name, doc); } static PyGetSetDef wrapperdescr_getset[] = { {"__doc__", (getter)wrapperdescr_get_doc}, {"__qualname__", (getter)descr_get_qualname}, + {"__text_signature__", (getter)wrapperdescr_get_text_signature}, {0} }; @@ -1143,17 +1157,19 @@ } static PyObject * -wrapper_doc(wrapperobject *wp) +wrapper_doc(wrapperobject *wp, void *closure) { - const char *s = wp->descr->d_base->doc; + const char *name = wp->descr->d_base->name; + const char *doc = wp->descr->d_base->doc; + return _PyType_GetDocFromInternalDoc(name, doc); +} - if (s == NULL) { - Py_INCREF(Py_None); - return Py_None; - } - else { - return PyUnicode_FromString(s); - } +static PyObject * +wrapper_text_signature(wrapperobject *wp, void *closure) +{ + const char *name = wp->descr->d_base->name; + const char *doc = wp->descr->d_base->doc; + return _PyType_GetTextSignatureFromInternalDoc(name, doc); } static PyObject * @@ -1167,6 +1183,7 @@ {"__name__", (getter)wrapper_name}, {"__qualname__", (getter)wrapper_qualname}, {"__doc__", (getter)wrapper_doc}, + {"__text_signature__", (getter)wrapper_text_signature}, {0} }; diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1691,37 +1691,71 @@ return v; } +/*[clinic input] + at classmethod +dict.fromkeys + + iterable: object + value: object=None + / + +Returns a new dict with keys from iterable and values equal to value. +[clinic start generated code]*/ + +PyDoc_STRVAR(dict_fromkeys__doc__, +"fromkeys(type, iterable, value=None)\n" +"Returns a new dict with keys from iterable and values equal to value."); + +#define DICT_FROMKEYS_METHODDEF \ + {"fromkeys", (PyCFunction)dict_fromkeys, METH_VARARGS|METH_CLASS, dict_fromkeys__doc__}, + static PyObject * -dict_fromkeys(PyObject *cls, PyObject *args) +dict_fromkeys_impl(PyTypeObject *type, PyObject *iterable, PyObject *value); + +static PyObject * +dict_fromkeys(PyTypeObject *type, PyObject *args) { - PyObject *seq; + PyObject *return_value = NULL; + PyObject *iterable; PyObject *value = Py_None; + + if (!PyArg_UnpackTuple(args, "fromkeys", + 1, 2, + &iterable, &value)) + goto exit; + return_value = dict_fromkeys_impl(type, iterable, value); + +exit: + return return_value; +} + +static PyObject * +dict_fromkeys_impl(PyTypeObject *type, PyObject *iterable, PyObject *value) +/*[clinic end generated code: checksum=008269e1774a379b356841548c04061fd78a9542]*/ +{ PyObject *it; /* iter(seq) */ PyObject *key; PyObject *d; int status; - if (!PyArg_UnpackTuple(args, "fromkeys", 1, 2, &seq, &value)) - return NULL; - - d = PyObject_CallObject(cls, NULL); + d = PyObject_CallObject((PyObject *)type, NULL); if (d == NULL) return NULL; if (PyDict_CheckExact(d) && ((PyDictObject *)d)->ma_used == 0) { - if (PyDict_CheckExact(seq)) { + if (PyDict_CheckExact(iterable)) { PyDictObject *mp = (PyDictObject *)d; PyObject *oldvalue; Py_ssize_t pos = 0; PyObject *key; Py_hash_t hash; - if (dictresize(mp, Py_SIZE(seq))) { + if (dictresize(mp, Py_SIZE(iterable))) { Py_DECREF(d); return NULL; } - while (_PyDict_Next(seq, &pos, &key, &oldvalue, &hash)) { + while (_PyDict_Next(iterable, &pos, &key, &oldvalue, &hash)) { if (insertdict(mp, key, hash, value)) { Py_DECREF(d); return NULL; @@ -1729,18 +1763,18 @@ } return d; } - if (PyAnySet_CheckExact(seq)) { + if (PyAnySet_CheckExact(iterable)) { PyDictObject *mp = (PyDictObject *)d; Py_ssize_t pos = 0; PyObject *key; Py_hash_t hash; - if (dictresize(mp, PySet_GET_SIZE(seq))) { + if (dictresize(mp, PySet_GET_SIZE(iterable))) { Py_DECREF(d); return NULL; } - while (_PySet_NextEntry(seq, &pos, &key, &hash)) { + while (_PySet_NextEntry(iterable, &pos, &key, &hash)) { if (insertdict(mp, key, hash, value)) { Py_DECREF(d); return NULL; @@ -1750,7 +1784,7 @@ } } - it = PyObject_GetIter(seq); + it = PyObject_GetIter(iterable); if (it == NULL){ Py_DECREF(d); return NULL; @@ -2176,7 +2210,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(dict___contains____doc__, -"__contains__(key)\n" +"__contains__(self, key)\n" "True if D has a key k, else False."); #define DICT___CONTAINS___METHODDEF \ @@ -2184,7 +2218,7 @@ static PyObject * dict___contains__(PyObject *self, PyObject *key) -/*[clinic end generated code: checksum=402ddb624ba1e4db764bfdfbbee6c1c59d1a11fa]*/ +/*[clinic end generated code: checksum=c4f85a39baac4776c4275ad5f072f7732c5f0806]*/ { register PyDictObject *mp = (PyDictObject *)self; Py_hash_t hash; @@ -2496,10 +2530,6 @@ If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v\n\ In either case, this is followed by: for k in F: D[k] = F[k]"); -PyDoc_STRVAR(fromkeys__doc__, -"dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.\n\ -v defaults to None."); - PyDoc_STRVAR(clear__doc__, "D.clear() -> None. Remove all items from D."); @@ -2540,8 +2570,7 @@ values__doc__}, {"update", (PyCFunction)dict_update, METH_VARARGS | METH_KEYWORDS, update__doc__}, - {"fromkeys", (PyCFunction)dict_fromkeys, METH_VARARGS | METH_CLASS, - fromkeys__doc__}, + DICT_FROMKEYS_METHODDEF {"clear", (PyCFunction)dict_clear, METH_NOARGS, clear__doc__}, {"copy", (PyCFunction)dict_copy, METH_NOARGS, diff --git a/Objects/methodobject.c b/Objects/methodobject.c --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -179,75 +179,20 @@ {NULL, NULL} }; -/* - * finds the docstring's introspection signature. - * if present, returns a pointer pointing to the first '('. - * otherwise returns NULL. - */ -static const char *find_signature(PyCFunctionObject *m) -{ - const char *trace = m->m_ml->ml_doc; - const char *name = m->m_ml->ml_name; - size_t length; - if (!trace || !name) - return NULL; - length = strlen(name); - if (strncmp(trace, name, length)) - return NULL; - trace += length; - if (*trace != '(') - return NULL; - return trace; -} - -/* - * skips to the end of the docstring's instrospection signature. - */ -static const char *skip_signature(const char *trace) -{ - while (*trace && *trace != '\n') - trace++; - return trace; -} - -static const char *skip_eols(const char *trace) -{ - while (*trace == '\n') - trace++; - return trace; -} - static PyObject * meth_get__text_signature__(PyCFunctionObject *m, void *closure) { - const char *start = find_signature(m); - const char *trace; - - if (!start) { - Py_INCREF(Py_None); - return Py_None; - } - - trace = skip_signature(start); - return PyUnicode_FromStringAndSize(start, trace - start); + const char *name = m->m_ml->ml_name; + const char *doc = m->m_ml->ml_doc; + return _PyType_GetTextSignatureFromInternalDoc(name, doc); } static PyObject * meth_get__doc__(PyCFunctionObject *m, void *closure) { - const char *doc = find_signature(m); - - if (doc) - doc = skip_eols(skip_signature(doc)); - else - doc = m->m_ml->ml_doc; - - if (!doc) { - Py_INCREF(Py_None); - return Py_None; - } - - return PyUnicode_FromString(doc); + const char *name = m->m_ml->ml_name; + const char *doc = m->m_ml->ml_doc; + return _PyType_GetDocFromInternalDoc(name, doc); } static PyObject * diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -54,6 +54,83 @@ static PyObject * slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds); +/* + * finds the docstring's introspection signature. + * if present, returns a pointer pointing to the first '('. + * otherwise returns NULL. + */ +static const char * +find_signature(const char *name, const char *doc) +{ + size_t length; + if (!doc || !name) + return NULL; + length = strlen(name); + if (strncmp(doc, name, length)) + return NULL; + doc += length; + if (*doc != '(') + return NULL; + return doc; +} + +/* + * skips to the end of the docstring's instrospection signature. + */ +static const char * +skip_signature(const char *doc) +{ + while (*doc && *doc != '\n') + doc++; + return doc; +} + +static const char * +skip_eols(const char *trace) +{ + while (*trace == '\n') + trace++; + return trace; +} + +static const char * +_PyType_DocWithoutSignature(const char *name, const char *internal_doc) +{ + const char *signature = find_signature(name, internal_doc); + + if (signature) + return skip_eols(skip_signature(signature)); + return internal_doc; +} + +PyObject * +_PyType_GetDocFromInternalDoc(const char *name, const char *internal_doc) +{ + const char *doc = _PyType_DocWithoutSignature(name, internal_doc); + + if (!doc) { + Py_INCREF(Py_None); + return Py_None; + } + + return PyUnicode_FromString(doc); +} + +PyObject * +_PyType_GetTextSignatureFromInternalDoc(const char *name, const char *internal_doc) +{ + const char *signature = find_signature(name, internal_doc); + const char *doc; + + if (!signature) { + Py_INCREF(Py_None); + return Py_None; + } + + doc = skip_signature(signature); + return PyUnicode_FromStringAndSize(signature, doc - signature); +} + unsigned int PyType_ClearCache(void) { @@ -628,8 +705,11 @@ type_get_doc(PyTypeObject *type, void *context) { PyObject *result; - if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE) && type->tp_doc != NULL) - return PyUnicode_FromString(type->tp_doc); + if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE) && type->tp_doc != NULL) { + const char *name = type->tp_name; + const char *doc = type->tp_doc; + return _PyType_GetDocFromInternalDoc(name, doc); + } result = _PyDict_GetItemId(type->tp_dict, &PyId___doc__); if (result == NULL) { result = Py_None; @@ -645,6 +725,14 @@ return result; } +static PyObject * +type_get_text_signature(PyTypeObject *type, void *context) +{ + const char *name = type->tp_name; + const char *doc = type->tp_doc; + return _PyType_GetTextSignatureFromInternalDoc(name, doc); +} + static int type_set_doc(PyTypeObject *type, PyObject *value, void *context) { @@ -691,6 +779,7 @@ (setter)type_set_abstractmethods, NULL}, {"__dict__", (getter)type_dict, NULL, NULL}, {"__doc__", (getter)type_get_doc, (setter)type_set_doc, NULL}, + {"__text_signature__", (getter)type_get_text_signature, NULL, NULL}, {0} }; @@ -2519,13 +2608,14 @@ /* need to make a copy of the docstring slot, which usually points to a static string literal */ if (slot->slot == Py_tp_doc) { - size_t len = strlen(slot->pfunc)+1; + const char *old_doc = _PyType_DocWithoutSignature(spec->name, slot->pfunc); + size_t len = strlen(old_doc)+1; char *tp_doc = PyObject_MALLOC(len); if (tp_doc == NULL) { PyErr_NoMemory(); goto fail; } - memcpy(tp_doc, slot->pfunc, len); + memcpy(tp_doc, old_doc, len); type->tp_doc = tp_doc; } } @@ -2909,6 +2999,8 @@ }; PyDoc_STRVAR(type_doc, +/* this text signature cannot be accurate yet. will fix. --larry */ +"type(object_or_name, bases, dict)\n" "type(object) -> the object's type\n" "type(name, bases, dict) -> a new type"); @@ -3480,7 +3572,7 @@ { PyObject **dict; dict = _PyObject_GetDictPtr(obj); - /* It is possible that the object's dict is not initialized + /* It is possible that the object's dict is not initialized yet. In this case, we will return None for the state. We also return None if the dict is empty to make the behavior consistent regardless whether the dict was initialized or not. @@ -3788,7 +3880,7 @@ Py_DECREF(state); Py_DECREF(listitems); Py_DECREF(dictitems); - return result; + return result; } static PyObject * @@ -3813,7 +3905,7 @@ } else if (kwargs != NULL) { if (PyDict_Size(kwargs) > 0) { - PyErr_SetString(PyExc_ValueError, + PyErr_SetString(PyExc_ValueError, "must use protocol 4 or greater to copy this " "object; since __getnewargs_ex__ returned " "keyword arguments."); @@ -4103,8 +4195,8 @@ PyObject_GenericGetAttr, /* tp_getattro */ PyObject_GenericSetAttr, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - PyDoc_STR("The most base type"), /* tp_doc */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + PyDoc_STR("object()\nThe most base type"), /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ object_richcompare, /* tp_richcompare */ @@ -4571,7 +4663,8 @@ */ if (_PyDict_GetItemId(type->tp_dict, &PyId___doc__) == NULL) { if (type->tp_doc != NULL) { - PyObject *doc = PyUnicode_FromString(type->tp_doc); + const char *old_doc = _PyType_DocWithoutSignature(type->tp_name, type->tp_doc); + PyObject *doc = PyUnicode_FromString(old_doc); if (doc == NULL) goto error; if (_PyDict_SetItemId(type->tp_dict, &PyId___doc__, doc) < 0) { @@ -6005,22 +6098,22 @@ ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, DOC) #define UNSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, \ - "x." NAME "() <==> " DOC) + NAME "(self)\n" DOC) #define IBSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, \ - "x." NAME "(y) <==> x" DOC "y") + NAME "(self, value)\nReturns self" DOC "value.") #define BINSLOT(NAME, SLOT, FUNCTION, DOC) \ ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_l, \ - "x." NAME "(y) <==> x" DOC "y") + NAME "(self, value)\nReturns self" DOC "value.") #define RBINSLOT(NAME, SLOT, FUNCTION, DOC) \ ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r, \ - "x." NAME "(y) <==> y" DOC "x") + NAME "(self, value)\nReturns value" DOC "self.") #define BINSLOTNOTINFIX(NAME, SLOT, FUNCTION, DOC) \ ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_l, \ - "x." NAME "(y) <==> " DOC) + NAME "(self, value)\n" DOC) #define RBINSLOTNOTINFIX(NAME, SLOT, FUNCTION, DOC) \ ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r, \ - "x." NAME "(y) <==> " DOC) + NAME "(self, value)\n" DOC) static slotdef slotdefs[] = { TPSLOT("__getattribute__", tp_getattr, NULL, NULL, ""), @@ -6028,80 +6121,85 @@ TPSLOT("__setattr__", tp_setattr, NULL, NULL, ""), TPSLOT("__delattr__", tp_setattr, NULL, NULL, ""), TPSLOT("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc, - "x.__repr__() <==> repr(x)"), + "__repr__(self)\nReturns repr(self)."), TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc, - "x.__hash__() <==> hash(x)"), + "__hash__(self)\nReturns hash(self)."), FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call, - "x.__call__(...) <==> x(...)", PyWrapperFlag_KEYWORDS), + "__call__(self, *args, **kwargs)\nCalls self as a function.", + PyWrapperFlag_KEYWORDS), TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc, - "x.__str__() <==> str(x)"), + "__str__(self)\nReturns str(self)."), TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook, - wrap_binaryfunc, "x.__getattribute__('name') <==> x.name"), + wrap_binaryfunc, + "__getattribute__(self, name)\nReturns getattr(self, name)."), TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL, ""), TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr, - "x.__setattr__('name', value) <==> x.name = value"), + "__setattr__(self, name, value)\nImplements setattr(self, name, value)."), TPSLOT("__delattr__", tp_setattro, slot_tp_setattro, wrap_delattr, - "x.__delattr__('name') <==> del x.name"), + "__delattr__(self, name)\nImplements delattr(self, name)."), TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare, richcmp_lt, - "x.__lt__(y) <==> x x<=y"), + "__le__(self, value)\nReturns self<=value."), TPSLOT("__eq__", tp_richcompare, slot_tp_richcompare, richcmp_eq, - "x.__eq__(y) <==> x==y"), + "__eq__(self, value)\nReturns self==value."), TPSLOT("__ne__", tp_richcompare, slot_tp_richcompare, richcmp_ne, - "x.__ne__(y) <==> x!=y"), + "__ne__(self, value)\nReturns self!=value."), TPSLOT("__gt__", tp_richcompare, slot_tp_richcompare, richcmp_gt, - "x.__gt__(y) <==> x>y"), + "__gt__(self, value)\nReturns self>value."), TPSLOT("__ge__", tp_richcompare, slot_tp_richcompare, richcmp_ge, - "x.__ge__(y) <==> x>=y"), + "__ge__(self, value)\nReturns self>=value."), TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc, - "x.__iter__() <==> iter(x)"), + "__iter__(self)\nImplements iter(self)."), TPSLOT("__next__", tp_iternext, slot_tp_iternext, wrap_next, - "x.__next__() <==> next(x)"), + "__next__(self)\nImplements next(self)."), TPSLOT("__get__", tp_descr_get, slot_tp_descr_get, wrap_descr_get, - "descr.__get__(obj[, type]) -> value"), + "__get__(self, instance, owner)\nCalled to get an attribute of instance, which is of type owner."), TPSLOT("__set__", tp_descr_set, slot_tp_descr_set, wrap_descr_set, - "descr.__set__(obj, value)"), + "__set__(self, instance, value)\nSets an attribute of instance to value."), TPSLOT("__delete__", tp_descr_set, slot_tp_descr_set, - wrap_descr_delete, "descr.__delete__(obj)"), + wrap_descr_delete, + "__delete__(instance)\nDeletes an attribute of instance."), FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)wrap_init, - "x.__init__(...) initializes x; " - "see help(type(x)) for signature", + "__init__(self, *args, **kwargs)\n" + "Initializes self. See help(type(self)) for accurate signature.", PyWrapperFlag_KEYWORDS), - TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""), + TPSLOT("__new__", tp_new, slot_tp_new, NULL, + "__new__(cls, *args, **kwargs)\n" + "Creates new object. See help(cls) for accurate signature."), TPSLOT("__del__", tp_finalize, slot_tp_finalize, (wrapperfunc)wrap_del, ""), BINSLOT("__add__", nb_add, slot_nb_add, - "+"), + "+"), RBINSLOT("__radd__", nb_add, slot_nb_add, - "+"), + "+"), BINSLOT("__sub__", nb_subtract, slot_nb_subtract, - "-"), + "-"), RBINSLOT("__rsub__", nb_subtract, slot_nb_subtract, - "-"), + "-"), BINSLOT("__mul__", nb_multiply, slot_nb_multiply, - "*"), + "*"), RBINSLOT("__rmul__", nb_multiply, slot_nb_multiply, - "*"), + "*"), BINSLOT("__mod__", nb_remainder, slot_nb_remainder, - "%"), + "%"), RBINSLOT("__rmod__", nb_remainder, slot_nb_remainder, - "%"), + "%"), BINSLOTNOTINFIX("__divmod__", nb_divmod, slot_nb_divmod, - "divmod(x, y)"), + "__divmod__(self, value)\nReturns divmod(self, value)."), RBINSLOTNOTINFIX("__rdivmod__", nb_divmod, slot_nb_divmod, - "divmod(y, x)"), + "__rdivmod__(self, value)\nReturns divmod(value, self)."), NBSLOT("__pow__", nb_power, slot_nb_power, wrap_ternaryfunc, - "x.__pow__(y[, z]) <==> pow(x, y[, z])"), + "__pow__(self, value, mod=None)\nReturns pow(self, value, mod)."), NBSLOT("__rpow__", nb_power, slot_nb_power, wrap_ternaryfunc_r, - "y.__rpow__(x[, z]) <==> pow(x, y[, z])"), - UNSLOT("__neg__", nb_negative, slot_nb_negative, wrap_unaryfunc, "-x"), - UNSLOT("__pos__", nb_positive, slot_nb_positive, wrap_unaryfunc, "+x"), + "__rpow__(self, value, mod=None)\nReturns pow(value, self, mod)."), + UNSLOT("__neg__", nb_negative, slot_nb_negative, wrap_unaryfunc, "-self"), + UNSLOT("__pos__", nb_positive, slot_nb_positive, wrap_unaryfunc, "+self"), UNSLOT("__abs__", nb_absolute, slot_nb_absolute, wrap_unaryfunc, - "abs(x)"), + "abs(self)"), UNSLOT("__bool__", nb_bool, slot_nb_bool, wrap_inquirypred, - "x != 0"), - UNSLOT("__invert__", nb_invert, slot_nb_invert, wrap_unaryfunc, "~x"), + "self != 0"), + UNSLOT("__invert__", nb_invert, slot_nb_invert, wrap_unaryfunc, "~self"), BINSLOT("__lshift__", nb_lshift, slot_nb_lshift, "<<"), RBINSLOT("__rlshift__", nb_lshift, slot_nb_lshift, "<<"), BINSLOT("__rshift__", nb_rshift, slot_nb_rshift, ">>"), @@ -6113,9 +6211,9 @@ BINSLOT("__or__", nb_or, slot_nb_or, "|"), RBINSLOT("__ror__", nb_or, slot_nb_or, "|"), UNSLOT("__int__", nb_int, slot_nb_int, wrap_unaryfunc, - "int(x)"), + "int(self)"), UNSLOT("__float__", nb_float, slot_nb_float, wrap_unaryfunc, - "float(x)"), + "float(self)"), IBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add, wrap_binaryfunc, "+="), IBSLOT("__isub__", nb_inplace_subtract, slot_nb_inplace_subtract, @@ -6145,45 +6243,48 @@ IBSLOT("__itruediv__", nb_inplace_true_divide, slot_nb_inplace_true_divide, wrap_binaryfunc, "/"), NBSLOT("__index__", nb_index, slot_nb_index, wrap_unaryfunc, - "x[y:z] <==> x[y.__index__():z.__index__()]"), - + "__index__(self)\n" + "Returns self converted to an integer, if self is suitable" + "for use as an index into a list."), MPSLOT("__len__", mp_length, slot_mp_length, wrap_lenfunc, - "x.__len__() <==> len(x)"), + "__len__(self)\nReturns len(self)."), MPSLOT("__getitem__", mp_subscript, slot_mp_subscript, wrap_binaryfunc, - "x.__getitem__(y) <==> x[y]"), + "__getitem__(self, key)\nReturns self[key]."), MPSLOT("__setitem__", mp_ass_subscript, slot_mp_ass_subscript, wrap_objobjargproc, - "x.__setitem__(i, y) <==> x[i]=y"), + "__setitem__(self, key, value)\nSets self[key] to value."), MPSLOT("__delitem__", mp_ass_subscript, slot_mp_ass_subscript, wrap_delitem, - "x.__delitem__(y) <==> del x[y]"), + "__delitem__(key)\nDeletes self[key]."), SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc, - "x.__len__() <==> len(x)"), + "__len__(self)\nReturns len(self)."), /* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL. The logic in abstract.c always falls back to nb_add/nb_multiply in this case. Defining both the nb_* and the sq_* slots to call the user-defined methods has unexpected side-effects, as shown by test_descr.notimplemented() */ SQSLOT("__add__", sq_concat, NULL, wrap_binaryfunc, - "x.__add__(y) <==> x+y"), + "__add__(self, value)\nReturns self+value."), SQSLOT("__mul__", sq_repeat, NULL, wrap_indexargfunc, - "x.__mul__(n) <==> x*n"), + "__mul__(self, value)\nReturns self*value.n"), SQSLOT("__rmul__", sq_repeat, NULL, wrap_indexargfunc, - "x.__rmul__(n) <==> n*x"), + "__rmul__(self, value)\nReturns self*value."), SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item, - "x.__getitem__(y) <==> x[y]"), + "__getitem__(self, key)\nReturns self[key]."), SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_setitem, - "x.__setitem__(i, y) <==> x[i]=y"), + "__setitem__(self, key, value)\nSets self[key] to value."), SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_delitem, - "x.__delitem__(y) <==> del x[y]"), + "__delitem__(self, key)\nDeletes self[key]."), SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc, - "x.__contains__(y) <==> y in x"), + "__contains__(self, key)\nReturns key in self."), SQSLOT("__iadd__", sq_inplace_concat, NULL, - wrap_binaryfunc, "x.__iadd__(y) <==> x+=y"), + wrap_binaryfunc, + "__iadd__(self, value)\nImplements self+=value."), SQSLOT("__imul__", sq_inplace_repeat, NULL, - wrap_indexargfunc, "x.__imul__(y) <==> x*=y"), + wrap_indexargfunc, + "__imul__(self, value)\nImplements self*=value."), {NULL} }; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -12900,7 +12900,7 @@ {"maketrans", (PyCFunction)unicode_maketrans, METH_VARARGS|METH_STATIC, unicode_maketrans__doc__}, static PyObject * -unicode_maketrans_impl(void *null, PyObject *x, PyObject *y, PyObject *z); +unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z); static PyObject * unicode_maketrans(void *null, PyObject *args) @@ -12914,15 +12914,15 @@ "O|UU:maketrans", &x, &y, &z)) goto exit; - return_value = unicode_maketrans_impl(null, x, y, z); + return_value = unicode_maketrans_impl(x, y, z); exit: return return_value; } static PyObject * -unicode_maketrans_impl(void *null, PyObject *x, PyObject *y, PyObject *z) -/*[clinic end generated code: checksum=7f76f414a0dfd0c614e0d4717872eeb520516da7]*/ +unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z) +/*[clinic end generated code: checksum=90a3de8c494b304687e1e0d7e5fa8ba78eac6533]*/ { PyObject *new = NULL, *key, *value; Py_ssize_t i = 0; diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -1325,7 +1325,7 @@ } PyDoc_STRVAR(len_doc, -"len(object) -> integer\n\ +"len(module, object)\n\ \n\ Return the number of items of a sequence or mapping."); diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -232,7 +232,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_lock_held__doc__, -"lock_held()\n" +"lock_held(module)\n" "Return True if the import lock is currently held, else False.\n" "\n" "On platforms without threads, return False."); @@ -251,7 +251,7 @@ static PyObject * _imp_lock_held_impl(PyModuleDef *module) -/*[clinic end generated code: checksum=ede1cafb78eb22e3009602f684c8b780e2b82d62]*/ +/*[clinic end generated code: checksum=17172a9917d389dd1564e2108fec34d23aecb6c2]*/ { #ifdef WITH_THREAD return PyBool_FromLong(import_lock_thread != -1); @@ -270,7 +270,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_acquire_lock__doc__, -"acquire_lock()\n" +"acquire_lock(module)\n" "Acquires the interpreter\'s import lock for the current thread.\n" "\n" "This lock should be used by import hooks to ensure thread-safety when importing\n" @@ -290,7 +290,7 @@ static PyObject * _imp_acquire_lock_impl(PyModuleDef *module) -/*[clinic end generated code: checksum=5b520b2416c5954a7cf0ed30955d68abe20b5868]*/ +/*[clinic end generated code: checksum=20db30e18f6b8758386fe06907edb3f8e43080d7]*/ { #ifdef WITH_THREAD _PyImport_AcquireLock(); @@ -308,7 +308,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_release_lock__doc__, -"release_lock()\n" +"release_lock(module)\n" "Release the interpreter\'s import lock.\n" "\n" "On platforms without threads, this function does nothing."); @@ -327,7 +327,7 @@ static PyObject * _imp_release_lock_impl(PyModuleDef *module) -/*[clinic end generated code: checksum=efcd9d2923294c04371596e7f6d66a706d43fcac]*/ +/*[clinic end generated code: checksum=17749fd7752d2c392447a1f83c5d371f54d7ebd3]*/ { #ifdef WITH_THREAD if (_PyImport_ReleaseLock() < 0) { @@ -927,7 +927,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp__fix_co_filename__doc__, -"_fix_co_filename(code, path)\n" +"_fix_co_filename(module, code, path)\n" "Changes code.co_filename to specify the passed-in file path.\n" "\n" " code\n" @@ -960,7 +960,7 @@ static PyObject * _imp__fix_co_filename_impl(PyModuleDef *module, PyCodeObject *code, PyObject *path) -/*[clinic end generated code: checksum=4f55bad308072b30ad1921068fc4ce85bd2b39bf]*/ +/*[clinic end generated code: checksum=d32cf2b2e0480c714f909921cc9e55d763b39dd5]*/ { update_compiled_module(code, path); @@ -1823,7 +1823,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_extension_suffixes__doc__, -"extension_suffixes()\n" +"extension_suffixes(module)\n" "Returns the list of file suffixes used to identify extension modules."); #define _IMP_EXTENSION_SUFFIXES_METHODDEF \ @@ -1840,7 +1840,7 @@ static PyObject * _imp_extension_suffixes_impl(PyModuleDef *module) -/*[clinic end generated code: checksum=82fb35d8429a429a4dc80c84b45b1aad73ff1de7]*/ +/*[clinic end generated code: checksum=625c8f11a5bbd4b85373f0a54f7f3ef19c55beb4]*/ { PyObject *list; const char *suffix; @@ -1878,7 +1878,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_init_builtin__doc__, -"init_builtin(name)\n" +"init_builtin(module, name)\n" "Initializes a built-in module."); #define _IMP_INIT_BUILTIN_METHODDEF \ @@ -1905,7 +1905,7 @@ static PyObject * _imp_init_builtin_impl(PyModuleDef *module, PyObject *name) -/*[clinic end generated code: checksum=59239206e5b2fb59358066e72fd0e72e55a7baf5]*/ +/*[clinic end generated code: checksum=a4e4805a523757cd3ddfeec6e5b16740678fed6a]*/ { int ret; PyObject *m; @@ -1932,7 +1932,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_init_frozen__doc__, -"init_frozen(name)\n" +"init_frozen(module, name)\n" "Initializes a frozen module."); #define _IMP_INIT_FROZEN_METHODDEF \ @@ -1959,7 +1959,7 @@ static PyObject * _imp_init_frozen_impl(PyModuleDef *module, PyObject *name) -/*[clinic end generated code: checksum=503fcc3de9961263e4d9484259af357a7d287a0b]*/ +/*[clinic end generated code: checksum=2a58c119dd3e121cf5a9924f936cfd7b40253c12]*/ { int ret; PyObject *m; @@ -1986,7 +1986,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_get_frozen_object__doc__, -"get_frozen_object(name)\n" +"get_frozen_object(module, name)\n" "Create a code object for a frozen module."); #define _IMP_GET_FROZEN_OBJECT_METHODDEF \ @@ -2013,7 +2013,7 @@ static PyObject * _imp_get_frozen_object_impl(PyModuleDef *module, PyObject *name) -/*[clinic end generated code: checksum=7a6423a4daf139496b9a394ff3ac6130089d1cba]*/ +/*[clinic end generated code: checksum=94c9108b58dda80d187fef21275a009bd0f91e96]*/ { return get_frozen_object(name); } @@ -2028,7 +2028,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_is_frozen_package__doc__, -"is_frozen_package(name)\n" +"is_frozen_package(module, name)\n" "Returns True if the module name is of a frozen package."); #define _IMP_IS_FROZEN_PACKAGE_METHODDEF \ @@ -2055,7 +2055,7 @@ static PyObject * _imp_is_frozen_package_impl(PyModuleDef *module, PyObject *name) -/*[clinic end generated code: checksum=dc7e361ea30b6945b8bbe7266d7b9a5ea433b510]*/ +/*[clinic end generated code: checksum=17a342b94dbe859cdfc361bc8a6bc1b3cb163364]*/ { return is_frozen_package(name); } @@ -2070,7 +2070,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_is_builtin__doc__, -"is_builtin(name)\n" +"is_builtin(module, name)\n" "Returns True if the module name corresponds to a built-in module."); #define _IMP_IS_BUILTIN_METHODDEF \ @@ -2097,7 +2097,7 @@ static PyObject * _imp_is_builtin_impl(PyModuleDef *module, PyObject *name) -/*[clinic end generated code: checksum=353938c1d55210a1e3850d3ccba7539d02165cac]*/ +/*[clinic end generated code: checksum=51c6139dcfd9bee1f40980ea68b7797f8489d69a]*/ { return PyLong_FromLong(is_builtin(name)); } @@ -2112,7 +2112,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_is_frozen__doc__, -"is_frozen(name)\n" +"is_frozen(module, name)\n" "Returns True if the module name corresponds to a frozen module."); #define _IMP_IS_FROZEN_METHODDEF \ @@ -2139,7 +2139,7 @@ static PyObject * _imp_is_frozen_impl(PyModuleDef *module, PyObject *name) -/*[clinic end generated code: checksum=978b547ddcb76fa6c4a181ad53569c9acf382c7b]*/ +/*[clinic end generated code: checksum=4b079fb45a495835056ea5604735d552d222be5c]*/ { const struct _frozen *p; @@ -2161,7 +2161,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_load_dynamic__doc__, -"load_dynamic(name, path, file=None)\n" +"load_dynamic(module, name, path, file=None)\n" "Loads an extension module."); #define _IMP_LOAD_DYNAMIC_METHODDEF \ @@ -2190,7 +2190,7 @@ static PyObject * _imp_load_dynamic_impl(PyModuleDef *module, PyObject *name, PyObject *path, PyObject *file) -/*[clinic end generated code: checksum=6795f65d9ce003ccaf08e4e8eef484dc52e262d0]*/ +/*[clinic end generated code: checksum=63e051fd0d0350c785bf185be41b0892f9920622]*/ { PyObject *mod; FILE *fp; diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -139,9 +139,9 @@ # so if they're used Argument Clinic will add "_value" to the end # of the name in C. c_keywords = set(""" -asm auto break case char cls const continue default do double -else enum extern float for goto if inline int long module null -register return self short signed sizeof static struct switch +asm auto break case char const continue default do double +else enum extern float for goto if inline int long +register return short signed sizeof static struct switch typedef typeof union unsigned void volatile while """.strip().split()) @@ -635,6 +635,9 @@ def output_templates(self, f): parameters = list(f.parameters.values()) + assert parameters + assert isinstance(parameters[0].converter, self_converter) + del parameters[0] converters = [p.converter for p in parameters] has_option_groups = parameters and (parameters[0].group or parameters[-1].group) @@ -679,8 +682,11 @@ return_value_declaration = "PyObject *return_value = NULL;" methoddef_define = templates['methoddef_define'] - docstring_prototype = templates['docstring_prototype'] - docstring_definition = templates['docstring_definition'] + if new_or_init and not f.docstring: + docstring_prototype = docstring_definition = '' + else: + docstring_prototype = templates['docstring_prototype'] + docstring_definition = templates['docstring_definition'] impl_definition = templates['impl_definition'] impl_prototype = parser_prototype = parser_definition = None @@ -858,6 +864,8 @@ add, output = text_accumulator() parameters = list(f.parameters.values()) + if isinstance(parameters[0].converter, self_converter): + del parameters[0] groups = [] group = None @@ -936,14 +944,69 @@ data = CRenderData() parameters = list(f.parameters.values()) + assert parameters, "We should always have a 'self' at this point!" + converters = [p.converter for p in parameters] + templates = self.output_templates(f) + + f_self = parameters[0] + selfless = parameters[1:] + assert isinstance(f_self.converter, self_converter), "No self parameter in " + repr(f.full_name) + "!" + + last_group = 0 + first_optional = len(selfless) + positional = selfless and selfless[-1].kind == inspect.Parameter.POSITIONAL_ONLY + new_or_init = f.kind in (METHOD_NEW, METHOD_INIT) + default_return_converter = (not f.return_converter or + f.return_converter.type == 'PyObject *') + has_option_groups = False + + # offset i by -1 because first_optional needs to ignore self + for i, p in enumerate(parameters, -1): + c = p.converter + + if (i != -1) and (p.default is not unspecified): + first_optional = min(first_optional, i) + + # insert group variable + group = p.group + if last_group != group: + last_group = group + if group: + group_name = self.group_to_variable_name(group) + data.impl_arguments.append(group_name) + data.declarations.append("int " + group_name + " = 0;") + data.impl_parameters.append("int " + group_name) + has_option_groups = True + + c.render(p, data) + + if has_option_groups and (not positional): + fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').") + + # HACK + # when we're METH_O, but have a custom return converter, + # we use "impl_parameters" for the parsing function + # because that works better. but that means we must + # supress actually declaring the impl's parameters + # as variables in the parsing function. but since it's + # METH_O, we have exactly one anyway, so we know exactly + # where it is. + if ("METH_O" in templates['methoddef_define'] and + not default_return_converter): + data.declarations.pop(0) + template_dict = {} full_name = f.full_name template_dict['full_name'] = full_name - name = full_name.rpartition('.')[2] + if new_or_init: + name = f.cls.name + else: + name = f.name + template_dict['name'] = name if f.c_basename: @@ -953,6 +1016,7 @@ if fields[-1] == '__new__': fields.pop() c_basename = "_".join(fields) + template_dict['c_basename'] = c_basename methoddef_name = "{}_METHODDEF".format(c_basename.upper()) @@ -960,67 +1024,7 @@ template_dict['docstring'] = self.docstring_for_c_string(f) - positional = has_option_groups = False - - first_optional = len(parameters) - - if parameters: - last_group = 0 - - for i, p in enumerate(parameters): - c = p.converter - - if p.default is not unspecified: - first_optional = min(first_optional, i) - - # insert group variable - group = p.group - if last_group != group: - last_group = group - if group: - group_name = self.group_to_variable_name(group) - data.impl_arguments.append(group_name) - data.declarations.append("int " + group_name + " = 0;") - data.impl_parameters.append("int " + group_name) - has_option_groups = True - c.render(p, data) - - positional = parameters[-1].kind == inspect.Parameter.POSITIONAL_ONLY - if has_option_groups and (not positional): - fail("You cannot use optional groups ('[' and ']')\nunless all parameters are positional-only ('/').") - - # HACK - # when we're METH_O, but have a custom - # return converter, we use - # "impl_parameters" for the parsing - # function because that works better. - # but that means we must supress actually - # declaring the impl's parameters as variables - # in the parsing function. but since it's - # METH_O, we only have one anyway, so we don't - # have any problem finding it. - default_return_converter = (not f.return_converter or - f.return_converter.type == 'PyObject *') - if (len(parameters) == 1 and - parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY and - not converters[0].is_optional() and - isinstance(converters[0], object_converter) and - converters[0].format_unit == 'O' and - not default_return_converter): - - data.declarations.pop(0) - - # now insert our "self" (or whatever) parameters - # (we deliberately don't call render on self converters) - stock_self = self_converter('self', f) - template_dict['self_name'] = stock_self.name - template_dict['self_type'] = stock_self.type - data.impl_parameters.insert(0, f.self_converter.type + ("" if f.self_converter.type.endswith('*') else " ") + f.self_converter.name) - if f.self_converter.type != stock_self.type: - self_cast = '(' + f.self_converter.type + ')' - else: - self_cast = '' - data.impl_arguments.insert(0, self_cast + stock_self.name) + f_self.converter.set_template_dict(template_dict) f.return_converter.render(f, data) template_dict['impl_return_type'] = f.return_converter.type @@ -1036,15 +1040,16 @@ template_dict['cleanup'] = "".join(data.cleanup) template_dict['return_value'] = data.return_value - # used by unpack tuple - template_dict['unpack_min'] = str(first_optional) - template_dict['unpack_max'] = str(len(parameters)) + # used by unpack tuple code generator + ignore_self = -1 if isinstance(converters[0], self_converter) else 0 + unpack_min = first_optional + unpack_max = len(selfless) + template_dict['unpack_min'] = str(unpack_min) + template_dict['unpack_max'] = str(unpack_max) if has_option_groups: self.render_option_group_parsing(f, template_dict) - templates = self.output_templates(f) - for name, destination in clinic.field_destinations.items(): template = templates[name] if has_option_groups: @@ -1077,6 +1082,7 @@ + @contextlib.contextmanager def OverrideStdioWith(stdout): saved_stdout = sys.stdout @@ -1775,7 +1781,9 @@ """.strip().split()) -INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = range(6) +INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = """ +INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW +""".replace(",", "").strip().split() class Function: """ @@ -1969,6 +1977,19 @@ # Only used by format units ending with '#'. length = False + # Should we show this parameter in the generated + # __text_signature__? This is *almost* always True. + show_in_signature = True + + # Overrides the name used in a text signature. + # The name used for a "self" parameter must be one of + # self, type, or module; however users can set their own. + # This lets the self_converter overrule the user-settable + # name, *just* for the text signature. + # Only set by self_converter. + signature_name = None + + # keep in sync with self_converter.__init__! def __init__(self, name, function, default=unspecified, *, c_default=None, py_default=None, annotation=unspecified, **kwargs): self.function = function self.name = name @@ -1998,30 +2019,36 @@ def is_optional(self): return (self.default is not unspecified) - def render(self, parameter, data): - """ - parameter is a clinic.Parameter instance. - data is a CRenderData instance. - """ + def _render_self(self, parameter, data): self.parameter = parameter original_name = self.name name = ensure_legal_c_identifier(original_name) - # declarations - d = self.declaration() - data.declarations.append(d) - - # initializers - initializers = self.initialize() - if initializers: - data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip()) - # impl_arguments s = ("&" if self.impl_by_reference else "") + name data.impl_arguments.append(s) if self.length: data.impl_arguments.append(self.length_name()) + # impl_parameters + data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference)) + if self.length: + data.impl_parameters.append("Py_ssize_clean_t " + self.length_name()) + + def _render_non_self(self, parameter, data): + self.parameter = parameter + original_name = self.name + name = ensure_legal_c_identifier(original_name) + + # declarations + d = self.declaration() + data.declarations.append(d) + + # initializers + initializers = self.initialize() + if initializers: + data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip()) + # keywords data.keywords.append(original_name) @@ -2035,16 +2062,19 @@ # parse_arguments self.parse_argument(data.parse_arguments) - # impl_parameters - data.impl_parameters.append(self.simple_declaration(by_reference=self.impl_by_reference)) - if self.length: - data.impl_parameters.append("Py_ssize_clean_t " + self.length_name()) - # cleanup cleanup = self.cleanup() if cleanup: data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n") + def render(self, parameter, data): + """ + parameter is a clinic.Parameter instance. + data is a CRenderData instance. + """ + self._render_self(parameter, data) + self._render_non_self(parameter, data) + def length_name(self): """Computes the name of the associated "length" variable.""" if not self.length: @@ -2318,7 +2348,7 @@ format_unit = 'et#' if format_unit.endswith('#'): - print("Warning: code using format unit ", repr(format_unit), "probably doesn't work properly.") + fail("Sorry: code using format unit ", repr(format_unit), "probably doesn't work properly yet.\nGive Larry your test case and he'll it.") # TODO set pointer to NULL # TODO add cleanup for buffer pass @@ -2421,35 +2451,108 @@ return "".join(["if (", name, ".obj)\n PyBuffer_Release(&", name, ");\n"]) +def correct_name_for_self(f): + if f.kind in (CALLABLE, METHOD_INIT): + if f.cls: + return "PyObject *", "self" + return "PyModuleDef *", "module" + if f.kind == STATIC_METHOD: + return "void *", "null" + if f.kind in (CLASS_METHOD, METHOD_NEW): + return "PyTypeObject *", "type" + raise RuntimeError("Unhandled type of function f: " + repr(f.kind)) + + class self_converter(CConverter): """ A special-case converter: this is the default converter used for "self". """ - type = "PyObject *" + type = None + format_unit = '' + + def converter_init(self, *, type=None): f = self.function - if f.kind in (CALLABLE, METHOD_INIT): - if f.cls: - self.name = "self" - else: - self.name = "module" - self.type = "PyModuleDef *" - elif f.kind == STATIC_METHOD: - self.name = "null" - self.type = "void *" - elif f.kind == CLASS_METHOD: - self.name = "cls" - self.type = "PyTypeObject *" - elif f.kind == METHOD_NEW: - self.name = "type" - self.type = "PyTypeObject *" - - if type: - self.type = type + default_type, default_name = correct_name_for_self(f) + self.signature_name = default_name + self.type = type or self.type or default_type + + kind = self.function.kind + new_or_init = kind in (METHOD_NEW, METHOD_INIT) + + if (kind == STATIC_METHOD) or new_or_init: + self.show_in_signature = False + + # tp_new (METHOD_NEW) functions are of type newfunc: + # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *); + # PyTypeObject is a typedef for struct _typeobject. + # + # tp_init (METHOD_INIT) functions are of type initproc: + # typedef int (*initproc)(PyObject *, PyObject *, PyObject *); + # + # All other functions generated by Argument Clinic are stored in + # PyMethodDef structures, in the ml_meth slot, which is of type PyCFunction: + # typedef PyObject *(*PyCFunction)(PyObject *, PyObject *); + # However! We habitually cast these functions to PyCFunction, + # since functions that accept keyword arguments don't fit this signature + # but are stored there anyway. So strict type equality isn't important + # for these functions. + # + # So: + # + # * The name of the first parameter to the impl and the parsing function will always + # be self.name. + # + # * The type of the first parameter to the impl will always be of self.type. + # + # * If the function is neither tp_new (METHOD_NEW) nor tp_init (METHOD_INIT): + # * The type of the first parameter to the parsing function is also self.type. + # This means that if you step into the parsing function, your "self" parameter + # is of the correct type, which may make debugging more pleasant. + # + # * Else if the function is tp_new (METHOD_NEW): + # * The type of the first parameter to the parsing function is "PyTypeObject *", + # so the type signature of the function call is an exact match. + # * If self.type != "PyTypeObject *", we cast the first parameter to self.type + # in the impl call. + # + # * Else if the function is tp_init (METHOD_INIT): + # * The type of the first parameter to the parsing function is "PyObject *", + # so the type signature of the function call is an exact match. + # * If self.type != "PyObject *", we cast the first parameter to self.type + # in the impl call. + + @property + def parser_type(self): + kind = self.function.kind + if kind == METHOD_NEW: + return "PyTypeObject *" + if kind == METHOD_INIT: + return "PyObject *" + return self.type def render(self, parameter, data): - fail("render() should never be called on self_converter instances") + """ + parameter is a clinic.Parameter instance. + data is a CRenderData instance. + """ + if self.function.kind == STATIC_METHOD: + return + + self._render_self(parameter, data) + + if self.type != self.parser_type: + # insert cast to impl_argument[0], aka self. + # we know we're in the first slot in all the CRenderData lists, + # because we render parameters in order, and self is always first. + assert len(data.impl_arguments) == 1 + assert data.impl_arguments[0] == self.name + data.impl_arguments[0] = '(' + self.type + ")" + data.impl_arguments[0] + + def set_template_dict(self, template_dict): + template_dict['self_name'] = self.name + template_dict['self_type'] = self.parser_type @@ -2997,7 +3100,7 @@ if not return_converter: return_converter = init_return_converter() elif fields[-1] in unsupported_special_methods: - fail(fields[-1] + " should not be converted to Argument Clinic! (Yet.)") + fail(fields[-1] + " is a special method and cannot be converted to Argument Clinic! (Yet.)") if not return_converter: return_converter = CReturnConverter() @@ -3007,6 +3110,13 @@ self.function = Function(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename, return_converter=return_converter, kind=self.kind, coexist=self.coexist) self.block.signatures.append(self.function) + + # insert a self converter automatically + _, name = correct_name_for_self(self.function) + sc = self.function.self_converter = self_converter(name, self.function) + p_self = Parameter(sc.name, inspect.Parameter.POSITIONAL_ONLY, function=self.function, converter=sc) + self.function.parameters[sc.name] = p_self + (cls or module).functions.append(self.function) self.next(self.state_parameters_start) @@ -3173,34 +3283,43 @@ try: module = ast.parse(ast_input) - # blacklist of disallowed ast nodes - class DetectBadNodes(ast.NodeVisitor): - bad = False - def bad_node(self, node): - self.bad = True - - # inline function call - visit_Call = bad_node - # inline if statement ("x = 3 if y else z") - visit_IfExp = bad_node - - # comprehensions and generator expressions - visit_ListComp = visit_SetComp = bad_node - visit_DictComp = visit_GeneratorExp = bad_node - - # literals for advanced types - visit_Dict = visit_Set = bad_node - visit_List = visit_Tuple = bad_node - - # "starred": "a = [1, 2, 3]; *a" - visit_Starred = bad_node - - # allow ellipsis, for now - # visit_Ellipsis = bad_node - - blacklist = DetectBadNodes() - blacklist.visit(module) - if blacklist.bad: + bad = False + if 'c_default' not in kwargs: + # we can only represent very simple data values in C. + # detect whether default is okay, via a blacklist + # of disallowed ast nodes. + class DetectBadNodes(ast.NodeVisitor): + bad = False + def bad_node(self, node): + self.bad = True + + # inline function call + visit_Call = bad_node + # inline if statement ("x = 3 if y else z") + visit_IfExp = bad_node + + # comprehensions and generator expressions + visit_ListComp = visit_SetComp = bad_node + visit_DictComp = visit_GeneratorExp = bad_node + + # literals for advanced types + visit_Dict = visit_Set = bad_node + visit_List = visit_Tuple = bad_node + + # "starred": "a = [1, 2, 3]; *a" + visit_Starred = bad_node + + # allow ellipsis, for now + # visit_Ellipsis = bad_node + + blacklist = DetectBadNodes() + blacklist.visit(module) + bad = blacklist.bad + else: + # if they specify a c_default, we can be more lenient about the default value. + # but at least ensure that we can turn it into text and reconstitute it correctly. + bad = default != repr(eval(default)) + if bad: fail("Unsupported expression as default value: " + repr(default)) expr = module.body[0].value @@ -3263,18 +3382,22 @@ fail('{} is not a valid {}converter'.format(name, legacy_str)) converter = dict[name](parameter_name, self.function, value, **kwargs) - # special case: if it's the self converter, - # don't actually add it to the parameter list + kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD + if isinstance(converter, self_converter): - if self.function.parameters or (self.parameter_state != self.ps_required): - fail("The 'self' parameter, if specified, must be the very first thing in the parameter block.") - if self.function.self_converter: - fail("You can't specify the 'self' parameter more than once.") - self.function.self_converter = converter - self.parameter_state = self.ps_start - return - - kind = inspect.Parameter.KEYWORD_ONLY if self.keyword_only else inspect.Parameter.POSITIONAL_OR_KEYWORD + if len(self.function.parameters) == 1: + if (self.parameter_state != self.ps_required): + fail("A 'self' parameter cannot be marked optional.") + if value is not unspecified: + fail("A 'self' parameter cannot have a default value.") + if self.group: + fail("A 'self' parameter cannot be in an optional group.") + kind = inspect.Parameter.POSITIONAL_ONLY + self.parameter_state = self.ps_start + self.function.parameters.clear() + else: + fail("A 'self' parameter, if specified, must be the very first thing in the parameter block.") + p = Parameter(parameter_name, kind, function=self.function, converter=converter, default=value, group=self.group) if parameter_name in self.function.parameters: @@ -3333,7 +3456,7 @@ self.parameter_state = self.ps_seen_slash # fixup preceeding parameters for p in self.function.parameters.values(): - if p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD: + if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)): fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.") p.kind = inspect.Parameter.POSITIONAL_ONLY @@ -3394,6 +3517,11 @@ def format_docstring(self): f = self.function + new_or_init = f.kind in (METHOD_NEW, METHOD_INIT) + if new_or_init and not f.docstring: + # don't render a docstring at all, no signature, nothing. + return f.docstring + add, output = text_accumulator() parameters = list(f.parameters.values()) @@ -3401,7 +3529,7 @@ ## docstring first line ## - if f.kind in (METHOD_NEW, METHOD_INIT): + if new_or_init: assert f.cls add(f.cls.name) else: @@ -3409,17 +3537,24 @@ add('(') # populate "right_bracket_count" field for every parameter - if parameters: + assert parameters, "We should always have a self parameter. " + repr(f) + assert isinstance(parameters[0].converter, self_converter) + parameters[0].right_bracket_count = 0 + parameters_after_self = parameters[1:] + if parameters_after_self: # for now, the only way Clinic supports positional-only parameters - # is if all of them are positional-only. - positional_only_parameters = [p.kind == inspect.Parameter.POSITIONAL_ONLY for p in parameters] - if parameters[0].kind == inspect.Parameter.POSITIONAL_ONLY: + # is if all of them are positional-only... + # + # ... except for self! self is always positional-only. + + positional_only_parameters = [p.kind == inspect.Parameter.POSITIONAL_ONLY for p in parameters_after_self] + if parameters_after_self[0].kind == inspect.Parameter.POSITIONAL_ONLY: assert all(positional_only_parameters) for p in parameters: p.right_bracket_count = abs(p.group) else: # don't put any right brackets around non-positional-only parameters, ever. - for p in parameters: + for p in parameters_after_self: p.right_bracket_count = 0 right_bracket_count = 0 @@ -3439,6 +3574,9 @@ add_comma = False for p in parameters: + if not p.converter.show_in_signature: + continue + assert p.name if p.is_keyword_only() and not added_star: @@ -3446,8 +3584,10 @@ if add_comma: add(', ') add('*') - - a = [p.name] + add_comma = True + + name = p.converter.signature_name or p.name + a = [name] if p.converter.is_optional(): a.append('=') value = p.converter.py_default @@ -3560,9 +3700,6 @@ if not self.function: return - if not self.function.self_converter: - self.function.self_converter = self_converter("self", self.function) - if self.keyword_only: values = self.function.parameters.values() if not values: @@ -3582,6 +3719,8 @@ self.function.docstring = self.format_docstring() + + # maps strings to callables. # the callable should return an object # that implements the clinic parser @@ -3607,6 +3746,7 @@ cmdline = argparse.ArgumentParser() cmdline.add_argument("-f", "--force", action='store_true') cmdline.add_argument("-o", "--output", type=str) + cmdline.add_argument("-v", "--verbose", action='store_true') cmdline.add_argument("--converters", action='store_true') cmdline.add_argument("--make", action='store_true') cmdline.add_argument("filename", type=str, nargs="*") @@ -3680,13 +3820,15 @@ cmdline.print_usage() sys.exit(-1) for root, dirs, files in os.walk('.'): - for rcs_dir in ('.svn', '.git', '.hg'): + for rcs_dir in ('.svn', '.git', '.hg', 'build'): if rcs_dir in dirs: dirs.remove(rcs_dir) for filename in files: - if not filename.endswith('.c'): + if not (filename.endswith('.c') or filename.endswith('.h')): continue path = os.path.join(root, filename) + if ns.verbose: + print(path) parse_file(path, verify=not ns.force) return @@ -3701,6 +3843,8 @@ sys.exit(-1) for filename in ns.filename: + if ns.verbose: + print(filename) parse_file(filename, output=ns.output, verify=not ns.force) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 24 15:35:24 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 24 Jan 2014 15:35:24 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_mention_that_tr?= =?utf-8?q?ansports/protocols_are_low-level=2C_streams_are_high-level?= Message-ID: <3f9jZ44SySzS88@mail.python.org> http://hg.python.org/cpython/rev/9af7a7f14e94 changeset: 88669:9af7a7f14e94 user: Victor Stinner date: Fri Jan 24 15:34:19 2014 +0100 summary: asyncio: mention that transports/protocols are low-level, streams are high-level files: Doc/library/asyncio-protocol.rst | 6 +++--- Doc/library/asyncio-stream.rst | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) 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 @@ -1,8 +1,8 @@ .. currentmodule:: asyncio -+++++++++++++++++++++++++ -Transports and protocols -+++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++ +Transports and protocols (low-level API) ++++++++++++++++++++++++++++++++++++++++++ .. _transport: 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 @@ -1,8 +1,8 @@ .. currentmodule:: asyncio -+++++++ -Streams -+++++++ +++++++++++++++++++++++++ +Streams (high-level API) +++++++++++++++++++++++++ Stream functions ================ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 24 17:33:29 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 24 Jan 2014 17:33:29 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio_doc=3A_add_a_=22Co?= =?utf-8?q?routines_and_protocols=22_section?= Message-ID: <3f9mBK2Wf5z7Ll2@mail.python.org> http://hg.python.org/cpython/rev/3e7eddf7b328 changeset: 88670:3e7eddf7b328 user: Victor Stinner date: Fri Jan 24 17:33:20 2014 +0100 summary: asyncio doc: add a "Coroutines and protocols" section files: Doc/library/asyncio-protocol.rst | 12 ++++++++++++ Doc/library/asyncio-stream.rst | 2 ++ 2 files changed, 14 insertions(+), 0 deletions(-) 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 @@ -403,6 +403,18 @@ mark is zero. +Coroutines and protocols +------------------------ + +Coroutines can be scheduled in a protocol method using :func:`async`, but there +is not guarantee on the execution order. Protocols are not aware of coroutines +created in protocol methods and so will not wait for them. + +To have a reliable execution order, use :ref:`stream objects ` in a +coroutine with ``yield from``. For example, the :meth:`StreamWriter.drain` +coroutine can be used to wait until the write buffer is flushed. + + Server ------ 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 @@ -1,5 +1,7 @@ .. currentmodule:: asyncio +.. _streams: + ++++++++++++++++++++++++ Streams (high-level API) ++++++++++++++++++++++++ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 24 17:44:49 2014 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 24 Jan 2014 17:44:49 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogbmV3IHBsYW46IGp1?= =?utf-8?q?st_remove_typecasts_=28closes_=2320374=29?= Message-ID: <3f9mRP4Q8mz7LjM@mail.python.org> http://hg.python.org/cpython/rev/5e42e5764ac6 changeset: 88671:5e42e5764ac6 branch: 2.7 parent: 88663:79b82ebc4fd1 user: Benjamin Peterson date: Fri Jan 24 11:44:16 2014 -0500 summary: new plan: just remove typecasts (closes #20374) files: Modules/readline.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/readline.c b/Modules/readline.c --- a/Modules/readline.c +++ b/Modules/readline.c @@ -852,7 +852,7 @@ * before calling the normal completer */ static char ** -flex_complete(char *text, int start, int end) +flex_complete(const char *text, int start, int end) { #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER rl_completion_append_character ='\0'; @@ -911,12 +911,12 @@ rl_bind_key_in_map ('\t', rl_complete, emacs_meta_keymap); rl_bind_key_in_map ('\033', rl_complete, emacs_meta_keymap); /* Set our hook functions */ - rl_startup_hook = (rl_hook_func_t *)on_startup_hook; + rl_startup_hook = on_startup_hook; #ifdef HAVE_RL_PRE_INPUT_HOOK - rl_pre_input_hook = (rl_hook_func_t *)on_pre_input_hook; + rl_pre_input_hook = on_pre_input_hook; #endif /* Set our completion function */ - rl_attempted_completion_function = (rl_completion_func_t *)flex_complete; + rl_attempted_completion_function = flex_complete; /* Set Python word break characters */ completer_word_break_characters = rl_completer_word_break_characters = -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 24 17:44:50 2014 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 24 Jan 2014 17:44:50 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogbmV3IHBsYW46IGp1?= =?utf-8?q?st_remove_typecasts_=28closes_=2320374=29?= Message-ID: <3f9mRQ6G8Xz7LjM@mail.python.org> http://hg.python.org/cpython/rev/fc62fcd8e990 changeset: 88672:fc62fcd8e990 branch: 3.3 parent: 88666:b3eaeb4bdf84 user: Benjamin Peterson date: Fri Jan 24 11:44:16 2014 -0500 summary: new plan: just remove typecasts (closes #20374) files: Modules/readline.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/readline.c b/Modules/readline.c --- a/Modules/readline.c +++ b/Modules/readline.c @@ -877,7 +877,7 @@ * before calling the normal completer */ static char ** -flex_complete(char *text, int start, int end) +flex_complete(const char *text, int start, int end) { #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER rl_completion_append_character ='\0'; @@ -936,12 +936,12 @@ rl_bind_key_in_map ('\t', rl_complete, emacs_meta_keymap); rl_bind_key_in_map ('\033', rl_complete, emacs_meta_keymap); /* Set our hook functions */ - rl_startup_hook = (rl_hook_func_t *)on_startup_hook; + rl_startup_hook = on_startup_hook; #ifdef HAVE_RL_PRE_INPUT_HOOK - rl_pre_input_hook = (rl_hook_func_t *)on_pre_input_hook; + rl_pre_input_hook = on_pre_input_hook; #endif /* Set our completion function */ - rl_attempted_completion_function = (rl_completion_func_t *)flex_complete; + rl_attempted_completion_function = flex_complete; /* Set Python word break characters */ completer_word_break_characters = rl_completer_word_break_characters = -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 24 17:44:52 2014 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 24 Jan 2014 17:44:52 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4zICgjMjAzNzQp?= Message-ID: <3f9mRS123Gz7Ljq@mail.python.org> http://hg.python.org/cpython/rev/3c3624fec6c8 changeset: 88673:3c3624fec6c8 parent: 88670:3e7eddf7b328 parent: 88672:fc62fcd8e990 user: Benjamin Peterson date: Fri Jan 24 11:44:40 2014 -0500 summary: merge 3.3 (#20374) files: Modules/readline.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/readline.c b/Modules/readline.c --- a/Modules/readline.c +++ b/Modules/readline.c @@ -935,7 +935,7 @@ * before calling the normal completer */ static char ** -flex_complete(char *text, int start, int end) +flex_complete(const char *text, int start, int end) { char **result; #ifdef WITH_THREAD @@ -998,12 +998,12 @@ rl_bind_key_in_map ('\t', rl_complete, emacs_meta_keymap); rl_bind_key_in_map ('\033', rl_complete, emacs_meta_keymap); /* Set our hook functions */ - rl_startup_hook = (rl_hook_func_t *)on_startup_hook; + rl_startup_hook = on_startup_hook; #ifdef HAVE_RL_PRE_INPUT_HOOK - rl_pre_input_hook = (rl_hook_func_t *)on_pre_input_hook; + rl_pre_input_hook = on_pre_input_hook; #endif /* Set our completion function */ - rl_attempted_completion_function = (rl_completion_func_t *)flex_complete; + rl_attempted_completion_function = flex_complete; /* Set Python word break characters */ completer_word_break_characters = rl_completer_word_break_characters = -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 24 18:12:20 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 24 Jan 2014 18:12:20 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio_doc=3A_move_Abstra?= =?utf-8?q?ctServer_to_the_event_loop_page?= Message-ID: <3f9n381ZGhzMs9@mail.python.org> http://hg.python.org/cpython/rev/eca51c887c37 changeset: 88674:eca51c887c37 user: Victor Stinner date: Fri Jan 24 18:11:43 2014 +0100 summary: asyncio doc: move AbstractServer to the event loop page Add also entries in the table of content for each synchronization primitive class. files: Doc/library/asyncio-eventloop.rst | 16 +++++++++++ Doc/library/asyncio-protocol.rst | 16 ----------- Doc/library/asyncio-sync.rst | 27 +++++++++++++++++++ 3 files changed, 43 insertions(+), 16 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 @@ -344,6 +344,22 @@ Set the default executor used by :meth:`run_in_executor`. +Server +------ + +.. class:: AbstractServer + + Abstract server returned by :func:`BaseEventLoop.create_server`. + + .. method:: close() + + Stop serving. This leaves existing connections open. + + .. method:: wait_closed() + + Coroutine to wait until service is closed. + + .. _asyncio-hello-world-callback: Example: Hello World (callback) 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 @@ -415,22 +415,6 @@ coroutine can be used to wait until the write buffer is flushed. -Server ------- - -.. class:: AbstractServer - - Abstract server returned by :func:`BaseEventLoop.create_server`. - - .. method:: close() - - Stop serving. This leaves existing connections open. - - .. method:: wait_closed() - - Coroutine to wait until service is closed. - - Protocol example: TCP echo server and client ============================================ diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-sync.rst --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-sync.rst @@ -7,6 +7,9 @@ Locks ----- +Lock +^^^^ + .. class:: Lock(\*, loop=None) Primitive lock objects. @@ -85,6 +88,9 @@ There is no return value. +Event +^^^^^ + .. class:: Event(\*, loop=None) An Event implementation, asynchronous equivalent to :class:`threading.Event`. @@ -121,6 +127,9 @@ This method returns a :ref:`coroutine object `. +Condition +^^^^^^^^^ + .. class:: Condition(\*, loop=None) A Condition implementation, asynchronous equivalent to @@ -181,6 +190,9 @@ Semaphores ---------- +Semaphore +^^^^^^^^^ + .. class:: Semaphore(value=1, \*, loop=None) A Semaphore implementation. @@ -218,6 +230,9 @@ larger than zero again, wake up that coroutine. +BoundedSemaphore +^^^^^^^^^^^^^^^^ + .. class:: BoundedSemaphore(value=1, \*, loop=None) A bounded semaphore implementation. Inherit from :class:`Semaphore`. @@ -229,6 +244,9 @@ Queues ------ +Queue +^^^^^ + .. class:: Queue(maxsize=0, \*, loop=None) A queue, useful for coordinating producer and consumer coroutines. @@ -294,6 +312,9 @@ Number of items allowed in the queue. +PriorityQueue +^^^^^^^^^^^^^ + .. class:: PriorityQueue A subclass of :class:`Queue`; retrieves entries in priority order (lowest @@ -302,12 +323,18 @@ Entries are typically tuples of the form: (priority number, data). +LifoQueue +^^^^^^^^^ + .. class:: LifoQueue A subclass of :class:`Queue` that retrieves most recently added entries first. +JoinableQueue +^^^^^^^^^^^^^ + .. class:: JoinableQueue A subclass of :class:`Queue` with :meth:`task_done` and :meth:`join` -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 24 18:47:34 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 24 Jan 2014 18:47:34 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio_doc=3A_document_St?= =?utf-8?q?reamWriter=2Edrain=28=29?= Message-ID: <3f9nqp5rRpz7Ljq@mail.python.org> http://hg.python.org/cpython/rev/1975d7d87c48 changeset: 88675:1975d7d87c48 user: Victor Stinner date: Fri Jan 24 18:47:26 2014 +0100 summary: asyncio doc: document StreamWriter.drain() files: Doc/library/asyncio-stream.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 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 @@ -126,9 +126,9 @@ .. method:: drain() - This method has an unusual return value. + Wait until the write buffer of the underlying transport is flushed. - The intended use is to write:: + This method has an unusual return value. The intended use is to write:: w.write(data) yield from w.drain() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 24 21:20:23 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 24 Jan 2014 21:20:23 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMzg0?= =?utf-8?q?=3A_Fix_the_test=5Ftarfile_test_on_Windows=2E?= Message-ID: <3f9sD74VNXzS5K@mail.python.org> http://hg.python.org/cpython/rev/69d885ac042d changeset: 88676:69d885ac042d branch: 3.3 parent: 88672:fc62fcd8e990 user: Serhiy Storchaka date: Fri Jan 24 22:19:23 2014 +0200 summary: Issue #20384: Fix the test_tarfile test on Windows. On Windows os.open() error message doesn't contain file name. files: Lib/test/test_tarfile.py | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -239,7 +239,12 @@ def test_non_existent_tarfile(self): # Test for issue11513: prevent non-existent gzipped tarfiles raising # multiple exceptions. - with self.assertRaisesRegex(FileNotFoundError, "xxx"): + test = 'xxx' + if sys.platform == 'win32' and '|' in self.mode: + # Issue #20384: On Windows os.open() error message doesn't + # contain file name. + text = '' + with self.assertRaisesRegex(FileNotFoundError, test): tarfile.open("xxx", self.mode) def test_null_tarfile(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 24 21:20:24 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 24 Jan 2014 21:20:24 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Null_merge?= Message-ID: <3f9sD86Lv8z7Lk0@mail.python.org> http://hg.python.org/cpython/rev/334b5db73204 changeset: 88677:334b5db73204 parent: 88675:1975d7d87c48 parent: 88676:69d885ac042d user: Serhiy Storchaka date: Fri Jan 24 22:20:05 2014 +0200 summary: Null merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 24 21:29:30 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 24 Jan 2014 21:29:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogRml4IHR5cG8u?= Message-ID: <3f9sQf5RDjz7Ljt@mail.python.org> http://hg.python.org/cpython/rev/38a50d8102be changeset: 88678:38a50d8102be branch: 3.3 parent: 88676:69d885ac042d user: Serhiy Storchaka date: Fri Jan 24 22:28:06 2014 +0200 summary: Fix typo. files: Lib/test/test_tarfile.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -243,7 +243,7 @@ if sys.platform == 'win32' and '|' in self.mode: # Issue #20384: On Windows os.open() error message doesn't # contain file name. - text = '' + test = '' with self.assertRaisesRegex(FileNotFoundError, test): tarfile.open("xxx", self.mode) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 24 21:29:32 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 24 Jan 2014 21:29:32 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Null_merge?= Message-ID: <3f9sQh0Qjnz7Ljt@mail.python.org> http://hg.python.org/cpython/rev/c6e529c1f87c changeset: 88679:c6e529c1f87c parent: 88677:334b5db73204 parent: 88678:38a50d8102be user: Serhiy Storchaka date: Fri Jan 24 22:28:42 2014 +0200 summary: Null merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 05:41:12 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 25 Jan 2014 05:41:12 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?devguide=3A_mention_hgaccounts=40?= Message-ID: <3fB4L009lDz7Llj@mail.python.org> http://hg.python.org/devguide/rev/94daeaf7c227 changeset: 661:94daeaf7c227 user: Benjamin Peterson date: Fri Jan 24 23:41:08 2014 -0500 summary: mention hgaccounts@ files: developers.rst | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/developers.rst b/developers.rst --- a/developers.rst +++ b/developers.rst @@ -13,9 +13,10 @@ Entries should include the initials of the project admin who made the change or granted access. -Note, when giving new commit permissions, be sure to get a contributor -agreement from the committer. See http://www.python.org/psf/contrib/ -for details. When the agreement is signed, please note it in this log. +Note, when giving new commit permissions, be sure to get a contributor agreement +from the committer. See http://www.python.org/psf/contrib/ for details. When +the agreement is signed, please note it in this log. SSH keys of the committer +should be sent to hgaccounts at python.org. This file is encoded in UTF-8. If the usual form for a name is not in a Latin or extended Latin alphabet, make sure to include an ASCII -- Repository URL: http://hg.python.org/devguide From root at python.org Sat Jan 25 05:45:05 2014 From: root at python.org (Cron Daemon) Date: Sat, 25 Jan 2014 05:45:05 +0100 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: Could not find platform independent libraries Could not find platform dependent libraries Consider setting $PYTHONHOME to [:] 'import site' failed; use -v for traceback Traceback (most recent call last): File "/data/hg/sphinx-env/bin/sphinx-build", line 5, in from pkg_resources import load_entry_point ImportError: No module named pkg_resources From python-checkins at python.org Sat Jan 25 05:52:47 2014 From: python-checkins at python.org (zach.ware) Date: Sat, 25 Jan 2014 05:52:47 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320381=3A_Fix_sani?= =?utf-8?q?ty_checking_on_default_arguments_when_c=5Fdefault_is?= Message-ID: <3fB4bM0PdCz7Lk1@mail.python.org> http://hg.python.org/cpython/rev/93afa651e074 changeset: 88680:93afa651e074 user: Zachary Ware date: Fri Jan 24 22:52:30 2014 -0600 summary: Issue #20381: Fix sanity checking on default arguments when c_default is also specified. files: Misc/NEWS | 5 +++++ Tools/clinic/clinic.py | 14 +++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -141,6 +141,11 @@ Tools/Demos ----------- + +- Issue #20381: Argument Clinic now sanity checks the default argument when + c_default is also specified, providing a nice failure message for + disallowed values. + - Issue #20189: Argument Clinic now ensures that parser functions for __new__ are always of type newfunc, the type of the tp_new slot. Similarly, parser functions for __init__ are now always of type initproc, diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -3279,11 +3279,11 @@ fail("You can't specify py_default without specifying a default value!") else: default = default.strip() + bad = False ast_input = "x = {}".format(default) try: module = ast.parse(ast_input) - bad = False if 'c_default' not in kwargs: # we can only represent very simple data values in C. # detect whether default is okay, via a blacklist @@ -3317,8 +3317,16 @@ bad = blacklist.bad else: # if they specify a c_default, we can be more lenient about the default value. - # but at least ensure that we can turn it into text and reconstitute it correctly. - bad = default != repr(eval(default)) + # but at least make an attempt at ensuring it's a valid expression. + try: + value = eval(default) + if value == unspecified: + fail("'unspecified' is not a legal default value!") + except NameError: + pass # probably a named constant + except Exception as e: + fail("Malformed expression given as default value\n" + "{!r} caused {!r}".format(default, e)) if bad: fail("Unsupported expression as default value: " + repr(default)) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 06:00:35 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 25 Jan 2014 06:00:35 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_update_hosting?= =?utf-8?q?_faq?= Message-ID: <3fB4mM6b31z7LkS@mail.python.org> http://hg.python.org/cpython/rev/3551f184b282 changeset: 88681:3551f184b282 branch: 3.3 parent: 88678:38a50d8102be user: Benjamin Peterson date: Fri Jan 24 23:59:57 2014 -0500 summary: update hosting faq files: Doc/faq/general.rst | 9 ++++++--- 1 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -268,9 +268,12 @@ Where in the world is www.python.org located? --------------------------------------------- -It's currently in Amsterdam, graciously hosted by `XS4ALL -`_. Thanks to Thomas Wouters for his work in arranging -python.org's hosting. +The Python project's infrastructure is located all over the world. +www.python.org is currently in Amsterdam, graciously hosted by `XS4ALL +`_. `Upfront Systems `_ +hosts bugs.python.org. Most other Python services like `PyPI +`_ and hg.python.org are hosted by `Oregon State +University Open Source Lab `_. Why is it called Python? -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 06:00:37 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 25 Jan 2014 06:00:37 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_update_hosting?= =?utf-8?q?_faq?= Message-ID: <3fB4mP1DYlz7Llb@mail.python.org> http://hg.python.org/cpython/rev/02f6c31c36a5 changeset: 88682:02f6c31c36a5 branch: 2.7 parent: 88671:5e42e5764ac6 user: Benjamin Peterson date: Fri Jan 24 23:59:57 2014 -0500 summary: update hosting faq files: Doc/faq/general.rst | 9 ++++++--- 1 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -268,9 +268,12 @@ Where in the world is www.python.org located? --------------------------------------------- -It's currently in Amsterdam, graciously hosted by `XS4ALL -`_. Thanks to Thomas Wouters for his work in arranging -python.org's hosting. +The Python project's infrastructure is located all over the world. +www.python.org is currently in Amsterdam, graciously hosted by `XS4ALL +`_. `Upfront Systems `_ +hosts bugs.python.org. Most other Python services like `PyPI +`_ and hg.python.org are hosted by `Oregon State +University Open Source Lab `_. Why is it called Python? -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 06:00:38 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 25 Jan 2014 06:00:38 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3fB4mQ33f2z7Llg@mail.python.org> http://hg.python.org/cpython/rev/de2b96f220a5 changeset: 88683:de2b96f220a5 parent: 88680:93afa651e074 parent: 88681:3551f184b282 user: Benjamin Peterson date: Sat Jan 25 00:00:28 2014 -0500 summary: merge 3.3 files: Doc/faq/general.rst | 9 ++++++--- 1 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -268,9 +268,12 @@ Where in the world is www.python.org located? --------------------------------------------- -It's currently in Amsterdam, graciously hosted by `XS4ALL -`_. Thanks to Thomas Wouters for his work in arranging -python.org's hosting. +The Python project's infrastructure is located all over the world. +www.python.org is currently in Amsterdam, graciously hosted by `XS4ALL +`_. `Upfront Systems `_ +hosts bugs.python.org. Most other Python services like `PyPI +`_ and hg.python.org are hosted by `Oregon State +University Open Source Lab `_. Why is it called Python? -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 06:27:51 2014 From: python-checkins at python.org (nick.coghlan) Date: Sat, 25 Jan 2014 06:27:51 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Draft_PEP_for_merge_workflow_?= =?utf-8?q?automation?= Message-ID: <3fB5Mq0jDLz7Llf@mail.python.org> http://hg.python.org/peps/rev/717d4d2478c6 changeset: 5356:717d4d2478c6 user: Nick Coghlan date: Sat Jan 25 15:27:37 2014 +1000 summary: Draft PEP for merge workflow automation files: pep-0462.txt | 507 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 507 insertions(+), 0 deletions(-) diff --git a/pep-0462.txt b/pep-0462.txt new file mode 100644 --- /dev/null +++ b/pep-0462.txt @@ -0,0 +1,507 @@ +PEP: 462 +Title: Core development workflow automation for CPython +Version: $Revision$ +Last-Modified: $Date$ +Author: Nick Coghlan +Status: Draft +Type: Process +Content-Type: text/x-rst +Created: 23-Jan-2014 + + +Abstract +======== + +This PEP proposes investing in automation of several of the tedious, time +consuming activities that are currently required for the core developerment +team to incorporate changes into CPython. This proposal is intended to +allow core developers to make more effective use of the time they have +available to contribute to CPython, which should also result in an improved +experience for other contributors that are reliant on the core team to get +their changes incorporated. + + +Rationale +========= + +The current core developer workflow to merge a new feature into CPython +on a POSIX system "works" as follows: + +#. If applying a change submitted to bugs.python.org by another user, first + check they have signed the PSF Contributor Licensing Agreement. If not, + request that they sign one before continuing with merging the change. +#. Apply the change locally to a current checkout of the main CPython + repository (the change will typically have been discussed and reviewed + as a patch on bugs.python.org first, but this step is not currently + considered mandatory for changes originating directly from core + developers). +#. Run the test suite locally, at least ``make test`` or + ``./python -m test`` (depending on system specs, this takes a few + minutes in the default configuration, but substantially longer if all + optional resources, like external network access, are enabled). +#. Run ``make patchcheck`` to fix any whitespace issues and as a reminder + of other changes that may be needed (such as updating Misc/ACKS or + adding an entry to Misc/NEWS) +#. Commit the change and push it to the main repository. If hg indicates + this would create a new head in the remote repository, run + ``hg pull --rebase`` (or an equivalent). Theoretically, you should + rerun the tests at this point, but it's *very* tempting to skip that + step. +#. After pushing, monitor the `stable buildbots + `__ + for any new failures introduced by your change. In particular, developers + on POSIX systems will often break the Windows buildbots, and vice-versa. + Less commonly, developers on Linux or Mac OS X may break other POSIX + systems. + +The steps required on Windows are similar, but the exact commands used +will be different. + +Rather than being simpler, the workflow for a bug fix is *more* complicated +than that for a new feature! New features have the advantage of only being +applied to the ``default`` branch, while bug fixes also need to be considered +for inclusion in maintenance branches. + +* If a bug fix is applicable to Python 2.7, then it is also separately + applied to the 2.7 branch, which is maintained as an independent head + in Mercurial +* If a bug fix is applicable to the current 3.x maintenance release, then + it is first applied to the maintenance branch and then merged forward + to the default branch. Both branches are pushed to hg.python.org at the + same time. + +Documentation patches are simpler than functional patches, but not +hugely so - the main benefit is only needing to check the docs build +successfully rather than running the test suite. + +I would estimate that even when everything goes smoothly, it would still +take me at least 20-30 minutes to commit a bug fix patch that applies +cleanly. Given that it should be possible to automate several of these +tasks, I do not believe our current practices are making effective use +of scarce core developer resources. + +There are many, many frustrations involved with this current workflow, and +they lead directly to some undesirable development practices. + +* Much of this overhead is incurred on a per-patch applied basis. This + encourages large commits, rather than small isolated changes. The time + required to commit a 500 line feature is essentially the same as that + needed to commit a 1 line bug fix - the additional time needed for the + larger change appears in any preceding review rather than as part of the + commit process. +* The additional overhead of working on applying bug fixes creates an + additional incentive to work on new features instead, and new features + are already *inherently* more interesting to work on - they don't need + workflow difficulties giving them a helping hand! +* Getting a preceding review on bugs.python.org is *additional* work, + creating an incentive to commit changes directly, increasing the reliance + on post-review on the python-checkins mailing list. +* Patches on the tracker that are complete, correct and ready to merge may + still languish for extended periods awaiting a core developer with the + time to devote to getting it merged. +* The risk of push races (especially when pushing a merged bug fix) creates + a temptation to skip doing full local test runs (especially after a push + race has already been encountered once), increasing the chance of + breaking the buildbots. +* The buildbots are sometimes red for extended periods, introducing errors + into local test runs, and also meaning that they sometimes fail to serve + as a reliable indicator of whether or not a patch has introduced cross + platform issues. +* Post-conference development sprints are a nightmare, as they collapse + into a mire of push races. It's tempting to just leave patches on the + tracker until after the sprint is over and then try to clean them up + afterwards. + +There are also many, many opportunities for core developers to make +mistakes that inconvience others, both in managing the Mercurial branches +and in breaking the buildbots without being in a position to fix them +promptly. This both makes the existing core development team cautious in +granting new developers commit access, as well as making those new +developers cautious about actually making use of their increased level of +access. + +There are also some incidental annoyances (like keeping the NEWS file up to +date) that will also be necessarily addressed as part of this proposal. + +One of the most critical resources of a volunteer-driven open source project +is the emotional energy of its contributors. The current approach to change +incorporation doesn't score well on that front for anyone: + +* For core developers, the branch wrangling for bug fixes is delicate and + easy to get wrong. Conflicts on the NEWS file and push races when + attempting to upload changes add to the irritation of something most of + us aren't being paid to spend time on. The time we spend actually getting + a change merged is time we're not spending coding additional changes, + writing or updating documentation or reviewing contributions from others. +* Red buildbots make life difficult for other developers (since a local + test failure may *not* be due to anything that developer did), release + managers (since they may need to enlist assistance cleaning up test + failures prior to a release) and for the developers themselves (since + it creates significant pressure to fix any failures we inadvertently + introduce right *now*, rather than at a more convenient time). +* For new contributors, a core developer spending time actually getting + changes merged is a developer that isn't reviewing and discussing patches + on the issue tracker or otherwise helping others to contribute effectively. + It is especially frustrating for contributors that are accustomed to the + simplicity of a developer just being able to hit "Merge" on a pull + request that has already been automatically tested in the project's CI + system (which is a common workflow on sites like GitHub and BitBucket), or + where the post-review part of the merge process is fully automated (as is + the case for OpenStack). + + +Current Tools +============= + +The following tools are currently used to manage various parts of the +CPython core development workflow. + +* Mercurial (hg.python.org) for version control +* Roundup (bugs.python.org) for issue tracking +* Rietveld (also hosted on bugs.python.org) for code review +* Buildbot (buildbot.python.org) for automated testing + +This proposal does *not* suggest replacing any of these tools, although +implementing it effectively may require modifications to some or all of +them. + +It does however suggest the addition of new tools in order to automate +additional parts of the workflow. + + +Proposal +======== + +The essence of this proposal is that CPython aim to adopt a "core reviewer" +development model, similar to that used by the OpenStack project. + +These problems experienced by CPython are not unique. The OpenStack +infrastructure team have come up with a well designed automated workflow +that is designed to ensure: + +* once a patch has been reviewed, further developer involvement is needed + only if the automated tests fail prior to merging +* patches never get merged without being tested relative to the current + state of the branch +* the main development branch always stays green. Patches that do not pass + the automated tests do not get merged. + +The core of this workflow is implemented using a tool called Zuul_, a +Python web service created specifically for the OpenStack project, but +deliberately designed with a plugin based trigger and action system to make +it easier to adapt to alternate code review systems, issue trackers and +CI systems. James Blair of the OpenStack infrastructure team provided +an `excellent overview of Zuul +`__ at linux.conf.au 2014. + +While Zuul handles several workflows for OpenStack, the specific one of +interest for this PEP is the "merge gating" workflow. + +For this workflow, Zuul is configured to monitor the Gerrit code review +system for patches which have been marked as "+2 Approved". Once it sees +such a patch, Zuul takes it, and combines it into a queue of "candidate +merges". It then creates a pipeline of test runs that execute in parallel in +Jenkins (in order to allow more than 24 commits a day when a full test run +takes the better part of an hour), and are merged as they pass (and as all +the candidate merges ahead of them in the queue pass). If a patch fails the +tests, Zuul takes it of the queue, cancels any test runs after that patch in +the queue, and rebuilds the queue without the failing patch. + +To adapt this process to CPython, it should be feasible to have Zuul monitor +Rietveld for approved patches (which would require a feature addition in +Rietveld), submit them to Buildbot for testing on the stable buildbots, and +then merge the changes appropriately in Mercurial. This idea poses a few +technical challenges, which have their own section below. + +For CPython, I don't believe we will need to take advantage of Zuul's +ability to execute tests in parallel (certainly not in the initial +iteration - if we get to a point where serial testing of patches by the +merge gating system is our primary bottleneck rather than having the +people we need in order to be able to review and approve patches, then +that will be a very good day). + +However, the merge queue itself is a very powerful concept that should +directly address several of the issues described above. + +.. _Zuul: http://ci.openstack.org/zuul/ + + +Deferred Proposals +================== + +The OpenStack team also use Zuul to coordinate several other activities: + +* Running preliminary "check" tests against patches posted to Gerrit. +* Creation of updated release artefacts and republishing documentation when + changes are merged +* Using ElasticSearch in conjunction with a spam filter to monitor test + output and suggest the specific intermittent failure that may have + caused a test to fail, rather than requiring users to search logs manually + +While these are possibilities worth exploring in the future (and one of the +possible benefits I see to seeking closer coordination with the OpenStack +Infrastructure team), I don't see them as offering quite the same kind of +fundamental workflow improvement that merge gating appears to provide. + + +Perceived Benefits +================== + +The benefits of this proposal accrue most directly to the core development +team. First and foremost, it means that once we mark a patch as "Approved" +in the updated code review system, *we're usually done*. The extra 20-30 +minutes (or more) of actually applying the patch, running the tests and +merging it into Mercurial would all be orchestrated by Zuul. Push races +would also be a thing of the past - if lots of core developers are +approving patches at a sprint, then that just means the queue gets +deeper in Zuul, rather than developers getting frustrated trying to +merge changes and failing. Test failures would still happen, but they +would result in the affected patch being removed from the merge queue, +rather than breaking the code in the main repository. + +With the bulk of the time investment moved to the review process, this +also encourages "development for reviewability" - smaller, easier to review +patches, since the overhead of running the tests five times rather than once +will be incurred by Zuul rather than by the core developers. + +However, removing this time sink from the core development team should also +improve the experience of CPython development for other contributors, as it +removes several of the opportunities for patches to get "dropped on the +floor", as well as increasing the time core developers are likely to have +available for reviewing contributed patches. + +Another example of benefits to other contributors is that when a sprint +aimed primarily at new contributors is running with just a single core +developer present (such as the sprints at PyCon AU for the last +few years), the merge queue would allow that developer to focus more of +their time on reviewing patches and helping the other contributors at the +sprint, since accepting a patch for inclusion would now be a single click +in the Rietveld UI, rather than the relatively time consuming process that +it is currently. Even when multiple core developers are present, it is +better to enable them to spend their time and effort on interacting with +the other sprint participants than it is on things that are sufficiently +mechanical that a computer can (and should) handle them. + + +Technical Challenges +==================== + +Adapting Zuul from the OpenStack infrastructure to the CPython +infrastructure will at least require the development of additional +Zuul trigger and action plugins, and may require additional development +in some of our existing tools. + + +Rietveld vs Gerrit +------------------ + +Rietveld does not currently include a voting/approval feature that is +equivalent to Gerrit's. For CPython, we wouldn't need anything as +sophisticated as Gerrit's voting system - a simple core-developer-only +"Approved" marker to trigger action from Zuul should suffice. The +core-developer-or-not flag is available in Roundup, which may require +further additions to the existing integration between the two tools. + +Rietveld may also require some changes to allow the uploader of a patch +to indicate which branch it is intended for. + +There would also be an additional Zuul trigger plugin needed to monitor +Rietveld activity rather than Gerrit. + + +Mercurial vs Gerrit/git +----------------------- + +Gerrit uses git as the actual storage mechanism for patches, and +automatically handles merging of approved patches. By contrast, Rietveld +works directly on patches, and is completely decoupled from any specific +version control system. + +Zuul is also directly integrated with git for patch manipulation - as far +as I am aware, this part of the design isn't pluggable. + +Rather than trying to adapt Zuul to work directly with Mercurial, it will +likely be more practical to let Zuul continue to use git internally, and +then use the hg-git Mercurial plugin to pull the output from Zuul into the +master repo at hg.python.org. (While there are various plugins that are +designed to let git push to Mercurial repos, the influence of GitHub is +such that the hg-git plugin appears to be the most mature of the available +options for hg-git interoperability). + + +Buildbot vs Jenkins +------------------- + +As far as I am aware, Zuul's interaction with the CI system is also +pluggable, so this should only require creating a Buildbot plugin to use +instead of the Jenkins one. + +Note that, in the initial iteration, I am proposing that we *do not* +attempt to pipeline test execution. This means Zuul would be running in +a very simple mode where only the patch at the head of the merge queue +is being tested on the Buildbot fleet, rather than potentially testing +several patches in parallel. I am picturing something equivalent to +requesting a forced build from the Buildbot master, and then waiting for +the result to come back before moving on to the second patch in the queue. + +If we ultimately decide that this is not sufficient, and we need to start +using the CI pipelining features of Zuul, then we may need to look at using +Jenkins test runs to control the gating process. Due to the differences +in the client/server architectures between Jenkins and Buildbot, the +initial feedback from the OpenStack infrastructure team is that it is likely +to be difficult to adapt the way Zuul controls the CI pipelining process in +Jenkins to control Buildbot instead. + +If that latter step occurs, it would likely make sense to look at moving the +test execution to dynamically provisioned cloud images, rather than relying +on volunteer maintained statically provisioned systems as we do currently. + +In this case, the main technical risk would become Zuul's handling of testing +on platforms other than Linux (our stable buildbots currently cover Windows, +Mac OS X, FreeBSD and OpenIndiana in addition to a couple of different Linux +variants). + +In such a scenario, the Buildbot fleet would still have a place in doing +"check" runs against the master repository (either periodically or for +every commit), even if it did not play a part in the merge gating process. +More unusual configurations (such as building without threads, or without +SSL/TLS support) would likely still be handled that way rather than being +included in the gate criteria. + + +Handling of maintenance branches +-------------------------------- + +The OpenStack project largely leaves the question of maintenance branches +to downstream vendors, rather than handling it directly. This means there +are questions to be answered regarding how we adapt Zuul to handle our +maintenance branches. + +Python 2.7 can be handled easily enough by treating it as a separate patch +queue. This would just require a change in Rietveld to indicate which +branch was the intended target of the patch. + +The Python 3.x maintenance branches are potentially more complicated. One +option would be to simply stop using Mercurial merges to manage them, and +instead treat them as independent heads, similar to the Python 2.7 branch. +Patches that applied cleanly to both the active maintenance branch and to +default would then just be submitted to both queues, while other changes +might involve submitting separate patches for the active maintenance branch +and for default. This approach also has the benefit of adjusting cleanly to +the intermittent periods where we have two active Python 3 maintenance +branches. + + +Handling of security branches +----------------------------- + +For simplicity's sake, I would suggest leaving the handling of +security-fix only branches alone: the release managers for those branches +backport specific changes manually. + + +Handling of NEWS file updates +----------------------------- + +Our current approaching to handling NEWS file updates regularly results in +spurious conflicts when merging bug fixes forward from an active maintenance +branch to a later branch. + +`Issue #18967* `__ discusses some +possible improvements in that area, which would be beneficial regardless +of whether or not we adopt Zuul as a workflow automation tool. + + +Stability of "stable" Buildbot slaves +------------------------------------- + +Instability of the nominally stable buildbots has a substantially larger +impact under this proposal. We would need to ensure we're happy with each +of those systems gating merges to the development branches, or else move +then to "unstable" status. + + +Intermittent test failures +-------------------------- + +Some tests, especially timing tests, exhibit intermittent failures on the +existing Buildbot fleet. In particular, test systems running as VMs may +sometimes exhibit timing failures + + +Social Challenges +================= + +The primary social challenge here is getting the core development team to +change their practices. However, the tedious-but-necessary steps that are +automated by the proposal should create a strong incentive for the +existing developers to go along with the idea. + +I believe two specific features may be needed to assure existing +developers that there are no downsides to the automation of this workflow: + +* Only requiring approval from a single core developer to incorporate a + patch. This could be revisited in the future, but we should preserve the + status quo for the initial rollout. + +* Explicitly stating that core developers remain free to approve their own + patches, except during the release candidate phase of a release. This + could be revisited in the future, but we should preserve the status quo + for the initial rollout. + +* Ensuring that at least release managers have a "merge it now" capability + that allows them to force a particular patch to the head of the merge + queue. Using a separate clone for release preparation may be sufficient + for this purpose. Longer term, automatic merge gating may also allow for + more automated preparation of release artefacts as well. + + +Open Questions +============== + +Pretty much everything in the PEP. Do we want to do this? Is Rietveld the +right place to hook Zuul into our current workflows? How do we want to +address the various technical challenges? + +Assuming we do want to do it (or something like it), how is the work going +to get done? Do we try to get it done solely as a volunteer effort? Do we +put together a grant proposal for the PSF board to consider (assuming we can +find people willing and available to do the work)? + +Do we approach the OpenStack Foundation for assistance, since +we're a key dependency of OpenStack itself, Zuul is a creation of the +OpenStack infrastructure team, and the available development resources for +OpenStack currently dwarf those for CPython? + + +Next Steps +========== + +The topic of CPython workflow automation is on the agenda for the Language +Summit at PyCon US 2014 in Montreal, and we will be inviting additional +participants (specifically Mercurial and Zuul developers) to be involved +in the discussions (Guido van Rossum is the creator of Rietveld, and these +workflow changes are not expected to require any significant changes in +Roundup or Buildbot). + + +Acknowledgements +================ + +Thanks to Jesse Noller, Alex Gaynor and James Blair for providing valuable +feedback on a preliminary draft of this proposal. + + +Copyright +========= + +This document has been placed in the public domain. + +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + coding: utf-8 + End: -- Repository URL: http://hg.python.org/peps From solipsis at pitrou.net Sat Jan 25 09:38:20 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 25 Jan 2014 09:38:20 +0100 Subject: [Python-checkins] Daily reference leaks (c6e529c1f87c): sum=4 Message-ID: results for c6e529c1f87c on branch "default" -------------------------------------------- test_httplib leaked [-1, 1, 0] references, sum=0 test_site leaked [0, 2, 0] references, sum=2 test_site leaked [0, 2, 0] memory blocks, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogKaQIME', '-x'] From python-checkins at python.org Sat Jan 25 10:22:15 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 25 Jan 2014 10:22:15 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320151=3A_The_bina?= =?utf-8?q?scii_module_now_uses_Argument_Clinic=2E?= Message-ID: <3fBBZH5t9yzSwb@mail.python.org> http://hg.python.org/cpython/rev/21f8abfe459a changeset: 88684:21f8abfe459a user: Serhiy Storchaka date: Sat Jan 25 11:21:23 2014 +0200 summary: Issue #20151: The binascii module now uses Argument Clinic. files: Modules/binascii.c | 601 +++++++++++++------------ Modules/binascii.clinic.c | 429 ++++++++++++++++++ 2 files changed, 736 insertions(+), 294 deletions(-) diff --git a/Modules/binascii.c b/Modules/binascii.c --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -183,6 +183,22 @@ 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, }; +/*[clinic input] +output preset file +module binascii +[clinic start generated code]*/ +/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + +/*[python input] + +class ascii_buffer_converter(CConverter): + type = 'Py_buffer' + converter = 'ascii_buffer_converter' + impl_by_reference = True + +[python start generated code]*/ +/*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + static int ascii_buffer_converter(PyObject *arg, Py_buffer *buf) { @@ -220,13 +236,21 @@ return Py_CLEANUP_SUPPORTED; } +#include "binascii.clinic.c" -PyDoc_STRVAR(doc_a2b_uu, "(ascii) -> bin. Decode a line of uuencoded data"); +/*[clinic input] +binascii.a2b_uu + + ascii: ascii_buffer + / + +Decode a line of uuencoded data. +[clinic start generated code]*/ static PyObject * -binascii_a2b_uu(PyObject *self, PyObject *args) +binascii_a2b_uu_impl(PyModuleDef *module, Py_buffer *ascii) +/*[clinic end generated code: checksum=3252d1dbb682979eee03fb2c0c48a4d98a229df4]*/ { - Py_buffer pascii; unsigned char *ascii_data, *bin_data; int leftbits = 0; unsigned char this_ch; @@ -234,10 +258,8 @@ PyObject *rv; Py_ssize_t ascii_len, bin_len; - if ( !PyArg_ParseTuple(args, "O&:a2b_uu", ascii_buffer_converter, &pascii) ) - return NULL; - ascii_data = pascii.buf; - ascii_len = pascii.len; + ascii_data = ascii->buf; + ascii_len = ascii->len; assert(ascii_len >= 0); @@ -246,10 +268,8 @@ ascii_len--; /* Allocate the buffer */ - if ( (rv=PyBytes_FromStringAndSize(NULL, bin_len)) == NULL ) { - PyBuffer_Release(&pascii); + if ( (rv=PyBytes_FromStringAndSize(NULL, bin_len)) == NULL ) return NULL; - } bin_data = (unsigned char *)PyBytes_AS_STRING(rv); for( ; bin_len > 0 ; ascii_len--, ascii_data++ ) { @@ -269,7 +289,6 @@ */ if ( this_ch < ' ' || this_ch > (' ' + 64)) { PyErr_SetString(Error, "Illegal char"); - PyBuffer_Release(&pascii); Py_DECREF(rv); return NULL; } @@ -298,21 +317,26 @@ if ( this_ch != ' ' && this_ch != ' '+64 && this_ch != '\n' && this_ch != '\r' ) { PyErr_SetString(Error, "Trailing garbage"); - PyBuffer_Release(&pascii); Py_DECREF(rv); return NULL; } } - PyBuffer_Release(&pascii); return rv; } -PyDoc_STRVAR(doc_b2a_uu, "(bin) -> ascii. Uuencode line of data"); +/*[clinic input] +binascii.b2a_uu + + data: Py_buffer + / + +Uuencode line of data. +[clinic start generated code]*/ static PyObject * -binascii_b2a_uu(PyObject *self, PyObject *args) +binascii_b2a_uu_impl(PyModuleDef *module, Py_buffer *data) +/*[clinic end generated code: checksum=181021b69bb9a4149fffa98aa3ed57b59ffa38cb]*/ { - Py_buffer pbin; unsigned char *ascii_data, *bin_data; int leftbits = 0; unsigned char this_ch; @@ -320,22 +344,17 @@ PyObject *rv; Py_ssize_t bin_len; - if ( !PyArg_ParseTuple(args, "y*:b2a_uu", &pbin) ) - return NULL; - bin_data = pbin.buf; - bin_len = pbin.len; + bin_data = data->buf; + bin_len = data->len; if ( bin_len > 45 ) { /* The 45 is a limit that appears in all uuencode's */ PyErr_SetString(Error, "At most 45 bytes at once"); - PyBuffer_Release(&pbin); return NULL; } /* We're lazy and allocate to much (fixed up later) */ - if ( (rv=PyBytes_FromStringAndSize(NULL, 2 + (bin_len+2)/3*4)) == NULL ) { - PyBuffer_Release(&pbin); + if ( (rv=PyBytes_FromStringAndSize(NULL, 2 + (bin_len+2)/3*4)) == NULL ) return NULL; - } ascii_data = (unsigned char *)PyBytes_AS_STRING(rv); /* Store the length */ @@ -363,7 +382,6 @@ (unsigned char *)PyBytes_AS_STRING(rv))) < 0) { Py_CLEAR(rv); } - PyBuffer_Release(&pbin); return rv; } @@ -393,12 +411,19 @@ return ret; } -PyDoc_STRVAR(doc_a2b_base64, "(ascii) -> bin. Decode a line of base64 data"); +/*[clinic input] +binascii.a2b_base64 + + ascii: ascii_buffer + / + +Decode a line of base64 data. +[clinic start generated code]*/ static PyObject * -binascii_a2b_base64(PyObject *self, PyObject *args) +binascii_a2b_base64_impl(PyModuleDef *module, Py_buffer *ascii) +/*[clinic end generated code: checksum=73c265f87068c1f3e4bc01834ae6ac5a974143b4]*/ { - Py_buffer pascii; unsigned char *ascii_data, *bin_data; int leftbits = 0; unsigned char this_ch; @@ -407,25 +432,19 @@ Py_ssize_t ascii_len, bin_len; int quad_pos = 0; - if ( !PyArg_ParseTuple(args, "O&:a2b_base64", ascii_buffer_converter, &pascii) ) - return NULL; - ascii_data = pascii.buf; - ascii_len = pascii.len; + ascii_data = ascii->buf; + ascii_len = ascii->len; assert(ascii_len >= 0); - if (ascii_len > PY_SSIZE_T_MAX - 3) { - PyBuffer_Release(&pascii); + if (ascii_len > PY_SSIZE_T_MAX - 3) return PyErr_NoMemory(); - } bin_len = ((ascii_len+3)/4)*3; /* Upper bound, corrected later */ /* Allocate the buffer */ - if ( (rv=PyBytes_FromStringAndSize(NULL, bin_len)) == NULL ) { - PyBuffer_Release(&pascii); + if ( (rv=PyBytes_FromStringAndSize(NULL, bin_len)) == NULL ) return NULL; - } bin_data = (unsigned char *)PyBytes_AS_STRING(rv); bin_len = 0; @@ -478,7 +497,6 @@ } if (leftbits != 0) { - PyBuffer_Release(&pascii); PyErr_SetString(Error, "Incorrect padding"); Py_DECREF(rv); return NULL; @@ -497,16 +515,23 @@ Py_DECREF(rv); rv = PyBytes_FromStringAndSize("", 0); } - PyBuffer_Release(&pascii); return rv; } -PyDoc_STRVAR(doc_b2a_base64, "(bin) -> ascii. Base64-code line of data"); + +/*[clinic input] +binascii.b2a_base64 + + data: Py_buffer + / + +Base64-code line of data. +[clinic start generated code]*/ static PyObject * -binascii_b2a_base64(PyObject *self, PyObject *args) +binascii_b2a_base64_impl(PyModuleDef *module, Py_buffer *data) +/*[clinic end generated code: checksum=3cd61fbee2913285e253bc5415c9d052b0c5dd96]*/ { - Py_buffer pbuf; unsigned char *ascii_data, *bin_data; int leftbits = 0; unsigned char this_ch; @@ -514,26 +539,21 @@ PyObject *rv; Py_ssize_t bin_len; - if ( !PyArg_ParseTuple(args, "y*:b2a_base64", &pbuf) ) - return NULL; - bin_data = pbuf.buf; - bin_len = pbuf.len; + bin_data = data->buf; + bin_len = data->len; assert(bin_len >= 0); if ( bin_len > BASE64_MAXBIN ) { PyErr_SetString(Error, "Too much data for base64 line"); - PyBuffer_Release(&pbuf); return NULL; } /* We're lazy and allocate too much (fixed up later). "+3" leaves room for up to two pad characters and a trailing newline. Note that 'b' gets encoded as 'Yg==\n' (1 in, 5 out). */ - if ( (rv=PyBytes_FromStringAndSize(NULL, bin_len*2 + 3)) == NULL ) { - PyBuffer_Release(&pbuf); + if ( (rv=PyBytes_FromStringAndSize(NULL, bin_len*2 + 3)) == NULL ) return NULL; - } ascii_data = (unsigned char *)PyBytes_AS_STRING(rv); for( ; bin_len > 0 ; bin_len--, bin_data++ ) { @@ -563,16 +583,22 @@ (unsigned char *)PyBytes_AS_STRING(rv))) < 0) { Py_CLEAR(rv); } - PyBuffer_Release(&pbuf); return rv; } -PyDoc_STRVAR(doc_a2b_hqx, "ascii -> bin, done. Decode .hqx coding"); +/*[clinic input] +binascii.a2b_hqx + + ascii: ascii_buffer + / + +Decode .hqx coding. +[clinic start generated code]*/ static PyObject * -binascii_a2b_hqx(PyObject *self, PyObject *args) +binascii_a2b_hqx_impl(PyModuleDef *module, Py_buffer *ascii) +/*[clinic end generated code: checksum=48075dc4017b66f93086386d5b5848f1e6af260c]*/ { - Py_buffer pascii; unsigned char *ascii_data, *bin_data; int leftbits = 0; unsigned char this_ch; @@ -581,25 +607,19 @@ Py_ssize_t len; int done = 0; - if ( !PyArg_ParseTuple(args, "O&:a2b_hqx", ascii_buffer_converter, &pascii) ) - return NULL; - ascii_data = pascii.buf; - len = pascii.len; + ascii_data = ascii->buf; + len = ascii->len; assert(len >= 0); - if (len > PY_SSIZE_T_MAX - 2) { - PyBuffer_Release(&pascii); + if (len > PY_SSIZE_T_MAX - 2) return PyErr_NoMemory(); - } /* Allocate a string that is too big (fixed later) Add two to the initial length to prevent interning which would preclude subsequent resizing. */ - if ( (rv=PyBytes_FromStringAndSize(NULL, len+2)) == NULL ) { - PyBuffer_Release(&pascii); + if ( (rv=PyBytes_FromStringAndSize(NULL, len+2)) == NULL ) return NULL; - } bin_data = (unsigned char *)PyBytes_AS_STRING(rv); for( ; len > 0 ; len--, ascii_data++ ) { @@ -609,7 +629,6 @@ continue; if ( this_ch == FAIL ) { PyErr_SetString(Error, "Illegal char"); - PyBuffer_Release(&pascii); Py_DECREF(rv); return NULL; } @@ -632,7 +651,6 @@ if ( leftbits && !done ) { PyErr_SetString(Incomplete, "String has incomplete number of bytes"); - PyBuffer_Release(&pascii); Py_DECREF(rv); return NULL; } @@ -643,43 +661,43 @@ } if (rv) { PyObject *rrv = Py_BuildValue("Oi", rv, done); - PyBuffer_Release(&pascii); Py_DECREF(rv); return rrv; } - PyBuffer_Release(&pascii); return NULL; } -PyDoc_STRVAR(doc_rlecode_hqx, "Binhex RLE-code binary data"); + +/*[clinic input] +binascii.rlecode_hqx + + data: Py_buffer + / + +Binhex RLE-code binary data. +[clinic start generated code]*/ static PyObject * -binascii_rlecode_hqx(PyObject *self, PyObject *args) +binascii_rlecode_hqx_impl(PyModuleDef *module, Py_buffer *data) +/*[clinic end generated code: checksum=0905da344dbf064855925c3a0fb83ec11ca33e8b]*/ { - Py_buffer pbuf; unsigned char *in_data, *out_data; PyObject *rv; unsigned char ch; Py_ssize_t in, inend, len; - if ( !PyArg_ParseTuple(args, "y*:rlecode_hqx", &pbuf) ) - return NULL; - in_data = pbuf.buf; - len = pbuf.len; + in_data = data->buf; + len = data->len; assert(len >= 0); - if (len > PY_SSIZE_T_MAX / 2 - 2) { - PyBuffer_Release(&pbuf); + if (len > PY_SSIZE_T_MAX / 2 - 2) return PyErr_NoMemory(); - } /* Worst case: output is twice as big as input (fixed later) */ - if ( (rv=PyBytes_FromStringAndSize(NULL, len*2+2)) == NULL ) { - PyBuffer_Release(&pbuf); + if ( (rv=PyBytes_FromStringAndSize(NULL, len*2+2)) == NULL ) return NULL; - } out_data = (unsigned char *)PyBytes_AS_STRING(rv); for( in=0; inbuf; + len = data->len; assert(len >= 0); - if (len > PY_SSIZE_T_MAX / 2 - 2) { - PyBuffer_Release(&pbin); + if (len > PY_SSIZE_T_MAX / 2 - 2) return PyErr_NoMemory(); - } /* Allocate a buffer that is at least large enough */ - if ( (rv=PyBytes_FromStringAndSize(NULL, len*2+2)) == NULL ) { - PyBuffer_Release(&pbin); + if ( (rv=PyBytes_FromStringAndSize(NULL, len*2+2)) == NULL ) return NULL; - } ascii_data = (unsigned char *)PyBytes_AS_STRING(rv); for( ; len > 0 ; len--, bin_data++ ) { @@ -767,44 +786,43 @@ (unsigned char *)PyBytes_AS_STRING(rv))) < 0) { Py_CLEAR(rv); } - PyBuffer_Release(&pbin); return rv; } -PyDoc_STRVAR(doc_rledecode_hqx, "Decode hexbin RLE-coded string"); + +/*[clinic input] +binascii.rledecode_hqx + + data: Py_buffer + / + +Decode hexbin RLE-coded string. +[clinic start generated code]*/ static PyObject * -binascii_rledecode_hqx(PyObject *self, PyObject *args) +binascii_rledecode_hqx_impl(PyModuleDef *module, Py_buffer *data) +/*[clinic end generated code: checksum=f7afd89b789946ab50e31d595c695d5cad7e27e3]*/ { - Py_buffer pin; unsigned char *in_data, *out_data; unsigned char in_byte, in_repeat; PyObject *rv; Py_ssize_t in_len, out_len, out_len_left; - if ( !PyArg_ParseTuple(args, "y*:rledecode_hqx", &pin) ) - return NULL; - in_data = pin.buf; - in_len = pin.len; + in_data = data->buf; + in_len = data->len; assert(in_len >= 0); /* Empty string is a special case */ - if ( in_len == 0 ) { - PyBuffer_Release(&pin); + if ( in_len == 0 ) return PyBytes_FromStringAndSize("", 0); - } - else if (in_len > PY_SSIZE_T_MAX / 2) { - PyBuffer_Release(&pin); + else if (in_len > PY_SSIZE_T_MAX / 2) return PyErr_NoMemory(); - } /* Allocate a buffer of reasonable size. Resized when needed */ out_len = in_len*2; - if ( (rv=PyBytes_FromStringAndSize(NULL, out_len)) == NULL ) { - PyBuffer_Release(&pin); + if ( (rv=PyBytes_FromStringAndSize(NULL, out_len)) == NULL ) return NULL; - } out_len_left = out_len; out_data = (unsigned char *)PyBytes_AS_STRING(rv); @@ -817,7 +835,6 @@ if ( --in_len < 0 ) { \ PyErr_SetString(Incomplete, ""); \ Py_DECREF(rv); \ - PyBuffer_Release(&pin); \ return NULL; \ } \ b = *in_data++; \ @@ -828,7 +845,7 @@ if ( --out_len_left < 0 ) { \ if ( out_len > PY_SSIZE_T_MAX / 2) return PyErr_NoMemory(); \ if (_PyBytes_Resize(&rv, 2*out_len) < 0) \ - { Py_XDECREF(rv); PyBuffer_Release(&pin); return NULL; } \ + { Py_XDECREF(rv); return NULL; } \ out_data = (unsigned char *)PyBytes_AS_STRING(rv) \ + out_len; \ out_len_left = out_len-1; \ @@ -850,7 +867,6 @@ ** of the string only). This is a programmer error. */ PyErr_SetString(Error, "Orphaned RLE code at start"); - PyBuffer_Release(&pin); Py_DECREF(rv); return NULL; } @@ -883,57 +899,39 @@ (unsigned char *)PyBytes_AS_STRING(rv))) < 0) { Py_CLEAR(rv); } - PyBuffer_Release(&pin); return rv; } -PyDoc_STRVAR(doc_crc_hqx, -"(data, oldcrc) -> newcrc. Compute hqx CRC incrementally"); -static PyObject * -binascii_crc_hqx(PyObject *self, PyObject *args) +/*[clinic input] +binascii.crc_hqx -> int + + data: Py_buffer + crc: int + / + +Compute hqx CRC incrementally. +[clinic start generated code]*/ + +static int +binascii_crc_hqx_impl(PyModuleDef *module, Py_buffer *data, int crc) +/*[clinic end generated code: checksum=634dac18dfa863d738833b5a0886eca93c034c0c]*/ { - Py_buffer pin; unsigned char *bin_data; - unsigned int crc; + unsigned int ucrc = (unsigned int)crc; Py_ssize_t len; - if ( !PyArg_ParseTuple(args, "y*i:crc_hqx", &pin, &crc) ) - return NULL; - bin_data = pin.buf; - len = pin.len; + bin_data = data->buf; + len = data->len; while(len-- > 0) { - crc=((crc<<8)&0xff00)^crctab_hqx[((crc>>8)&0xff)^*bin_data++]; + ucrc=((ucrc<<8)&0xff00)^crctab_hqx[((ucrc>>8)&0xff)^*bin_data++]; } - PyBuffer_Release(&pin); - return Py_BuildValue("i", crc); + return (int)ucrc; } -PyDoc_STRVAR(doc_crc32, -"(data, oldcrc = 0) -> newcrc. Compute CRC-32 incrementally"); - -#ifdef USE_ZLIB_CRC32 -/* This was taken from zlibmodule.c PyZlib_crc32 (but is PY_SSIZE_T_CLEAN) */ -static PyObject * -binascii_crc32(PyObject *self, PyObject *args) -{ - unsigned int crc32val = 0; /* crc32(0L, Z_NULL, 0) */ - Py_buffer pbuf; - Byte *buf; - Py_ssize_t len; - int signed_val; - - if (!PyArg_ParseTuple(args, "y*|I:crc32", &pbuf, &crc32val)) - return NULL; - buf = (Byte*)pbuf.buf; - len = pbuf.len; - signed_val = crc32(crc32val, buf, len); - PyBuffer_Release(&pbuf); - return PyLong_FromUnsignedLong(signed_val & 0xffffffffU); -} -#else /* USE_ZLIB_CRC32 */ +#ifndef USE_ZLIB_CRC32 /* Crc - 32 BIT ANSI X3.66 CRC checksum files Also known as: ISO 3307 **********************************************************************| @@ -1051,20 +1049,42 @@ 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU, 0x2d02ef8dU }; +#endif /* USE_ZLIB_CRC32 */ -static PyObject * -binascii_crc32(PyObject *self, PyObject *args) +/*[clinic input] +binascii.crc32 -> unsigned_int + + data: Py_buffer + crc: unsigned_int(bitwise=True) = 0 + / + +Compute CRC-32 incrementally. +[clinic start generated code]*/ + +static unsigned int +binascii_crc32_impl(PyModuleDef *module, Py_buffer *data, unsigned int crc) +/*[clinic end generated code: checksum=620a961643393c4f2a1fb273fda2acb43970c3f5]*/ + +#ifdef USE_ZLIB_CRC32 +/* This was taken from zlibmodule.c PyZlib_crc32 (but is PY_SSIZE_T_CLEAN) */ +{ + Byte *buf; + Py_ssize_t len; + int signed_val; + + buf = (Byte*)data->buf; + len = data->len; + signed_val = crc32(crc, buf, len); + return (unsigned int)signed_val & 0xffffffffU; +} +#else /* USE_ZLIB_CRC32 */ { /* By Jim Ahlstrom; All rights transferred to CNRI */ - Py_buffer pbin; unsigned char *bin_data; - unsigned int crc = 0; /* initial value of CRC */ Py_ssize_t len; unsigned int result; - if ( !PyArg_ParseTuple(args, "y*|I:crc32", &pbin, &crc) ) - return NULL; - bin_data = pbin.buf; - len = pbin.len; + bin_data = data->buf; + len = data->len; crc = ~ crc; while (len-- > 0) { @@ -1073,38 +1093,42 @@ } result = (crc ^ 0xFFFFFFFF); - PyBuffer_Release(&pbin); - return PyLong_FromUnsignedLong(result & 0xffffffff); + return result & 0xffffffff; } #endif /* USE_ZLIB_CRC32 */ +/*[clinic input] +binascii.b2a_hex + + data: Py_buffer + / + +Hexadecimal representation of binary data. + +The return value is a bytes object. This function is also +available as "hexlify()". +[clinic start generated code]*/ static PyObject * -binascii_hexlify(PyObject *self, PyObject *args) +binascii_b2a_hex_impl(PyModuleDef *module, Py_buffer *data) +/*[clinic end generated code: checksum=179318922c2f8fdaee0d4d3283758aec8e8741a5]*/ { - Py_buffer parg; char* argbuf; Py_ssize_t arglen; PyObject *retval; char* retbuf; Py_ssize_t i, j; - if (!PyArg_ParseTuple(args, "y*:b2a_hex", &parg)) - return NULL; - argbuf = parg.buf; - arglen = parg.len; + argbuf = data->buf; + arglen = data->len; assert(arglen >= 0); - if (arglen > PY_SSIZE_T_MAX / 2) { - PyBuffer_Release(&parg); + if (arglen > PY_SSIZE_T_MAX / 2) return PyErr_NoMemory(); - } retval = PyBytes_FromStringAndSize(NULL, arglen*2); - if (!retval) { - PyBuffer_Release(&parg); + if (!retval) return NULL; - } retbuf = PyBytes_AS_STRING(retval); /* make hex version of string, taken from shamodule.c */ @@ -1115,16 +1139,9 @@ c = argbuf[i] & 0xf; retbuf[j++] = Py_hexdigits[c]; } - PyBuffer_Release(&parg); return retval; } -PyDoc_STRVAR(doc_hexlify, -"b2a_hex(data) -> s; Hexadecimal representation of binary data.\n\ -\n\ -The return value is a bytes object. This function is also\n\ -available as \"hexlify()\"."); - static int to_int(int c) @@ -1141,20 +1158,30 @@ } +/*[clinic input] +binascii.a2b_hex + + hexstr: ascii_buffer + / + +Binary data of hexadecimal representation. + +hexstr must contain an even number of hex digits (upper or lower case). +This function is also available as "unhexlify()". +[clinic start generated code]*/ + static PyObject * -binascii_unhexlify(PyObject *self, PyObject *args) +binascii_a2b_hex_impl(PyModuleDef *module, Py_buffer *hexstr) +/*[clinic end generated code: checksum=d61da452b5c6d2903c32c3e90e6a97221b25989b]*/ { - Py_buffer parg; char* argbuf; Py_ssize_t arglen; PyObject *retval; char* retbuf; Py_ssize_t i, j; - if (!PyArg_ParseTuple(args, "O&:a2b_hex", ascii_buffer_converter, &parg)) - return NULL; - argbuf = parg.buf; - arglen = parg.len; + argbuf = hexstr->buf; + arglen = hexstr->len; assert(arglen >= 0); @@ -1163,16 +1190,13 @@ * raise an exception. */ if (arglen % 2) { - PyBuffer_Release(&parg); PyErr_SetString(Error, "Odd-length string"); return NULL; } retval = PyBytes_FromStringAndSize(NULL, (arglen/2)); - if (!retval) { - PyBuffer_Release(&parg); + if (!retval) return NULL; - } retbuf = PyBytes_AS_STRING(retval); for (i=j=0; i < arglen; i += 2) { @@ -1185,21 +1209,13 @@ } retbuf[j++] = (top << 4) + bot; } - PyBuffer_Release(&parg); return retval; finally: - PyBuffer_Release(&parg); Py_DECREF(retval); return NULL; } -PyDoc_STRVAR(doc_unhexlify, -"a2b_hex(hexstr) -> s; Binary data of hexadecimal representation.\n\ -\n\ -hexstr must contain an even number of hex digits (upper or lower case).\n\ -This function is also available as \"unhexlify()\""); - static int table_hex[128] = { -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, @@ -1215,25 +1231,29 @@ #define MAXLINESIZE 76 -PyDoc_STRVAR(doc_a2b_qp, "Decode a string of qp-encoded data"); -static PyObject* -binascii_a2b_qp(PyObject *self, PyObject *args, PyObject *kwargs) +/*[clinic input] +binascii.a2b_qp + + ascii: ascii_buffer + header: int(c_default="0") = False + / + +Decode a string of qp-encoded data. +[clinic start generated code]*/ + +static PyObject * +binascii_a2b_qp_impl(PyModuleDef *module, Py_buffer *ascii, int header) +/*[clinic end generated code: checksum=33910d5b347bf9f33203769e649f35ea41694b71]*/ { Py_ssize_t in, out; char ch; - Py_buffer pdata; unsigned char *data, *odata; Py_ssize_t datalen = 0; PyObject *rv; - static char *kwlist[] = {"data", "header", NULL}; - int header = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|i:a2b_qp", kwlist, - ascii_buffer_converter, &pdata, &header)) - return NULL; - data = pdata.buf; - datalen = pdata.len; + data = ascii->buf; + datalen = ascii->len; /* We allocate the output same size as input, this is overkill. * The previous implementation used calloc() so we'll zero out the @@ -1241,7 +1261,6 @@ */ odata = (unsigned char *) PyMem_Malloc(datalen); if (odata == NULL) { - PyBuffer_Release(&pdata); PyErr_NoMemory(); return NULL; } @@ -1292,11 +1311,9 @@ } } if ((rv = PyBytes_FromStringAndSize((char *)odata, out)) == NULL) { - PyBuffer_Release(&pdata); PyMem_Free(odata); return NULL; } - PyBuffer_Release(&pdata); PyMem_Free(odata); return rv; } @@ -1312,62 +1329,62 @@ return 0; } -PyDoc_STRVAR(doc_b2a_qp, -"b2a_qp(data, quotetabs=0, istext=1, header=0) -> s; \n\ - Encode a string using quoted-printable encoding. \n\ -\n\ -On encoding, when istext is set, newlines are not encoded, and white \n\ -space at end of lines is. When istext is not set, \\r and \\n (CR/LF) are \n\ -both encoded. When quotetabs is set, space and tabs are encoded."); - /* XXX: This is ridiculously complicated to be backward compatible * (mostly) with the quopri module. It doesn't re-create the quopri * module bug where text ending in CRLF has the CR encoded */ -static PyObject* -binascii_b2a_qp (PyObject *self, PyObject *args, PyObject *kwargs) + +/*[clinic input] +binascii.b2a_qp + + data: Py_buffer + quotetabs: int(c_default="0") = False + istext: int(c_default="1") = True + header: int(c_default="0") = False + +Encode a string using quoted-printable encoding. + +On encoding, when istext is set, newlines are not encoded, and white +space at end of lines is. When istext is not set, \r and \n (CR/LF) +are both encoded. When quotetabs is set, space and tabs are encoded. +[clinic start generated code]*/ + +static PyObject * +binascii_b2a_qp_impl(PyModuleDef *module, Py_buffer *data, int quotetabs, int istext, int header) +/*[clinic end generated code: checksum=ff2991ba640fff3e67ac63205801c7173a0366cd]*/ { Py_ssize_t in, out; - Py_buffer pdata; - unsigned char *data, *odata; + unsigned char *databuf, *odata; Py_ssize_t datalen = 0, odatalen = 0; PyObject *rv; unsigned int linelen = 0; - static char *kwlist[] = {"data", "quotetabs", "istext", - "header", NULL}; - int istext = 1; - int quotetabs = 0; - int header = 0; unsigned char ch; int crlf = 0; unsigned char *p; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y*|iii", kwlist, &pdata, - "etabs, &istext, &header)) - return NULL; - data = pdata.buf; - datalen = pdata.len; + databuf = data->buf; + datalen = data->len; /* See if this string is using CRLF line ends */ /* XXX: this function has the side effect of converting all of * the end of lines to be the same depending on this detection * here */ - p = (unsigned char *) memchr(data, '\n', datalen); - if ((p != NULL) && (p > data) && (*(p-1) == '\r')) + p = (unsigned char *) memchr(databuf, '\n', datalen); + if ((p != NULL) && (p > databuf) && (*(p-1) == '\r')) crlf = 1; /* First, scan to see how many characters need to be encoded */ in = 0; while (in < datalen) { - if ((data[in] > 126) || - (data[in] == '=') || - (header && data[in] == '_') || - ((data[in] == '.') && (linelen == 0) && - (data[in+1] == '\n' || data[in+1] == '\r' || data[in+1] == 0)) || - (!istext && ((data[in] == '\r') || (data[in] == '\n'))) || - ((data[in] == '\t' || data[in] == ' ') && (in + 1 == datalen)) || - ((data[in] < 33) && - (data[in] != '\r') && (data[in] != '\n') && - (quotetabs || ((data[in] != '\t') && (data[in] != ' '))))) + if ((databuf[in] > 126) || + (databuf[in] == '=') || + (header && databuf[in] == '_') || + ((databuf[in] == '.') && (linelen == 0) && + (databuf[in+1] == '\n' || databuf[in+1] == '\r' || databuf[in+1] == 0)) || + (!istext && ((databuf[in] == '\r') || (databuf[in] == '\n'))) || + ((databuf[in] == '\t' || databuf[in] == ' ') && (in + 1 == datalen)) || + ((databuf[in] < 33) && + (databuf[in] != '\r') && (databuf[in] != '\n') && + (quotetabs || ((databuf[in] != '\t') && (databuf[in] != ' '))))) { if ((linelen + 3) >= MAXLINESIZE) { linelen = 0; @@ -1382,26 +1399,26 @@ } else { if (istext && - ((data[in] == '\n') || - ((in+1 < datalen) && (data[in] == '\r') && - (data[in+1] == '\n')))) + ((databuf[in] == '\n') || + ((in+1 < datalen) && (databuf[in] == '\r') && + (databuf[in+1] == '\n')))) { linelen = 0; /* Protect against whitespace on end of line */ - if (in && ((data[in-1] == ' ') || (data[in-1] == '\t'))) + if (in && ((databuf[in-1] == ' ') || (databuf[in-1] == '\t'))) odatalen += 2; if (crlf) odatalen += 2; else odatalen += 1; - if (data[in] == '\r') + if (databuf[in] == '\r') in += 2; else in++; } else { if ((in + 1 != datalen) && - (data[in+1] != '\n') && + (databuf[in+1] != '\n') && (linelen + 1) >= MAXLINESIZE) { linelen = 0; if (crlf) @@ -1422,7 +1439,6 @@ */ odata = (unsigned char *) PyMem_Malloc(odatalen); if (odata == NULL) { - PyBuffer_Release(&pdata); PyErr_NoMemory(); return NULL; } @@ -1430,17 +1446,17 @@ in = out = linelen = 0; while (in < datalen) { - if ((data[in] > 126) || - (data[in] == '=') || - (header && data[in] == '_') || - ((data[in] == '.') && (linelen == 0) && - (data[in+1] == '\n' || data[in+1] == '\r' || data[in+1] == 0)) || - (!istext && ((data[in] == '\r') || (data[in] == '\n'))) || - ((data[in] == '\t' || data[in] == ' ') && (in + 1 == datalen)) || - ((data[in] < 33) && - (data[in] != '\r') && (data[in] != '\n') && + if ((databuf[in] > 126) || + (databuf[in] == '=') || + (header && databuf[in] == '_') || + ((databuf[in] == '.') && (linelen == 0) && + (databuf[in+1] == '\n' || databuf[in+1] == '\r' || databuf[in+1] == 0)) || + (!istext && ((databuf[in] == '\r') || (databuf[in] == '\n'))) || + ((databuf[in] == '\t' || databuf[in] == ' ') && (in + 1 == datalen)) || + ((databuf[in] < 33) && + (databuf[in] != '\r') && (databuf[in] != '\n') && (quotetabs || - (!quotetabs && ((data[in] != '\t') && (data[in] != ' ')))))) + (!quotetabs && ((databuf[in] != '\t') && (databuf[in] != ' ')))))) { if ((linelen + 3 )>= MAXLINESIZE) { odata[out++] = '='; @@ -1449,16 +1465,16 @@ linelen = 0; } odata[out++] = '='; - to_hex(data[in], &odata[out]); + to_hex(databuf[in], &odata[out]); out += 2; in++; linelen += 3; } else { if (istext && - ((data[in] == '\n') || - ((in+1 < datalen) && (data[in] == '\r') && - (data[in+1] == '\n')))) + ((databuf[in] == '\n') || + ((in+1 < datalen) && (databuf[in] == '\r') && + (databuf[in+1] == '\n')))) { linelen = 0; /* Protect against whitespace on end of line */ @@ -1471,14 +1487,14 @@ if (crlf) odata[out++] = '\r'; odata[out++] = '\n'; - if (data[in] == '\r') + if (databuf[in] == '\r') in += 2; else in++; } else { if ((in + 1 != datalen) && - (data[in+1] != '\n') && + (databuf[in+1] != '\n') && (linelen + 1) >= MAXLINESIZE) { odata[out++] = '='; if (crlf) odata[out++] = '\r'; @@ -1486,22 +1502,20 @@ linelen = 0; } linelen++; - if (header && data[in] == ' ') { + if (header && databuf[in] == ' ') { odata[out++] = '_'; in++; } else { - odata[out++] = data[in++]; + odata[out++] = databuf[in++]; } } } } if ((rv = PyBytes_FromStringAndSize((char *)odata, out)) == NULL) { - PyBuffer_Release(&pdata); PyMem_Free(odata); return NULL; } - PyBuffer_Release(&pdata); PyMem_Free(odata); return rv; } @@ -1509,25 +1523,24 @@ /* List of functions defined in the module */ static struct PyMethodDef binascii_module_methods[] = { - {"a2b_uu", binascii_a2b_uu, METH_VARARGS, doc_a2b_uu}, - {"b2a_uu", binascii_b2a_uu, METH_VARARGS, doc_b2a_uu}, - {"a2b_base64", binascii_a2b_base64, METH_VARARGS, doc_a2b_base64}, - {"b2a_base64", binascii_b2a_base64, METH_VARARGS, doc_b2a_base64}, - {"a2b_hqx", binascii_a2b_hqx, METH_VARARGS, doc_a2b_hqx}, - {"b2a_hqx", binascii_b2a_hqx, METH_VARARGS, doc_b2a_hqx}, - {"b2a_hex", binascii_hexlify, METH_VARARGS, doc_hexlify}, - {"a2b_hex", binascii_unhexlify, METH_VARARGS, doc_unhexlify}, - {"hexlify", binascii_hexlify, METH_VARARGS, doc_hexlify}, - {"unhexlify", binascii_unhexlify, METH_VARARGS, doc_unhexlify}, - {"rlecode_hqx", binascii_rlecode_hqx, METH_VARARGS, doc_rlecode_hqx}, - {"rledecode_hqx", binascii_rledecode_hqx, METH_VARARGS, - doc_rledecode_hqx}, - {"crc_hqx", binascii_crc_hqx, METH_VARARGS, doc_crc_hqx}, - {"crc32", binascii_crc32, METH_VARARGS, doc_crc32}, - {"a2b_qp", (PyCFunction)binascii_a2b_qp, METH_VARARGS | METH_KEYWORDS, - doc_a2b_qp}, - {"b2a_qp", (PyCFunction)binascii_b2a_qp, METH_VARARGS | METH_KEYWORDS, - doc_b2a_qp}, + BINASCII_A2B_UU_METHODDEF + BINASCII_B2A_UU_METHODDEF + BINASCII_A2B_BASE64_METHODDEF + BINASCII_B2A_BASE64_METHODDEF + BINASCII_A2B_HQX_METHODDEF + BINASCII_B2A_HQX_METHODDEF + BINASCII_A2B_HEX_METHODDEF + BINASCII_B2A_HEX_METHODDEF + {"unhexlify", (PyCFunction)binascii_a2b_hex, METH_VARARGS, + binascii_a2b_hex__doc__}, + {"hexlify", (PyCFunction)binascii_b2a_hex, METH_VARARGS, + binascii_b2a_hex__doc__}, + BINASCII_RLECODE_HQX_METHODDEF + BINASCII_RLEDECODE_HQX_METHODDEF + BINASCII_CRC_HQX_METHODDEF + BINASCII_CRC32_METHODDEF + BINASCII_A2B_QP_METHODDEF + BINASCII_B2A_QP_METHODDEF {NULL, NULL} /* sentinel */ }; diff --git a/Modules/binascii.clinic.c b/Modules/binascii.clinic.c new file mode 100644 --- /dev/null +++ b/Modules/binascii.clinic.c @@ -0,0 +1,429 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(binascii_a2b_uu__doc__, +"a2b_uu(module, ascii)\n" +"Decode a line of uuencoded data."); + +#define BINASCII_A2B_UU_METHODDEF \ + {"a2b_uu", (PyCFunction)binascii_a2b_uu, METH_VARARGS, binascii_a2b_uu__doc__}, + +static PyObject * +binascii_a2b_uu_impl(PyModuleDef *module, Py_buffer *ascii); + +static PyObject * +binascii_a2b_uu(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer ascii; + + if (!PyArg_ParseTuple(args, + "O&:a2b_uu", + ascii_buffer_converter, &ascii)) + goto exit; + return_value = binascii_a2b_uu_impl(module, &ascii); + +exit: + return return_value; +} + +PyDoc_STRVAR(binascii_b2a_uu__doc__, +"b2a_uu(module, data)\n" +"Uuencode line of data."); + +#define BINASCII_B2A_UU_METHODDEF \ + {"b2a_uu", (PyCFunction)binascii_b2a_uu, METH_VARARGS, binascii_b2a_uu__doc__}, + +static PyObject * +binascii_b2a_uu_impl(PyModuleDef *module, Py_buffer *data); + +static PyObject * +binascii_b2a_uu(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + + if (!PyArg_ParseTuple(args, + "y*:b2a_uu", + &data)) + goto exit; + return_value = binascii_b2a_uu_impl(module, &data); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(binascii_a2b_base64__doc__, +"a2b_base64(module, ascii)\n" +"Decode a line of base64 data."); + +#define BINASCII_A2B_BASE64_METHODDEF \ + {"a2b_base64", (PyCFunction)binascii_a2b_base64, METH_VARARGS, binascii_a2b_base64__doc__}, + +static PyObject * +binascii_a2b_base64_impl(PyModuleDef *module, Py_buffer *ascii); + +static PyObject * +binascii_a2b_base64(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer ascii; + + if (!PyArg_ParseTuple(args, + "O&:a2b_base64", + ascii_buffer_converter, &ascii)) + goto exit; + return_value = binascii_a2b_base64_impl(module, &ascii); + +exit: + return return_value; +} + +PyDoc_STRVAR(binascii_b2a_base64__doc__, +"b2a_base64(module, data)\n" +"Base64-code line of data."); + +#define BINASCII_B2A_BASE64_METHODDEF \ + {"b2a_base64", (PyCFunction)binascii_b2a_base64, METH_VARARGS, binascii_b2a_base64__doc__}, + +static PyObject * +binascii_b2a_base64_impl(PyModuleDef *module, Py_buffer *data); + +static PyObject * +binascii_b2a_base64(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + + if (!PyArg_ParseTuple(args, + "y*:b2a_base64", + &data)) + goto exit; + return_value = binascii_b2a_base64_impl(module, &data); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(binascii_a2b_hqx__doc__, +"a2b_hqx(module, ascii)\n" +"Decode .hqx coding."); + +#define BINASCII_A2B_HQX_METHODDEF \ + {"a2b_hqx", (PyCFunction)binascii_a2b_hqx, METH_VARARGS, binascii_a2b_hqx__doc__}, + +static PyObject * +binascii_a2b_hqx_impl(PyModuleDef *module, Py_buffer *ascii); + +static PyObject * +binascii_a2b_hqx(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer ascii; + + if (!PyArg_ParseTuple(args, + "O&:a2b_hqx", + ascii_buffer_converter, &ascii)) + goto exit; + return_value = binascii_a2b_hqx_impl(module, &ascii); + +exit: + return return_value; +} + +PyDoc_STRVAR(binascii_rlecode_hqx__doc__, +"rlecode_hqx(module, data)\n" +"Binhex RLE-code binary data."); + +#define BINASCII_RLECODE_HQX_METHODDEF \ + {"rlecode_hqx", (PyCFunction)binascii_rlecode_hqx, METH_VARARGS, binascii_rlecode_hqx__doc__}, + +static PyObject * +binascii_rlecode_hqx_impl(PyModuleDef *module, Py_buffer *data); + +static PyObject * +binascii_rlecode_hqx(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + + if (!PyArg_ParseTuple(args, + "y*:rlecode_hqx", + &data)) + goto exit; + return_value = binascii_rlecode_hqx_impl(module, &data); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(binascii_b2a_hqx__doc__, +"b2a_hqx(module, data)\n" +"Encode .hqx data."); + +#define BINASCII_B2A_HQX_METHODDEF \ + {"b2a_hqx", (PyCFunction)binascii_b2a_hqx, METH_VARARGS, binascii_b2a_hqx__doc__}, + +static PyObject * +binascii_b2a_hqx_impl(PyModuleDef *module, Py_buffer *data); + +static PyObject * +binascii_b2a_hqx(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + + if (!PyArg_ParseTuple(args, + "y*:b2a_hqx", + &data)) + goto exit; + return_value = binascii_b2a_hqx_impl(module, &data); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(binascii_rledecode_hqx__doc__, +"rledecode_hqx(module, data)\n" +"Decode hexbin RLE-coded string."); + +#define BINASCII_RLEDECODE_HQX_METHODDEF \ + {"rledecode_hqx", (PyCFunction)binascii_rledecode_hqx, METH_VARARGS, binascii_rledecode_hqx__doc__}, + +static PyObject * +binascii_rledecode_hqx_impl(PyModuleDef *module, Py_buffer *data); + +static PyObject * +binascii_rledecode_hqx(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + + if (!PyArg_ParseTuple(args, + "y*:rledecode_hqx", + &data)) + goto exit; + return_value = binascii_rledecode_hqx_impl(module, &data); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(binascii_crc_hqx__doc__, +"crc_hqx(module, data, crc)\n" +"Compute hqx CRC incrementally."); + +#define BINASCII_CRC_HQX_METHODDEF \ + {"crc_hqx", (PyCFunction)binascii_crc_hqx, METH_VARARGS, binascii_crc_hqx__doc__}, + +static int +binascii_crc_hqx_impl(PyModuleDef *module, Py_buffer *data, int crc); + +static PyObject * +binascii_crc_hqx(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + int crc; + int _return_value; + + if (!PyArg_ParseTuple(args, + "y*i:crc_hqx", + &data, &crc)) + goto exit; + _return_value = binascii_crc_hqx_impl(module, &data, crc); + if ((_return_value == -1) && PyErr_Occurred()) + goto exit; + return_value = PyLong_FromLong((long)_return_value); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(binascii_crc32__doc__, +"crc32(module, data, crc=0)\n" +"Compute CRC-32 incrementally."); + +#define BINASCII_CRC32_METHODDEF \ + {"crc32", (PyCFunction)binascii_crc32, METH_VARARGS, binascii_crc32__doc__}, + +static unsigned int +binascii_crc32_impl(PyModuleDef *module, Py_buffer *data, unsigned int crc); + +static PyObject * +binascii_crc32(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + unsigned int crc = 0; + unsigned int _return_value; + + if (!PyArg_ParseTuple(args, + "y*|I:crc32", + &data, &crc)) + goto exit; + _return_value = binascii_crc32_impl(module, &data, crc); + if ((_return_value == -1) && PyErr_Occurred()) + goto exit; + return_value = PyLong_FromUnsignedLong((unsigned long)_return_value); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(binascii_b2a_hex__doc__, +"b2a_hex(module, data)\n" +"Hexadecimal representation of binary data.\n" +"\n" +"The return value is a bytes object. This function is also\n" +"available as \"hexlify()\"."); + +#define BINASCII_B2A_HEX_METHODDEF \ + {"b2a_hex", (PyCFunction)binascii_b2a_hex, METH_VARARGS, binascii_b2a_hex__doc__}, + +static PyObject * +binascii_b2a_hex_impl(PyModuleDef *module, Py_buffer *data); + +static PyObject * +binascii_b2a_hex(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + + if (!PyArg_ParseTuple(args, + "y*:b2a_hex", + &data)) + goto exit; + return_value = binascii_b2a_hex_impl(module, &data); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(binascii_a2b_hex__doc__, +"a2b_hex(module, hexstr)\n" +"Binary data of hexadecimal representation.\n" +"\n" +"hexstr must contain an even number of hex digits (upper or lower case).\n" +"This function is also available as \"unhexlify()\"."); + +#define BINASCII_A2B_HEX_METHODDEF \ + {"a2b_hex", (PyCFunction)binascii_a2b_hex, METH_VARARGS, binascii_a2b_hex__doc__}, + +static PyObject * +binascii_a2b_hex_impl(PyModuleDef *module, Py_buffer *hexstr); + +static PyObject * +binascii_a2b_hex(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer hexstr; + + if (!PyArg_ParseTuple(args, + "O&:a2b_hex", + ascii_buffer_converter, &hexstr)) + goto exit; + return_value = binascii_a2b_hex_impl(module, &hexstr); + +exit: + return return_value; +} + +PyDoc_STRVAR(binascii_a2b_qp__doc__, +"a2b_qp(module, ascii, header=False)\n" +"Decode a string of qp-encoded data."); + +#define BINASCII_A2B_QP_METHODDEF \ + {"a2b_qp", (PyCFunction)binascii_a2b_qp, METH_VARARGS, binascii_a2b_qp__doc__}, + +static PyObject * +binascii_a2b_qp_impl(PyModuleDef *module, Py_buffer *ascii, int header); + +static PyObject * +binascii_a2b_qp(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer ascii; + int header = 0; + + if (!PyArg_ParseTuple(args, + "O&|i:a2b_qp", + ascii_buffer_converter, &ascii, &header)) + goto exit; + return_value = binascii_a2b_qp_impl(module, &ascii, header); + +exit: + return return_value; +} + +PyDoc_STRVAR(binascii_b2a_qp__doc__, +"b2a_qp(module, data, quotetabs=False, istext=True, header=False)\n" +"Encode a string using quoted-printable encoding.\n" +"\n" +"On encoding, when istext is set, newlines are not encoded, and white\n" +"space at end of lines is. When istext is not set, \\r and \\n (CR/LF)\n" +"are both encoded. When quotetabs is set, space and tabs are encoded."); + +#define BINASCII_B2A_QP_METHODDEF \ + {"b2a_qp", (PyCFunction)binascii_b2a_qp, METH_VARARGS|METH_KEYWORDS, binascii_b2a_qp__doc__}, + +static PyObject * +binascii_b2a_qp_impl(PyModuleDef *module, Py_buffer *data, int quotetabs, int istext, int header); + +static PyObject * +binascii_b2a_qp(PyModuleDef *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + static char *_keywords[] = {"data", "quotetabs", "istext", "header", NULL}; + Py_buffer data = {NULL, NULL}; + int quotetabs = 0; + int istext = 1; + int header = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "y*|iii:b2a_qp", _keywords, + &data, "etabs, &istext, &header)) + goto exit; + return_value = binascii_b2a_qp_impl(module, &data, quotetabs, istext, header); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} +/*[clinic end generated code: checksum=bd769a1cd1169bfa0b73a0ee3081b0748fc39e2c]*/ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 10:26:34 2014 From: python-checkins at python.org (zach.ware) Date: Sat, 25 Jan 2014 10:26:34 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320376=3A_Argument?= =?utf-8?q?_Clinic_now_escapes_backslashes_in_docstrings=2E?= Message-ID: <3fBBgG4Yb0z7LlH@mail.python.org> http://hg.python.org/cpython/rev/381c9d592cc8 changeset: 88685:381c9d592cc8 user: Zachary Ware date: Sat Jan 25 03:26:20 2014 -0600 summary: Issue #20376: Argument Clinic now escapes backslashes in docstrings. files: Misc/NEWS | 2 ++ Tools/clinic/clinic.py | 1 + 2 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -142,6 +142,8 @@ Tools/Demos ----------- +- Issue #20376: Argument Clinic now escapes backslashes in docstrings. + - Issue #20381: Argument Clinic now sanity checks the default argument when c_default is also specified, providing a nice failure message for disallowed values. diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -120,6 +120,7 @@ def quoted_for_c_string(s): for old, new in ( + ('\\', '\\\\'), # must be first! ('"', '\\"'), ("'", "\\'"), ): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 10:49:57 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 25 Jan 2014 10:49:57 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fixed_converting_errors_in?= =?utf-8?q?_the_binascii_module_=28issue20151=29=2E?= Message-ID: <3fBCBF17DHz7LjP@mail.python.org> http://hg.python.org/cpython/rev/76a3cc6f3aca changeset: 88686:76a3cc6f3aca user: Serhiy Storchaka date: Sat Jan 25 11:49:49 2014 +0200 summary: Fixed converting errors in the binascii module (issue20151). a2b_qp() now accepts keyword arguments. All "ascii" parameters is renamed to "data" for consistancy with a2b_qp(). files: Modules/binascii.c | 73 +++++++++++++------------- Modules/binascii.clinic.c | 51 +++++++++--------- 2 files changed, 62 insertions(+), 62 deletions(-) diff --git a/Modules/binascii.c b/Modules/binascii.c --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -241,15 +241,15 @@ /*[clinic input] binascii.a2b_uu - ascii: ascii_buffer + data: ascii_buffer / Decode a line of uuencoded data. [clinic start generated code]*/ static PyObject * -binascii_a2b_uu_impl(PyModuleDef *module, Py_buffer *ascii) -/*[clinic end generated code: checksum=3252d1dbb682979eee03fb2c0c48a4d98a229df4]*/ +binascii_a2b_uu_impl(PyModuleDef *module, Py_buffer *data) +/*[clinic end generated code: checksum=5779f39b0b48459ff0f7a365d7e69b57422e2a4a]*/ { unsigned char *ascii_data, *bin_data; int leftbits = 0; @@ -258,8 +258,8 @@ PyObject *rv; Py_ssize_t ascii_len, bin_len; - ascii_data = ascii->buf; - ascii_len = ascii->len; + ascii_data = data->buf; + ascii_len = data->len; assert(ascii_len >= 0); @@ -414,15 +414,15 @@ /*[clinic input] binascii.a2b_base64 - ascii: ascii_buffer + data: ascii_buffer / Decode a line of base64 data. [clinic start generated code]*/ static PyObject * -binascii_a2b_base64_impl(PyModuleDef *module, Py_buffer *ascii) -/*[clinic end generated code: checksum=73c265f87068c1f3e4bc01834ae6ac5a974143b4]*/ +binascii_a2b_base64_impl(PyModuleDef *module, Py_buffer *data) +/*[clinic end generated code: checksum=3e351b702bed56d249caa4aa0f1bb3fae7546025]*/ { unsigned char *ascii_data, *bin_data; int leftbits = 0; @@ -432,8 +432,8 @@ Py_ssize_t ascii_len, bin_len; int quad_pos = 0; - ascii_data = ascii->buf; - ascii_len = ascii->len; + ascii_data = data->buf; + ascii_len = data->len; assert(ascii_len >= 0); @@ -589,15 +589,15 @@ /*[clinic input] binascii.a2b_hqx - ascii: ascii_buffer + data: ascii_buffer / Decode .hqx coding. [clinic start generated code]*/ static PyObject * -binascii_a2b_hqx_impl(PyModuleDef *module, Py_buffer *ascii) -/*[clinic end generated code: checksum=48075dc4017b66f93086386d5b5848f1e6af260c]*/ +binascii_a2b_hqx_impl(PyModuleDef *module, Py_buffer *data) +/*[clinic end generated code: checksum=60bcdbbd28b105cd7091d98e70a6e458f8039e9e]*/ { unsigned char *ascii_data, *bin_data; int leftbits = 0; @@ -607,8 +607,8 @@ Py_ssize_t len; int done = 0; - ascii_data = ascii->buf; - len = ascii->len; + ascii_data = data->buf; + len = data->len; assert(len >= 0); @@ -1235,25 +1235,24 @@ /*[clinic input] binascii.a2b_qp - ascii: ascii_buffer + data: ascii_buffer header: int(c_default="0") = False - / Decode a string of qp-encoded data. [clinic start generated code]*/ static PyObject * -binascii_a2b_qp_impl(PyModuleDef *module, Py_buffer *ascii, int header) -/*[clinic end generated code: checksum=33910d5b347bf9f33203769e649f35ea41694b71]*/ +binascii_a2b_qp_impl(PyModuleDef *module, Py_buffer *data, int header) +/*[clinic end generated code: checksum=a44ef8827035211431d0906a76dbfe97e59a5079]*/ { Py_ssize_t in, out; char ch; - unsigned char *data, *odata; + unsigned char *ascii_data, *odata; Py_ssize_t datalen = 0; PyObject *rv; - data = ascii->buf; - datalen = ascii->len; + ascii_data = data->buf; + datalen = data->len; /* We allocate the output same size as input, this is overkill. * The previous implementation used calloc() so we'll zero out the @@ -1268,31 +1267,31 @@ in = out = 0; while (in < datalen) { - if (data[in] == '=') { + if (ascii_data[in] == '=') { in++; if (in >= datalen) break; /* Soft line breaks */ - if ((data[in] == '\n') || (data[in] == '\r')) { - if (data[in] != '\n') { - while (in < datalen && data[in] != '\n') in++; + if ((ascii_data[in] == '\n') || (ascii_data[in] == '\r')) { + if (ascii_data[in] != '\n') { + while (in < datalen && ascii_data[in] != '\n') in++; } if (in < datalen) in++; } - else if (data[in] == '=') { + else if (ascii_data[in] == '=') { /* broken case from broken python qp */ odata[out++] = '='; in++; } - else if (((data[in] >= 'A' && data[in] <= 'F') || - (data[in] >= 'a' && data[in] <= 'f') || - (data[in] >= '0' && data[in] <= '9')) && - ((data[in+1] >= 'A' && data[in+1] <= 'F') || - (data[in+1] >= 'a' && data[in+1] <= 'f') || - (data[in+1] >= '0' && data[in+1] <= '9'))) { + else if (((ascii_data[in] >= 'A' && ascii_data[in] <= 'F') || + (ascii_data[in] >= 'a' && ascii_data[in] <= 'f') || + (ascii_data[in] >= '0' && ascii_data[in] <= '9')) && + ((ascii_data[in+1] >= 'A' && ascii_data[in+1] <= 'F') || + (ascii_data[in+1] >= 'a' && ascii_data[in+1] <= 'f') || + (ascii_data[in+1] >= '0' && ascii_data[in+1] <= '9'))) { /* hexval */ - ch = hexval(data[in]) << 4; + ch = hexval(ascii_data[in]) << 4; in++; - ch |= hexval(data[in]); + ch |= hexval(ascii_data[in]); in++; odata[out++] = ch; } @@ -1300,12 +1299,12 @@ odata[out++] = '='; } } - else if (header && data[in] == '_') { + else if (header && ascii_data[in] == '_') { odata[out++] = ' '; in++; } else { - odata[out] = data[in]; + odata[out] = ascii_data[in]; in++; out++; } diff --git a/Modules/binascii.clinic.c b/Modules/binascii.clinic.c --- a/Modules/binascii.clinic.c +++ b/Modules/binascii.clinic.c @@ -3,26 +3,26 @@ [clinic start generated code]*/ PyDoc_STRVAR(binascii_a2b_uu__doc__, -"a2b_uu(module, ascii)\n" +"a2b_uu(module, data)\n" "Decode a line of uuencoded data."); #define BINASCII_A2B_UU_METHODDEF \ {"a2b_uu", (PyCFunction)binascii_a2b_uu, METH_VARARGS, binascii_a2b_uu__doc__}, static PyObject * -binascii_a2b_uu_impl(PyModuleDef *module, Py_buffer *ascii); +binascii_a2b_uu_impl(PyModuleDef *module, Py_buffer *data); static PyObject * binascii_a2b_uu(PyModuleDef *module, PyObject *args) { PyObject *return_value = NULL; - Py_buffer ascii; + Py_buffer data; if (!PyArg_ParseTuple(args, "O&:a2b_uu", - ascii_buffer_converter, &ascii)) + ascii_buffer_converter, &data)) goto exit; - return_value = binascii_a2b_uu_impl(module, &ascii); + return_value = binascii_a2b_uu_impl(module, &data); exit: return return_value; @@ -59,26 +59,26 @@ } PyDoc_STRVAR(binascii_a2b_base64__doc__, -"a2b_base64(module, ascii)\n" +"a2b_base64(module, data)\n" "Decode a line of base64 data."); #define BINASCII_A2B_BASE64_METHODDEF \ {"a2b_base64", (PyCFunction)binascii_a2b_base64, METH_VARARGS, binascii_a2b_base64__doc__}, static PyObject * -binascii_a2b_base64_impl(PyModuleDef *module, Py_buffer *ascii); +binascii_a2b_base64_impl(PyModuleDef *module, Py_buffer *data); static PyObject * binascii_a2b_base64(PyModuleDef *module, PyObject *args) { PyObject *return_value = NULL; - Py_buffer ascii; + Py_buffer data; if (!PyArg_ParseTuple(args, "O&:a2b_base64", - ascii_buffer_converter, &ascii)) + ascii_buffer_converter, &data)) goto exit; - return_value = binascii_a2b_base64_impl(module, &ascii); + return_value = binascii_a2b_base64_impl(module, &data); exit: return return_value; @@ -115,26 +115,26 @@ } PyDoc_STRVAR(binascii_a2b_hqx__doc__, -"a2b_hqx(module, ascii)\n" +"a2b_hqx(module, data)\n" "Decode .hqx coding."); #define BINASCII_A2B_HQX_METHODDEF \ {"a2b_hqx", (PyCFunction)binascii_a2b_hqx, METH_VARARGS, binascii_a2b_hqx__doc__}, static PyObject * -binascii_a2b_hqx_impl(PyModuleDef *module, Py_buffer *ascii); +binascii_a2b_hqx_impl(PyModuleDef *module, Py_buffer *data); static PyObject * binascii_a2b_hqx(PyModuleDef *module, PyObject *args) { PyObject *return_value = NULL; - Py_buffer ascii; + Py_buffer data; if (!PyArg_ParseTuple(args, "O&:a2b_hqx", - ascii_buffer_converter, &ascii)) + ascii_buffer_converter, &data)) goto exit; - return_value = binascii_a2b_hqx_impl(module, &ascii); + return_value = binascii_a2b_hqx_impl(module, &data); exit: return return_value; @@ -363,27 +363,28 @@ } PyDoc_STRVAR(binascii_a2b_qp__doc__, -"a2b_qp(module, ascii, header=False)\n" +"a2b_qp(module, data, header=False)\n" "Decode a string of qp-encoded data."); #define BINASCII_A2B_QP_METHODDEF \ - {"a2b_qp", (PyCFunction)binascii_a2b_qp, METH_VARARGS, binascii_a2b_qp__doc__}, + {"a2b_qp", (PyCFunction)binascii_a2b_qp, METH_VARARGS|METH_KEYWORDS, binascii_a2b_qp__doc__}, static PyObject * -binascii_a2b_qp_impl(PyModuleDef *module, Py_buffer *ascii, int header); +binascii_a2b_qp_impl(PyModuleDef *module, Py_buffer *data, int header); static PyObject * -binascii_a2b_qp(PyModuleDef *module, PyObject *args) +binascii_a2b_qp(PyModuleDef *module, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; - Py_buffer ascii; + static char *_keywords[] = {"data", "header", NULL}; + Py_buffer data; int header = 0; - if (!PyArg_ParseTuple(args, - "O&|i:a2b_qp", - ascii_buffer_converter, &ascii, &header)) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O&|i:a2b_qp", _keywords, + ascii_buffer_converter, &data, &header)) goto exit; - return_value = binascii_a2b_qp_impl(module, &ascii, header); + return_value = binascii_a2b_qp_impl(module, &data, header); exit: return return_value; @@ -426,4 +427,4 @@ return return_value; } -/*[clinic end generated code: checksum=bd769a1cd1169bfa0b73a0ee3081b0748fc39e2c]*/ +/*[clinic end generated code: checksum=abe48ca8020fa3ec25e13bd9fa7414f6b3ee2946]*/ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 10:58:16 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 25 Jan 2014 10:58:16 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320133=3A_The_audi?= =?utf-8?q?oop_module_now_uses_Argument_Clinic=2E?= Message-ID: <3fBCMr1Wdpz7LjP@mail.python.org> http://hg.python.org/cpython/rev/d4099b8a7d0f changeset: 88687:d4099b8a7d0f user: Serhiy Storchaka date: Sat Jan 25 11:57:59 2014 +0200 summary: Issue #20133: The audioop module now uses Argument Clinic. files: Modules/audioop.c | 1077 ++++++++++++++----------- Modules/audioop.clinic.c | 836 ++++++++++++++++++++ 2 files changed, 1427 insertions(+), 486 deletions(-) diff --git a/Modules/audioop.c b/Modules/audioop.c --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -390,128 +390,154 @@ return 1; } +/*[clinic input] +output preset file +module audioop +class audioop.error +[clinic start generated code]*/ +/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + +/*[clinic input] +audioop.getsample + + fragment: Py_buffer + width: int + index: Py_ssize_t + / + +Return the value of sample index from the fragment. +[clinic start generated code]*/ + static PyObject * -audioop_getsample(PyObject *self, PyObject *args) +audioop_getsample_impl(PyModuleDef *module, Py_buffer *fragment, int width, Py_ssize_t index) +/*[clinic end generated code: checksum=f4482497e6f6e78fe88451c19a288837099d6eef]*/ { - Py_buffer view; - Py_ssize_t i; - int size; int val; - if (!PyArg_ParseTuple(args, "y*in:getsample", &view, &size, &i)) + if (!audioop_check_parameters(fragment->len, width)) return NULL; - if (!audioop_check_parameters(view.len, size)) - goto error; - if (i < 0 || i >= view.len/size) { + if (index < 0 || index >= fragment->len/width) { PyErr_SetString(AudioopError, "Index out of range"); - goto error; + return NULL; } - val = GETRAWSAMPLE(size, view.buf, i*size); - PyBuffer_Release(&view); + val = GETRAWSAMPLE(width, fragment->buf, index*width); return PyLong_FromLong(val); - - error: - PyBuffer_Release(&view); - return NULL; } +/*[clinic input] +audioop.max + + fragment: Py_buffer + width: int + / + +Return the maximum of the absolute value of all samples in a fragment. +[clinic start generated code]*/ + static PyObject * -audioop_max(PyObject *self, PyObject *args) +audioop_max_impl(PyModuleDef *module, Py_buffer *fragment, int width) +/*[clinic end generated code: checksum=85047ee1001f230518386b16148955ba9be4874f]*/ { - Py_buffer view; Py_ssize_t i; - int size; unsigned int absval, max = 0; - if (!PyArg_ParseTuple(args, "y*i:max", &view, &size)) + if (!audioop_check_parameters(fragment->len, width)) return NULL; - if (!audioop_check_parameters(view.len, size)) { - PyBuffer_Release(&view); - return NULL; - } - for (i = 0; i < view.len; i += size) { - int val = GETRAWSAMPLE(size, view.buf, i); + for (i = 0; i < fragment->len; i += width) { + int val = GETRAWSAMPLE(width, fragment->buf, i); if (val < 0) absval = (-val); else absval = val; if (absval > max) max = absval; } - PyBuffer_Release(&view); return PyLong_FromUnsignedLong(max); } +/*[clinic input] +audioop.minmax + + fragment: Py_buffer + width: int + / + +Return the minimum and maximum values of all samples in the sound fragment. +[clinic start generated code]*/ + static PyObject * -audioop_minmax(PyObject *self, PyObject *args) +audioop_minmax_impl(PyModuleDef *module, Py_buffer *fragment, int width) +/*[clinic end generated code: checksum=ae8f5513c64fd569849adbbcc5fcd4d8f399da1b]*/ { - Py_buffer view; Py_ssize_t i; - int size; /* -1 trick below is needed on Windows to support -0x80000000 without a warning */ int min = 0x7fffffff, max = -0x7FFFFFFF-1; - if (!PyArg_ParseTuple(args, "y*i:minmax", &view, &size)) + if (!audioop_check_parameters(fragment->len, width)) return NULL; - if (!audioop_check_parameters(view.len, size)) { - PyBuffer_Release(&view); - return NULL; - } - for (i = 0; i < view.len; i += size) { - int val = GETRAWSAMPLE(size, view.buf, i); + for (i = 0; i < fragment->len; i += width) { + int val = GETRAWSAMPLE(width, fragment->buf, i); if (val > max) max = val; if (val < min) min = val; } - PyBuffer_Release(&view); return Py_BuildValue("(ii)", min, max); } +/*[clinic input] +audioop.avg + + fragment: Py_buffer + width: int + / + +Return the average over all samples in the fragment. +[clinic start generated code]*/ + static PyObject * -audioop_avg(PyObject *self, PyObject *args) +audioop_avg_impl(PyModuleDef *module, Py_buffer *fragment, int width) +/*[clinic end generated code: checksum=7fccd645c95f4860899f6b3aaab269e3e58806e1]*/ { - Py_buffer view; Py_ssize_t i; - int size, avg; + int avg; double sum = 0.0; - if (!PyArg_ParseTuple(args, "y*i:avg", &view, &size)) + if (!audioop_check_parameters(fragment->len, width)) return NULL; - if (!audioop_check_parameters(view.len, size)) { - PyBuffer_Release(&view); - return NULL; - } - for (i = 0; i < view.len; i += size) - sum += GETRAWSAMPLE(size, view.buf, i); - if (view.len == 0) + for (i = 0; i < fragment->len; i += width) + sum += GETRAWSAMPLE(width, fragment->buf, i); + if (fragment->len == 0) avg = 0; else - avg = (int)floor(sum / (double)(view.len/size)); - PyBuffer_Release(&view); + avg = (int)floor(sum / (double)(fragment->len/width)); return PyLong_FromLong(avg); } +/*[clinic input] +audioop.rms + + fragment: Py_buffer + width: int + / + +Return the root-mean-square of the fragment, i.e. sqrt(sum(S_i^2)/n). +[clinic start generated code]*/ + static PyObject * -audioop_rms(PyObject *self, PyObject *args) +audioop_rms_impl(PyModuleDef *module, Py_buffer *fragment, int width) +/*[clinic end generated code: checksum=7b398702c81b709d87aba3f0635eeb3fc1b0a1a4]*/ { - Py_buffer view; Py_ssize_t i; - int size; unsigned int res; double sum_squares = 0.0; - if (!PyArg_ParseTuple(args, "y*i:rms", &view, &size)) + if (!audioop_check_parameters(fragment->len, width)) return NULL; - if (!audioop_check_parameters(view.len, size)) { - PyBuffer_Release(&view); - return NULL; - } - for (i = 0; i < view.len; i += size) { - double val = GETRAWSAMPLE(size, view.buf, i); + for (i = 0; i < fragment->len; i += width) { + double val = GETRAWSAMPLE(width, fragment->buf, i); sum_squares += val*val; } - if (view.len == 0) + if (fragment->len == 0) res = 0; else - res = (unsigned int)sqrt(sum_squares / (double)(view.len/size)); - PyBuffer_Release(&view); + res = (unsigned int)sqrt(sum_squares / (double)(fragment->len/width)); return PyLong_FromUnsignedLong(res); } @@ -558,31 +584,38 @@ ** sum_ri is calculated once, sum_aij_2 is updated each step and sum_aij_ri ** is completely recalculated each step. */ +/*[clinic input] +audioop.findfit + + fragment: Py_buffer + reference: Py_buffer + / + +Try to match reference as well as possible to a portion of fragment. +[clinic start generated code]*/ + static PyObject * -audioop_findfit(PyObject *self, PyObject *args) +audioop_findfit_impl(PyModuleDef *module, Py_buffer *fragment, Py_buffer *reference) +/*[clinic end generated code: checksum=505fd04d4244db31044abb5c114a5e8f9c45b171]*/ { - Py_buffer view1; - Py_buffer view2; const short *cp1, *cp2; Py_ssize_t len1, len2; Py_ssize_t j, best_j; double aj_m1, aj_lm1; double sum_ri_2, sum_aij_2, sum_aij_ri, result, best_result, factor; - if (!PyArg_ParseTuple(args, "y*y*:findfit", &view1, &view2)) + if (fragment->len & 1 || reference->len & 1) { + PyErr_SetString(AudioopError, "Strings should be even-sized"); return NULL; - if (view1.len & 1 || view2.len & 1) { - PyErr_SetString(AudioopError, "Strings should be even-sized"); - goto error; } - cp1 = (const short *)view1.buf; - len1 = view1.len >> 1; - cp2 = (const short *)view2.buf; - len2 = view2.len >> 1; + cp1 = (const short *)fragment->buf; + len1 = fragment->len >> 1; + cp2 = (const short *)reference->buf; + len2 = reference->len >> 1; if (len1 < len2) { PyErr_SetString(AudioopError, "First sample should be longer"); - goto error; + return NULL; } sum_ri_2 = _sum2(cp2, cp2, len2); sum_aij_2 = _sum2(cp1, cp1, len2); @@ -612,93 +645,94 @@ factor = _sum2(cp1+best_j, cp2, len2) / sum_ri_2; - PyBuffer_Release(&view1); - PyBuffer_Release(&view2); return Py_BuildValue("(nf)", best_j, factor); - - error: - PyBuffer_Release(&view1); - PyBuffer_Release(&view2); - return NULL; } /* ** findfactor finds a factor f so that the energy in A-fB is minimal. ** See the comment for findfit for details. */ +/*[clinic input] +audioop.findfactor + + fragment: Py_buffer + reference: Py_buffer + / + +Return a factor F such that rms(add(fragment, mul(reference, -F))) is minimal. +[clinic start generated code]*/ + static PyObject * -audioop_findfactor(PyObject *self, PyObject *args) +audioop_findfactor_impl(PyModuleDef *module, Py_buffer *fragment, Py_buffer *reference) +/*[clinic end generated code: checksum=ddf35a1e57575ce4acbc000104810d9fdde8eba5]*/ { - Py_buffer view1; - Py_buffer view2; const short *cp1, *cp2; Py_ssize_t len; double sum_ri_2, sum_aij_ri, result; - if (!PyArg_ParseTuple(args, "y*y*:findfactor", &view1, &view2)) + if (fragment->len & 1 || reference->len & 1) { + PyErr_SetString(AudioopError, "Strings should be even-sized"); return NULL; - if (view1.len & 1 || view2.len & 1) { - PyErr_SetString(AudioopError, "Strings should be even-sized"); - goto error; } - if (view1.len != view2.len) { + if (fragment->len != reference->len) { PyErr_SetString(AudioopError, "Samples should be same size"); - goto error; + return NULL; } - cp1 = (const short *)view1.buf; - cp2 = (const short *)view2.buf; - len = view1.len >> 1; + cp1 = (const short *)fragment->buf; + cp2 = (const short *)reference->buf; + len = fragment->len >> 1; sum_ri_2 = _sum2(cp2, cp2, len); sum_aij_ri = _sum2(cp1, cp2, len); result = sum_aij_ri / sum_ri_2; - PyBuffer_Release(&view1); - PyBuffer_Release(&view2); return PyFloat_FromDouble(result); - - error: - PyBuffer_Release(&view1); - PyBuffer_Release(&view2); - return NULL; } /* ** findmax returns the index of the n-sized segment of the input sample ** that contains the most energy. */ +/*[clinic input] +audioop.findmax + + fragment: Py_buffer + length: Py_ssize_t + / + +Search fragment for a slice of specified number of samples with maximum energy. +[clinic start generated code]*/ + static PyObject * -audioop_findmax(PyObject *self, PyObject *args) +audioop_findmax_impl(PyModuleDef *module, Py_buffer *fragment, Py_ssize_t length) +/*[clinic end generated code: checksum=21d0c2a1e5655134f7460b7fd49ee4ba1e5fdb13]*/ { - Py_buffer view; const short *cp1; - Py_ssize_t len1, len2; + Py_ssize_t len1; Py_ssize_t j, best_j; double aj_m1, aj_lm1; double result, best_result; - if (!PyArg_ParseTuple(args, "y*n:findmax", &view, &len2)) + if (fragment->len & 1) { + PyErr_SetString(AudioopError, "Strings should be even-sized"); return NULL; - if (view.len & 1) { - PyErr_SetString(AudioopError, "Strings should be even-sized"); - goto error; } - cp1 = (const short *)view.buf; - len1 = view.len >> 1; + cp1 = (const short *)fragment->buf; + len1 = fragment->len >> 1; - if (len2 < 0 || len1 < len2) { + if (length < 0 || len1 < length) { PyErr_SetString(AudioopError, "Input sample should be longer"); - goto error; + return NULL; } - result = _sum2(cp1, cp1, len2); + result = _sum2(cp1, cp1, length); best_result = result; best_j = 0; - for ( j=1; j<=len1-len2; j++) { + for ( j=1; j<=len1-length; j++) { aj_m1 = (double)cp1[j-1]; - aj_lm1 = (double)cp1[j+len2-1]; + aj_lm1 = (double)cp1[j+length-1]; result = result + aj_lm1*aj_lm1 - aj_m1*aj_m1; @@ -709,39 +743,37 @@ } - PyBuffer_Release(&view); return PyLong_FromSsize_t(best_j); - - error: - PyBuffer_Release(&view); - return NULL; } +/*[clinic input] +audioop.avgpp + + fragment: Py_buffer + width: int + / + +Return the average peak-peak value over all samples in the fragment. +[clinic start generated code]*/ + static PyObject * -audioop_avgpp(PyObject *self, PyObject *args) +audioop_avgpp_impl(PyModuleDef *module, Py_buffer *fragment, int width) +/*[clinic end generated code: checksum=06c8380fd6e34207f4b58d6c3d4b5ebc7afe138d]*/ { - Py_buffer view; Py_ssize_t i; - int size, prevval, prevextremevalid = 0, - prevextreme = 0; + int prevval, prevextremevalid = 0, prevextreme = 0; double sum = 0.0; unsigned int avg; int diff, prevdiff, nextreme = 0; - if (!PyArg_ParseTuple(args, "y*i:avgpp", &view, &size)) + if (!audioop_check_parameters(fragment->len, width)) return NULL; - if (!audioop_check_parameters(view.len, size)) { - PyBuffer_Release(&view); - return NULL; - } - if (view.len <= size) { - PyBuffer_Release(&view); + if (fragment->len <= width) return PyLong_FromLong(0); - } - prevval = GETRAWSAMPLE(size, view.buf, 0); + prevval = GETRAWSAMPLE(width, fragment->buf, 0); prevdiff = 17; /* Anything != 0, 1 */ - for (i = size; i < view.len; i += size) { - int val = GETRAWSAMPLE(size, view.buf, i); + for (i = width; i < fragment->len; i += width) { + int val = GETRAWSAMPLE(width, fragment->buf, i); if (val != prevval) { diff = val < prevval; if (prevdiff == !diff) { @@ -768,34 +800,36 @@ avg = 0; else avg = (unsigned int)(sum / (double)nextreme); - PyBuffer_Release(&view); return PyLong_FromUnsignedLong(avg); } +/*[clinic input] +audioop.maxpp + + fragment: Py_buffer + width: int + / + +Return the maximum peak-peak value in the sound fragment. +[clinic start generated code]*/ + static PyObject * -audioop_maxpp(PyObject *self, PyObject *args) +audioop_maxpp_impl(PyModuleDef *module, Py_buffer *fragment, int width) +/*[clinic end generated code: checksum=c300c0bd7e8535c07e128bbaac211c69744f750b]*/ { - Py_buffer view; Py_ssize_t i; - int size, prevval, prevextremevalid = 0, - prevextreme = 0; + int prevval, prevextremevalid = 0, prevextreme = 0; unsigned int max = 0, extremediff; int diff, prevdiff; - if (!PyArg_ParseTuple(args, "y*i:maxpp", &view, &size)) + if (!audioop_check_parameters(fragment->len, width)) return NULL; - if (!audioop_check_parameters(view.len, size)) { - PyBuffer_Release(&view); - return NULL; - } - if (view.len <= size) { - PyBuffer_Release(&view); + if (fragment->len <= width) return PyLong_FromLong(0); - } - prevval = GETRAWSAMPLE(size, view.buf, 0); + prevval = GETRAWSAMPLE(width, fragment->buf, 0); prevdiff = 17; /* Anything != 0, 1 */ - for (i = size; i < view.len; i += size) { - int val = GETRAWSAMPLE(size, view.buf, i); + for (i = width; i < fragment->len; i += width) { + int val = GETRAWSAMPLE(width, fragment->buf, i); if (val != prevval) { diff = val < prevval; if (prevdiff == !diff) { @@ -819,187 +853,215 @@ prevdiff = diff; } } - PyBuffer_Release(&view); return PyLong_FromUnsignedLong(max); } +/*[clinic input] +audioop.cross + + fragment: Py_buffer + width: int + / + +Return the number of zero crossings in the fragment passed as an argument. +[clinic start generated code]*/ + static PyObject * -audioop_cross(PyObject *self, PyObject *args) +audioop_cross_impl(PyModuleDef *module, Py_buffer *fragment, int width) +/*[clinic end generated code: checksum=99e6572d7d7cdbf1b5372090308201c62d518a43]*/ { - Py_buffer view; Py_ssize_t i; - int size; int prevval; Py_ssize_t ncross; - if (!PyArg_ParseTuple(args, "y*i:cross", &view, &size)) + if (!audioop_check_parameters(fragment->len, width)) return NULL; - if (!audioop_check_parameters(view.len, size)) { - PyBuffer_Release(&view); - return NULL; - } ncross = -1; prevval = 17; /* Anything <> 0,1 */ - for (i = 0; i < view.len; i += size) { - int val = GETRAWSAMPLE(size, view.buf, i) < 0; + for (i = 0; i < fragment->len; i += width) { + int val = GETRAWSAMPLE(width, fragment->buf, i) < 0; if (val != prevval) ncross++; prevval = val; } - PyBuffer_Release(&view); return PyLong_FromSsize_t(ncross); } +/*[clinic input] +audioop.mul + + fragment: Py_buffer + width: int + factor: double + / + +Return a fragment that has all samples in the original fragment multiplied by the floating-point value factor. +[clinic start generated code]*/ + static PyObject * -audioop_mul(PyObject *self, PyObject *args) +audioop_mul_impl(PyModuleDef *module, Py_buffer *fragment, int width, double factor) +/*[clinic end generated code: checksum=a697ebbd5852d38f941d52127a5b38e4f8cd5540]*/ { - Py_buffer view; signed char *ncp; Py_ssize_t i; - int size; - double factor, maxval, minval; - PyObject *rv = NULL; + double maxval, minval; + PyObject *rv; - if (!PyArg_ParseTuple(args, "y*id:mul", &view, &size, &factor)) + if (!audioop_check_parameters(fragment->len, width)) return NULL; - if (!audioop_check_parameters(view.len, size)) - goto exit; - maxval = (double) maxvals[size]; - minval = (double) minvals[size]; + maxval = (double) maxvals[width]; + minval = (double) minvals[width]; - rv = PyBytes_FromStringAndSize(NULL, view.len); + rv = PyBytes_FromStringAndSize(NULL, fragment->len); if (rv == NULL) - goto exit; + return NULL; ncp = (signed char *)PyBytes_AsString(rv); - for (i = 0; i < view.len; i += size) { - double val = GETRAWSAMPLE(size, view.buf, i); + for (i = 0; i < fragment->len; i += width) { + double val = GETRAWSAMPLE(width, fragment->buf, i); val *= factor; val = floor(fbound(val, minval, maxval)); - SETRAWSAMPLE(size, ncp, i, (int)val); + SETRAWSAMPLE(width, ncp, i, (int)val); } - exit: - PyBuffer_Release(&view); return rv; } +/*[clinic input] +audioop.tomono + + fragment: Py_buffer + width: int + lfactor: double + rfactor: double + / + +Convert a stereo fragment to a mono fragment. +[clinic start generated code]*/ + static PyObject * -audioop_tomono(PyObject *self, PyObject *args) +audioop_tomono_impl(PyModuleDef *module, Py_buffer *fragment, int width, double lfactor, double rfactor) +/*[clinic end generated code: checksum=436e7710521661dd541ec177ee53e6b0ee340182]*/ { - Py_buffer pcp; signed char *cp, *ncp; Py_ssize_t len, i; - int size; - double fac1, fac2, maxval, minval; - PyObject *rv = NULL; + double maxval, minval; + PyObject *rv; - if (!PyArg_ParseTuple(args, "y*idd:tomono", - &pcp, &size, &fac1, &fac2)) + cp = fragment->buf; + len = fragment->len; + if (!audioop_check_parameters(len, width)) return NULL; - cp = pcp.buf; - len = pcp.len; - if (!audioop_check_parameters(len, size)) - goto exit; - if (((len / size) & 1) != 0) { + if (((len / width) & 1) != 0) { PyErr_SetString(AudioopError, "not a whole number of frames"); - goto exit; + return NULL; } - maxval = (double) maxvals[size]; - minval = (double) minvals[size]; + maxval = (double) maxvals[width]; + minval = (double) minvals[width]; rv = PyBytes_FromStringAndSize(NULL, len/2); if (rv == NULL) - goto exit; + return NULL; ncp = (signed char *)PyBytes_AsString(rv); - for (i = 0; i < len; i += size*2) { - double val1 = GETRAWSAMPLE(size, cp, i); - double val2 = GETRAWSAMPLE(size, cp, i + size); - double val = val1*fac1 + val2*fac2; + for (i = 0; i < len; i += width*2) { + double val1 = GETRAWSAMPLE(width, cp, i); + double val2 = GETRAWSAMPLE(width, cp, i + width); + double val = val1*lfactor + val2*rfactor; val = floor(fbound(val, minval, maxval)); - SETRAWSAMPLE(size, ncp, i/2, val); + SETRAWSAMPLE(width, ncp, i/2, val); } - exit: - PyBuffer_Release(&pcp); return rv; } +/*[clinic input] +audioop.tostereo + + fragment: Py_buffer + width: int + lfactor: double + rfactor: double + / + +Generate a stereo fragment from a mono fragment. +[clinic start generated code]*/ + static PyObject * -audioop_tostereo(PyObject *self, PyObject *args) +audioop_tostereo_impl(PyModuleDef *module, Py_buffer *fragment, int width, double lfactor, double rfactor) +/*[clinic end generated code: checksum=6ff50681c87f4c1cbe4c394c4186ae8ae91b5c0d]*/ { - Py_buffer view; signed char *ncp; Py_ssize_t i; - int size; - double fac1, fac2, maxval, minval; - PyObject *rv = NULL; + double maxval, minval; + PyObject *rv; - if (!PyArg_ParseTuple(args, "y*idd:tostereo", - &view, &size, &fac1, &fac2)) + if (!audioop_check_parameters(fragment->len, width)) return NULL; - if (!audioop_check_parameters(view.len, size)) - goto exit; - maxval = (double) maxvals[size]; - minval = (double) minvals[size]; + maxval = (double) maxvals[width]; + minval = (double) minvals[width]; - if (view.len > PY_SSIZE_T_MAX/2) { + if (fragment->len > PY_SSIZE_T_MAX/2) { PyErr_SetString(PyExc_MemoryError, "not enough memory for output buffer"); - goto exit; + return NULL; } - rv = PyBytes_FromStringAndSize(NULL, view.len*2); + rv = PyBytes_FromStringAndSize(NULL, fragment->len*2); if (rv == NULL) - goto exit; + return NULL; ncp = (signed char *)PyBytes_AsString(rv); - for (i = 0; i < view.len; i += size) { - double val = GETRAWSAMPLE(size, view.buf, i); - int val1 = (int)floor(fbound(val*fac1, minval, maxval)); - int val2 = (int)floor(fbound(val*fac2, minval, maxval)); - SETRAWSAMPLE(size, ncp, i*2, val1); - SETRAWSAMPLE(size, ncp, i*2 + size, val2); + for (i = 0; i < fragment->len; i += width) { + double val = GETRAWSAMPLE(width, fragment->buf, i); + int val1 = (int)floor(fbound(val*lfactor, minval, maxval)); + int val2 = (int)floor(fbound(val*rfactor, minval, maxval)); + SETRAWSAMPLE(width, ncp, i*2, val1); + SETRAWSAMPLE(width, ncp, i*2 + width, val2); } - exit: - PyBuffer_Release(&view); return rv; } +/*[clinic input] +audioop.add + + fragment1: Py_buffer + fragment2: Py_buffer + width: int + / + +Return a fragment which is the addition of the two samples passed as parameters. +[clinic start generated code]*/ + static PyObject * -audioop_add(PyObject *self, PyObject *args) +audioop_add_impl(PyModuleDef *module, Py_buffer *fragment1, Py_buffer *fragment2, int width) +/*[clinic end generated code: checksum=f9218bf9ea75c3f1e4b2ed5ffdfd631354e8fdfe]*/ { - Py_buffer view1; - Py_buffer view2; signed char *ncp; Py_ssize_t i; - int size, minval, maxval, newval; - PyObject *rv = NULL; + int minval, maxval, newval; + PyObject *rv; - if (!PyArg_ParseTuple(args, "y*y*i:add", - &view1, &view2, &size)) + if (!audioop_check_parameters(fragment1->len, width)) return NULL; - if (!audioop_check_parameters(view1.len, size)) - goto exit; - if (view1.len != view2.len) { + if (fragment1->len != fragment2->len) { PyErr_SetString(AudioopError, "Lengths should be the same"); - goto exit; + return NULL; } - maxval = maxvals[size]; - minval = minvals[size]; + maxval = maxvals[width]; + minval = minvals[width]; - rv = PyBytes_FromStringAndSize(NULL, view1.len); + rv = PyBytes_FromStringAndSize(NULL, fragment1->len); if (rv == NULL) - goto exit; + return NULL; ncp = (signed char *)PyBytes_AsString(rv); - for (i = 0; i < view1.len; i += size) { - int val1 = GETRAWSAMPLE(size, view1.buf, i); - int val2 = GETRAWSAMPLE(size, view2.buf, i); + for (i = 0; i < fragment1->len; i += width) { + int val1 = GETRAWSAMPLE(width, fragment1->buf, i); + int val2 = GETRAWSAMPLE(width, fragment2->buf, i); - if (size < 4) { + if (width < 4) { newval = val1 + val2; /* truncate in case of overflow */ if (newval > maxval) @@ -1013,165 +1075,176 @@ newval = (int)floor(fbound(fval, minval, maxval)); } - SETRAWSAMPLE(size, ncp, i, newval); + SETRAWSAMPLE(width, ncp, i, newval); } - exit: - PyBuffer_Release(&view1); - PyBuffer_Release(&view2); return rv; } +/*[clinic input] +audioop.bias + + fragment: Py_buffer + width: int + bias: int + / + +Return a fragment that is the original fragment with a bias added to each sample. +[clinic start generated code]*/ + static PyObject * -audioop_bias(PyObject *self, PyObject *args) +audioop_bias_impl(PyModuleDef *module, Py_buffer *fragment, int width, int bias) +/*[clinic end generated code: checksum=8ec80b3f5d510a51a85e89e8c0a73070697f2ab4]*/ { - Py_buffer view; signed char *ncp; Py_ssize_t i; - int size, bias; unsigned int val = 0, mask; - PyObject *rv = NULL; + PyObject *rv; - if (!PyArg_ParseTuple(args, "y*ii:bias", - &view, &size, &bias)) + if (!audioop_check_parameters(fragment->len, width)) return NULL; - if (!audioop_check_parameters(view.len, size)) - goto exit; - - rv = PyBytes_FromStringAndSize(NULL, view.len); + rv = PyBytes_FromStringAndSize(NULL, fragment->len); if (rv == NULL) - goto exit; + return NULL; ncp = (signed char *)PyBytes_AsString(rv); - mask = masks[size]; + mask = masks[width]; - for (i = 0; i < view.len; i += size) { - if (size == 1) - val = GETINTX(unsigned char, view.buf, i); - else if (size == 2) - val = GETINTX(unsigned short, view.buf, i); - else if (size == 3) - val = ((unsigned int)GETINT24(view.buf, i)) & 0xffffffu; + for (i = 0; i < fragment->len; i += width) { + if (width == 1) + val = GETINTX(unsigned char, fragment->buf, i); + else if (width == 2) + val = GETINTX(unsigned short, fragment->buf, i); + else if (width == 3) + val = ((unsigned int)GETINT24(fragment->buf, i)) & 0xffffffu; else { - assert(size == 4); - val = GETINTX(PY_UINT32_T, view.buf, i); + assert(width == 4); + val = GETINTX(PY_UINT32_T, fragment->buf, i); } val += (unsigned int)bias; /* wrap around in case of overflow */ val &= mask; - if (size == 1) + if (width == 1) SETINTX(unsigned char, ncp, i, val); - else if (size == 2) + else if (width == 2) SETINTX(unsigned short, ncp, i, val); - else if (size == 3) + else if (width == 3) SETINT24(ncp, i, (int)val); else { - assert(size == 4); + assert(width == 4); SETINTX(PY_UINT32_T, ncp, i, val); } } - exit: - PyBuffer_Release(&view); return rv; } +/*[clinic input] +audioop.reverse + + fragment: Py_buffer + width: int + / + +Reverse the samples in a fragment and returns the modified fragment. +[clinic start generated code]*/ + static PyObject * -audioop_reverse(PyObject *self, PyObject *args) +audioop_reverse_impl(PyModuleDef *module, Py_buffer *fragment, int width) +/*[clinic end generated code: checksum=6ec3c91337f5925eaf17a7b8b907120102b6fb72]*/ { - Py_buffer view; unsigned char *ncp; Py_ssize_t i; - int size; - PyObject *rv = NULL; + PyObject *rv; - if (!PyArg_ParseTuple(args, "y*i:reverse", - &view, &size)) + if (!audioop_check_parameters(fragment->len, width)) return NULL; - if (!audioop_check_parameters(view.len, size)) - goto exit; - - rv = PyBytes_FromStringAndSize(NULL, view.len); + rv = PyBytes_FromStringAndSize(NULL, fragment->len); if (rv == NULL) - goto exit; + return NULL; ncp = (unsigned char *)PyBytes_AsString(rv); - for (i = 0; i < view.len; i += size) { - int val = GETRAWSAMPLE(size, view.buf, i); - SETRAWSAMPLE(size, ncp, view.len - i - size, val); + for (i = 0; i < fragment->len; i += width) { + int val = GETRAWSAMPLE(width, fragment->buf, i); + SETRAWSAMPLE(width, ncp, fragment->len - i - width, val); } - exit: - PyBuffer_Release(&view); return rv; } +/*[clinic input] +audioop.byteswap + + fragment: Py_buffer + width: int + / + +Convert big-endian samples to little-endian and vice versa. +[clinic start generated code]*/ + static PyObject * -audioop_byteswap(PyObject *self, PyObject *args) +audioop_byteswap_impl(PyModuleDef *module, Py_buffer *fragment, int width) +/*[clinic end generated code: checksum=bfe4aa584b7a3f5bd818cf79f83fa73e612cc9b8]*/ { - Py_buffer view; unsigned char *ncp; Py_ssize_t i; - int size; - PyObject *rv = NULL; + PyObject *rv; - if (!PyArg_ParseTuple(args, "y*i:swapbytes", - &view, &size)) + if (!audioop_check_parameters(fragment->len, width)) return NULL; - if (!audioop_check_parameters(view.len, size)) - goto exit; - - rv = PyBytes_FromStringAndSize(NULL, view.len); + rv = PyBytes_FromStringAndSize(NULL, fragment->len); if (rv == NULL) - goto exit; + return NULL; ncp = (unsigned char *)PyBytes_AsString(rv); - for (i = 0; i < view.len; i += size) { + for (i = 0; i < fragment->len; i += width) { int j; - for (j = 0; j < size; j++) - ncp[i + size - 1 - j] = ((unsigned char *)view.buf)[i + j]; + for (j = 0; j < width; j++) + ncp[i + width - 1 - j] = ((unsigned char *)fragment->buf)[i + j]; } - exit: - PyBuffer_Release(&view); return rv; } +/*[clinic input] +audioop.lin2lin + + fragment: Py_buffer + width: int + newwidth: int + / + +Convert samples between 1-, 2-, 3- and 4-byte formats. +[clinic start generated code]*/ + static PyObject * -audioop_lin2lin(PyObject *self, PyObject *args) +audioop_lin2lin_impl(PyModuleDef *module, Py_buffer *fragment, int width, int newwidth) +/*[clinic end generated code: checksum=3f9468a74472a93e2054a9da0ea1bbc39fe23e84]*/ { - Py_buffer view; unsigned char *ncp; Py_ssize_t i, j; - int size, size2; - PyObject *rv = NULL; + PyObject *rv; - if (!PyArg_ParseTuple(args, "y*ii:lin2lin", - &view, &size, &size2)) + if (!audioop_check_parameters(fragment->len, width)) + return NULL; + if (!audioop_check_size(newwidth)) return NULL; - if (!audioop_check_parameters(view.len, size)) - goto exit; - if (!audioop_check_size(size2)) - goto exit; - - if (view.len/size > PY_SSIZE_T_MAX/size2) { + if (fragment->len/width > PY_SSIZE_T_MAX/newwidth) { PyErr_SetString(PyExc_MemoryError, "not enough memory for output buffer"); - goto exit; + return NULL; } - rv = PyBytes_FromStringAndSize(NULL, (view.len/size)*size2); + rv = PyBytes_FromStringAndSize(NULL, (fragment->len/width)*newwidth); if (rv == NULL) - goto exit; + return NULL; ncp = (unsigned char *)PyBytes_AsString(rv); - for (i = j = 0; i < view.len; i += size, j += size2) { - int val = GETSAMPLE32(size, view.buf, i); - SETSAMPLE32(size2, ncp, j, val); + for (i = j = 0; i < fragment->len; i += width, j += newwidth) { + int val = GETSAMPLE32(width, fragment->buf, i); + SETSAMPLE32(newwidth, ncp, j, val); } - exit: - PyBuffer_Release(&view); return rv; } @@ -1186,50 +1259,59 @@ return a; } +/*[clinic input] +audioop.ratecv + + fragment: Py_buffer + width: int + nchannels: int + inrate: int + outrate: int + state: object + weightA: int = 1 + weightB: int = 0 + / + +Convert the frame rate of the input fragment. +[clinic start generated code]*/ + static PyObject * -audioop_ratecv(PyObject *self, PyObject *args) +audioop_ratecv_impl(PyModuleDef *module, Py_buffer *fragment, int width, int nchannels, int inrate, int outrate, PyObject *state, int weightA, int weightB) +/*[clinic end generated code: checksum=5585dddc4b5ff2363877076f4c6616df8d3e6f14]*/ { - Py_buffer view; char *cp, *ncp; Py_ssize_t len; - int size, nchannels, inrate, outrate, weightA, weightB; int chan, d, *prev_i, *cur_i, cur_o; - PyObject *state, *samps, *str, *rv = NULL; + PyObject *samps, *str, *rv = NULL; int bytes_per_frame; - weightA = 1; - weightB = 0; - if (!PyArg_ParseTuple(args, "y*iiiiO|ii:ratecv", &view, &size, - &nchannels, &inrate, &outrate, &state, - &weightA, &weightB)) + if (!audioop_check_size(width)) return NULL; - if (!audioop_check_size(size)) - goto exit2; if (nchannels < 1) { PyErr_SetString(AudioopError, "# of channels should be >= 1"); - goto exit2; + return NULL; } - if (size > INT_MAX / nchannels) { + if (width > INT_MAX / nchannels) { /* This overflow test is rigorously correct because both multiplicands are >= 1. Use the argument names from the docs for the error msg. */ PyErr_SetString(PyExc_OverflowError, "width * nchannels too big for a C int"); - goto exit2; + return NULL; } - bytes_per_frame = size * nchannels; + bytes_per_frame = width * nchannels; if (weightA < 1 || weightB < 0) { PyErr_SetString(AudioopError, "weightA should be >= 1, weightB should be >= 0"); - goto exit2; + return NULL; } - if (view.len % bytes_per_frame != 0) { + if (fragment->len % bytes_per_frame != 0) { PyErr_SetString(AudioopError, "not a whole number of frames"); - goto exit2; + return NULL; } if (inrate <= 0 || outrate <= 0) { PyErr_SetString(AudioopError, "sampling rate not > 0"); - goto exit2; + return NULL; } /* divide inrate and outrate by their greatest common divisor */ d = gcd(inrate, outrate); @@ -1243,7 +1325,7 @@ if ((size_t)nchannels > PY_SIZE_MAX/sizeof(int)) { PyErr_SetString(PyExc_MemoryError, "not enough memory for output buffer"); - goto exit2; + return NULL; } prev_i = (int *) PyMem_Malloc(nchannels * sizeof(int)); cur_i = (int *) PyMem_Malloc(nchannels * sizeof(int)); @@ -1252,7 +1334,7 @@ goto exit; } - len = view.len / bytes_per_frame; /* # of frames */ + len = fragment->len / bytes_per_frame; /* # of frames */ if (state == Py_None) { d = -outrate; @@ -1302,7 +1384,7 @@ goto exit; } ncp = PyBytes_AsString(str); - cp = view.buf; + cp = fragment->buf; for (;;) { while (d < 0) { @@ -1333,8 +1415,8 @@ } for (chan = 0; chan < nchannels; chan++) { prev_i[chan] = cur_i[chan]; - cur_i[chan] = GETSAMPLE32(size, cp, 0); - cp += size; + cur_i[chan] = GETSAMPLE32(width, cp, 0); + cp += width; /* implements a simple digital filter */ cur_i[chan] = (int)( ((double)weightA * (double)cur_i[chan] + @@ -1349,8 +1431,8 @@ cur_o = (int)(((double)prev_i[chan] * (double)d + (double)cur_i[chan] * (double)(outrate - d)) / (double)outrate); - SETSAMPLE32(size, ncp, 0, cur_o); - ncp += size; + SETSAMPLE32(width, ncp, 0, cur_o); + ncp += width; } d -= inrate; } @@ -1358,166 +1440,184 @@ exit: PyMem_Free(prev_i); PyMem_Free(cur_i); - exit2: - PyBuffer_Release(&view); return rv; } +/*[clinic input] +audioop.lin2ulaw + + fragment: Py_buffer + width: int + / + +Convert samples in the audio fragment to u-LAW encoding. +[clinic start generated code]*/ + static PyObject * -audioop_lin2ulaw(PyObject *self, PyObject *args) +audioop_lin2ulaw_impl(PyModuleDef *module, Py_buffer *fragment, int width) +/*[clinic end generated code: checksum=26263cc877c5e1bc84fede972fb59499a82d949c]*/ { - Py_buffer view; unsigned char *ncp; Py_ssize_t i; - int size; - PyObject *rv = NULL; + PyObject *rv; - if (!PyArg_ParseTuple(args, "y*i:lin2ulaw", - &view, &size)) + if (!audioop_check_parameters(fragment->len, width)) return NULL; - if (!audioop_check_parameters(view.len, size)) - goto exit; - - rv = PyBytes_FromStringAndSize(NULL, view.len/size); + rv = PyBytes_FromStringAndSize(NULL, fragment->len/width); if (rv == NULL) - goto exit; + return NULL; ncp = (unsigned char *)PyBytes_AsString(rv); - for (i = 0; i < view.len; i += size) { - int val = GETSAMPLE32(size, view.buf, i); + for (i = 0; i < fragment->len; i += width) { + int val = GETSAMPLE32(width, fragment->buf, i); *ncp++ = st_14linear2ulaw(val >> 18); } - exit: - PyBuffer_Release(&view); return rv; } +/*[clinic input] +audioop.ulaw2lin + + fragment: Py_buffer + width: int + / + +Convert sound fragments in u-LAW encoding to linearly encoded sound fragments. +[clinic start generated code]*/ + static PyObject * -audioop_ulaw2lin(PyObject *self, PyObject *args) +audioop_ulaw2lin_impl(PyModuleDef *module, Py_buffer *fragment, int width) +/*[clinic end generated code: checksum=9864cb34e3a1d87689f830d4c95cdcaae9a44561]*/ { - Py_buffer view; unsigned char *cp; signed char *ncp; Py_ssize_t i; - int size; - PyObject *rv = NULL; + PyObject *rv; - if (!PyArg_ParseTuple(args, "y*i:ulaw2lin", - &view, &size)) + if (!audioop_check_size(width)) return NULL; - if (!audioop_check_size(size)) - goto exit; - - if (view.len > PY_SSIZE_T_MAX/size) { + if (fragment->len > PY_SSIZE_T_MAX/width) { PyErr_SetString(PyExc_MemoryError, "not enough memory for output buffer"); - goto exit; + return NULL; } - rv = PyBytes_FromStringAndSize(NULL, view.len*size); + rv = PyBytes_FromStringAndSize(NULL, fragment->len*width); if (rv == NULL) - goto exit; + return NULL; ncp = (signed char *)PyBytes_AsString(rv); - cp = view.buf; - for (i = 0; i < view.len*size; i += size) { + cp = fragment->buf; + for (i = 0; i < fragment->len*width; i += width) { int val = st_ulaw2linear16(*cp++) << 16; - SETSAMPLE32(size, ncp, i, val); + SETSAMPLE32(width, ncp, i, val); } - exit: - PyBuffer_Release(&view); return rv; } +/*[clinic input] +audioop.lin2alaw + + fragment: Py_buffer + width: int + / + +Convert samples in the audio fragment to a-LAW encoding. +[clinic start generated code]*/ + static PyObject * -audioop_lin2alaw(PyObject *self, PyObject *args) +audioop_lin2alaw_impl(PyModuleDef *module, Py_buffer *fragment, int width) +/*[clinic end generated code: checksum=d5bf14bd0fe6fdcd4b0d604ccdf257097eb2419e]*/ { - Py_buffer view; unsigned char *ncp; Py_ssize_t i; - int size; - PyObject *rv = NULL; + PyObject *rv; - if (!PyArg_ParseTuple(args, "y*i:lin2alaw", - &view, &size)) + if (!audioop_check_parameters(fragment->len, width)) return NULL; - if (!audioop_check_parameters(view.len, size)) - goto exit; - - rv = PyBytes_FromStringAndSize(NULL, view.len/size); + rv = PyBytes_FromStringAndSize(NULL, fragment->len/width); if (rv == NULL) - goto exit; + return NULL; ncp = (unsigned char *)PyBytes_AsString(rv); - for (i = 0; i < view.len; i += size) { - int val = GETSAMPLE32(size, view.buf, i); + for (i = 0; i < fragment->len; i += width) { + int val = GETSAMPLE32(width, fragment->buf, i); *ncp++ = st_linear2alaw(val >> 19); } - exit: - PyBuffer_Release(&view); return rv; } +/*[clinic input] +audioop.alaw2lin + + fragment: Py_buffer + width: int + / + +Convert sound fragments in a-LAW encoding to linearly encoded sound fragments. +[clinic start generated code]*/ + static PyObject * -audioop_alaw2lin(PyObject *self, PyObject *args) +audioop_alaw2lin_impl(PyModuleDef *module, Py_buffer *fragment, int width) +/*[clinic end generated code: checksum=d2b604ddd036e1cd4bb95b5553626b44302db48a]*/ { - Py_buffer view; unsigned char *cp; signed char *ncp; Py_ssize_t i; - int size, val; - PyObject *rv = NULL; + int val; + PyObject *rv; - if (!PyArg_ParseTuple(args, "y*i:alaw2lin", - &view, &size)) + if (!audioop_check_size(width)) return NULL; - if (!audioop_check_size(size)) - goto exit; - - if (view.len > PY_SSIZE_T_MAX/size) { + if (fragment->len > PY_SSIZE_T_MAX/width) { PyErr_SetString(PyExc_MemoryError, "not enough memory for output buffer"); - goto exit; + return NULL; } - rv = PyBytes_FromStringAndSize(NULL, view.len*size); + rv = PyBytes_FromStringAndSize(NULL, fragment->len*width); if (rv == NULL) - goto exit; + return NULL; ncp = (signed char *)PyBytes_AsString(rv); - cp = view.buf; + cp = fragment->buf; - for (i = 0; i < view.len*size; i += size) { + for (i = 0; i < fragment->len*width; i += width) { val = st_alaw2linear16(*cp++) << 16; - SETSAMPLE32(size, ncp, i, val); + SETSAMPLE32(width, ncp, i, val); } - exit: - PyBuffer_Release(&view); return rv; } +/*[clinic input] +audioop.lin2adpcm + + fragment: Py_buffer + width: int + state: object + / + +Convert samples to 4 bit Intel/DVI ADPCM encoding. +[clinic start generated code]*/ + static PyObject * -audioop_lin2adpcm(PyObject *self, PyObject *args) +audioop_lin2adpcm_impl(PyModuleDef *module, Py_buffer *fragment, int width, PyObject *state) +/*[clinic end generated code: checksum=4654c29d2731fafe35e7aa1e3d261361dbbbcc3b]*/ { - Py_buffer view; signed char *ncp; Py_ssize_t i; - int size, step, valpred, delta, + int step, valpred, delta, index, sign, vpdiff, diff; - PyObject *rv = NULL, *state, *str = NULL; + PyObject *rv, *str; int outputbuffer = 0, bufferstep; - if (!PyArg_ParseTuple(args, "y*iO:lin2adpcm", - &view, &size, &state)) + if (!audioop_check_parameters(fragment->len, width)) return NULL; - if (!audioop_check_parameters(view.len, size)) - goto exit; - - str = PyBytes_FromStringAndSize(NULL, view.len/(size*2)); + str = PyBytes_FromStringAndSize(NULL, fragment->len/(width*2)); if (str == NULL) - goto exit; + return NULL; ncp = (signed char *)PyBytes_AsString(str); /* Decode state, should have (value, step) */ @@ -1527,15 +1627,15 @@ index = 0; } else if (!PyTuple_Check(state)) { PyErr_SetString(PyExc_TypeError, "state must be a tuple or None"); - goto exit; + return NULL; } else if (!PyArg_ParseTuple(state, "ii", &valpred, &index)) - goto exit; + return NULL; step = stepsizeTable[index]; bufferstep = 1; - for (i = 0; i < view.len; i += size) { - int val = GETSAMPLE32(size, view.buf, i) >> 16; + for (i = 0; i < fragment->len; i += width) { + int val = GETSAMPLE32(width, fragment->buf, i) >> 16; /* Step 1 - compute difference with previous value */ if (val < valpred) { @@ -1605,30 +1705,35 @@ bufferstep = !bufferstep; } rv = Py_BuildValue("(O(ii))", str, valpred, index); - exit: - Py_XDECREF(str); - PyBuffer_Release(&view); + Py_DECREF(str); return rv; } +/*[clinic input] +audioop.adpcm2lin + + fragment: Py_buffer + width: int + state: object + / + +Decode an Intel/DVI ADPCM coded fragment to a linear fragment. +[clinic start generated code]*/ + static PyObject * -audioop_adpcm2lin(PyObject *self, PyObject *args) +audioop_adpcm2lin_impl(PyModuleDef *module, Py_buffer *fragment, int width, PyObject *state) +/*[clinic end generated code: checksum=371965cdcc0aa69ba970e8bc5662b30d45bcc38d]*/ { - Py_buffer view; signed char *cp; signed char *ncp; Py_ssize_t i, outlen; - int size, valpred, step, delta, index, sign, vpdiff; - PyObject *rv = NULL, *str, *state; + int valpred, step, delta, index, sign, vpdiff; + PyObject *rv, *str; int inputbuffer = 0, bufferstep; - if (!PyArg_ParseTuple(args, "y*iO:adpcm2lin", - &view, &size, &state)) + if (!audioop_check_size(width)) return NULL; - if (!audioop_check_size(size)) - goto exit; - /* Decode state, should have (value, step) */ if ( state == Py_None ) { /* First time, it seems. Set defaults */ @@ -1636,26 +1741,26 @@ index = 0; } else if (!PyTuple_Check(state)) { PyErr_SetString(PyExc_TypeError, "state must be a tuple or None"); - goto exit; + return NULL; } else if (!PyArg_ParseTuple(state, "ii", &valpred, &index)) - goto exit; + return NULL; - if (view.len > (PY_SSIZE_T_MAX/2)/size) { + if (fragment->len > (PY_SSIZE_T_MAX/2)/width) { PyErr_SetString(PyExc_MemoryError, "not enough memory for output buffer"); - goto exit; + return NULL; } - outlen = view.len*size*2; + outlen = fragment->len*width*2; str = PyBytes_FromStringAndSize(NULL, outlen); if (str == NULL) - goto exit; + return NULL; ncp = (signed char *)PyBytes_AsString(str); - cp = view.buf; + cp = fragment->buf; step = stepsizeTable[index]; bufferstep = 0; - for (i = 0; i < outlen; i += size) { + for (i = 0; i < outlen; i += width) { /* Step 1 - get the delta value and compute next index */ if ( bufferstep ) { delta = inputbuffer & 0xf; @@ -1700,43 +1805,43 @@ step = stepsizeTable[index]; /* Step 6 - Output value */ - SETSAMPLE32(size, ncp, i, valpred << 16); + SETSAMPLE32(width, ncp, i, valpred << 16); } rv = Py_BuildValue("(O(ii))", str, valpred, index); Py_DECREF(str); - exit: - PyBuffer_Release(&view); return rv; } +#include "audioop.clinic.c" + static PyMethodDef audioop_methods[] = { - { "max", audioop_max, METH_VARARGS }, - { "minmax", audioop_minmax, METH_VARARGS }, - { "avg", audioop_avg, METH_VARARGS }, - { "maxpp", audioop_maxpp, METH_VARARGS }, - { "avgpp", audioop_avgpp, METH_VARARGS }, - { "rms", audioop_rms, METH_VARARGS }, - { "findfit", audioop_findfit, METH_VARARGS }, - { "findmax", audioop_findmax, METH_VARARGS }, - { "findfactor", audioop_findfactor, METH_VARARGS }, - { "cross", audioop_cross, METH_VARARGS }, - { "mul", audioop_mul, METH_VARARGS }, - { "add", audioop_add, METH_VARARGS }, - { "bias", audioop_bias, METH_VARARGS }, - { "ulaw2lin", audioop_ulaw2lin, METH_VARARGS }, - { "lin2ulaw", audioop_lin2ulaw, METH_VARARGS }, - { "alaw2lin", audioop_alaw2lin, METH_VARARGS }, - { "lin2alaw", audioop_lin2alaw, METH_VARARGS }, - { "lin2lin", audioop_lin2lin, METH_VARARGS }, - { "adpcm2lin", audioop_adpcm2lin, METH_VARARGS }, - { "lin2adpcm", audioop_lin2adpcm, METH_VARARGS }, - { "tomono", audioop_tomono, METH_VARARGS }, - { "tostereo", audioop_tostereo, METH_VARARGS }, - { "getsample", audioop_getsample, METH_VARARGS }, - { "reverse", audioop_reverse, METH_VARARGS }, - { "byteswap", audioop_byteswap, METH_VARARGS }, - { "ratecv", audioop_ratecv, METH_VARARGS }, + AUDIOOP_MAX_METHODDEF + AUDIOOP_MINMAX_METHODDEF + AUDIOOP_AVG_METHODDEF + AUDIOOP_MAXPP_METHODDEF + AUDIOOP_AVGPP_METHODDEF + AUDIOOP_RMS_METHODDEF + AUDIOOP_FINDFIT_METHODDEF + AUDIOOP_FINDMAX_METHODDEF + AUDIOOP_FINDFACTOR_METHODDEF + AUDIOOP_CROSS_METHODDEF + AUDIOOP_MUL_METHODDEF + AUDIOOP_ADD_METHODDEF + AUDIOOP_BIAS_METHODDEF + AUDIOOP_ULAW2LIN_METHODDEF + AUDIOOP_LIN2ULAW_METHODDEF + AUDIOOP_ALAW2LIN_METHODDEF + AUDIOOP_LIN2ALAW_METHODDEF + AUDIOOP_LIN2LIN_METHODDEF + AUDIOOP_ADPCM2LIN_METHODDEF + AUDIOOP_LIN2ADPCM_METHODDEF + AUDIOOP_TOMONO_METHODDEF + AUDIOOP_TOSTEREO_METHODDEF + AUDIOOP_GETSAMPLE_METHODDEF + AUDIOOP_REVERSE_METHODDEF + AUDIOOP_BYTESWAP_METHODDEF + AUDIOOP_RATECV_METHODDEF { 0, 0 } }; diff --git a/Modules/audioop.clinic.c b/Modules/audioop.clinic.c new file mode 100644 --- /dev/null +++ b/Modules/audioop.clinic.c @@ -0,0 +1,836 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(audioop_getsample__doc__, +"getsample(module, fragment, width, index)\n" +"Return the value of sample index from the fragment."); + +#define AUDIOOP_GETSAMPLE_METHODDEF \ + {"getsample", (PyCFunction)audioop_getsample, METH_VARARGS, audioop_getsample__doc__}, + +static PyObject * +audioop_getsample_impl(PyModuleDef *module, Py_buffer *fragment, int width, Py_ssize_t index); + +static PyObject * +audioop_getsample(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + Py_ssize_t index; + + if (!PyArg_ParseTuple(args, + "y*in:getsample", + &fragment, &width, &index)) + goto exit; + return_value = audioop_getsample_impl(module, &fragment, width, index); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_max__doc__, +"max(module, fragment, width)\n" +"Return the maximum of the absolute value of all samples in a fragment."); + +#define AUDIOOP_MAX_METHODDEF \ + {"max", (PyCFunction)audioop_max, METH_VARARGS, audioop_max__doc__}, + +static PyObject * +audioop_max_impl(PyModuleDef *module, Py_buffer *fragment, int width); + +static PyObject * +audioop_max(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + + if (!PyArg_ParseTuple(args, + "y*i:max", + &fragment, &width)) + goto exit; + return_value = audioop_max_impl(module, &fragment, width); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_minmax__doc__, +"minmax(module, fragment, width)\n" +"Return the minimum and maximum values of all samples in the sound fragment."); + +#define AUDIOOP_MINMAX_METHODDEF \ + {"minmax", (PyCFunction)audioop_minmax, METH_VARARGS, audioop_minmax__doc__}, + +static PyObject * +audioop_minmax_impl(PyModuleDef *module, Py_buffer *fragment, int width); + +static PyObject * +audioop_minmax(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + + if (!PyArg_ParseTuple(args, + "y*i:minmax", + &fragment, &width)) + goto exit; + return_value = audioop_minmax_impl(module, &fragment, width); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_avg__doc__, +"avg(module, fragment, width)\n" +"Return the average over all samples in the fragment."); + +#define AUDIOOP_AVG_METHODDEF \ + {"avg", (PyCFunction)audioop_avg, METH_VARARGS, audioop_avg__doc__}, + +static PyObject * +audioop_avg_impl(PyModuleDef *module, Py_buffer *fragment, int width); + +static PyObject * +audioop_avg(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + + if (!PyArg_ParseTuple(args, + "y*i:avg", + &fragment, &width)) + goto exit; + return_value = audioop_avg_impl(module, &fragment, width); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_rms__doc__, +"rms(module, fragment, width)\n" +"Return the root-mean-square of the fragment, i.e. sqrt(sum(S_i^2)/n)."); + +#define AUDIOOP_RMS_METHODDEF \ + {"rms", (PyCFunction)audioop_rms, METH_VARARGS, audioop_rms__doc__}, + +static PyObject * +audioop_rms_impl(PyModuleDef *module, Py_buffer *fragment, int width); + +static PyObject * +audioop_rms(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + + if (!PyArg_ParseTuple(args, + "y*i:rms", + &fragment, &width)) + goto exit; + return_value = audioop_rms_impl(module, &fragment, width); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_findfit__doc__, +"findfit(module, fragment, reference)\n" +"Try to match reference as well as possible to a portion of fragment."); + +#define AUDIOOP_FINDFIT_METHODDEF \ + {"findfit", (PyCFunction)audioop_findfit, METH_VARARGS, audioop_findfit__doc__}, + +static PyObject * +audioop_findfit_impl(PyModuleDef *module, Py_buffer *fragment, Py_buffer *reference); + +static PyObject * +audioop_findfit(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + Py_buffer reference = {NULL, NULL}; + + if (!PyArg_ParseTuple(args, + "y*y*:findfit", + &fragment, &reference)) + goto exit; + return_value = audioop_findfit_impl(module, &fragment, &reference); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + /* Cleanup for reference */ + if (reference.obj) + PyBuffer_Release(&reference); + + return return_value; +} + +PyDoc_STRVAR(audioop_findfactor__doc__, +"findfactor(module, fragment, reference)\n" +"Return a factor F such that rms(add(fragment, mul(reference, -F))) is minimal."); + +#define AUDIOOP_FINDFACTOR_METHODDEF \ + {"findfactor", (PyCFunction)audioop_findfactor, METH_VARARGS, audioop_findfactor__doc__}, + +static PyObject * +audioop_findfactor_impl(PyModuleDef *module, Py_buffer *fragment, Py_buffer *reference); + +static PyObject * +audioop_findfactor(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + Py_buffer reference = {NULL, NULL}; + + if (!PyArg_ParseTuple(args, + "y*y*:findfactor", + &fragment, &reference)) + goto exit; + return_value = audioop_findfactor_impl(module, &fragment, &reference); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + /* Cleanup for reference */ + if (reference.obj) + PyBuffer_Release(&reference); + + return return_value; +} + +PyDoc_STRVAR(audioop_findmax__doc__, +"findmax(module, fragment, length)\n" +"Search fragment for a slice of specified number of samples with maximum energy."); + +#define AUDIOOP_FINDMAX_METHODDEF \ + {"findmax", (PyCFunction)audioop_findmax, METH_VARARGS, audioop_findmax__doc__}, + +static PyObject * +audioop_findmax_impl(PyModuleDef *module, Py_buffer *fragment, Py_ssize_t length); + +static PyObject * +audioop_findmax(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + Py_ssize_t length; + + if (!PyArg_ParseTuple(args, + "y*n:findmax", + &fragment, &length)) + goto exit; + return_value = audioop_findmax_impl(module, &fragment, length); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_avgpp__doc__, +"avgpp(module, fragment, width)\n" +"Return the average peak-peak value over all samples in the fragment."); + +#define AUDIOOP_AVGPP_METHODDEF \ + {"avgpp", (PyCFunction)audioop_avgpp, METH_VARARGS, audioop_avgpp__doc__}, + +static PyObject * +audioop_avgpp_impl(PyModuleDef *module, Py_buffer *fragment, int width); + +static PyObject * +audioop_avgpp(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + + if (!PyArg_ParseTuple(args, + "y*i:avgpp", + &fragment, &width)) + goto exit; + return_value = audioop_avgpp_impl(module, &fragment, width); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_maxpp__doc__, +"maxpp(module, fragment, width)\n" +"Return the maximum peak-peak value in the sound fragment."); + +#define AUDIOOP_MAXPP_METHODDEF \ + {"maxpp", (PyCFunction)audioop_maxpp, METH_VARARGS, audioop_maxpp__doc__}, + +static PyObject * +audioop_maxpp_impl(PyModuleDef *module, Py_buffer *fragment, int width); + +static PyObject * +audioop_maxpp(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + + if (!PyArg_ParseTuple(args, + "y*i:maxpp", + &fragment, &width)) + goto exit; + return_value = audioop_maxpp_impl(module, &fragment, width); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_cross__doc__, +"cross(module, fragment, width)\n" +"Return the number of zero crossings in the fragment passed as an argument."); + +#define AUDIOOP_CROSS_METHODDEF \ + {"cross", (PyCFunction)audioop_cross, METH_VARARGS, audioop_cross__doc__}, + +static PyObject * +audioop_cross_impl(PyModuleDef *module, Py_buffer *fragment, int width); + +static PyObject * +audioop_cross(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + + if (!PyArg_ParseTuple(args, + "y*i:cross", + &fragment, &width)) + goto exit; + return_value = audioop_cross_impl(module, &fragment, width); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_mul__doc__, +"mul(module, fragment, width, factor)\n" +"Return a fragment that has all samples in the original fragment multiplied by the floating-point value factor."); + +#define AUDIOOP_MUL_METHODDEF \ + {"mul", (PyCFunction)audioop_mul, METH_VARARGS, audioop_mul__doc__}, + +static PyObject * +audioop_mul_impl(PyModuleDef *module, Py_buffer *fragment, int width, double factor); + +static PyObject * +audioop_mul(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + double factor; + + if (!PyArg_ParseTuple(args, + "y*id:mul", + &fragment, &width, &factor)) + goto exit; + return_value = audioop_mul_impl(module, &fragment, width, factor); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_tomono__doc__, +"tomono(module, fragment, width, lfactor, rfactor)\n" +"Convert a stereo fragment to a mono fragment."); + +#define AUDIOOP_TOMONO_METHODDEF \ + {"tomono", (PyCFunction)audioop_tomono, METH_VARARGS, audioop_tomono__doc__}, + +static PyObject * +audioop_tomono_impl(PyModuleDef *module, Py_buffer *fragment, int width, double lfactor, double rfactor); + +static PyObject * +audioop_tomono(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + double lfactor; + double rfactor; + + if (!PyArg_ParseTuple(args, + "y*idd:tomono", + &fragment, &width, &lfactor, &rfactor)) + goto exit; + return_value = audioop_tomono_impl(module, &fragment, width, lfactor, rfactor); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_tostereo__doc__, +"tostereo(module, fragment, width, lfactor, rfactor)\n" +"Generate a stereo fragment from a mono fragment."); + +#define AUDIOOP_TOSTEREO_METHODDEF \ + {"tostereo", (PyCFunction)audioop_tostereo, METH_VARARGS, audioop_tostereo__doc__}, + +static PyObject * +audioop_tostereo_impl(PyModuleDef *module, Py_buffer *fragment, int width, double lfactor, double rfactor); + +static PyObject * +audioop_tostereo(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + double lfactor; + double rfactor; + + if (!PyArg_ParseTuple(args, + "y*idd:tostereo", + &fragment, &width, &lfactor, &rfactor)) + goto exit; + return_value = audioop_tostereo_impl(module, &fragment, width, lfactor, rfactor); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_add__doc__, +"add(module, fragment1, fragment2, width)\n" +"Return a fragment which is the addition of the two samples passed as parameters."); + +#define AUDIOOP_ADD_METHODDEF \ + {"add", (PyCFunction)audioop_add, METH_VARARGS, audioop_add__doc__}, + +static PyObject * +audioop_add_impl(PyModuleDef *module, Py_buffer *fragment1, Py_buffer *fragment2, int width); + +static PyObject * +audioop_add(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment1 = {NULL, NULL}; + Py_buffer fragment2 = {NULL, NULL}; + int width; + + if (!PyArg_ParseTuple(args, + "y*y*i:add", + &fragment1, &fragment2, &width)) + goto exit; + return_value = audioop_add_impl(module, &fragment1, &fragment2, width); + +exit: + /* Cleanup for fragment1 */ + if (fragment1.obj) + PyBuffer_Release(&fragment1); + /* Cleanup for fragment2 */ + if (fragment2.obj) + PyBuffer_Release(&fragment2); + + return return_value; +} + +PyDoc_STRVAR(audioop_bias__doc__, +"bias(module, fragment, width, bias)\n" +"Return a fragment that is the original fragment with a bias added to each sample."); + +#define AUDIOOP_BIAS_METHODDEF \ + {"bias", (PyCFunction)audioop_bias, METH_VARARGS, audioop_bias__doc__}, + +static PyObject * +audioop_bias_impl(PyModuleDef *module, Py_buffer *fragment, int width, int bias); + +static PyObject * +audioop_bias(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + int bias; + + if (!PyArg_ParseTuple(args, + "y*ii:bias", + &fragment, &width, &bias)) + goto exit; + return_value = audioop_bias_impl(module, &fragment, width, bias); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_reverse__doc__, +"reverse(module, fragment, width)\n" +"Reverse the samples in a fragment and returns the modified fragment."); + +#define AUDIOOP_REVERSE_METHODDEF \ + {"reverse", (PyCFunction)audioop_reverse, METH_VARARGS, audioop_reverse__doc__}, + +static PyObject * +audioop_reverse_impl(PyModuleDef *module, Py_buffer *fragment, int width); + +static PyObject * +audioop_reverse(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + + if (!PyArg_ParseTuple(args, + "y*i:reverse", + &fragment, &width)) + goto exit; + return_value = audioop_reverse_impl(module, &fragment, width); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_byteswap__doc__, +"byteswap(module, fragment, width)\n" +"Convert big-endian samples to little-endian and vice versa."); + +#define AUDIOOP_BYTESWAP_METHODDEF \ + {"byteswap", (PyCFunction)audioop_byteswap, METH_VARARGS, audioop_byteswap__doc__}, + +static PyObject * +audioop_byteswap_impl(PyModuleDef *module, Py_buffer *fragment, int width); + +static PyObject * +audioop_byteswap(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + + if (!PyArg_ParseTuple(args, + "y*i:byteswap", + &fragment, &width)) + goto exit; + return_value = audioop_byteswap_impl(module, &fragment, width); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_lin2lin__doc__, +"lin2lin(module, fragment, width, newwidth)\n" +"Convert samples between 1-, 2-, 3- and 4-byte formats."); + +#define AUDIOOP_LIN2LIN_METHODDEF \ + {"lin2lin", (PyCFunction)audioop_lin2lin, METH_VARARGS, audioop_lin2lin__doc__}, + +static PyObject * +audioop_lin2lin_impl(PyModuleDef *module, Py_buffer *fragment, int width, int newwidth); + +static PyObject * +audioop_lin2lin(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + int newwidth; + + if (!PyArg_ParseTuple(args, + "y*ii:lin2lin", + &fragment, &width, &newwidth)) + goto exit; + return_value = audioop_lin2lin_impl(module, &fragment, width, newwidth); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_ratecv__doc__, +"ratecv(module, fragment, width, nchannels, inrate, outrate, state, weightA=1, weightB=0)\n" +"Convert the frame rate of the input fragment."); + +#define AUDIOOP_RATECV_METHODDEF \ + {"ratecv", (PyCFunction)audioop_ratecv, METH_VARARGS, audioop_ratecv__doc__}, + +static PyObject * +audioop_ratecv_impl(PyModuleDef *module, Py_buffer *fragment, int width, int nchannels, int inrate, int outrate, PyObject *state, int weightA, int weightB); + +static PyObject * +audioop_ratecv(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + int nchannels; + int inrate; + int outrate; + PyObject *state; + int weightA = 1; + int weightB = 0; + + if (!PyArg_ParseTuple(args, + "y*iiiiO|ii:ratecv", + &fragment, &width, &nchannels, &inrate, &outrate, &state, &weightA, &weightB)) + goto exit; + return_value = audioop_ratecv_impl(module, &fragment, width, nchannels, inrate, outrate, state, weightA, weightB); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_lin2ulaw__doc__, +"lin2ulaw(module, fragment, width)\n" +"Convert samples in the audio fragment to u-LAW encoding."); + +#define AUDIOOP_LIN2ULAW_METHODDEF \ + {"lin2ulaw", (PyCFunction)audioop_lin2ulaw, METH_VARARGS, audioop_lin2ulaw__doc__}, + +static PyObject * +audioop_lin2ulaw_impl(PyModuleDef *module, Py_buffer *fragment, int width); + +static PyObject * +audioop_lin2ulaw(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + + if (!PyArg_ParseTuple(args, + "y*i:lin2ulaw", + &fragment, &width)) + goto exit; + return_value = audioop_lin2ulaw_impl(module, &fragment, width); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_ulaw2lin__doc__, +"ulaw2lin(module, fragment, width)\n" +"Convert sound fragments in u-LAW encoding to linearly encoded sound fragments."); + +#define AUDIOOP_ULAW2LIN_METHODDEF \ + {"ulaw2lin", (PyCFunction)audioop_ulaw2lin, METH_VARARGS, audioop_ulaw2lin__doc__}, + +static PyObject * +audioop_ulaw2lin_impl(PyModuleDef *module, Py_buffer *fragment, int width); + +static PyObject * +audioop_ulaw2lin(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + + if (!PyArg_ParseTuple(args, + "y*i:ulaw2lin", + &fragment, &width)) + goto exit; + return_value = audioop_ulaw2lin_impl(module, &fragment, width); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_lin2alaw__doc__, +"lin2alaw(module, fragment, width)\n" +"Convert samples in the audio fragment to a-LAW encoding."); + +#define AUDIOOP_LIN2ALAW_METHODDEF \ + {"lin2alaw", (PyCFunction)audioop_lin2alaw, METH_VARARGS, audioop_lin2alaw__doc__}, + +static PyObject * +audioop_lin2alaw_impl(PyModuleDef *module, Py_buffer *fragment, int width); + +static PyObject * +audioop_lin2alaw(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + + if (!PyArg_ParseTuple(args, + "y*i:lin2alaw", + &fragment, &width)) + goto exit; + return_value = audioop_lin2alaw_impl(module, &fragment, width); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_alaw2lin__doc__, +"alaw2lin(module, fragment, width)\n" +"Convert sound fragments in a-LAW encoding to linearly encoded sound fragments."); + +#define AUDIOOP_ALAW2LIN_METHODDEF \ + {"alaw2lin", (PyCFunction)audioop_alaw2lin, METH_VARARGS, audioop_alaw2lin__doc__}, + +static PyObject * +audioop_alaw2lin_impl(PyModuleDef *module, Py_buffer *fragment, int width); + +static PyObject * +audioop_alaw2lin(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + + if (!PyArg_ParseTuple(args, + "y*i:alaw2lin", + &fragment, &width)) + goto exit; + return_value = audioop_alaw2lin_impl(module, &fragment, width); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_lin2adpcm__doc__, +"lin2adpcm(module, fragment, width, state)\n" +"Convert samples to 4 bit Intel/DVI ADPCM encoding."); + +#define AUDIOOP_LIN2ADPCM_METHODDEF \ + {"lin2adpcm", (PyCFunction)audioop_lin2adpcm, METH_VARARGS, audioop_lin2adpcm__doc__}, + +static PyObject * +audioop_lin2adpcm_impl(PyModuleDef *module, Py_buffer *fragment, int width, PyObject *state); + +static PyObject * +audioop_lin2adpcm(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + PyObject *state; + + if (!PyArg_ParseTuple(args, + "y*iO:lin2adpcm", + &fragment, &width, &state)) + goto exit; + return_value = audioop_lin2adpcm_impl(module, &fragment, width, state); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} + +PyDoc_STRVAR(audioop_adpcm2lin__doc__, +"adpcm2lin(module, fragment, width, state)\n" +"Decode an Intel/DVI ADPCM coded fragment to a linear fragment."); + +#define AUDIOOP_ADPCM2LIN_METHODDEF \ + {"adpcm2lin", (PyCFunction)audioop_adpcm2lin, METH_VARARGS, audioop_adpcm2lin__doc__}, + +static PyObject * +audioop_adpcm2lin_impl(PyModuleDef *module, Py_buffer *fragment, int width, PyObject *state); + +static PyObject * +audioop_adpcm2lin(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer fragment = {NULL, NULL}; + int width; + PyObject *state; + + if (!PyArg_ParseTuple(args, + "y*iO:adpcm2lin", + &fragment, &width, &state)) + goto exit; + return_value = audioop_adpcm2lin_impl(module, &fragment, width, state); + +exit: + /* Cleanup for fragment */ + if (fragment.obj) + PyBuffer_Release(&fragment); + + return return_value; +} +/*[clinic end generated code: checksum=0d9fa2c5719e996b169f808350016cd622799562]*/ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 11:08:02 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 25 Jan 2014 11:08:02 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320193=3A_The_=5Fb?= =?utf-8?q?z2_module_now_uses_Argument_Clinic=2E?= Message-ID: <3fBCb66XdBzMfZ@mail.python.org> http://hg.python.org/cpython/rev/0a3e02251bd6 changeset: 88688:0a3e02251bd6 user: Serhiy Storchaka date: Sat Jan 25 12:07:57 2014 +0200 summary: Issue #20193: The _bz2 module now uses Argument Clinic. files: Modules/_bz2module.c | 164 +++++++++++++---------- Modules/_bz2module.clinic.c | 149 +++++++++++++++++++++ 2 files changed, 241 insertions(+), 72 deletions(-) diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -196,44 +196,61 @@ return NULL; } -PyDoc_STRVAR(BZ2Compressor_compress__doc__, -"compress(data) -> bytes\n" -"\n" -"Provide data to the compressor object. Returns a chunk of\n" -"compressed data if possible, or b'' otherwise.\n" -"\n" -"When you have finished providing data to the compressor, call the\n" -"flush() method to finish the compression process.\n"); +/*[clinic input] +output preset file +module _bz2 +class _bz2.BZ2Compressor +class _bz2.BZ2Decompressor +[clinic start generated code]*/ +/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + +#include "_bz2module.clinic.c" + +/*[clinic input] +_bz2.BZ2Compressor.compress + + self: self(type="BZ2Compressor *") + data: Py_buffer + / + +Provide data to the compressor object. + +Returns a chunk of compressed data if possible, or b'' otherwise. + +When you have finished providing data to the compressor, call the +flush() method to finish the compression process. +[clinic start generated code]*/ static PyObject * -BZ2Compressor_compress(BZ2Compressor *self, PyObject *args) +_bz2_BZ2Compressor_compress_impl(BZ2Compressor *self, Py_buffer *data) +/*[clinic end generated code: checksum=59365426e941fbcc4c7a4d0eef85ca7e19196eaa]*/ { - Py_buffer buffer; PyObject *result = NULL; - if (!PyArg_ParseTuple(args, "y*:compress", &buffer)) - return NULL; - ACQUIRE_LOCK(self); if (self->flushed) PyErr_SetString(PyExc_ValueError, "Compressor has been flushed"); else - result = compress(self, buffer.buf, buffer.len, BZ_RUN); + result = compress(self, data->buf, data->len, BZ_RUN); RELEASE_LOCK(self); - PyBuffer_Release(&buffer); return result; } -PyDoc_STRVAR(BZ2Compressor_flush__doc__, -"flush() -> bytes\n" -"\n" -"Finish the compression process. Returns the compressed data left\n" -"in internal buffers.\n" -"\n" -"The compressor object may not be used after this method is called.\n"); +/*[clinic input] +_bz2.BZ2Compressor.flush + + self: self(type="BZ2Compressor *") + +Finish the compression process. + +Returns the compressed data left in internal buffers. + +The compressor object may not be used after this method is called. +[clinic start generated code]*/ static PyObject * -BZ2Compressor_flush(BZ2Compressor *self, PyObject *noargs) +_bz2_BZ2Compressor_flush_impl(BZ2Compressor *self) +/*[clinic end generated code: checksum=3ef03fc1b092a701b382b97096c7fd50db87190b]*/ { PyObject *result = NULL; @@ -274,14 +291,25 @@ PyMem_RawFree(ptr); } +/*[clinic input] +_bz2.BZ2Compressor.__init__ + + self: self(type="BZ2Compressor *") + compresslevel: int = 9 + Compression level, as a number between 1 and 9. + / + +Create a compressor object for compressing data incrementally. + +For one-shot compression, use the compress() function instead. +[clinic start generated code]*/ + static int -BZ2Compressor_init(BZ2Compressor *self, PyObject *args, PyObject *kwargs) +_bz2_BZ2Compressor___init___impl(BZ2Compressor *self, int compresslevel) +/*[clinic end generated code: checksum=c4e6adfd02963827075a1cc9309dc6df184b1246]*/ { - int compresslevel = 9; int bzerror; - if (!PyArg_ParseTuple(args, "|i:BZ2Compressor", &compresslevel)) - return -1; if (!(1 <= compresslevel && compresslevel <= 9)) { PyErr_SetString(PyExc_ValueError, "compresslevel must be between 1 and 9"); @@ -325,22 +353,12 @@ } static PyMethodDef BZ2Compressor_methods[] = { - {"compress", (PyCFunction)BZ2Compressor_compress, METH_VARARGS, - BZ2Compressor_compress__doc__}, - {"flush", (PyCFunction)BZ2Compressor_flush, METH_NOARGS, - BZ2Compressor_flush__doc__}, + _BZ2_BZ2COMPRESSOR_COMPRESS_METHODDEF + _BZ2_BZ2COMPRESSOR_FLUSH_METHODDEF {"__getstate__", (PyCFunction)BZ2Compressor_getstate, METH_NOARGS}, {NULL} }; -PyDoc_STRVAR(BZ2Compressor__doc__, -"BZ2Compressor(compresslevel=9)\n" -"\n" -"Create a compressor object for compressing data incrementally.\n" -"\n" -"compresslevel, if given, must be a number between 1 and 9.\n" -"\n" -"For one-shot compression, use the compress() function instead.\n"); static PyTypeObject BZ2Compressor_Type = { PyVarObject_HEAD_INIT(NULL, 0) @@ -363,7 +381,7 @@ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ - BZ2Compressor__doc__, /* tp_doc */ + _bz2_BZ2Compressor___init____doc__, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ @@ -378,7 +396,7 @@ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - (initproc)BZ2Compressor_init, /* tp_init */ + _bz2_BZ2Compressor___init__, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ }; @@ -451,32 +469,34 @@ return NULL; } -PyDoc_STRVAR(BZ2Decompressor_decompress__doc__, -"decompress(data) -> bytes\n" -"\n" -"Provide data to the decompressor object. Returns a chunk of\n" -"decompressed data if possible, or b'' otherwise.\n" -"\n" -"Attempting to decompress data after the end of stream is reached\n" -"raises an EOFError. Any data found after the end of the stream\n" -"is ignored and saved in the unused_data attribute.\n"); +/*[clinic input] +_bz2.BZ2Decompressor.decompress + + self: self(type="BZ2Decompressor *") + data: Py_buffer + / + +Provide data to the decompressor object. + +Returns a chunk of decompressed data if possible, or b'' otherwise. + +Attempting to decompress data after the end of stream is reached +raises an EOFError. Any data found after the end of the stream +is ignored and saved in the unused_data attribute. +[clinic start generated code]*/ static PyObject * -BZ2Decompressor_decompress(BZ2Decompressor *self, PyObject *args) +_bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data) +/*[clinic end generated code: checksum=086e4b99e60cb3f67c0481959591eae0735320bc]*/ { - Py_buffer buffer; PyObject *result = NULL; - if (!PyArg_ParseTuple(args, "y*:decompress", &buffer)) - return NULL; - ACQUIRE_LOCK(self); if (self->eof) PyErr_SetString(PyExc_EOFError, "End of stream already reached"); else - result = decompress(self, buffer.buf, buffer.len); + result = decompress(self, data->buf, data->len); RELEASE_LOCK(self); - PyBuffer_Release(&buffer); return result; } @@ -488,14 +508,22 @@ return NULL; } +/*[clinic input] +_bz2.BZ2Decompressor.__init__ + + self: self(type="BZ2Decompressor *") + +Create a decompressor object for decompressing data incrementally. + +For one-shot decompression, use the decompress() function instead. +[clinic start generated code]*/ + static int -BZ2Decompressor_init(BZ2Decompressor *self, PyObject *args, PyObject *kwargs) +_bz2_BZ2Decompressor___init___impl(BZ2Decompressor *self) +/*[clinic end generated code: checksum=e4d2b9bb866ab8f1f4a8bb786ddb5b614ce323c0]*/ { int bzerror; - if (!PyArg_ParseTuple(args, ":BZ2Decompressor")) - return -1; - #ifdef WITH_THREAD self->lock = PyThread_allocate_lock(); if (self->lock == NULL) { @@ -536,8 +564,7 @@ } static PyMethodDef BZ2Decompressor_methods[] = { - {"decompress", (PyCFunction)BZ2Decompressor_decompress, METH_VARARGS, - BZ2Decompressor_decompress__doc__}, + _BZ2_BZ2DECOMPRESSOR_DECOMPRESS_METHODDEF {"__getstate__", (PyCFunction)BZ2Decompressor_getstate, METH_NOARGS}, {NULL} }; @@ -556,13 +583,6 @@ {NULL} }; -PyDoc_STRVAR(BZ2Decompressor__doc__, -"BZ2Decompressor()\n" -"\n" -"Create a decompressor object for decompressing data incrementally.\n" -"\n" -"For one-shot decompression, use the decompress() function instead.\n"); - static PyTypeObject BZ2Decompressor_Type = { PyVarObject_HEAD_INIT(NULL, 0) "_bz2.BZ2Decompressor", /* tp_name */ @@ -584,7 +604,7 @@ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ - BZ2Decompressor__doc__, /* tp_doc */ + _bz2_BZ2Decompressor___init____doc__, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ @@ -599,7 +619,7 @@ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - (initproc)BZ2Decompressor_init, /* tp_init */ + _bz2_BZ2Decompressor___init__, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ }; diff --git a/Modules/_bz2module.clinic.c b/Modules/_bz2module.clinic.c new file mode 100644 --- /dev/null +++ b/Modules/_bz2module.clinic.c @@ -0,0 +1,149 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(_bz2_BZ2Compressor_compress__doc__, +"compress(self, data)\n" +"Provide data to the compressor object.\n" +"\n" +"Returns a chunk of compressed data if possible, or b\'\' otherwise.\n" +"\n" +"When you have finished providing data to the compressor, call the\n" +"flush() method to finish the compression process."); + +#define _BZ2_BZ2COMPRESSOR_COMPRESS_METHODDEF \ + {"compress", (PyCFunction)_bz2_BZ2Compressor_compress, METH_VARARGS, _bz2_BZ2Compressor_compress__doc__}, + +static PyObject * +_bz2_BZ2Compressor_compress_impl(BZ2Compressor *self, Py_buffer *data); + +static PyObject * +_bz2_BZ2Compressor_compress(BZ2Compressor *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + + if (!PyArg_ParseTuple(args, + "y*:compress", + &data)) + goto exit; + return_value = _bz2_BZ2Compressor_compress_impl(self, &data); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(_bz2_BZ2Compressor_flush__doc__, +"flush(self)\n" +"Finish the compression process.\n" +"\n" +"Returns the compressed data left in internal buffers.\n" +"\n" +"The compressor object may not be used after this method is called."); + +#define _BZ2_BZ2COMPRESSOR_FLUSH_METHODDEF \ + {"flush", (PyCFunction)_bz2_BZ2Compressor_flush, METH_NOARGS, _bz2_BZ2Compressor_flush__doc__}, + +static PyObject * +_bz2_BZ2Compressor_flush_impl(BZ2Compressor *self); + +static PyObject * +_bz2_BZ2Compressor_flush(BZ2Compressor *self, PyObject *Py_UNUSED(ignored)) +{ + return _bz2_BZ2Compressor_flush_impl(self); +} + +PyDoc_STRVAR(_bz2_BZ2Compressor___init____doc__, +"BZ2Compressor(compresslevel=9)\n" +"Create a compressor object for compressing data incrementally.\n" +"\n" +" compresslevel\n" +" Compression level, as a number between 1 and 9.\n" +"\n" +"For one-shot compression, use the compress() function instead."); + +static int +_bz2_BZ2Compressor___init___impl(BZ2Compressor *self, int compresslevel); + +static int +_bz2_BZ2Compressor___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + int compresslevel = 9; + + if (!_PyArg_NoKeywords("BZ2Compressor", kwargs)) + goto exit; + if (!PyArg_ParseTuple(args, + "|i:BZ2Compressor", + &compresslevel)) + goto exit; + return_value = _bz2_BZ2Compressor___init___impl((BZ2Compressor *)self, compresslevel); + +exit: + return return_value; +} + +PyDoc_STRVAR(_bz2_BZ2Decompressor_decompress__doc__, +"decompress(self, data)\n" +"Provide data to the decompressor object.\n" +"\n" +"Returns a chunk of decompressed data if possible, or b\'\' otherwise.\n" +"\n" +"Attempting to decompress data after the end of stream is reached\n" +"raises an EOFError. Any data found after the end of the stream\n" +"is ignored and saved in the unused_data attribute."); + +#define _BZ2_BZ2DECOMPRESSOR_DECOMPRESS_METHODDEF \ + {"decompress", (PyCFunction)_bz2_BZ2Decompressor_decompress, METH_VARARGS, _bz2_BZ2Decompressor_decompress__doc__}, + +static PyObject * +_bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data); + +static PyObject * +_bz2_BZ2Decompressor_decompress(BZ2Decompressor *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + + if (!PyArg_ParseTuple(args, + "y*:decompress", + &data)) + goto exit; + return_value = _bz2_BZ2Decompressor_decompress_impl(self, &data); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(_bz2_BZ2Decompressor___init____doc__, +"BZ2Decompressor()\n" +"Create a decompressor object for decompressing data incrementally.\n" +"\n" +"For one-shot decompression, use the decompress() function instead."); + +static int +_bz2_BZ2Decompressor___init___impl(BZ2Decompressor *self); + +static int +_bz2_BZ2Decompressor___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + + if (!_PyArg_NoPositional("BZ2Decompressor", args)) + goto exit; + if (!_PyArg_NoKeywords("BZ2Decompressor", kwargs)) + goto exit; + return_value = _bz2_BZ2Decompressor___init___impl((BZ2Decompressor *)self); + +exit: + return return_value; +} +/*[clinic end generated code: checksum=9bb33ae7d35494b7a5365f03f390e4b5b8b1bc49]*/ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 11:11:32 2014 From: python-checkins at python.org (ezio.melotti) Date: Sat, 25 Jan 2014 11:11:32 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?devguide=3A_Update_a_couple_of_links_?= =?utf-8?q?in_the_FAQs=2E?= Message-ID: <3fBCg82WTtz7LjP@mail.python.org> http://hg.python.org/devguide/rev/bdf4e11ffccc changeset: 662:bdf4e11ffccc user: Ezio Melotti date: Sat Jan 25 12:10:52 2014 +0200 summary: Update a couple of links in the FAQs. files: faq.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/faq.rst b/faq.rst --- a/faq.rst +++ b/faq.rst @@ -58,8 +58,8 @@ .. _issue tracker: http://bugs.python.org .. _PEP Index: http://www.python.org/dev/peps .. _draft PEP: http://www.python.org/dev/peps/pep-0001/ -.. _Status Quo Wins a Stalemate: http://www.boredomandlaziness.org/2011/02/status-quo-wins-stalemate.html -.. _Justifying Python Language Changes: http://www.boredomandlaziness.org/2011/02/justifying-python-language-changes.html +.. _Status Quo Wins a Stalemate: http://www.curiousefficiency.org/posts/2011/02/status-quo-wins-stalemate.html +.. _Justifying Python Language Changes: http://www.curiousefficiency.org/posts/2011/02/justifying-python-language-changes.html Where should I ask general questions about contributing to CPython? ------------------------------------------------------------------- -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat Jan 25 11:13:20 2014 From: python-checkins at python.org (eric.smith) Date: Sat, 25 Jan 2014 11:13:20 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogRml4IGdyYW1tYXIu?= Message-ID: <3fBCjD2tFBz7LjP@mail.python.org> http://hg.python.org/cpython/rev/a516eec7117e changeset: 88689:a516eec7117e branch: 3.3 parent: 88681:3551f184b282 user: Eric V. Smith date: Sat Jan 25 05:11:43 2014 -0500 summary: Fix grammar. files: Doc/whatsnew/3.3.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1767,7 +1767,7 @@ select ------ -Solaris and derivatives platforms have a new class :class:`select.devpoll` +Solaris and derivative platforms have a new class :class:`select.devpoll` for high performance asynchronous sockets via :file:`/dev/poll`. (Contributed by Jes?s Cea Avi?n in :issue:`6397`.) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 11:13:21 2014 From: python-checkins at python.org (eric.smith) Date: Sat, 25 Jan 2014 11:13:21 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Fix_grammar=3A_merge_with_3=2E3=2E?= Message-ID: <3fBCjF4LxCz7LjP@mail.python.org> http://hg.python.org/cpython/rev/92292b81dca4 changeset: 88690:92292b81dca4 parent: 88688:0a3e02251bd6 parent: 88689:a516eec7117e user: Eric V. Smith date: Sat Jan 25 05:12:11 2014 -0500 summary: Fix grammar: merge with 3.3. files: Doc/whatsnew/3.3.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1767,7 +1767,7 @@ select ------ -Solaris and derivatives platforms have a new class :class:`select.devpoll` +Solaris and derivative platforms have a new class :class:`select.devpoll` for high performance asynchronous sockets via :file:`/dev/poll`. (Contributed by Jes?s Cea Avi?n in :issue:`6397`.) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 13:02:37 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 25 Jan 2014 13:02:37 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320193=3A_The_=5Fl?= =?utf-8?q?zma_module_now_uses_Argument_Clinic=2E?= Message-ID: <3fBG7K3qjtz7LkF@mail.python.org> http://hg.python.org/cpython/rev/7ba9642fc800 changeset: 88691:7ba9642fc800 user: Serhiy Storchaka date: Sat Jan 25 14:02:29 2014 +0200 summary: Issue #20193: The _lzma module now uses Argument Clinic. LZMACompressor.__init__ is left not converted. files: Modules/_lzmamodule.c | 349 +++++++++++++--------- Modules/_lzmamodule.clinic.c | 231 +++++++++++++++ 2 files changed, 434 insertions(+), 146 deletions(-) diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -298,36 +298,37 @@ return options; } -static void * -parse_filter_spec(lzma_filter *f, PyObject *spec) +static int +lzma_filter_converter(PyObject *spec, void *ptr) { + lzma_filter *f = (lzma_filter *)ptr; PyObject *id_obj; if (!PyMapping_Check(spec)) { PyErr_SetString(PyExc_TypeError, "Filter specifier must be a dict or dict-like object"); - return NULL; + return 0; } id_obj = PyMapping_GetItemString(spec, "id"); if (id_obj == NULL) { if (PyErr_ExceptionMatches(PyExc_KeyError)) PyErr_SetString(PyExc_ValueError, "Filter specifier must have an \"id\" entry"); - return NULL; + return 0; } f->id = PyLong_AsUnsignedLongLong(id_obj); Py_DECREF(id_obj); if (PyErr_Occurred()) - return NULL; + return 0; switch (f->id) { case LZMA_FILTER_LZMA1: case LZMA_FILTER_LZMA2: f->options = parse_filter_spec_lzma(spec); - return f->options; + return f->options != NULL; case LZMA_FILTER_DELTA: f->options = parse_filter_spec_delta(spec); - return f->options; + return f->options != NULL; case LZMA_FILTER_X86: case LZMA_FILTER_POWERPC: case LZMA_FILTER_IA64: @@ -335,10 +336,10 @@ case LZMA_FILTER_ARMTHUMB: case LZMA_FILTER_SPARC: f->options = parse_filter_spec_bcj(spec); - return f->options; + return f->options != NULL; default: PyErr_Format(PyExc_ValueError, "Invalid filter ID: %llu", f->id); - return NULL; + return 0; } } @@ -369,7 +370,7 @@ for (i = 0; i < num_filters; i++) { int ok = 1; PyObject *spec = PySequence_GetItem(filterspecs, i); - if (spec == NULL || parse_filter_spec(&filters[i], spec) == NULL) + if (spec == NULL || !lzma_filter_converter(spec, &filters[i])) ok = 0; Py_XDECREF(spec); if (!ok) { @@ -468,6 +469,36 @@ } +/*[clinic input] +output preset file +module _lzma +class _lzma.LZMACompressor +class _lzma.LZMADecompressor +[clinic start generated code]*/ +/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + +#include "_lzmamodule.clinic.c" + +/*[python input] + +class lzma_vli_converter(CConverter): + type = 'lzma_vli' + converter = 'lzma_vli_converter' + +class lzma_filter_converter(CConverter): + type = 'lzma_filter' + converter = 'lzma_filter_converter' + c_default = c_ignored_default = "{LZMA_VLI_UNKNOWN, NULL}" + + def cleanup(self): + name = ensure_legal_c_identifier(self.name) + return ('if (%(name)s.id != LZMA_VLI_UNKNOWN)\n' + ' PyMem_Free(%(name)s.options);\n') % {'name': name} + +[python start generated code]*/ +/*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + + /* LZMACompressor class. */ static PyObject * @@ -512,44 +543,51 @@ return NULL; } -PyDoc_STRVAR(Compressor_compress_doc, -"compress(data) -> bytes\n" -"\n" -"Provide data to the compressor object. Returns a chunk of\n" -"compressed data if possible, or b\"\" otherwise.\n" -"\n" -"When you have finished providing data to the compressor, call the\n" -"flush() method to finish the conversion process.\n"); +/*[clinic input] +_lzma.LZMACompressor.compress + + self: self(type="Compressor *") + data: Py_buffer + / + +Provide data to the compressor object. + +Returns a chunk of compressed data if possible, or b'' otherwise. + +When you have finished providing data to the compressor, call the +flush() method to finish the compression process. +[clinic start generated code]*/ static PyObject * -Compressor_compress(Compressor *self, PyObject *args) +_lzma_LZMACompressor_compress_impl(Compressor *self, Py_buffer *data) +/*[clinic end generated code: checksum=31f615136963e00f26f8be33440ec1e3604565ba]*/ { - Py_buffer buffer; PyObject *result = NULL; - if (!PyArg_ParseTuple(args, "y*:compress", &buffer)) - return NULL; - ACQUIRE_LOCK(self); if (self->flushed) PyErr_SetString(PyExc_ValueError, "Compressor has been flushed"); else - result = compress(self, buffer.buf, buffer.len, LZMA_RUN); + result = compress(self, data->buf, data->len, LZMA_RUN); RELEASE_LOCK(self); - PyBuffer_Release(&buffer); return result; } -PyDoc_STRVAR(Compressor_flush_doc, -"flush() -> bytes\n" -"\n" -"Finish the compression process. Returns the compressed data left\n" -"in internal buffers.\n" -"\n" -"The compressor object cannot be used after this method is called.\n"); +/*[clinic input] +_lzma.LZMACompressor.flush + + self: self(type="Compressor *") + +Finish the compression process. + +Returns the compressed data left in internal buffers. + +The compressor object may not be used after this method is called. +[clinic start generated code]*/ static PyObject * -Compressor_flush(Compressor *self, PyObject *noargs) +_lzma_LZMACompressor_flush_impl(Compressor *self) +/*[clinic end generated code: checksum=fec21f3e22504f500606ba60e1ba70d79eb22188]*/ { PyObject *result = NULL; @@ -650,6 +688,39 @@ return 0; } +/*[-clinic input] +_lzma.LZMACompressor.__init__ + + self: self(type="Compressor *") + format: int(c_default="FORMAT_XZ") = FORMAT_XZ + The container format to use for the output. This can + be FORMAT_XZ (default), FORMAT_ALONE, or FORMAT_RAW. + + check: int(c_default="-1") = unspecified + The integrity check to use. For FORMAT_XZ, the default + is CHECK_CRC64. FORMAT_ALONE and FORMAT_RAW do not suport integrity + checks; for these formats, check must be omitted, or be CHECK_NONE. + + preset: object = None + If provided should be an integer in the range 0-9, optionally + OR-ed with the constant PRESET_EXTREME. + + filters: object = None + If provided should be a sequence of dicts. Each dict should + have an entry for "id" indicating the ID of the filter, plus + additional entries for options to the filter. + +Create a compressor object for compressing data incrementally. + +The settings used by the compressor can be specified either as a +preset compression level (with the 'preset' argument), or in detail +as a custom filter chain (with the 'filters' argument). For FORMAT_XZ +and FORMAT_ALONE, the default is to use the PRESET_DEFAULT preset +level. For FORMAT_RAW, the caller must always specify a filter chain; +the raw compressor does not support preset compression levels. + +For one-shot compression, use the compress() function instead. +[-clinic start generated code]*/ static int Compressor_init(Compressor *self, PyObject *args, PyObject *kwargs) { @@ -739,10 +810,8 @@ } static PyMethodDef Compressor_methods[] = { - {"compress", (PyCFunction)Compressor_compress, METH_VARARGS, - Compressor_compress_doc}, - {"flush", (PyCFunction)Compressor_flush, METH_NOARGS, - Compressor_flush_doc}, + _LZMA_LZMACOMPRESSOR_COMPRESS_METHODDEF + _LZMA_LZMACOMPRESSOR_FLUSH_METHODDEF {"__getstate__", (PyCFunction)Compressor_getstate, METH_NOARGS}, {NULL} }; @@ -872,32 +941,34 @@ return NULL; } -PyDoc_STRVAR(Decompressor_decompress_doc, -"decompress(data) -> bytes\n" -"\n" -"Provide data to the decompressor object. Returns a chunk of\n" -"decompressed data if possible, or b\"\" otherwise.\n" -"\n" -"Attempting to decompress data after the end of the stream is\n" -"reached raises an EOFError. Any data found after the end of the\n" -"stream is ignored, and saved in the unused_data attribute.\n"); +/*[clinic input] +_lzma.LZMADecompressor.decompress + + self: self(type="Decompressor *") + data: Py_buffer + / + +Provide data to the decompressor object. + +Returns a chunk of decompressed data if possible, or b'' otherwise. + +Attempting to decompress data after the end of stream is reached +raises an EOFError. Any data found after the end of the stream +is ignored and saved in the unused_data attribute. +[clinic start generated code]*/ static PyObject * -Decompressor_decompress(Decompressor *self, PyObject *args) +_lzma_LZMADecompressor_decompress_impl(Decompressor *self, Py_buffer *data) +/*[clinic end generated code: checksum=d86e78da7ff0ff219d511275b16b79476da8922e]*/ { - Py_buffer buffer; PyObject *result = NULL; - if (!PyArg_ParseTuple(args, "y*:decompress", &buffer)) - return NULL; - ACQUIRE_LOCK(self); if (self->eof) PyErr_SetString(PyExc_EOFError, "Already at end of stream"); else - result = decompress(self, buffer.buf, buffer.len); + result = decompress(self, data->buf, data->len); RELEASE_LOCK(self); - PyBuffer_Release(&buffer); return result; } @@ -925,38 +996,56 @@ return 0; } +/*[clinic input] +_lzma.LZMADecompressor.__init__ + + self: self(type="Decompressor *") + format: int(c_default="FORMAT_AUTO") = FORMAT_AUTO + Specifies the container format of the input stream. If this is + FORMAT_AUTO (the default), the decompressor will automatically detect + whether the input is FORMAT_XZ or FORMAT_ALONE. Streams created with + FORMAT_RAW cannot be autodetected. + + memlimit: object = None + Limit the amount of memory used by the decompressor. This will cause + decompression to fail if the input cannot be decompressed within the + given limit. + + filters: object = None + A custom filter chain. This argument is required for FORMAT_RAW, and + not accepted with any other format. When provided, this should be a + sequence of dicts, each indicating the ID and options for a single + filter. + +Create a decompressor object for decompressing data incrementally. + +For one-shot decompression, use the decompress() function instead. +[clinic start generated code]*/ + static int -Decompressor_init(Decompressor *self, PyObject *args, PyObject *kwargs) +_lzma_LZMADecompressor___init___impl(Decompressor *self, int format, PyObject *memlimit, PyObject *filters) +/*[clinic end generated code: checksum=9b119f6f2cc2d7a8e5be41c164a6c080ee82d0c2]*/ { - static char *arg_names[] = {"format", "memlimit", "filters", NULL}; const uint32_t decoder_flags = LZMA_TELL_ANY_CHECK | LZMA_TELL_NO_CHECK; - int format = FORMAT_AUTO; - uint64_t memlimit = UINT64_MAX; - PyObject *memlimit_obj = Py_None; - PyObject *filterspecs = Py_None; + uint64_t memlimit_ = UINT64_MAX; lzma_ret lzret; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "|iOO:LZMADecompressor", arg_names, - &format, &memlimit_obj, &filterspecs)) - return -1; - - if (memlimit_obj != Py_None) { + if (memlimit != Py_None) { if (format == FORMAT_RAW) { PyErr_SetString(PyExc_ValueError, "Cannot specify memory limit with FORMAT_RAW"); return -1; } - memlimit = PyLong_AsUnsignedLongLong(memlimit_obj); + memlimit_ = PyLong_AsUnsignedLongLong(memlimit); if (PyErr_Occurred()) return -1; } - if (format == FORMAT_RAW && filterspecs == Py_None) { + if (format == FORMAT_RAW && filters == Py_None) { PyErr_SetString(PyExc_ValueError, "Must specify filters for FORMAT_RAW"); return -1; - } else if (format != FORMAT_RAW && filterspecs != Py_None) { + } else if (format != FORMAT_RAW && filters != Py_None) { PyErr_SetString(PyExc_ValueError, "Cannot specify filters except with FORMAT_RAW"); return -1; @@ -982,27 +1071,27 @@ switch (format) { case FORMAT_AUTO: - lzret = lzma_auto_decoder(&self->lzs, memlimit, decoder_flags); + lzret = lzma_auto_decoder(&self->lzs, memlimit_, decoder_flags); if (catch_lzma_error(lzret)) break; return 0; case FORMAT_XZ: - lzret = lzma_stream_decoder(&self->lzs, memlimit, decoder_flags); + lzret = lzma_stream_decoder(&self->lzs, memlimit_, decoder_flags); if (catch_lzma_error(lzret)) break; return 0; case FORMAT_ALONE: self->check = LZMA_CHECK_NONE; - lzret = lzma_alone_decoder(&self->lzs, memlimit); + lzret = lzma_alone_decoder(&self->lzs, memlimit_); if (catch_lzma_error(lzret)) break; return 0; case FORMAT_RAW: self->check = LZMA_CHECK_NONE; - if (Decompressor_init_raw(&self->lzs, filterspecs) == -1) + if (Decompressor_init_raw(&self->lzs, filters) == -1) break; return 0; @@ -1034,8 +1123,7 @@ } static PyMethodDef Decompressor_methods[] = { - {"decompress", (PyCFunction)Decompressor_decompress, METH_VARARGS, - Decompressor_decompress_doc}, + _LZMA_LZMADECOMPRESSOR_DECOMPRESS_METHODDEF {"__getstate__", (PyCFunction)Decompressor_getstate, METH_NOARGS}, {NULL} }; @@ -1059,27 +1147,6 @@ {NULL} }; -PyDoc_STRVAR(Decompressor_doc, -"LZMADecompressor(format=FORMAT_AUTO, memlimit=None, filters=None)\n" -"\n" -"Create a decompressor object for decompressing data incrementally.\n" -"\n" -"format specifies the container format of the input stream. If this is\n" -"FORMAT_AUTO (the default), the decompressor will automatically detect\n" -"whether the input is FORMAT_XZ or FORMAT_ALONE. Streams created with\n" -"FORMAT_RAW cannot be autodetected.\n" -"\n" -"memlimit can be specified to limit the amount of memory used by the\n" -"decompressor. This will cause decompression to fail if the input\n" -"cannot be decompressed within the given limit.\n" -"\n" -"filters specifies a custom filter chain. This argument is required for\n" -"FORMAT_RAW, and not accepted with any other format. When provided,\n" -"this should be a sequence of dicts, each indicating the ID and options\n" -"for a single filter.\n" -"\n" -"For one-shot decompression, use the decompress() function instead.\n"); - static PyTypeObject Decompressor_type = { PyVarObject_HEAD_INIT(NULL, 0) "_lzma.LZMADecompressor", /* tp_name */ @@ -1101,7 +1168,7 @@ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ - Decompressor_doc, /* tp_doc */ + _lzma_LZMADecompressor___init____doc__, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ @@ -1116,7 +1183,7 @@ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - (initproc)Decompressor_init, /* tp_init */ + _lzma_LZMADecompressor___init__, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ }; @@ -1124,48 +1191,42 @@ /* Module-level functions. */ -PyDoc_STRVAR(is_check_supported_doc, -"is_check_supported(check_id) -> bool\n" -"\n" -"Test whether the given integrity check is supported.\n" -"\n" -"Always returns True for CHECK_NONE and CHECK_CRC32.\n"); +/*[clinic input] +_lzma.is_check_supported + check_id: int + / + +Test whether the given integrity check is supported. + +Always returns True for CHECK_NONE and CHECK_CRC32. +[clinic start generated code]*/ static PyObject * -is_check_supported(PyObject *self, PyObject *args) +_lzma_is_check_supported_impl(PyModuleDef *module, int check_id) +/*[clinic end generated code: checksum=bb828e90e00ad96ed61f66719c2fca7fde637418]*/ { - int check_id; - - if (!PyArg_ParseTuple(args, "i:is_check_supported", &check_id)) - return NULL; - return PyBool_FromLong(lzma_check_is_supported(check_id)); } -PyDoc_STRVAR(_encode_filter_properties_doc, -"_encode_filter_properties(filter) -> bytes\n" -"\n" -"Return a bytes object encoding the options (properties) of the filter\n" -"specified by *filter* (a dict).\n" -"\n" -"The result does not include the filter ID itself, only the options.\n"); +/*[clinic input] +_lzma._encode_filter_properties + filter: lzma_filter(c_default="{LZMA_VLI_UNKNOWN, NULL}") + / + +Return a bytes object encoding the options (properties) of the filter specified by *filter* (a dict). + +The result does not include the filter ID itself, only the options. +[clinic start generated code]*/ static PyObject * -_encode_filter_properties(PyObject *self, PyObject *args) +_lzma__encode_filter_properties_impl(PyModuleDef *module, lzma_filter filter) +/*[clinic end generated code: checksum=b5fe690acd6b61d1abfc32f522ada5bdcf9b13da]*/ { - PyObject *filterspec; - lzma_filter filter; lzma_ret lzret; uint32_t encoded_size; PyObject *result = NULL; - if (!PyArg_ParseTuple(args, "O:_encode_filter_properties", &filterspec)) - return NULL; - - if (parse_filter_spec(&filter, filterspec) == NULL) - return NULL; - lzret = lzma_properties_size(&encoded_size, &filter); if (catch_lzma_error(lzret)) goto error; @@ -1179,37 +1240,36 @@ if (catch_lzma_error(lzret)) goto error; - PyMem_Free(filter.options); return result; error: Py_XDECREF(result); - PyMem_Free(filter.options); return NULL; } -PyDoc_STRVAR(_decode_filter_properties_doc, -"_decode_filter_properties(filter_id, encoded_props) -> dict\n" -"\n" -"Return a dict describing a filter with ID *filter_id*, and options\n" -"(properties) decoded from the bytes object *encoded_props*.\n"); +/*[clinic input] +_lzma._decode_filter_properties + filter_id: lzma_vli + encoded_props: Py_buffer + / + +Return a bytes object encoding the options (properties) of the filter specified by *filter* (a dict). + +The result does not include the filter ID itself, only the options. +[clinic start generated code]*/ static PyObject * -_decode_filter_properties(PyObject *self, PyObject *args) +_lzma__decode_filter_properties_impl(PyModuleDef *module, lzma_vli filter_id, Py_buffer *encoded_props) +/*[clinic end generated code: checksum=235f7f5345d48744dcd21f781dafbbf05a717538]*/ { - Py_buffer encoded_props; lzma_filter filter; lzma_ret lzret; PyObject *result = NULL; - - if (!PyArg_ParseTuple(args, "O&y*:_decode_filter_properties", - lzma_vli_converter, &filter.id, &encoded_props)) - return NULL; + filter.id = filter_id; lzret = lzma_properties_decode( - &filter, NULL, encoded_props.buf, encoded_props.len); - PyBuffer_Release(&encoded_props); + &filter, NULL, encoded_props->buf, encoded_props->len); if (catch_lzma_error(lzret)) return NULL; @@ -1225,12 +1285,9 @@ /* Module initialization. */ static PyMethodDef module_methods[] = { - {"is_check_supported", (PyCFunction)is_check_supported, - METH_VARARGS, is_check_supported_doc}, - {"_encode_filter_properties", (PyCFunction)_encode_filter_properties, - METH_VARARGS, _encode_filter_properties_doc}, - {"_decode_filter_properties", (PyCFunction)_decode_filter_properties, - METH_VARARGS, _decode_filter_properties_doc}, + _LZMA_IS_CHECK_SUPPORTED_METHODDEF + _LZMA__ENCODE_FILTER_PROPERTIES_METHODDEF + _LZMA__DECODE_FILTER_PROPERTIES_METHODDEF {NULL} }; diff --git a/Modules/_lzmamodule.clinic.c b/Modules/_lzmamodule.clinic.c new file mode 100644 --- /dev/null +++ b/Modules/_lzmamodule.clinic.c @@ -0,0 +1,231 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(_lzma_LZMACompressor_compress__doc__, +"compress(self, data)\n" +"Provide data to the compressor object.\n" +"\n" +"Returns a chunk of compressed data if possible, or b\'\' otherwise.\n" +"\n" +"When you have finished providing data to the compressor, call the\n" +"flush() method to finish the compression process."); + +#define _LZMA_LZMACOMPRESSOR_COMPRESS_METHODDEF \ + {"compress", (PyCFunction)_lzma_LZMACompressor_compress, METH_VARARGS, _lzma_LZMACompressor_compress__doc__}, + +static PyObject * +_lzma_LZMACompressor_compress_impl(Compressor *self, Py_buffer *data); + +static PyObject * +_lzma_LZMACompressor_compress(Compressor *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + + if (!PyArg_ParseTuple(args, + "y*:compress", + &data)) + goto exit; + return_value = _lzma_LZMACompressor_compress_impl(self, &data); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(_lzma_LZMACompressor_flush__doc__, +"flush(self)\n" +"Finish the compression process.\n" +"\n" +"Returns the compressed data left in internal buffers.\n" +"\n" +"The compressor object may not be used after this method is called."); + +#define _LZMA_LZMACOMPRESSOR_FLUSH_METHODDEF \ + {"flush", (PyCFunction)_lzma_LZMACompressor_flush, METH_NOARGS, _lzma_LZMACompressor_flush__doc__}, + +static PyObject * +_lzma_LZMACompressor_flush_impl(Compressor *self); + +static PyObject * +_lzma_LZMACompressor_flush(Compressor *self, PyObject *Py_UNUSED(ignored)) +{ + return _lzma_LZMACompressor_flush_impl(self); +} + +PyDoc_STRVAR(_lzma_LZMADecompressor_decompress__doc__, +"decompress(self, data)\n" +"Provide data to the decompressor object.\n" +"\n" +"Returns a chunk of decompressed data if possible, or b\'\' otherwise.\n" +"\n" +"Attempting to decompress data after the end of stream is reached\n" +"raises an EOFError. Any data found after the end of the stream\n" +"is ignored and saved in the unused_data attribute."); + +#define _LZMA_LZMADECOMPRESSOR_DECOMPRESS_METHODDEF \ + {"decompress", (PyCFunction)_lzma_LZMADecompressor_decompress, METH_VARARGS, _lzma_LZMADecompressor_decompress__doc__}, + +static PyObject * +_lzma_LZMADecompressor_decompress_impl(Decompressor *self, Py_buffer *data); + +static PyObject * +_lzma_LZMADecompressor_decompress(Decompressor *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + + if (!PyArg_ParseTuple(args, + "y*:decompress", + &data)) + goto exit; + return_value = _lzma_LZMADecompressor_decompress_impl(self, &data); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(_lzma_LZMADecompressor___init____doc__, +"LZMADecompressor(format=FORMAT_AUTO, memlimit=None, filters=None)\n" +"Create a decompressor object for decompressing data incrementally.\n" +"\n" +" format\n" +" Specifies the container format of the input stream. If this is\n" +" FORMAT_AUTO (the default), the decompressor will automatically detect\n" +" whether the input is FORMAT_XZ or FORMAT_ALONE. Streams created with\n" +" FORMAT_RAW cannot be autodetected.\n" +" memlimit\n" +" Limit the amount of memory used by the decompressor. This will cause\n" +" decompression to fail if the input cannot be decompressed within the\n" +" given limit.\n" +" filters\n" +" A custom filter chain. This argument is required for FORMAT_RAW, and\n" +" not accepted with any other format. When provided, this should be a\n" +" sequence of dicts, each indicating the ID and options for a single\n" +" filter.\n" +"\n" +"For one-shot decompression, use the decompress() function instead."); + +static int +_lzma_LZMADecompressor___init___impl(Decompressor *self, int format, PyObject *memlimit, PyObject *filters); + +static int +_lzma_LZMADecompressor___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + static char *_keywords[] = {"format", "memlimit", "filters", NULL}; + int format = FORMAT_AUTO; + PyObject *memlimit = Py_None; + PyObject *filters = Py_None; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "|iOO:LZMADecompressor", _keywords, + &format, &memlimit, &filters)) + goto exit; + return_value = _lzma_LZMADecompressor___init___impl((Decompressor *)self, format, memlimit, filters); + +exit: + return return_value; +} + +PyDoc_STRVAR(_lzma_is_check_supported__doc__, +"is_check_supported(module, check_id)\n" +"Test whether the given integrity check is supported.\n" +"\n" +"Always returns True for CHECK_NONE and CHECK_CRC32."); + +#define _LZMA_IS_CHECK_SUPPORTED_METHODDEF \ + {"is_check_supported", (PyCFunction)_lzma_is_check_supported, METH_VARARGS, _lzma_is_check_supported__doc__}, + +static PyObject * +_lzma_is_check_supported_impl(PyModuleDef *module, int check_id); + +static PyObject * +_lzma_is_check_supported(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + int check_id; + + if (!PyArg_ParseTuple(args, + "i:is_check_supported", + &check_id)) + goto exit; + return_value = _lzma_is_check_supported_impl(module, check_id); + +exit: + return return_value; +} + +PyDoc_STRVAR(_lzma__encode_filter_properties__doc__, +"_encode_filter_properties(module, filter)\n" +"Return a bytes object encoding the options (properties) of the filter specified by *filter* (a dict).\n" +"\n" +"The result does not include the filter ID itself, only the options."); + +#define _LZMA__ENCODE_FILTER_PROPERTIES_METHODDEF \ + {"_encode_filter_properties", (PyCFunction)_lzma__encode_filter_properties, METH_VARARGS, _lzma__encode_filter_properties__doc__}, + +static PyObject * +_lzma__encode_filter_properties_impl(PyModuleDef *module, lzma_filter filter); + +static PyObject * +_lzma__encode_filter_properties(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + lzma_filter filter = {LZMA_VLI_UNKNOWN, NULL}; + + if (!PyArg_ParseTuple(args, + "O&:_encode_filter_properties", + lzma_filter_converter, &filter)) + goto exit; + return_value = _lzma__encode_filter_properties_impl(module, filter); + +exit: + /* Cleanup for filter */ + if (filter.id != LZMA_VLI_UNKNOWN) + PyMem_Free(filter.options); + + return return_value; +} + +PyDoc_STRVAR(_lzma__decode_filter_properties__doc__, +"_decode_filter_properties(module, filter_id, encoded_props)\n" +"Return a bytes object encoding the options (properties) of the filter specified by *filter* (a dict).\n" +"\n" +"The result does not include the filter ID itself, only the options."); + +#define _LZMA__DECODE_FILTER_PROPERTIES_METHODDEF \ + {"_decode_filter_properties", (PyCFunction)_lzma__decode_filter_properties, METH_VARARGS, _lzma__decode_filter_properties__doc__}, + +static PyObject * +_lzma__decode_filter_properties_impl(PyModuleDef *module, lzma_vli filter_id, Py_buffer *encoded_props); + +static PyObject * +_lzma__decode_filter_properties(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + lzma_vli filter_id; + Py_buffer encoded_props = {NULL, NULL}; + + if (!PyArg_ParseTuple(args, + "O&y*:_decode_filter_properties", + lzma_vli_converter, &filter_id, &encoded_props)) + goto exit; + return_value = _lzma__decode_filter_properties_impl(module, filter_id, &encoded_props); + +exit: + /* Cleanup for encoded_props */ + if (encoded_props.obj) + PyBuffer_Release(&encoded_props); + + return return_value; +} +/*[clinic end generated code: checksum=b4b90dcbd0c9c349c3a94e26a7eecf71aab179a0]*/ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 14:40:46 2014 From: python-checkins at python.org (victor.stinner) Date: Sat, 25 Jan 2014 14:40:46 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMzEx?= =?utf-8?q?=3A_Revert_033137c12d88=2C_select=2Eepoll=2Epoll=28=29_rounds_a?= =?utf-8?q?gain_the_timeout?= Message-ID: <3fBJJZ2QXQz7LjS@mail.python.org> http://hg.python.org/cpython/rev/900a1ff323bb changeset: 88692:900a1ff323bb branch: 3.3 parent: 88689:a516eec7117e user: Victor Stinner date: Sat Jan 25 14:37:50 2014 +0100 summary: Issue #20311: Revert 033137c12d88, select.epoll.poll() rounds again the timeout towards zero files: Lib/test/test_epoll.py | 11 ----------- Misc/NEWS | 6 +----- Modules/selectmodule.c | 4 +--- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/Lib/test/test_epoll.py b/Lib/test/test_epoll.py --- a/Lib/test/test_epoll.py +++ b/Lib/test/test_epoll.py @@ -217,17 +217,6 @@ server.close() ep.unregister(fd) - def test_timeout_rounding(self): - # epoll_wait() has a resolution of 1 millisecond, check if the timeout - # is correctly rounded to the upper bound - epoll = select.epoll() - self.addCleanup(epoll.close) - for timeout in (1e-2, 1e-3, 1e-4): - t0 = time.monotonic() - epoll.poll(timeout) - dt = time.monotonic() - t0 - self.assertGreaterEqual(dt, timeout) - def test_main(): support.run_unittest(TestEPoll) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -58,10 +58,6 @@ - Issue #20374: Fix build with GNU readline >= 6.3. -- Issue #20311: select.epoll.poll() now rounds the timeout away from zero, - instead of rounding towards zero. For example, a timeout of one microsecond - is now rounded to one millisecond, instead of being rounded to zero. - - Issue #20262: Warnings are raised now when duplicate names are added in the ZIP file or too long ZIP file comment is truncated. @@ -278,7 +274,7 @@ --Issue #17390: Add Python version to Idle editor window title bar. Original patches by Edmond Burnett and Kent Johnson. - + - Issue #18960: IDLE now ignores the source encoding declaration on the second line if the first line contains anything except a comment. diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -1379,9 +1379,7 @@ return NULL; } else { - /* epoll_wait() has a resolution of 1 millisecond, round away from zero - to wait *at least* dtimeout seconds. */ - timeout = (int)ceil(dtimeout * 1000.0); + timeout = (int)(dtimeout * 1000.0); } if (maxevents == -1) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 14:40:47 2014 From: python-checkins at python.org (victor.stinner) Date: Sat, 25 Jan 2014 14:40:47 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_=28Merge_3=2E3=29_Issue_=2320311=3A_Revert_033137c12d88_?= =?utf-8?b?KDAyZjlkYjNlNjg0ZSks?= Message-ID: <3fBJJb40S7z7LlK@mail.python.org> http://hg.python.org/cpython/rev/caab3e191485 changeset: 88693:caab3e191485 parent: 88691:7ba9642fc800 parent: 88692:900a1ff323bb user: Victor Stinner date: Sat Jan 25 14:40:04 2014 +0100 summary: (Merge 3.3) Issue #20311: Revert 033137c12d88 (02f9db3e684e), select.epoll.poll() rounds again the timeout towards zero files: Lib/test/test_epoll.py | 11 ----------- Misc/NEWS | 4 ---- Modules/selectmodule.c | 4 +--- 3 files changed, 1 insertions(+), 18 deletions(-) diff --git a/Lib/test/test_epoll.py b/Lib/test/test_epoll.py --- a/Lib/test/test_epoll.py +++ b/Lib/test/test_epoll.py @@ -254,17 +254,6 @@ self.addCleanup(epoll.close) self.assertEqual(os.get_inheritable(epoll.fileno()), False) - def test_timeout_rounding(self): - # epoll_wait() has a resolution of 1 millisecond, check if the timeout - # is correctly rounded to the upper bound - epoll = select.epoll() - self.addCleanup(epoll.close) - for timeout in (1e-2, 1e-3, 1e-4): - t0 = time.monotonic() - epoll.poll(timeout) - dt = time.monotonic() - t0 - self.assertGreaterEqual(dt, timeout) - def test_main(): support.run_unittest(TestEPoll) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -53,10 +53,6 @@ - Issue #20374: Fix build with GNU readline >= 6.3. -- Issue #20311: select.epoll.poll() now rounds the timeout away from zero, - instead of rounding towards zero. For example, a timeout of one microsecond - is now rounded to one millisecond, instead of being rounded to zero. - - Issue #20262: Warnings are raised now when duplicate names are added in the ZIP file or too long ZIP file comment is truncated. diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -1458,9 +1458,7 @@ return NULL; } else { - /* epoll_wait() has a resolution of 1 millisecond, round away from zero - to wait *at least* dtimeout seconds. */ - timeout = (int)ceil(dtimeout * 1000.0); + timeout = (int)(dtimeout * 1000.0); } if (maxevents == -1) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 14:44:31 2014 From: python-checkins at python.org (victor.stinner) Date: Sat, 25 Jan 2014 14:44:31 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320311=3A_Revert_e?= =?utf-8?q?042ea77a152_and_7ce7295393c2=2C_PollSelector=2Eselect=28=29_and?= Message-ID: <3fBJNv60Hfz7LmG@mail.python.org> http://hg.python.org/cpython/rev/90354a4c9dde changeset: 88694:90354a4c9dde user: Victor Stinner date: Sat Jan 25 14:43:45 2014 +0100 summary: Issue #20311: Revert e042ea77a152 and 7ce7295393c2, PollSelector.select() and EpollSelector.select() round again the timeout towards zero files: Lib/selectors.py | 10 ++-------- Lib/test/test_selectors.py | 19 ------------------- Misc/NEWS | 5 ----- 3 files changed, 2 insertions(+), 32 deletions(-) diff --git a/Lib/selectors.py b/Lib/selectors.py --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -8,7 +8,6 @@ from abc import ABCMeta, abstractmethod from collections import namedtuple, Mapping import functools -import math import select import sys @@ -357,9 +356,8 @@ elif timeout <= 0: timeout = 0 else: - # poll() has a resolution of 1 millisecond, round away from - # zero to wait *at least* timeout seconds. - timeout = int(math.ceil(timeout * 1e3)) + # Round towards zero + timeout = int(timeout * 1000) ready = [] try: fd_event_list = self._poll.poll(timeout) @@ -415,10 +413,6 @@ timeout = -1 elif timeout <= 0: timeout = 0 - else: - # epoll_wait() has a resolution of 1 millisecond, round away - # from zero to wait *at least* timeout seconds. - timeout = math.ceil(timeout * 1e3) * 1e-3 max_ev = len(self._fd_to_key) ready = [] try: 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 @@ -363,25 +363,6 @@ self.assertFalse(s.select(2)) self.assertLess(time() - t, 2.5) - def test_timeout_rounding(self): - # Issue #20311: Timeout must be rounded away from zero to wait *at - # least* timeout seconds. For example, epoll_wait() has a resolution of - # 1 ms (10^-3), epoll.select(0.0001) must wait 1 ms, not 0 ms. - s = self.SELECTOR() - self.addCleanup(s.close) - - rd, wr = self.make_socketpair() - s.register(rd, selectors.EVENT_READ) - - for timeout in (1e-2, 1e-3, 1e-4): - t0 = perf_counter() - s.select(timeout) - dt = perf_counter() - t0 - clock = get_clock_info('perf_counter') - self.assertGreaterEqual(dt, timeout, - "%.30f < %.30f ; clock=%s" - % (dt, timeout, clock)) - class ScalableSelectorMixIn: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -40,11 +40,6 @@ which it could get an inspect.Signature is a callable written in Python. Fix courtesy of Michael Foord. -- Issue #20311: selector.PollSelector.select() now rounds the timeout away from - zero, instead of rounding towards zero. For example, a timeout of one - microsecond is now rounded to one millisecond, instead of being rounded to - zero. - - Issue #20317: ExitStack.__exit__ could create a self-referential loop if an exception raised by a cleanup operation already had its context set correctly (for example, by the @contextmanager decorator). The infinite -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 15:02:54 2014 From: python-checkins at python.org (victor.stinner) Date: Sat, 25 Jan 2014 15:02:54 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320311=3A_selector?= =?utf-8?q?s=3A_Add_a_resolution_attribute_to_BaseSelector=2E?= Message-ID: <3fBJp66bKdz7LjP@mail.python.org> http://hg.python.org/cpython/rev/3b8a2281d323 changeset: 88695:3b8a2281d323 user: Victor Stinner date: Sat Jan 25 14:56:48 2014 +0100 summary: Issue #20311: selectors: Add a resolution attribute to BaseSelector. files: Doc/library/selectors.rst | 4 ++++ Lib/selectors.py | 23 ++++++++++++++++++++++- Lib/test/test_selectors.py | 5 +++++ Misc/NEWS | 2 ++ 4 files changed, 33 insertions(+), 1 deletions(-) diff --git a/Doc/library/selectors.rst b/Doc/library/selectors.rst --- a/Doc/library/selectors.rst +++ b/Doc/library/selectors.rst @@ -98,6 +98,10 @@ :class:`BaseSelector` and its concrete implementations support the :term:`context manager` protocol. + .. attribute:: resolution + + Resolution of the selector in seconds. + .. method:: register(fileobj, events, data=None) Register a file object for selection, monitoring it for I/O events. diff --git a/Lib/selectors.py b/Lib/selectors.py --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -5,7 +5,7 @@ """ -from abc import ABCMeta, abstractmethod +from abc import ABCMeta, abstractmethod, abstractproperty from collections import namedtuple, Mapping import functools import select @@ -82,6 +82,11 @@ performant implementation on the current platform. """ + @abstractproperty + def resolution(self): + """Resolution of the selector in seconds""" + return None + @abstractmethod def register(self, fileobj, events, data=None): """Register a file object. @@ -283,6 +288,10 @@ self._readers = set() self._writers = set() + @property + def resolution(self): + return 1e-6 + def register(self, fileobj, events, data=None): key = super().register(fileobj, events, data) if events & EVENT_READ: @@ -335,6 +344,10 @@ super().__init__() self._poll = select.poll() + @property + def resolution(self): + return 1e-3 + def register(self, fileobj, events, data=None): key = super().register(fileobj, events, data) poll_events = 0 @@ -385,6 +398,10 @@ super().__init__() self._epoll = select.epoll() + @property + def resolution(self): + return 1e-3 + def fileno(self): return self._epoll.fileno() @@ -445,6 +462,10 @@ super().__init__() self._kqueue = select.kqueue() + @property + def resolution(self): + return 1e-9 + def fileno(self): return self._kqueue.fileno() 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 @@ -363,6 +363,11 @@ self.assertFalse(s.select(2)) self.assertLess(time() - t, 2.5) + def test_resolution(self): + s = self.SELECTOR() + self.assertIsInstance(s.resolution, (int, float)) + self.assertGreater(s.resolution, 0.0) + class ScalableSelectorMixIn: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,8 @@ Library ------- +- Issue #20311: selectors: Add a resolution attribute to BaseSelector. + - Issue #20189: unittest.mock now no longer assumes that any object for which it could get an inspect.Signature is a callable written in Python. Fix courtesy of Michael Foord. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 15:02:56 2014 From: python-checkins at python.org (victor.stinner) Date: Sat, 25 Jan 2014 15:02:56 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320311=3A_asyncio?= =?utf-8?q?=3A_Add_a_granularity_attribute_to_BaseEventLoop=3A_maximum?= Message-ID: <3fBJp820h8z7LlL@mail.python.org> http://hg.python.org/cpython/rev/4bc550c66228 changeset: 88696:4bc550c66228 user: Victor Stinner date: Sat Jan 25 15:01:33 2014 +0100 summary: Issue #20311: asyncio: Add a granularity attribute to BaseEventLoop: maximum between the resolution of the BaseEventLoop.time() method and the resolution of the selector. The granuarility is used in the scheduler to round time and deadline. files: Doc/library/asyncio-eventloop.rst | 6 ++ Lib/asyncio/base_events.py | 6 ++ Lib/asyncio/selector_events.py | 1 + Lib/test/test_asyncio/test_events.py | 23 ++++++++++ Lib/test/test_asyncio/test_selector_events.py | 4 +- Misc/NEWS | 5 ++ 6 files changed, 44 insertions(+), 1 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 @@ -144,6 +144,12 @@ Return the current time, as a :class:`float` value, according to the event loop's internal clock. +.. attribute:: BaseEventLoop.granularity + + Granularity of the time: maximum between the resolution of the + :meth:`BaseEventLoop.time` method and the resolution of the selector (see + :attr:`selectors.BaseSelector.resolution`). + .. seealso:: The :func:`asyncio.sleep` function. 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 @@ -18,6 +18,7 @@ import concurrent.futures import heapq import logging +import math import socket import subprocess import time @@ -96,6 +97,7 @@ self._default_executor = None self._internal_fds = 0 self._running = False + self.granularity = time.get_clock_info('monotonic').resolution def _make_socket_transport(self, sock, protocol, waiter=None, *, extra=None, server=None): @@ -603,6 +605,8 @@ elif self._scheduled: # Compute the desired timeout. when = self._scheduled[0]._when + # round deadline aways from zero + when = math.ceil(when / self.granularity) * self.granularity deadline = max(0, when - self.time()) if timeout is None: timeout = deadline @@ -629,6 +633,8 @@ # Handle 'later' callbacks that are ready. now = self.time() + # round current time aways from zero + now = math.ceil(now / self.granularity) * self.granularity while self._scheduled: handle = self._scheduled[0] if handle._when > now: 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 @@ -34,6 +34,7 @@ selector = selectors.DefaultSelector() logger.debug('Using selector: %s', selector.__class__.__name__) self._selector = selector + self.granularity = max(selector.resolution, self.granularity) self._make_self_pipe() def _make_socket_transport(self, sock, protocol, waiter=None, *, 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 @@ -1116,6 +1116,29 @@ r.close() w.close() + def test_timeout_rounding(self): + def _run_once(): + self.loop._run_once_counter += 1 + orig_run_once() + + orig_run_once = self.loop._run_once + self.loop._run_once_counter = 0 + self.loop._run_once = _run_once + calls = [] + + @tasks.coroutine + def wait(): + loop = self.loop + calls.append(loop._run_once_counter) + yield from tasks.sleep(loop.granularity * 10, loop=loop) + calls.append(loop._run_once_counter) + yield from tasks.sleep(loop.granularity / 10, loop=loop) + calls.append(loop._run_once_counter) + + self.loop.run_until_complete(wait()) + calls.append(self.loop._run_once_counter) + self.assertEqual(calls, [1, 3, 5, 6]) + class SubprocessTestsMixin: 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 @@ -39,7 +39,9 @@ class BaseSelectorEventLoopTests(unittest.TestCase): def setUp(self): - self.loop = TestBaseSelectorEventLoop(unittest.mock.Mock()) + selector = unittest.mock.Mock() + selector.resolution = 1e-3 + self.loop = TestBaseSelectorEventLoop(selector) def test_make_socket_transport(self): m = unittest.mock.Mock() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,11 @@ Library ------- +- Issue #20311: asyncio: Add a granularity attribute to BaseEventLoop: maximum + between the resolution of the BaseEventLoop.time() method and the resolution + of the selector. The granuarility is used in the scheduler to round time and + deadline. + - Issue #20311: selectors: Add a resolution attribute to BaseSelector. - Issue #20189: unittest.mock now no longer assumes that any object for -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 15:04:53 2014 From: python-checkins at python.org (victor.stinner) Date: Sat, 25 Jan 2014 15:04:53 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_test=5Fselectors=3A_remove?= =?utf-8?q?_unused_imports?= Message-ID: <3fBJrP0yHkz7LjP@mail.python.org> http://hg.python.org/cpython/rev/80e37be4efb2 changeset: 88697:80e37be4efb2 user: Victor Stinner date: Sat Jan 25 15:04:22 2014 +0100 summary: test_selectors: remove unused imports files: Lib/test/test_selectors.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) 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,7 +5,7 @@ import signal import socket from test import support -from time import sleep, perf_counter, get_clock_info +from time import sleep import unittest import unittest.mock try: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 15:36:40 2014 From: python-checkins at python.org (victor.stinner) Date: Sat, 25 Jan 2014 15:36:40 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_asyncio_tests=3A_defin?= =?utf-8?q?e_resolution?= Message-ID: <3fBKY4226Xz7Llv@mail.python.org> http://hg.python.org/cpython/rev/5d009141512a changeset: 88698:5d009141512a user: Victor Stinner date: Sat Jan 25 15:31:06 2014 +0100 summary: Fix asyncio tests: define resolution files: Lib/asyncio/test_utils.py | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) 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 @@ -144,6 +144,10 @@ def __init__(self): self.keys = {} + @property + def resolution(self): + return 1e-3 + def register(self, fileobj, events, data=None): key = selectors.SelectorKey(fileobj, 0, events, data) self.keys[fileobj] = key -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 15:36:42 2014 From: python-checkins at python.org (victor.stinner) Date: Sat, 25 Jan 2014 15:36:42 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Update_asyncio_from_the_Tu?= =?utf-8?q?lip_project?= Message-ID: <3fBKY63dTjz7Ll8@mail.python.org> http://hg.python.org/cpython/rev/905d141e84da changeset: 88699:905d141e84da user: Victor Stinner date: Sat Jan 25 15:32:06 2014 +0100 summary: Update asyncio from the Tulip project Major changes: - StreamReader.readexactly() now raises an IncompleteReadError if the end of stream is reached before we received enough bytes, instead of returning less bytes than requested. - Unit tests use the main asyncio module instead of submodules like events - _UnixWritePipeTransport now also supports character devices, as _UnixReadPipeTransport. Patch written by Jonathan Slenders. - Export more symbols: BaseEventLoop, BaseProactorEventLoop, BaseSelectorEventLoop, Queue and Queue sublasses, Empty, Full files: Lib/asyncio/__init__.py | 18 +- Lib/asyncio/proactor_events.py | 2 + Lib/asyncio/selector_events.py | 2 + Lib/asyncio/streams.py | 22 +- Lib/asyncio/unix_events.py | 8 +- Lib/test/test_asyncio/test_base_events.py | 98 +- Lib/test/test_asyncio/test_events.py | 269 ++- Lib/test/test_asyncio/test_futures.py | 99 +- Lib/test/test_asyncio/test_locks.py | 243 ++-- Lib/test/test_asyncio/test_proactor_events.py | 11 +- Lib/test/test_asyncio/test_queues.py | 166 +- Lib/test/test_asyncio/test_selector_events.py | 76 +- Lib/test/test_asyncio/test_streams.py | 118 +- Lib/test/test_asyncio/test_tasks.py | 596 ++++----- Lib/test/test_asyncio/test_transports.py | 14 +- Lib/test/test_asyncio/test_unix_events.py | 51 +- Lib/test/test_asyncio/test_windows_events.py | 25 +- 17 files changed, 931 insertions(+), 887 deletions(-) diff --git a/Lib/asyncio/__init__.py b/Lib/asyncio/__init__.py --- a/Lib/asyncio/__init__.py +++ b/Lib/asyncio/__init__.py @@ -18,13 +18,17 @@ import _overlapped # Will also be exported. # This relies on each of the submodules having an __all__ variable. +from .base_events import * +from .events import * from .futures import * -from .events import * from .locks import * -from .transports import * +from .proactor_events import * from .protocols import * +from .queues import * +from .selector_events import * from .streams import * from .tasks import * +from .transports import * if sys.platform == 'win32': # pragma: no cover from .windows_events import * @@ -32,10 +36,14 @@ from .unix_events import * # pragma: no cover -__all__ = (futures.__all__ + +__all__ = (base_events.__all__ + events.__all__ + + futures.__all__ + locks.__all__ + - transports.__all__ + + proactor_events.__all__ + protocols.__all__ + + queues.__all__ + + selector_events.__all__ + streams.__all__ + - tasks.__all__) + tasks.__all__ + + transports.__all__) diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -4,6 +4,8 @@ proactor is only implemented on Windows with IOCP. """ +__all__ = ['BaseProactorEventLoop'] + import socket from . import base_events 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 @@ -4,6 +4,8 @@ also includes support for signal handling, see the unix_events sub-module. """ +__all__ = ['BaseSelectorEventLoop'] + import collections import errno import socket diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -1,7 +1,7 @@ """Stream-related things.""" __all__ = ['StreamReader', 'StreamWriter', 'StreamReaderProtocol', - 'open_connection', 'start_server', + 'open_connection', 'start_server', 'IncompleteReadError', ] import collections @@ -14,6 +14,19 @@ _DEFAULT_LIMIT = 2**16 +class IncompleteReadError(EOFError): + """ + Incomplete read error. Attributes: + + - partial: read bytes string before the end of stream was reached + - expected: total number of expected bytes + """ + def __init__(self, partial, expected): + EOFError.__init__(self, "%s bytes read on a total of %s expected bytes" + % (len(partial), expected)) + self.partial = partial + self.expected = expected + @tasks.coroutine def open_connection(host=None, port=None, *, @@ -403,12 +416,9 @@ while n > 0: block = yield from self.read(n) if not block: - break + partial = b''.join(blocks) + raise IncompleteReadError(partial, len(partial) + n) blocks.append(block) n -= len(block) - # TODO: Raise EOFError if we break before n == 0? (That would - # be a change in specification, but I've always had to add an - # explicit size check to the caller.) - return b''.join(blocks) 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 @@ -259,9 +259,11 @@ self._fileno = pipe.fileno() mode = os.fstat(self._fileno).st_mode is_socket = stat.S_ISSOCK(mode) - is_pipe = stat.S_ISFIFO(mode) - if not (is_socket or is_pipe): - raise ValueError("Pipe transport is for pipes/sockets only.") + if not (is_socket or + stat.S_ISFIFO(mode) or + stat.S_ISCHR(mode)): + raise ValueError("Pipe transport is only for " + "pipes, sockets and character devices") _set_nonblocking(self._fileno) self._protocol = protocol self._buffer = [] 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 @@ -8,21 +8,17 @@ import unittest.mock from test.support import find_unused_port, IPV6_ENABLED -from asyncio import base_events +import asyncio from asyncio import constants -from asyncio import events -from asyncio import futures -from asyncio import protocols -from asyncio import tasks from asyncio import test_utils class BaseEventLoopTests(unittest.TestCase): def setUp(self): - self.loop = base_events.BaseEventLoop() + self.loop = asyncio.BaseEventLoop() self.loop._selector = unittest.mock.Mock() - events.set_event_loop(None) + asyncio.set_event_loop(None) def test_not_implemented(self): m = unittest.mock.Mock() @@ -51,20 +47,20 @@ self.assertRaises(NotImplementedError, next, iter(gen)) def test__add_callback_handle(self): - h = events.Handle(lambda: False, ()) + h = asyncio.Handle(lambda: False, ()) self.loop._add_callback(h) self.assertFalse(self.loop._scheduled) self.assertIn(h, self.loop._ready) def test__add_callback_timer(self): - h = events.TimerHandle(time.monotonic()+10, lambda: False, ()) + h = asyncio.TimerHandle(time.monotonic()+10, lambda: False, ()) self.loop._add_callback(h) self.assertIn(h, self.loop._scheduled) def test__add_callback_cancelled_handle(self): - h = events.Handle(lambda: False, ()) + h = asyncio.Handle(lambda: False, ()) h.cancel() self.loop._add_callback(h) @@ -90,7 +86,7 @@ h = self.loop.call_soon(cb) self.assertEqual(h._callback, cb) - self.assertIsInstance(h, events.Handle) + self.assertIsInstance(h, asyncio.Handle) self.assertIn(h, self.loop._ready) def test_call_later(self): @@ -98,7 +94,7 @@ pass h = self.loop.call_later(10.0, cb) - self.assertIsInstance(h, events.TimerHandle) + self.assertIsInstance(h, asyncio.TimerHandle) self.assertIn(h, self.loop._scheduled) self.assertNotIn(h, self.loop._ready) @@ -132,27 +128,27 @@ self.assertRaises( AssertionError, self.loop.run_in_executor, - None, events.Handle(cb, ()), ('',)) + None, asyncio.Handle(cb, ()), ('',)) self.assertRaises( AssertionError, self.loop.run_in_executor, - None, events.TimerHandle(10, cb, ())) + None, asyncio.TimerHandle(10, cb, ())) def test_run_once_in_executor_cancelled(self): def cb(): pass - h = events.Handle(cb, ()) + h = asyncio.Handle(cb, ()) h.cancel() f = self.loop.run_in_executor(None, h) - self.assertIsInstance(f, futures.Future) + self.assertIsInstance(f, asyncio.Future) self.assertTrue(f.done()) self.assertIsNone(f.result()) def test_run_once_in_executor_plain(self): def cb(): pass - h = events.Handle(cb, ()) - f = futures.Future(loop=self.loop) + h = asyncio.Handle(cb, ()) + f = asyncio.Future(loop=self.loop) executor = unittest.mock.Mock() executor.submit.return_value = f @@ -170,8 +166,8 @@ f.cancel() # Don't complain about abandoned Future. def test__run_once(self): - h1 = events.TimerHandle(time.monotonic() + 5.0, lambda: True, ()) - h2 = events.TimerHandle(time.monotonic() + 10.0, lambda: True, ()) + h1 = asyncio.TimerHandle(time.monotonic() + 5.0, lambda: True, ()) + h2 = asyncio.TimerHandle(time.monotonic() + 10.0, lambda: True, ()) h1.cancel() @@ -202,14 +198,14 @@ m_logging.DEBUG = logging.DEBUG self.loop._scheduled.append( - events.TimerHandle(11.0, lambda: True, ())) + asyncio.TimerHandle(11.0, lambda: True, ())) self.loop._process_events = unittest.mock.Mock() self.loop._run_once() self.assertEqual(logging.INFO, m_logging.log.call_args[0][0]) idx = -1 data = [10.0, 10.0, 10.3, 13.0] - self.loop._scheduled = [events.TimerHandle(11.0, lambda:True, ())] + self.loop._scheduled = [asyncio.TimerHandle(11.0, lambda:True, ())] self.loop._run_once() self.assertEqual(logging.DEBUG, m_logging.log.call_args[0][0]) @@ -222,7 +218,7 @@ processed = True handle = loop.call_soon(lambda: True) - h = events.TimerHandle(time.monotonic() - 1, cb, (self.loop,)) + h = asyncio.TimerHandle(time.monotonic() - 1, cb, (self.loop,)) self.loop._process_events = unittest.mock.Mock() self.loop._scheduled.append(h) @@ -236,14 +232,14 @@ TypeError, self.loop.run_until_complete, 'blah') -class MyProto(protocols.Protocol): +class MyProto(asyncio.Protocol): done = None def __init__(self, create_future=False): self.state = 'INITIAL' self.nbytes = 0 if create_future: - self.done = futures.Future() + self.done = asyncio.Future() def connection_made(self, transport): self.transport = transport @@ -266,14 +262,14 @@ self.done.set_result(None) -class MyDatagramProto(protocols.DatagramProtocol): +class MyDatagramProto(asyncio.DatagramProtocol): done = None def __init__(self, create_future=False): self.state = 'INITIAL' self.nbytes = 0 if create_future: - self.done = futures.Future() + self.done = asyncio.Future() def connection_made(self, transport): self.transport = transport @@ -297,8 +293,8 @@ class BaseEventLoopWithSelectorTests(unittest.TestCase): def setUp(self): - self.loop = events.new_event_loop() - events.set_event_loop(None) + self.loop = asyncio.new_event_loop() + asyncio.set_event_loop(None) def tearDown(self): self.loop.close() @@ -306,17 +302,17 @@ @unittest.mock.patch('asyncio.base_events.socket') def test_create_connection_multiple_errors(self, m_socket): - class MyProto(protocols.Protocol): + class MyProto(asyncio.Protocol): pass - @tasks.coroutine + @asyncio.coroutine def getaddrinfo(*args, **kw): yield from [] return [(2, 1, 6, '', ('107.6.106.82', 80)), (2, 1, 6, '', ('107.6.106.82', 80))] def getaddrinfo_task(*args, **kwds): - return tasks.Task(getaddrinfo(*args, **kwds), loop=self.loop) + return asyncio.Task(getaddrinfo(*args, **kwds), loop=self.loop) idx = -1 errors = ['err1', 'err2'] @@ -346,12 +342,12 @@ self.assertRaises(ValueError, self.loop.run_until_complete, coro) def test_create_connection_no_getaddrinfo(self): - @tasks.coroutine + @asyncio.coroutine def getaddrinfo(*args, **kw): yield from [] def getaddrinfo_task(*args, **kwds): - return tasks.Task(getaddrinfo(*args, **kwds), loop=self.loop) + return asyncio.Task(getaddrinfo(*args, **kwds), loop=self.loop) self.loop.getaddrinfo = getaddrinfo_task coro = self.loop.create_connection(MyProto, 'example.com', 80) @@ -359,13 +355,13 @@ OSError, self.loop.run_until_complete, coro) def test_create_connection_connect_err(self): - @tasks.coroutine + @asyncio.coroutine def getaddrinfo(*args, **kw): yield from [] return [(2, 1, 6, '', ('107.6.106.82', 80))] def getaddrinfo_task(*args, **kwds): - return tasks.Task(getaddrinfo(*args, **kwds), loop=self.loop) + return asyncio.Task(getaddrinfo(*args, **kwds), loop=self.loop) self.loop.getaddrinfo = getaddrinfo_task self.loop.sock_connect = unittest.mock.Mock() @@ -376,13 +372,13 @@ OSError, self.loop.run_until_complete, coro) def test_create_connection_multiple(self): - @tasks.coroutine + @asyncio.coroutine def getaddrinfo(*args, **kw): return [(2, 1, 6, '', ('0.0.0.1', 80)), (2, 1, 6, '', ('0.0.0.2', 80))] def getaddrinfo_task(*args, **kwds): - return tasks.Task(getaddrinfo(*args, **kwds), loop=self.loop) + return asyncio.Task(getaddrinfo(*args, **kwds), loop=self.loop) self.loop.getaddrinfo = getaddrinfo_task self.loop.sock_connect = unittest.mock.Mock() @@ -404,13 +400,13 @@ m_socket.socket.return_value.bind = bind - @tasks.coroutine + @asyncio.coroutine def getaddrinfo(*args, **kw): return [(2, 1, 6, '', ('0.0.0.1', 80)), (2, 1, 6, '', ('0.0.0.2', 80))] def getaddrinfo_task(*args, **kwds): - return tasks.Task(getaddrinfo(*args, **kwds), loop=self.loop) + return asyncio.Task(getaddrinfo(*args, **kwds), loop=self.loop) self.loop.getaddrinfo = getaddrinfo_task self.loop.sock_connect = unittest.mock.Mock() @@ -426,7 +422,7 @@ self.assertTrue(m_socket.socket.return_value.close.called) def test_create_connection_no_local_addr(self): - @tasks.coroutine + @asyncio.coroutine def getaddrinfo(host, *args, **kw): if host == 'example.com': return [(2, 1, 6, '', ('107.6.106.82', 80)), @@ -435,7 +431,7 @@ return [] def getaddrinfo_task(*args, **kwds): - return tasks.Task(getaddrinfo(*args, **kwds), loop=self.loop) + return asyncio.Task(getaddrinfo(*args, **kwds), loop=self.loop) self.loop.getaddrinfo = getaddrinfo_task coro = self.loop.create_connection( @@ -448,7 +444,7 @@ self.loop.getaddrinfo = unittest.mock.Mock() def mock_getaddrinfo(*args, **kwds): - f = futures.Future(loop=self.loop) + f = asyncio.Future(loop=self.loop) f.set_result([(socket.AF_INET, socket.SOCK_STREAM, socket.SOL_TCP, '', ('1.2.3.4', 80))]) return f @@ -527,14 +523,14 @@ # if host is empty string use None instead host = object() - @tasks.coroutine + @asyncio.coroutine def getaddrinfo(*args, **kw): nonlocal host host = args[0] yield from [] def getaddrinfo_task(*args, **kwds): - return tasks.Task(getaddrinfo(*args, **kwds), loop=self.loop) + return asyncio.Task(getaddrinfo(*args, **kwds), loop=self.loop) self.loop.getaddrinfo = getaddrinfo_task fut = self.loop.create_server(MyProto, '', 0) @@ -596,7 +592,7 @@ self.loop.sock_connect.side_effect = OSError coro = self.loop.create_datagram_endpoint( - protocols.DatagramProtocol, remote_addr=('127.0.0.1', 0)) + asyncio.DatagramProtocol, remote_addr=('127.0.0.1', 0)) self.assertRaises( OSError, self.loop.run_until_complete, coro) @@ -606,19 +602,19 @@ m_socket.socket.side_effect = OSError coro = self.loop.create_datagram_endpoint( - protocols.DatagramProtocol, family=socket.AF_INET) + asyncio.DatagramProtocol, family=socket.AF_INET) self.assertRaises( OSError, self.loop.run_until_complete, coro) coro = self.loop.create_datagram_endpoint( - protocols.DatagramProtocol, local_addr=('127.0.0.1', 0)) + asyncio.DatagramProtocol, local_addr=('127.0.0.1', 0)) self.assertRaises( OSError, self.loop.run_until_complete, coro) @unittest.skipUnless(IPV6_ENABLED, 'IPv6 not supported or enabled') def test_create_datagram_endpoint_no_matching_family(self): coro = self.loop.create_datagram_endpoint( - protocols.DatagramProtocol, + asyncio.DatagramProtocol, remote_addr=('127.0.0.1', 0), local_addr=('::1', 0)) self.assertRaises( ValueError, self.loop.run_until_complete, coro) @@ -628,7 +624,7 @@ m_socket.socket.return_value.setblocking.side_effect = OSError coro = self.loop.create_datagram_endpoint( - protocols.DatagramProtocol, family=socket.AF_INET) + asyncio.DatagramProtocol, family=socket.AF_INET) self.assertRaises( OSError, self.loop.run_until_complete, coro) self.assertTrue( @@ -636,7 +632,7 @@ def test_create_datagram_endpoint_noaddr_nofamily(self): coro = self.loop.create_datagram_endpoint( - protocols.DatagramProtocol) + asyncio.DatagramProtocol) self.assertRaises(ValueError, self.loop.run_until_complete, coro) @unittest.mock.patch('asyncio.base_events.socket') 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 @@ -23,14 +23,9 @@ from test import support # find_unused_port, IPV6_ENABLED, TEST_HOME_DIR -from asyncio import futures +import asyncio from asyncio import events -from asyncio import transports -from asyncio import protocols -from asyncio import selector_events -from asyncio import tasks from asyncio import test_utils -from asyncio import locks def data_file(filename): @@ -49,7 +44,7 @@ SIGNING_CA = data_file('pycacert.pem') -class MyProto(protocols.Protocol): +class MyProto(asyncio.Protocol): done = None def __init__(self, loop=None): @@ -57,7 +52,7 @@ self.state = 'INITIAL' self.nbytes = 0 if loop is not None: - self.done = futures.Future(loop=loop) + self.done = asyncio.Future(loop=loop) def connection_made(self, transport): self.transport = transport @@ -80,14 +75,14 @@ self.done.set_result(None) -class MyDatagramProto(protocols.DatagramProtocol): +class MyDatagramProto(asyncio.DatagramProtocol): done = None def __init__(self, loop=None): self.state = 'INITIAL' self.nbytes = 0 if loop is not None: - self.done = futures.Future(loop=loop) + self.done = asyncio.Future(loop=loop) def connection_made(self, transport): self.transport = transport @@ -108,7 +103,7 @@ self.done.set_result(None) -class MyReadPipeProto(protocols.Protocol): +class MyReadPipeProto(asyncio.Protocol): done = None def __init__(self, loop=None): @@ -116,7 +111,7 @@ self.nbytes = 0 self.transport = None if loop is not None: - self.done = futures.Future(loop=loop) + self.done = asyncio.Future(loop=loop) def connection_made(self, transport): self.transport = transport @@ -140,14 +135,14 @@ self.done.set_result(None) -class MyWritePipeProto(protocols.BaseProtocol): +class MyWritePipeProto(asyncio.BaseProtocol): done = None def __init__(self, loop=None): self.state = 'INITIAL' self.transport = None if loop is not None: - self.done = futures.Future(loop=loop) + self.done = asyncio.Future(loop=loop) def connection_made(self, transport): self.transport = transport @@ -161,18 +156,18 @@ self.done.set_result(None) -class MySubprocessProtocol(protocols.SubprocessProtocol): +class MySubprocessProtocol(asyncio.SubprocessProtocol): def __init__(self, loop): self.state = 'INITIAL' self.transport = None - self.connected = futures.Future(loop=loop) - self.completed = futures.Future(loop=loop) - self.disconnects = {fd: futures.Future(loop=loop) for fd in range(3)} + self.connected = asyncio.Future(loop=loop) + self.completed = asyncio.Future(loop=loop) + self.disconnects = {fd: asyncio.Future(loop=loop) for fd in range(3)} self.data = {1: b'', 2: b''} self.returncode = None - self.got_data = {1: locks.Event(loop=loop), - 2: locks.Event(loop=loop)} + self.got_data = {1: asyncio.Event(loop=loop), + 2: asyncio.Event(loop=loop)} def connection_made(self, transport): self.transport = transport @@ -207,7 +202,7 @@ def setUp(self): super().setUp() self.loop = self.create_event_loop() - events.set_event_loop(None) + asyncio.set_event_loop(None) def tearDown(self): # just in case if we have transport close callbacks @@ -218,11 +213,11 @@ super().tearDown() def test_run_until_complete_nesting(self): - @tasks.coroutine + @asyncio.coroutine def coro1(): yield - @tasks.coroutine + @asyncio.coroutine def coro2(): self.assertTrue(self.loop.is_running()) self.loop.run_until_complete(coro1()) @@ -235,15 +230,15 @@ def test_run_until_complete(self): t0 = self.loop.time() - self.loop.run_until_complete(tasks.sleep(0.1, loop=self.loop)) + self.loop.run_until_complete(asyncio.sleep(0.1, loop=self.loop)) t1 = self.loop.time() self.assertTrue(0.08 <= t1-t0 <= 0.8, t1-t0) def test_run_until_complete_stopped(self): - @tasks.coroutine + @asyncio.coroutine def cb(): self.loop.stop() - yield from tasks.sleep(0.1, loop=self.loop) + yield from asyncio.sleep(0.1, loop=self.loop) task = cb() self.assertRaises(RuntimeError, self.loop.run_until_complete, task) @@ -494,8 +489,8 @@ f = self.loop.create_connection( lambda: MyProto(loop=self.loop), *httpd.address) tr, pr = self.loop.run_until_complete(f) - self.assertIsInstance(tr, transports.Transport) - self.assertIsInstance(pr, protocols.Protocol) + self.assertIsInstance(tr, asyncio.Transport) + self.assertIsInstance(pr, asyncio.Protocol) self.loop.run_until_complete(pr.done) self.assertGreater(pr.nbytes, 0) tr.close() @@ -522,8 +517,8 @@ f = self.loop.create_connection( lambda: MyProto(loop=self.loop), sock=sock) tr, pr = self.loop.run_until_complete(f) - self.assertIsInstance(tr, transports.Transport) - self.assertIsInstance(pr, protocols.Protocol) + self.assertIsInstance(tr, asyncio.Transport) + self.assertIsInstance(pr, asyncio.Protocol) self.loop.run_until_complete(pr.done) self.assertGreater(pr.nbytes, 0) tr.close() @@ -535,8 +530,8 @@ lambda: MyProto(loop=self.loop), *httpd.address, ssl=test_utils.dummy_ssl_context()) tr, pr = self.loop.run_until_complete(f) - self.assertIsInstance(tr, transports.Transport) - self.assertIsInstance(pr, protocols.Protocol) + self.assertIsInstance(tr, asyncio.Transport) + self.assertIsInstance(pr, asyncio.Protocol) self.assertTrue('ssl' in tr.__class__.__name__.lower()) self.assertIsNotNone(tr.get_extra_info('sockname')) self.loop.run_until_complete(pr.done) @@ -762,7 +757,7 @@ server.close() def test_create_server_sock(self): - proto = futures.Future(loop=self.loop) + proto = asyncio.Future(loop=self.loop) class TestMyProto(MyProto): def connection_made(self, transport): @@ -805,7 +800,7 @@ @unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 not supported or enabled') def test_create_server_dual_stack(self): - f_proto = futures.Future(loop=self.loop) + f_proto = asyncio.Future(loop=self.loop) class TestMyProto(MyProto): def connection_made(self, transport): @@ -834,7 +829,7 @@ proto.transport.close() client.close() - f_proto = futures.Future(loop=self.loop) + f_proto = asyncio.Future(loop=self.loop) client = socket.socket(socket.AF_INET6) client.connect(('::1', port)) client.send(b'xxx') @@ -907,7 +902,7 @@ def test_internal_fds(self): loop = self.create_event_loop() - if not isinstance(loop, selector_events.BaseSelectorEventLoop): + if not isinstance(loop, asyncio.BaseSelectorEventLoop): self.skipTest('loop is not a BaseSelectorEventLoop') self.assertEqual(1, loop._internal_fds) @@ -929,7 +924,7 @@ rpipe, wpipe = os.pipe() pipeobj = io.open(rpipe, 'rb', 1024) - @tasks.coroutine + @asyncio.coroutine def connect(): t, p = yield from self.loop.connect_read_pipe(factory, pipeobj) self.assertIs(p, proto) @@ -957,9 +952,6 @@ @unittest.skipUnless(sys.platform != 'win32', "Don't support pipes for Windows") - # kqueue doesn't support character devices (PTY) on Mac OS X older - # than 10.9 (Maverick) - @support.requires_mac_ver(10, 9) def test_read_pty_output(self): proto = None @@ -971,7 +963,7 @@ master, slave = os.openpty() master_read_obj = io.open(master, 'rb', 0) - @tasks.coroutine + @asyncio.coroutine def connect(): t, p = yield from self.loop.connect_read_pipe(factory, master_read_obj) @@ -1012,7 +1004,7 @@ rpipe, wpipe = os.pipe() pipeobj = io.open(wpipe, 'wb', 1024) - @tasks.coroutine + @asyncio.coroutine def connect(): nonlocal transport t, p = yield from self.loop.connect_write_pipe(factory, pipeobj) @@ -1058,7 +1050,7 @@ rsock, wsock = test_utils.socketpair() pipeobj = io.open(wsock.detach(), 'wb', 1024) - @tasks.coroutine + @asyncio.coroutine def connect(): nonlocal transport t, p = yield from self.loop.connect_write_pipe(factory, @@ -1080,6 +1072,53 @@ self.loop.run_until_complete(proto.done) self.assertEqual('CLOSED', proto.state) + @unittest.skipUnless(sys.platform != 'win32', + "Don't support pipes for Windows") + def test_write_pty(self): + proto = None + transport = None + + def factory(): + nonlocal proto + proto = MyWritePipeProto(loop=self.loop) + return proto + + master, slave = os.openpty() + slave_write_obj = io.open(slave, 'wb', 0) + + @asyncio.coroutine + def connect(): + nonlocal transport + t, p = yield from self.loop.connect_write_pipe(factory, + slave_write_obj) + self.assertIs(p, proto) + self.assertIs(t, proto.transport) + self.assertEqual('CONNECTED', proto.state) + transport = t + + self.loop.run_until_complete(connect()) + + transport.write(b'1') + test_utils.run_briefly(self.loop) + data = os.read(master, 1024) + self.assertEqual(b'1', data) + + transport.write(b'2345') + test_utils.run_briefly(self.loop) + data = os.read(master, 1024) + self.assertEqual(b'2345', data) + self.assertEqual('CONNECTED', proto.state) + + os.close(master) + + # extra info is available + self.assertIsNotNone(proto.transport.get_extra_info('pipe')) + + # close connection + proto.transport.close() + self.loop.run_until_complete(proto.done) + self.assertEqual('CLOSED', proto.state) + def test_prompt_cancellation(self): r, w = test_utils.socketpair() r.setblocking(False) @@ -1088,12 +1127,12 @@ if ov is not None: self.assertTrue(ov.pending) - @tasks.coroutine + @asyncio.coroutine def main(): try: self.loop.call_soon(f.cancel) yield from f - except futures.CancelledError: + except asyncio.CancelledError: res = 'cancelled' else: res = None @@ -1102,13 +1141,13 @@ return res start = time.monotonic() - t = tasks.Task(main(), loop=self.loop) + t = asyncio.Task(main(), loop=self.loop) self.loop.run_forever() elapsed = time.monotonic() - start self.assertLess(elapsed, 0.1) self.assertEqual(t.result(), 'cancelled') - self.assertRaises(futures.CancelledError, f.result) + self.assertRaises(asyncio.CancelledError, f.result) if ov is not None: self.assertFalse(ov.pending) self.loop._stop_serving(r) @@ -1126,13 +1165,13 @@ self.loop._run_once = _run_once calls = [] - @tasks.coroutine + @asyncio.coroutine def wait(): loop = self.loop calls.append(loop._run_once_counter) - yield from tasks.sleep(loop.granularity * 10, loop=loop) + yield from asyncio.sleep(loop.granularity * 10, loop=loop) calls.append(loop._run_once_counter) - yield from tasks.sleep(loop.granularity / 10, loop=loop) + yield from asyncio.sleep(loop.granularity / 10, loop=loop) calls.append(loop._run_once_counter) self.loop.run_until_complete(wait()) @@ -1162,7 +1201,7 @@ prog = os.path.join(os.path.dirname(__file__), 'echo.py') - @tasks.coroutine + @asyncio.coroutine def connect(): nonlocal proto, transp transp, proto = yield from self.loop.subprocess_exec( @@ -1188,7 +1227,7 @@ prog = os.path.join(os.path.dirname(__file__), 'echo.py') - @tasks.coroutine + @asyncio.coroutine def connect(): nonlocal proto, transp transp, proto = yield from self.loop.subprocess_exec( @@ -1220,7 +1259,7 @@ proto = None transp = None - @tasks.coroutine + @asyncio.coroutine def connect(): nonlocal proto, transp transp, proto = yield from self.loop.subprocess_shell( @@ -1241,7 +1280,7 @@ def test_subprocess_exitcode(self): proto = None - @tasks.coroutine + @asyncio.coroutine def connect(): nonlocal proto transp, proto = yield from self.loop.subprocess_shell( @@ -1257,7 +1296,7 @@ proto = None transp = None - @tasks.coroutine + @asyncio.coroutine def connect(): nonlocal proto, transp transp, proto = yield from self.loop.subprocess_shell( @@ -1279,7 +1318,7 @@ prog = os.path.join(os.path.dirname(__file__), 'echo.py') - @tasks.coroutine + @asyncio.coroutine def connect(): nonlocal proto, transp transp, proto = yield from self.loop.subprocess_exec( @@ -1300,7 +1339,7 @@ prog = os.path.join(os.path.dirname(__file__), 'echo.py') - @tasks.coroutine + @asyncio.coroutine def connect(): nonlocal proto, transp transp, proto = yield from self.loop.subprocess_exec( @@ -1322,7 +1361,7 @@ prog = os.path.join(os.path.dirname(__file__), 'echo.py') - @tasks.coroutine + @asyncio.coroutine def connect(): nonlocal proto, transp transp, proto = yield from self.loop.subprocess_exec( @@ -1343,7 +1382,7 @@ prog = os.path.join(os.path.dirname(__file__), 'echo2.py') - @tasks.coroutine + @asyncio.coroutine def connect(): nonlocal proto, transp transp, proto = yield from self.loop.subprocess_exec( @@ -1370,7 +1409,7 @@ prog = os.path.join(os.path.dirname(__file__), 'echo2.py') - @tasks.coroutine + @asyncio.coroutine def connect(): nonlocal proto, transp transp, proto = yield from self.loop.subprocess_exec( @@ -1400,7 +1439,7 @@ prog = os.path.join(os.path.dirname(__file__), 'echo3.py') - @tasks.coroutine + @asyncio.coroutine def connect(): nonlocal proto, transp transp, proto = yield from self.loop.subprocess_exec( @@ -1437,7 +1476,7 @@ proto = None transp = None - @tasks.coroutine + @asyncio.coroutine def connect(): nonlocal proto # start the new process in a new session @@ -1453,19 +1492,18 @@ if sys.platform == 'win32': - from asyncio import windows_events class SelectEventLoopTests(EventLoopTestsMixin, unittest.TestCase): def create_event_loop(self): - return windows_events.SelectorEventLoop() + return asyncio.SelectorEventLoop() class ProactorEventLoopTests(EventLoopTestsMixin, SubprocessTestsMixin, unittest.TestCase): def create_event_loop(self): - return windows_events.ProactorEventLoop() + return asyncio.ProactorEventLoop() def test_create_ssl_connection(self): raise unittest.SkipTest("IocpEventLoop incompatible with SSL") @@ -1499,17 +1537,16 @@ "IocpEventLoop does not have create_datagram_endpoint()") else: from asyncio import selectors - from asyncio import unix_events class UnixEventLoopTestsMixin(EventLoopTestsMixin): def setUp(self): super().setUp() - watcher = unix_events.SafeChildWatcher() + watcher = asyncio.SafeChildWatcher() watcher.attach_loop(self.loop) - events.set_child_watcher(watcher) + asyncio.set_child_watcher(watcher) def tearDown(self): - events.set_child_watcher(None) + asyncio.set_child_watcher(None) super().tearDown() if hasattr(selectors, 'KqueueSelector'): @@ -1518,16 +1555,28 @@ unittest.TestCase): def create_event_loop(self): - return unix_events.SelectorEventLoop( + return asyncio.SelectorEventLoop( selectors.KqueueSelector()) + # kqueue doesn't support character devices (PTY) on Mac OS X older + # than 10.9 (Maverick) + @support.requires_mac_ver(10, 9) + def test_read_pty_output(self): + super().test_read_pty_output() + + # kqueue doesn't support character devices (PTY) on Mac OS X older + # than 10.9 (Maverick) + @support.requires_mac_ver(10, 9) + def test_write_pty(self): + super().test_write_pty() + if hasattr(selectors, 'EpollSelector'): class EPollEventLoopTests(UnixEventLoopTestsMixin, SubprocessTestsMixin, unittest.TestCase): def create_event_loop(self): - return unix_events.SelectorEventLoop(selectors.EpollSelector()) + return asyncio.SelectorEventLoop(selectors.EpollSelector()) if hasattr(selectors, 'PollSelector'): class PollEventLoopTests(UnixEventLoopTestsMixin, @@ -1535,7 +1584,7 @@ unittest.TestCase): def create_event_loop(self): - return unix_events.SelectorEventLoop(selectors.PollSelector()) + return asyncio.SelectorEventLoop(selectors.PollSelector()) # Should always exist. class SelectEventLoopTests(UnixEventLoopTestsMixin, @@ -1543,7 +1592,7 @@ unittest.TestCase): def create_event_loop(self): - return unix_events.SelectorEventLoop(selectors.SelectSelector()) + return asyncio.SelectorEventLoop(selectors.SelectSelector()) class HandleTests(unittest.TestCase): @@ -1553,7 +1602,7 @@ return args args = () - h = events.Handle(callback, args) + h = asyncio.Handle(callback, args) self.assertIs(h._callback, callback) self.assertIs(h._args, args) self.assertFalse(h._cancelled) @@ -1576,16 +1625,16 @@ def test_make_handle(self): def callback(*args): return args - h1 = events.Handle(callback, ()) + h1 = asyncio.Handle(callback, ()) self.assertRaises( - AssertionError, events.make_handle, h1, ()) + AssertionError, asyncio.events.make_handle, h1, ()) @unittest.mock.patch('asyncio.events.logger') def test_callback_with_exception(self, log): def callback(): raise ValueError() - h = events.Handle(callback, ()) + h = asyncio.Handle(callback, ()) h._run() self.assertTrue(log.exception.called) @@ -1594,7 +1643,7 @@ def test_hash(self): when = time.monotonic() - h = events.TimerHandle(when, lambda: False, ()) + h = asyncio.TimerHandle(when, lambda: False, ()) self.assertEqual(hash(h), hash(when)) def test_timer(self): @@ -1603,7 +1652,7 @@ args = () when = time.monotonic() - h = events.TimerHandle(when, callback, args) + h = asyncio.TimerHandle(when, callback, args) self.assertIs(h._callback, callback) self.assertIs(h._args, args) self.assertFalse(h._cancelled) @@ -1618,7 +1667,7 @@ self.assertTrue(r.endswith('())'), r) self.assertRaises(AssertionError, - events.TimerHandle, None, callback, args) + asyncio.TimerHandle, None, callback, args) def test_timer_comparison(self): def callback(*args): @@ -1626,8 +1675,8 @@ when = time.monotonic() - h1 = events.TimerHandle(when, callback, ()) - h2 = events.TimerHandle(when, callback, ()) + h1 = asyncio.TimerHandle(when, callback, ()) + h2 = asyncio.TimerHandle(when, callback, ()) # TODO: Use assertLess etc. self.assertFalse(h1 < h2) self.assertFalse(h2 < h1) @@ -1643,8 +1692,8 @@ h2.cancel() self.assertFalse(h1 == h2) - h1 = events.TimerHandle(when, callback, ()) - h2 = events.TimerHandle(when + 10.0, callback, ()) + h1 = asyncio.TimerHandle(when, callback, ()) + h2 = asyncio.TimerHandle(when + 10.0, callback, ()) self.assertTrue(h1 < h2) self.assertFalse(h2 < h1) self.assertTrue(h1 <= h2) @@ -1656,7 +1705,7 @@ self.assertFalse(h1 == h2) self.assertTrue(h1 != h2) - h3 = events.Handle(callback, ()) + h3 = asyncio.Handle(callback, ()) self.assertIs(NotImplemented, h1.__eq__(h3)) self.assertIs(NotImplemented, h1.__ne__(h3)) @@ -1665,7 +1714,7 @@ def test_not_implemented(self): f = unittest.mock.Mock() - loop = events.AbstractEventLoop() + loop = asyncio.AbstractEventLoop() self.assertRaises( NotImplementedError, loop.run_forever) self.assertRaises( @@ -1739,19 +1788,19 @@ def test_empty(self): f = unittest.mock.Mock() - p = protocols.Protocol() + p = asyncio.Protocol() self.assertIsNone(p.connection_made(f)) self.assertIsNone(p.connection_lost(f)) self.assertIsNone(p.data_received(f)) self.assertIsNone(p.eof_received()) - dp = protocols.DatagramProtocol() + dp = asyncio.DatagramProtocol() self.assertIsNone(dp.connection_made(f)) self.assertIsNone(dp.connection_lost(f)) self.assertIsNone(dp.error_received(f)) self.assertIsNone(dp.datagram_received(f, f)) - sp = protocols.SubprocessProtocol() + sp = asyncio.SubprocessProtocol() self.assertIsNone(sp.connection_made(f)) self.assertIsNone(sp.connection_lost(f)) self.assertIsNone(sp.pipe_data_received(1, f)) @@ -1761,16 +1810,8 @@ class PolicyTests(unittest.TestCase): - def create_policy(self): - if sys.platform == "win32": - from asyncio import windows_events - return windows_events.DefaultEventLoopPolicy() - else: - from asyncio import unix_events - return unix_events.DefaultEventLoopPolicy() - def test_event_loop_policy(self): - policy = events.AbstractEventLoopPolicy() + policy = asyncio.AbstractEventLoopPolicy() self.assertRaises(NotImplementedError, policy.get_event_loop) self.assertRaises(NotImplementedError, policy.set_event_loop, object()) self.assertRaises(NotImplementedError, policy.new_event_loop) @@ -1779,18 +1820,18 @@ object()) def test_get_event_loop(self): - policy = self.create_policy() + policy = asyncio.DefaultEventLoopPolicy() self.assertIsNone(policy._local._loop) loop = policy.get_event_loop() - self.assertIsInstance(loop, events.AbstractEventLoop) + self.assertIsInstance(loop, asyncio.AbstractEventLoop) self.assertIs(policy._local._loop, loop) self.assertIs(loop, policy.get_event_loop()) loop.close() def test_get_event_loop_calls_set_event_loop(self): - policy = self.create_policy() + policy = asyncio.DefaultEventLoopPolicy() with unittest.mock.patch.object( policy, "set_event_loop", @@ -1806,7 +1847,7 @@ loop.close() def test_get_event_loop_after_set_none(self): - policy = self.create_policy() + policy = asyncio.DefaultEventLoopPolicy() policy.set_event_loop(None) self.assertRaises(AssertionError, policy.get_event_loop) @@ -1814,7 +1855,7 @@ def test_get_event_loop_thread(self, m_current_thread): def f(): - policy = self.create_policy() + policy = asyncio.DefaultEventLoopPolicy() self.assertRaises(AssertionError, policy.get_event_loop) th = threading.Thread(target=f) @@ -1822,14 +1863,14 @@ th.join() def test_new_event_loop(self): - policy = self.create_policy() + policy = asyncio.DefaultEventLoopPolicy() loop = policy.new_event_loop() - self.assertIsInstance(loop, events.AbstractEventLoop) + self.assertIsInstance(loop, asyncio.AbstractEventLoop) loop.close() def test_set_event_loop(self): - policy = self.create_policy() + policy = asyncio.DefaultEventLoopPolicy() old_loop = policy.get_event_loop() self.assertRaises(AssertionError, policy.set_event_loop, object()) @@ -1842,19 +1883,19 @@ old_loop.close() def test_get_event_loop_policy(self): - policy = events.get_event_loop_policy() - self.assertIsInstance(policy, events.AbstractEventLoopPolicy) - self.assertIs(policy, events.get_event_loop_policy()) + policy = asyncio.get_event_loop_policy() + self.assertIsInstance(policy, asyncio.AbstractEventLoopPolicy) + self.assertIs(policy, asyncio.get_event_loop_policy()) def test_set_event_loop_policy(self): self.assertRaises( - AssertionError, events.set_event_loop_policy, object()) + AssertionError, asyncio.set_event_loop_policy, object()) - old_policy = events.get_event_loop_policy() + old_policy = asyncio.get_event_loop_policy() - policy = self.create_policy() - events.set_event_loop_policy(policy) - self.assertIs(policy, events.get_event_loop_policy()) + policy = asyncio.DefaultEventLoopPolicy() + asyncio.set_event_loop_policy(policy) + self.assertIs(policy, asyncio.get_event_loop_policy()) self.assertIsNot(policy, old_policy) 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 @@ -5,8 +5,7 @@ import unittest import unittest.mock -from asyncio import events -from asyncio import futures +import asyncio from asyncio import test_utils @@ -18,13 +17,13 @@ def setUp(self): self.loop = test_utils.TestLoop() - events.set_event_loop(None) + asyncio.set_event_loop(None) def tearDown(self): self.loop.close() def test_initial_state(self): - f = futures.Future(loop=self.loop) + f = asyncio.Future(loop=self.loop) self.assertFalse(f.cancelled()) self.assertFalse(f.done()) f.cancel() @@ -32,56 +31,56 @@ def test_init_constructor_default_loop(self): try: - events.set_event_loop(self.loop) - f = futures.Future() + asyncio.set_event_loop(self.loop) + f = asyncio.Future() self.assertIs(f._loop, self.loop) finally: - events.set_event_loop(None) + asyncio.set_event_loop(None) def test_constructor_positional(self): # Make sure Future does't accept a positional argument - self.assertRaises(TypeError, futures.Future, 42) + self.assertRaises(TypeError, asyncio.Future, 42) def test_cancel(self): - f = futures.Future(loop=self.loop) + f = asyncio.Future(loop=self.loop) self.assertTrue(f.cancel()) self.assertTrue(f.cancelled()) self.assertTrue(f.done()) - self.assertRaises(futures.CancelledError, f.result) - self.assertRaises(futures.CancelledError, f.exception) - self.assertRaises(futures.InvalidStateError, f.set_result, None) - self.assertRaises(futures.InvalidStateError, f.set_exception, None) + self.assertRaises(asyncio.CancelledError, f.result) + self.assertRaises(asyncio.CancelledError, f.exception) + self.assertRaises(asyncio.InvalidStateError, f.set_result, None) + self.assertRaises(asyncio.InvalidStateError, f.set_exception, None) self.assertFalse(f.cancel()) def test_result(self): - f = futures.Future(loop=self.loop) - self.assertRaises(futures.InvalidStateError, f.result) + f = asyncio.Future(loop=self.loop) + self.assertRaises(asyncio.InvalidStateError, f.result) f.set_result(42) self.assertFalse(f.cancelled()) self.assertTrue(f.done()) self.assertEqual(f.result(), 42) self.assertEqual(f.exception(), None) - self.assertRaises(futures.InvalidStateError, f.set_result, None) - self.assertRaises(futures.InvalidStateError, f.set_exception, None) + self.assertRaises(asyncio.InvalidStateError, f.set_result, None) + self.assertRaises(asyncio.InvalidStateError, f.set_exception, None) self.assertFalse(f.cancel()) def test_exception(self): exc = RuntimeError() - f = futures.Future(loop=self.loop) - self.assertRaises(futures.InvalidStateError, f.exception) + f = asyncio.Future(loop=self.loop) + self.assertRaises(asyncio.InvalidStateError, f.exception) f.set_exception(exc) self.assertFalse(f.cancelled()) self.assertTrue(f.done()) self.assertRaises(RuntimeError, f.result) self.assertEqual(f.exception(), exc) - self.assertRaises(futures.InvalidStateError, f.set_result, None) - self.assertRaises(futures.InvalidStateError, f.set_exception, None) + self.assertRaises(asyncio.InvalidStateError, f.set_result, None) + self.assertRaises(asyncio.InvalidStateError, f.set_exception, None) self.assertFalse(f.cancel()) def test_yield_from_twice(self): - f = futures.Future(loop=self.loop) + f = asyncio.Future(loop=self.loop) def fixture(): yield 'A' @@ -99,32 +98,32 @@ self.assertEqual(next(g), ('C', 42)) # yield 'C', y. def test_repr(self): - f_pending = futures.Future(loop=self.loop) + f_pending = asyncio.Future(loop=self.loop) self.assertEqual(repr(f_pending), 'Future') f_pending.cancel() - f_cancelled = futures.Future(loop=self.loop) + f_cancelled = asyncio.Future(loop=self.loop) f_cancelled.cancel() self.assertEqual(repr(f_cancelled), 'Future') - f_result = futures.Future(loop=self.loop) + f_result = asyncio.Future(loop=self.loop) f_result.set_result(4) self.assertEqual(repr(f_result), 'Future') self.assertEqual(f_result.result(), 4) exc = RuntimeError() - f_exception = futures.Future(loop=self.loop) + f_exception = asyncio.Future(loop=self.loop) f_exception.set_exception(exc) self.assertEqual(repr(f_exception), 'Future') self.assertIs(f_exception.exception(), exc) - f_few_callbacks = futures.Future(loop=self.loop) + f_few_callbacks = asyncio.Future(loop=self.loop) f_few_callbacks.add_done_callback(_fakefunc) self.assertIn('Future')) self.assertTrue(RGX_REPR.match(repr(lock))) - @tasks.coroutine + @asyncio.coroutine def acquire_lock(): yield from lock @@ -59,9 +56,9 @@ self.assertTrue(RGX_REPR.match(repr(lock))) def test_lock(self): - lock = locks.Lock(loop=self.loop) + lock = asyncio.Lock(loop=self.loop) - @tasks.coroutine + @asyncio.coroutine def acquire_lock(): return (yield from lock) @@ -74,31 +71,31 @@ self.assertFalse(lock.locked()) def test_acquire(self): - lock = locks.Lock(loop=self.loop) + lock = asyncio.Lock(loop=self.loop) result = [] self.assertTrue(self.loop.run_until_complete(lock.acquire())) - @tasks.coroutine + @asyncio.coroutine def c1(result): if (yield from lock.acquire()): result.append(1) return True - @tasks.coroutine + @asyncio.coroutine def c2(result): if (yield from lock.acquire()): result.append(2) return True - @tasks.coroutine + @asyncio.coroutine def c3(result): if (yield from lock.acquire()): result.append(3) return True - t1 = tasks.Task(c1(result), loop=self.loop) - t2 = tasks.Task(c2(result), loop=self.loop) + t1 = asyncio.Task(c1(result), loop=self.loop) + t2 = asyncio.Task(c2(result), loop=self.loop) test_utils.run_briefly(self.loop) self.assertEqual([], result) @@ -110,7 +107,7 @@ test_utils.run_briefly(self.loop) self.assertEqual([1], result) - t3 = tasks.Task(c3(result), loop=self.loop) + t3 = asyncio.Task(c3(result), loop=self.loop) lock.release() test_utils.run_briefly(self.loop) @@ -128,13 +125,13 @@ self.assertTrue(t3.result()) def test_acquire_cancel(self): - lock = locks.Lock(loop=self.loop) + lock = asyncio.Lock(loop=self.loop) self.assertTrue(self.loop.run_until_complete(lock.acquire())) - task = tasks.Task(lock.acquire(), loop=self.loop) + task = asyncio.Task(lock.acquire(), loop=self.loop) self.loop.call_soon(task.cancel) self.assertRaises( - futures.CancelledError, + asyncio.CancelledError, self.loop.run_until_complete, task) self.assertFalse(lock._waiters) @@ -153,9 +150,9 @@ # B's waiter; instead, it should move on to C's waiter. # Setup: A has the lock, b and c are waiting. - lock = locks.Lock(loop=self.loop) + lock = asyncio.Lock(loop=self.loop) - @tasks.coroutine + @asyncio.coroutine def lockit(name, blocker): yield from lock.acquire() try: @@ -164,14 +161,14 @@ finally: lock.release() - fa = futures.Future(loop=self.loop) - ta = tasks.Task(lockit('A', fa), loop=self.loop) + fa = asyncio.Future(loop=self.loop) + ta = asyncio.Task(lockit('A', fa), loop=self.loop) test_utils.run_briefly(self.loop) self.assertTrue(lock.locked()) - tb = tasks.Task(lockit('B', None), loop=self.loop) + tb = asyncio.Task(lockit('B', None), loop=self.loop) test_utils.run_briefly(self.loop) self.assertEqual(len(lock._waiters), 1) - tc = tasks.Task(lockit('C', None), loop=self.loop) + tc = asyncio.Task(lockit('C', None), loop=self.loop) test_utils.run_briefly(self.loop) self.assertEqual(len(lock._waiters), 2) @@ -187,12 +184,12 @@ self.assertTrue(tc.done()) def test_release_not_acquired(self): - lock = locks.Lock(loop=self.loop) + lock = asyncio.Lock(loop=self.loop) self.assertRaises(RuntimeError, lock.release) def test_release_no_waiters(self): - lock = locks.Lock(loop=self.loop) + lock = asyncio.Lock(loop=self.loop) self.loop.run_until_complete(lock.acquire()) self.assertTrue(lock.locked()) @@ -200,9 +197,9 @@ self.assertFalse(lock.locked()) def test_context_manager(self): - lock = locks.Lock(loop=self.loop) + lock = asyncio.Lock(loop=self.loop) - @tasks.coroutine + @asyncio.coroutine def acquire_lock(): return (yield from lock) @@ -212,7 +209,7 @@ self.assertFalse(lock.locked()) def test_context_manager_no_yield(self): - lock = locks.Lock(loop=self.loop) + lock = asyncio.Lock(loop=self.loop) try: with lock: @@ -227,29 +224,29 @@ def setUp(self): self.loop = test_utils.TestLoop() - events.set_event_loop(None) + asyncio.set_event_loop(None) def tearDown(self): self.loop.close() def test_ctor_loop(self): loop = unittest.mock.Mock() - ev = locks.Event(loop=loop) + ev = asyncio.Event(loop=loop) self.assertIs(ev._loop, loop) - ev = locks.Event(loop=self.loop) + ev = asyncio.Event(loop=self.loop) self.assertIs(ev._loop, self.loop) def test_ctor_noloop(self): try: - events.set_event_loop(self.loop) - ev = locks.Event() + asyncio.set_event_loop(self.loop) + ev = asyncio.Event() self.assertIs(ev._loop, self.loop) finally: - events.set_event_loop(None) + asyncio.set_event_loop(None) def test_repr(self): - ev = locks.Event(loop=self.loop) + ev = asyncio.Event(loop=self.loop) self.assertTrue(repr(ev).endswith('[unset]>')) match = RGX_REPR.match(repr(ev)) self.assertEqual(match.group('extras'), 'unset') @@ -263,33 +260,33 @@ self.assertTrue(RGX_REPR.match(repr(ev))) def test_wait(self): - ev = locks.Event(loop=self.loop) + ev = asyncio.Event(loop=self.loop) self.assertFalse(ev.is_set()) result = [] - @tasks.coroutine + @asyncio.coroutine def c1(result): if (yield from ev.wait()): result.append(1) - @tasks.coroutine + @asyncio.coroutine def c2(result): if (yield from ev.wait()): result.append(2) - @tasks.coroutine + @asyncio.coroutine def c3(result): if (yield from ev.wait()): result.append(3) - t1 = tasks.Task(c1(result), loop=self.loop) - t2 = tasks.Task(c2(result), loop=self.loop) + t1 = asyncio.Task(c1(result), loop=self.loop) + t2 = asyncio.Task(c2(result), loop=self.loop) test_utils.run_briefly(self.loop) self.assertEqual([], result) - t3 = tasks.Task(c3(result), loop=self.loop) + t3 = asyncio.Task(c3(result), loop=self.loop) ev.set() test_utils.run_briefly(self.loop) @@ -303,24 +300,24 @@ self.assertIsNone(t3.result()) def test_wait_on_set(self): - ev = locks.Event(loop=self.loop) + ev = asyncio.Event(loop=self.loop) ev.set() res = self.loop.run_until_complete(ev.wait()) self.assertTrue(res) def test_wait_cancel(self): - ev = locks.Event(loop=self.loop) + ev = asyncio.Event(loop=self.loop) - wait = tasks.Task(ev.wait(), loop=self.loop) + wait = asyncio.Task(ev.wait(), loop=self.loop) self.loop.call_soon(wait.cancel) self.assertRaises( - futures.CancelledError, + asyncio.CancelledError, self.loop.run_until_complete, wait) self.assertFalse(ev._waiters) def test_clear(self): - ev = locks.Event(loop=self.loop) + ev = asyncio.Event(loop=self.loop) self.assertFalse(ev.is_set()) ev.set() @@ -330,16 +327,16 @@ self.assertFalse(ev.is_set()) def test_clear_with_waiters(self): - ev = locks.Event(loop=self.loop) + ev = asyncio.Event(loop=self.loop) result = [] - @tasks.coroutine + @asyncio.coroutine def c1(result): if (yield from ev.wait()): result.append(1) return True - t = tasks.Task(c1(result), loop=self.loop) + t = asyncio.Task(c1(result), loop=self.loop) test_utils.run_briefly(self.loop) self.assertEqual([], result) @@ -363,55 +360,55 @@ def setUp(self): self.loop = test_utils.TestLoop() - events.set_event_loop(None) + asyncio.set_event_loop(None) def tearDown(self): self.loop.close() def test_ctor_loop(self): loop = unittest.mock.Mock() - cond = locks.Condition(loop=loop) + cond = asyncio.Condition(loop=loop) self.assertIs(cond._loop, loop) - cond = locks.Condition(loop=self.loop) + cond = asyncio.Condition(loop=self.loop) self.assertIs(cond._loop, self.loop) def test_ctor_noloop(self): try: - events.set_event_loop(self.loop) - cond = locks.Condition() + asyncio.set_event_loop(self.loop) + cond = asyncio.Condition() self.assertIs(cond._loop, self.loop) finally: - events.set_event_loop(None) + asyncio.set_event_loop(None) def test_wait(self): - cond = locks.Condition(loop=self.loop) + cond = asyncio.Condition(loop=self.loop) result = [] - @tasks.coroutine + @asyncio.coroutine def c1(result): yield from cond.acquire() if (yield from cond.wait()): result.append(1) return True - @tasks.coroutine + @asyncio.coroutine def c2(result): yield from cond.acquire() if (yield from cond.wait()): result.append(2) return True - @tasks.coroutine + @asyncio.coroutine def c3(result): yield from cond.acquire() if (yield from cond.wait()): result.append(3) return True - t1 = tasks.Task(c1(result), loop=self.loop) - t2 = tasks.Task(c2(result), loop=self.loop) - t3 = tasks.Task(c3(result), loop=self.loop) + t1 = asyncio.Task(c1(result), loop=self.loop) + t2 = asyncio.Task(c2(result), loop=self.loop) + t3 = asyncio.Task(c3(result), loop=self.loop) test_utils.run_briefly(self.loop) self.assertEqual([], result) @@ -451,25 +448,25 @@ self.assertTrue(t3.result()) def test_wait_cancel(self): - cond = locks.Condition(loop=self.loop) + cond = asyncio.Condition(loop=self.loop) self.loop.run_until_complete(cond.acquire()) - wait = tasks.Task(cond.wait(), loop=self.loop) + wait = asyncio.Task(cond.wait(), loop=self.loop) self.loop.call_soon(wait.cancel) self.assertRaises( - futures.CancelledError, + asyncio.CancelledError, self.loop.run_until_complete, wait) self.assertFalse(cond._waiters) self.assertTrue(cond.locked()) def test_wait_unacquired(self): - cond = locks.Condition(loop=self.loop) + cond = asyncio.Condition(loop=self.loop) self.assertRaises( RuntimeError, self.loop.run_until_complete, cond.wait()) def test_wait_for(self): - cond = locks.Condition(loop=self.loop) + cond = asyncio.Condition(loop=self.loop) presult = False def predicate(): @@ -477,7 +474,7 @@ result = [] - @tasks.coroutine + @asyncio.coroutine def c1(result): yield from cond.acquire() if (yield from cond.wait_for(predicate)): @@ -485,7 +482,7 @@ cond.release() return True - t = tasks.Task(c1(result), loop=self.loop) + t = asyncio.Task(c1(result), loop=self.loop) test_utils.run_briefly(self.loop) self.assertEqual([], result) @@ -507,7 +504,7 @@ self.assertTrue(t.result()) def test_wait_for_unacquired(self): - cond = locks.Condition(loop=self.loop) + cond = asyncio.Condition(loop=self.loop) # predicate can return true immediately res = self.loop.run_until_complete(cond.wait_for(lambda: [1, 2, 3])) @@ -519,10 +516,10 @@ cond.wait_for(lambda: False)) def test_notify(self): - cond = locks.Condition(loop=self.loop) + cond = asyncio.Condition(loop=self.loop) result = [] - @tasks.coroutine + @asyncio.coroutine def c1(result): yield from cond.acquire() if (yield from cond.wait()): @@ -530,7 +527,7 @@ cond.release() return True - @tasks.coroutine + @asyncio.coroutine def c2(result): yield from cond.acquire() if (yield from cond.wait()): @@ -538,7 +535,7 @@ cond.release() return True - @tasks.coroutine + @asyncio.coroutine def c3(result): yield from cond.acquire() if (yield from cond.wait()): @@ -546,9 +543,9 @@ cond.release() return True - t1 = tasks.Task(c1(result), loop=self.loop) - t2 = tasks.Task(c2(result), loop=self.loop) - t3 = tasks.Task(c3(result), loop=self.loop) + t1 = asyncio.Task(c1(result), loop=self.loop) + t2 = asyncio.Task(c2(result), loop=self.loop) + t3 = asyncio.Task(c3(result), loop=self.loop) test_utils.run_briefly(self.loop) self.assertEqual([], result) @@ -574,11 +571,11 @@ self.assertTrue(t3.result()) def test_notify_all(self): - cond = locks.Condition(loop=self.loop) + cond = asyncio.Condition(loop=self.loop) result = [] - @tasks.coroutine + @asyncio.coroutine def c1(result): yield from cond.acquire() if (yield from cond.wait()): @@ -586,7 +583,7 @@ cond.release() return True - @tasks.coroutine + @asyncio.coroutine def c2(result): yield from cond.acquire() if (yield from cond.wait()): @@ -594,8 +591,8 @@ cond.release() return True - t1 = tasks.Task(c1(result), loop=self.loop) - t2 = tasks.Task(c2(result), loop=self.loop) + t1 = asyncio.Task(c1(result), loop=self.loop) + t2 = asyncio.Task(c2(result), loop=self.loop) test_utils.run_briefly(self.loop) self.assertEqual([], result) @@ -612,15 +609,15 @@ self.assertTrue(t2.result()) def test_notify_unacquired(self): - cond = locks.Condition(loop=self.loop) + cond = asyncio.Condition(loop=self.loop) self.assertRaises(RuntimeError, cond.notify) def test_notify_all_unacquired(self): - cond = locks.Condition(loop=self.loop) + cond = asyncio.Condition(loop=self.loop) self.assertRaises(RuntimeError, cond.notify_all) def test_repr(self): - cond = locks.Condition(loop=self.loop) + cond = asyncio.Condition(loop=self.loop) self.assertTrue('unlocked' in repr(cond)) self.assertTrue(RGX_REPR.match(repr(cond))) @@ -636,9 +633,9 @@ self.assertTrue(RGX_REPR.match(repr(cond))) def test_context_manager(self): - cond = locks.Condition(loop=self.loop) + cond = asyncio.Condition(loop=self.loop) - @tasks.coroutine + @asyncio.coroutine def acquire_cond(): return (yield from cond) @@ -648,7 +645,7 @@ self.assertFalse(cond.locked()) def test_context_manager_no_yield(self): - cond = locks.Condition(loop=self.loop) + cond = asyncio.Condition(loop=self.loop) try: with cond: @@ -663,33 +660,33 @@ def setUp(self): self.loop = test_utils.TestLoop() - events.set_event_loop(None) + asyncio.set_event_loop(None) def tearDown(self): self.loop.close() def test_ctor_loop(self): loop = unittest.mock.Mock() - sem = locks.Semaphore(loop=loop) + sem = asyncio.Semaphore(loop=loop) self.assertIs(sem._loop, loop) - sem = locks.Semaphore(loop=self.loop) + sem = asyncio.Semaphore(loop=self.loop) self.assertIs(sem._loop, self.loop) def test_ctor_noloop(self): try: - events.set_event_loop(self.loop) - sem = locks.Semaphore() + asyncio.set_event_loop(self.loop) + sem = asyncio.Semaphore() self.assertIs(sem._loop, self.loop) finally: - events.set_event_loop(None) + asyncio.set_event_loop(None) def test_initial_value_zero(self): - sem = locks.Semaphore(0, loop=self.loop) + sem = asyncio.Semaphore(0, loop=self.loop) self.assertTrue(sem.locked()) def test_repr(self): - sem = locks.Semaphore(loop=self.loop) + sem = asyncio.Semaphore(loop=self.loop) self.assertTrue(repr(sem).endswith('[unlocked,value:1]>')) self.assertTrue(RGX_REPR.match(repr(sem))) @@ -707,10 +704,10 @@ self.assertTrue(RGX_REPR.match(repr(sem))) def test_semaphore(self): - sem = locks.Semaphore(loop=self.loop) + sem = asyncio.Semaphore(loop=self.loop) self.assertEqual(1, sem._value) - @tasks.coroutine + @asyncio.coroutine def acquire_lock(): return (yield from sem) @@ -725,43 +722,43 @@ self.assertEqual(1, sem._value) def test_semaphore_value(self): - self.assertRaises(ValueError, locks.Semaphore, -1) + self.assertRaises(ValueError, asyncio.Semaphore, -1) def test_acquire(self): - sem = locks.Semaphore(3, loop=self.loop) + sem = asyncio.Semaphore(3, loop=self.loop) result = [] self.assertTrue(self.loop.run_until_complete(sem.acquire())) self.assertTrue(self.loop.run_until_complete(sem.acquire())) self.assertFalse(sem.locked()) - @tasks.coroutine + @asyncio.coroutine def c1(result): yield from sem.acquire() result.append(1) return True - @tasks.coroutine + @asyncio.coroutine def c2(result): yield from sem.acquire() result.append(2) return True - @tasks.coroutine + @asyncio.coroutine def c3(result): yield from sem.acquire() result.append(3) return True - @tasks.coroutine + @asyncio.coroutine def c4(result): yield from sem.acquire() result.append(4) return True - t1 = tasks.Task(c1(result), loop=self.loop) - t2 = tasks.Task(c2(result), loop=self.loop) - t3 = tasks.Task(c3(result), loop=self.loop) + t1 = asyncio.Task(c1(result), loop=self.loop) + t2 = asyncio.Task(c2(result), loop=self.loop) + t3 = asyncio.Task(c3(result), loop=self.loop) test_utils.run_briefly(self.loop) self.assertEqual([1], result) @@ -769,7 +766,7 @@ self.assertEqual(2, len(sem._waiters)) self.assertEqual(0, sem._value) - t4 = tasks.Task(c4(result), loop=self.loop) + t4 = asyncio.Task(c4(result), loop=self.loop) sem.release() sem.release() @@ -794,23 +791,23 @@ sem.release() def test_acquire_cancel(self): - sem = locks.Semaphore(loop=self.loop) + sem = asyncio.Semaphore(loop=self.loop) self.loop.run_until_complete(sem.acquire()) - acquire = tasks.Task(sem.acquire(), loop=self.loop) + acquire = asyncio.Task(sem.acquire(), loop=self.loop) self.loop.call_soon(acquire.cancel) self.assertRaises( - futures.CancelledError, + asyncio.CancelledError, self.loop.run_until_complete, acquire) self.assertFalse(sem._waiters) def test_release_not_acquired(self): - sem = locks.BoundedSemaphore(loop=self.loop) + sem = asyncio.BoundedSemaphore(loop=self.loop) self.assertRaises(ValueError, sem.release) def test_release_no_waiters(self): - sem = locks.Semaphore(loop=self.loop) + sem = asyncio.Semaphore(loop=self.loop) self.loop.run_until_complete(sem.acquire()) self.assertTrue(sem.locked()) @@ -818,9 +815,9 @@ self.assertFalse(sem.locked()) def test_context_manager(self): - sem = locks.Semaphore(2, loop=self.loop) + sem = asyncio.Semaphore(2, loop=self.loop) - @tasks.coroutine + @asyncio.coroutine def acquire_lock(): return (yield from sem) diff --git a/Lib/test/test_asyncio/test_proactor_events.py b/Lib/test/test_asyncio/test_proactor_events.py --- a/Lib/test/test_asyncio/test_proactor_events.py +++ b/Lib/test/test_asyncio/test_proactor_events.py @@ -5,7 +5,6 @@ import unittest.mock import asyncio -from asyncio.proactor_events import BaseProactorEventLoop from asyncio.proactor_events import _ProactorSocketTransport from asyncio.proactor_events import _ProactorWritePipeTransport from asyncio.proactor_events import _ProactorDuplexPipeTransport @@ -345,18 +344,18 @@ self.ssock, self.csock = unittest.mock.Mock(), unittest.mock.Mock() - class EventLoop(BaseProactorEventLoop): + class EventLoop(asyncio.BaseProactorEventLoop): def _socketpair(s): return (self.ssock, self.csock) self.loop = EventLoop(self.proactor) - @unittest.mock.patch.object(BaseProactorEventLoop, 'call_soon') - @unittest.mock.patch.object(BaseProactorEventLoop, '_socketpair') + @unittest.mock.patch.object(asyncio.BaseProactorEventLoop, 'call_soon') + @unittest.mock.patch.object(asyncio.BaseProactorEventLoop, '_socketpair') def test_ctor(self, socketpair, call_soon): ssock, csock = socketpair.return_value = ( unittest.mock.Mock(), unittest.mock.Mock()) - loop = BaseProactorEventLoop(self.proactor) + loop = asyncio.BaseProactorEventLoop(self.proactor) self.assertIs(loop._ssock, ssock) self.assertIs(loop._csock, csock) self.assertEqual(loop._internal_fds, 1) @@ -399,7 +398,7 @@ def test_socketpair(self): self.assertRaises( - NotImplementedError, BaseProactorEventLoop, self.proactor) + NotImplementedError, asyncio.BaseProactorEventLoop, self.proactor) def test_make_socket_transport(self): tr = self.loop._make_socket_transport(self.sock, unittest.mock.Mock()) diff --git a/Lib/test/test_asyncio/test_queues.py b/Lib/test/test_asyncio/test_queues.py --- a/Lib/test/test_asyncio/test_queues.py +++ b/Lib/test/test_asyncio/test_queues.py @@ -3,11 +3,7 @@ import unittest import unittest.mock -from asyncio import events -from asyncio import futures -from asyncio import locks -from asyncio import queues -from asyncio import tasks +import asyncio from asyncio import test_utils @@ -15,7 +11,7 @@ def setUp(self): self.loop = test_utils.TestLoop() - events.set_event_loop(None) + asyncio.set_event_loop(None) def tearDown(self): self.loop.close() @@ -39,57 +35,57 @@ loop = test_utils.TestLoop(gen) self.addCleanup(loop.close) - q = queues.Queue(loop=loop) + q = asyncio.Queue(loop=loop) self.assertTrue(fn(q).startswith(')') t.cancel() # Does not take immediate effect! self.assertEqual(repr(t), 'Task()') - self.assertRaises(futures.CancelledError, + self.assertRaises(asyncio.CancelledError, self.loop.run_until_complete, t) self.assertEqual(repr(t), 'Task()') - t = tasks.Task(notmuch(), loop=self.loop) + t = asyncio.Task(notmuch(), loop=self.loop) self.loop.run_until_complete(t) self.assertEqual(repr(t), "Task()") def test_task_repr_custom(self): - @tasks.coroutine + @asyncio.coroutine def coro(): pass - class T(futures.Future): + class T(asyncio.Future): def __repr__(self): return 'T[]' - class MyTask(tasks.Task, T): + class MyTask(asyncio.Task, T): def __repr__(self): return super().__repr__() @@ -142,17 +140,17 @@ gen.close() def test_task_basics(self): - @tasks.coroutine + @asyncio.coroutine def outer(): a = yield from inner1() b = yield from inner2() return a+b - @tasks.coroutine + @asyncio.coroutine def inner1(): return 42 - @tasks.coroutine + @asyncio.coroutine def inner2(): return 1000 @@ -169,66 +167,66 @@ loop = test_utils.TestLoop(gen) self.addCleanup(loop.close) - @tasks.coroutine + @asyncio.coroutine def task(): - yield from tasks.sleep(10.0, loop=loop) + yield from asyncio.sleep(10.0, loop=loop) return 12 - t = tasks.Task(task(), loop=loop) + t = asyncio.Task(task(), loop=loop) loop.call_soon(t.cancel) - with self.assertRaises(futures.CancelledError): + with self.assertRaises(asyncio.CancelledError): loop.run_until_complete(t) self.assertTrue(t.done()) self.assertTrue(t.cancelled()) self.assertFalse(t.cancel()) def test_cancel_yield(self): - @tasks.coroutine + @asyncio.coroutine def task(): yield yield return 12 - t = tasks.Task(task(), loop=self.loop) + t = asyncio.Task(task(), loop=self.loop) test_utils.run_briefly(self.loop) # start coro t.cancel() self.assertRaises( - futures.CancelledError, self.loop.run_until_complete, t) + asyncio.CancelledError, self.loop.run_until_complete, t) self.assertTrue(t.done()) self.assertTrue(t.cancelled()) self.assertFalse(t.cancel()) def test_cancel_inner_future(self): - f = futures.Future(loop=self.loop) + f = asyncio.Future(loop=self.loop) - @tasks.coroutine + @asyncio.coroutine def task(): yield from f return 12 - t = tasks.Task(task(), loop=self.loop) + t = asyncio.Task(task(), loop=self.loop) test_utils.run_briefly(self.loop) # start task f.cancel() - with self.assertRaises(futures.CancelledError): + with self.assertRaises(asyncio.CancelledError): self.loop.run_until_complete(t) self.assertTrue(f.cancelled()) self.assertTrue(t.cancelled()) def test_cancel_both_task_and_inner_future(self): - f = futures.Future(loop=self.loop) + f = asyncio.Future(loop=self.loop) - @tasks.coroutine + @asyncio.coroutine def task(): yield from f return 12 - t = tasks.Task(task(), loop=self.loop) + t = asyncio.Task(task(), loop=self.loop) test_utils.run_briefly(self.loop) f.cancel() t.cancel() - with self.assertRaises(futures.CancelledError): + with self.assertRaises(asyncio.CancelledError): self.loop.run_until_complete(t) self.assertTrue(t.done()) @@ -236,18 +234,18 @@ self.assertTrue(t.cancelled()) def test_cancel_task_catching(self): - fut1 = futures.Future(loop=self.loop) - fut2 = futures.Future(loop=self.loop) + fut1 = asyncio.Future(loop=self.loop) + fut2 = asyncio.Future(loop=self.loop) - @tasks.coroutine + @asyncio.coroutine def task(): yield from fut1 try: yield from fut2 - except futures.CancelledError: + except asyncio.CancelledError: return 42 - t = tasks.Task(task(), loop=self.loop) + t = asyncio.Task(task(), loop=self.loop) test_utils.run_briefly(self.loop) self.assertIs(t._fut_waiter, fut1) # White-box test. fut1.set_result(None) @@ -260,21 +258,21 @@ self.assertFalse(t.cancelled()) def test_cancel_task_ignoring(self): - fut1 = futures.Future(loop=self.loop) - fut2 = futures.Future(loop=self.loop) - fut3 = futures.Future(loop=self.loop) + fut1 = asyncio.Future(loop=self.loop) + fut2 = asyncio.Future(loop=self.loop) + fut3 = asyncio.Future(loop=self.loop) - @tasks.coroutine + @asyncio.coroutine def task(): yield from fut1 try: yield from fut2 - except futures.CancelledError: + except asyncio.CancelledError: pass res = yield from fut3 return res - t = tasks.Task(task(), loop=self.loop) + t = asyncio.Task(task(), loop=self.loop) test_utils.run_briefly(self.loop) self.assertIs(t._fut_waiter, fut1) # White-box test. fut1.set_result(None) @@ -291,20 +289,20 @@ self.assertFalse(t.cancelled()) def test_cancel_current_task(self): - loop = events.new_event_loop() + loop = asyncio.new_event_loop() self.addCleanup(loop.close) - @tasks.coroutine + @asyncio.coroutine def task(): t.cancel() self.assertTrue(t._must_cancel) # White-box test. # The sleep should be cancelled immediately. - yield from tasks.sleep(100, loop=loop) + yield from asyncio.sleep(100, loop=loop) return 12 - t = tasks.Task(task(), loop=loop) + t = asyncio.Task(task(), loop=loop) self.assertRaises( - futures.CancelledError, loop.run_until_complete, t) + asyncio.CancelledError, loop.run_until_complete, t) self.assertTrue(t.done()) self.assertFalse(t._must_cancel) # White-box test. self.assertFalse(t.cancel()) @@ -326,17 +324,17 @@ x = 0 waiters = [] - @tasks.coroutine + @asyncio.coroutine def task(): nonlocal x while x < 10: - waiters.append(tasks.sleep(0.1, loop=loop)) + waiters.append(asyncio.sleep(0.1, loop=loop)) yield from waiters[-1] x += 1 if x == 2: loop.stop() - t = tasks.Task(task(), loop=loop) + t = asyncio.Task(task(), loop=loop) self.assertRaises( RuntimeError, loop.run_until_complete, t) self.assertFalse(t.done()) @@ -361,20 +359,20 @@ foo_running = None - @tasks.coroutine + @asyncio.coroutine def foo(): nonlocal foo_running foo_running = True try: - yield from tasks.sleep(0.2, loop=loop) + yield from asyncio.sleep(0.2, loop=loop) finally: foo_running = False return 'done' - fut = tasks.Task(foo(), loop=loop) + fut = asyncio.Task(foo(), loop=loop) - with self.assertRaises(futures.TimeoutError): - loop.run_until_complete(tasks.wait_for(fut, 0.1, loop=loop)) + with self.assertRaises(asyncio.TimeoutError): + loop.run_until_complete(asyncio.wait_for(fut, 0.1, loop=loop)) self.assertTrue(fut.done()) # it should have been cancelled due to the timeout self.assertTrue(fut.cancelled()) @@ -394,18 +392,18 @@ loop = test_utils.TestLoop(gen) self.addCleanup(loop.close) - @tasks.coroutine + @asyncio.coroutine def foo(): - yield from tasks.sleep(0.2, loop=loop) + yield from asyncio.sleep(0.2, loop=loop) return 'done' - events.set_event_loop(loop) + asyncio.set_event_loop(loop) try: - fut = tasks.Task(foo(), loop=loop) - with self.assertRaises(futures.TimeoutError): - loop.run_until_complete(tasks.wait_for(fut, 0.01)) + fut = asyncio.Task(foo(), loop=loop) + with self.assertRaises(asyncio.TimeoutError): + loop.run_until_complete(asyncio.wait_for(fut, 0.01)) finally: - events.set_event_loop(None) + asyncio.set_event_loop(None) self.assertAlmostEqual(0.01, loop.time()) self.assertTrue(fut.done()) @@ -423,22 +421,22 @@ loop = test_utils.TestLoop(gen) self.addCleanup(loop.close) - a = tasks.Task(tasks.sleep(0.1, loop=loop), loop=loop) - b = tasks.Task(tasks.sleep(0.15, loop=loop), loop=loop) + a = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop) + b = asyncio.Task(asyncio.sleep(0.15, loop=loop), loop=loop) - @tasks.coroutine + @asyncio.coroutine def foo(): - done, pending = yield from tasks.wait([b, a], loop=loop) + done, pending = yield from asyncio.wait([b, a], loop=loop) self.assertEqual(done, set([a, b])) self.assertEqual(pending, set()) return 42 - res = loop.run_until_complete(tasks.Task(foo(), loop=loop)) + res = loop.run_until_complete(asyncio.Task(foo(), loop=loop)) 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(tasks.Task(foo(), loop=loop)) + res = loop.run_until_complete(asyncio.Task(foo(), loop=loop)) self.assertAlmostEqual(0.15, loop.time()) self.assertEqual(res, 42) @@ -454,33 +452,33 @@ loop = test_utils.TestLoop(gen) self.addCleanup(loop.close) - a = tasks.Task(tasks.sleep(0.01, loop=loop), loop=loop) - b = tasks.Task(tasks.sleep(0.015, loop=loop), loop=loop) + a = asyncio.Task(asyncio.sleep(0.01, loop=loop), loop=loop) + b = asyncio.Task(asyncio.sleep(0.015, loop=loop), loop=loop) - @tasks.coroutine + @asyncio.coroutine def foo(): - done, pending = yield from tasks.wait([b, a]) + done, pending = yield from asyncio.wait([b, a]) self.assertEqual(done, set([a, b])) self.assertEqual(pending, set()) return 42 - events.set_event_loop(loop) + asyncio.set_event_loop(loop) try: res = loop.run_until_complete( - tasks.Task(foo(), loop=loop)) + asyncio.Task(foo(), loop=loop)) finally: - events.set_event_loop(None) + asyncio.set_event_loop(None) self.assertEqual(res, 42) def test_wait_errors(self): self.assertRaises( ValueError, self.loop.run_until_complete, - tasks.wait(set(), loop=self.loop)) + asyncio.wait(set(), loop=self.loop)) self.assertRaises( ValueError, self.loop.run_until_complete, - tasks.wait([tasks.sleep(10.0, loop=self.loop)], + asyncio.wait([asyncio.sleep(10.0, loop=self.loop)], return_when=-1, loop=self.loop)) def test_wait_first_completed(self): @@ -495,10 +493,10 @@ loop = test_utils.TestLoop(gen) self.addCleanup(loop.close) - a = tasks.Task(tasks.sleep(10.0, loop=loop), loop=loop) - b = tasks.Task(tasks.sleep(0.1, loop=loop), loop=loop) - task = tasks.Task( - tasks.wait([b, a], return_when=tasks.FIRST_COMPLETED, + 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( + asyncio.wait([b, a], return_when=asyncio.FIRST_COMPLETED, loop=loop), loop=loop) @@ -512,25 +510,25 @@ # move forward to close generator loop.advance_time(10) - loop.run_until_complete(tasks.wait([a, b], loop=loop)) + loop.run_until_complete(asyncio.wait([a, b], loop=loop)) def test_wait_really_done(self): # there is possibility that some tasks in the pending list # became done but their callbacks haven't all been called yet - @tasks.coroutine + @asyncio.coroutine def coro1(): yield - @tasks.coroutine + @asyncio.coroutine def coro2(): yield yield - a = tasks.Task(coro1(), loop=self.loop) - b = tasks.Task(coro2(), loop=self.loop) - task = tasks.Task( - tasks.wait([b, a], return_when=tasks.FIRST_COMPLETED, + a = asyncio.Task(coro1(), loop=self.loop) + b = asyncio.Task(coro2(), loop=self.loop) + task = asyncio.Task( + asyncio.wait([b, a], return_when=asyncio.FIRST_COMPLETED, loop=self.loop), loop=self.loop) @@ -552,15 +550,15 @@ self.addCleanup(loop.close) # first_exception, task already has exception - a = tasks.Task(tasks.sleep(10.0, loop=loop), loop=loop) + a = asyncio.Task(asyncio.sleep(10.0, loop=loop), loop=loop) - @tasks.coroutine + @asyncio.coroutine def exc(): raise ZeroDivisionError('err') - b = tasks.Task(exc(), loop=loop) - task = tasks.Task( - tasks.wait([b, a], return_when=tasks.FIRST_EXCEPTION, + b = asyncio.Task(exc(), loop=loop) + task = asyncio.Task( + asyncio.wait([b, a], return_when=asyncio.FIRST_EXCEPTION, loop=loop), loop=loop) @@ -571,7 +569,7 @@ # move forward to close generator loop.advance_time(10) - loop.run_until_complete(tasks.wait([a, b], loop=loop)) + loop.run_until_complete(asyncio.wait([a, b], loop=loop)) def test_wait_first_exception_in_wait(self): @@ -586,15 +584,15 @@ self.addCleanup(loop.close) # first_exception, exception during waiting - a = tasks.Task(tasks.sleep(10.0, loop=loop), loop=loop) + a = asyncio.Task(asyncio.sleep(10.0, loop=loop), loop=loop) - @tasks.coroutine + @asyncio.coroutine def exc(): - yield from tasks.sleep(0.01, loop=loop) + yield from asyncio.sleep(0.01, loop=loop) raise ZeroDivisionError('err') - b = tasks.Task(exc(), loop=loop) - task = tasks.wait([b, a], return_when=tasks.FIRST_EXCEPTION, + b = asyncio.Task(exc(), loop=loop) + task = asyncio.wait([b, a], return_when=asyncio.FIRST_EXCEPTION, loop=loop) done, pending = loop.run_until_complete(task) @@ -604,7 +602,7 @@ # move forward to close generator loop.advance_time(10) - loop.run_until_complete(tasks.wait([a, b], loop=loop)) + loop.run_until_complete(asyncio.wait([a, b], loop=loop)) def test_wait_with_exception(self): @@ -618,27 +616,27 @@ loop = test_utils.TestLoop(gen) self.addCleanup(loop.close) - a = tasks.Task(tasks.sleep(0.1, loop=loop), loop=loop) + a = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop) - @tasks.coroutine + @asyncio.coroutine def sleeper(): - yield from tasks.sleep(0.15, loop=loop) + yield from asyncio.sleep(0.15, loop=loop) raise ZeroDivisionError('really') - b = tasks.Task(sleeper(), loop=loop) + b = asyncio.Task(sleeper(), loop=loop) - @tasks.coroutine + @asyncio.coroutine def foo(): - done, pending = yield from tasks.wait([b, a], loop=loop) + done, pending = yield from asyncio.wait([b, a], loop=loop) self.assertEqual(len(done), 2) self.assertEqual(pending, set()) errors = set(f for f in done if f.exception() is not None) self.assertEqual(len(errors), 1) - loop.run_until_complete(tasks.Task(foo(), loop=loop)) + loop.run_until_complete(asyncio.Task(foo(), loop=loop)) self.assertAlmostEqual(0.15, loop.time()) - loop.run_until_complete(tasks.Task(foo(), loop=loop)) + loop.run_until_complete(asyncio.Task(foo(), loop=loop)) self.assertAlmostEqual(0.15, loop.time()) def test_wait_with_timeout(self): @@ -655,22 +653,22 @@ loop = test_utils.TestLoop(gen) self.addCleanup(loop.close) - a = tasks.Task(tasks.sleep(0.1, loop=loop), loop=loop) - b = tasks.Task(tasks.sleep(0.15, loop=loop), loop=loop) + a = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop) + b = asyncio.Task(asyncio.sleep(0.15, loop=loop), loop=loop) - @tasks.coroutine + @asyncio.coroutine def foo(): - done, pending = yield from tasks.wait([b, a], timeout=0.11, + done, pending = yield from asyncio.wait([b, a], timeout=0.11, loop=loop) self.assertEqual(done, set([a])) self.assertEqual(pending, set([b])) - loop.run_until_complete(tasks.Task(foo(), loop=loop)) + loop.run_until_complete(asyncio.Task(foo(), loop=loop)) self.assertAlmostEqual(0.11, loop.time()) # move forward to close generator loop.advance_time(10) - loop.run_until_complete(tasks.wait([a, b], loop=loop)) + loop.run_until_complete(asyncio.wait([a, b], loop=loop)) def test_wait_concurrent_complete(self): @@ -686,11 +684,11 @@ loop = test_utils.TestLoop(gen) self.addCleanup(loop.close) - a = tasks.Task(tasks.sleep(0.1, loop=loop), loop=loop) - b = tasks.Task(tasks.sleep(0.15, loop=loop), loop=loop) + a = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop) + b = asyncio.Task(asyncio.sleep(0.15, loop=loop), loop=loop) done, pending = loop.run_until_complete( - tasks.wait([b, a], timeout=0.1, loop=loop)) + asyncio.wait([b, a], timeout=0.1, loop=loop)) self.assertEqual(done, set([a])) self.assertEqual(pending, set([b])) @@ -698,7 +696,7 @@ # move forward to close generator loop.advance_time(10) - loop.run_until_complete(tasks.wait([a, b], loop=loop)) + loop.run_until_complete(asyncio.wait([a, b], loop=loop)) def test_as_completed(self): @@ -713,10 +711,10 @@ completed = set() time_shifted = False - @tasks.coroutine + @asyncio.coroutine def sleeper(dt, x): nonlocal time_shifted - yield from tasks.sleep(dt, loop=loop) + yield from asyncio.sleep(dt, loop=loop) completed.add(x) if not time_shifted and 'a' in completed and 'b' in completed: time_shifted = True @@ -727,21 +725,21 @@ b = sleeper(0.01, 'b') c = sleeper(0.15, 'c') - @tasks.coroutine + @asyncio.coroutine def foo(): values = [] - for f in tasks.as_completed([b, c, a], loop=loop): + for f in asyncio.as_completed([b, c, a], loop=loop): values.append((yield from f)) return values - res = loop.run_until_complete(tasks.Task(foo(), loop=loop)) + res = loop.run_until_complete(asyncio.Task(foo(), loop=loop)) 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(tasks.Task(foo(), loop=loop)) + res = loop.run_until_complete(asyncio.Task(foo(), loop=loop)) self.assertAlmostEqual(0.15, loop.time()) def test_as_completed_with_timeout(self): @@ -760,30 +758,30 @@ loop = test_utils.TestLoop(gen) self.addCleanup(loop.close) - a = tasks.sleep(0.1, 'a', loop=loop) - b = tasks.sleep(0.15, 'b', loop=loop) + a = asyncio.sleep(0.1, 'a', loop=loop) + b = asyncio.sleep(0.15, 'b', loop=loop) - @tasks.coroutine + @asyncio.coroutine def foo(): values = [] - for f in tasks.as_completed([a, b], timeout=0.12, loop=loop): + for f in asyncio.as_completed([a, b], timeout=0.12, loop=loop): try: v = yield from f values.append((1, v)) - except futures.TimeoutError as exc: + except asyncio.TimeoutError as exc: values.append((2, exc)) return values - res = loop.run_until_complete(tasks.Task(foo(), loop=loop)) + res = loop.run_until_complete(asyncio.Task(foo(), loop=loop)) self.assertEqual(len(res), 2, res) self.assertEqual(res[0], (1, 'a')) self.assertEqual(res[1][0], 2) - self.assertIsInstance(res[1][1], futures.TimeoutError) + self.assertIsInstance(res[1][1], asyncio.TimeoutError) self.assertAlmostEqual(0.12, loop.time()) # move forward to close generator loop.advance_time(10) - loop.run_until_complete(tasks.wait([a, b], loop=loop)) + loop.run_until_complete(asyncio.wait([a, b], loop=loop)) def test_as_completed_reverse_wait(self): @@ -795,10 +793,10 @@ loop = test_utils.TestLoop(gen) self.addCleanup(loop.close) - a = tasks.sleep(0.05, 'a', loop=loop) - b = tasks.sleep(0.10, 'b', loop=loop) + a = asyncio.sleep(0.05, 'a', loop=loop) + b = asyncio.sleep(0.10, 'b', loop=loop) fs = {a, b} - futs = list(tasks.as_completed(fs, loop=loop)) + futs = list(asyncio.as_completed(fs, loop=loop)) self.assertEqual(len(futs), 2) x = loop.run_until_complete(futs[1]) @@ -821,12 +819,12 @@ loop = test_utils.TestLoop(gen) self.addCleanup(loop.close) - a = tasks.sleep(0.05, 'a', loop=loop) - b = tasks.sleep(0.05, 'b', loop=loop) + a = asyncio.sleep(0.05, 'a', loop=loop) + b = asyncio.sleep(0.05, 'b', loop=loop) fs = {a, b} - futs = list(tasks.as_completed(fs, loop=loop)) + futs = list(asyncio.as_completed(fs, loop=loop)) self.assertEqual(len(futs), 2) - waiter = tasks.wait(futs, loop=loop) + waiter = asyncio.wait(futs, loop=loop) done, pending = loop.run_until_complete(waiter) self.assertEqual(set(f.result() for f in done), {'a', 'b'}) @@ -842,13 +840,13 @@ loop = test_utils.TestLoop(gen) self.addCleanup(loop.close) - @tasks.coroutine + @asyncio.coroutine def sleeper(dt, arg): - yield from tasks.sleep(dt/2, loop=loop) - res = yield from tasks.sleep(dt/2, arg, loop=loop) + yield from asyncio.sleep(dt/2, loop=loop) + res = yield from asyncio.sleep(dt/2, arg, loop=loop) return res - t = tasks.Task(sleeper(0.1, 'yeah'), loop=loop) + t = asyncio.Task(sleeper(0.1, 'yeah'), loop=loop) loop.run_until_complete(t) self.assertTrue(t.done()) self.assertEqual(t.result(), 'yeah') @@ -864,7 +862,7 @@ loop = test_utils.TestLoop(gen) self.addCleanup(loop.close) - t = tasks.Task(tasks.sleep(10.0, 'yeah', loop=loop), + t = asyncio.Task(asyncio.sleep(10.0, 'yeah', loop=loop), loop=loop) handle = None @@ -898,19 +896,19 @@ sleepfut = None - @tasks.coroutine + @asyncio.coroutine def sleep(dt): nonlocal sleepfut - sleepfut = tasks.sleep(dt, loop=loop) + sleepfut = asyncio.sleep(dt, loop=loop) yield from sleepfut - @tasks.coroutine + @asyncio.coroutine def doit(): - sleeper = tasks.Task(sleep(5000), loop=loop) + sleeper = asyncio.Task(sleep(5000), loop=loop) loop.call_later(0.1, sleeper.cancel) try: yield from sleeper - except futures.CancelledError: + except asyncio.CancelledError: return 'cancelled' else: return 'slept in' @@ -920,37 +918,37 @@ self.assertAlmostEqual(0.1, loop.time()) def test_task_cancel_waiter_future(self): - fut = futures.Future(loop=self.loop) + fut = asyncio.Future(loop=self.loop) - @tasks.coroutine + @asyncio.coroutine def coro(): yield from fut - task = tasks.Task(coro(), loop=self.loop) + task = asyncio.Task(coro(), loop=self.loop) test_utils.run_briefly(self.loop) self.assertIs(task._fut_waiter, fut) task.cancel() test_utils.run_briefly(self.loop) self.assertRaises( - futures.CancelledError, self.loop.run_until_complete, task) + asyncio.CancelledError, self.loop.run_until_complete, task) self.assertIsNone(task._fut_waiter) self.assertTrue(fut.cancelled()) def test_step_in_completed_task(self): - @tasks.coroutine + @asyncio.coroutine def notmuch(): return 'ko' gen = notmuch() - task = tasks.Task(gen, loop=self.loop) + task = asyncio.Task(gen, loop=self.loop) task.set_result('ok') self.assertRaises(AssertionError, task._step) gen.close() def test_step_result(self): - @tasks.coroutine + @asyncio.coroutine def notmuch(): yield None yield 1 @@ -962,7 +960,7 @@ def test_step_result_future(self): # If coroutine returns future, task waits on this future. - class Fut(futures.Future): + class Fut(asyncio.Future): def __init__(self, *args, **kwds): self.cb_added = False super().__init__(*args, **kwds) @@ -974,12 +972,12 @@ fut = Fut(loop=self.loop) result = None - @tasks.coroutine + @asyncio.coroutine def wait_for_future(): nonlocal result result = yield from fut - t = tasks.Task(wait_for_future(), loop=self.loop) + t = asyncio.Task(wait_for_future(), loop=self.loop) test_utils.run_briefly(self.loop) self.assertTrue(fut.cb_added) @@ -991,11 +989,11 @@ self.assertIsNone(t.result()) def test_step_with_baseexception(self): - @tasks.coroutine + @asyncio.coroutine def notmutch(): raise BaseException() - task = tasks.Task(notmutch(), loop=self.loop) + task = asyncio.Task(notmutch(), loop=self.loop) self.assertRaises(BaseException, task._step) self.assertTrue(task.done()) @@ -1011,20 +1009,20 @@ loop = test_utils.TestLoop(gen) self.addCleanup(loop.close) - @tasks.coroutine + @asyncio.coroutine def sleeper(): - yield from tasks.sleep(10, loop=loop) + yield from asyncio.sleep(10, loop=loop) base_exc = BaseException() - @tasks.coroutine + @asyncio.coroutine def notmutch(): try: yield from sleeper() - except futures.CancelledError: + except asyncio.CancelledError: raise base_exc - task = tasks.Task(notmutch(), loop=loop) + task = asyncio.Task(notmutch(), loop=loop) test_utils.run_briefly(loop) task.cancel() @@ -1040,21 +1038,21 @@ def fn(): pass - self.assertFalse(tasks.iscoroutinefunction(fn)) + self.assertFalse(asyncio.iscoroutinefunction(fn)) def fn1(): yield - self.assertFalse(tasks.iscoroutinefunction(fn1)) + self.assertFalse(asyncio.iscoroutinefunction(fn1)) - @tasks.coroutine + @asyncio.coroutine def fn2(): yield - self.assertTrue(tasks.iscoroutinefunction(fn2)) + self.assertTrue(asyncio.iscoroutinefunction(fn2)) def test_yield_vs_yield_from(self): - fut = futures.Future(loop=self.loop) + fut = asyncio.Future(loop=self.loop) - @tasks.coroutine + @asyncio.coroutine def wait_for_future(): yield fut @@ -1065,11 +1063,11 @@ self.assertFalse(fut.done()) def test_yield_vs_yield_from_generator(self): - @tasks.coroutine + @asyncio.coroutine def coro(): yield - @tasks.coroutine + @asyncio.coroutine def wait_for_future(): gen = coro() try: @@ -1083,72 +1081,72 @@ self.loop.run_until_complete, task) def test_coroutine_non_gen_function(self): - @tasks.coroutine + @asyncio.coroutine def func(): return 'test' - self.assertTrue(tasks.iscoroutinefunction(func)) + self.assertTrue(asyncio.iscoroutinefunction(func)) coro = func() - self.assertTrue(tasks.iscoroutine(coro)) + self.assertTrue(asyncio.iscoroutine(coro)) res = self.loop.run_until_complete(coro) self.assertEqual(res, 'test') def test_coroutine_non_gen_function_return_future(self): - fut = futures.Future(loop=self.loop) + fut = asyncio.Future(loop=self.loop) - @tasks.coroutine + @asyncio.coroutine def func(): return fut - @tasks.coroutine + @asyncio.coroutine def coro(): fut.set_result('test') - t1 = tasks.Task(func(), loop=self.loop) - t2 = tasks.Task(coro(), loop=self.loop) + t1 = asyncio.Task(func(), loop=self.loop) + t2 = asyncio.Task(coro(), loop=self.loop) res = self.loop.run_until_complete(t1) self.assertEqual(res, 'test') self.assertIsNone(t2.result()) def test_current_task(self): - self.assertIsNone(tasks.Task.current_task(loop=self.loop)) + self.assertIsNone(asyncio.Task.current_task(loop=self.loop)) - @tasks.coroutine + @asyncio.coroutine def coro(loop): - self.assertTrue(tasks.Task.current_task(loop=loop) is task) + self.assertTrue(asyncio.Task.current_task(loop=loop) is task) - task = tasks.Task(coro(self.loop), loop=self.loop) + task = asyncio.Task(coro(self.loop), loop=self.loop) self.loop.run_until_complete(task) - self.assertIsNone(tasks.Task.current_task(loop=self.loop)) + self.assertIsNone(asyncio.Task.current_task(loop=self.loop)) def test_current_task_with_interleaving_tasks(self): - self.assertIsNone(tasks.Task.current_task(loop=self.loop)) + self.assertIsNone(asyncio.Task.current_task(loop=self.loop)) - fut1 = futures.Future(loop=self.loop) - fut2 = futures.Future(loop=self.loop) + fut1 = asyncio.Future(loop=self.loop) + fut2 = asyncio.Future(loop=self.loop) - @tasks.coroutine + @asyncio.coroutine def coro1(loop): - self.assertTrue(tasks.Task.current_task(loop=loop) is task1) + self.assertTrue(asyncio.Task.current_task(loop=loop) is task1) yield from fut1 - self.assertTrue(tasks.Task.current_task(loop=loop) is task1) + self.assertTrue(asyncio.Task.current_task(loop=loop) is task1) fut2.set_result(True) - @tasks.coroutine + @asyncio.coroutine def coro2(loop): - self.assertTrue(tasks.Task.current_task(loop=loop) is task2) + self.assertTrue(asyncio.Task.current_task(loop=loop) is task2) fut1.set_result(True) yield from fut2 - self.assertTrue(tasks.Task.current_task(loop=loop) is task2) + self.assertTrue(asyncio.Task.current_task(loop=loop) is task2) - task1 = tasks.Task(coro1(self.loop), loop=self.loop) - task2 = tasks.Task(coro2(self.loop), loop=self.loop) + task1 = asyncio.Task(coro1(self.loop), loop=self.loop) + task2 = asyncio.Task(coro2(self.loop), loop=self.loop) - self.loop.run_until_complete(tasks.wait((task1, task2), + self.loop.run_until_complete(asyncio.wait((task1, task2), loop=self.loop)) - self.assertIsNone(tasks.Task.current_task(loop=self.loop)) + self.assertIsNone(asyncio.Task.current_task(loop=self.loop)) # Some thorough tests for cancellation propagation through # coroutines, tasks and wait(). @@ -1156,30 +1154,30 @@ def test_yield_future_passes_cancel(self): # Cancelling outer() cancels inner() cancels waiter. proof = 0 - waiter = futures.Future(loop=self.loop) + waiter = asyncio.Future(loop=self.loop) - @tasks.coroutine + @asyncio.coroutine def inner(): nonlocal proof try: yield from waiter - except futures.CancelledError: + except asyncio.CancelledError: proof += 1 raise else: self.fail('got past sleep() in inner()') - @tasks.coroutine + @asyncio.coroutine def outer(): nonlocal proof try: yield from inner() - except futures.CancelledError: + except asyncio.CancelledError: proof += 100 # Expect this path. else: proof += 10 - f = tasks.async(outer(), loop=self.loop) + f = asyncio.async(outer(), loop=self.loop) test_utils.run_briefly(self.loop) f.cancel() self.loop.run_until_complete(f) @@ -1190,39 +1188,39 @@ # Cancelling outer() makes wait() return early, leaves inner() # running. proof = 0 - waiter = futures.Future(loop=self.loop) + waiter = asyncio.Future(loop=self.loop) - @tasks.coroutine + @asyncio.coroutine def inner(): nonlocal proof yield from waiter proof += 1 - @tasks.coroutine + @asyncio.coroutine def outer(): nonlocal proof - d, p = yield from tasks.wait([inner()], loop=self.loop) + d, p = yield from asyncio.wait([inner()], loop=self.loop) proof += 100 - f = tasks.async(outer(), loop=self.loop) + f = asyncio.async(outer(), loop=self.loop) test_utils.run_briefly(self.loop) f.cancel() self.assertRaises( - futures.CancelledError, self.loop.run_until_complete, f) + asyncio.CancelledError, self.loop.run_until_complete, f) waiter.set_result(None) test_utils.run_briefly(self.loop) self.assertEqual(proof, 1) def test_shield_result(self): - inner = futures.Future(loop=self.loop) - outer = tasks.shield(inner) + inner = asyncio.Future(loop=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 = futures.Future(loop=self.loop) - outer = tasks.shield(inner) + inner = asyncio.Future(loop=self.loop) + outer = asyncio.shield(inner) test_utils.run_briefly(self.loop) exc = RuntimeError('expected') inner.set_exception(exc) @@ -1230,50 +1228,50 @@ self.assertIs(outer.exception(), exc) def test_shield_cancel(self): - inner = futures.Future(loop=self.loop) - outer = tasks.shield(inner) + inner = asyncio.Future(loop=self.loop) + outer = asyncio.shield(inner) test_utils.run_briefly(self.loop) inner.cancel() test_utils.run_briefly(self.loop) self.assertTrue(outer.cancelled()) def test_shield_shortcut(self): - fut = futures.Future(loop=self.loop) + fut = asyncio.Future(loop=self.loop) fut.set_result(42) - res = self.loop.run_until_complete(tasks.shield(fut)) + res = self.loop.run_until_complete(asyncio.shield(fut)) self.assertEqual(res, 42) def test_shield_effect(self): # Cancelling outer() does not affect inner(). proof = 0 - waiter = futures.Future(loop=self.loop) + waiter = asyncio.Future(loop=self.loop) - @tasks.coroutine + @asyncio.coroutine def inner(): nonlocal proof yield from waiter proof += 1 - @tasks.coroutine + @asyncio.coroutine def outer(): nonlocal proof - yield from tasks.shield(inner(), loop=self.loop) + yield from asyncio.shield(inner(), loop=self.loop) proof += 100 - f = tasks.async(outer(), loop=self.loop) + f = asyncio.async(outer(), loop=self.loop) test_utils.run_briefly(self.loop) f.cancel() - with self.assertRaises(futures.CancelledError): + with self.assertRaises(asyncio.CancelledError): self.loop.run_until_complete(f) waiter.set_result(None) test_utils.run_briefly(self.loop) self.assertEqual(proof, 1) def test_shield_gather(self): - child1 = futures.Future(loop=self.loop) - child2 = futures.Future(loop=self.loop) - parent = tasks.gather(child1, child2, loop=self.loop) - outer = tasks.shield(parent, loop=self.loop) + child1 = asyncio.Future(loop=self.loop) + child2 = asyncio.Future(loop=self.loop) + parent = asyncio.gather(child1, child2, loop=self.loop) + outer = asyncio.shield(parent, loop=self.loop) test_utils.run_briefly(self.loop) outer.cancel() test_utils.run_briefly(self.loop) @@ -1284,16 +1282,16 @@ self.assertEqual(parent.result(), [1, 2]) def test_gather_shield(self): - child1 = futures.Future(loop=self.loop) - child2 = futures.Future(loop=self.loop) - inner1 = tasks.shield(child1, loop=self.loop) - inner2 = tasks.shield(child2, loop=self.loop) - parent = tasks.gather(inner1, inner2, loop=self.loop) + child1 = asyncio.Future(loop=self.loop) + child2 = asyncio.Future(loop=self.loop) + inner1 = asyncio.shield(child1, loop=self.loop) + inner2 = asyncio.shield(child2, loop=self.loop) + parent = asyncio.gather(inner1, inner2, loop=self.loop) test_utils.run_briefly(self.loop) parent.cancel() # This should cancel inner1 and inner2 but bot child1 and child2. test_utils.run_briefly(self.loop) - self.assertIsInstance(parent.exception(), futures.CancelledError) + self.assertIsInstance(parent.exception(), asyncio.CancelledError) self.assertTrue(inner1.cancelled()) self.assertTrue(inner2.cancelled()) child1.set_result(1) @@ -1316,8 +1314,8 @@ test_utils.run_briefly(loop) def _check_success(self, **kwargs): - a, b, c = [futures.Future(loop=self.one_loop) for i in range(3)] - fut = tasks.gather(*self.wrap_futures(a, b, c), **kwargs) + a, b, c = [asyncio.Future(loop=self.one_loop) for i in range(3)] + fut = asyncio.gather(*self.wrap_futures(a, b, c), **kwargs) cb = Mock() fut.add_done_callback(cb) b.set_result(1) @@ -1338,8 +1336,8 @@ self._check_success(return_exceptions=True) def test_one_exception(self): - a, b, c, d, e = [futures.Future(loop=self.one_loop) for i in range(5)] - fut = tasks.gather(*self.wrap_futures(a, b, c, d, e)) + a, b, c, d, e = [asyncio.Future(loop=self.one_loop) for i in range(5)] + fut = asyncio.gather(*self.wrap_futures(a, b, c, d, e)) cb = Mock() fut.add_done_callback(cb) exc = ZeroDivisionError() @@ -1356,8 +1354,8 @@ e.exception() def test_return_exceptions(self): - a, b, c, d = [futures.Future(loop=self.one_loop) for i in range(4)] - fut = tasks.gather(*self.wrap_futures(a, b, c, d), + a, b, c, d = [asyncio.Future(loop=self.one_loop) for i in range(4)] + fut = asyncio.gather(*self.wrap_futures(a, b, c, d), return_exceptions=True) cb = Mock() fut.add_done_callback(cb) @@ -1381,15 +1379,15 @@ return futures def _check_empty_sequence(self, seq_or_iter): - events.set_event_loop(self.one_loop) - self.addCleanup(events.set_event_loop, None) - fut = tasks.gather(*seq_or_iter) - self.assertIsInstance(fut, futures.Future) + asyncio.set_event_loop(self.one_loop) + self.addCleanup(asyncio.set_event_loop, None) + fut = asyncio.gather(*seq_or_iter) + self.assertIsInstance(fut, asyncio.Future) self.assertIs(fut._loop, self.one_loop) self._run_loop(self.one_loop) self.assertTrue(fut.done()) self.assertEqual(fut.result(), []) - fut = tasks.gather(*seq_or_iter, loop=self.other_loop) + fut = asyncio.gather(*seq_or_iter, loop=self.other_loop) self.assertIs(fut._loop, self.other_loop) def test_constructor_empty_sequence(self): @@ -1399,27 +1397,27 @@ self._check_empty_sequence(iter("")) def test_constructor_heterogenous_futures(self): - fut1 = futures.Future(loop=self.one_loop) - fut2 = futures.Future(loop=self.other_loop) + fut1 = asyncio.Future(loop=self.one_loop) + fut2 = asyncio.Future(loop=self.other_loop) with self.assertRaises(ValueError): - tasks.gather(fut1, fut2) + asyncio.gather(fut1, fut2) with self.assertRaises(ValueError): - tasks.gather(fut1, loop=self.other_loop) + asyncio.gather(fut1, loop=self.other_loop) def test_constructor_homogenous_futures(self): - children = [futures.Future(loop=self.other_loop) for i in range(3)] - fut = tasks.gather(*children) + children = [asyncio.Future(loop=self.other_loop) for i in range(3)] + fut = asyncio.gather(*children) self.assertIs(fut._loop, self.other_loop) self._run_loop(self.other_loop) self.assertFalse(fut.done()) - fut = tasks.gather(*children, loop=self.other_loop) + fut = asyncio.gather(*children, loop=self.other_loop) self.assertIs(fut._loop, self.other_loop) self._run_loop(self.other_loop) self.assertFalse(fut.done()) def test_one_cancellation(self): - a, b, c, d, e = [futures.Future(loop=self.one_loop) for i in range(5)] - fut = tasks.gather(a, b, c, d, e) + a, b, c, d, e = [asyncio.Future(loop=self.one_loop) for i in range(5)] + fut = asyncio.gather(a, b, c, d, e) cb = Mock() fut.add_done_callback(cb) a.set_result(1) @@ -1428,7 +1426,7 @@ self.assertTrue(fut.done()) cb.assert_called_once_with(fut) self.assertFalse(fut.cancelled()) - self.assertIsInstance(fut.exception(), futures.CancelledError) + self.assertIsInstance(fut.exception(), asyncio.CancelledError) # Does nothing c.set_result(3) d.cancel() @@ -1436,9 +1434,9 @@ e.exception() def test_result_exception_one_cancellation(self): - a, b, c, d, e, f = [futures.Future(loop=self.one_loop) + a, b, c, d, e, f = [asyncio.Future(loop=self.one_loop) for i in range(6)] - fut = tasks.gather(a, b, c, d, e, f, return_exceptions=True) + fut = asyncio.gather(a, b, c, d, e, f, return_exceptions=True) cb = Mock() fut.add_done_callback(cb) a.set_result(1) @@ -1452,8 +1450,8 @@ rte = RuntimeError() f.set_exception(rte) res = self.one_loop.run_until_complete(fut) - self.assertIsInstance(res[2], futures.CancelledError) - self.assertIsInstance(res[4], futures.CancelledError) + self.assertIsInstance(res[2], asyncio.CancelledError) + self.assertIsInstance(res[4], asyncio.CancelledError) res[2] = res[4] = None self.assertEqual(res, [1, zde, None, 3, None, rte]) cb.assert_called_once_with(fut) @@ -1463,34 +1461,34 @@ def setUp(self): super().setUp() - events.set_event_loop(self.one_loop) + asyncio.set_event_loop(self.one_loop) def tearDown(self): - events.set_event_loop(None) + asyncio.set_event_loop(None) super().tearDown() def wrap_futures(self, *futures): coros = [] for fut in futures: - @tasks.coroutine + @asyncio.coroutine def coro(fut=fut): return (yield from fut) coros.append(coro()) return coros def test_constructor_loop_selection(self): - @tasks.coroutine + @asyncio.coroutine def coro(): return 'abc' gen1 = coro() gen2 = coro() - fut = tasks.gather(gen1, gen2) + fut = asyncio.gather(gen1, gen2) self.assertIs(fut._loop, self.one_loop) gen1.close() gen2.close() gen3 = coro() gen4 = coro() - fut = tasks.gather(gen3, gen4, loop=self.other_loop) + fut = asyncio.gather(gen3, gen4, loop=self.other_loop) self.assertIs(fut._loop, self.other_loop) gen3.close() gen4.close() @@ -1498,29 +1496,29 @@ def test_cancellation_broadcast(self): # Cancelling outer() cancels all children. proof = 0 - waiter = futures.Future(loop=self.one_loop) + waiter = asyncio.Future(loop=self.one_loop) - @tasks.coroutine + @asyncio.coroutine def inner(): nonlocal proof yield from waiter proof += 1 - child1 = tasks.async(inner(), loop=self.one_loop) - child2 = tasks.async(inner(), loop=self.one_loop) + child1 = asyncio.async(inner(), loop=self.one_loop) + child2 = asyncio.async(inner(), loop=self.one_loop) gatherer = None - @tasks.coroutine + @asyncio.coroutine def outer(): nonlocal proof, gatherer - gatherer = tasks.gather(child1, child2, loop=self.one_loop) + gatherer = asyncio.gather(child1, child2, loop=self.one_loop) yield from gatherer proof += 100 - f = tasks.async(outer(), loop=self.one_loop) + f = asyncio.async(outer(), loop=self.one_loop) test_utils.run_briefly(self.one_loop) self.assertTrue(f.cancel()) - with self.assertRaises(futures.CancelledError): + with self.assertRaises(asyncio.CancelledError): self.one_loop.run_until_complete(f) self.assertFalse(gatherer.cancel()) self.assertTrue(waiter.cancelled()) @@ -1532,19 +1530,19 @@ def test_exception_marking(self): # Test for the first line marked "Mark exception retrieved." - @tasks.coroutine + @asyncio.coroutine def inner(f): yield from f raise RuntimeError('should not be ignored') - a = futures.Future(loop=self.one_loop) - b = futures.Future(loop=self.one_loop) + a = asyncio.Future(loop=self.one_loop) + b = asyncio.Future(loop=self.one_loop) - @tasks.coroutine + @asyncio.coroutine def outer(): - yield from tasks.gather(inner(a), inner(b), loop=self.one_loop) + yield from asyncio.gather(inner(a), inner(b), loop=self.one_loop) - f = tasks.async(outer(), loop=self.one_loop) + f = asyncio.async(outer(), loop=self.one_loop) test_utils.run_briefly(self.one_loop) a.set_result(None) test_utils.run_briefly(self.one_loop) diff --git a/Lib/test/test_asyncio/test_transports.py b/Lib/test/test_asyncio/test_transports.py --- a/Lib/test/test_asyncio/test_transports.py +++ b/Lib/test/test_asyncio/test_transports.py @@ -3,17 +3,17 @@ import unittest import unittest.mock -from asyncio import transports +import asyncio class TransportTests(unittest.TestCase): def test_ctor_extra_is_none(self): - transport = transports.Transport() + transport = asyncio.Transport() self.assertEqual(transport._extra, {}) def test_get_extra_info(self): - transport = transports.Transport({'extra': 'info'}) + transport = asyncio.Transport({'extra': 'info'}) self.assertEqual('info', transport.get_extra_info('extra')) self.assertIsNone(transport.get_extra_info('unknown')) @@ -21,7 +21,7 @@ self.assertIs(default, transport.get_extra_info('unknown', default)) def test_writelines(self): - transport = transports.Transport() + transport = asyncio.Transport() transport.write = unittest.mock.Mock() transport.writelines([b'line1', @@ -31,7 +31,7 @@ transport.write.assert_called_with(b'line1line2line3') def test_not_implemented(self): - transport = transports.Transport() + transport = asyncio.Transport() self.assertRaises(NotImplementedError, transport.set_write_buffer_limits) @@ -45,13 +45,13 @@ self.assertRaises(NotImplementedError, transport.abort) def test_dgram_not_implemented(self): - transport = transports.DatagramTransport() + transport = asyncio.DatagramTransport() self.assertRaises(NotImplementedError, transport.sendto, 'data') self.assertRaises(NotImplementedError, transport.abort) def test_subprocess_transport_not_implemented(self): - transport = transports.SubprocessTransport() + transport = asyncio.SubprocessTransport() self.assertRaises(NotImplementedError, transport.get_pid) self.assertRaises(NotImplementedError, transport.get_returncode) 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 @@ -17,9 +17,8 @@ raise unittest.SkipTest('UNIX only') -from asyncio import events -from asyncio import futures -from asyncio import protocols +import asyncio +from asyncio import log from asyncio import test_utils from asyncio import unix_events @@ -28,8 +27,8 @@ class SelectorEventLoopTests(unittest.TestCase): def setUp(self): - self.loop = unix_events.SelectorEventLoop() - events.set_event_loop(None) + self.loop = asyncio.SelectorEventLoop() + asyncio.set_event_loop(None) def tearDown(self): self.loop.close() @@ -44,7 +43,7 @@ self.loop._handle_signal(signal.NSIG + 1, ()) def test_handle_signal_cancelled_handler(self): - h = events.Handle(unittest.mock.Mock(), ()) + h = asyncio.Handle(unittest.mock.Mock(), ()) h.cancel() self.loop._signal_handlers[signal.NSIG + 1] = h self.loop.remove_signal_handler = unittest.mock.Mock() @@ -68,7 +67,7 @@ cb = lambda: True self.loop.add_signal_handler(signal.SIGHUP, cb) h = self.loop._signal_handlers.get(signal.SIGHUP) - self.assertIsInstance(h, events.Handle) + self.assertIsInstance(h, asyncio.Handle) self.assertEqual(h._callback, cb) @unittest.mock.patch('asyncio.unix_events.signal') @@ -205,7 +204,7 @@ def setUp(self): self.loop = test_utils.TestLoop() - self.protocol = test_utils.make_test_protocol(protocols.Protocol) + self.protocol = test_utils.make_test_protocol(asyncio.Protocol) self.pipe = unittest.mock.Mock(spec_set=io.RawIOBase) self.pipe.fileno.return_value = 5 @@ -228,7 +227,7 @@ self.protocol.connection_made.assert_called_with(tr) def test_ctor_with_waiter(self): - fut = futures.Future(loop=self.loop) + fut = asyncio.Future(loop=self.loop) unix_events._UnixReadPipeTransport( self.loop, self.pipe, self.protocol, fut) test_utils.run_briefly(self.loop) @@ -368,7 +367,7 @@ def setUp(self): self.loop = test_utils.TestLoop() - self.protocol = test_utils.make_test_protocol(protocols.BaseProtocol) + self.protocol = test_utils.make_test_protocol(asyncio.BaseProtocol) self.pipe = unittest.mock.Mock(spec_set=io.RawIOBase) self.pipe.fileno.return_value = 5 @@ -391,7 +390,7 @@ self.protocol.connection_made.assert_called_with(tr) def test_ctor_with_waiter(self): - fut = futures.Future(loop=self.loop) + fut = asyncio.Future(loop=self.loop) tr = unix_events._UnixWritePipeTransport( self.loop, self.pipe, self.protocol, fut) self.loop.assert_reader(5, tr._read_ready) @@ -682,7 +681,7 @@ def test_not_implemented(self): f = unittest.mock.Mock() - watcher = unix_events.AbstractChildWatcher() + watcher = asyncio.AbstractChildWatcher() self.assertRaises( NotImplementedError, watcher.add_child_handler, f, f) self.assertRaises( @@ -717,7 +716,7 @@ class ChildWatcherTestsMixin: - ignore_warnings = unittest.mock.patch.object(unix_events.logger, "warning") + ignore_warnings = unittest.mock.patch.object(log.logger, "warning") def setUp(self): self.loop = test_utils.TestLoop() @@ -730,7 +729,7 @@ self.watcher.attach_loop(self.loop) def waitpid(self, pid, flags): - if isinstance(self.watcher, unix_events.SafeChildWatcher) or pid != -1: + if isinstance(self.watcher, asyncio.SafeChildWatcher) or pid != -1: self.assertGreater(pid, 0) try: if pid < 0: @@ -1205,7 +1204,7 @@ # raise an exception m.waitpid.side_effect = ValueError - with unittest.mock.patch.object(unix_events.logger, + with unittest.mock.patch.object(log.logger, "exception") as m_exception: self.assertEqual(self.watcher._sig_chld(), None) @@ -1240,7 +1239,7 @@ self.watcher._sig_chld() callback.assert_called(m.waitpid) - if isinstance(self.watcher, unix_events.FastChildWatcher): + if isinstance(self.watcher, asyncio.FastChildWatcher): # here the FastChildWatche enters a deadlock # (there is no way to prevent it) self.assertFalse(callback.called) @@ -1380,7 +1379,7 @@ self.watcher.add_child_handler(64, callback1) self.assertEqual(len(self.watcher._callbacks), 1) - if isinstance(self.watcher, unix_events.FastChildWatcher): + if isinstance(self.watcher, asyncio.FastChildWatcher): self.assertEqual(len(self.watcher._zombies), 1) with unittest.mock.patch.object( @@ -1392,31 +1391,31 @@ m_remove_signal_handler.assert_called_once_with( signal.SIGCHLD) self.assertFalse(self.watcher._callbacks) - if isinstance(self.watcher, unix_events.FastChildWatcher): + if isinstance(self.watcher, asyncio.FastChildWatcher): self.assertFalse(self.watcher._zombies) class SafeChildWatcherTests (ChildWatcherTestsMixin, unittest.TestCase): def create_watcher(self): - return unix_events.SafeChildWatcher() + return asyncio.SafeChildWatcher() class FastChildWatcherTests (ChildWatcherTestsMixin, unittest.TestCase): def create_watcher(self): - return unix_events.FastChildWatcher() + return asyncio.FastChildWatcher() class PolicyTests(unittest.TestCase): def create_policy(self): - return unix_events.DefaultEventLoopPolicy() + return asyncio.DefaultEventLoopPolicy() def test_get_child_watcher(self): policy = self.create_policy() self.assertIsNone(policy._watcher) watcher = policy.get_child_watcher() - self.assertIsInstance(watcher, unix_events.SafeChildWatcher) + self.assertIsInstance(watcher, asyncio.SafeChildWatcher) self.assertIs(policy._watcher, watcher) @@ -1425,7 +1424,7 @@ def test_get_child_watcher_after_set(self): policy = self.create_policy() - watcher = unix_events.FastChildWatcher() + watcher = asyncio.FastChildWatcher() policy.set_child_watcher(watcher) self.assertIs(policy._watcher, watcher) @@ -1438,7 +1437,7 @@ self.assertIsNone(policy._watcher) watcher = policy.get_child_watcher() - self.assertIsInstance(watcher, unix_events.SafeChildWatcher) + self.assertIsInstance(watcher, asyncio.SafeChildWatcher) self.assertIs(watcher._loop, loop) loop.close() @@ -1449,10 +1448,10 @@ policy.set_event_loop(policy.new_event_loop()) self.assertIsInstance(policy.get_event_loop(), - events.AbstractEventLoop) + asyncio.AbstractEventLoop) watcher = policy.get_child_watcher() - self.assertIsInstance(watcher, unix_events.SafeChildWatcher) + self.assertIsInstance(watcher, asyncio.SafeChildWatcher) self.assertIsNone(watcher._loop) policy.get_event_loop().close() diff --git a/Lib/test/test_asyncio/test_windows_events.py b/Lib/test/test_asyncio/test_windows_events.py --- a/Lib/test/test_asyncio/test_windows_events.py +++ b/Lib/test/test_asyncio/test_windows_events.py @@ -8,17 +8,12 @@ import _winapi import asyncio - -from asyncio import windows_events -from asyncio import futures -from asyncio import protocols -from asyncio import streams -from asyncio import transports from asyncio import test_utils from asyncio import _overlapped +from asyncio import windows_events -class UpperProto(protocols.Protocol): +class UpperProto(asyncio.Protocol): def __init__(self): self.buf = [] @@ -35,7 +30,7 @@ class ProactorTests(unittest.TestCase): def setUp(self): - self.loop = windows_events.ProactorEventLoop() + self.loop = asyncio.ProactorEventLoop() asyncio.set_event_loop(None) def tearDown(self): @@ -44,7 +39,7 @@ def test_close(self): a, b = self.loop._socketpair() - trans = self.loop._make_socket_transport(a, protocols.Protocol()) + trans = self.loop._make_socket_transport(a, asyncio.Protocol()) f = asyncio.async(self.loop.sock_recv(b, 100)) trans.close() self.loop.run_until_complete(f) @@ -67,7 +62,7 @@ with self.assertRaises(FileNotFoundError): yield from self.loop.create_pipe_connection( - protocols.Protocol, ADDRESS) + asyncio.Protocol, ADDRESS) [server] = yield from self.loop.start_serving_pipe( UpperProto, ADDRESS) @@ -75,11 +70,11 @@ clients = [] for i in range(5): - stream_reader = streams.StreamReader(loop=self.loop) - protocol = streams.StreamReaderProtocol(stream_reader) + stream_reader = asyncio.StreamReader(loop=self.loop) + protocol = asyncio.StreamReaderProtocol(stream_reader) trans, proto = yield from self.loop.create_pipe_connection( lambda: protocol, ADDRESS) - self.assertIsInstance(trans, transports.Transport) + self.assertIsInstance(trans, asyncio.Transport) self.assertEqual(protocol, proto) clients.append((stream_reader, trans)) @@ -95,7 +90,7 @@ with self.assertRaises(FileNotFoundError): yield from self.loop.create_pipe_connection( - protocols.Protocol, ADDRESS) + asyncio.Protocol, ADDRESS) return 'done' @@ -130,7 +125,7 @@ f = self.loop._proactor.wait_for_handle(event, 10) f.cancel() start = self.loop.time() - with self.assertRaises(futures.CancelledError): + with self.assertRaises(asyncio.CancelledError): self.loop.run_until_complete(f) elapsed = self.loop.time() - start self.assertTrue(0 <= elapsed < 0.1, elapsed) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 16:28:27 2014 From: python-checkins at python.org (ezio.melotti) Date: Sat, 25 Jan 2014 16:28:27 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_=2320348=3A_fix_headers_ma?= =?utf-8?q?rkup_in_Argument_Clinic_howto=2E__Patch_by_Moritz_Neeb=2E?= Message-ID: <3fBLhq5YCrz7Llb@mail.python.org> http://hg.python.org/cpython/rev/1eec62cf3675 changeset: 88700:1eec62cf3675 user: Ezio Melotti date: Sat Jan 25 17:27:46 2014 +0200 summary: #20348: fix headers markup in Argument Clinic howto. Patch by Moritz Neeb. files: Doc/howto/clinic.rst | 8 ++------ 1 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -1,6 +1,6 @@ -====================== +********************** Argument Clinic How-To -====================== +********************** :author: Larry Hastings @@ -23,7 +23,6 @@ version of Argument Clinic that ships with CPython 3.5 *could* be totally incompatible and break all your code. -============================ The Goals Of Argument Clinic ============================ @@ -75,7 +74,6 @@ things with all the information you give it. -======================== Basic Concepts And Usage ======================== @@ -131,7 +129,6 @@ a block.) -============================== Converting Your First Function ============================== @@ -533,7 +530,6 @@ Congratulations, you've ported your first function to work with Argument Clinic! -=============== Advanced Topics =============== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 18:44:09 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 25 Jan 2014 18:44:09 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIwMzMx?= =?utf-8?q?=3A_Fixed_possible_FD_leaks_in_various_modules=3A?= Message-ID: <3fBPjP6BH8zSxD@mail.python.org> http://hg.python.org/cpython/rev/6548f894b590 changeset: 88701:6548f894b590 branch: 2.7 parent: 88682:02f6c31c36a5 user: Serhiy Storchaka date: Sat Jan 25 19:42:27 2014 +0200 summary: Issue #20331: Fixed possible FD leaks in various modules: SimpleHTTPServer, imghdr, mailcap, mimetypes, xml.etree. files: Lib/SimpleHTTPServer.py | 24 +++++++++++++------- Lib/imghdr.py | 20 +++++++--------- Lib/mailcap.py | 4 +- Lib/mimetypes.py | 7 +++-- Lib/xml/etree/ElementInclude.py | 15 ++++++------- 5 files changed, 37 insertions(+), 33 deletions(-) diff --git a/Lib/SimpleHTTPServer.py b/Lib/SimpleHTTPServer.py --- a/Lib/SimpleHTTPServer.py +++ b/Lib/SimpleHTTPServer.py @@ -43,8 +43,10 @@ """Serve a GET request.""" f = self.send_head() if f: - self.copyfile(f, self.wfile) - f.close() + try: + self.copyfile(f, self.wfile) + finally: + f.close() def do_HEAD(self): """Serve a HEAD request.""" @@ -88,13 +90,17 @@ except IOError: self.send_error(404, "File not found") return None - self.send_response(200) - self.send_header("Content-type", ctype) - fs = os.fstat(f.fileno()) - self.send_header("Content-Length", str(fs[6])) - self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) - self.end_headers() - return f + try: + self.send_response(200) + self.send_header("Content-type", ctype) + fs = os.fstat(f.fileno()) + self.send_header("Content-Length", str(fs[6])) + self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) + self.end_headers() + return f + except: + f.close() + raise def list_directory(self, path): """Helper to produce a directory listing (absent index.html). diff --git a/Lib/imghdr.py b/Lib/imghdr.py --- a/Lib/imghdr.py +++ b/Lib/imghdr.py @@ -7,18 +7,16 @@ #-------------------------# def what(file, h=None): - if h is None: - if isinstance(file, basestring): - f = open(file, 'rb') - h = f.read(32) - else: - location = file.tell() - h = file.read(32) - file.seek(location) - f = None - else: - f = None + f = None try: + if h is None: + if isinstance(file, basestring): + f = open(file, 'rb') + h = f.read(32) + else: + location = file.tell() + h = file.read(32) + file.seek(location) for tf in tests: res = tf(h, f) if res: diff --git a/Lib/mailcap.py b/Lib/mailcap.py --- a/Lib/mailcap.py +++ b/Lib/mailcap.py @@ -22,8 +22,8 @@ fp = open(mailcap, 'r') except IOError: continue - morecaps = readmailcapfile(fp) - fp.close() + with fp: + morecaps = readmailcapfile(fp) for key, value in morecaps.iteritems(): if not key in caps: caps[key] = value diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py --- a/Lib/mimetypes.py +++ b/Lib/mimetypes.py @@ -373,9 +373,10 @@ f = open(file) except IOError: return None - db = MimeTypes() - db.readfp(f, True) - return db.types_map[True] + with f: + db = MimeTypes() + db.readfp(f, True) + return db.types_map[True] def _default_mime_types(): diff --git a/Lib/xml/etree/ElementInclude.py b/Lib/xml/etree/ElementInclude.py --- a/Lib/xml/etree/ElementInclude.py +++ b/Lib/xml/etree/ElementInclude.py @@ -75,14 +75,13 @@ # @throws IOError If the loader fails to load the resource. def default_loader(href, parse, encoding=None): - file = open(href) - if parse == "xml": - data = ElementTree.parse(file).getroot() - else: - data = file.read() - if encoding: - data = data.decode(encoding) - file.close() + with open(href) as file: + if parse == "xml": + data = ElementTree.parse(file).getroot() + else: + data = file.read() + if encoding: + data = data.decode(encoding) return data ## -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 18:44:11 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 25 Jan 2014 18:44:11 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMzMx?= =?utf-8?q?=3A_Fixed_possible_FD_leaks_in_various_modules=3A?= Message-ID: <3fBPjR1WvYzSxD@mail.python.org> http://hg.python.org/cpython/rev/2766320bdb10 changeset: 88702:2766320bdb10 branch: 3.3 parent: 88692:900a1ff323bb user: Serhiy Storchaka date: Sat Jan 25 19:43:02 2014 +0200 summary: Issue #20331: Fixed possible FD leaks in various modules: http.server, imghdr, mailcap, mimetypes, xml.etree. files: Lib/http/server.py | 24 +++++++++++++------- Lib/imghdr.py | 20 +++++++--------- Lib/mailcap.py | 4 +- Lib/mimetypes.py | 7 +++-- Lib/xml/etree/ElementInclude.py | 9 +++---- 5 files changed, 34 insertions(+), 30 deletions(-) diff --git a/Lib/http/server.py b/Lib/http/server.py --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -670,8 +670,10 @@ """Serve a GET request.""" f = self.send_head() if f: - self.copyfile(f, self.wfile) - f.close() + try: + self.copyfile(f, self.wfile) + finally: + f.close() def do_HEAD(self): """Serve a HEAD request.""" @@ -712,13 +714,17 @@ except IOError: self.send_error(404, "File not found") return None - self.send_response(200) - self.send_header("Content-type", ctype) - fs = os.fstat(f.fileno()) - self.send_header("Content-Length", str(fs[6])) - self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) - self.end_headers() - return f + try: + self.send_response(200) + self.send_header("Content-type", ctype) + fs = os.fstat(f.fileno()) + self.send_header("Content-Length", str(fs[6])) + self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) + self.end_headers() + return f + except: + f.close() + raise def list_directory(self, path): """Helper to produce a directory listing (absent index.html). diff --git a/Lib/imghdr.py b/Lib/imghdr.py --- a/Lib/imghdr.py +++ b/Lib/imghdr.py @@ -7,18 +7,16 @@ #-------------------------# def what(file, h=None): - if h is None: - if isinstance(file, str): - f = open(file, 'rb') - h = f.read(32) - else: - location = file.tell() - h = file.read(32) - file.seek(location) - f = None - else: - f = None + f = None try: + if h is None: + if isinstance(file, str): + f = open(file, 'rb') + h = f.read(32) + else: + location = file.tell() + h = file.read(32) + file.seek(location) for tf in tests: res = tf(h, f) if res: diff --git a/Lib/mailcap.py b/Lib/mailcap.py --- a/Lib/mailcap.py +++ b/Lib/mailcap.py @@ -22,8 +22,8 @@ fp = open(mailcap, 'r') except IOError: continue - morecaps = readmailcapfile(fp) - fp.close() + with fp: + morecaps = readmailcapfile(fp) for key, value in morecaps.items(): if not key in caps: caps[key] = value diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py --- a/Lib/mimetypes.py +++ b/Lib/mimetypes.py @@ -363,9 +363,10 @@ f = open(file) except IOError: return None - db = MimeTypes() - db.readfp(f, True) - return db.types_map[True] + with f: + db = MimeTypes() + db.readfp(f, True) + return db.types_map[True] def _default_mime_types(): diff --git a/Lib/xml/etree/ElementInclude.py b/Lib/xml/etree/ElementInclude.py --- a/Lib/xml/etree/ElementInclude.py +++ b/Lib/xml/etree/ElementInclude.py @@ -76,14 +76,13 @@ def default_loader(href, parse, encoding=None): if parse == "xml": - file = open(href, 'rb') - data = ElementTree.parse(file).getroot() + with open(href, 'rb') as file: + data = ElementTree.parse(file).getroot() else: if not encoding: encoding = 'UTF-8' - file = open(href, 'r', encoding=encoding) - data = file.read() - file.close() + with open(href, 'r', encoding=encoding) as file: + data = file.read() return data ## -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 18:44:16 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 25 Jan 2014 18:44:16 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320331=3A_Fixed_possible_FD_leaks_in_various_mod?= =?utf-8?q?ules=3A?= Message-ID: <3fBPjX1QwPz7LlK@mail.python.org> http://hg.python.org/cpython/rev/b30e57756686 changeset: 88703:b30e57756686 parent: 88700:1eec62cf3675 parent: 88702:2766320bdb10 user: Serhiy Storchaka date: Sat Jan 25 19:43:56 2014 +0200 summary: Issue #20331: Fixed possible FD leaks in various modules: http.server, imghdr, mailcap, mimetypes, xml.etree. files: Lib/http/server.py | 24 +++++++++++++------- Lib/imghdr.py | 20 +++++++--------- Lib/mailcap.py | 4 +- Lib/mimetypes.py | 7 +++-- Lib/xml/etree/ElementInclude.py | 9 +++---- 5 files changed, 34 insertions(+), 30 deletions(-) diff --git a/Lib/http/server.py b/Lib/http/server.py --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -678,8 +678,10 @@ """Serve a GET request.""" f = self.send_head() if f: - self.copyfile(f, self.wfile) - f.close() + try: + self.copyfile(f, self.wfile) + finally: + f.close() def do_HEAD(self): """Serve a HEAD request.""" @@ -720,13 +722,17 @@ except OSError: self.send_error(404, "File not found") return None - self.send_response(200) - self.send_header("Content-type", ctype) - fs = os.fstat(f.fileno()) - self.send_header("Content-Length", str(fs[6])) - self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) - self.end_headers() - return f + try: + self.send_response(200) + self.send_header("Content-type", ctype) + fs = os.fstat(f.fileno()) + self.send_header("Content-Length", str(fs[6])) + self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) + self.end_headers() + return f + except: + f.close() + raise def list_directory(self, path): """Helper to produce a directory listing (absent index.html). diff --git a/Lib/imghdr.py b/Lib/imghdr.py --- a/Lib/imghdr.py +++ b/Lib/imghdr.py @@ -7,18 +7,16 @@ #-------------------------# def what(file, h=None): - if h is None: - if isinstance(file, str): - f = open(file, 'rb') - h = f.read(32) - else: - location = file.tell() - h = file.read(32) - file.seek(location) - f = None - else: - f = None + f = None try: + if h is None: + if isinstance(file, str): + f = open(file, 'rb') + h = f.read(32) + else: + location = file.tell() + h = file.read(32) + file.seek(location) for tf in tests: res = tf(h, f) if res: diff --git a/Lib/mailcap.py b/Lib/mailcap.py --- a/Lib/mailcap.py +++ b/Lib/mailcap.py @@ -22,8 +22,8 @@ fp = open(mailcap, 'r') except OSError: continue - morecaps = readmailcapfile(fp) - fp.close() + with fp: + morecaps = readmailcapfile(fp) for key, value in morecaps.items(): if not key in caps: caps[key] = value diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py --- a/Lib/mimetypes.py +++ b/Lib/mimetypes.py @@ -363,9 +363,10 @@ f = open(file) except OSError: return None - db = MimeTypes() - db.readfp(f, True) - return db.types_map[True] + with f: + db = MimeTypes() + db.readfp(f, True) + return db.types_map[True] def _default_mime_types(): diff --git a/Lib/xml/etree/ElementInclude.py b/Lib/xml/etree/ElementInclude.py --- a/Lib/xml/etree/ElementInclude.py +++ b/Lib/xml/etree/ElementInclude.py @@ -76,14 +76,13 @@ def default_loader(href, parse, encoding=None): if parse == "xml": - file = open(href, 'rb') - data = ElementTree.parse(file).getroot() + with open(href, 'rb') as file: + data = ElementTree.parse(file).getroot() else: if not encoding: encoding = 'UTF-8' - file = open(href, 'r', encoding=encoding) - data = file.read() - file.close() + with open(href, 'r', encoding=encoding) as file: + data = file.read() return data ## -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 19:28:00 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 25 Jan 2014 19:28:00 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_linkify?= Message-ID: <3fBQh05chBz7LjV@mail.python.org> http://hg.python.org/cpython/rev/035ab711b8cc changeset: 88704:035ab711b8cc branch: 3.3 parent: 88702:2766320bdb10 user: Benjamin Peterson date: Sat Jan 25 13:26:18 2014 -0500 summary: linkify files: Doc/faq/general.rst | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -269,9 +269,10 @@ --------------------------------------------- The Python project's infrastructure is located all over the world. -www.python.org is currently in Amsterdam, graciously hosted by `XS4ALL -`_. `Upfront Systems `_ -hosts bugs.python.org. Most other Python services like `PyPI +`www.python.org `_ is currently in Amsterdam, graciously +hosted by `XS4ALL `_. `Upfront Systems +`_ hosts `bugs.python.org +`_. Most other Python services like `PyPI `_ and hg.python.org are hosted by `Oregon State University Open Source Lab `_. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 19:28:02 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 25 Jan 2014 19:28:02 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_update_sphinx_?= =?utf-8?q?url?= Message-ID: <3fBQh20HX0z7LjV@mail.python.org> http://hg.python.org/cpython/rev/8c5876a6b3ed changeset: 88705:8c5876a6b3ed branch: 3.3 user: Benjamin Peterson date: Sat Jan 25 13:27:06 2014 -0500 summary: update sphinx url files: Doc/faq/general.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -181,8 +181,8 @@ also available at http://docs.python.org/download.html. The documentation is written in reStructuredText and processed by `the Sphinx -documentation tool `__. The reStructuredText source -for the documentation is part of the Python source distribution. +documentation tool `__. The reStructuredText source for +the documentation is part of the Python source distribution. I've never programmed before. Is there a Python tutorial? -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 19:28:03 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 25 Jan 2014 19:28:03 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_linkify?= Message-ID: <3fBQh32RWpz7LjV@mail.python.org> http://hg.python.org/cpython/rev/ecacfed9b785 changeset: 88706:ecacfed9b785 branch: 2.7 parent: 88701:6548f894b590 user: Benjamin Peterson date: Sat Jan 25 13:26:18 2014 -0500 summary: linkify files: Doc/faq/general.rst | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -269,9 +269,10 @@ --------------------------------------------- The Python project's infrastructure is located all over the world. -www.python.org is currently in Amsterdam, graciously hosted by `XS4ALL -`_. `Upfront Systems `_ -hosts bugs.python.org. Most other Python services like `PyPI +`www.python.org `_ is currently in Amsterdam, graciously +hosted by `XS4ALL `_. `Upfront Systems +`_ hosts `bugs.python.org +`_. Most other Python services like `PyPI `_ and hg.python.org are hosted by `Oregon State University Open Source Lab `_. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 19:28:04 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 25 Jan 2014 19:28:04 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_update_sphinx_?= =?utf-8?q?url?= Message-ID: <3fBQh43q02z7LlL@mail.python.org> http://hg.python.org/cpython/rev/25f6da4c49c2 changeset: 88707:25f6da4c49c2 branch: 2.7 user: Benjamin Peterson date: Sat Jan 25 13:27:06 2014 -0500 summary: update sphinx url files: Doc/faq/general.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -181,8 +181,8 @@ also available at http://docs.python.org/download.html. The documentation is written in reStructuredText and processed by `the Sphinx -documentation tool `__. The reStructuredText source -for the documentation is part of the Python source distribution. +documentation tool `__. The reStructuredText source for +the documentation is part of the Python source distribution. I've never programmed before. Is there a Python tutorial? -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 19:28:05 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 25 Jan 2014 19:28:05 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3fBQh55Yh7z7Lm5@mail.python.org> http://hg.python.org/cpython/rev/fae92299eb68 changeset: 88708:fae92299eb68 parent: 88703:b30e57756686 parent: 88705:8c5876a6b3ed user: Benjamin Peterson date: Sat Jan 25 13:27:53 2014 -0500 summary: merge 3.3 files: Doc/faq/general.rst | 11 ++++++----- 1 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -181,8 +181,8 @@ also available at http://docs.python.org/download.html. The documentation is written in reStructuredText and processed by `the Sphinx -documentation tool `__. The reStructuredText source -for the documentation is part of the Python source distribution. +documentation tool `__. The reStructuredText source for +the documentation is part of the Python source distribution. I've never programmed before. Is there a Python tutorial? @@ -269,9 +269,10 @@ --------------------------------------------- The Python project's infrastructure is located all over the world. -www.python.org is currently in Amsterdam, graciously hosted by `XS4ALL -`_. `Upfront Systems `_ -hosts bugs.python.org. Most other Python services like `PyPI +`www.python.org `_ is currently in Amsterdam, graciously +hosted by `XS4ALL `_. `Upfront Systems +`_ hosts `bugs.python.org +`_. Most other Python services like `PyPI `_ and hg.python.org are hosted by `Oregon State University Open Source Lab `_. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 22:22:29 2014 From: python-checkins at python.org (victor.stinner) Date: Sat, 25 Jan 2014 22:22:29 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Don=27t_export_?= =?utf-8?q?BaseEventLoop=2C_BaseSelectorEventLoop_nor?= Message-ID: <3fBVYK3KLdz7LmS@mail.python.org> http://hg.python.org/cpython/rev/ae405c11193b changeset: 88709:ae405c11193b user: Victor Stinner date: Sat Jan 25 22:22:18 2014 +0100 summary: asyncio: Don't export BaseEventLoop, BaseSelectorEventLoop nor BaseProactorEventLoop Import them from submodules if you really need them. files: Lib/asyncio/__init__.py | 8 +------ Lib/test/test_asyncio/test_base_events.py | 3 +- Lib/test/test_asyncio/test_events.py | 3 +- Lib/test/test_asyncio/test_proactor_events.py | 11 +++++---- Lib/test/test_asyncio/test_selector_events.py | 3 +- 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/Lib/asyncio/__init__.py b/Lib/asyncio/__init__.py --- a/Lib/asyncio/__init__.py +++ b/Lib/asyncio/__init__.py @@ -18,14 +18,11 @@ import _overlapped # Will also be exported. # This relies on each of the submodules having an __all__ variable. -from .base_events import * from .events import * from .futures import * from .locks import * -from .proactor_events import * from .protocols import * from .queues import * -from .selector_events import * from .streams import * from .tasks import * from .transports import * @@ -36,14 +33,11 @@ from .unix_events import * # pragma: no cover -__all__ = (base_events.__all__ + - events.__all__ + +__all__ = (events.__all__ + futures.__all__ + locks.__all__ + - proactor_events.__all__ + protocols.__all__ + queues.__all__ + - selector_events.__all__ + streams.__all__ + tasks.__all__ + transports.__all__) 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 @@ -9,6 +9,7 @@ from test.support import find_unused_port, IPV6_ENABLED import asyncio +from asyncio import base_events from asyncio import constants from asyncio import test_utils @@ -16,7 +17,7 @@ class BaseEventLoopTests(unittest.TestCase): def setUp(self): - self.loop = asyncio.BaseEventLoop() + self.loop = base_events.BaseEventLoop() self.loop._selector = unittest.mock.Mock() asyncio.set_event_loop(None) 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 @@ -25,6 +25,7 @@ import asyncio from asyncio import events +from asyncio import selector_events from asyncio import test_utils @@ -902,7 +903,7 @@ def test_internal_fds(self): loop = self.create_event_loop() - if not isinstance(loop, asyncio.BaseSelectorEventLoop): + if not isinstance(loop, selector_events.BaseSelectorEventLoop): self.skipTest('loop is not a BaseSelectorEventLoop') self.assertEqual(1, loop._internal_fds) diff --git a/Lib/test/test_asyncio/test_proactor_events.py b/Lib/test/test_asyncio/test_proactor_events.py --- a/Lib/test/test_asyncio/test_proactor_events.py +++ b/Lib/test/test_asyncio/test_proactor_events.py @@ -5,6 +5,7 @@ import unittest.mock import asyncio +from asyncio.proactor_events import BaseProactorEventLoop from asyncio.proactor_events import _ProactorSocketTransport from asyncio.proactor_events import _ProactorWritePipeTransport from asyncio.proactor_events import _ProactorDuplexPipeTransport @@ -344,18 +345,18 @@ self.ssock, self.csock = unittest.mock.Mock(), unittest.mock.Mock() - class EventLoop(asyncio.BaseProactorEventLoop): + class EventLoop(BaseProactorEventLoop): def _socketpair(s): return (self.ssock, self.csock) self.loop = EventLoop(self.proactor) - @unittest.mock.patch.object(asyncio.BaseProactorEventLoop, 'call_soon') - @unittest.mock.patch.object(asyncio.BaseProactorEventLoop, '_socketpair') + @unittest.mock.patch.object(BaseProactorEventLoop, 'call_soon') + @unittest.mock.patch.object(BaseProactorEventLoop, '_socketpair') def test_ctor(self, socketpair, call_soon): ssock, csock = socketpair.return_value = ( unittest.mock.Mock(), unittest.mock.Mock()) - loop = asyncio.BaseProactorEventLoop(self.proactor) + loop = BaseProactorEventLoop(self.proactor) self.assertIs(loop._ssock, ssock) self.assertIs(loop._csock, csock) self.assertEqual(loop._internal_fds, 1) @@ -398,7 +399,7 @@ def test_socketpair(self): self.assertRaises( - NotImplementedError, asyncio.BaseProactorEventLoop, self.proactor) + NotImplementedError, BaseProactorEventLoop, self.proactor) def test_make_socket_transport(self): tr = self.loop._make_socket_transport(self.sock, unittest.mock.Mock()) 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 @@ -16,13 +16,14 @@ import asyncio from asyncio import selectors from asyncio import test_utils +from asyncio.selector_events import BaseSelectorEventLoop from asyncio.selector_events import _SelectorTransport from asyncio.selector_events import _SelectorSslTransport from asyncio.selector_events import _SelectorSocketTransport from asyncio.selector_events import _SelectorDatagramTransport -class TestBaseSelectorEventLoop(asyncio.BaseSelectorEventLoop): +class TestBaseSelectorEventLoop(BaseSelectorEventLoop): def _make_self_pipe(self): self._ssock = unittest.mock.Mock() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 23:37:49 2014 From: python-checkins at python.org (eric.snow) Date: Sat, 25 Jan 2014 23:37:49 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_19944=3A_Fix_importl?= =?utf-8?q?ib=2Efind=5Fspec=28=29_so_it_imports_parents_as_needed=2E?= Message-ID: <3fBXDF0vdHz7LjS@mail.python.org> http://hg.python.org/cpython/rev/665f1ba77b57 changeset: 88710:665f1ba77b57 user: Eric Snow date: Sat Jan 25 15:32:46 2014 -0700 summary: Issue 19944: Fix importlib.find_spec() so it imports parents as needed. The function is also moved to importlib.util. files: Doc/library/importlib.rst | 34 +- Lib/idlelib/EditorWindow.py | 3 +- Lib/importlib/__init__.py | 46 +--- Lib/importlib/util.py | 72 +++++++ Lib/pkgutil.py | 2 +- Lib/pyclbr.py | 4 +- Lib/runpy.py | 26 +-- Lib/test/test_importlib/test_api.py | 151 +-------------- Lib/test/test_importlib/test_util.py | 147 ++++++++++++++ Lib/test/test_importlib/util.py | 34 +++- Misc/NEWS | 3 + 11 files changed, 292 insertions(+), 230 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -89,22 +89,6 @@ .. versionchanged:: 3.3 Parent packages are automatically imported. -.. function:: find_spec(name, path=None) - - Find the :term:`spec ` for a module, optionally within the - specified *path*. If the module is in :attr:`sys.modules`, then - ``sys.modules[name].__spec__`` is returned (unless the spec would be - ``None`` or is not set, in which case :exc:`ValueError` is raised). - Otherwise a search using :attr:`sys.meta_path` is done. ``None`` is - returned if no spec is found. - - A dotted name does not have its parent implicitly imported as that requires - loading them and that may not be desired. To properly import a submodule you - will need to import all parent packages of the submodule and use the correct - argument to *path*. - - .. versionadded:: 3.4 - .. function:: find_loader(name, path=None) Find the loader for a module, optionally within the specified *path*. If the @@ -125,7 +109,7 @@ attribute is set to ``None``. .. deprecated:: 3.4 - Use :func:`find_spec` instead. + Use :func:`importlib.util.find_spec` instead. .. function:: invalidate_caches() @@ -1111,6 +1095,22 @@ .. versionadded:: 3.3 +.. function:: find_spec(name, package=None) + + Find the :term:`spec ` for a module, optionally relative to + the specified **package** name. If the module is in :attr:`sys.modules`, + then ``sys.modules[name].__spec__`` is returned (unless the spec would be + ``None`` or is not set, in which case :exc:`ValueError` is raised). + Otherwise a search using :attr:`sys.meta_path` is done. ``None`` is + returned if no spec is found. + + If **name** is for a submodule (contains a dot), the parent module is + automatically imported. + + **name** and **package** work the same as for :func:`import_module`. + + .. versionadded:: 3.4 + .. decorator:: module_for_loader A :term:`decorator` for :meth:`importlib.abc.Loader.load_module` diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -1,5 +1,6 @@ import importlib import importlib.abc +import importlib.util import os from platform import python_version import re @@ -660,7 +661,7 @@ return # XXX Ought to insert current file's directory in front of path try: - spec = importlib.find_spec(name) + spec = importlib.util.find_spec(name) except (ValueError, ImportError) as msg: tkMessageBox.showerror("Import error", str(msg), parent=self.text) return diff --git a/Lib/importlib/__init__.py b/Lib/importlib/__init__.py --- a/Lib/importlib/__init__.py +++ b/Lib/importlib/__init__.py @@ -11,8 +11,6 @@ # initialised below if the frozen one is not available). import _imp # Just the builtin component, NOT the full Python module import sys -import types -import warnings try: import _frozen_importlib as _bootstrap @@ -34,6 +32,10 @@ # Fully bootstrapped at this point, import whatever you like, circular # dependencies and startup overhead minimisation permitting :) +import types +import warnings + + # Public API ######################################################### from ._bootstrap import __import__ @@ -47,47 +49,16 @@ finder.invalidate_caches() -def find_spec(name, path=None): - """Return the spec for the specified module. - - First, sys.modules is checked to see if the module was already imported. If - so, then sys.modules[name].__spec__ is returned. If that happens to be - set to None, then ValueError is raised. If the module is not in - sys.modules, then sys.meta_path is searched for a suitable spec with the - value of 'path' given to the finders. None is returned if no spec could - be found. - - Dotted names do not have their parent packages implicitly imported. You will - most likely need to explicitly import all parent packages in the proper - order for a submodule to get the correct spec. - - """ - if name not in sys.modules: - return _bootstrap._find_spec(name, path) - else: - module = sys.modules[name] - if module is None: - return None - try: - spec = module.__spec__ - except AttributeError: - raise ValueError('{}.__spec__ is not set'.format(name)) - else: - if spec is None: - raise ValueError('{}.__spec__ is None'.format(name)) - return spec - - def find_loader(name, path=None): """Return the loader for the specified module. This is a backward-compatible wrapper around find_spec(). - This function is deprecated in favor of importlib.find_spec(). + This function is deprecated in favor of importlib.util.find_spec(). """ - warnings.warn('Use importlib.find_spec() instead.', DeprecationWarning, - stacklevel=2) + warnings.warn('Use importlib.util.find_spec() instead.', + DeprecationWarning, stacklevel=2) try: loader = sys.modules[name].__loader__ if loader is None: @@ -167,7 +138,8 @@ pkgpath = parent.__path__ else: pkgpath = None - spec = module.__spec__ = _bootstrap._find_spec(name, pkgpath, module) + target = module + spec = module.__spec__ = _bootstrap._find_spec(name, pkgpath, target) methods = _bootstrap._SpecMethods(spec) methods.exec(module) # The module may have replaced itself in sys.modules! diff --git a/Lib/importlib/util.py b/Lib/importlib/util.py --- a/Lib/importlib/util.py +++ b/Lib/importlib/util.py @@ -7,6 +7,7 @@ from ._bootstrap import spec_from_loader from ._bootstrap import spec_from_file_location from ._bootstrap import _resolve_name +from ._bootstrap import _find_spec from contextlib import contextmanager import functools @@ -29,6 +30,77 @@ return _resolve_name(name[level:], package, level) +def _find_spec_from_path(name, path=None): + """Return the spec for the specified module. + + First, sys.modules is checked to see if the module was already imported. If + so, then sys.modules[name].__spec__ is returned. If that happens to be + set to None, then ValueError is raised. If the module is not in + sys.modules, then sys.meta_path is searched for a suitable spec with the + value of 'path' given to the finders. None is returned if no spec could + be found. + + Dotted names do not have their parent packages implicitly imported. You will + most likely need to explicitly import all parent packages in the proper + order for a submodule to get the correct spec. + + """ + if name not in sys.modules: + return _find_spec(name, path) + else: + module = sys.modules[name] + if module is None: + return None + try: + spec = module.__spec__ + except AttributeError: + raise ValueError('{}.__spec__ is not set'.format(name)) + else: + if spec is None: + raise ValueError('{}.__spec__ is None'.format(name)) + return spec + + +def find_spec(name, package=None): + """Return the spec for the specified module. + + First, sys.modules is checked to see if the module was already imported. If + so, then sys.modules[name].__spec__ is returned. If that happens to be + set to None, then ValueError is raised. If the module is not in + sys.modules, then sys.meta_path is searched for a suitable spec with the + value of 'path' given to the finders. None is returned if no spec could + be found. + + If the name is for submodule (contains a dot), the parent module is + automatically imported. + + The name and package arguments work the same as importlib.import_module(). + In other words, relative module names (with leading dots) work. + + """ + fullname = resolve_name(name, package) if name.startswith('.') else name + if fullname not in sys.modules: + parent_name = fullname.rpartition('.')[0] + if parent_name: + # Use builtins.__import__() in case someone replaced it. + parent = __import__(parent_name, fromlist=['__path__']) + return _find_spec(fullname, parent.__path__) + else: + return _find_spec(fullname, None) + else: + module = sys.modules[fullname] + if module is None: + return None + try: + spec = module.__spec__ + except AttributeError: + raise ValueError('{}.__spec__ is not set'.format(name)) + else: + if spec is None: + raise ValueError('{}.__spec__ is None'.format(name)) + return spec + + @contextmanager def _module_to_load(name): is_reload = name in sys.modules diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py --- a/Lib/pkgutil.py +++ b/Lib/pkgutil.py @@ -611,7 +611,7 @@ which does not support get_data(), then None is returned. """ - spec = importlib.find_spec(package) + spec = importlib.util.find_spec(package) if spec is None: return None loader = spec.loader diff --git a/Lib/pyclbr.py b/Lib/pyclbr.py --- a/Lib/pyclbr.py +++ b/Lib/pyclbr.py @@ -42,7 +42,7 @@ import io import os import sys -import importlib +import importlib.util import tokenize from token import NAME, DEDENT, OP from operator import itemgetter @@ -141,7 +141,7 @@ else: search_path = path + sys.path # XXX This will change once issue19944 lands. - spec = importlib.find_spec(fullmodule, search_path) + spec = importlib.util._find_spec_from_path(fullmodule, search_path) fname = spec.loader.get_filename(fullmodule) _modules[fullmodule] = dict if spec.loader.is_package(fullmodule): diff --git a/Lib/runpy.py b/Lib/runpy.py --- a/Lib/runpy.py +++ b/Lib/runpy.py @@ -13,9 +13,8 @@ import os import sys import importlib.machinery # importlib first so we can test #15386 via -m +import importlib.util import types -from importlib import find_spec -from importlib.util import spec_from_loader from pkgutil import read_code, get_importer __all__ = [ @@ -100,33 +99,16 @@ # may be cleared when the temporary module goes away return mod_globals.copy() - -def _fixed_find_spec(mod_name): - # find_spec has the same annoying behaviour as find_loader did (it - # fails to work properly for dotted names), so this is a fixed version - # ala pkgutil.get_loader - if mod_name.startswith('.'): - msg = "Relative module name {!r} not supported".format(mod_name) - raise ImportError(msg) - path = None - pkg_name = mod_name.rpartition(".")[0] - if pkg_name: - pkg = importlib.import_module(pkg_name) - path = getattr(pkg, "__path__", None) - if path is None: - return None +# Helper to get the loader, code and filename for a module +def _get_module_details(mod_name): try: - return importlib.find_spec(mod_name, path) + spec = importlib.util.find_spec(mod_name) except (ImportError, AttributeError, TypeError, ValueError) as ex: # This hack fixes an impedance mismatch between pkgutil and # importlib, where the latter raises other errors for cases where # pkgutil previously raised ImportError msg = "Error while finding spec for {!r} ({}: {})" raise ImportError(msg.format(mod_name, type(ex), ex)) from ex - -# Helper to get the loader, code and filename for a module -def _get_module_details(mod_name): - spec = _fixed_find_spec(mod_name) if spec is None: raise ImportError("No module named %s" % mod_name) if spec.submodule_search_locations is not None: diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py --- a/Lib/test/test_importlib/test_api.py +++ b/Lib/test/test_importlib/test_api.py @@ -4,7 +4,6 @@ frozen_util, source_util = util.import_importlib('importlib.util') frozen_machinery, source_machinery = util.import_importlib('importlib.machinery') -from contextlib import contextmanager import os.path import sys from test import support @@ -13,37 +12,6 @@ import warnings - at contextmanager -def temp_module(name, content='', *, pkg=False): - conflicts = [n for n in sys.modules if n.partition('.')[0] == name] - with support.temp_cwd(None) as cwd: - with util.uncache(name, *conflicts): - with support.DirsOnSysPath(cwd): - frozen_init.invalidate_caches() - - location = os.path.join(cwd, name) - if pkg: - modpath = os.path.join(location, '__init__.py') - os.mkdir(name) - else: - modpath = location + '.py' - if content is None: - # Make sure the module file gets created. - content = '' - if content is not None: - # not a namespace package - with open(modpath, 'w') as modfile: - modfile.write(content) - yield location - - -def submodule(parent, name, pkg_dir, content=''): - path = os.path.join(pkg_dir, name + '.py') - with open(path, 'w') as subfile: - subfile.write(content) - return '{}.{}'.format(parent, name), path - - class ImportModuleTests: """Test importlib.import_module.""" @@ -210,121 +178,6 @@ init = source_init -class FindSpecTests: - - class FakeMetaFinder: - @staticmethod - def find_spec(name, path=None, target=None): return name, path, target - - def test_sys_modules(self): - name = 'some_mod' - with util.uncache(name): - module = types.ModuleType(name) - loader = 'a loader!' - spec = self.machinery.ModuleSpec(name, loader) - module.__loader__ = loader - module.__spec__ = spec - sys.modules[name] = module - found = self.init.find_spec(name) - self.assertEqual(found, spec) - - def test_sys_modules_without___loader__(self): - name = 'some_mod' - with util.uncache(name): - module = types.ModuleType(name) - del module.__loader__ - loader = 'a loader!' - spec = self.machinery.ModuleSpec(name, loader) - module.__spec__ = spec - sys.modules[name] = module - found = self.init.find_spec(name) - self.assertEqual(found, spec) - - def test_sys_modules_spec_is_None(self): - name = 'some_mod' - with util.uncache(name): - module = types.ModuleType(name) - module.__spec__ = None - sys.modules[name] = module - with self.assertRaises(ValueError): - self.init.find_spec(name) - - def test_sys_modules_loader_is_None(self): - name = 'some_mod' - with util.uncache(name): - module = types.ModuleType(name) - spec = self.machinery.ModuleSpec(name, None) - module.__spec__ = spec - sys.modules[name] = module - found = self.init.find_spec(name) - self.assertEqual(found, spec) - - def test_sys_modules_spec_is_not_set(self): - name = 'some_mod' - with util.uncache(name): - module = types.ModuleType(name) - try: - del module.__spec__ - except AttributeError: - pass - sys.modules[name] = module - with self.assertRaises(ValueError): - self.init.find_spec(name) - - def test_success(self): - name = 'some_mod' - with util.uncache(name): - with util.import_state(meta_path=[self.FakeMetaFinder]): - self.assertEqual((name, None, None), - self.init.find_spec(name)) - - def test_success_path(self): - # Searching on a path should work. - name = 'some_mod' - path = 'path to some place' - with util.uncache(name): - with util.import_state(meta_path=[self.FakeMetaFinder]): - self.assertEqual((name, path, None), - self.init.find_spec(name, path)) - - def test_nothing(self): - # None is returned upon failure to find a loader. - self.assertIsNone(self.init.find_spec('nevergoingtofindthismodule')) - - def test_find_submodule(self): - name = 'spam' - subname = 'ham' - with temp_module(name, pkg=True) as pkg_dir: - fullname, _ = submodule(name, subname, pkg_dir) - spec = self.init.find_spec(fullname, [pkg_dir]) - self.assertIsNot(spec, None) - self.assertNotIn(name, sorted(sys.modules)) - # Ensure successive calls behave the same. - spec_again = self.init.find_spec(fullname, [pkg_dir]) - self.assertEqual(spec_again, spec) - - def test_find_submodule_missing_path(self): - name = 'spam' - subname = 'ham' - with temp_module(name, pkg=True) as pkg_dir: - fullname, _ = submodule(name, subname, pkg_dir) - spec = self.init.find_spec(fullname) - self.assertIs(spec, None) - self.assertNotIn(name, sorted(sys.modules)) - # Ensure successive calls behave the same. - spec = self.init.find_spec(fullname) - self.assertIs(spec, None) - - -class Frozen_FindSpecTests(FindSpecTests, unittest.TestCase): - init = frozen_init - machinery = frozen_machinery - -class Source_FindSpecTests(FindSpecTests, unittest.TestCase): - init = source_init - machinery = source_machinery - - class ReloadTests: """Test module reloading for builtin and extension modules.""" @@ -484,8 +337,8 @@ # See #19851. name = 'spam' subname = 'ham' - with temp_module(name, pkg=True) as pkg_dir: - fullname, _ = submodule(name, subname, pkg_dir) + with util.temp_module(name, pkg=True) as pkg_dir: + fullname, _ = util.submodule(name, subname, pkg_dir) ham = self.init.import_module(fullname) reloaded = self.init.reload(ham) self.assertIs(reloaded, ham) diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py --- a/Lib/test/test_importlib/test_util.py +++ b/Lib/test/test_importlib/test_util.py @@ -1,5 +1,7 @@ from importlib import util from . import util as test_util +frozen_init, source_init = test_util.import_importlib('importlib') +frozen_machinery, source_machinery = test_util.import_importlib('importlib.machinery') frozen_util, source_util = test_util.import_importlib('importlib.util') import os @@ -310,6 +312,151 @@ util=[frozen_util, source_util]) +class FindSpecTests: + + class FakeMetaFinder: + @staticmethod + def find_spec(name, path=None, target=None): return name, path, target + + def test_sys_modules(self): + name = 'some_mod' + with test_util.uncache(name): + module = types.ModuleType(name) + loader = 'a loader!' + spec = self.machinery.ModuleSpec(name, loader) + module.__loader__ = loader + module.__spec__ = spec + sys.modules[name] = module + found = self.util.find_spec(name) + self.assertEqual(found, spec) + + def test_sys_modules_without___loader__(self): + name = 'some_mod' + with test_util.uncache(name): + module = types.ModuleType(name) + del module.__loader__ + loader = 'a loader!' + spec = self.machinery.ModuleSpec(name, loader) + module.__spec__ = spec + sys.modules[name] = module + found = self.util.find_spec(name) + self.assertEqual(found, spec) + + def test_sys_modules_spec_is_None(self): + name = 'some_mod' + with test_util.uncache(name): + module = types.ModuleType(name) + module.__spec__ = None + sys.modules[name] = module + with self.assertRaises(ValueError): + self.util.find_spec(name) + + def test_sys_modules_loader_is_None(self): + name = 'some_mod' + with test_util.uncache(name): + module = types.ModuleType(name) + spec = self.machinery.ModuleSpec(name, None) + module.__spec__ = spec + sys.modules[name] = module + found = self.util.find_spec(name) + self.assertEqual(found, spec) + + def test_sys_modules_spec_is_not_set(self): + name = 'some_mod' + with test_util.uncache(name): + module = types.ModuleType(name) + try: + del module.__spec__ + except AttributeError: + pass + sys.modules[name] = module + with self.assertRaises(ValueError): + self.util.find_spec(name) + + def test_success(self): + name = 'some_mod' + with test_util.uncache(name): + with test_util.import_state(meta_path=[self.FakeMetaFinder]): + self.assertEqual((name, None, None), + self.util.find_spec(name)) + +# def test_success_path(self): +# # Searching on a path should work. +# name = 'some_mod' +# path = 'path to some place' +# with test_util.uncache(name): +# with test_util.import_state(meta_path=[self.FakeMetaFinder]): +# self.assertEqual((name, path, None), +# self.util.find_spec(name, path)) + + def test_nothing(self): + # None is returned upon failure to find a loader. + self.assertIsNone(self.util.find_spec('nevergoingtofindthismodule')) + + def test_find_submodule(self): + name = 'spam' + subname = 'ham' + with test_util.temp_module(name, pkg=True) as pkg_dir: + fullname, _ = test_util.submodule(name, subname, pkg_dir) + spec = self.util.find_spec(fullname) + self.assertIsNot(spec, None) + self.assertIn(name, sorted(sys.modules)) + self.assertNotIn(fullname, sorted(sys.modules)) + # Ensure successive calls behave the same. + spec_again = self.util.find_spec(fullname) + self.assertEqual(spec_again, spec) + + def test_find_submodule_parent_already_imported(self): + name = 'spam' + subname = 'ham' + with test_util.temp_module(name, pkg=True) as pkg_dir: + self.init.import_module(name) + fullname, _ = test_util.submodule(name, subname, pkg_dir) + spec = self.util.find_spec(fullname) + self.assertIsNot(spec, None) + self.assertIn(name, sorted(sys.modules)) + self.assertNotIn(fullname, sorted(sys.modules)) + # Ensure successive calls behave the same. + spec_again = self.util.find_spec(fullname) + self.assertEqual(spec_again, spec) + + def test_find_relative_module(self): + name = 'spam' + subname = 'ham' + with test_util.temp_module(name, pkg=True) as pkg_dir: + fullname, _ = test_util.submodule(name, subname, pkg_dir) + relname = '.' + subname + spec = self.util.find_spec(relname, name) + self.assertIsNot(spec, None) + self.assertIn(name, sorted(sys.modules)) + self.assertNotIn(fullname, sorted(sys.modules)) + # Ensure successive calls behave the same. + spec_again = self.util.find_spec(fullname) + self.assertEqual(spec_again, spec) + + def test_find_relative_module_missing_package(self): + name = 'spam' + subname = 'ham' + with test_util.temp_module(name, pkg=True) as pkg_dir: + fullname, _ = test_util.submodule(name, subname, pkg_dir) + relname = '.' + subname + with self.assertRaises(ValueError): + self.util.find_spec(relname) + self.assertNotIn(name, sorted(sys.modules)) + self.assertNotIn(fullname, sorted(sys.modules)) + + +class Frozen_FindSpecTests(FindSpecTests, unittest.TestCase): + init = frozen_init + machinery = frozen_machinery + util = frozen_util + +class Source_FindSpecTests(FindSpecTests, unittest.TestCase): + init = source_init + machinery = source_machinery + util = source_util + + class MagicNumberTests: def test_length(self): diff --git a/Lib/test/test_importlib/util.py b/Lib/test/test_importlib/util.py --- a/Lib/test/test_importlib/util.py +++ b/Lib/test/test_importlib/util.py @@ -1,5 +1,5 @@ from contextlib import contextmanager -from importlib import util +from importlib import util, invalidate_caches import os.path from test import support import unittest @@ -46,6 +46,13 @@ "requires a case-insensitive filesystem")(test) +def submodule(parent, name, pkg_dir, content=''): + path = os.path.join(pkg_dir, name + '.py') + with open(path, 'w') as subfile: + subfile.write(content) + return '{}.{}'.format(parent, name), path + + @contextmanager def uncache(*names): """Uncache a module from sys.modules. @@ -71,6 +78,31 @@ except KeyError: pass + + at contextmanager +def temp_module(name, content='', *, pkg=False): + conflicts = [n for n in sys.modules if n.partition('.')[0] == name] + with support.temp_cwd(None) as cwd: + with uncache(name, *conflicts): + with support.DirsOnSysPath(cwd): + invalidate_caches() + + location = os.path.join(cwd, name) + if pkg: + modpath = os.path.join(location, '__init__.py') + os.mkdir(name) + else: + modpath = location + '.py' + if content is None: + # Make sure the module file gets created. + content = '' + if content is not None: + # not a namespace package + with open(modpath, 'w') as modfile: + modfile.write(content) + yield location + + @contextmanager def import_state(**kwargs): """Context manager to manage the various importers and stored state in the diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -382,6 +382,9 @@ - Issue #15475: Add __sizeof__ implementations for itertools objects. +- Issue #19944: Fix importlib.find_spec() so it imports parents as needed + and move the function to importlib.util. + - Issue #19880: Fix a reference leak in unittest.TestCase. Explicitly break reference cycles between frames and the _Outcome instance. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat Jan 25 23:53:42 2014 From: python-checkins at python.org (victor.stinner) Date: Sat, 25 Jan 2014 23:53:42 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320311=3A_Fix_test?= =?utf-8?q?=5Ftelnetlib=2C_set_the_resolution_of_the_MockSelector?= Message-ID: <3fBXZZ1MpDz7LjS@mail.python.org> http://hg.python.org/cpython/rev/f453443c96e4 changeset: 88711:f453443c96e4 user: Victor Stinner date: Sat Jan 25 23:53:28 2014 +0100 summary: Issue #20311: Fix test_telnetlib, set the resolution of the MockSelector files: Lib/test/test_telnetlib.py | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_telnetlib.py b/Lib/test/test_telnetlib.py --- a/Lib/test/test_telnetlib.py +++ b/Lib/test/test_telnetlib.py @@ -116,6 +116,10 @@ def __init__(self): self.keys = {} + @property + def resolution(self): + return 1e-3 + def register(self, fileobj, events, data=None): key = selectors.SelectorKey(fileobj, 0, events, data) self.keys[fileobj] = key -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 00:03:07 2014 From: python-checkins at python.org (victor.stinner) Date: Sun, 26 Jan 2014 00:03:07 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Merge_latest_Tulip_into_as?= =?utf-8?q?yncio?= Message-ID: <3fBXnR56Pzz7LjS@mail.python.org> http://hg.python.org/cpython/rev/5011e0d64c8b changeset: 88712:5011e0d64c8b user: Victor Stinner date: Sun Jan 26 00:02:31 2014 +0100 summary: Merge latest Tulip into asyncio - Make the new granularity attribute private - Simplify BaseEventLoop._run_once(): avoid math.ceil(), use simple arithmetic instead files: Doc/library/asyncio-eventloop.rst | 6 ------ Lib/asyncio/base_events.py | 9 ++------- Lib/asyncio/selector_events.py | 2 +- Lib/test/test_asyncio/test_events.py | 4 ++-- 4 files changed, 5 insertions(+), 16 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 @@ -144,12 +144,6 @@ Return the current time, as a :class:`float` value, according to the event loop's internal clock. -.. attribute:: BaseEventLoop.granularity - - Granularity of the time: maximum between the resolution of the - :meth:`BaseEventLoop.time` method and the resolution of the selector (see - :attr:`selectors.BaseSelector.resolution`). - .. seealso:: The :func:`asyncio.sleep` function. 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 @@ -18,7 +18,6 @@ import concurrent.futures import heapq import logging -import math import socket import subprocess import time @@ -97,7 +96,7 @@ self._default_executor = None self._internal_fds = 0 self._running = False - self.granularity = time.get_clock_info('monotonic').resolution + self._granularity = time.get_clock_info('monotonic').resolution def _make_socket_transport(self, sock, protocol, waiter=None, *, extra=None, server=None): @@ -605,8 +604,6 @@ elif self._scheduled: # Compute the desired timeout. when = self._scheduled[0]._when - # round deadline aways from zero - when = math.ceil(when / self.granularity) * self.granularity deadline = max(0, when - self.time()) if timeout is None: timeout = deadline @@ -632,9 +629,7 @@ self._process_events(event_list) # Handle 'later' callbacks that are ready. - now = self.time() - # round current time aways from zero - now = math.ceil(now / self.granularity) * self.granularity + now = self.time() + self._granularity while self._scheduled: handle = self._scheduled[0] if handle._when > now: 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 @@ -36,7 +36,7 @@ selector = selectors.DefaultSelector() logger.debug('Using selector: %s', selector.__class__.__name__) self._selector = selector - self.granularity = max(selector.resolution, self.granularity) + self._granularity = max(selector.resolution, self._granularity) self._make_self_pipe() def _make_socket_transport(self, sock, protocol, waiter=None, *, 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 @@ -1170,9 +1170,9 @@ def wait(): loop = self.loop calls.append(loop._run_once_counter) - yield from asyncio.sleep(loop.granularity * 10, loop=loop) + yield from asyncio.sleep(loop._granularity * 10, loop=loop) calls.append(loop._run_once_counter) - yield from asyncio.sleep(loop.granularity / 10, loop=loop) + yield from asyncio.sleep(loop._granularity / 10, loop=loop) calls.append(loop._run_once_counter) self.loop.run_until_complete(wait()) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 01:32:35 2014 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 26 Jan 2014 01:32:35 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Fix_race_in_Fas?= =?utf-8?q?tChildWatcher_=28by_its_original_author=2C_Anthony_Baire=29=2E?= Message-ID: <3fBZmg430wz7LjV@mail.python.org> http://hg.python.org/cpython/rev/3d8c91924a41 changeset: 88713:3d8c91924a41 user: Guido van Rossum date: Sat Jan 25 16:32:17 2014 -0800 summary: asyncio: Fix race in FastChildWatcher (by its original author, Anthony Baire). files: Lib/asyncio/unix_events.py | 36 +++++++++++-------------- 1 files changed, 16 insertions(+), 20 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 @@ -641,22 +641,16 @@ def add_child_handler(self, pid, callback, *args): assert self._forks, "Must use the context manager" + with self._lock: + try: + returncode = self._zombies.pop(pid) + except KeyError: + # The child is running. + self._callbacks[pid] = callback, args + return - self._callbacks[pid] = callback, args - - try: - # Ensure that the child is not already terminated. - # (raise KeyError if still alive) - returncode = self._zombies.pop(pid) - - # Child is dead, therefore we can fire the callback immediately. - # First we remove it from the dict. - # (raise KeyError if .remove_child_handler() was called in-between) - del self._callbacks[pid] - except KeyError: - pass - else: - callback(pid, returncode, *args) + # The child is dead already. We can fire the callback. + callback(pid, returncode, *args) def remove_child_handler(self, pid): try: @@ -681,16 +675,18 @@ returncode = self._compute_returncode(status) - try: - callback, args = self._callbacks.pop(pid) - except KeyError: - # unknown child - with self._lock: + with self._lock: + try: + callback, args = self._callbacks.pop(pid) + except KeyError: + # unknown child if self._forks: # It may not be registered yet. self._zombies[pid] = returncode continue + callback = None + if callback is None: logger.warning( "Caught subprocess termination from unknown pid: " "%d -> %d", pid, returncode) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 01:52:16 2014 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 26 Jan 2014 01:52:16 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Locks_refactor?= =?utf-8?q?=3A_use_a_separate_context_manager=3B_remove?= Message-ID: <3fBbCN2Z4mz7LkR@mail.python.org> http://hg.python.org/cpython/rev/0f831481bbe9 changeset: 88714:0f831481bbe9 user: Guido van Rossum date: Sat Jan 25 16:51:57 2014 -0800 summary: asyncio: Locks refactor: use a separate context manager; remove Semaphore._locked. files: Lib/asyncio/locks.py | 82 ++++++++++++---- Lib/test/test_asyncio/test_locks.py | 35 +++++++ 2 files changed, 95 insertions(+), 22 deletions(-) diff --git a/Lib/asyncio/locks.py b/Lib/asyncio/locks.py --- a/Lib/asyncio/locks.py +++ b/Lib/asyncio/locks.py @@ -9,6 +9,36 @@ from . import tasks +class _ContextManager: + """Context manager. + + This enables the following idiom for acquiring and releasing a + lock around a block: + + with (yield from lock): + + + while failing loudly when accidentally using: + + with lock: + + """ + + def __init__(self, lock): + self._lock = lock + + def __enter__(self): + # We have no use for the "as ..." clause in the with + # statement for locks. + return None + + def __exit__(self, *args): + try: + self._lock.release() + finally: + self._lock = None # Crudely prevent reuse. + + class Lock: """Primitive lock objects. @@ -124,17 +154,29 @@ raise RuntimeError('Lock is not acquired.') def __enter__(self): - if not self._locked: - raise RuntimeError( - '"yield from" should be used as context manager expression') - return True + raise RuntimeError( + '"yield from" should be used as context manager expression') def __exit__(self, *args): - self.release() + # This must exist because __enter__ exists, even though that + # always raises; that's how the with-statement works. + pass def __iter__(self): + # This is not a coroutine. It is meant to enable the idiom: + # + # with (yield from lock): + # + # + # as an alternative to: + # + # yield from lock.acquire() + # try: + # + # finally: + # lock.release() yield from self.acquire() - return self + return _ContextManager(self) class Event: @@ -311,14 +353,16 @@ self.notify(len(self._waiters)) def __enter__(self): - return self._lock.__enter__() + raise RuntimeError( + '"yield from" should be used as context manager expression') def __exit__(self, *args): - return self._lock.__exit__(*args) + pass def __iter__(self): + # See comment in Lock.__iter__(). yield from self.acquire() - return self + return _ContextManager(self) class Semaphore: @@ -341,7 +385,6 @@ raise ValueError("Semaphore initial value must be >= 0") self._value = value self._waiters = collections.deque() - self._locked = (value == 0) if loop is not None: self._loop = loop else: @@ -349,7 +392,7 @@ def __repr__(self): res = super().__repr__() - extra = 'locked' if self._locked else 'unlocked,value:{}'.format( + extra = 'locked' if self.locked() else 'unlocked,value:{}'.format( self._value) if self._waiters: extra = '{},waiters:{}'.format(extra, len(self._waiters)) @@ -357,7 +400,7 @@ def locked(self): """Returns True if semaphore can not be acquired immediately.""" - return self._locked + return self._value == 0 @tasks.coroutine def acquire(self): @@ -371,8 +414,6 @@ """ if not self._waiters and self._value > 0: self._value -= 1 - if self._value == 0: - self._locked = True return True fut = futures.Future(loop=self._loop) @@ -380,8 +421,6 @@ try: yield from fut self._value -= 1 - if self._value == 0: - self._locked = True return True finally: self._waiters.remove(fut) @@ -392,23 +431,22 @@ become larger than zero again, wake up that coroutine. """ self._value += 1 - self._locked = False for waiter in self._waiters: if not waiter.done(): waiter.set_result(True) break def __enter__(self): - # TODO: This is questionable. How do we know the user actually - # wrote "with (yield from sema)" instead of "with sema"? - return True + raise RuntimeError( + '"yield from" should be used as context manager expression') def __exit__(self, *args): - self.release() + pass def __iter__(self): + # See comment in Lock.__iter__(). yield from self.acquire() - return self + return _ContextManager(self) class BoundedSemaphore(Semaphore): diff --git a/Lib/test/test_asyncio/test_locks.py b/Lib/test/test_asyncio/test_locks.py --- a/Lib/test/test_asyncio/test_locks.py +++ b/Lib/test/test_asyncio/test_locks.py @@ -208,6 +208,24 @@ self.assertFalse(lock.locked()) + def test_context_manager_cant_reuse(self): + lock = asyncio.Lock(loop=self.loop) + + @asyncio.coroutine + def acquire_lock(): + return (yield from lock) + + # This spells "yield from lock" outside a generator. + cm = self.loop.run_until_complete(acquire_lock()) + with cm: + self.assertTrue(lock.locked()) + + self.assertFalse(lock.locked()) + + with self.assertRaises(AttributeError): + with cm: + pass + def test_context_manager_no_yield(self): lock = asyncio.Lock(loop=self.loop) @@ -219,6 +237,8 @@ str(err), '"yield from" should be used as context manager expression') + self.assertFalse(lock.locked()) + class EventTests(unittest.TestCase): @@ -655,6 +675,8 @@ str(err), '"yield from" should be used as context manager expression') + self.assertFalse(cond.locked()) + class SemaphoreTests(unittest.TestCase): @@ -830,6 +852,19 @@ self.assertEqual(2, sem._value) + def test_context_manager_no_yield(self): + sem = asyncio.Semaphore(2, loop=self.loop) + + try: + with sem: + self.fail('RuntimeError is not raised in with expression') + except RuntimeError as err: + self.assertEqual( + str(err), + '"yield from" should be used as context manager expression') + + self.assertEqual(2, sem._value) + if __name__ == '__main__': unittest.main() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 02:25:10 2014 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 26 Jan 2014 02:25:10 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Rename_=7BEmpty?= =?utf-8?q?=2CFull=7D_to_=7BQueueEmpty=2CQueueFull=7D_and_no_longer_get_th?= =?utf-8?q?em?= Message-ID: <3fBbxL13yWzS64@mail.python.org> http://hg.python.org/cpython/rev/c853a4784082 changeset: 88715:c853a4784082 user: Guido van Rossum date: Sat Jan 25 17:24:51 2014 -0800 summary: asyncio: Rename {Empty,Full} to {QueueEmpty,QueueFull} and no longer get them from queue.py. files: Lib/asyncio/queues.py | 28 ++++++++++----- Lib/test/test_asyncio/test_queues.py | 4 +- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/Lib/asyncio/queues.py b/Lib/asyncio/queues.py --- a/Lib/asyncio/queues.py +++ b/Lib/asyncio/queues.py @@ -1,11 +1,10 @@ """Queues""" __all__ = ['Queue', 'PriorityQueue', 'LifoQueue', 'JoinableQueue', - 'Full', 'Empty'] + 'QueueFull', 'QueueEmpty'] import collections import heapq -import queue from . import events from . import futures @@ -13,9 +12,20 @@ from .tasks import coroutine -# Re-export queue.Full and .Empty exceptions. -Full = queue.Full -Empty = queue.Empty +class QueueEmpty(Exception): + 'Exception raised by Queue.get(block=0)/get_nowait().' + pass + + +class QueueFull(Exception): + 'Exception raised by Queue.put(block=0)/put_nowait().' + pass + + +# Un-exported aliases for temporary backward compatibility. +# Will disappear soon. +Full = QueueFull +Empty = QueueEmpty class Queue: @@ -134,7 +144,7 @@ def put_nowait(self, item): """Put an item into the queue without blocking. - If no free slot is immediately available, raise Full. + If no free slot is immediately available, raise QueueFull. """ self._consume_done_getters() if self._getters: @@ -149,7 +159,7 @@ getter.set_result(self._get()) elif self._maxsize > 0 and self._maxsize == self.qsize(): - raise Full + raise QueueFull else: self._put(item) @@ -184,7 +194,7 @@ def get_nowait(self): """Remove and return an item from the queue. - Return an item if one is immediately available, else raise Empty. + Return an item if one is immediately available, else raise QueueEmpty. """ self._consume_done_putters() if self._putters: @@ -199,7 +209,7 @@ elif self.qsize(): return self._get() else: - raise Empty + raise QueueEmpty class PriorityQueue(Queue): diff --git a/Lib/test/test_asyncio/test_queues.py b/Lib/test/test_asyncio/test_queues.py --- a/Lib/test/test_asyncio/test_queues.py +++ b/Lib/test/test_asyncio/test_queues.py @@ -230,7 +230,7 @@ def test_nonblocking_get_exception(self): q = asyncio.Queue(loop=self.loop) - self.assertRaises(asyncio.Empty, q.get_nowait) + self.assertRaises(asyncio.QueueEmpty, q.get_nowait) def test_get_cancelled(self): @@ -337,7 +337,7 @@ def test_nonblocking_put_exception(self): q = asyncio.Queue(maxsize=1, loop=self.loop) q.put_nowait(1) - self.assertRaises(asyncio.Full, q.put_nowait, 2) + self.assertRaises(asyncio.QueueFull, q.put_nowait, 2) def test_put_cancelled(self): q = asyncio.Queue(loop=self.loop) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 02:30:39 2014 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 26 Jan 2014 02:30:39 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_NEWS_update_for_asyncio=2E?= Message-ID: <3fBc3g3chfz7LmQ@mail.python.org> http://hg.python.org/cpython/rev/4c685807ba06 changeset: 88716:4c685807ba06 user: Guido van Rossum date: Sat Jan 25 17:30:19 2014 -0800 summary: NEWS update for asyncio. files: Misc/NEWS | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,13 @@ Library ------- +- asyncio: Various improvements and small changes not all covered by + issues listed below. E.g. wait_for() now cancels the inner task if + the timeout occcurs; tweaked the set of exported symbols; renamed + Empty/Full to QueueEmpty/QueueFull; "with (yield from lock)" now + uses a separate context manager; readexactly() raises if not enough + data was read; PTY support tweaks. + - Issue #20311: asyncio: Add a granularity attribute to BaseEventLoop: maximum between the resolution of the BaseEventLoop.time() method and the resolution of the selector. The granuarility is used in the scheduler to round time and -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 02:38:50 2014 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 26 Jan 2014 02:38:50 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Document_asyncio=2EQueueFu?= =?utf-8?q?ll/Empty=2E?= Message-ID: <3fBcF65Zf2z7LjS@mail.python.org> http://hg.python.org/cpython/rev/9651fc0e7580 changeset: 88717:9651fc0e7580 user: Guido van Rossum date: Sat Jan 25 17:38:31 2014 -0800 summary: Document asyncio.QueueFull/Empty. files: Doc/library/asyncio-sync.rst | 20 ++++++++++++++++++-- 1 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Doc/library/asyncio-sync.rst b/Doc/library/asyncio-sync.rst --- a/Doc/library/asyncio-sync.rst +++ b/Doc/library/asyncio-sync.rst @@ -286,7 +286,7 @@ Remove and return an item from the queue. Return an item if one is immediately available, else raise - :exc:`~queue.Empty`. + :exc:`QueueEmpty`. .. method:: put(item) @@ -301,7 +301,7 @@ Put an item into the queue without blocking. - If no free slot is immediately available, raise :exc:`~queue.Full`. + If no free slot is immediately available, raise :exc:`QueueFull`. .. method:: qsize() @@ -367,3 +367,19 @@ Raises :exc:`ValueError` if called more times than there were items placed in the queue. + +Exceptions +^^^^^^^^^^ + +.. exception:: QueueEmpty + + Exception raised when non-blocking :meth:`~Queue.get` (or + :meth:`~Queue.get_nowait`) is called + on a :class:`Queue` object which is empty. + + +.. exception:: QueueFull + + Exception raised when non-blocking :meth:`~Queue.put` (or + :meth:`~Queue.put_nowait`) is called + on a :class:`Queue` object which is full. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 05:44:02 2014 From: python-checkins at python.org (larry.hastings) Date: Sun, 26 Jan 2014 05:44:02 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320390=3A_Small_fi?= =?utf-8?q?xes_and_improvements_for_Argument_Clinic=2E?= Message-ID: <3fBhLp3Mgpz7LjS@mail.python.org> http://hg.python.org/cpython/rev/9c5b421cc7de changeset: 88718:9c5b421cc7de user: Larry Hastings date: Sat Jan 25 20:43:29 2014 -0800 summary: Issue #20390: Small fixes and improvements for Argument Clinic. files: Include/object.h | 8 +- Misc/NEWS | 25 +++- Modules/_bz2module.c | 11 +- Modules/_cursesmodule.c | 10 +- Modules/_datetimemodule.c | 2 +- Modules/_dbmmodule.c | 2 +- Modules/_pickle.c | 49 +------- Modules/_sre.c | 3 +- Modules/audioop.c | 1 - Modules/_bz2module.clinic.c | 11 +- Modules/_lzmamodule.c | 4 +- Modules/audioop.clinic.c | 0 Modules/binascii.clinic.c | 0 Modules/unicodedata.c | 13 +- Modules/zlibmodule.c | 8 +- Objects/dictobject.c | 9 +- Objects/unicodeobject.c | 2 +- Tools/clinic/clinic.py | 133 +++++++++++++++++------ 18 files changed, 165 insertions(+), 126 deletions(-) diff --git a/Include/object.h b/Include/object.h --- a/Include/object.h +++ b/Include/object.h @@ -492,8 +492,12 @@ PyAPI_FUNC(unsigned int) PyType_ClearCache(void); PyAPI_FUNC(void) PyType_Modified(PyTypeObject *); -PyAPI_FUNC(PyObject *) _PyType_GetDocFromInternalDoc(const char *name, const char *internal_doc); -PyAPI_FUNC(PyObject *) _PyType_GetTextSignatureFromInternalDoc(const char *name, const char *internal_doc); +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) +_PyType_GetDocFromInternalDoc(const char *, const char *); +PyAPI_FUNC(PyObject *) +_PyType_GetTextSignatureFromInternalDoc(const char *, const char *); +#endif /* Generic operations on objects */ struct _Py_Identifier; diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,10 +2,10 @@ Python News +++++++++++ -What's New in Python 3.4.0 Release Candidate 1? -=============================================== - -Release date: 2014-01-19 +What's New in Python 3.4.0 Beta 3? +================================== + +Release date: 2014-01-25 Core and Builtins ----------------- @@ -147,6 +147,23 @@ Tools/Demos ----------- +- Issue #20390: Argument Clinic's "file" output preset now defaults to + "{dirname}/clinic/{basename}.h". + +- Issue #20390: Argument Clinic's "class" directive syntax has been extended + with two new required arguments: "typedef" and "type_object". + +- Issue #20390: Argument Clinic: If __new__ or __init__ functions didn't use + kwargs (or args), the PyArg_NoKeywords (or PyArg_NoPositional) calls + generated are only run when the type object is an exact match. + +- Issue #20390: Argument Clinic now fails if you have required parameters after + optional parameters. + +- Issue #20390: Argument Clinic converters now have a new template they can + inject code into: "modifiers". Code put there is run in the parsing + function after argument parsing but before the call to the impl. + - Issue #20376: Argument Clinic now escapes backslashes in docstrings. - Issue #20381: Argument Clinic now sanity checks the default argument when diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -199,8 +199,8 @@ /*[clinic input] output preset file module _bz2 -class _bz2.BZ2Compressor -class _bz2.BZ2Decompressor +class _bz2.BZ2Compressor "BZ2Compressor *" "&BZ2Compressor_Type" +class _bz2.BZ2Decompressor "BZ2Decompressor *" "&BZ2Decompressor_Type" [clinic start generated code]*/ /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ @@ -209,7 +209,6 @@ /*[clinic input] _bz2.BZ2Compressor.compress - self: self(type="BZ2Compressor *") data: Py_buffer / @@ -239,8 +238,6 @@ /*[clinic input] _bz2.BZ2Compressor.flush - self: self(type="BZ2Compressor *") - Finish the compression process. Returns the compressed data left in internal buffers. @@ -294,7 +291,6 @@ /*[clinic input] _bz2.BZ2Compressor.__init__ - self: self(type="BZ2Compressor *") compresslevel: int = 9 Compression level, as a number between 1 and 9. / @@ -472,7 +468,6 @@ /*[clinic input] _bz2.BZ2Decompressor.decompress - self: self(type="BZ2Decompressor *") data: Py_buffer / @@ -511,8 +506,6 @@ /*[clinic input] _bz2.BZ2Decompressor.__init__ - self: self(type="BZ2Decompressor *") - Create a decompressor object for decompressing data incrementally. For one-shot decompression, use the decompress() function instead. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -136,7 +136,7 @@ /*[clinic input] module curses -class curses.window +class curses.window "PyCursesWindowObject *" "&PyCursesWindow_Type" [clinic start generated code]*/ /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ @@ -605,10 +605,10 @@ {"addch", (PyCFunction)curses_window_addch, METH_VARARGS, curses_window_addch__doc__}, static PyObject * -curses_window_addch_impl(PyObject *self, int group_left_1, int x, int y, PyObject *ch, int group_right_1, long attr); +curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1, int x, int y, PyObject *ch, int group_right_1, long attr); static PyObject * -curses_window_addch(PyObject *self, PyObject *args) +curses_window_addch(PyCursesWindowObject *self, PyObject *args) { PyObject *return_value = NULL; int group_left_1 = 0; @@ -650,8 +650,8 @@ } static PyObject * -curses_window_addch_impl(PyObject *self, int group_left_1, int x, int y, PyObject *ch, int group_right_1, long attr) -/*[clinic end generated code: checksum=f6eeada77a9ec085125f3a27e4a2095f2a4c50be]*/ +curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1, int x, int y, PyObject *ch, int group_right_1, long attr) +/*[clinic end generated code: checksum=e1cdbd4f4e42fc6b36fd4755d7e4bd5b58751ea1]*/ { PyCursesWindowObject *cwself = (PyCursesWindowObject *)self; int coordinates_group = group_left_1; diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -18,7 +18,7 @@ /*[clinic input] module datetime -class datetime.datetime +class datetime.datetime "PyDateTime_DateTime *" "&PyDateTime_DateTimeType" [clinic start generated code]*/ /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c --- a/Modules/_dbmmodule.c +++ b/Modules/_dbmmodule.c @@ -30,7 +30,7 @@ /*[clinic input] module dbm -class dbm.dbm +class dbm.dbm "dbmobject *" "&Dbmtype" [clinic start generated code]*/ /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -6,28 +6,13 @@ /*[clinic input] module _pickle -class _pickle.Pickler -class _pickle.PicklerMemoProxy -class _pickle.Unpickler -class _pickle.UnpicklerMemoProxy +class _pickle.Pickler "PicklerObject *" "&Pickler_Type" +class _pickle.PicklerMemoProxy "PicklerMemoProxyObject *" "&PicklerMemoProxyType" +class _pickle.Unpickler "UnpicklerObject *" "&Unpickler_Type" +class _pickle.UnpicklerMemoProxy "UnpicklerMemoProxyObject *" "&UnpicklerMemoProxyType" [clinic start generated code]*/ /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ -/*[python input] -class PicklerObject_converter(self_converter): - type = "PicklerObject *" - -class PicklerMemoProxyObject_converter(self_converter): - type = "PicklerMemoProxyObject *" - -class UnpicklerObject_converter(self_converter): - type = "UnpicklerObject *" - -class UnpicklerMemoProxyObject_converter(self_converter): - type = "UnpicklerMemoProxyObject *" -[python start generated code]*/ -/*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ - /* Bump this when new opcodes are added to the pickle protocol. */ enum { HIGHEST_PROTOCOL = 4, @@ -3878,8 +3863,6 @@ _pickle.Pickler.clear_memo - self: PicklerObject - Clears the pickler's "memo". The memo is the data structure that remembers which objects the @@ -3923,7 +3906,6 @@ _pickle.Pickler.dump - self: PicklerObject obj: object / @@ -4018,7 +4000,6 @@ _pickle.Pickler.__init__ - self: PicklerObject file: object protocol: object = NULL fix_imports: bool = True @@ -4158,8 +4139,6 @@ /*[clinic input] _pickle.PicklerMemoProxy.clear - self: PicklerMemoProxyObject - Remove all items from memo. [clinic start generated code]*/ @@ -4191,8 +4170,6 @@ /*[clinic input] _pickle.PicklerMemoProxy.copy - self: PicklerMemoProxyObject - Copy the memo to a new object. [clinic start generated code]*/ @@ -4254,8 +4231,6 @@ /*[clinic input] _pickle.PicklerMemoProxy.__reduce__ - self: PicklerMemoProxyObject - Implement pickle support. [clinic start generated code]*/ @@ -6310,17 +6285,17 @@ {"load", (PyCFunction)_pickle_Unpickler_load, METH_NOARGS, _pickle_Unpickler_load__doc__}, static PyObject * -_pickle_Unpickler_load_impl(PyObject *self); +_pickle_Unpickler_load_impl(UnpicklerObject *self); static PyObject * -_pickle_Unpickler_load(PyObject *self, PyObject *Py_UNUSED(ignored)) +_pickle_Unpickler_load(UnpicklerObject *self, PyObject *Py_UNUSED(ignored)) { return _pickle_Unpickler_load_impl(self); } static PyObject * -_pickle_Unpickler_load_impl(PyObject *self) -/*[clinic end generated code: checksum=fb1119422c5e03045d690d1cd6c457f1ca4c585d]*/ +_pickle_Unpickler_load_impl(UnpicklerObject *self) +/*[clinic end generated code: checksum=5ccece694e9898856d916e0a87f0133d4537ebb9]*/ { UnpicklerObject *unpickler = (UnpicklerObject*)self; @@ -6347,7 +6322,6 @@ _pickle.Unpickler.find_class - self: UnpicklerObject module_name: object global_name: object / @@ -6551,7 +6525,6 @@ _pickle.Unpickler.__init__ - self: UnpicklerObject file: object * fix_imports: bool = True @@ -6692,8 +6665,6 @@ /*[clinic input] _pickle.UnpicklerMemoProxy.clear - self: UnpicklerMemoProxyObject - Remove all items from memo. [clinic start generated code]*/ @@ -6727,8 +6698,6 @@ /*[clinic input] _pickle.UnpicklerMemoProxy.copy - self: UnpicklerMemoProxyObject - Copy the memo to a new object. [clinic start generated code]*/ @@ -6783,8 +6752,6 @@ /*[clinic input] _pickle.UnpicklerMemoProxy.__reduce__ - self: UnpicklerMemoProxyObject - Implement pickling support. [clinic start generated code]*/ diff --git a/Modules/_sre.c b/Modules/_sre.c --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -528,11 +528,10 @@ /*[clinic input] module _sre -class _sre.SRE_Pattern +class _sre.SRE_Pattern "PatternObject *" "&Pattern_Type" _sre.SRE_Pattern.match as pattern_match - self: self(type="PatternObject *") pattern: object pos: Py_ssize_t = 0 endpos: Py_ssize_t(c_default="PY_SSIZE_T_MAX") = sys.maxsize diff --git a/Modules/audioop.c b/Modules/audioop.c --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -393,7 +393,6 @@ /*[clinic input] output preset file module audioop -class audioop.error [clinic start generated code]*/ /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ diff --git a/Modules/_bz2module.clinic.c b/Modules/clinic/_bz2module.c.h rename from Modules/_bz2module.clinic.c rename to Modules/clinic/_bz2module.c.h --- a/Modules/_bz2module.clinic.c +++ b/Modules/clinic/_bz2module.c.h @@ -75,7 +75,8 @@ int return_value = -1; int compresslevel = 9; - if (!_PyArg_NoKeywords("BZ2Compressor", kwargs)) + if (({self_name} == {self_type_object}) && + !_PyArg_NoKeywords("BZ2Compressor", kwargs)) goto exit; if (!PyArg_ParseTuple(args, "|i:BZ2Compressor", @@ -137,13 +138,15 @@ { int return_value = -1; - if (!_PyArg_NoPositional("BZ2Decompressor", args)) + if (({self_name} == {self_type_object}) && + !_PyArg_NoPositional("BZ2Decompressor", args)) goto exit; - if (!_PyArg_NoKeywords("BZ2Decompressor", kwargs)) + if (({self_name} == {self_type_object}) && + !_PyArg_NoKeywords("BZ2Decompressor", kwargs)) goto exit; return_value = _bz2_BZ2Decompressor___init___impl((BZ2Decompressor *)self); exit: return return_value; } -/*[clinic end generated code: checksum=9bb33ae7d35494b7a5365f03f390e4b5b8b1bc49]*/ +/*[clinic end generated code: checksum=79ee0d9731dfe404baec35b704b2ca2179b9a6c0]*/ diff --git a/Modules/_lzmamodule.c b/Modules/clinic/_lzmamodule.c.h rename from Modules/_lzmamodule.c rename to Modules/clinic/_lzmamodule.c.h --- a/Modules/_lzmamodule.c +++ b/Modules/clinic/_lzmamodule.c.h @@ -472,8 +472,8 @@ /*[clinic input] output preset file module _lzma -class _lzma.LZMACompressor -class _lzma.LZMADecompressor +class _lzma.LZMACompressor "Compressor *" "&Compressor_type" +class _lzma.LZMADecompressor "Decompressor *" "&Decompressor_type" [clinic start generated code]*/ /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ diff --git a/Modules/audioop.clinic.c b/Modules/clinic/audioop.c.h rename from Modules/audioop.clinic.c rename to Modules/clinic/audioop.c.h diff --git a/Modules/binascii.clinic.c b/Modules/clinic/binascii.c.h rename from Modules/binascii.clinic.c rename to Modules/clinic/binascii.c.h diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -19,7 +19,7 @@ /*[clinic input] module unicodedata -class unicodedata.UCD +class unicodedata.UCD 'PreviousDBVersion *' '&UCD_Type' [clinic start generated code]*/ /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ @@ -140,10 +140,10 @@ {"decimal", (PyCFunction)unicodedata_UCD_decimal, METH_VARARGS, unicodedata_UCD_decimal__doc__}, static PyObject * -unicodedata_UCD_decimal_impl(PyObject *self, PyUnicodeObject *unichr, PyObject *default_value); +unicodedata_UCD_decimal_impl(PreviousDBVersion *self, PyUnicodeObject *unichr, PyObject *default_value); static PyObject * -unicodedata_UCD_decimal(PyObject *self, PyObject *args) +unicodedata_UCD_decimal(PreviousDBVersion *self, PyObject *args) { PyObject *return_value = NULL; PyUnicodeObject *unichr; @@ -160,15 +160,14 @@ } static PyObject * -unicodedata_UCD_decimal_impl(PyObject *self, PyUnicodeObject *unichr, PyObject *default_value) -/*[clinic end generated code: checksum=01826b179d497d8fd3842c56679ecbd4faddaa95]*/ +unicodedata_UCD_decimal_impl(PreviousDBVersion *self, PyUnicodeObject *unichr, PyObject *default_value) +/*[clinic end generated code: checksum=e1371a1a016e19fdd3cd2c1af1d1832df095f50b]*/ { - PyUnicodeObject *v = (PyUnicodeObject *)unichr; int have_old = 0; long rc; Py_UCS4 c; - c = getuchar(v); + c = getuchar(unichr); if (c == (Py_UCS4)-1) return NULL; diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -83,8 +83,8 @@ /*[clinic input] module zlib -class zlib.Compress -class zlib.Decompress +class zlib.Compress "compobject *" "&Comptype" +class zlib.Decompress "compobject *" "&Decomptype" [clinic start generated code]*/ /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ @@ -748,8 +748,6 @@ zlib.Decompress.decompress - self: self(type="compobject *") - data: Py_buffer The binary data to decompress. max_length: uint = 0 @@ -1030,8 +1028,6 @@ /*[clinic input] zlib.Compress.copy - self: self(type="compobject *") - Return a copy of the compression object. [clinic start generated code]*/ diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -70,7 +70,7 @@ #include "stringlib/eq.h" /*[clinic input] -class dict +class dict "PyDictObject *" "&PyDict_Type" [clinic start generated code]*/ /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ @@ -1694,7 +1694,6 @@ /*[clinic input] @classmethod dict.fromkeys - iterable: object value: object=None / @@ -2217,10 +2216,10 @@ {"__contains__", (PyCFunction)dict___contains__, METH_O|METH_COEXIST, dict___contains____doc__}, static PyObject * -dict___contains__(PyObject *self, PyObject *key) -/*[clinic end generated code: checksum=c4f85a39baac4776c4275ad5f072f7732c5f0806]*/ +dict___contains__(PyDictObject *self, PyObject *key) +/*[clinic end generated code: checksum=744ca54369dda9815a596304087f1b37fafa5960]*/ { - register PyDictObject *mp = (PyDictObject *)self; + register PyDictObject *mp = self; Py_hash_t hash; PyDictKeyEntry *ep; PyObject **value_addr; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -48,7 +48,7 @@ #endif /*[clinic input] -class str +class str "PyUnicodeObject *" "&PyUnicode_Type" [clinic start generated code]*/ /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -300,6 +300,10 @@ # Should be full lines with \n eol characters. self.initializers = [] + # The C statements needed to dynamically modify the values + # parsed by the parse call, before calling the impl. + self.modifications = [] + # The entries for the "keywords" array for PyArg_ParseTuple. # Should be individual strings representing the names. self.keywords = [] @@ -541,6 +545,7 @@ parser_definition_impl_call + {modifications} {return_value} = {c_basename}_impl({impl_arguments}); __________________________________________________ @@ -575,14 +580,14 @@ parser_definition_no_positional - if (!_PyArg_NoPositional("{name}", args)) + if ({self_type_check}!_PyArg_NoPositional("{name}", args)) goto exit; __________________________________________________ parser_definition_no_keywords - if (!_PyArg_NoKeywords("{name}", kwargs)) + if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs)) goto exit; __________________________________________________ @@ -691,7 +696,7 @@ impl_definition = templates['impl_definition'] impl_prototype = parser_prototype = parser_definition = None - parser_body_fields = None + parser_body_fields = () def parser_body(prototype, *fields): nonlocal parser_body_fields add, output = text_accumulator() @@ -1025,6 +1030,7 @@ template_dict['docstring'] = self.docstring_for_c_string(f) + template_dict['self_name'] = template_dict['self_type'] = template_dict['self_type_check'] = '' f_self.converter.set_template_dict(template_dict) f.return_converter.render(f, data) @@ -1032,6 +1038,7 @@ template_dict['declarations'] = "\n".join(data.declarations) template_dict['initializers'] = "\n\n".join(data.initializers) + template_dict['modifications'] = '\n\n'.join(data.modifications) template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"' template_dict['format_units'] = ''.join(data.format_units) template_dict['parse_arguments'] = ', '.join(data.parse_arguments) @@ -1060,6 +1067,7 @@ declarations=template_dict['declarations'], return_conversion=template_dict['return_conversion'], initializers=template_dict['initializers'], + modifications=template_dict['modifications'], cleanup=template_dict['cleanup'], ) @@ -1356,8 +1364,14 @@ fail("Too many arguments for destination " + name + " new " + type) if type =='file': d = {} - d['filename'] = filename = clinic.filename - d['basename'], d['extension'] = os.path.splitext(filename) + filename = clinic.filename + d['path'] = filename + dirname, basename = os.path.split(filename) + if not dirname: + dirname = '.' + d['dirname'] = dirname + d['basename'] = basename + d['basename_root'], d['basename_extension'] = os.path.splitext(filename) self.filename = args[0].format_map(d) if type == 'two-pass': self.id = None @@ -1476,7 +1490,7 @@ self.add_destination("buffer", "buffer") self.add_destination("two-pass", "two-pass") if filename: - self.add_destination("file", "file", "{basename}.clinic{extension}") + self.add_destination("file", "file", "{dirname}/clinic/{basename}.h") d = self.destinations.get self.field_destinations = collections.OrderedDict(( @@ -1572,6 +1586,14 @@ if destination.type == 'file': try: + dirname = os.path.dirname(destination.filename) + try: + os.makedirs(dirname) + except FileExistsError: + if not os.path.isdir(dirname): + fail("Can't write to destination {}, " + "can't make directory {}!".format( + destination.filename, dirname)) with open(destination.filename, "rt") as f: parser_2 = BlockParser(f.read(), language=self.language) blocks = list(parser_2) @@ -1696,10 +1718,12 @@ return "" class Class: - def __init__(self, name, module=None, cls=None): + def __init__(self, name, module=None, cls=None, typedef=None, type_object=None): self.name = name self.module = module self.cls = cls + self.typedef = typedef + self.type_object = type_object self.parent = cls or module self.classes = collections.OrderedDict() @@ -1980,6 +2004,7 @@ # Should we show this parameter in the generated # __text_signature__? This is *almost* always True. + # (It's only False for __new__, __init__, and METH_STATIC functions.) show_in_signature = True # Overrides the name used in a text signature. @@ -2050,6 +2075,11 @@ if initializers: data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip()) + # modifications + modifications = self.modify() + if modifications: + data.modifications.append('/* modifications for ' + name + ' */\n' + modifications.rstrip()) + # keywords data.keywords.append(original_name) @@ -2152,6 +2182,14 @@ """ return "" + def modify(self): + """ + The C statements required to modify this variable after parsing. + Returns a string containing this code indented at column 0. + If no initialization is necessary, returns an empty string. + """ + return "" + def cleanup(self): """ The C statements required to clean up after this variable. @@ -2463,6 +2501,12 @@ return "PyTypeObject *", "type" raise RuntimeError("Unhandled type of function f: " + repr(f.kind)) +def required_type_for_self_for_parser(f): + type, _ = correct_name_for_self(f) + if f.kind in (METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD): + return type + return None + class self_converter(CConverter): """ @@ -2526,12 +2570,7 @@ @property def parser_type(self): - kind = self.function.kind - if kind == METHOD_NEW: - return "PyTypeObject *" - if kind == METHOD_INIT: - return "PyObject *" - return self.type + return required_type_for_self_for_parser(self.function) or self.type def render(self, parameter, data): """ @@ -2554,6 +2593,7 @@ def set_template_dict(self, template_dict): template_dict['self_name'] = self.name template_dict['self_type'] = self.parser_type + template_dict['self_type_check'] = '({self_name} == {self_type_object}) &&\n ' @@ -2808,6 +2848,7 @@ self.keyword_only = False self.group = 0 self.parameter_state = self.ps_start + self.seen_positional_with_default = False self.indent = IndentStack() self.kind = CALLABLE self.coexist = False @@ -2825,11 +2866,15 @@ module, cls = self.clinic._module_and_class(fields) if cls: fail("Can't nest a module inside a class!") + + if name in module.classes: + fail("Already defined module " + repr(name) + "!") + m = Module(name, module) module.modules[name] = m self.block.signatures.append(m) - def directive_class(self, name): + def directive_class(self, name, typedef, type_object): fields = name.split('.') in_classes = False parent = self @@ -2837,11 +2882,12 @@ so_far = [] module, cls = self.clinic._module_and_class(fields) - c = Class(name, module, cls) - if cls: - cls.classes[name] = c - else: - module.classes[name] = c + parent = cls or module + if name in parent.classes: + fail("Already defined class " + repr(name) + "!") + + c = Class(name, module, cls, typedef, type_object) + parent.classes[name] = c self.block.signatures.append(c) def directive_set(self, name, value): @@ -3035,6 +3081,8 @@ else: existing_function = None if not existing_function: + print("class", cls, "module", module, "exsiting", existing) + print("cls. functions", cls.functions) fail("Couldn't find existing function " + repr(existing) + "!") fields = [x.strip() for x in full_name.split('.')] @@ -3113,8 +3161,11 @@ self.block.signatures.append(self.function) # insert a self converter automatically - _, name = correct_name_for_self(self.function) - sc = self.function.self_converter = self_converter(name, self.function) + type, name = correct_name_for_self(self.function) + kwargs = {} + if cls and type == "PyObject *": + kwargs['type'] = cls.typedef + sc = self.function.self_converter = self_converter(name, self.function, **kwargs) p_self = Parameter(sc.name, inspect.Parameter.POSITIONAL_ONLY, function=self.function, converter=sc) self.function.parameters[sc.name] = p_self @@ -3175,18 +3226,21 @@ # "parameter_state". (Previously the code was a miasma of ifs and # separate boolean state variables.) The states are: # - # [ [ a, b, ] c, ] d, e, f, [ g, h, [ i ] ] / <- line - # 01 2 3 4 5 6 <- state transitions + # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] / <- line + # 01 2 3 4 5 6 7 <- state transitions # # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3. # 1: ps_left_square_before. left square brackets before required parameters. # 2: ps_group_before. in a group, before required parameters. - # 3: ps_required. required parameters. (renumber left groups!) - # 4: ps_group_after. in a group, after required parameters. - # 5: ps_right_square_after. right square brackets after required parameters. - # 6: ps_seen_slash. seen slash. + # 3: ps_required. required parameters, positional-or-keyword or positional-only + # (we don't know yet). (renumber left groups!) + # 4: ps_optional. positional-or-keyword or positional-only parameters that + # now must have default values. + # 5: ps_group_after. in a group, after required parameters. + # 6: ps_right_square_after. right square brackets after required parameters. + # 7: ps_seen_slash. seen slash. ps_start, ps_left_square_before, ps_group_before, ps_required, \ - ps_group_after, ps_right_square_after, ps_seen_slash = range(7) + ps_optional, ps_group_after, ps_right_square_after, ps_seen_slash = range(8) def state_parameters_start(self, line): if self.ignore_line(line): @@ -3245,21 +3299,25 @@ elif self.parameter_state == self.ps_group_before: if not self.group: self.to_required() - elif self.parameter_state == self.ps_group_after: + elif self.parameter_state in (self.ps_group_after, self.ps_optional): pass else: - fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")") + fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".a)") base, equals, default = line.rpartition('=') if not equals: base = default default = None + module = None try: ast_input = "def x({}): pass".format(base) module = ast.parse(ast_input) except SyntaxError: try: + # the last = was probably inside a function call, like + # i: int(nullable=True) + # so assume there was no actual default value. default = None ast_input = "def x({}): pass".format(line) module = ast.parse(ast_input) @@ -3275,13 +3333,18 @@ name, legacy, kwargs = self.parse_converter(parameter.annotation) if not default: + if self.parameter_state == self.ps_optional: + fail("Can't have a parameter without a default (" + repr(parameter_name) + ")\nafter a parameter with a default!") value = unspecified if 'py_default' in kwargs: fail("You can't specify py_default without specifying a default value!") else: + if self.parameter_state == self.ps_required: + self.parameter_state = self.ps_optional default = default.strip() bad = False ast_input = "x = {}".format(default) + bad = False try: module = ast.parse(ast_input) @@ -3441,7 +3504,7 @@ elif self.parameter_state in (self.ps_required, self.ps_group_after): self.parameter_state = self.ps_group_after else: - fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")") + fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)") self.group += 1 elif symbol == ']': if not self.group: @@ -3454,12 +3517,12 @@ elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after): self.parameter_state = self.ps_right_square_after else: - fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")") + fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".c)") elif symbol == '/': - # ps_required is allowed here, that allows positional-only without option groups + # ps_required and ps_optional are allowed here, that allows positional-only without option groups # to work (and have default values!) - if (self.parameter_state not in (self.ps_required, self.ps_right_square_after, self.ps_group_before)) or self.group: - fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")") + if (self.parameter_state not in (self.ps_required, self.ps_optional, self.ps_right_square_after, self.ps_group_before)) or self.group: + fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".d)") if self.keyword_only: fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.") self.parameter_state = self.ps_seen_slash -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 06:33:54 2014 From: python-checkins at python.org (larry.hastings) Date: Sun, 26 Jan 2014 06:33:54 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_for_catestrophic_error?= =?utf-8?q?s_in_previous_checkin_=28Argument_Clinic_rollup_patch=29=2E?= Message-ID: <3fBjSL0wQLz7LjV@mail.python.org> http://hg.python.org/cpython/rev/fe8bfa069389 changeset: 88719:fe8bfa069389 user: Larry Hastings date: Sat Jan 25 21:30:37 2014 -0800 summary: Fix for catestrophic errors in previous checkin (Argument Clinic rollup patch). files: Modules/_bz2module.c | 4 +- Modules/clinic/_lzmamodule.c.h | 2 +- Modules/audioop.c | 2 +- Modules/binascii.c | 2 +- Modules/clinic/_bz2module.c.h | 11 +- Modules/clinic/_lzmamodule.c.h | 1540 ++----------------- Tools/clinic/clinic.py | 6 +- 7 files changed, 206 insertions(+), 1361 deletions(-) diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -56,6 +56,8 @@ #endif } BZ2Decompressor; +static PyTypeObject BZ2Compressor_Type; +static PyTypeObject BZ2Decompressor_Type; /* Helper functions. */ @@ -204,7 +206,7 @@ [clinic start generated code]*/ /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ -#include "_bz2module.clinic.c" +#include "clinic/_bz2module.c.h" /*[clinic input] _bz2.BZ2Compressor.compress diff --git a/Modules/clinic/_lzmamodule.c.h b/Modules/_lzmamodule.c copy from Modules/clinic/_lzmamodule.c.h copy to Modules/_lzmamodule.c --- a/Modules/clinic/_lzmamodule.c.h +++ b/Modules/_lzmamodule.c @@ -477,7 +477,7 @@ [clinic start generated code]*/ /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ -#include "_lzmamodule.clinic.c" +#include "clinic/_lzmamodule.c.h" /*[python input] diff --git a/Modules/audioop.c b/Modules/audioop.c --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -1812,7 +1812,7 @@ return rv; } -#include "audioop.clinic.c" +#include "clinic/audioop.c.h" static PyMethodDef audioop_methods[] = { AUDIOOP_MAX_METHODDEF diff --git a/Modules/binascii.c b/Modules/binascii.c --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -236,7 +236,7 @@ return Py_CLEANUP_SUPPORTED; } -#include "binascii.clinic.c" +#include "clinic/binascii.c.h" /*[clinic input] binascii.a2b_uu diff --git a/Modules/clinic/_bz2module.c.h b/Modules/clinic/_bz2module.c.h --- a/Modules/clinic/_bz2module.c.h +++ b/Modules/clinic/_bz2module.c.h @@ -75,8 +75,7 @@ int return_value = -1; int compresslevel = 9; - if (({self_name} == {self_type_object}) && - !_PyArg_NoKeywords("BZ2Compressor", kwargs)) + if (!_PyArg_NoKeywords("BZ2Compressor", kwargs)) goto exit; if (!PyArg_ParseTuple(args, "|i:BZ2Compressor", @@ -138,15 +137,13 @@ { int return_value = -1; - if (({self_name} == {self_type_object}) && - !_PyArg_NoPositional("BZ2Decompressor", args)) + if (!_PyArg_NoPositional("BZ2Decompressor", args)) goto exit; - if (({self_name} == {self_type_object}) && - !_PyArg_NoKeywords("BZ2Decompressor", kwargs)) + if (!_PyArg_NoKeywords("BZ2Decompressor", kwargs)) goto exit; return_value = _bz2_BZ2Decompressor___init___impl((BZ2Decompressor *)self); exit: return return_value; } -/*[clinic end generated code: checksum=79ee0d9731dfe404baec35b704b2ca2179b9a6c0]*/ +/*[clinic end generated code: checksum=9bb33ae7d35494b7a5365f03f390e4b5b8b1bc49]*/ diff --git a/Modules/clinic/_lzmamodule.c.h b/Modules/clinic/_lzmamodule.c.h --- a/Modules/clinic/_lzmamodule.c.h +++ b/Modules/clinic/_lzmamodule.c.h @@ -1,1389 +1,231 @@ -/* _lzma - Low-level Python interface to liblzma. +/*[clinic input] +preserve +[clinic start generated code]*/ - Initial implementation by Per ?yvind Karlsen. - Rewritten by Nadeem Vawda. +PyDoc_STRVAR(_lzma_LZMACompressor_compress__doc__, +"compress(self, data)\n" +"Provide data to the compressor object.\n" +"\n" +"Returns a chunk of compressed data if possible, or b\'\' otherwise.\n" +"\n" +"When you have finished providing data to the compressor, call the\n" +"flush() method to finish the compression process."); -*/ +#define _LZMA_LZMACOMPRESSOR_COMPRESS_METHODDEF \ + {"compress", (PyCFunction)_lzma_LZMACompressor_compress, METH_VARARGS, _lzma_LZMACompressor_compress__doc__}, -#define PY_SSIZE_T_CLEAN +static PyObject * +_lzma_LZMACompressor_compress_impl(Compressor *self, Py_buffer *data); -#include "Python.h" -#include "structmember.h" -#ifdef WITH_THREAD -#include "pythread.h" -#endif +static PyObject * +_lzma_LZMACompressor_compress(Compressor *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; -#include -#include + if (!PyArg_ParseTuple(args, + "y*:compress", + &data)) + goto exit; + return_value = _lzma_LZMACompressor_compress_impl(self, &data); -#include +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + return return_value; +} -#ifndef PY_LONG_LONG -#error "This module requires PY_LONG_LONG to be defined" -#endif +PyDoc_STRVAR(_lzma_LZMACompressor_flush__doc__, +"flush(self)\n" +"Finish the compression process.\n" +"\n" +"Returns the compressed data left in internal buffers.\n" +"\n" +"The compressor object may not be used after this method is called."); +#define _LZMA_LZMACOMPRESSOR_FLUSH_METHODDEF \ + {"flush", (PyCFunction)_lzma_LZMACompressor_flush, METH_NOARGS, _lzma_LZMACompressor_flush__doc__}, -#ifdef WITH_THREAD -#define ACQUIRE_LOCK(obj) do { \ - if (!PyThread_acquire_lock((obj)->lock, 0)) { \ - Py_BEGIN_ALLOW_THREADS \ - PyThread_acquire_lock((obj)->lock, 1); \ - Py_END_ALLOW_THREADS \ - } } while (0) -#define RELEASE_LOCK(obj) PyThread_release_lock((obj)->lock) -#else -#define ACQUIRE_LOCK(obj) -#define RELEASE_LOCK(obj) -#endif +static PyObject * +_lzma_LZMACompressor_flush_impl(Compressor *self); +static PyObject * +_lzma_LZMACompressor_flush(Compressor *self, PyObject *Py_UNUSED(ignored)) +{ + return _lzma_LZMACompressor_flush_impl(self); +} -/* Container formats: */ -enum { - FORMAT_AUTO, - FORMAT_XZ, - FORMAT_ALONE, - FORMAT_RAW, -}; +PyDoc_STRVAR(_lzma_LZMADecompressor_decompress__doc__, +"decompress(self, data)\n" +"Provide data to the decompressor object.\n" +"\n" +"Returns a chunk of decompressed data if possible, or b\'\' otherwise.\n" +"\n" +"Attempting to decompress data after the end of stream is reached\n" +"raises an EOFError. Any data found after the end of the stream\n" +"is ignored and saved in the unused_data attribute."); -#define LZMA_CHECK_UNKNOWN (LZMA_CHECK_ID_MAX + 1) +#define _LZMA_LZMADECOMPRESSOR_DECOMPRESS_METHODDEF \ + {"decompress", (PyCFunction)_lzma_LZMADecompressor_decompress, METH_VARARGS, _lzma_LZMADecompressor_decompress__doc__}, +static PyObject * +_lzma_LZMADecompressor_decompress_impl(Decompressor *self, Py_buffer *data); -typedef struct { - PyObject_HEAD - lzma_allocator alloc; - lzma_stream lzs; - int flushed; -#ifdef WITH_THREAD - PyThread_type_lock lock; -#endif -} Compressor; +static PyObject * +_lzma_LZMADecompressor_decompress(Decompressor *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; -typedef struct { - PyObject_HEAD - lzma_allocator alloc; - lzma_stream lzs; - int check; - char eof; - PyObject *unused_data; -#ifdef WITH_THREAD - PyThread_type_lock lock; -#endif -} Decompressor; + if (!PyArg_ParseTuple(args, + "y*:decompress", + &data)) + goto exit; + return_value = _lzma_LZMADecompressor_decompress_impl(self, &data); -/* LZMAError class object. */ -static PyObject *Error; +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); -/* An empty tuple, used by the filter specifier parsing code. */ -static PyObject *empty_tuple; + return return_value; +} - -/* Helper functions. */ +PyDoc_STRVAR(_lzma_LZMADecompressor___init____doc__, +"LZMADecompressor(format=FORMAT_AUTO, memlimit=None, filters=None)\n" +"Create a decompressor object for decompressing data incrementally.\n" +"\n" +" format\n" +" Specifies the container format of the input stream. If this is\n" +" FORMAT_AUTO (the default), the decompressor will automatically detect\n" +" whether the input is FORMAT_XZ or FORMAT_ALONE. Streams created with\n" +" FORMAT_RAW cannot be autodetected.\n" +" memlimit\n" +" Limit the amount of memory used by the decompressor. This will cause\n" +" decompression to fail if the input cannot be decompressed within the\n" +" given limit.\n" +" filters\n" +" A custom filter chain. This argument is required for FORMAT_RAW, and\n" +" not accepted with any other format. When provided, this should be a\n" +" sequence of dicts, each indicating the ID and options for a single\n" +" filter.\n" +"\n" +"For one-shot decompression, use the decompress() function instead."); static int -catch_lzma_error(lzma_ret lzret) +_lzma_LZMADecompressor___init___impl(Decompressor *self, int format, PyObject *memlimit, PyObject *filters); + +static int +_lzma_LZMADecompressor___init__(PyObject *self, PyObject *args, PyObject *kwargs) { - switch (lzret) { - case LZMA_OK: - case LZMA_GET_CHECK: - case LZMA_NO_CHECK: - case LZMA_STREAM_END: - return 0; - case LZMA_UNSUPPORTED_CHECK: - PyErr_SetString(Error, "Unsupported integrity check"); - return 1; - case LZMA_MEM_ERROR: - PyErr_NoMemory(); - return 1; - case LZMA_MEMLIMIT_ERROR: - PyErr_SetString(Error, "Memory usage limit exceeded"); - return 1; - case LZMA_FORMAT_ERROR: - PyErr_SetString(Error, "Input format not supported by decoder"); - return 1; - case LZMA_OPTIONS_ERROR: - PyErr_SetString(Error, "Invalid or unsupported options"); - return 1; - case LZMA_DATA_ERROR: - PyErr_SetString(Error, "Corrupt input data"); - return 1; - case LZMA_BUF_ERROR: - PyErr_SetString(Error, "Insufficient buffer space"); - return 1; - case LZMA_PROG_ERROR: - PyErr_SetString(Error, "Internal error"); - return 1; - default: - PyErr_Format(Error, "Unrecognized error from liblzma: %d", lzret); - return 1; - } + int return_value = -1; + static char *_keywords[] = {"format", "memlimit", "filters", NULL}; + int format = FORMAT_AUTO; + PyObject *memlimit = Py_None; + PyObject *filters = Py_None; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "|iOO:LZMADecompressor", _keywords, + &format, &memlimit, &filters)) + goto exit; + return_value = _lzma_LZMADecompressor___init___impl((Decompressor *)self, format, memlimit, filters); + +exit: + return return_value; } -static void* -PyLzma_Malloc(void *opaque, size_t items, size_t size) +PyDoc_STRVAR(_lzma_is_check_supported__doc__, +"is_check_supported(module, check_id)\n" +"Test whether the given integrity check is supported.\n" +"\n" +"Always returns True for CHECK_NONE and CHECK_CRC32."); + +#define _LZMA_IS_CHECK_SUPPORTED_METHODDEF \ + {"is_check_supported", (PyCFunction)_lzma_is_check_supported, METH_VARARGS, _lzma_is_check_supported__doc__}, + +static PyObject * +_lzma_is_check_supported_impl(PyModuleDef *module, int check_id); + +static PyObject * +_lzma_is_check_supported(PyModuleDef *module, PyObject *args) { - if (items > (size_t)PY_SSIZE_T_MAX / size) - return NULL; - /* PyMem_Malloc() cannot be used: - the GIL is not held when lzma_code() is called */ - return PyMem_RawMalloc(items * size); + PyObject *return_value = NULL; + int check_id; + + if (!PyArg_ParseTuple(args, + "i:is_check_supported", + &check_id)) + goto exit; + return_value = _lzma_is_check_supported_impl(module, check_id); + +exit: + return return_value; } -static void -PyLzma_Free(void *opaque, void *ptr) +PyDoc_STRVAR(_lzma__encode_filter_properties__doc__, +"_encode_filter_properties(module, filter)\n" +"Return a bytes object encoding the options (properties) of the filter specified by *filter* (a dict).\n" +"\n" +"The result does not include the filter ID itself, only the options."); + +#define _LZMA__ENCODE_FILTER_PROPERTIES_METHODDEF \ + {"_encode_filter_properties", (PyCFunction)_lzma__encode_filter_properties, METH_VARARGS, _lzma__encode_filter_properties__doc__}, + +static PyObject * +_lzma__encode_filter_properties_impl(PyModuleDef *module, lzma_filter filter); + +static PyObject * +_lzma__encode_filter_properties(PyModuleDef *module, PyObject *args) { - PyMem_RawFree(ptr); + PyObject *return_value = NULL; + lzma_filter filter = {LZMA_VLI_UNKNOWN, NULL}; + + if (!PyArg_ParseTuple(args, + "O&:_encode_filter_properties", + lzma_filter_converter, &filter)) + goto exit; + return_value = _lzma__encode_filter_properties_impl(module, filter); + +exit: + /* Cleanup for filter */ + if (filter.id != LZMA_VLI_UNKNOWN) + PyMem_Free(filter.options); + + return return_value; } -#if BUFSIZ < 8192 -#define INITIAL_BUFFER_SIZE 8192 -#else -#define INITIAL_BUFFER_SIZE BUFSIZ -#endif +PyDoc_STRVAR(_lzma__decode_filter_properties__doc__, +"_decode_filter_properties(module, filter_id, encoded_props)\n" +"Return a bytes object encoding the options (properties) of the filter specified by *filter* (a dict).\n" +"\n" +"The result does not include the filter ID itself, only the options."); -static int -grow_buffer(PyObject **buf) -{ - size_t size = PyBytes_GET_SIZE(*buf); - return _PyBytes_Resize(buf, size + (size >> 3) + 6); -} - - -/* Some custom type conversions for PyArg_ParseTupleAndKeywords(), - since the predefined conversion specifiers do not suit our needs: - - uint32_t - the "I" (unsigned int) specifier is the right size, but - silently ignores overflows on conversion. - - lzma_vli - the "K" (unsigned PY_LONG_LONG) specifier is the right - size, but like "I" it silently ignores overflows on conversion. - - lzma_mode and lzma_match_finder - these are enumeration types, and - so the size of each is implementation-defined. Worse, different - enum types can be of different sizes within the same program, so - to be strictly correct, we need to define two separate converters. - */ - -#define INT_TYPE_CONVERTER_FUNC(TYPE, FUNCNAME) \ - static int \ - FUNCNAME(PyObject *obj, void *ptr) \ - { \ - unsigned PY_LONG_LONG val; \ - \ - val = PyLong_AsUnsignedLongLong(obj); \ - if (PyErr_Occurred()) \ - return 0; \ - if ((unsigned PY_LONG_LONG)(TYPE)val != val) { \ - PyErr_SetString(PyExc_OverflowError, \ - "Value too large for " #TYPE " type"); \ - return 0; \ - } \ - *(TYPE *)ptr = (TYPE)val; \ - return 1; \ - } - -INT_TYPE_CONVERTER_FUNC(uint32_t, uint32_converter) -INT_TYPE_CONVERTER_FUNC(lzma_vli, lzma_vli_converter) -INT_TYPE_CONVERTER_FUNC(lzma_mode, lzma_mode_converter) -INT_TYPE_CONVERTER_FUNC(lzma_match_finder, lzma_mf_converter) - -#undef INT_TYPE_CONVERTER_FUNC - - -/* Filter specifier parsing. - - This code handles converting filter specifiers (Python dicts) into - the C lzma_filter structs expected by liblzma. */ - -static void * -parse_filter_spec_lzma(PyObject *spec) -{ - static char *optnames[] = {"id", "preset", "dict_size", "lc", "lp", - "pb", "mode", "nice_len", "mf", "depth", NULL}; - PyObject *id; - PyObject *preset_obj; - uint32_t preset = LZMA_PRESET_DEFAULT; - lzma_options_lzma *options; - - /* First, fill in default values for all the options using a preset. - Then, override the defaults with any values given by the caller. */ - - preset_obj = PyMapping_GetItemString(spec, "preset"); - if (preset_obj == NULL) { - if (PyErr_ExceptionMatches(PyExc_KeyError)) - PyErr_Clear(); - else - return NULL; - } else { - int ok = uint32_converter(preset_obj, &preset); - Py_DECREF(preset_obj); - if (!ok) - return NULL; - } - - options = (lzma_options_lzma *)PyMem_Malloc(sizeof *options); - if (options == NULL) - return PyErr_NoMemory(); - memset(options, 0, sizeof *options); - - if (lzma_lzma_preset(options, preset)) { - PyMem_Free(options); - PyErr_Format(Error, "Invalid compression preset: %d", preset); - return NULL; - } - - if (!PyArg_ParseTupleAndKeywords(empty_tuple, spec, - "|OOO&O&O&O&O&O&O&O&", optnames, - &id, &preset_obj, - uint32_converter, &options->dict_size, - uint32_converter, &options->lc, - uint32_converter, &options->lp, - uint32_converter, &options->pb, - lzma_mode_converter, &options->mode, - uint32_converter, &options->nice_len, - lzma_mf_converter, &options->mf, - uint32_converter, &options->depth)) { - PyErr_SetString(PyExc_ValueError, - "Invalid filter specifier for LZMA filter"); - PyMem_Free(options); - options = NULL; - } - return options; -} - -static void * -parse_filter_spec_delta(PyObject *spec) -{ - static char *optnames[] = {"id", "dist", NULL}; - PyObject *id; - uint32_t dist = 1; - lzma_options_delta *options; - - if (!PyArg_ParseTupleAndKeywords(empty_tuple, spec, "|OO&", optnames, - &id, uint32_converter, &dist)) { - PyErr_SetString(PyExc_ValueError, - "Invalid filter specifier for delta filter"); - return NULL; - } - - options = (lzma_options_delta *)PyMem_Malloc(sizeof *options); - if (options == NULL) - return PyErr_NoMemory(); - memset(options, 0, sizeof *options); - options->type = LZMA_DELTA_TYPE_BYTE; - options->dist = dist; - return options; -} - -static void * -parse_filter_spec_bcj(PyObject *spec) -{ - static char *optnames[] = {"id", "start_offset", NULL}; - PyObject *id; - uint32_t start_offset = 0; - lzma_options_bcj *options; - - if (!PyArg_ParseTupleAndKeywords(empty_tuple, spec, "|OO&", optnames, - &id, uint32_converter, &start_offset)) { - PyErr_SetString(PyExc_ValueError, - "Invalid filter specifier for BCJ filter"); - return NULL; - } - - options = (lzma_options_bcj *)PyMem_Malloc(sizeof *options); - if (options == NULL) - return PyErr_NoMemory(); - memset(options, 0, sizeof *options); - options->start_offset = start_offset; - return options; -} - -static int -lzma_filter_converter(PyObject *spec, void *ptr) -{ - lzma_filter *f = (lzma_filter *)ptr; - PyObject *id_obj; - - if (!PyMapping_Check(spec)) { - PyErr_SetString(PyExc_TypeError, - "Filter specifier must be a dict or dict-like object"); - return 0; - } - id_obj = PyMapping_GetItemString(spec, "id"); - if (id_obj == NULL) { - if (PyErr_ExceptionMatches(PyExc_KeyError)) - PyErr_SetString(PyExc_ValueError, - "Filter specifier must have an \"id\" entry"); - return 0; - } - f->id = PyLong_AsUnsignedLongLong(id_obj); - Py_DECREF(id_obj); - if (PyErr_Occurred()) - return 0; - - switch (f->id) { - case LZMA_FILTER_LZMA1: - case LZMA_FILTER_LZMA2: - f->options = parse_filter_spec_lzma(spec); - return f->options != NULL; - case LZMA_FILTER_DELTA: - f->options = parse_filter_spec_delta(spec); - return f->options != NULL; - case LZMA_FILTER_X86: - case LZMA_FILTER_POWERPC: - case LZMA_FILTER_IA64: - case LZMA_FILTER_ARM: - case LZMA_FILTER_ARMTHUMB: - case LZMA_FILTER_SPARC: - f->options = parse_filter_spec_bcj(spec); - return f->options != NULL; - default: - PyErr_Format(PyExc_ValueError, "Invalid filter ID: %llu", f->id); - return 0; - } -} - -static void -free_filter_chain(lzma_filter filters[]) -{ - int i; - - for (i = 0; filters[i].id != LZMA_VLI_UNKNOWN; i++) - PyMem_Free(filters[i].options); -} - -static int -parse_filter_chain_spec(lzma_filter filters[], PyObject *filterspecs) -{ - Py_ssize_t i, num_filters; - - num_filters = PySequence_Length(filterspecs); - if (num_filters == -1) - return -1; - if (num_filters > LZMA_FILTERS_MAX) { - PyErr_Format(PyExc_ValueError, - "Too many filters - liblzma supports a maximum of %d", - LZMA_FILTERS_MAX); - return -1; - } - - for (i = 0; i < num_filters; i++) { - int ok = 1; - PyObject *spec = PySequence_GetItem(filterspecs, i); - if (spec == NULL || !lzma_filter_converter(spec, &filters[i])) - ok = 0; - Py_XDECREF(spec); - if (!ok) { - filters[i].id = LZMA_VLI_UNKNOWN; - free_filter_chain(filters); - return -1; - } - } - filters[num_filters].id = LZMA_VLI_UNKNOWN; - return 0; -} - - -/* Filter specifier construction. - - This code handles converting C lzma_filter structs into - Python-level filter specifiers (represented as dicts). */ - -static int -spec_add_field(PyObject *spec, _Py_Identifier *key, unsigned PY_LONG_LONG value) -{ - int status; - PyObject *value_object; - - value_object = PyLong_FromUnsignedLongLong(value); - if (value_object == NULL) - return -1; - - status = _PyDict_SetItemId(spec, key, value_object); - Py_DECREF(value_object); - return status; -} +#define _LZMA__DECODE_FILTER_PROPERTIES_METHODDEF \ + {"_decode_filter_properties", (PyCFunction)_lzma__decode_filter_properties, METH_VARARGS, _lzma__decode_filter_properties__doc__}, static PyObject * -build_filter_spec(const lzma_filter *f) -{ - PyObject *spec; - - spec = PyDict_New(); - if (spec == NULL) - return NULL; - -#define ADD_FIELD(SOURCE, FIELD) \ - do { \ - _Py_IDENTIFIER(FIELD); \ - if (spec_add_field(spec, &PyId_##FIELD, SOURCE->FIELD) == -1) \ - goto error;\ - } while (0) - - ADD_FIELD(f, id); - - switch (f->id) { - /* For LZMA1 filters, lzma_properties_{encode,decode}() only look at the - lc, lp, pb, and dict_size fields. For LZMA2 filters, only the - dict_size field is used. */ - case LZMA_FILTER_LZMA1: { - lzma_options_lzma *options = f->options; - ADD_FIELD(options, lc); - ADD_FIELD(options, lp); - ADD_FIELD(options, pb); - ADD_FIELD(options, dict_size); - break; - } - case LZMA_FILTER_LZMA2: { - lzma_options_lzma *options = f->options; - ADD_FIELD(options, dict_size); - break; - } - case LZMA_FILTER_DELTA: { - lzma_options_delta *options = f->options; - ADD_FIELD(options, dist); - break; - } - case LZMA_FILTER_X86: - case LZMA_FILTER_POWERPC: - case LZMA_FILTER_IA64: - case LZMA_FILTER_ARM: - case LZMA_FILTER_ARMTHUMB: - case LZMA_FILTER_SPARC: { - lzma_options_bcj *options = f->options; - ADD_FIELD(options, start_offset); - break; - } - default: - PyErr_Format(PyExc_ValueError, "Invalid filter ID: %llu", f->id); - goto error; - } - -#undef ADD_FIELD - - return spec; - -error: - Py_DECREF(spec); - return NULL; -} - - -/*[clinic input] -output preset file -module _lzma -class _lzma.LZMACompressor "Compressor *" "&Compressor_type" -class _lzma.LZMADecompressor "Decompressor *" "&Decompressor_type" -[clinic start generated code]*/ -/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ - -#include "_lzmamodule.clinic.c" - -/*[python input] - -class lzma_vli_converter(CConverter): - type = 'lzma_vli' - converter = 'lzma_vli_converter' - -class lzma_filter_converter(CConverter): - type = 'lzma_filter' - converter = 'lzma_filter_converter' - c_default = c_ignored_default = "{LZMA_VLI_UNKNOWN, NULL}" - - def cleanup(self): - name = ensure_legal_c_identifier(self.name) - return ('if (%(name)s.id != LZMA_VLI_UNKNOWN)\n' - ' PyMem_Free(%(name)s.options);\n') % {'name': name} - -[python start generated code]*/ -/*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ - - -/* LZMACompressor class. */ +_lzma__decode_filter_properties_impl(PyModuleDef *module, lzma_vli filter_id, Py_buffer *encoded_props); static PyObject * -compress(Compressor *c, uint8_t *data, size_t len, lzma_action action) +_lzma__decode_filter_properties(PyModuleDef *module, PyObject *args) { - size_t data_size = 0; - PyObject *result; + PyObject *return_value = NULL; + lzma_vli filter_id; + Py_buffer encoded_props = {NULL, NULL}; - result = PyBytes_FromStringAndSize(NULL, INITIAL_BUFFER_SIZE); - if (result == NULL) - return NULL; - c->lzs.next_in = data; - c->lzs.avail_in = len; - c->lzs.next_out = (uint8_t *)PyBytes_AS_STRING(result); - c->lzs.avail_out = PyBytes_GET_SIZE(result); - for (;;) { - lzma_ret lzret; + if (!PyArg_ParseTuple(args, + "O&y*:_decode_filter_properties", + lzma_vli_converter, &filter_id, &encoded_props)) + goto exit; + return_value = _lzma__decode_filter_properties_impl(module, filter_id, &encoded_props); - Py_BEGIN_ALLOW_THREADS - lzret = lzma_code(&c->lzs, action); - data_size = (char *)c->lzs.next_out - PyBytes_AS_STRING(result); - Py_END_ALLOW_THREADS - if (catch_lzma_error(lzret)) - goto error; - if ((action == LZMA_RUN && c->lzs.avail_in == 0) || - (action == LZMA_FINISH && lzret == LZMA_STREAM_END)) { - break; - } else if (c->lzs.avail_out == 0) { - if (grow_buffer(&result) == -1) - goto error; - c->lzs.next_out = (uint8_t *)PyBytes_AS_STRING(result) + data_size; - c->lzs.avail_out = PyBytes_GET_SIZE(result) - data_size; - } - } - if (data_size != PyBytes_GET_SIZE(result)) - if (_PyBytes_Resize(&result, data_size) == -1) - goto error; - return result; +exit: + /* Cleanup for encoded_props */ + if (encoded_props.obj) + PyBuffer_Release(&encoded_props); -error: - Py_XDECREF(result); - return NULL; + return return_value; } - -/*[clinic input] -_lzma.LZMACompressor.compress - - self: self(type="Compressor *") - data: Py_buffer - / - -Provide data to the compressor object. - -Returns a chunk of compressed data if possible, or b'' otherwise. - -When you have finished providing data to the compressor, call the -flush() method to finish the compression process. -[clinic start generated code]*/ - -static PyObject * -_lzma_LZMACompressor_compress_impl(Compressor *self, Py_buffer *data) -/*[clinic end generated code: checksum=31f615136963e00f26f8be33440ec1e3604565ba]*/ -{ - PyObject *result = NULL; - - ACQUIRE_LOCK(self); - if (self->flushed) - PyErr_SetString(PyExc_ValueError, "Compressor has been flushed"); - else - result = compress(self, data->buf, data->len, LZMA_RUN); - RELEASE_LOCK(self); - return result; -} - -/*[clinic input] -_lzma.LZMACompressor.flush - - self: self(type="Compressor *") - -Finish the compression process. - -Returns the compressed data left in internal buffers. - -The compressor object may not be used after this method is called. -[clinic start generated code]*/ - -static PyObject * -_lzma_LZMACompressor_flush_impl(Compressor *self) -/*[clinic end generated code: checksum=fec21f3e22504f500606ba60e1ba70d79eb22188]*/ -{ - PyObject *result = NULL; - - ACQUIRE_LOCK(self); - if (self->flushed) { - PyErr_SetString(PyExc_ValueError, "Repeated call to flush()"); - } else { - self->flushed = 1; - result = compress(self, NULL, 0, LZMA_FINISH); - } - RELEASE_LOCK(self); - return result; -} - -static PyObject * -Compressor_getstate(Compressor *self, PyObject *noargs) -{ - PyErr_Format(PyExc_TypeError, "cannot serialize '%s' object", - Py_TYPE(self)->tp_name); - return NULL; -} - -static int -Compressor_init_xz(lzma_stream *lzs, int check, uint32_t preset, - PyObject *filterspecs) -{ - lzma_ret lzret; - - if (filterspecs == Py_None) { - lzret = lzma_easy_encoder(lzs, preset, check); - } else { - lzma_filter filters[LZMA_FILTERS_MAX + 1]; - - if (parse_filter_chain_spec(filters, filterspecs) == -1) - return -1; - lzret = lzma_stream_encoder(lzs, filters, check); - free_filter_chain(filters); - } - if (catch_lzma_error(lzret)) - return -1; - else - return 0; -} - -static int -Compressor_init_alone(lzma_stream *lzs, uint32_t preset, PyObject *filterspecs) -{ - lzma_ret lzret; - - if (filterspecs == Py_None) { - lzma_options_lzma options; - - if (lzma_lzma_preset(&options, preset)) { - PyErr_Format(Error, "Invalid compression preset: %d", preset); - return -1; - } - lzret = lzma_alone_encoder(lzs, &options); - } else { - lzma_filter filters[LZMA_FILTERS_MAX + 1]; - - if (parse_filter_chain_spec(filters, filterspecs) == -1) - return -1; - if (filters[0].id == LZMA_FILTER_LZMA1 && - filters[1].id == LZMA_VLI_UNKNOWN) { - lzret = lzma_alone_encoder(lzs, filters[0].options); - } else { - PyErr_SetString(PyExc_ValueError, - "Invalid filter chain for FORMAT_ALONE - " - "must be a single LZMA1 filter"); - lzret = LZMA_PROG_ERROR; - } - free_filter_chain(filters); - } - if (PyErr_Occurred() || catch_lzma_error(lzret)) - return -1; - else - return 0; -} - -static int -Compressor_init_raw(lzma_stream *lzs, PyObject *filterspecs) -{ - lzma_filter filters[LZMA_FILTERS_MAX + 1]; - lzma_ret lzret; - - if (filterspecs == Py_None) { - PyErr_SetString(PyExc_ValueError, - "Must specify filters for FORMAT_RAW"); - return -1; - } - if (parse_filter_chain_spec(filters, filterspecs) == -1) - return -1; - lzret = lzma_raw_encoder(lzs, filters); - free_filter_chain(filters); - if (catch_lzma_error(lzret)) - return -1; - else - return 0; -} - -/*[-clinic input] -_lzma.LZMACompressor.__init__ - - self: self(type="Compressor *") - format: int(c_default="FORMAT_XZ") = FORMAT_XZ - The container format to use for the output. This can - be FORMAT_XZ (default), FORMAT_ALONE, or FORMAT_RAW. - - check: int(c_default="-1") = unspecified - The integrity check to use. For FORMAT_XZ, the default - is CHECK_CRC64. FORMAT_ALONE and FORMAT_RAW do not suport integrity - checks; for these formats, check must be omitted, or be CHECK_NONE. - - preset: object = None - If provided should be an integer in the range 0-9, optionally - OR-ed with the constant PRESET_EXTREME. - - filters: object = None - If provided should be a sequence of dicts. Each dict should - have an entry for "id" indicating the ID of the filter, plus - additional entries for options to the filter. - -Create a compressor object for compressing data incrementally. - -The settings used by the compressor can be specified either as a -preset compression level (with the 'preset' argument), or in detail -as a custom filter chain (with the 'filters' argument). For FORMAT_XZ -and FORMAT_ALONE, the default is to use the PRESET_DEFAULT preset -level. For FORMAT_RAW, the caller must always specify a filter chain; -the raw compressor does not support preset compression levels. - -For one-shot compression, use the compress() function instead. -[-clinic start generated code]*/ -static int -Compressor_init(Compressor *self, PyObject *args, PyObject *kwargs) -{ - static char *arg_names[] = {"format", "check", "preset", "filters", NULL}; - int format = FORMAT_XZ; - int check = -1; - uint32_t preset = LZMA_PRESET_DEFAULT; - PyObject *preset_obj = Py_None; - PyObject *filterspecs = Py_None; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "|iiOO:LZMACompressor", arg_names, - &format, &check, &preset_obj, - &filterspecs)) - return -1; - - if (format != FORMAT_XZ && check != -1 && check != LZMA_CHECK_NONE) { - PyErr_SetString(PyExc_ValueError, - "Integrity checks are only supported by FORMAT_XZ"); - return -1; - } - - if (preset_obj != Py_None && filterspecs != Py_None) { - PyErr_SetString(PyExc_ValueError, - "Cannot specify both preset and filter chain"); - return -1; - } - - if (preset_obj != Py_None) - if (!uint32_converter(preset_obj, &preset)) - return -1; - - self->alloc.opaque = NULL; - self->alloc.alloc = PyLzma_Malloc; - self->alloc.free = PyLzma_Free; - self->lzs.allocator = &self->alloc; - -#ifdef WITH_THREAD - self->lock = PyThread_allocate_lock(); - if (self->lock == NULL) { - PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); - return -1; - } -#endif - - self->flushed = 0; - switch (format) { - case FORMAT_XZ: - if (check == -1) - check = LZMA_CHECK_CRC64; - if (Compressor_init_xz(&self->lzs, check, preset, filterspecs) != 0) - break; - return 0; - - case FORMAT_ALONE: - if (Compressor_init_alone(&self->lzs, preset, filterspecs) != 0) - break; - return 0; - - case FORMAT_RAW: - if (Compressor_init_raw(&self->lzs, filterspecs) != 0) - break; - return 0; - - default: - PyErr_Format(PyExc_ValueError, - "Invalid container format: %d", format); - break; - } - -#ifdef WITH_THREAD - PyThread_free_lock(self->lock); - self->lock = NULL; -#endif - return -1; -} - -static void -Compressor_dealloc(Compressor *self) -{ - lzma_end(&self->lzs); -#ifdef WITH_THREAD - if (self->lock != NULL) - PyThread_free_lock(self->lock); -#endif - Py_TYPE(self)->tp_free((PyObject *)self); -} - -static PyMethodDef Compressor_methods[] = { - _LZMA_LZMACOMPRESSOR_COMPRESS_METHODDEF - _LZMA_LZMACOMPRESSOR_FLUSH_METHODDEF - {"__getstate__", (PyCFunction)Compressor_getstate, METH_NOARGS}, - {NULL} -}; - -PyDoc_STRVAR(Compressor_doc, -"LZMACompressor(format=FORMAT_XZ, check=-1, preset=None, filters=None)\n" -"\n" -"Create a compressor object for compressing data incrementally.\n" -"\n" -"format specifies the container format to use for the output. This can\n" -"be FORMAT_XZ (default), FORMAT_ALONE, or FORMAT_RAW.\n" -"\n" -"check specifies the integrity check to use. For FORMAT_XZ, the default\n" -"is CHECK_CRC64. FORMAT_ALONE and FORMAT_RAW do not suport integrity\n" -"checks; for these formats, check must be omitted, or be CHECK_NONE.\n" -"\n" -"The settings used by the compressor can be specified either as a\n" -"preset compression level (with the 'preset' argument), or in detail\n" -"as a custom filter chain (with the 'filters' argument). For FORMAT_XZ\n" -"and FORMAT_ALONE, the default is to use the PRESET_DEFAULT preset\n" -"level. For FORMAT_RAW, the caller must always specify a filter chain;\n" -"the raw compressor does not support preset compression levels.\n" -"\n" -"preset (if provided) should be an integer in the range 0-9, optionally\n" -"OR-ed with the constant PRESET_EXTREME.\n" -"\n" -"filters (if provided) should be a sequence of dicts. Each dict should\n" -"have an entry for \"id\" indicating the ID of the filter, plus\n" -"additional entries for options to the filter.\n" -"\n" -"For one-shot compression, use the compress() function instead.\n"); - -static PyTypeObject Compressor_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_lzma.LZMACompressor", /* tp_name */ - sizeof(Compressor), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)Compressor_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - Compressor_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Compressor_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Compressor_init, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ -}; - - -/* LZMADecompressor class. */ - -static PyObject * -decompress(Decompressor *d, uint8_t *data, size_t len) -{ - size_t data_size = 0; - PyObject *result; - - result = PyBytes_FromStringAndSize(NULL, INITIAL_BUFFER_SIZE); - if (result == NULL) - return NULL; - d->lzs.next_in = data; - d->lzs.avail_in = len; - d->lzs.next_out = (uint8_t *)PyBytes_AS_STRING(result); - d->lzs.avail_out = PyBytes_GET_SIZE(result); - for (;;) { - lzma_ret lzret; - - Py_BEGIN_ALLOW_THREADS - lzret = lzma_code(&d->lzs, LZMA_RUN); - data_size = (char *)d->lzs.next_out - PyBytes_AS_STRING(result); - Py_END_ALLOW_THREADS - if (catch_lzma_error(lzret)) - goto error; - if (lzret == LZMA_GET_CHECK || lzret == LZMA_NO_CHECK) - d->check = lzma_get_check(&d->lzs); - if (lzret == LZMA_STREAM_END) { - d->eof = 1; - if (d->lzs.avail_in > 0) { - Py_CLEAR(d->unused_data); - d->unused_data = PyBytes_FromStringAndSize( - (char *)d->lzs.next_in, d->lzs.avail_in); - if (d->unused_data == NULL) - goto error; - } - break; - } else if (d->lzs.avail_in == 0) { - break; - } else if (d->lzs.avail_out == 0) { - if (grow_buffer(&result) == -1) - goto error; - d->lzs.next_out = (uint8_t *)PyBytes_AS_STRING(result) + data_size; - d->lzs.avail_out = PyBytes_GET_SIZE(result) - data_size; - } - } - if (data_size != PyBytes_GET_SIZE(result)) - if (_PyBytes_Resize(&result, data_size) == -1) - goto error; - return result; - -error: - Py_XDECREF(result); - return NULL; -} - -/*[clinic input] -_lzma.LZMADecompressor.decompress - - self: self(type="Decompressor *") - data: Py_buffer - / - -Provide data to the decompressor object. - -Returns a chunk of decompressed data if possible, or b'' otherwise. - -Attempting to decompress data after the end of stream is reached -raises an EOFError. Any data found after the end of the stream -is ignored and saved in the unused_data attribute. -[clinic start generated code]*/ - -static PyObject * -_lzma_LZMADecompressor_decompress_impl(Decompressor *self, Py_buffer *data) -/*[clinic end generated code: checksum=d86e78da7ff0ff219d511275b16b79476da8922e]*/ -{ - PyObject *result = NULL; - - ACQUIRE_LOCK(self); - if (self->eof) - PyErr_SetString(PyExc_EOFError, "Already at end of stream"); - else - result = decompress(self, data->buf, data->len); - RELEASE_LOCK(self); - return result; -} - -static PyObject * -Decompressor_getstate(Decompressor *self, PyObject *noargs) -{ - PyErr_Format(PyExc_TypeError, "cannot serialize '%s' object", - Py_TYPE(self)->tp_name); - return NULL; -} - -static int -Decompressor_init_raw(lzma_stream *lzs, PyObject *filterspecs) -{ - lzma_filter filters[LZMA_FILTERS_MAX + 1]; - lzma_ret lzret; - - if (parse_filter_chain_spec(filters, filterspecs) == -1) - return -1; - lzret = lzma_raw_decoder(lzs, filters); - free_filter_chain(filters); - if (catch_lzma_error(lzret)) - return -1; - else - return 0; -} - -/*[clinic input] -_lzma.LZMADecompressor.__init__ - - self: self(type="Decompressor *") - format: int(c_default="FORMAT_AUTO") = FORMAT_AUTO - Specifies the container format of the input stream. If this is - FORMAT_AUTO (the default), the decompressor will automatically detect - whether the input is FORMAT_XZ or FORMAT_ALONE. Streams created with - FORMAT_RAW cannot be autodetected. - - memlimit: object = None - Limit the amount of memory used by the decompressor. This will cause - decompression to fail if the input cannot be decompressed within the - given limit. - - filters: object = None - A custom filter chain. This argument is required for FORMAT_RAW, and - not accepted with any other format. When provided, this should be a - sequence of dicts, each indicating the ID and options for a single - filter. - -Create a decompressor object for decompressing data incrementally. - -For one-shot decompression, use the decompress() function instead. -[clinic start generated code]*/ - -static int -_lzma_LZMADecompressor___init___impl(Decompressor *self, int format, PyObject *memlimit, PyObject *filters) -/*[clinic end generated code: checksum=9b119f6f2cc2d7a8e5be41c164a6c080ee82d0c2]*/ -{ - const uint32_t decoder_flags = LZMA_TELL_ANY_CHECK | LZMA_TELL_NO_CHECK; - uint64_t memlimit_ = UINT64_MAX; - lzma_ret lzret; - - if (memlimit != Py_None) { - if (format == FORMAT_RAW) { - PyErr_SetString(PyExc_ValueError, - "Cannot specify memory limit with FORMAT_RAW"); - return -1; - } - memlimit_ = PyLong_AsUnsignedLongLong(memlimit); - if (PyErr_Occurred()) - return -1; - } - - if (format == FORMAT_RAW && filters == Py_None) { - PyErr_SetString(PyExc_ValueError, - "Must specify filters for FORMAT_RAW"); - return -1; - } else if (format != FORMAT_RAW && filters != Py_None) { - PyErr_SetString(PyExc_ValueError, - "Cannot specify filters except with FORMAT_RAW"); - return -1; - } - - self->alloc.opaque = NULL; - self->alloc.alloc = PyLzma_Malloc; - self->alloc.free = PyLzma_Free; - self->lzs.allocator = &self->alloc; - -#ifdef WITH_THREAD - self->lock = PyThread_allocate_lock(); - if (self->lock == NULL) { - PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); - return -1; - } -#endif - - self->check = LZMA_CHECK_UNKNOWN; - self->unused_data = PyBytes_FromStringAndSize(NULL, 0); - if (self->unused_data == NULL) - goto error; - - switch (format) { - case FORMAT_AUTO: - lzret = lzma_auto_decoder(&self->lzs, memlimit_, decoder_flags); - if (catch_lzma_error(lzret)) - break; - return 0; - - case FORMAT_XZ: - lzret = lzma_stream_decoder(&self->lzs, memlimit_, decoder_flags); - if (catch_lzma_error(lzret)) - break; - return 0; - - case FORMAT_ALONE: - self->check = LZMA_CHECK_NONE; - lzret = lzma_alone_decoder(&self->lzs, memlimit_); - if (catch_lzma_error(lzret)) - break; - return 0; - - case FORMAT_RAW: - self->check = LZMA_CHECK_NONE; - if (Decompressor_init_raw(&self->lzs, filters) == -1) - break; - return 0; - - default: - PyErr_Format(PyExc_ValueError, - "Invalid container format: %d", format); - break; - } - -error: - Py_CLEAR(self->unused_data); -#ifdef WITH_THREAD - PyThread_free_lock(self->lock); - self->lock = NULL; -#endif - return -1; -} - -static void -Decompressor_dealloc(Decompressor *self) -{ - lzma_end(&self->lzs); - Py_CLEAR(self->unused_data); -#ifdef WITH_THREAD - if (self->lock != NULL) - PyThread_free_lock(self->lock); -#endif - Py_TYPE(self)->tp_free((PyObject *)self); -} - -static PyMethodDef Decompressor_methods[] = { - _LZMA_LZMADECOMPRESSOR_DECOMPRESS_METHODDEF - {"__getstate__", (PyCFunction)Decompressor_getstate, METH_NOARGS}, - {NULL} -}; - -PyDoc_STRVAR(Decompressor_check_doc, -"ID of the integrity check used by the input stream."); - -PyDoc_STRVAR(Decompressor_eof_doc, -"True if the end-of-stream marker has been reached."); - -PyDoc_STRVAR(Decompressor_unused_data_doc, -"Data found after the end of the compressed stream."); - -static PyMemberDef Decompressor_members[] = { - {"check", T_INT, offsetof(Decompressor, check), READONLY, - Decompressor_check_doc}, - {"eof", T_BOOL, offsetof(Decompressor, eof), READONLY, - Decompressor_eof_doc}, - {"unused_data", T_OBJECT_EX, offsetof(Decompressor, unused_data), READONLY, - Decompressor_unused_data_doc}, - {NULL} -}; - -static PyTypeObject Decompressor_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_lzma.LZMADecompressor", /* tp_name */ - sizeof(Decompressor), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)Decompressor_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - _lzma_LZMADecompressor___init____doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Decompressor_methods, /* tp_methods */ - Decompressor_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - _lzma_LZMADecompressor___init__, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ -}; - - -/* Module-level functions. */ - -/*[clinic input] -_lzma.is_check_supported - check_id: int - / - -Test whether the given integrity check is supported. - -Always returns True for CHECK_NONE and CHECK_CRC32. -[clinic start generated code]*/ - -static PyObject * -_lzma_is_check_supported_impl(PyModuleDef *module, int check_id) -/*[clinic end generated code: checksum=bb828e90e00ad96ed61f66719c2fca7fde637418]*/ -{ - return PyBool_FromLong(lzma_check_is_supported(check_id)); -} - - -/*[clinic input] -_lzma._encode_filter_properties - filter: lzma_filter(c_default="{LZMA_VLI_UNKNOWN, NULL}") - / - -Return a bytes object encoding the options (properties) of the filter specified by *filter* (a dict). - -The result does not include the filter ID itself, only the options. -[clinic start generated code]*/ - -static PyObject * -_lzma__encode_filter_properties_impl(PyModuleDef *module, lzma_filter filter) -/*[clinic end generated code: checksum=b5fe690acd6b61d1abfc32f522ada5bdcf9b13da]*/ -{ - lzma_ret lzret; - uint32_t encoded_size; - PyObject *result = NULL; - - lzret = lzma_properties_size(&encoded_size, &filter); - if (catch_lzma_error(lzret)) - goto error; - - result = PyBytes_FromStringAndSize(NULL, encoded_size); - if (result == NULL) - goto error; - - lzret = lzma_properties_encode( - &filter, (uint8_t *)PyBytes_AS_STRING(result)); - if (catch_lzma_error(lzret)) - goto error; - - return result; - -error: - Py_XDECREF(result); - return NULL; -} - - -/*[clinic input] -_lzma._decode_filter_properties - filter_id: lzma_vli - encoded_props: Py_buffer - / - -Return a bytes object encoding the options (properties) of the filter specified by *filter* (a dict). - -The result does not include the filter ID itself, only the options. -[clinic start generated code]*/ - -static PyObject * -_lzma__decode_filter_properties_impl(PyModuleDef *module, lzma_vli filter_id, Py_buffer *encoded_props) -/*[clinic end generated code: checksum=235f7f5345d48744dcd21f781dafbbf05a717538]*/ -{ - lzma_filter filter; - lzma_ret lzret; - PyObject *result = NULL; - filter.id = filter_id; - - lzret = lzma_properties_decode( - &filter, NULL, encoded_props->buf, encoded_props->len); - if (catch_lzma_error(lzret)) - return NULL; - - result = build_filter_spec(&filter); - - /* We use vanilla free() here instead of PyMem_Free() - filter.options was - allocated by lzma_properties_decode() using the default allocator. */ - free(filter.options); - return result; -} - - -/* Module initialization. */ - -static PyMethodDef module_methods[] = { - _LZMA_IS_CHECK_SUPPORTED_METHODDEF - _LZMA__ENCODE_FILTER_PROPERTIES_METHODDEF - _LZMA__DECODE_FILTER_PROPERTIES_METHODDEF - {NULL} -}; - -static PyModuleDef _lzmamodule = { - PyModuleDef_HEAD_INIT, - "_lzma", - NULL, - -1, - module_methods, - NULL, - NULL, - NULL, - NULL, -}; - -/* Some of our constants are more than 32 bits wide, so PyModule_AddIntConstant - would not work correctly on platforms with 32-bit longs. */ -static int -module_add_int_constant(PyObject *m, const char *name, PY_LONG_LONG value) -{ - PyObject *o = PyLong_FromLongLong(value); - if (o == NULL) - return -1; - if (PyModule_AddObject(m, name, o) == 0) - return 0; - Py_DECREF(o); - return -1; -} - -#define ADD_INT_PREFIX_MACRO(m, macro) \ - module_add_int_constant(m, #macro, LZMA_ ## macro) - -PyMODINIT_FUNC -PyInit__lzma(void) -{ - PyObject *m; - - empty_tuple = PyTuple_New(0); - if (empty_tuple == NULL) - return NULL; - - m = PyModule_Create(&_lzmamodule); - if (m == NULL) - return NULL; - - if (PyModule_AddIntMacro(m, FORMAT_AUTO) == -1 || - PyModule_AddIntMacro(m, FORMAT_XZ) == -1 || - PyModule_AddIntMacro(m, FORMAT_ALONE) == -1 || - PyModule_AddIntMacro(m, FORMAT_RAW) == -1 || - ADD_INT_PREFIX_MACRO(m, CHECK_NONE) == -1 || - ADD_INT_PREFIX_MACRO(m, CHECK_CRC32) == -1 || - ADD_INT_PREFIX_MACRO(m, CHECK_CRC64) == -1 || - ADD_INT_PREFIX_MACRO(m, CHECK_SHA256) == -1 || - ADD_INT_PREFIX_MACRO(m, CHECK_ID_MAX) == -1 || - ADD_INT_PREFIX_MACRO(m, CHECK_UNKNOWN) == -1 || - ADD_INT_PREFIX_MACRO(m, FILTER_LZMA1) == -1 || - ADD_INT_PREFIX_MACRO(m, FILTER_LZMA2) == -1 || - ADD_INT_PREFIX_MACRO(m, FILTER_DELTA) == -1 || - ADD_INT_PREFIX_MACRO(m, FILTER_X86) == -1 || - ADD_INT_PREFIX_MACRO(m, FILTER_IA64) == -1 || - ADD_INT_PREFIX_MACRO(m, FILTER_ARM) == -1 || - ADD_INT_PREFIX_MACRO(m, FILTER_ARMTHUMB) == -1 || - ADD_INT_PREFIX_MACRO(m, FILTER_SPARC) == -1 || - ADD_INT_PREFIX_MACRO(m, FILTER_POWERPC) == -1 || - ADD_INT_PREFIX_MACRO(m, MF_HC3) == -1 || - ADD_INT_PREFIX_MACRO(m, MF_HC4) == -1 || - ADD_INT_PREFIX_MACRO(m, MF_BT2) == -1 || - ADD_INT_PREFIX_MACRO(m, MF_BT3) == -1 || - ADD_INT_PREFIX_MACRO(m, MF_BT4) == -1 || - ADD_INT_PREFIX_MACRO(m, MODE_FAST) == -1 || - ADD_INT_PREFIX_MACRO(m, MODE_NORMAL) == -1 || - ADD_INT_PREFIX_MACRO(m, PRESET_DEFAULT) == -1 || - ADD_INT_PREFIX_MACRO(m, PRESET_EXTREME) == -1) - return NULL; - - Error = PyErr_NewExceptionWithDoc( - "_lzma.LZMAError", "Call to liblzma failed.", NULL, NULL); - if (Error == NULL) - return NULL; - Py_INCREF(Error); - if (PyModule_AddObject(m, "LZMAError", Error) == -1) - return NULL; - - if (PyType_Ready(&Compressor_type) == -1) - return NULL; - Py_INCREF(&Compressor_type); - if (PyModule_AddObject(m, "LZMACompressor", - (PyObject *)&Compressor_type) == -1) - return NULL; - - if (PyType_Ready(&Decompressor_type) == -1) - return NULL; - Py_INCREF(&Decompressor_type); - if (PyModule_AddObject(m, "LZMADecompressor", - (PyObject *)&Decompressor_type) == -1) - return NULL; - - return m; -} +/*[clinic end generated code: checksum=b4b90dcbd0c9c349c3a94e26a7eecf71aab179a0]*/ diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2593,7 +2593,11 @@ def set_template_dict(self, template_dict): template_dict['self_name'] = self.name template_dict['self_type'] = self.parser_type - template_dict['self_type_check'] = '({self_name} == {self_type_object}) &&\n ' + if ((self.function.kind == METHOD_NEW) and + self.function.cls and + self.function.cls.typedef): + template_dict['self_type_object'] = self.function.cls.type_object + template_dict['self_type_check'] = '({self_name} == {self_type_object}) &&\n '.format_map(template_dict) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 06:51:51 2014 From: python-checkins at python.org (donald.stufft) Date: Sun, 26 Jan 2014 06:51:51 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Update_pip_to_1=2E5=2E2_an?= =?utf-8?q?d_setuptools_to_2=2E1?= Message-ID: <3fBjs31RDyz7LlL@mail.python.org> http://hg.python.org/cpython/rev/fb7cee081e31 changeset: 88720:fb7cee081e31 user: Donald Stufft date: Sun Jan 26 00:22:39 2014 -0500 summary: Update pip to 1.5.2 and setuptools to 2.1 files: Lib/ensurepip/__init__.py | 4 ++-- Lib/ensurepip/_bundled/pip-1.5-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/pip-1.5.2-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-2.0.2-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-2.1-py2.py3-none-any.whl | Bin 5 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -8,9 +8,9 @@ __all__ = ["version", "bootstrap"] -_SETUPTOOLS_VERSION = "2.0.2" +_SETUPTOOLS_VERSION = "2.1" -_PIP_VERSION = "1.5" +_PIP_VERSION = "1.5.2" # pip currently requires ssl support, so we try to provide a nicer # error message when that is missing (http://bugs.python.org/issue19744) diff --git a/Lib/ensurepip/_bundled/pip-1.5-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-1.5-py2.py3-none-any.whl deleted file mode 100644 index dd7ca2e634424d8f443cf82f7b92393410219748..0000000000000000000000000000000000000000 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/pip-1.5.2-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-1.5.2-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..9133eed9718ca6849514fa8a0b874fcc05050913 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-2.0.2-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-2.0.2-py2.py3-none-any.whl deleted file mode 100644 index 267eeff2387c02dbf6b1450024b1c5101c307056..0000000000000000000000000000000000000000 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-2.1-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-2.1-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..ed77b59e632f32d09a3ae52adaa7f3e6659d8b48 GIT binary patch [stripped] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 07:01:39 2014 From: python-checkins at python.org (larry.hastings) Date: Sun, 26 Jan 2014 07:01:39 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320390=3A_Final_fi?= =?utf-8?q?x=2C_for_generating_NoPositional/NoKeyword_for_=5F=5Finit=5F=5F?= Message-ID: <3fBk4M0Gwrz7LkR@mail.python.org> http://hg.python.org/cpython/rev/1435d2fe8e34 changeset: 88721:1435d2fe8e34 user: Larry Hastings date: Sat Jan 25 22:01:12 2014 -0800 summary: Issue #20390: Final fix, for generating NoPositional/NoKeyword for __init__ calls. files: Misc/NEWS | 2 +- Modules/clinic/_bz2module.c.h | 11 +++++++---- Tools/clinic/clinic.py | 20 +++++++++++++++----- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -133,7 +133,7 @@ IDLE ---- ---Issue #17390: Add Python version to Idle editor window title bar. +- Issue #17390: Add Python version to Idle editor window title bar. Original patches by Edmond Burnett and Kent Johnson. - Issue #18960: IDLE now ignores the source encoding declaration on the second diff --git a/Modules/clinic/_bz2module.c.h b/Modules/clinic/_bz2module.c.h --- a/Modules/clinic/_bz2module.c.h +++ b/Modules/clinic/_bz2module.c.h @@ -75,7 +75,8 @@ int return_value = -1; int compresslevel = 9; - if (!_PyArg_NoKeywords("BZ2Compressor", kwargs)) + if ((Py_TYPE(self) == &BZ2Compressor_Type) && + !_PyArg_NoKeywords("BZ2Compressor", kwargs)) goto exit; if (!PyArg_ParseTuple(args, "|i:BZ2Compressor", @@ -137,13 +138,15 @@ { int return_value = -1; - if (!_PyArg_NoPositional("BZ2Decompressor", args)) + if ((Py_TYPE(self) == &BZ2Decompressor_Type) && + !_PyArg_NoPositional("BZ2Decompressor", args)) goto exit; - if (!_PyArg_NoKeywords("BZ2Decompressor", kwargs)) + if ((Py_TYPE(self) == &BZ2Decompressor_Type) && + !_PyArg_NoKeywords("BZ2Decompressor", kwargs)) goto exit; return_value = _bz2_BZ2Decompressor___init___impl((BZ2Decompressor *)self); exit: return return_value; } -/*[clinic end generated code: checksum=9bb33ae7d35494b7a5365f03f390e4b5b8b1bc49]*/ +/*[clinic end generated code: checksum=4ade1dba3921a8bd8a614e5417f7654d8fb10be5]*/ diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2593,11 +2593,21 @@ def set_template_dict(self, template_dict): template_dict['self_name'] = self.name template_dict['self_type'] = self.parser_type - if ((self.function.kind == METHOD_NEW) and - self.function.cls and - self.function.cls.typedef): - template_dict['self_type_object'] = self.function.cls.type_object - template_dict['self_type_check'] = '({self_name} == {self_type_object}) &&\n '.format_map(template_dict) + kind = self.function.kind + cls = self.function.cls + + if ((kind in (METHOD_NEW, METHOD_INIT)) and cls and cls.typedef): + if kind == METHOD_NEW: + passed_in_type = self.name + else: + passed_in_type = 'Py_TYPE({})'.format(self.name) + + line = '({passed_in_type} == {type_object}) &&\n ' + d = { + 'type_object': self.function.cls.type_object, + 'passed_in_type': passed_in_type + } + template_dict['self_type_check'] = line.format_map(d) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 07:20:18 2014 From: python-checkins at python.org (larry.hastings) Date: Sun, 26 Jan 2014 07:20:18 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320358=3A_Tests_fo?= =?utf-8?q?r_curses=2Ewindow=2Eoverlay_and_curses=2Ewindow=2Eoverwrite?= Message-ID: <3fBkTt0jcWz7LlL@mail.python.org> http://hg.python.org/cpython/rev/0ae768637a07 changeset: 88722:0ae768637a07 user: Larry Hastings date: Sat Jan 25 22:19:47 2014 -0800 summary: Issue #20358: Tests for curses.window.overlay and curses.window.overwrite no longer specify min{row,col} > max{row,col}. files: Lib/test/test_curses.py | 4 ++-- Misc/NEWS | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -115,8 +115,8 @@ stdscr.notimeout(1) win2.overlay(win) win2.overwrite(win) - win2.overlay(win, 1, 2, 3, 3, 2, 1) - win2.overwrite(win, 1, 2, 3, 3, 2, 1) + win2.overlay(win, 1, 2, 2, 1, 3, 3) + win2.overwrite(win, 1, 2, 2, 1, 3, 3) stdscr.redrawln(1,2) stdscr.scrollok(1) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -142,6 +142,9 @@ Tests ----- +- Issue #20358: Tests for curses.window.overlay and curses.window.overwrite + no longer specify min{row,col} > max{row,col}. + - Issue #19886: Use better estimated memory requirements for bigmem tests. Tools/Demos -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun Jan 26 09:30:49 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 26 Jan 2014 09:30:49 +0100 Subject: [Python-checkins] Daily reference leaks (9651fc0e7580): sum=106197 Message-ID: results for 9651fc0e7580 on branch "default" -------------------------------------------- test_audioop leaked [1, 1, 1] references, sum=3 test_base64 leaked [89, 89, 89] references, sum=267 test_base64 leaked [57, 57, 57] memory blocks, sum=171 test_binascii leaked [268, 268, 268] references, sum=804 test_binascii leaked [246, 247, 247] memory blocks, sum=740 test_binhex leaked [5, 5, 5] references, sum=15 test_binhex leaked [5, 5, 5] memory blocks, sum=15 test_codecs leaked [39, 39, 39] references, sum=117 test_codecs leaked [30, 30, 30] memory blocks, sum=90 test_email leaked [166, 166, 166] references, sum=498 test_email leaked [163, 163, 163] memory blocks, sum=489 test_gettext leaked [87, 87, 87] references, sum=261 test_httpservers leaked [1, 1, 1] references, sum=3 test_imaplib leaked [4, 4, 4] references, sum=12 test_imaplib leaked [4, 4, 4] memory blocks, sum=12 test_io leaked [6, 6, 6] references, sum=18 test_io leaked [6, 6, 6] memory blocks, sum=18 test_nntplib leaked [1, 1, 1] references, sum=3 test_plistlib leaked [36, 36, 36] references, sum=108 test_plistlib leaked [36, 36, 36] memory blocks, sum=108 test_quopri leaked [40, 40, 40] references, sum=120 test_quopri leaked [24, 24, 24] memory blocks, sum=72 test_site leaked [-2, 2, -2] references, sum=-2 test_site leaked [-2, 2, -2] memory blocks, sum=-2 test_smtplib leaked [2, 2, 2] references, sum=6 test_smtplib leaked [2, 2, 2] memory blocks, sum=6 test_ssl leaked [6, 6, 6] references, sum=18 test_ssl leaked [6, 6, 6] memory blocks, sum=18 test_struct leaked [16936, 16897, 17115] references, sum=50948 test_struct leaked [16936, 16899, 17117] memory blocks, sum=50952 test_urllib leaked [17, 17, 17] references, sum=51 test_urllib leaked [17, 17, 17] memory blocks, sum=51 test_uu leaked [20, 20, 20] references, sum=60 test_uu leaked [20, 20, 20] memory blocks, sum=60 test_xmlrpc leaked [15, 15, 15] references, sum=45 test_xmlrpc leaked [14, 14, 14] memory blocks, sum=42 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogmdwQtr', '-x'] From python-checkins at python.org Sun Jan 26 15:53:52 2014 From: python-checkins at python.org (nick.coghlan) Date: Sun, 26 Jan 2014 15:53:52 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Close_=2320105=3A_set_=5F?= =?utf-8?q?=5Ftraceback=5F=5F_when_chaining_exceptions_in_C?= Message-ID: <3fBxtS1ZJZz7Ll8@mail.python.org> http://hg.python.org/cpython/rev/b27352f87404 changeset: 88723:b27352f87404 user: Nick Coghlan date: Mon Jan 27 00:53:38 2014 +1000 summary: Close #20105: set __traceback__ when chaining exceptions in C files: Doc/c-api/exceptions.rst | 10 ++++++++++ Doc/whatsnew/3.4.rst | 8 ++++++++ Lib/test/test_codecs.py | 1 + Misc/NEWS | 3 +++ Objects/exceptions.c | 7 +++++-- 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -90,6 +90,16 @@ the class in that case. If the values are already normalized, nothing happens. The delayed normalization is implemented to improve performance. + .. note:: + + This function *does not* implicitly set the ``__traceback__`` + attribute on the exception value. If setting the traceback + appropriately is desired, the following additional snippet is needed:: + + if (tb != NULL) { + PyException_SetTraceback(val, tb); + } + .. c:function:: void PyErr_Clear() 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 @@ -264,6 +264,9 @@ >>> import codecs >>> codecs.decode(b"abcdefgh", "hex") + Traceback (most recent call last): + File "/usr/lib/python3.4/encodings/hex_codec.py", line 20, in hex_decode + return (binascii.a2b_hex(input), len(input)) binascii.Error: Non-hexadecimal digit found The above exception was the direct cause of the following exception: @@ -273,6 +276,11 @@ binascii.Error: decoding with 'hex' codec failed (Error: Non-hexadecimal digit found) >>> codecs.encode("hello", "bz2") + Traceback (most recent call last): + File "/usr/lib/python3.4/encodings/bz2_codec.py", line 17, in bz2_encode + return (bz2.compress(input), len(input)) + File "/usr/lib/python3.4/bz2.py", line 498, in compress + return comp.compress(data) + comp.flush() TypeError: 'str' does not support the buffer interface The above exception was the direct cause of the following exception: diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -2522,6 +2522,7 @@ with self.assertRaisesRegex(exc_type, full_msg) as caught: yield caught self.assertIsInstance(caught.exception.__cause__, exc_type) + self.assertIsNotNone(caught.exception.__cause__.__traceback__) def raise_obj(self, *args, **kwds): # Helper to dynamically change the object raised by a test codec diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,9 @@ Library ------- +- Issue #20105: the codec exception chaining now correctly sets the + traceback of the original exception as its __traceback__ attribute. + - asyncio: Various improvements and small changes not all covered by issues listed below. E.g. wait_for() now cancels the inner task if the timeout occcurs; tweaked the set of exported symbols; renamed diff --git a/Objects/exceptions.c b/Objects/exceptions.c --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -2689,8 +2689,11 @@ * types as well, but that's quite a bit trickier due to the extra * state potentially stored on OSError instances. */ - - Py_XDECREF(tb); + /* Ensure the traceback is set correctly on the existing exception */ + if (tb != NULL) { + PyException_SetTraceback(val, tb); + Py_DECREF(tb); + } #ifdef HAVE_STDARG_PROTOTYPES va_start(vargs, format); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 16:24:30 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 26 Jan 2014 16:24:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_fix_refleak_on_error?= Message-ID: <3fByYp3w5bz7Lkn@mail.python.org> http://hg.python.org/cpython/rev/406ef1101d7d changeset: 88724:406ef1101d7d user: Benjamin Peterson date: Sun Jan 26 10:24:24 2014 -0500 summary: fix refleak on error files: Modules/audioop.c | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Modules/audioop.c b/Modules/audioop.c --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -1608,7 +1608,7 @@ Py_ssize_t i; int step, valpred, delta, index, sign, vpdiff, diff; - PyObject *rv, *str; + PyObject *rv = NULL, *str; int outputbuffer = 0, bufferstep; if (!audioop_check_parameters(fragment->len, width)) @@ -1626,9 +1626,10 @@ index = 0; } else if (!PyTuple_Check(state)) { PyErr_SetString(PyExc_TypeError, "state must be a tuple or None"); - return NULL; - } else if (!PyArg_ParseTuple(state, "ii", &valpred, &index)) - return NULL; + goto exit; + } else if (!PyArg_ParseTuple(state, "ii", &valpred, &index)) { + goto exit; + } step = stepsizeTable[index]; bufferstep = 1; @@ -1704,6 +1705,8 @@ bufferstep = !bufferstep; } rv = Py_BuildValue("(O(ii))", str, valpred, index); + + exit: Py_DECREF(str); return rv; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 16:42:04 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 26 Jan 2014 16:42:04 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_cleanup_after_custom_buffe?= =?utf-8?q?r_converter?= Message-ID: <3fByy46k4QzS64@mail.python.org> http://hg.python.org/cpython/rev/259aeb0ecd2a changeset: 88725:259aeb0ecd2a user: Benjamin Peterson date: Sun Jan 26 10:41:58 2014 -0500 summary: cleanup after custom buffer converter files: Modules/binascii.c | 5 +++ Modules/clinic/binascii.c.h | 32 ++++++++++++++++++++---- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/Modules/binascii.c b/Modules/binascii.c --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -195,6 +195,11 @@ type = 'Py_buffer' converter = 'ascii_buffer_converter' impl_by_reference = True + c_default = "{NULL, NULL}" + + def cleanup(self): + name = self.name + return "".join(["if (", name, ".obj)\n PyBuffer_Release(&", name, ");\n"]) [python start generated code]*/ /*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ diff --git a/Modules/clinic/binascii.c.h b/Modules/clinic/binascii.c.h --- a/Modules/clinic/binascii.c.h +++ b/Modules/clinic/binascii.c.h @@ -16,7 +16,7 @@ binascii_a2b_uu(PyModuleDef *module, PyObject *args) { PyObject *return_value = NULL; - Py_buffer data; + Py_buffer data = {NULL, NULL}; if (!PyArg_ParseTuple(args, "O&:a2b_uu", @@ -25,6 +25,10 @@ return_value = binascii_a2b_uu_impl(module, &data); exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + return return_value; } @@ -72,7 +76,7 @@ binascii_a2b_base64(PyModuleDef *module, PyObject *args) { PyObject *return_value = NULL; - Py_buffer data; + Py_buffer data = {NULL, NULL}; if (!PyArg_ParseTuple(args, "O&:a2b_base64", @@ -81,6 +85,10 @@ return_value = binascii_a2b_base64_impl(module, &data); exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + return return_value; } @@ -128,7 +136,7 @@ binascii_a2b_hqx(PyModuleDef *module, PyObject *args) { PyObject *return_value = NULL; - Py_buffer data; + Py_buffer data = {NULL, NULL}; if (!PyArg_ParseTuple(args, "O&:a2b_hqx", @@ -137,6 +145,10 @@ return_value = binascii_a2b_hqx_impl(module, &data); exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + return return_value; } @@ -350,7 +362,7 @@ binascii_a2b_hex(PyModuleDef *module, PyObject *args) { PyObject *return_value = NULL; - Py_buffer hexstr; + Py_buffer hexstr = {NULL, NULL}; if (!PyArg_ParseTuple(args, "O&:a2b_hex", @@ -359,6 +371,10 @@ return_value = binascii_a2b_hex_impl(module, &hexstr); exit: + /* Cleanup for hexstr */ + if (hexstr.obj) + PyBuffer_Release(&hexstr); + return return_value; } @@ -377,7 +393,7 @@ { PyObject *return_value = NULL; static char *_keywords[] = {"data", "header", NULL}; - Py_buffer data; + Py_buffer data = {NULL, NULL}; int header = 0; if (!PyArg_ParseTupleAndKeywords(args, kwargs, @@ -387,6 +403,10 @@ return_value = binascii_a2b_qp_impl(module, &data, header); exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + return return_value; } @@ -427,4 +447,4 @@ return return_value; } -/*[clinic end generated code: checksum=abe48ca8020fa3ec25e13bd9fa7414f6b3ee2946]*/ +/*[clinic end generated code: checksum=8180e5be47a110ae8c89263a7c12a91d80754f60]*/ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 17:36:14 2014 From: python-checkins at python.org (andrew.svetlov) Date: Sun, 26 Jan 2014 17:36:14 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Merge_latest_Tulip_into_as?= =?utf-8?q?yncio?= Message-ID: <3fC08Z5BCrz7LjV@mail.python.org> http://hg.python.org/cpython/rev/ae7b80efd632 changeset: 88726:ae7b80efd632 user: Andrew Svetlov date: Sun Jan 26 18:36:01 2014 +0200 summary: Merge latest Tulip into asyncio files: Lib/asyncio/base_subprocess.py | 1 - Lib/asyncio/unix_events.py | 3 --- Lib/asyncio/windows_events.py | 3 --- 3 files changed, 0 insertions(+), 7 deletions(-) diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -114,7 +114,6 @@ assert returncode is not None, returncode assert self._returncode is None, self._returncode self._returncode = returncode - self._loop._subprocess_closed(self) self._call(self._protocol.process_exited) self._try_finish() 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 @@ -169,9 +169,6 @@ def _child_watcher_callback(self, pid, returncode, transp): self.call_soon_threadsafe(transp._process_exited, returncode) - def _subprocess_closed(self, transp): - pass - def _set_nonblocking(fd): flags = fcntl.fcntl(fd, fcntl.F_GETFL) 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 @@ -178,9 +178,6 @@ yield from transp._post_init() return transp - def _subprocess_closed(self, transport): - pass - class IocpProactor: """Proactor implementation using IOCP.""" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 18:30:33 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 26 Jan 2014 18:30:33 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzgyNjA6?= =?utf-8?q?_The_read=28=29=2C_readline=28=29_and_readlines=28=29_methods_o?= =?utf-8?q?f?= Message-ID: <3fC1MF1wd4z7Lmn@mail.python.org> http://hg.python.org/cpython/rev/e24265eb2271 changeset: 88727:e24265eb2271 branch: 2.7 parent: 88707:25f6da4c49c2 user: Serhiy Storchaka date: Sun Jan 26 19:20:24 2014 +0200 summary: Issue #8260: The read(), readline() and readlines() methods of codecs.StreamReader returned incomplete data when were called after readline() or read(size). Based on patch by Amaury Forgeot d'Arc. files: Lib/codecs.py | 15 +++++------ Lib/test/test_codecs.py | 34 +++++++++++++++++++++++++++++ Misc/NEWS | 4 +++ 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/Lib/codecs.py b/Lib/codecs.py --- a/Lib/codecs.py +++ b/Lib/codecs.py @@ -456,15 +456,12 @@ # read until we get the required number of characters (if available) while True: - # can the request can be satisfied from the character buffer? - if chars < 0: - if size < 0: - if self.charbuffer: - break - elif len(self.charbuffer) >= size: + # can the request be satisfied from the character buffer? + if chars >= 0: + if len(self.charbuffer) >= chars: break - else: - if len(self.charbuffer) >= chars: + elif size >= 0: + if len(self.charbuffer) >= size: break # we need more data if size < 0: @@ -473,6 +470,8 @@ newdata = self.stream.read(size) # decode bytes (those remaining from the last call included) data = self.bytebuffer + newdata + if not data: + break try: newchars, decodedbytes = self.decode(data, self.errors) except UnicodeDecodeError, exc: diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -124,6 +124,40 @@ size*u"a", ) + def test_mixed_readline_and_read(self): + lines = ["Humpty Dumpty sat on a wall,\n", + "Humpty Dumpty had a great fall.\r\n", + "All the king's horses and all the king's men\r", + "Couldn't put Humpty together again."] + data = ''.join(lines) + def getreader(): + stream = StringIO.StringIO(data.encode(self.encoding)) + return codecs.getreader(self.encoding)(stream) + + # Issue #8260: Test readline() followed by read() + f = getreader() + self.assertEqual(f.readline(), lines[0]) + self.assertEqual(f.read(), ''.join(lines[1:])) + self.assertEqual(f.read(), '') + + # Issue #16636: Test readline() followed by readlines() + f = getreader() + self.assertEqual(f.readline(), lines[0]) + self.assertEqual(f.readlines(), lines[1:]) + self.assertEqual(f.read(), '') + + # Test read() followed by read() + f = getreader() + self.assertEqual(f.read(size=40, chars=5), data[:5]) + self.assertEqual(f.read(), data[5:]) + self.assertEqual(f.read(), '') + + # Issue #12446: Test read() followed by readlines() + f = getreader() + self.assertEqual(f.read(size=40, chars=5), data[:5]) + self.assertEqual(f.readlines(), [lines[0][5:]] + lines[1:]) + self.assertEqual(f.read(), '') + def test_bug1175396(self): s = [ '<%!--===================================================\r\n', diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -38,6 +38,10 @@ Library ------- +- Issue #8260: The read(), readline() and readlines() methods of + codecs.StreamReader returned incomplete data when were called after + readline() or read(size). Based on patch by Amaury Forgeot d'Arc. + - Issue #20374: Fix build with GNU readline >= 6.3. - Issue #14548: Make multiprocessing finalizers check pid before -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 18:30:34 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 26 Jan 2014 18:30:34 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzgyNjA6?= =?utf-8?q?_The_read=28=29=2C_readline=28=29_and_readlines=28=29_methods_o?= =?utf-8?q?f?= Message-ID: <3fC1MG4stFz7Ln5@mail.python.org> http://hg.python.org/cpython/rev/9c96c266896e changeset: 88728:9c96c266896e branch: 3.3 parent: 88705:8c5876a6b3ed user: Serhiy Storchaka date: Sun Jan 26 19:21:00 2014 +0200 summary: Issue #8260: The read(), readline() and readlines() methods of codecs.StreamReader returned incomplete data when were called after readline() or read(size). Based on patch by Amaury Forgeot d'Arc. files: Lib/codecs.py | 13 ++++----- Lib/test/test_codecs.py | 36 +++++++++++++++++++++++++++- Misc/NEWS | 4 +++ 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/Lib/codecs.py b/Lib/codecs.py --- a/Lib/codecs.py +++ b/Lib/codecs.py @@ -463,14 +463,11 @@ # read until we get the required number of characters (if available) while True: # can the request be satisfied from the character buffer? - if chars < 0: - if size < 0: - if self.charbuffer: - break - elif len(self.charbuffer) >= size: + if chars >= 0: + if len(self.charbuffer) >= chars: break - else: - if len(self.charbuffer) >= chars: + elif size >= 0: + if len(self.charbuffer) >= size: break # we need more data if size < 0: @@ -479,6 +476,8 @@ newdata = self.stream.read(size) # decode bytes (those remaining from the last call included) data = self.bytebuffer + newdata + if not data: + break try: newchars, decodedbytes = self.decode(data, self.errors) except UnicodeDecodeError as exc: diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -173,6 +173,40 @@ size*"a", ) + def test_mixed_readline_and_read(self): + lines = ["Humpty Dumpty sat on a wall,\n", + "Humpty Dumpty had a great fall.\r\n", + "All the king's horses and all the king's men\r", + "Couldn't put Humpty together again."] + data = ''.join(lines) + def getreader(): + stream = io.BytesIO(data.encode(self.encoding)) + return codecs.getreader(self.encoding)(stream) + + # Issue #8260: Test readline() followed by read() + f = getreader() + self.assertEqual(f.readline(), lines[0]) + self.assertEqual(f.read(), ''.join(lines[1:])) + self.assertEqual(f.read(), '') + + # Issue #16636: Test readline() followed by readlines() + f = getreader() + self.assertEqual(f.readline(), lines[0]) + self.assertEqual(f.readlines(), lines[1:]) + self.assertEqual(f.read(), '') + + # Test read() followed by read() + f = getreader() + self.assertEqual(f.read(size=40, chars=5), data[:5]) + self.assertEqual(f.read(), data[5:]) + self.assertEqual(f.read(), '') + + # Issue #12446: Test read() followed by readlines() + f = getreader() + self.assertEqual(f.read(size=40, chars=5), data[:5]) + self.assertEqual(f.readlines(), [lines[0][5:]] + lines[1:]) + self.assertEqual(f.read(), '') + def test_bug1175396(self): s = [ '<%!--===================================================\r\n', @@ -2307,8 +2341,6 @@ def test_readline(self): for encoding in bytes_transform_encodings: - if encoding in ['uu_codec', 'zlib_codec']: - continue sin = codecs.encode(b"\x80", encoding) reader = codecs.getreader(encoding)(io.BytesIO(sin)) sout = reader.readline() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -50,6 +50,10 @@ Library ------- +- Issue #8260: The read(), readline() and readlines() methods of + codecs.StreamReader returned incomplete data when were called after + readline() or read(size). Based on patch by Amaury Forgeot d'Arc. + - Issue #20317: ExitStack.__exit__ could create a self-referential loop if an exception raised by a cleanup operation already had its context set correctly (for example, by the @contextmanager decorator). The infinite -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 18:30:36 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 26 Jan 2014 18:30:36 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=238260=3A_The_read?= =?utf-8?q?=28=29=2C_readline=28=29_and_readlines=28=29_methods_of?= Message-ID: <3fC1MJ0Prcz7Lmn@mail.python.org> http://hg.python.org/cpython/rev/b72508a785de changeset: 88729:b72508a785de parent: 88726:ae7b80efd632 user: Serhiy Storchaka date: Sun Jan 26 19:27:56 2014 +0200 summary: Issue #8260: The read(), readline() and readlines() methods of codecs.StreamReader returned incomplete data when were called after readline() or read(size). Based on patch by Amaury Forgeot d'Arc. files: Lib/codecs.py | 13 ++++----- Lib/test/test_codecs.py | 36 +++++++++++++++++++++++++++- Misc/NEWS | 4 +++ 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/Lib/codecs.py b/Lib/codecs.py --- a/Lib/codecs.py +++ b/Lib/codecs.py @@ -475,14 +475,11 @@ # read until we get the required number of characters (if available) while True: # can the request be satisfied from the character buffer? - if chars < 0: - if size < 0: - if self.charbuffer: - break - elif len(self.charbuffer) >= size: + if chars >= 0: + if len(self.charbuffer) >= chars: break - else: - if len(self.charbuffer) >= chars: + elif size >= 0: + if len(self.charbuffer) >= size: break # we need more data if size < 0: @@ -491,6 +488,8 @@ newdata = self.stream.read(size) # decode bytes (those remaining from the last call included) data = self.bytebuffer + newdata + if not data: + break try: newchars, decodedbytes = self.decode(data, self.errors) except UnicodeDecodeError as exc: diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -175,6 +175,40 @@ size*"a", ) + def test_mixed_readline_and_read(self): + lines = ["Humpty Dumpty sat on a wall,\n", + "Humpty Dumpty had a great fall.\r\n", + "All the king's horses and all the king's men\r", + "Couldn't put Humpty together again."] + data = ''.join(lines) + def getreader(): + stream = io.BytesIO(data.encode(self.encoding)) + return codecs.getreader(self.encoding)(stream) + + # Issue #8260: Test readline() followed by read() + f = getreader() + self.assertEqual(f.readline(), lines[0]) + self.assertEqual(f.read(), ''.join(lines[1:])) + self.assertEqual(f.read(), '') + + # Issue #16636: Test readline() followed by readlines() + f = getreader() + self.assertEqual(f.readline(), lines[0]) + self.assertEqual(f.readlines(), lines[1:]) + self.assertEqual(f.read(), '') + + # Test read() followed by read() + f = getreader() + self.assertEqual(f.read(size=40, chars=5), data[:5]) + self.assertEqual(f.read(), data[5:]) + self.assertEqual(f.read(), '') + + # Issue #12446: Test read() followed by readlines() + f = getreader() + self.assertEqual(f.read(size=40, chars=5), data[:5]) + self.assertEqual(f.readlines(), [lines[0][5:]] + lines[1:]) + self.assertEqual(f.read(), '') + def test_bug1175396(self): s = [ '<%!--===================================================\r\n', @@ -2370,8 +2404,6 @@ def test_readline(self): for encoding in bytes_transform_encodings: - if encoding in ['uu_codec', 'zlib_codec']: - continue with self.subTest(encoding=encoding): sin = codecs.encode(b"\x80", encoding) reader = codecs.getreader(encoding)(io.BytesIO(sin)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,10 @@ Library ------- +- Issue #8260: The read(), readline() and readlines() methods of + codecs.StreamReader returned incomplete data when were called after + readline() or read(size). Based on patch by Amaury Forgeot d'Arc. + - Issue #20105: the codec exception chaining now correctly sets the traceback of the original exception as its __traceback__ attribute. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 18:37:46 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 26 Jan 2014 18:37:46 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_heads?= Message-ID: <3fC1WZ2DbVz7LjV@mail.python.org> http://hg.python.org/cpython/rev/913848da1af0 changeset: 88730:913848da1af0 parent: 88729:b72508a785de parent: 88728:9c96c266896e user: Serhiy Storchaka date: Sun Jan 26 19:36:59 2014 +0200 summary: Merge heads files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 18:59:20 2014 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 26 Jan 2014 18:59:20 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_issue_=2320367=3A_conc?= =?utf-8?q?urrent=2Efutures=2Eas=5Fcompleted=28=29_for_duplicate_arguments?= =?utf-8?q?=2E?= Message-ID: <3fC20S2XgCz7Ll8@mail.python.org> http://hg.python.org/cpython/rev/58b0f3e1ddf8 changeset: 88731:58b0f3e1ddf8 user: Guido van Rossum date: Sun Jan 26 09:57:51 2014 -0800 summary: Fix issue #20367: concurrent.futures.as_completed() for duplicate arguments. Patch by Glenn Langford. files: Doc/library/concurrent.futures.rst | 3 ++- Lib/concurrent/futures/_base.py | 6 ++++-- Lib/test/test_concurrent_futures.py | 7 +++++++ Misc/NEWS | 3 +++ 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -371,7 +371,8 @@ Returns an iterator over the :class:`Future` instances (possibly created by different :class:`Executor` instances) given by *fs* that yields futures as - they complete (finished or were cancelled). Any futures that completed + they complete (finished or were cancelled). Any futures given by *fs* that + are duplicated will be returned once. Any futures that completed before :func:`as_completed` is called will be yielded first. The returned iterator raises a :exc:`TimeoutError` if :meth:`~iterator.__next__` is called and the result isn't available after *timeout* seconds from the diff --git a/Lib/concurrent/futures/_base.py b/Lib/concurrent/futures/_base.py --- a/Lib/concurrent/futures/_base.py +++ b/Lib/concurrent/futures/_base.py @@ -181,7 +181,8 @@ Returns: An iterator that yields the given Futures as they complete (finished or - cancelled). + cancelled). If any given Futures are duplicated, they will be returned + once. Raises: TimeoutError: If the entire result iterator could not be generated @@ -190,11 +191,12 @@ if timeout is not None: end_time = timeout + time.time() + fs = set(fs) with _AcquireFutures(fs): finished = set( f for f in fs if f._state in [CANCELLED_AND_NOTIFIED, FINISHED]) - pending = set(fs) - finished + pending = fs - finished waiter = _create_and_install_waiters(fs, _AS_COMPLETED) try: diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -350,6 +350,13 @@ SUCCESSFUL_FUTURE]), completed_futures) + def test_duplicate_futures(self): + # Issue 20367. Duplicate futures should not raise exceptions or give + # duplicate responses. + future1 = self.executor.submit(time.sleep, 2) + completed = [f for f in futures.as_completed([future1,future1])] + self.assertEqual(len(completed), 1) + class ThreadPoolAsCompletedTests(ThreadPoolMixin, AsCompletedTests, unittest.TestCase): pass diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,9 @@ Library ------- +- Issue #20367: Fix behavior of concurrent.futures.as_completed() for + duplicate arguments. Patch by Glenn Langford. + - Issue #8260: The read(), readline() and readlines() methods of codecs.StreamReader returned incomplete data when were called after readline() or read(size). Based on patch by Amaury Forgeot d'Arc. -- Repository URL: http://hg.python.org/cpython From root at python.org Sun Jan 26 19:25:04 2014 From: root at python.org (Cron Daemon) Date: Sun, 26 Jan 2014 19:25:04 +0100 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: abort: error: Name or service not known From python-checkins at python.org Sun Jan 26 20:21:03 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 26 Jan 2014 20:21:03 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fixed_a_bug_in?= =?utf-8?q?_previous_changeset=3A_StreamReader_returned_=27=27_instead_of_?= =?utf-8?b?dScnLg==?= Message-ID: <3fC3pl1qpGz7Lkf@mail.python.org> http://hg.python.org/cpython/rev/450fd2a2447e changeset: 88732:450fd2a2447e branch: 2.7 parent: 88727:e24265eb2271 user: Serhiy Storchaka date: Sun Jan 26 21:19:59 2014 +0200 summary: Fixed a bug in previous changeset: StreamReader returned '' instead of u''. files: Lib/codecs.py | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/Lib/codecs.py b/Lib/codecs.py --- a/Lib/codecs.py +++ b/Lib/codecs.py @@ -470,8 +470,6 @@ newdata = self.stream.read(size) # decode bytes (those remaining from the last call included) data = self.bytebuffer + newdata - if not data: - break try: newchars, decodedbytes = self.decode(data, self.errors) except UnicodeDecodeError, exc: -- Repository URL: http://hg.python.org/cpython From root at python.org Sun Jan 26 20:35:24 2014 From: root at python.org (Cron Daemon) Date: Sun, 26 Jan 2014 20:35:24 +0100 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: abort: error: Connection timed out From python-checkins at python.org Sun Jan 26 22:53:56 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 26 Jan 2014 22:53:56 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE5OTkw?= =?utf-8?q?=3A_Added_tests_for_the_imghdr_module=2E?= Message-ID: <3fC7C84p71z7Llb@mail.python.org> http://hg.python.org/cpython/rev/b28909d501c0 changeset: 88733:b28909d501c0 branch: 2.7 user: Serhiy Storchaka date: Sun Jan 26 23:48:20 2014 +0200 summary: Issue #19990: Added tests for the imghdr module. Based on patch by Claudiu Popa. files: Lib/test/imghdrdata/python.bmp | Bin Lib/test/imghdrdata/python.gif | Bin Lib/test/imghdrdata/python.jpg | Bin Lib/test/imghdrdata/python.pbm | 3 + Lib/test/imghdrdata/python.pgm | Bin Lib/test/imghdrdata/python.png | Bin Lib/test/imghdrdata/python.ppm | Bin Lib/test/imghdrdata/python.ras | Bin Lib/test/imghdrdata/python.sgi | Bin Lib/test/imghdrdata/python.tiff | Bin Lib/test/imghdrdata/python.xbm | 6 + Lib/test/test_imghdr.py | 120 ++++++++++++++++++++ Lib/test/test_sundry.py | 1 - Misc/NEWS | 3 + 14 files changed, 132 insertions(+), 1 deletions(-) diff --git a/Lib/test/imghdrdata/python.bmp b/Lib/test/imghdrdata/python.bmp new file mode 100644 index 0000000000000000000000000000000000000000..675f95191a45fdb3ae845996d6871b86286f848a GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.gif b/Lib/test/imghdrdata/python.gif new file mode 100644 index 0000000000000000000000000000000000000000..96fd9fef76b10899807d3724c97335f35a03743a GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.jpg b/Lib/test/imghdrdata/python.jpg new file mode 100644 index 0000000000000000000000000000000000000000..21222c09f5a71d9d86a0323e49ebc5da6639b22f GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.pbm b/Lib/test/imghdrdata/python.pbm new file mode 100644 --- /dev/null +++ b/Lib/test/imghdrdata/python.pbm @@ -0,0 +1,3 @@ +P4 +16 16 +????????[??a_?X????????? \ No newline at end of file diff --git a/Lib/test/imghdrdata/python.pgm b/Lib/test/imghdrdata/python.pgm new file mode 100644 index 0000000000000000000000000000000000000000..8349f2a53a9be1d895a561cc0fd31f91d7d42b33 GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.png b/Lib/test/imghdrdata/python.png new file mode 100644 index 0000000000000000000000000000000000000000..1a987f79fcd248a94fcd1c45934136919cc0ffdd GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.ppm b/Lib/test/imghdrdata/python.ppm new file mode 100644 index 0000000000000000000000000000000000000000..7d9cdb3215877b4604de4c177fc81ebb645b8290 GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.ras b/Lib/test/imghdrdata/python.ras new file mode 100644 index 0000000000000000000000000000000000000000..130e96f817ed9dd45f411f2f93e0749a4b33ba49 GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.sgi b/Lib/test/imghdrdata/python.sgi new file mode 100644 index 0000000000000000000000000000000000000000..ffe9081c7a5b67ed14285041fd0650f4010bc36d GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.tiff b/Lib/test/imghdrdata/python.tiff new file mode 100644 index 0000000000000000000000000000000000000000..39d0bfcec02533ade8934a8796aebb8990c9d389 GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.xbm b/Lib/test/imghdrdata/python.xbm new file mode 100644 --- /dev/null +++ b/Lib/test/imghdrdata/python.xbm @@ -0,0 +1,6 @@ +#define python_width 16 +#define python_height 16 +static char python_bits[] = { + 0xDF, 0xFE, 0x8F, 0xFD, 0x5F, 0xFB, 0xAB, 0xFE, 0xB5, 0x8D, 0xDA, 0x8F, + 0xA5, 0x86, 0xFA, 0x83, 0x1A, 0x80, 0x0D, 0x80, 0x0D, 0x80, 0x0F, 0xE0, + 0x0F, 0xF8, 0x0F, 0xF8, 0x0F, 0xFC, 0xFF, 0xFF, }; diff --git a/Lib/test/test_imghdr.py b/Lib/test/test_imghdr.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_imghdr.py @@ -0,0 +1,120 @@ +import imghdr +import io +import sys +import unittest +from test.test_support import findfile, TESTFN, unlink, run_unittest + +TEST_FILES = ( + ('python.png', 'png'), + ('python.gif', 'gif'), + ('python.bmp', 'bmp'), + ('python.ppm', 'ppm'), + ('python.pgm', 'pgm'), + ('python.pbm', 'pbm'), + ('python.jpg', 'jpeg'), + ('python.ras', 'rast'), + ('python.sgi', 'rgb'), + ('python.tiff', 'tiff'), + ('python.xbm', 'xbm') +) + +class UnseekableIO(io.FileIO): + def tell(self): + raise io.UnsupportedOperation + + def seek(self, *args, **kwargs): + raise io.UnsupportedOperation + +class TestImghdr(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.testfile = findfile('python.png', subdir='imghdrdata') + with open(cls.testfile, 'rb') as stream: + cls.testdata = stream.read() + + def tearDown(self): + unlink(TESTFN) + + def test_data(self): + for filename, expected in TEST_FILES: + filename = findfile(filename, subdir='imghdrdata') + self.assertEqual(imghdr.what(filename), expected) + ufilename = filename.decode(sys.getfilesystemencoding()) + self.assertEqual(imghdr.what(ufilename), expected) + with open(filename, 'rb') as stream: + self.assertEqual(imghdr.what(stream), expected) + with open(filename, 'rb') as stream: + data = stream.read() + self.assertEqual(imghdr.what(None, data), expected) + + def test_register_test(self): + def test_jumbo(h, file): + if h.startswith(b'eggs'): + return 'ham' + imghdr.tests.append(test_jumbo) + self.addCleanup(imghdr.tests.pop) + self.assertEqual(imghdr.what(None, b'eggs'), 'ham') + + def test_file_pos(self): + with open(TESTFN, 'wb') as stream: + stream.write(b'ababagalamaga') + pos = stream.tell() + stream.write(self.testdata) + with open(TESTFN, 'rb') as stream: + stream.seek(pos) + self.assertEqual(imghdr.what(stream), 'png') + self.assertEqual(stream.tell(), pos) + + def test_bad_args(self): + with self.assertRaises(TypeError): + imghdr.what() + with self.assertRaises(AttributeError): + imghdr.what(None) + with self.assertRaises(TypeError): + imghdr.what(self.testfile, 1) + with open(self.testfile, 'rb') as f: + with self.assertRaises(AttributeError): + imghdr.what(f.fileno()) + + def test_invalid_headers(self): + for header in (b'\211PN\r\n', + b'\001\331', + b'\x59\xA6', + b'cutecat', + b'000000JFI', + b'GIF80'): + self.assertIsNone(imghdr.what(None, header)) + + def test_missing_file(self): + with self.assertRaises(IOError): + imghdr.what('missing') + + def test_closed_file(self): + stream = open(self.testfile, 'rb') + stream.close() + with self.assertRaises(ValueError) as cm: + imghdr.what(stream) + stream = io.BytesIO(self.testdata) + stream.close() + with self.assertRaises(ValueError) as cm: + imghdr.what(stream) + + def test_unseekable(self): + with open(TESTFN, 'wb') as stream: + stream.write(self.testdata) + with UnseekableIO(TESTFN, 'rb') as stream: + with self.assertRaises(io.UnsupportedOperation): + imghdr.what(stream) + + def test_output_stream(self): + with open(TESTFN, 'wb') as stream: + stream.write(self.testdata) + stream.seek(0) + with self.assertRaises(IOError) as cm: + imghdr.what(stream) + +def test_main(): + run_unittest(TestImghdr) + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_sundry.py b/Lib/test/test_sundry.py --- a/Lib/test/test_sundry.py +++ b/Lib/test/test_sundry.py @@ -49,7 +49,6 @@ import getpass import htmlentitydefs import ihooks - import imghdr import imputil import keyword import linecache diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -203,6 +203,9 @@ Tests ----- +- Issue #19990: Added tests for the imghdr module. Based on patch by + Claudiu Popa. + - Issue #19804: The test_find_mac test in test_uuid is now skipped if the ifconfig executable is not available. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 22:53:58 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 26 Jan 2014 22:53:58 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE5OTkw?= =?utf-8?q?=3A_Added_tests_for_the_imghdr_module=2E?= Message-ID: <3fC7CB0KZSz7Ll8@mail.python.org> http://hg.python.org/cpython/rev/fde9e9832749 changeset: 88734:fde9e9832749 branch: 3.3 parent: 88728:9c96c266896e user: Serhiy Storchaka date: Sun Jan 26 23:48:38 2014 +0200 summary: Issue #19990: Added tests for the imghdr module. Based on patch by Claudiu Popa. files: Lib/test/imghdrdata/python.bmp | Bin Lib/test/imghdrdata/python.gif | Bin Lib/test/imghdrdata/python.jpg | Bin Lib/test/imghdrdata/python.pbm | 3 + Lib/test/imghdrdata/python.pgm | Bin Lib/test/imghdrdata/python.png | Bin Lib/test/imghdrdata/python.ppm | Bin Lib/test/imghdrdata/python.ras | Bin Lib/test/imghdrdata/python.sgi | Bin Lib/test/imghdrdata/python.tiff | Bin Lib/test/imghdrdata/python.xbm | 6 + Lib/test/test_imghdr.py | 131 ++++++++++++++++++++ Lib/test/test_sundry.py | 1 - Misc/NEWS | 3 + 14 files changed, 143 insertions(+), 1 deletions(-) diff --git a/Lib/test/imghdrdata/python.bmp b/Lib/test/imghdrdata/python.bmp new file mode 100644 index 0000000000000000000000000000000000000000..675f95191a45fdb3ae845996d6871b86286f848a GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.gif b/Lib/test/imghdrdata/python.gif new file mode 100644 index 0000000000000000000000000000000000000000..96fd9fef76b10899807d3724c97335f35a03743a GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.jpg b/Lib/test/imghdrdata/python.jpg new file mode 100644 index 0000000000000000000000000000000000000000..21222c09f5a71d9d86a0323e49ebc5da6639b22f GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.pbm b/Lib/test/imghdrdata/python.pbm new file mode 100644 --- /dev/null +++ b/Lib/test/imghdrdata/python.pbm @@ -0,0 +1,3 @@ +P4 +16 16 +????????[??a_?X????????? \ No newline at end of file diff --git a/Lib/test/imghdrdata/python.pgm b/Lib/test/imghdrdata/python.pgm new file mode 100644 index 0000000000000000000000000000000000000000..8349f2a53a9be1d895a561cc0fd31f91d7d42b33 GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.png b/Lib/test/imghdrdata/python.png new file mode 100644 index 0000000000000000000000000000000000000000..1a987f79fcd248a94fcd1c45934136919cc0ffdd GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.ppm b/Lib/test/imghdrdata/python.ppm new file mode 100644 index 0000000000000000000000000000000000000000..7d9cdb3215877b4604de4c177fc81ebb645b8290 GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.ras b/Lib/test/imghdrdata/python.ras new file mode 100644 index 0000000000000000000000000000000000000000..130e96f817ed9dd45f411f2f93e0749a4b33ba49 GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.sgi b/Lib/test/imghdrdata/python.sgi new file mode 100644 index 0000000000000000000000000000000000000000..ffe9081c7a5b67ed14285041fd0650f4010bc36d GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.tiff b/Lib/test/imghdrdata/python.tiff new file mode 100644 index 0000000000000000000000000000000000000000..39d0bfcec02533ade8934a8796aebb8990c9d389 GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.xbm b/Lib/test/imghdrdata/python.xbm new file mode 100644 --- /dev/null +++ b/Lib/test/imghdrdata/python.xbm @@ -0,0 +1,6 @@ +#define python_width 16 +#define python_height 16 +static char python_bits[] = { + 0xDF, 0xFE, 0x8F, 0xFD, 0x5F, 0xFB, 0xAB, 0xFE, 0xB5, 0x8D, 0xDA, 0x8F, + 0xA5, 0x86, 0xFA, 0x83, 0x1A, 0x80, 0x0D, 0x80, 0x0D, 0x80, 0x0F, 0xE0, + 0x0F, 0xF8, 0x0F, 0xF8, 0x0F, 0xFC, 0xFF, 0xFF, }; diff --git a/Lib/test/test_imghdr.py b/Lib/test/test_imghdr.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_imghdr.py @@ -0,0 +1,131 @@ +import imghdr +import io +import os +import unittest +import warnings +from test.support import findfile, TESTFN, unlink + +TEST_FILES = ( + ('python.png', 'png'), + ('python.gif', 'gif'), + ('python.bmp', 'bmp'), + ('python.ppm', 'ppm'), + ('python.pgm', 'pgm'), + ('python.pbm', 'pbm'), + ('python.jpg', 'jpeg'), + ('python.ras', 'rast'), + ('python.sgi', 'rgb'), + ('python.tiff', 'tiff'), + ('python.xbm', 'xbm') +) + +class UnseekableIO(io.FileIO): + def tell(self): + raise io.UnsupportedOperation + + def seek(self, *args, **kwargs): + raise io.UnsupportedOperation + +class TestImghdr(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.testfile = findfile('python.png', subdir='imghdrdata') + with open(cls.testfile, 'rb') as stream: + cls.testdata = stream.read() + + def tearDown(self): + unlink(TESTFN) + + def test_data(self): + for filename, expected in TEST_FILES: + filename = findfile(filename, subdir='imghdrdata') + self.assertEqual(imghdr.what(filename), expected) + with open(filename, 'rb') as stream: + self.assertEqual(imghdr.what(stream), expected) + with open(filename, 'rb') as stream: + data = stream.read() + self.assertEqual(imghdr.what(None, data), expected) + self.assertEqual(imghdr.what(None, bytearray(data)), expected) + + def test_register_test(self): + def test_jumbo(h, file): + if h.startswith(b'eggs'): + return 'ham' + imghdr.tests.append(test_jumbo) + self.addCleanup(imghdr.tests.pop) + self.assertEqual(imghdr.what(None, b'eggs'), 'ham') + + def test_file_pos(self): + with open(TESTFN, 'wb') as stream: + stream.write(b'ababagalamaga') + pos = stream.tell() + stream.write(self.testdata) + with open(TESTFN, 'rb') as stream: + stream.seek(pos) + self.assertEqual(imghdr.what(stream), 'png') + self.assertEqual(stream.tell(), pos) + + def test_bad_args(self): + with self.assertRaises(TypeError): + imghdr.what() + with self.assertRaises(AttributeError): + imghdr.what(None) + with self.assertRaises(TypeError): + imghdr.what(self.testfile, 1) + with self.assertRaises(AttributeError): + imghdr.what(os.fsencode(self.testfile)) + with open(self.testfile, 'rb') as f: + with self.assertRaises(AttributeError): + imghdr.what(f.fileno()) + + def test_invalid_headers(self): + for header in (b'\211PN\r\n', + b'\001\331', + b'\x59\xA6', + b'cutecat', + b'000000JFI', + b'GIF80'): + self.assertIsNone(imghdr.what(None, header)) + + def test_string_data(self): + with warnings.catch_warnings(): + warnings.simplefilter("ignore", BytesWarning) + for filename, _ in TEST_FILES: + filename = findfile(filename, subdir='imghdrdata') + with open(filename, 'rb') as stream: + data = stream.read().decode('latin1') + with self.assertRaises(TypeError): + imghdr.what(io.StringIO(data)) + with self.assertRaises(TypeError): + imghdr.what(None, data) + + def test_missing_file(self): + with self.assertRaises(FileNotFoundError): + imghdr.what('missing') + + def test_closed_file(self): + stream = open(self.testfile, 'rb') + stream.close() + with self.assertRaises(ValueError) as cm: + imghdr.what(stream) + stream = io.BytesIO(self.testdata) + stream.close() + with self.assertRaises(ValueError) as cm: + imghdr.what(stream) + + def test_unseekable(self): + with open(TESTFN, 'wb') as stream: + stream.write(self.testdata) + with UnseekableIO(TESTFN, 'rb') as stream: + with self.assertRaises(io.UnsupportedOperation): + imghdr.what(stream) + + def test_output_stream(self): + with open(TESTFN, 'wb') as stream: + stream.write(self.testdata) + stream.seek(0) + with self.assertRaises(OSError) as cm: + imghdr.what(stream) + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_sundry.py b/Lib/test/test_sundry.py --- a/Lib/test/test_sundry.py +++ b/Lib/test/test_sundry.py @@ -42,7 +42,6 @@ import encodings import formatter import html.entities - import imghdr import keyword import mailcap import nturl2path diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -292,6 +292,9 @@ Tests ----- +- Issue #19990: Added tests for the imghdr module. Based on patch by + Claudiu Popa. + - Issue #19804: The test_find_mac test in test_uuid is now skipped if the ifconfig executable is not available. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 22:53:59 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 26 Jan 2014 22:53:59 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2319990=3A_Added_tests_for_the_imghdr_module=2E?= Message-ID: <3fC7CC3HBCz7Llv@mail.python.org> http://hg.python.org/cpython/rev/94813eab5a58 changeset: 88735:94813eab5a58 parent: 88731:58b0f3e1ddf8 parent: 88734:fde9e9832749 user: Serhiy Storchaka date: Sun Jan 26 23:52:57 2014 +0200 summary: Issue #19990: Added tests for the imghdr module. Based on patch by Claudiu Popa. files: Lib/test/imghdrdata/python.bmp | Bin Lib/test/imghdrdata/python.gif | Bin Lib/test/imghdrdata/python.jpg | Bin Lib/test/imghdrdata/python.pbm | 3 + Lib/test/imghdrdata/python.pgm | Bin Lib/test/imghdrdata/python.png | Bin Lib/test/imghdrdata/python.ppm | Bin Lib/test/imghdrdata/python.ras | Bin Lib/test/imghdrdata/python.sgi | Bin Lib/test/imghdrdata/python.tiff | Bin Lib/test/imghdrdata/python.xbm | 6 + Lib/test/test_imghdr.py | 131 ++++++++++++++++++++ Lib/test/test_sundry.py | 2 +- Misc/NEWS | 9 +- 14 files changed, 147 insertions(+), 4 deletions(-) diff --git a/Lib/test/imghdrdata/python.bmp b/Lib/test/imghdrdata/python.bmp new file mode 100644 index 0000000000000000000000000000000000000000..675f95191a45fdb3ae845996d6871b86286f848a GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.gif b/Lib/test/imghdrdata/python.gif new file mode 100644 index 0000000000000000000000000000000000000000..96fd9fef76b10899807d3724c97335f35a03743a GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.jpg b/Lib/test/imghdrdata/python.jpg new file mode 100644 index 0000000000000000000000000000000000000000..21222c09f5a71d9d86a0323e49ebc5da6639b22f GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.pbm b/Lib/test/imghdrdata/python.pbm new file mode 100644 --- /dev/null +++ b/Lib/test/imghdrdata/python.pbm @@ -0,0 +1,3 @@ +P4 +16 16 +????????[??a_?X????????? \ No newline at end of file diff --git a/Lib/test/imghdrdata/python.pgm b/Lib/test/imghdrdata/python.pgm new file mode 100644 index 0000000000000000000000000000000000000000..8349f2a53a9be1d895a561cc0fd31f91d7d42b33 GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.png b/Lib/test/imghdrdata/python.png new file mode 100644 index 0000000000000000000000000000000000000000..1a987f79fcd248a94fcd1c45934136919cc0ffdd GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.ppm b/Lib/test/imghdrdata/python.ppm new file mode 100644 index 0000000000000000000000000000000000000000..7d9cdb3215877b4604de4c177fc81ebb645b8290 GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.ras b/Lib/test/imghdrdata/python.ras new file mode 100644 index 0000000000000000000000000000000000000000..130e96f817ed9dd45f411f2f93e0749a4b33ba49 GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.sgi b/Lib/test/imghdrdata/python.sgi new file mode 100644 index 0000000000000000000000000000000000000000..ffe9081c7a5b67ed14285041fd0650f4010bc36d GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.tiff b/Lib/test/imghdrdata/python.tiff new file mode 100644 index 0000000000000000000000000000000000000000..39d0bfcec02533ade8934a8796aebb8990c9d389 GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.xbm b/Lib/test/imghdrdata/python.xbm new file mode 100644 --- /dev/null +++ b/Lib/test/imghdrdata/python.xbm @@ -0,0 +1,6 @@ +#define python_width 16 +#define python_height 16 +static char python_bits[] = { + 0xDF, 0xFE, 0x8F, 0xFD, 0x5F, 0xFB, 0xAB, 0xFE, 0xB5, 0x8D, 0xDA, 0x8F, + 0xA5, 0x86, 0xFA, 0x83, 0x1A, 0x80, 0x0D, 0x80, 0x0D, 0x80, 0x0F, 0xE0, + 0x0F, 0xF8, 0x0F, 0xF8, 0x0F, 0xFC, 0xFF, 0xFF, }; diff --git a/Lib/test/test_imghdr.py b/Lib/test/test_imghdr.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_imghdr.py @@ -0,0 +1,131 @@ +import imghdr +import io +import os +import unittest +import warnings +from test.support import findfile, TESTFN, unlink + +TEST_FILES = ( + ('python.png', 'png'), + ('python.gif', 'gif'), + ('python.bmp', 'bmp'), + ('python.ppm', 'ppm'), + ('python.pgm', 'pgm'), + ('python.pbm', 'pbm'), + ('python.jpg', 'jpeg'), + ('python.ras', 'rast'), + ('python.sgi', 'rgb'), + ('python.tiff', 'tiff'), + ('python.xbm', 'xbm') +) + +class UnseekableIO(io.FileIO): + def tell(self): + raise io.UnsupportedOperation + + def seek(self, *args, **kwargs): + raise io.UnsupportedOperation + +class TestImghdr(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.testfile = findfile('python.png', subdir='imghdrdata') + with open(cls.testfile, 'rb') as stream: + cls.testdata = stream.read() + + def tearDown(self): + unlink(TESTFN) + + def test_data(self): + for filename, expected in TEST_FILES: + filename = findfile(filename, subdir='imghdrdata') + self.assertEqual(imghdr.what(filename), expected) + with open(filename, 'rb') as stream: + self.assertEqual(imghdr.what(stream), expected) + with open(filename, 'rb') as stream: + data = stream.read() + self.assertEqual(imghdr.what(None, data), expected) + self.assertEqual(imghdr.what(None, bytearray(data)), expected) + + def test_register_test(self): + def test_jumbo(h, file): + if h.startswith(b'eggs'): + return 'ham' + imghdr.tests.append(test_jumbo) + self.addCleanup(imghdr.tests.pop) + self.assertEqual(imghdr.what(None, b'eggs'), 'ham') + + def test_file_pos(self): + with open(TESTFN, 'wb') as stream: + stream.write(b'ababagalamaga') + pos = stream.tell() + stream.write(self.testdata) + with open(TESTFN, 'rb') as stream: + stream.seek(pos) + self.assertEqual(imghdr.what(stream), 'png') + self.assertEqual(stream.tell(), pos) + + def test_bad_args(self): + with self.assertRaises(TypeError): + imghdr.what() + with self.assertRaises(AttributeError): + imghdr.what(None) + with self.assertRaises(TypeError): + imghdr.what(self.testfile, 1) + with self.assertRaises(AttributeError): + imghdr.what(os.fsencode(self.testfile)) + with open(self.testfile, 'rb') as f: + with self.assertRaises(AttributeError): + imghdr.what(f.fileno()) + + def test_invalid_headers(self): + for header in (b'\211PN\r\n', + b'\001\331', + b'\x59\xA6', + b'cutecat', + b'000000JFI', + b'GIF80'): + self.assertIsNone(imghdr.what(None, header)) + + def test_string_data(self): + with warnings.catch_warnings(): + warnings.simplefilter("ignore", BytesWarning) + for filename, _ in TEST_FILES: + filename = findfile(filename, subdir='imghdrdata') + with open(filename, 'rb') as stream: + data = stream.read().decode('latin1') + with self.assertRaises(TypeError): + imghdr.what(io.StringIO(data)) + with self.assertRaises(TypeError): + imghdr.what(None, data) + + def test_missing_file(self): + with self.assertRaises(FileNotFoundError): + imghdr.what('missing') + + def test_closed_file(self): + stream = open(self.testfile, 'rb') + stream.close() + with self.assertRaises(ValueError) as cm: + imghdr.what(stream) + stream = io.BytesIO(self.testdata) + stream.close() + with self.assertRaises(ValueError) as cm: + imghdr.what(stream) + + def test_unseekable(self): + with open(TESTFN, 'wb') as stream: + stream.write(self.testdata) + with UnseekableIO(TESTFN, 'rb') as stream: + with self.assertRaises(io.UnsupportedOperation): + imghdr.what(stream) + + def test_output_stream(self): + with open(TESTFN, 'wb') as stream: + stream.write(self.testdata) + stream.seek(0) + with self.assertRaises(OSError) as cm: + imghdr.what(stream) + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_sundry.py b/Lib/test/test_sundry.py --- a/Lib/test/test_sundry.py +++ b/Lib/test/test_sundry.py @@ -6,7 +6,7 @@ class TestUntestedModules(unittest.TestCase): def test_untested_modules_can_be_imported(self): - untested = ('bdb', 'encodings', 'formatter', 'imghdr', + untested = ('bdb', 'encodings', 'formatter', 'nturl2path', 'tabnanny') with support.check_warnings(quiet=True): for name in untested: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -152,9 +152,15 @@ Tests ----- +- Issue #19990: Added tests for the imghdr module. Based on patch by + Claudiu Popa. + - Issue #20358: Tests for curses.window.overlay and curses.window.overwrite no longer specify min{row,col} > max{row,col}. +- Issue #19804: The test_find_mac test in test_uuid is now skipped if the + ifconfig executable is not available. + - Issue #19886: Use better estimated memory requirements for bigmem tests. Tools/Demos @@ -551,9 +557,6 @@ Tests ----- -- Issue #19804: The test_find_mac test in test_uuid is now skipped if the - ifconfig executable is not available. - - Issue #20055: Fix test_shutil under Windows with symlink privileges held. Patch by Vajrasky Kok. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 23:04:03 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 26 Jan 2014 23:04:03 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320193=3A_The_zlib?= =?utf-8?q?_module_now_uses_Argument_Clinic=2E?= Message-ID: <3fC7Qq4mFCz7Lkf@mail.python.org> http://hg.python.org/cpython/rev/6f217456b9ba changeset: 88736:6f217456b9ba user: Serhiy Storchaka date: Mon Jan 27 00:03:31 2014 +0200 summary: Issue #20193: The zlib module now uses Argument Clinic. files: Modules/clinic/zlibmodule.c.h | 411 +++++++++++++++++ Modules/zlibmodule.c | 503 ++++++++------------- 2 files changed, 607 insertions(+), 307 deletions(-) diff --git a/Modules/clinic/zlibmodule.c.h b/Modules/clinic/zlibmodule.c.h new file mode 100644 --- /dev/null +++ b/Modules/clinic/zlibmodule.c.h @@ -0,0 +1,411 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(zlib_compress__doc__, +"compress(module, bytes, level=Z_DEFAULT_COMPRESSION)\n" +"Returns a bytes object containing compressed data.\n" +"\n" +" bytes\n" +" Binary data to be compressed.\n" +" level\n" +" Compression level, in 0-9."); + +#define ZLIB_COMPRESS_METHODDEF \ + {"compress", (PyCFunction)zlib_compress, METH_VARARGS, zlib_compress__doc__}, + +static PyObject * +zlib_compress_impl(PyModuleDef *module, Py_buffer *bytes, int level); + +static PyObject * +zlib_compress(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer bytes = {NULL, NULL}; + int level = Z_DEFAULT_COMPRESSION; + + if (!PyArg_ParseTuple(args, + "y*|i:compress", + &bytes, &level)) + goto exit; + return_value = zlib_compress_impl(module, &bytes, level); + +exit: + /* Cleanup for bytes */ + if (bytes.obj) + PyBuffer_Release(&bytes); + + return return_value; +} + +PyDoc_STRVAR(zlib_decompress__doc__, +"decompress(module, data, wbits=MAX_WBITS, bufsize=DEF_BUF_SIZE)\n" +"Returns a bytes object containing the uncompressed data.\n" +"\n" +" data\n" +" Compressed data.\n" +" wbits\n" +" The window buffer size.\n" +" bufsize\n" +" The initial output buffer size."); + +#define ZLIB_DECOMPRESS_METHODDEF \ + {"decompress", (PyCFunction)zlib_decompress, METH_VARARGS, zlib_decompress__doc__}, + +static PyObject * +zlib_decompress_impl(PyModuleDef *module, Py_buffer *data, int wbits, unsigned int bufsize); + +static PyObject * +zlib_decompress(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + int wbits = MAX_WBITS; + unsigned int bufsize = DEF_BUF_SIZE; + + if (!PyArg_ParseTuple(args, + "y*|iO&:decompress", + &data, &wbits, uint_converter, &bufsize)) + goto exit; + return_value = zlib_decompress_impl(module, &data, wbits, bufsize); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(zlib_compressobj__doc__, +"compressobj(module, level=Z_DEFAULT_COMPRESSION, method=DEFLATED, wbits=MAX_WBITS, memLevel=DEF_MEM_LEVEL, strategy=Z_DEFAULT_STRATEGY, zdict=None)\n" +"Return a compressor object.\n" +"\n" +" level\n" +" The compression level (an integer in the range 0-9; default is 6).\n" +" Higher compression levels are slower, but produce smaller results.\n" +" method\n" +" The compression algorithm. If given, this must be DEFLATED.\n" +" wbits\n" +" The base two logarithm of the window size (range: 8..15).\n" +" memLevel\n" +" Controls the amount of memory used for internal compression state.\n" +" Valid values range from 1 to 9. Higher values result in higher memory\n" +" usage, faster compression, and smaller output.\n" +" strategy\n" +" Used to tune the compression algorithm. Possible values are\n" +" Z_DEFAULT_STRATEGY, Z_FILTERED, and Z_HUFFMAN_ONLY.\n" +" zdict\n" +" The predefined compression dictionary - a sequence of bytes\n" +" containing subsequences that are likely to occur in the input data."); + +#define ZLIB_COMPRESSOBJ_METHODDEF \ + {"compressobj", (PyCFunction)zlib_compressobj, METH_VARARGS|METH_KEYWORDS, zlib_compressobj__doc__}, + +static PyObject * +zlib_compressobj_impl(PyModuleDef *module, int level, int method, int wbits, int memLevel, int strategy, Py_buffer *zdict); + +static PyObject * +zlib_compressobj(PyModuleDef *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + static char *_keywords[] = {"level", "method", "wbits", "memLevel", "strategy", "zdict", NULL}; + int level = Z_DEFAULT_COMPRESSION; + int method = DEFLATED; + int wbits = MAX_WBITS; + int memLevel = DEF_MEM_LEVEL; + int strategy = Z_DEFAULT_STRATEGY; + Py_buffer zdict = {NULL, NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "|iiiiiy*:compressobj", _keywords, + &level, &method, &wbits, &memLevel, &strategy, &zdict)) + goto exit; + return_value = zlib_compressobj_impl(module, level, method, wbits, memLevel, strategy, &zdict); + +exit: + /* Cleanup for zdict */ + if (zdict.obj) + PyBuffer_Release(&zdict); + + return return_value; +} + +PyDoc_STRVAR(zlib_decompressobj__doc__, +"decompressobj(module, wbits=MAX_WBITS, zdict=b\'\')\n" +"Return a decompressor object.\n" +"\n" +" wbits\n" +" The window buffer size.\n" +" zdict\n" +" The predefined compression dictionary. This must be the same\n" +" dictionary as used by the compressor that produced the input data."); + +#define ZLIB_DECOMPRESSOBJ_METHODDEF \ + {"decompressobj", (PyCFunction)zlib_decompressobj, METH_VARARGS|METH_KEYWORDS, zlib_decompressobj__doc__}, + +static PyObject * +zlib_decompressobj_impl(PyModuleDef *module, int wbits, PyObject *zdict); + +static PyObject * +zlib_decompressobj(PyModuleDef *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + static char *_keywords[] = {"wbits", "zdict", NULL}; + int wbits = MAX_WBITS; + PyObject *zdict = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "|iO:decompressobj", _keywords, + &wbits, &zdict)) + goto exit; + return_value = zlib_decompressobj_impl(module, wbits, zdict); + +exit: + return return_value; +} + +PyDoc_STRVAR(zlib_Compress_compress__doc__, +"compress(self, data)\n" +"Returns a bytes object containing compressed data.\n" +"\n" +" data\n" +" Binary data to be compressed.\n" +"\n" +"After calling this function, some of the input data may still\n" +"be stored in internal buffers for later processing.\n" +"Call the flush() method to clear these buffers."); + +#define ZLIB_COMPRESS_COMPRESS_METHODDEF \ + {"compress", (PyCFunction)zlib_Compress_compress, METH_VARARGS, zlib_Compress_compress__doc__}, + +static PyObject * +zlib_Compress_compress_impl(compobject *self, Py_buffer *data); + +static PyObject * +zlib_Compress_compress(compobject *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + + if (!PyArg_ParseTuple(args, + "y*:compress", + &data)) + goto exit; + return_value = zlib_Compress_compress_impl(self, &data); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(zlib_Decompress_decompress__doc__, +"decompress(self, data, max_length=0)\n" +"Return a bytes object containing the decompressed version of the data.\n" +"\n" +" data\n" +" The binary data to decompress.\n" +" max_length\n" +" The maximum allowable length of the decompressed data.\n" +" Unconsumed input data will be stored in\n" +" the unconsumed_tail attribute.\n" +"\n" +"After calling this function, some of the input data may still be stored in\n" +"internal buffers for later processing.\n" +"Call the flush() method to clear these buffers."); + +#define ZLIB_DECOMPRESS_DECOMPRESS_METHODDEF \ + {"decompress", (PyCFunction)zlib_Decompress_decompress, METH_VARARGS, zlib_Decompress_decompress__doc__}, + +static PyObject * +zlib_Decompress_decompress_impl(compobject *self, Py_buffer *data, unsigned int max_length); + +static PyObject * +zlib_Decompress_decompress(compobject *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + unsigned int max_length = 0; + + if (!PyArg_ParseTuple(args, + "y*|O&:decompress", + &data, uint_converter, &max_length)) + goto exit; + return_value = zlib_Decompress_decompress_impl(self, &data, max_length); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(zlib_Compress_flush__doc__, +"flush(self, mode=Z_FINISH)\n" +"Return a bytes object containing any remaining compressed data.\n" +"\n" +" mode\n" +" One of the constants Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH.\n" +" If mode == Z_FINISH, the compressor object can no longer be\n" +" used after calling the flush() method. Otherwise, more data\n" +" can still be compressed."); + +#define ZLIB_COMPRESS_FLUSH_METHODDEF \ + {"flush", (PyCFunction)zlib_Compress_flush, METH_VARARGS, zlib_Compress_flush__doc__}, + +static PyObject * +zlib_Compress_flush_impl(compobject *self, int mode); + +static PyObject * +zlib_Compress_flush(compobject *self, PyObject *args) +{ + PyObject *return_value = NULL; + int mode = Z_FINISH; + + if (!PyArg_ParseTuple(args, + "|i:flush", + &mode)) + goto exit; + return_value = zlib_Compress_flush_impl(self, mode); + +exit: + return return_value; +} + +PyDoc_STRVAR(zlib_Compress_copy__doc__, +"copy(self)\n" +"Return a copy of the compression object."); + +#define ZLIB_COMPRESS_COPY_METHODDEF \ + {"copy", (PyCFunction)zlib_Compress_copy, METH_NOARGS, zlib_Compress_copy__doc__}, + +static PyObject * +zlib_Compress_copy_impl(compobject *self); + +static PyObject * +zlib_Compress_copy(compobject *self, PyObject *Py_UNUSED(ignored)) +{ + return zlib_Compress_copy_impl(self); +} + +PyDoc_STRVAR(zlib_Decompress_copy__doc__, +"copy(self)\n" +"Return a copy of the decompression object."); + +#define ZLIB_DECOMPRESS_COPY_METHODDEF \ + {"copy", (PyCFunction)zlib_Decompress_copy, METH_NOARGS, zlib_Decompress_copy__doc__}, + +static PyObject * +zlib_Decompress_copy_impl(compobject *self); + +static PyObject * +zlib_Decompress_copy(compobject *self, PyObject *Py_UNUSED(ignored)) +{ + return zlib_Decompress_copy_impl(self); +} + +PyDoc_STRVAR(zlib_Decompress_flush__doc__, +"flush(self, length=DEF_BUF_SIZE)\n" +"Return a bytes object containing any remaining decompressed data.\n" +"\n" +" length\n" +" the initial size of the output buffer."); + +#define ZLIB_DECOMPRESS_FLUSH_METHODDEF \ + {"flush", (PyCFunction)zlib_Decompress_flush, METH_VARARGS, zlib_Decompress_flush__doc__}, + +static PyObject * +zlib_Decompress_flush_impl(compobject *self, unsigned int length); + +static PyObject * +zlib_Decompress_flush(compobject *self, PyObject *args) +{ + PyObject *return_value = NULL; + unsigned int length = DEF_BUF_SIZE; + + if (!PyArg_ParseTuple(args, + "|O&:flush", + uint_converter, &length)) + goto exit; + return_value = zlib_Decompress_flush_impl(self, length); + +exit: + return return_value; +} + +PyDoc_STRVAR(zlib_adler32__doc__, +"adler32(module, data, value=1)\n" +"Compute an Adler-32 checksum of data.\n" +"\n" +" value\n" +" Starting value of the checksum.\n" +"\n" +"The returned checksum is an integer."); + +#define ZLIB_ADLER32_METHODDEF \ + {"adler32", (PyCFunction)zlib_adler32, METH_VARARGS, zlib_adler32__doc__}, + +static PyObject * +zlib_adler32_impl(PyModuleDef *module, Py_buffer *data, unsigned int value); + +static PyObject * +zlib_adler32(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + unsigned int value = 1; + + if (!PyArg_ParseTuple(args, + "y*|I:adler32", + &data, &value)) + goto exit; + return_value = zlib_adler32_impl(module, &data, value); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(zlib_crc32__doc__, +"crc32(module, data, value=0)\n" +"Compute a CRC-32 checksum of data.\n" +"\n" +" value\n" +" Starting value of the checksum.\n" +"\n" +"The returned checksum is an integer."); + +#define ZLIB_CRC32_METHODDEF \ + {"crc32", (PyCFunction)zlib_crc32, METH_VARARGS, zlib_crc32__doc__}, + +static PyObject * +zlib_crc32_impl(PyModuleDef *module, Py_buffer *data, unsigned int value); + +static PyObject * +zlib_crc32(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + unsigned int value = 0; + + if (!PyArg_ParseTuple(args, + "y*|I:crc32", + &data, &value)) + goto exit; + return_value = zlib_crc32_impl(module, &data, value); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} +/*[clinic end generated code: checksum=04f94bbaf2652717753e237e4021bf6c92ddffdd]*/ diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -28,10 +28,9 @@ #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif -#define DEF_WBITS MAX_WBITS -/* The output buffer will be increased in chunks of DEFAULTALLOC bytes. */ -#define DEFAULTALLOC (16*1024) +/* Initial buffer size. */ +#define DEF_BUF_SIZE (16*1024) static PyTypeObject Comptype; static PyTypeObject Decomptype; @@ -82,42 +81,13 @@ } /*[clinic input] +output preset file module zlib class zlib.Compress "compobject *" "&Comptype" class zlib.Decompress "compobject *" "&Decomptype" [clinic start generated code]*/ /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ -PyDoc_STRVAR(compressobj__doc__, -"compressobj(level=-1, method=DEFLATED, wbits=15, memlevel=8,\n" -" strategy=Z_DEFAULT_STRATEGY[, zdict])\n" -" -- Return a compressor object.\n" -"\n" -"level is the compression level (an integer in the range 0-9; default is 6).\n" -"Higher compression levels are slower, but produce smaller results.\n" -"\n" -"method is the compression algorithm. If given, this must be DEFLATED.\n" -"\n" -"wbits is the base two logarithm of the window size (range: 8..15).\n" -"\n" -"memlevel controls the amount of memory used for internal compression state.\n" -"Valid values range from 1 to 9. Higher values result in higher memory usage,\n" -"faster compression, and smaller output.\n" -"\n" -"strategy is used to tune the compression algorithm. Possible values are\n" -"Z_DEFAULT_STRATEGY, Z_FILTERED, and Z_HUFFMAN_ONLY.\n" -"\n" -"zdict is the predefined compression dictionary - a sequence of bytes\n" -"containing subsequences that are likely to occur in the input data."); - -PyDoc_STRVAR(decompressobj__doc__, -"decompressobj([wbits[, zdict]]) -- Return a decompressor object.\n" -"\n" -"Optional arg wbits is the window buffer size.\n" -"\n" -"Optional arg zdict is the predefined compression dictionary. This must be\n" -"the same dictionary as used by the compressor that produced the input data."); - static compobject * newcompobject(PyTypeObject *type) { @@ -165,70 +135,20 @@ } /*[clinic input] +zlib.compress -zlib.compress bytes: Py_buffer Binary data to be compressed. - [ - level: int + level: int(c_default="Z_DEFAULT_COMPRESSION") = Z_DEFAULT_COMPRESSION Compression level, in 0-9. - ] / -Returns compressed string. - +Returns a bytes object containing compressed data. [clinic start generated code]*/ -PyDoc_STRVAR(zlib_compress__doc__, -"compress(module, bytes, [level])\n" -"Returns compressed string.\n" -"\n" -" bytes\n" -" Binary data to be compressed.\n" -" level\n" -" Compression level, in 0-9."); - -#define ZLIB_COMPRESS_METHODDEF \ - {"compress", (PyCFunction)zlib_compress, METH_VARARGS, zlib_compress__doc__}, - static PyObject * -zlib_compress_impl(PyModuleDef *module, Py_buffer *bytes, int group_right_1, int level); - -static PyObject * -zlib_compress(PyModuleDef *module, PyObject *args) -{ - PyObject *return_value = NULL; - Py_buffer bytes = {NULL, NULL}; - int group_right_1 = 0; - int level = 0; - - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "y*:compress", &bytes)) - goto exit; - break; - case 2: - if (!PyArg_ParseTuple(args, "y*i:compress", &bytes, &level)) - goto exit; - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "zlib.compress requires 1 to 2 arguments"); - goto exit; - } - return_value = zlib_compress_impl(module, &bytes, group_right_1, level); - -exit: - /* Cleanup for bytes */ - if (bytes.obj) - PyBuffer_Release(&bytes); - - return return_value; -} - -static PyObject * -zlib_compress_impl(PyModuleDef *module, Py_buffer *bytes, int group_right_1, int level) -/*[clinic end generated code: checksum=ce8d4c0a17ecd79c3ffcc032dcdf8ac6830ded1e]*/ +zlib_compress_impl(PyModuleDef *module, Py_buffer *bytes, int level) +/*[clinic end generated code: checksum=5d7dd4588788efd3516e5f4225050d6413632601]*/ { PyObject *ReturnVal = NULL; Byte *input, *output = NULL; @@ -236,9 +156,6 @@ int err; z_stream zst; - if (!group_right_1) - level = Z_DEFAULT_COMPRESSION; - if ((size_t)bytes->len > UINT_MAX) { PyErr_SetString(PyExc_OverflowError, "Size does not fit in an unsigned int"); @@ -312,6 +229,7 @@ class uint_converter(CConverter): type = 'unsigned int' converter = 'uint_converter' + c_ignored_default = "0" [python start generated code]*/ /*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ @@ -347,35 +265,38 @@ return 1; } -PyDoc_STRVAR(decompress__doc__, -"decompress(string[, wbits[, bufsize]]) -- Return decompressed string.\n" -"\n" -"Optional arg wbits is the window buffer size. Optional arg bufsize is\n" -"the initial output buffer size."); +/*[clinic input] +zlib.decompress + + data: Py_buffer + Compressed data. + wbits: int(c_default="MAX_WBITS") = MAX_WBITS + The window buffer size. + bufsize: uint(c_default="DEF_BUF_SIZE") = DEF_BUF_SIZE + The initial output buffer size. + / + +Returns a bytes object containing the uncompressed data. +[clinic start generated code]*/ static PyObject * -PyZlib_decompress(PyObject *self, PyObject *args) +zlib_decompress_impl(PyModuleDef *module, Py_buffer *data, int wbits, unsigned int bufsize) +/*[clinic end generated code: checksum=9e5464e72df9cb5fee73df662dbcaed867e01d32]*/ { PyObject *result_str = NULL; - Py_buffer pinput; Byte *input; unsigned int length; int err; - int wsize=DEF_WBITS; - unsigned int bufsize = DEFAULTALLOC, new_bufsize; + unsigned int new_bufsize; z_stream zst; - if (!PyArg_ParseTuple(args, "y*|iO&:decompress", - &pinput, &wsize, uint_converter, &bufsize)) - return NULL; - - if ((size_t)pinput.len > UINT_MAX) { + if ((size_t)data->len > UINT_MAX) { PyErr_SetString(PyExc_OverflowError, "Size does not fit in an unsigned int"); goto error; } - input = pinput.buf; - length = (unsigned int)pinput.len; + input = data->buf; + length = (unsigned int)data->len; if (bufsize == 0) bufsize = 1; @@ -391,7 +312,7 @@ zst.zfree = PyZlib_Free; zst.next_out = (Byte *)PyBytes_AS_STRING(result_str); zst.next_in = (Byte *)input; - err = inflateInit2(&zst, wsize); + err = inflateInit2(&zst, wbits); switch(err) { case(Z_OK): @@ -457,32 +378,45 @@ if (_PyBytes_Resize(&result_str, zst.total_out) < 0) goto error; - PyBuffer_Release(&pinput); return result_str; error: - PyBuffer_Release(&pinput); Py_XDECREF(result_str); return NULL; } +/*[clinic input] +zlib.compressobj + + level: int(c_default="Z_DEFAULT_COMPRESSION") = Z_DEFAULT_COMPRESSION + The compression level (an integer in the range 0-9; default is 6). + Higher compression levels are slower, but produce smaller results. + method: int(c_default="DEFLATED") = DEFLATED + The compression algorithm. If given, this must be DEFLATED. + wbits: int(c_default="MAX_WBITS") = MAX_WBITS + The base two logarithm of the window size (range: 8..15). + memLevel: int(c_default="DEF_MEM_LEVEL") = DEF_MEM_LEVEL + Controls the amount of memory used for internal compression state. + Valid values range from 1 to 9. Higher values result in higher memory + usage, faster compression, and smaller output. + strategy: int(c_default="Z_DEFAULT_STRATEGY") = Z_DEFAULT_STRATEGY + Used to tune the compression algorithm. Possible values are + Z_DEFAULT_STRATEGY, Z_FILTERED, and Z_HUFFMAN_ONLY. + zdict: Py_buffer = None + The predefined compression dictionary - a sequence of bytes + containing subsequences that are likely to occur in the input data. + +Return a compressor object. +[clinic start generated code]*/ + static PyObject * -PyZlib_compressobj(PyObject *selfptr, PyObject *args, PyObject *kwargs) +zlib_compressobj_impl(PyModuleDef *module, int level, int method, int wbits, int memLevel, int strategy, Py_buffer *zdict) +/*[clinic end generated code: checksum=89e5a6c1449caa9ed76f1baad066600e985151a9]*/ { compobject *self = NULL; - int level=Z_DEFAULT_COMPRESSION, method=DEFLATED; - int wbits=MAX_WBITS, memLevel=DEF_MEM_LEVEL, strategy=0, err; - Py_buffer zdict; - static char *kwlist[] = {"level", "method", "wbits", - "memLevel", "strategy", "zdict", NULL}; + int err; - zdict.buf = NULL; /* Sentinel, so we can tell whether zdict was supplied. */ - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iiiiiy*:compressobj", - kwlist, &level, &method, &wbits, - &memLevel, &strategy, &zdict)) - return NULL; - - if (zdict.buf != NULL && (size_t)zdict.len > UINT_MAX) { + if (zdict->buf != NULL && (size_t)zdict->len > UINT_MAX) { PyErr_SetString(PyExc_OverflowError, "zdict length does not fit in an unsigned int"); goto error; @@ -500,11 +434,11 @@ switch(err) { case (Z_OK): self->is_initialised = 1; - if (zdict.buf == NULL) { + if (zdict->buf == NULL) { goto success; } else { err = deflateSetDictionary(&self->zst, - zdict.buf, (unsigned int)zdict.len); + zdict->buf, (unsigned int)zdict->len); switch (err) { case (Z_OK): goto success; @@ -532,22 +466,28 @@ Py_XDECREF(self); self = NULL; success: - if (zdict.buf != NULL) - PyBuffer_Release(&zdict); return (PyObject*)self; } +/*[clinic input] +zlib.decompressobj + + wbits: int(c_default="MAX_WBITS") = MAX_WBITS + The window buffer size. + zdict: object(c_default="NULL") = b'' + The predefined compression dictionary. This must be the same + dictionary as used by the compressor that produced the input data. + +Return a decompressor object. +[clinic start generated code]*/ + static PyObject * -PyZlib_decompressobj(PyObject *selfptr, PyObject *args, PyObject *kwargs) +zlib_decompressobj_impl(PyModuleDef *module, int wbits, PyObject *zdict) +/*[clinic end generated code: checksum=8ccd583fbd631798566d415933cd44440c8a74b5]*/ { - static char *kwlist[] = {"wbits", "zdict", NULL}; - int wbits=DEF_WBITS, err; + int err; compobject *self; - PyObject *zdict=NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iO:decompressobj", - kwlist, &wbits, &zdict)) - return NULL; if (zdict != NULL && !PyObject_CheckBuffer(zdict)) { PyErr_SetString(PyExc_TypeError, "zdict argument must support the buffer protocol"); @@ -615,37 +555,41 @@ Dealloc(self); } -PyDoc_STRVAR(comp_compress__doc__, -"compress(data) -- Return a string containing data compressed.\n" -"\n" -"After calling this function, some of the input data may still\n" -"be stored in internal buffers for later processing.\n" -"Call the flush() method to clear these buffers."); +/*[clinic input] +zlib.Compress.compress + data: Py_buffer + Binary data to be compressed. + / + +Returns a bytes object containing compressed data. + +After calling this function, some of the input data may still +be stored in internal buffers for later processing. +Call the flush() method to clear these buffers. +[clinic start generated code]*/ static PyObject * -PyZlib_objcompress(compobject *self, PyObject *args) +zlib_Compress_compress_impl(compobject *self, Py_buffer *data) +/*[clinic end generated code: checksum=5d5cd791cbc6a7f4b6de4ec12c085c88d4d3e31c]*/ { int err; unsigned int inplen; - unsigned int length = DEFAULTALLOC, new_length; - PyObject *RetVal = NULL; - Py_buffer pinput; + unsigned int length = DEF_BUF_SIZE, new_length; + PyObject *RetVal; Byte *input; unsigned long start_total_out; - if (!PyArg_ParseTuple(args, "y*:compress", &pinput)) - return NULL; - if ((size_t)pinput.len > UINT_MAX) { + if ((size_t)data->len > UINT_MAX) { PyErr_SetString(PyExc_OverflowError, "Size does not fit in an unsigned int"); - goto error_outer; + return NULL; } - input = pinput.buf; - inplen = (unsigned int)pinput.len; + input = data->buf; + inplen = (unsigned int)data->len; if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) - goto error_outer; + return NULL; ENTER_ZLIB(self); @@ -668,7 +612,7 @@ new_length = UINT_MAX; if (_PyBytes_Resize(&RetVal, new_length) < 0) { Py_CLEAR(RetVal); - goto error; + goto done; } self->zst.next_out = (unsigned char *)PyBytes_AS_STRING(RetVal) + length; @@ -686,18 +630,15 @@ if (err != Z_OK && err != Z_BUF_ERROR) { zlib_error(self->zst, err, "while compressing data"); - Py_DECREF(RetVal); - RetVal = NULL; - goto error; + Py_CLEAR(RetVal); + goto done; } if (_PyBytes_Resize(&RetVal, self->zst.total_out - start_total_out) < 0) { Py_CLEAR(RetVal); } - error: + done: LEAVE_ZLIB(self); - error_outer: - PyBuffer_Release(&pinput); return RetVal; } @@ -745,7 +686,6 @@ } /*[clinic input] - zlib.Decompress.decompress data: Py_buffer @@ -756,61 +696,19 @@ the unconsumed_tail attribute. / -Return a string containing the decompressed version of the data. +Return a bytes object containing the decompressed version of the data. After calling this function, some of the input data may still be stored in internal buffers for later processing. Call the flush() method to clear these buffers. [clinic start generated code]*/ -PyDoc_STRVAR(zlib_Decompress_decompress__doc__, -"decompress(self, data, max_length=0)\n" -"Return a string containing the decompressed version of the data.\n" -"\n" -" data\n" -" The binary data to decompress.\n" -" max_length\n" -" The maximum allowable length of the decompressed data.\n" -" Unconsumed input data will be stored in\n" -" the unconsumed_tail attribute.\n" -"\n" -"After calling this function, some of the input data may still be stored in\n" -"internal buffers for later processing.\n" -"Call the flush() method to clear these buffers."); - -#define ZLIB_DECOMPRESS_DECOMPRESS_METHODDEF \ - {"decompress", (PyCFunction)zlib_Decompress_decompress, METH_VARARGS, zlib_Decompress_decompress__doc__}, - -static PyObject * -zlib_Decompress_decompress_impl(compobject *self, Py_buffer *data, unsigned int max_length); - -static PyObject * -zlib_Decompress_decompress(compobject *self, PyObject *args) -{ - PyObject *return_value = NULL; - Py_buffer data = {NULL, NULL}; - unsigned int max_length = 0; - - if (!PyArg_ParseTuple(args, - "y*|O&:decompress", - &data, uint_converter, &max_length)) - goto exit; - return_value = zlib_Decompress_decompress_impl(self, &data, max_length); - -exit: - /* Cleanup for data */ - if (data.obj) - PyBuffer_Release(&data); - - return return_value; -} - static PyObject * zlib_Decompress_decompress_impl(compobject *self, Py_buffer *data, unsigned int max_length) -/*[clinic end generated code: checksum=b7fd2e3b23430f57f5a84817189575bc46464901]*/ +/*[clinic end generated code: checksum=755cccc9087bfe55486b7e15fa7e2ab60b4c86d6]*/ { int err; - unsigned int old_length, length = DEFAULTALLOC; + unsigned int old_length, length = DEF_BUF_SIZE; PyObject *RetVal = NULL; unsigned long start_total_out; @@ -927,29 +825,31 @@ return RetVal; } -PyDoc_STRVAR(comp_flush__doc__, -"flush( [mode] ) -- Return a string containing any remaining compressed data.\n" -"\n" -"mode can be one of the constants Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH; the\n" -"default value used when mode is not specified is Z_FINISH.\n" -"If mode == Z_FINISH, the compressor object can no longer be used after\n" -"calling the flush() method. Otherwise, more data can still be compressed."); +/*[clinic input] +zlib.Compress.flush + + mode: int(c_default="Z_FINISH") = Z_FINISH + One of the constants Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH. + If mode == Z_FINISH, the compressor object can no longer be + used after calling the flush() method. Otherwise, more data + can still be compressed. + / + +Return a bytes object containing any remaining compressed data. +[clinic start generated code]*/ static PyObject * -PyZlib_flush(compobject *self, PyObject *args) +zlib_Compress_flush_impl(compobject *self, int mode) +/*[clinic end generated code: checksum=a203f4cefc9de727aa1d2ea39d11c0a16c32041a]*/ { int err; - unsigned int length = DEFAULTALLOC, new_length; + unsigned int length = DEF_BUF_SIZE, new_length; PyObject *RetVal; - int flushmode = Z_FINISH; unsigned long start_total_out; - if (!PyArg_ParseTuple(args, "|i:flush", &flushmode)) - return NULL; - /* Flushing with Z_NO_FLUSH is a no-op, so there's no point in doing any work at all; just return an empty string. */ - if (flushmode == Z_NO_FLUSH) { + if (mode == Z_NO_FLUSH) { return PyBytes_FromStringAndSize(NULL, 0); } @@ -964,7 +864,7 @@ self->zst.next_out = (unsigned char *)PyBytes_AS_STRING(RetVal); Py_BEGIN_ALLOW_THREADS - err = deflate(&(self->zst), flushmode); + err = deflate(&(self->zst), mode); Py_END_ALLOW_THREADS /* while Z_OK and the output buffer is full, there might be more output, @@ -984,14 +884,14 @@ length = new_length; Py_BEGIN_ALLOW_THREADS - err = deflate(&(self->zst), flushmode); + err = deflate(&(self->zst), mode); Py_END_ALLOW_THREADS } - /* If flushmode is Z_FINISH, we also have to call deflateEnd() to free + /* If mode is Z_FINISH, we also have to call deflateEnd() to free various data structures. Note we should only get Z_STREAM_END when - flushmode is Z_FINISH, but checking both for safety*/ - if (err == Z_STREAM_END && flushmode == Z_FINISH) { + mode is Z_FINISH, but checking both for safety*/ + if (err == Z_STREAM_END && mode == Z_FINISH) { err = deflateEnd(&(self->zst)); if (err != Z_OK) { zlib_error(self->zst, err, "while finishing compression"); @@ -1031,25 +931,9 @@ Return a copy of the compression object. [clinic start generated code]*/ -PyDoc_STRVAR(zlib_Compress_copy__doc__, -"copy(self)\n" -"Return a copy of the compression object."); - -#define ZLIB_COMPRESS_COPY_METHODDEF \ - {"copy", (PyCFunction)zlib_Compress_copy, METH_NOARGS, zlib_Compress_copy__doc__}, - -static PyObject * -zlib_Compress_copy_impl(compobject *self); - -static PyObject * -zlib_Compress_copy(compobject *self, PyObject *Py_UNUSED(ignored)) -{ - return zlib_Compress_copy_impl(self); -} - static PyObject * zlib_Compress_copy_impl(compobject *self) -/*[clinic end generated code: checksum=7aa841ad51297eb83250f511a76872e88fdc737e]*/ +/*[clinic end generated code: checksum=5144aa153c21e805afa5c19e5b48cf8e6480b5da]*/ { compobject *retval = NULL; int err; @@ -1099,11 +983,15 @@ return NULL; } -PyDoc_STRVAR(decomp_copy__doc__, -"copy() -- Return a copy of the decompression object."); +/*[clinic input] +zlib.Decompress.copy + +Return a copy of the decompression object. +[clinic start generated code]*/ static PyObject * -PyZlib_uncopy(compobject *self) +zlib_Decompress_copy_impl(compobject *self) +/*[clinic end generated code: checksum=02a883a2a510c8ccfeef3f89e317a275bfe8c094]*/ { compobject *retval = NULL; int err; @@ -1155,24 +1043,26 @@ } #endif -PyDoc_STRVAR(decomp_flush__doc__, -"flush( [length] ) -- Return a string containing any remaining\n" -"decompressed data. length, if given, is the initial size of the\n" -"output buffer.\n" -"\n" -"The decompressor object can no longer be used after this call."); +/*[clinic input] +zlib.Decompress.flush + + length: uint(c_default="DEF_BUF_SIZE") = DEF_BUF_SIZE + the initial size of the output buffer. + / + +Return a bytes object containing any remaining decompressed data. +[clinic start generated code]*/ static PyObject * -PyZlib_unflush(compobject *self, PyObject *args) +zlib_Decompress_flush_impl(compobject *self, unsigned int length) +/*[clinic end generated code: checksum=db6fb753ab698e22afe3957c9da9e5e77f4bfc08]*/ { int err; - unsigned int length = DEFAULTALLOC, new_length; + unsigned int new_length; PyObject * retval = NULL; unsigned long start_total_out; Py_ssize_t size; - if (!PyArg_ParseTuple(args, "|O&:flush", uint_converter, &length)) - return NULL; if (length == 0) { PyErr_SetString(PyExc_ValueError, "length must be greater than zero"); return NULL; @@ -1248,12 +1138,12 @@ return retval; } +#include "zlibmodule.clinic.c" + static PyMethodDef comp_methods[] = { - {"compress", (binaryfunc)PyZlib_objcompress, METH_VARARGS, - comp_compress__doc__}, - {"flush", (binaryfunc)PyZlib_flush, METH_VARARGS, - comp_flush__doc__}, + ZLIB_COMPRESS_COMPRESS_METHODDEF + ZLIB_COMPRESS_FLUSH_METHODDEF #ifdef HAVE_ZLIB_COPY ZLIB_COMPRESS_COPY_METHODDEF #endif @@ -1263,11 +1153,9 @@ static PyMethodDef Decomp_methods[] = { ZLIB_DECOMPRESS_DECOMPRESS_METHODDEF - {"flush", (binaryfunc)PyZlib_unflush, METH_VARARGS, - decomp_flush__doc__}, + ZLIB_DECOMPRESS_FLUSH_METHODDEF #ifdef HAVE_ZLIB_COPY - {"copy", (PyCFunction)PyZlib_uncopy, METH_NOARGS, - decomp_copy__doc__}, + ZLIB_DECOMPRESS_COPY_METHODDEF #endif {NULL, NULL} }; @@ -1280,95 +1168,95 @@ {NULL}, }; -PyDoc_STRVAR(adler32__doc__, -"adler32(string[, start]) -- Compute an Adler-32 checksum of string.\n" -"\n" -"An optional starting value can be specified. The returned checksum is\n" -"an integer."); +/*[clinic input] +zlib.adler32 + + data: Py_buffer + value: unsigned_int(bitwise=True) = 1 + Starting value of the checksum. + / + +Compute an Adler-32 checksum of data. + +The returned checksum is an integer. +[clinic start generated code]*/ static PyObject * -PyZlib_adler32(PyObject *self, PyObject *args) +zlib_adler32_impl(PyModuleDef *module, Py_buffer *data, unsigned int value) +/*[clinic end generated code: checksum=51d6d75ee655c78af8c968fdb4c11d97e62c67d5]*/ { - unsigned int adler32val = 1; /* adler32(0L, Z_NULL, 0) */ - Py_buffer pbuf; - - if (!PyArg_ParseTuple(args, "y*|I:adler32", &pbuf, &adler32val)) - return NULL; /* Releasing the GIL for very small buffers is inefficient and may lower performance */ - if (pbuf.len > 1024*5) { - unsigned char *buf = pbuf.buf; - Py_ssize_t len = pbuf.len; + if (data->len > 1024*5) { + unsigned char *buf = data->buf; + Py_ssize_t len = data->len; Py_BEGIN_ALLOW_THREADS /* Avoid truncation of length for very large buffers. adler32() takes length as an unsigned int, which may be narrower than Py_ssize_t. */ while ((size_t)len > UINT_MAX) { - adler32val = adler32(adler32val, buf, UINT_MAX); + value = adler32(value, buf, UINT_MAX); buf += (size_t) UINT_MAX; len -= (size_t) UINT_MAX; } - adler32val = adler32(adler32val, buf, (unsigned int)len); + value = adler32(value, buf, (unsigned int)len); Py_END_ALLOW_THREADS } else { - adler32val = adler32(adler32val, pbuf.buf, (unsigned int)pbuf.len); + value = adler32(value, data->buf, (unsigned int)data->len); } - PyBuffer_Release(&pbuf); - return PyLong_FromUnsignedLong(adler32val & 0xffffffffU); + return PyLong_FromUnsignedLong(value & 0xffffffffU); } -PyDoc_STRVAR(crc32__doc__, -"crc32(string[, start]) -- Compute a CRC-32 checksum of string.\n" -"\n" -"An optional starting value can be specified. The returned checksum is\n" -"an integer."); +/*[clinic input] +zlib.crc32 + + data: Py_buffer + value: unsigned_int(bitwise=True) = 0 + Starting value of the checksum. + / + +Compute a CRC-32 checksum of data. + +The returned checksum is an integer. +[clinic start generated code]*/ static PyObject * -PyZlib_crc32(PyObject *self, PyObject *args) +zlib_crc32_impl(PyModuleDef *module, Py_buffer *data, unsigned int value) +/*[clinic end generated code: checksum=c1e986e74fe7b62369998a71a81ebeb9b73e8d4c]*/ { - unsigned int crc32val = 0; /* crc32(0L, Z_NULL, 0) */ - Py_buffer pbuf; int signed_val; - if (!PyArg_ParseTuple(args, "y*|I:crc32", &pbuf, &crc32val)) - return NULL; /* Releasing the GIL for very small buffers is inefficient and may lower performance */ - if (pbuf.len > 1024*5) { - unsigned char *buf = pbuf.buf; - Py_ssize_t len = pbuf.len; + if (data->len > 1024*5) { + unsigned char *buf = data->buf; + Py_ssize_t len = data->len; Py_BEGIN_ALLOW_THREADS /* Avoid truncation of length for very large buffers. crc32() takes length as an unsigned int, which may be narrower than Py_ssize_t. */ while ((size_t)len > UINT_MAX) { - crc32val = crc32(crc32val, buf, UINT_MAX); + value = crc32(value, buf, UINT_MAX); buf += (size_t) UINT_MAX; len -= (size_t) UINT_MAX; } - signed_val = crc32(crc32val, buf, (unsigned int)len); + signed_val = crc32(value, buf, (unsigned int)len); Py_END_ALLOW_THREADS } else { - signed_val = crc32(crc32val, pbuf.buf, (unsigned int)pbuf.len); + signed_val = crc32(value, data->buf, (unsigned int)data->len); } - PyBuffer_Release(&pbuf); return PyLong_FromUnsignedLong(signed_val & 0xffffffffU); } static PyMethodDef zlib_methods[] = { - {"adler32", (PyCFunction)PyZlib_adler32, METH_VARARGS, - adler32__doc__}, + ZLIB_ADLER32_METHODDEF ZLIB_COMPRESS_METHODDEF - {"compressobj", (PyCFunction)PyZlib_compressobj, METH_VARARGS|METH_KEYWORDS, - compressobj__doc__}, - {"crc32", (PyCFunction)PyZlib_crc32, METH_VARARGS, - crc32__doc__}, - {"decompress", (PyCFunction)PyZlib_decompress, METH_VARARGS, - decompress__doc__}, - {"decompressobj", (PyCFunction)PyZlib_decompressobj, METH_VARARGS|METH_KEYWORDS, - decompressobj__doc__}, + ZLIB_COMPRESSOBJ_METHODDEF + ZLIB_CRC32_METHODDEF + ZLIB_DECOMPRESS_METHODDEF + ZLIB_DECOMPRESSOBJ_METHODDEF {NULL, NULL} }; @@ -1482,6 +1370,7 @@ PyModule_AddIntMacro(m, MAX_WBITS); PyModule_AddIntMacro(m, DEFLATED); PyModule_AddIntMacro(m, DEF_MEM_LEVEL); + PyModule_AddIntMacro(m, DEF_BUF_SIZE); PyModule_AddIntMacro(m, Z_BEST_SPEED); PyModule_AddIntMacro(m, Z_BEST_COMPRESSION); PyModule_AddIntMacro(m, Z_DEFAULT_COMPRESSION); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 23:34:04 2014 From: python-checkins at python.org (victor.stinner) Date: Sun, 26 Jan 2014 23:34:04 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320367=3A_Add_Glen?= =?utf-8?q?n_Langford_to_Misc/ACKS?= Message-ID: <3fC85S20NRz7LjS@mail.python.org> http://hg.python.org/cpython/rev/1dac8c954488 changeset: 88737:1dac8c954488 user: Victor Stinner date: Sun Jan 26 23:33:49 2014 +0100 summary: Issue #20367: Add Glenn Langford to Misc/ACKS 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 @@ -725,6 +725,7 @@ Torsten Landschoff ?ukasz Langa Tino Lange +Glenn Langford Andrew Langmead Detlef Lannert Soren Larsen -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun Jan 26 23:59:23 2014 From: python-checkins at python.org (eli.bendersky) Date: Sun, 26 Jan 2014 23:59:23 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Update_docstring_to_mentio?= =?utf-8?q?n_correct_PEP_number=2E?= Message-ID: <3fC8fg57cfz7LkF@mail.python.org> http://hg.python.org/cpython/rev/d0b1058efe20 changeset: 88738:d0b1058efe20 user: Eli Bendersky date: Sun Jan 26 14:59:30 2014 -0800 summary: Update docstring to mention correct PEP number. This file hasn't been touched since its initial commit in 2006. In CPython default branch (3.4), the relevant PEP number is 3333. files: Lib/wsgiref/__init__.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/wsgiref/__init__.py b/Lib/wsgiref/__init__.py --- a/Lib/wsgiref/__init__.py +++ b/Lib/wsgiref/__init__.py @@ -1,4 +1,4 @@ -"""wsgiref -- a WSGI (PEP 333) Reference Library +"""wsgiref -- a WSGI (PEP 3333) Reference Library Current Contents: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 01:04:12 2014 From: python-checkins at python.org (christian.heimes) Date: Mon, 27 Jan 2014 01:04:12 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_silence_compiler_warning_t?= =?utf-8?q?hat_=27s=27_may_be_used_uninitialized_in_the_load?= Message-ID: <3fCB5S6gGMzSqK@mail.python.org> http://hg.python.org/cpython/rev/efa65b43cc96 changeset: 88739:efa65b43cc96 user: Christian Heimes date: Mon Jan 27 01:03:53 2014 +0100 summary: silence compiler warning that 's' may be used uninitialized in the load function. files: Modules/_pickle.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -6149,7 +6149,7 @@ load(UnpicklerObject *self) { PyObject *value = NULL; - char *s; + char *s = NULL; self->num_marks = 0; self->proto = 0; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 01:07:07 2014 From: python-checkins at python.org (christian.heimes) Date: Mon, 27 Jan 2014 01:07:07 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320193=3A_Fix_comm?= =?utf-8?q?it_r6f217456b9ba_by_including_clinic/zlibmodule=2Ec=2Eh?= Message-ID: <3fCB8q5gKJz7LjS@mail.python.org> http://hg.python.org/cpython/rev/c2e425a05d35 changeset: 88740:c2e425a05d35 user: Christian Heimes date: Mon Jan 27 01:06:57 2014 +0100 summary: Issue #20193: Fix commit r6f217456b9ba by including clinic/zlibmodule.c.h instead of zlibmodule.clinic.c files: Modules/zlibmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -1138,7 +1138,7 @@ return retval; } -#include "zlibmodule.clinic.c" +#include "clinic/zlibmodule.c.h" static PyMethodDef comp_methods[] = { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 01:12:28 2014 From: python-checkins at python.org (christian.heimes) Date: Mon, 27 Jan 2014 01:12:28 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320394=3A_Attempt_?= =?utf-8?q?to_silence_CID_1164423=3A_Division_or_modulo_by_zero_in?= Message-ID: <3fCBH05t6Zz7LkF@mail.python.org> http://hg.python.org/cpython/rev/bf52f2dbfdde changeset: 88741:bf52f2dbfdde user: Christian Heimes date: Mon Jan 27 01:12:00 2014 +0100 summary: Issue #20394: Attempt to silence CID 1164423: Division or modulo by zero in audioop_ratecv_impl() Serhiy and I had the same idea so it's most likely right. ;) files: Modules/audioop.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Modules/audioop.c b/Modules/audioop.c --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -1304,6 +1304,7 @@ "weightA should be >= 1, weightB should be >= 0"); return NULL; } + assert(fragment->len >= 0); if (fragment->len % bytes_per_frame != 0) { PyErr_SetString(AudioopError, "not a whole number of frames"); return NULL; @@ -1370,7 +1371,7 @@ case ceiling(len/inrate) * outrate. */ /* compute ceiling(len/inrate) without overflow */ - Py_ssize_t q = len > 0 ? 1 + (len - 1) / inrate : 0; + Py_ssize_t q = 1 + (len - 1) / inrate; if (outrate > PY_SSIZE_T_MAX / q / bytes_per_frame) str = NULL; else -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 02:25:03 2014 From: python-checkins at python.org (terry.reedy) Date: Mon, 27 Jan 2014 02:25:03 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIwMzM4?= =?utf-8?q?=3A_Increase_allowed_tip_width_slightly_and_wrap_long_signagure?= =?utf-8?q?_lines=2E?= Message-ID: <3fCCtl1wbTz7LmM@mail.python.org> http://hg.python.org/cpython/rev/d960c4cabb2b changeset: 88742:d960c4cabb2b branch: 2.7 parent: 88641:bcfbab86f49a user: Terry Jan Reedy date: Sun Jan 26 19:55:07 2014 -0500 summary: Issue #20338: Increase allowed tip width slightly and wrap long signagure lines. Original patch by Serhiy Storchaka. files: Lib/idlelib/CallTips.py | 22 +++++++++---- Lib/idlelib/idle_test/test_calltips.py | 13 ++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -5,14 +5,15 @@ which disappear when you type a closing parenthesis. """ +import __main__ import re import sys +import textwrap import types from idlelib import CallTipWindow from idlelib.HyperParser import HyperParser -import __main__ class CallTips: @@ -131,8 +132,9 @@ return None # The following are used in get_arg_text -_MAX_COLS = 79 +_MAX_COLS = 85 _MAX_LINES = 5 # enough for bytes +_INDENT = ' '*4 # for wrapped signatures def get_arg_text(ob): '''Return a string describing the signature of a callable object, or ''. @@ -147,11 +149,15 @@ try: ob_call = ob.__call__ except BaseException: - return argspec + if type(ob) is types.ClassType: # old-style + ob_call = ob + else: + return argspec arg_offset = 0 if type(ob) in (types.ClassType, types.TypeType): - # Look for the highest __init__ in the class chain. + # Look for the first __init__ in the class chain with .im_func. + # Slot wrappers (builtins, classes defined in funcs) do not. fob = _find_constructor(ob) if fob is None: fob = lambda: None @@ -183,14 +189,16 @@ items.append("**kwds") argspec = ", ".join(items) argspec = "(%s)" % re.sub("(?", argspec) - # See if we can use the docstring + + lines = (textwrap.wrap(argspec, _MAX_COLS, subsequent_indent=_INDENT) + if len(argspec) > _MAX_COLS else [argspec] if argspec else []) + if isinstance(ob_call, types.MethodType): doc = ob_call.__doc__ else: doc = getattr(ob, "__doc__", "") if doc: - lines = [argspec] if argspec else [] - for line in doc.split('\n', 5)[:_MAX_LINES]: + for line in doc.split('\n', _MAX_LINES)[:_MAX_LINES]: line = line.strip() if not line: break diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -1,6 +1,7 @@ import unittest import idlelib.CallTips as ct CTi = ct.CallTips() # needed for get_entity test in 2.7 +import textwrap import types default_tip = '' @@ -66,6 +67,18 @@ gtest(types.MethodType, '()\ninstancemethod(function, instance, class)') gtest(SB(), default_tip) + def test_signature_wrap(self): + # This is also a test of an old-style class + self.assertEqual(signature(textwrap.TextWrapper), '''\ +(width=70, initial_indent='', subsequent_indent='', expand_tabs=True, + replace_whitespace=True, fix_sentence_endings=False, break_long_words=True, + drop_whitespace=True, break_on_hyphens=True)''') + + def test_docline_truncation(self): + def f(): pass + f.__doc__ = 'a'*300 + self.assertEqual(signature(f), '()\n' + 'a' * (ct._MAX_COLS-3) + '...') + def test_multiline_docstring(self): # Test fewer lines than max. self.assertEqual(signature(list), -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 02:25:04 2014 From: python-checkins at python.org (terry.reedy) Date: Mon, 27 Jan 2014 02:25:04 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMzM4?= =?utf-8?q?=3A_Increase_allowed_tip_width_slightly_and_wrap_long_signagure?= =?utf-8?q?_lines=2E?= Message-ID: <3fCCtm4q85z7Lmd@mail.python.org> http://hg.python.org/cpython/rev/7dcc19308a7b changeset: 88743:7dcc19308a7b branch: 3.3 parent: 88642:b26db63bb931 user: Terry Jan Reedy date: Sun Jan 26 19:55:34 2014 -0500 summary: Issue #20338: Increase allowed tip width slightly and wrap long signagure lines. Original patch by Serhiy Storchaka. files: Lib/idlelib/CallTips.py | 15 +++-- Lib/idlelib/idle_test/test_calltips.py | 32 ++++++++++--- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -5,16 +5,16 @@ which disappear when you type a closing parenthesis. """ +import __main__ +import inspect import re import sys +import textwrap import types -import inspect from idlelib import CallTipWindow from idlelib.HyperParser import HyperParser -import __main__ - class CallTips: menudefs = [ @@ -117,8 +117,9 @@ return None # The following are used in get_argspec and some in tests -_MAX_COLS = 79 +_MAX_COLS = 85 _MAX_LINES = 5 # enough for bytes +_INDENT = ' '*4 # for wrapped signatures _first_param = re.compile('(?<=\()\w*\,?\s*') _default_callable_argspec = "See source or doc" @@ -149,13 +150,15 @@ isinstance(ob_call, types.MethodType)): argspec = _first_param.sub("", argspec) + lines = (textwrap.wrap(argspec, _MAX_COLS, subsequent_indent=_INDENT) + if len(argspec) > _MAX_COLS else [argspec] if argspec else []) + if isinstance(ob_call, types.MethodType): doc = ob_call.__doc__ else: doc = getattr(ob, "__doc__", "") if doc: - lines = [argspec] if argspec else [] - for line in doc.split('\n', 5)[:_MAX_LINES]: + for line in doc.split('\n', _MAX_LINES)[:_MAX_LINES]: line = line.strip() if not line: break diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -1,5 +1,6 @@ import unittest import idlelib.CallTips as ct +import textwrap import types default_tip = ct._default_callable_argspec @@ -64,20 +65,35 @@ gtest(types.MethodType, "method(function, instance)") gtest(SB(), default_tip) + def test_signature_wrap(self): + self.assertEqual(signature(textwrap.TextWrapper), '''\ +(width=70, initial_indent='', subsequent_indent='', expand_tabs=True, + replace_whitespace=True, fix_sentence_endings=False, break_long_words=True, + drop_whitespace=True, break_on_hyphens=True, tabsize=8)''') + + def test_docline_truncation(self): + def f(): pass + f.__doc__ = 'a'*300 + self.assertEqual(signature(f), '()\n' + 'a' * (ct._MAX_COLS-3) + '...') + def test_multiline_docstring(self): # Test fewer lines than max. self.assertEqual(signature(list), "list() -> new empty list\n" "list(iterable) -> new list initialized from iterable's items") - # Test max lines and line (currently) too long. - self.assertEqual(signature(bytes), -"bytes(iterable_of_ints) -> bytes\n" -"bytes(string, encoding[, errors]) -> bytes\n" -"bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer\n" -#bytes(int) -> bytes object of size given by the parameter initialized with null bytes -"bytes(int) -> bytes object of size given by the parameter initialized with n...\n" -"bytes() -> empty bytes object") + # Test max lines + self.assertEqual(signature(bytes), '''\ +bytes(iterable_of_ints) -> bytes +bytes(string, encoding[, errors]) -> bytes +bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer +bytes(int) -> bytes object of size given by the parameter initialized with null bytes +bytes() -> empty bytes object''') + + # Test more than max lines + def f(): pass + f.__doc__ = 'a\n' * 15 + self.assertEqual(signature(f), '()' + '\na' * ct._MAX_LINES) def test_functions(self): def t1(): 'doc' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 02:25:06 2014 From: python-checkins at python.org (terry.reedy) Date: Mon, 27 Jan 2014 02:25:06 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320338=3A_Increase_allowed_tip_width_slightly_an?= =?utf-8?q?d_wrap_long_signagure_lines=2E?= Message-ID: <3fCCtp0Lzrz7LmP@mail.python.org> http://hg.python.org/cpython/rev/f7061219303c changeset: 88744:f7061219303c parent: 88643:aa1ad9e2f978 parent: 88743:7dcc19308a7b user: Terry Jan Reedy date: Sun Jan 26 20:08:26 2014 -0500 summary: Issue #20338: Increase allowed tip width slightly and wrap long signagure lines. Original patch by Serhiy Storchaka. files: Lib/idlelib/CallTips.py | 15 +++-- Lib/idlelib/idle_test/test_calltips.py | 34 ++++++++++--- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -5,16 +5,16 @@ which disappear when you type a closing parenthesis. """ +import __main__ +import inspect import re import sys +import textwrap import types -import inspect from idlelib import CallTipWindow from idlelib.HyperParser import HyperParser -import __main__ - class CallTips: menudefs = [ @@ -117,8 +117,9 @@ return None # The following are used in get_argspec and some in tests -_MAX_COLS = 79 +_MAX_COLS = 85 _MAX_LINES = 5 # enough for bytes +_INDENT = ' '*4 # for wrapped signatures _first_param = re.compile('(?<=\()\w*\,?\s*') _default_callable_argspec = "See source or doc" @@ -149,13 +150,15 @@ isinstance(ob_call, types.MethodType)): argspec = _first_param.sub("", argspec) + lines = (textwrap.wrap(argspec, _MAX_COLS, subsequent_indent=_INDENT) + if len(argspec) > _MAX_COLS else [argspec] if argspec else []) + if isinstance(ob_call, types.MethodType): doc = ob_call.__doc__ else: doc = getattr(ob, "__doc__", "") if doc: - lines = [argspec] if argspec else [] - for line in doc.split('\n', 5)[:_MAX_LINES]: + for line in doc.split('\n', _MAX_LINES)[:_MAX_LINES]: line = line.strip() if not line: break diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -1,5 +1,6 @@ import unittest import idlelib.CallTips as ct +import textwrap import types default_tip = ct._default_callable_argspec @@ -64,20 +65,37 @@ gtest(types.MethodType, "method(function, instance)") gtest(SB(), default_tip) + def test_signature_wrap(self): + #print(signature(textwrap.TextWrapper)) + self.assertEqual(signature(textwrap.TextWrapper), '''\ +(width=70, initial_indent='', subsequent_indent='', expand_tabs=True, + replace_whitespace=True, fix_sentence_endings=False, break_long_words=True, + drop_whitespace=True, break_on_hyphens=True, tabsize=8, *, max_lines=None, + placeholder=' [...]')''') + + def test_docline_truncation(self): + def f(): pass + f.__doc__ = 'a'*300 + self.assertEqual(signature(f), '()\n' + 'a' * (ct._MAX_COLS-3) + '...') + def test_multiline_docstring(self): # Test fewer lines than max. self.assertEqual(signature(list), "list() -> new empty list\n" "list(iterable) -> new list initialized from iterable's items") - # Test max lines and line (currently) too long. - self.assertEqual(signature(bytes), -"bytes(iterable_of_ints) -> bytes\n" -"bytes(string, encoding[, errors]) -> bytes\n" -"bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer\n" -#bytes(int) -> bytes object of size given by the parameter initialized with null bytes -"bytes(int) -> bytes object of size given by the parameter initialized with n...\n" -"bytes() -> empty bytes object") + # Test max lines + self.assertEqual(signature(bytes), '''\ +bytes(iterable_of_ints) -> bytes +bytes(string, encoding[, errors]) -> bytes +bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer +bytes(int) -> bytes object of size given by the parameter initialized with null bytes +bytes() -> empty bytes object''') + + # Test more than max lines + def f(): pass + f.__doc__ = 'a\n' * 15 + self.assertEqual(signature(f), '()' + '\na' * ct._MAX_LINES) def test_functions(self): def t1(): 'doc' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 02:25:07 2014 From: python-checkins at python.org (terry.reedy) Date: Mon, 27 Jan 2014 02:25:07 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf-8?q?_Merge_heads=2E?= Message-ID: <3fCCtq1sLgz7Lmt@mail.python.org> http://hg.python.org/cpython/rev/87e7a59d0d8e changeset: 88745:87e7a59d0d8e branch: 2.7 parent: 88733:b28909d501c0 parent: 88742:d960c4cabb2b user: Terry Jan Reedy date: Sun Jan 26 20:10:56 2014 -0500 summary: Merge heads. files: Lib/idlelib/CallTips.py | 22 +++++++++---- Lib/idlelib/idle_test/test_calltips.py | 13 ++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -5,14 +5,15 @@ which disappear when you type a closing parenthesis. """ +import __main__ import re import sys +import textwrap import types from idlelib import CallTipWindow from idlelib.HyperParser import HyperParser -import __main__ class CallTips: @@ -131,8 +132,9 @@ return None # The following are used in get_arg_text -_MAX_COLS = 79 +_MAX_COLS = 85 _MAX_LINES = 5 # enough for bytes +_INDENT = ' '*4 # for wrapped signatures def get_arg_text(ob): '''Return a string describing the signature of a callable object, or ''. @@ -147,11 +149,15 @@ try: ob_call = ob.__call__ except BaseException: - return argspec + if type(ob) is types.ClassType: # old-style + ob_call = ob + else: + return argspec arg_offset = 0 if type(ob) in (types.ClassType, types.TypeType): - # Look for the highest __init__ in the class chain. + # Look for the first __init__ in the class chain with .im_func. + # Slot wrappers (builtins, classes defined in funcs) do not. fob = _find_constructor(ob) if fob is None: fob = lambda: None @@ -183,14 +189,16 @@ items.append("**kwds") argspec = ", ".join(items) argspec = "(%s)" % re.sub("(?", argspec) - # See if we can use the docstring + + lines = (textwrap.wrap(argspec, _MAX_COLS, subsequent_indent=_INDENT) + if len(argspec) > _MAX_COLS else [argspec] if argspec else []) + if isinstance(ob_call, types.MethodType): doc = ob_call.__doc__ else: doc = getattr(ob, "__doc__", "") if doc: - lines = [argspec] if argspec else [] - for line in doc.split('\n', 5)[:_MAX_LINES]: + for line in doc.split('\n', _MAX_LINES)[:_MAX_LINES]: line = line.strip() if not line: break diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -1,6 +1,7 @@ import unittest import idlelib.CallTips as ct CTi = ct.CallTips() # needed for get_entity test in 2.7 +import textwrap import types default_tip = '' @@ -66,6 +67,18 @@ gtest(types.MethodType, '()\ninstancemethod(function, instance, class)') gtest(SB(), default_tip) + def test_signature_wrap(self): + # This is also a test of an old-style class + self.assertEqual(signature(textwrap.TextWrapper), '''\ +(width=70, initial_indent='', subsequent_indent='', expand_tabs=True, + replace_whitespace=True, fix_sentence_endings=False, break_long_words=True, + drop_whitespace=True, break_on_hyphens=True)''') + + def test_docline_truncation(self): + def f(): pass + f.__doc__ = 'a'*300 + self.assertEqual(signature(f), '()\n' + 'a' * (ct._MAX_COLS-3) + '...') + def test_multiline_docstring(self): # Test fewer lines than max. self.assertEqual(signature(list), -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 02:25:08 2014 From: python-checkins at python.org (terry.reedy) Date: Mon, 27 Jan 2014 02:25:08 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuMyk6?= =?utf-8?q?_Merge_heads=2E?= Message-ID: <3fCCtr4KvMz7Lmd@mail.python.org> http://hg.python.org/cpython/rev/bebc8fd20e97 changeset: 88746:bebc8fd20e97 branch: 3.3 parent: 88734:fde9e9832749 parent: 88743:7dcc19308a7b user: Terry Jan Reedy date: Sun Jan 26 20:12:18 2014 -0500 summary: Merge heads. files: Lib/idlelib/CallTips.py | 15 +++-- Lib/idlelib/idle_test/test_calltips.py | 32 ++++++++++--- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -5,16 +5,16 @@ which disappear when you type a closing parenthesis. """ +import __main__ +import inspect import re import sys +import textwrap import types -import inspect from idlelib import CallTipWindow from idlelib.HyperParser import HyperParser -import __main__ - class CallTips: menudefs = [ @@ -117,8 +117,9 @@ return None # The following are used in get_argspec and some in tests -_MAX_COLS = 79 +_MAX_COLS = 85 _MAX_LINES = 5 # enough for bytes +_INDENT = ' '*4 # for wrapped signatures _first_param = re.compile('(?<=\()\w*\,?\s*') _default_callable_argspec = "See source or doc" @@ -149,13 +150,15 @@ isinstance(ob_call, types.MethodType)): argspec = _first_param.sub("", argspec) + lines = (textwrap.wrap(argspec, _MAX_COLS, subsequent_indent=_INDENT) + if len(argspec) > _MAX_COLS else [argspec] if argspec else []) + if isinstance(ob_call, types.MethodType): doc = ob_call.__doc__ else: doc = getattr(ob, "__doc__", "") if doc: - lines = [argspec] if argspec else [] - for line in doc.split('\n', 5)[:_MAX_LINES]: + for line in doc.split('\n', _MAX_LINES)[:_MAX_LINES]: line = line.strip() if not line: break diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -1,5 +1,6 @@ import unittest import idlelib.CallTips as ct +import textwrap import types default_tip = ct._default_callable_argspec @@ -64,20 +65,35 @@ gtest(types.MethodType, "method(function, instance)") gtest(SB(), default_tip) + def test_signature_wrap(self): + self.assertEqual(signature(textwrap.TextWrapper), '''\ +(width=70, initial_indent='', subsequent_indent='', expand_tabs=True, + replace_whitespace=True, fix_sentence_endings=False, break_long_words=True, + drop_whitespace=True, break_on_hyphens=True, tabsize=8)''') + + def test_docline_truncation(self): + def f(): pass + f.__doc__ = 'a'*300 + self.assertEqual(signature(f), '()\n' + 'a' * (ct._MAX_COLS-3) + '...') + def test_multiline_docstring(self): # Test fewer lines than max. self.assertEqual(signature(list), "list() -> new empty list\n" "list(iterable) -> new list initialized from iterable's items") - # Test max lines and line (currently) too long. - self.assertEqual(signature(bytes), -"bytes(iterable_of_ints) -> bytes\n" -"bytes(string, encoding[, errors]) -> bytes\n" -"bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer\n" -#bytes(int) -> bytes object of size given by the parameter initialized with null bytes -"bytes(int) -> bytes object of size given by the parameter initialized with n...\n" -"bytes() -> empty bytes object") + # Test max lines + self.assertEqual(signature(bytes), '''\ +bytes(iterable_of_ints) -> bytes +bytes(string, encoding[, errors]) -> bytes +bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer +bytes(int) -> bytes object of size given by the parameter initialized with null bytes +bytes() -> empty bytes object''') + + # Test more than max lines + def f(): pass + f.__doc__ = 'a\n' * 15 + self.assertEqual(signature(f), '()' + '\na' * ct._MAX_LINES) def test_functions(self): def t1(): 'doc' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 02:25:10 2014 From: python-checkins at python.org (terry.reedy) Date: Mon, 27 Jan 2014 02:25:10 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgaGVhZHMu?= Message-ID: <3fCCtt07bkz7LmZ@mail.python.org> http://hg.python.org/cpython/rev/96af1aa04778 changeset: 88747:96af1aa04778 parent: 88741:bf52f2dbfdde parent: 88744:f7061219303c user: Terry Jan Reedy date: Sun Jan 26 20:16:53 2014 -0500 summary: Merge heads. files: Lib/idlelib/CallTips.py | 15 ++- Lib/idlelib/idle_test/test_calltips.py | 46 +++++++++---- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -5,16 +5,16 @@ which disappear when you type a closing parenthesis. """ +import __main__ +import inspect import re import sys +import textwrap import types -import inspect from idlelib import CallTipWindow from idlelib.HyperParser import HyperParser -import __main__ - class CallTips: menudefs = [ @@ -117,8 +117,9 @@ return None # The following are used in get_argspec and some in tests -_MAX_COLS = 79 +_MAX_COLS = 85 _MAX_LINES = 5 # enough for bytes +_INDENT = ' '*4 # for wrapped signatures _first_param = re.compile('(?<=\()\w*\,?\s*') _default_callable_argspec = "See source or doc" @@ -149,13 +150,15 @@ isinstance(ob_call, types.MethodType)): argspec = _first_param.sub("", argspec) + lines = (textwrap.wrap(argspec, _MAX_COLS, subsequent_indent=_INDENT) + if len(argspec) > _MAX_COLS else [argspec] if argspec else []) + if isinstance(ob_call, types.MethodType): doc = ob_call.__doc__ else: doc = getattr(ob, "__doc__", "") if doc: - lines = [argspec] if argspec else [] - for line in doc.split('\n', 5)[:_MAX_LINES]: + for line in doc.split('\n', _MAX_LINES)[:_MAX_LINES]: line = line.strip() if not line: break diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -1,5 +1,6 @@ import unittest import idlelib.CallTips as ct +import textwrap import types default_tip = ct._default_callable_argspec @@ -55,32 +56,45 @@ gtest(list.__new__, 'T.__new__(S, ...) -> a new object with type S, a subtype of T') gtest(list.__init__, - 'Initializes self. See help(type(self)) for accurate signature.') + 'x.__init__(...) initializes x; see help(type(x)) for signature') append_doc = "L.append(object) -> None -- append object to end" gtest(list.append, append_doc) gtest([].append, append_doc) gtest(List.append, append_doc) - gtest(types.MethodType, "Create a bound instance method object.") + gtest(types.MethodType, "method(function, instance)") gtest(SB(), default_tip) + def test_signature_wrap(self): + self.assertEqual(signature(textwrap.TextWrapper), '''\ +(width=70, initial_indent='', subsequent_indent='', expand_tabs=True, + replace_whitespace=True, fix_sentence_endings=False, break_long_words=True, + drop_whitespace=True, break_on_hyphens=True, tabsize=8, *, max_lines=None, + placeholder=' [...]')''') + + def test_docline_truncation(self): + def f(): pass + f.__doc__ = 'a'*300 + self.assertEqual(signature(f), '()\n' + 'a' * (ct._MAX_COLS-3) + '...') + def test_multiline_docstring(self): # Test fewer lines than max. - self.assertEqual(signature(dict), - "dict(mapping) -> new dictionary initialized from a mapping object's\n" - "(key, value) pairs\n" - "dict(iterable) -> new dictionary initialized as if via:\n" - "d = {}\n" - "for k, v in iterable:" - ) + self.assertEqual(signature(list), + "list() -> new empty list\n" + "list(iterable) -> new list initialized from iterable's items") - # Test max lines and line (currently) too long. - self.assertEqual(signature(bytes), -"bytes(string, encoding[, errors]) -> bytes\n" -"bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer\n" -#bytes(int) -> bytes object of size given by the parameter initialized with null bytes -"bytes(int) -> bytes object of size given by the parameter initialized with n...\n" -"bytes() -> empty bytes object") + # Test max lines + self.assertEqual(signature(bytes), '''\ +bytes(iterable_of_ints) -> bytes +bytes(string, encoding[, errors]) -> bytes +bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer +bytes(int) -> bytes object of size given by the parameter initialized with null bytes +bytes() -> empty bytes object''') + + # Test more than max lines + def f(): pass + f.__doc__ = 'a\n' * 15 + self.assertEqual(signature(f), '()' + '\na' * ct._MAX_LINES) def test_functions(self): def t1(): 'doc' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 02:25:11 2014 From: python-checkins at python.org (terry.reedy) Date: Mon, 27 Jan 2014 02:25:11 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E3?= Message-ID: <3fCCtv1xwFz7Ln3@mail.python.org> http://hg.python.org/cpython/rev/c8f3b85f3f2f changeset: 88748:c8f3b85f3f2f parent: 88747:96af1aa04778 parent: 88746:bebc8fd20e97 user: Terry Jan Reedy date: Sun Jan 26 20:17:48 2014 -0500 summary: Merge with 3.3 files: Lib/idlelib/idle_test/test_calltips.py | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -69,8 +69,12 @@ self.assertEqual(signature(textwrap.TextWrapper), '''\ (width=70, initial_indent='', subsequent_indent='', expand_tabs=True, replace_whitespace=True, fix_sentence_endings=False, break_long_words=True, +<<<<<<< local drop_whitespace=True, break_on_hyphens=True, tabsize=8, *, max_lines=None, placeholder=' [...]')''') +======= + drop_whitespace=True, break_on_hyphens=True, tabsize=8)''') +>>>>>>> other def test_docline_truncation(self): def f(): pass -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 02:25:12 2014 From: python-checkins at python.org (terry.reedy) Date: Mon, 27 Jan 2014 02:25:12 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_White_space_and_merge_clea?= =?utf-8?q?nup=2E?= Message-ID: <3fCCtw3VPTz7Lmq@mail.python.org> http://hg.python.org/cpython/rev/21c5e6b4f68b changeset: 88749:21c5e6b4f68b user: Terry Jan Reedy date: Sun Jan 26 20:24:35 2014 -0500 summary: White space and merge cleanup. files: Lib/idlelib/idle_test/test_calltips.py | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -69,12 +69,8 @@ self.assertEqual(signature(textwrap.TextWrapper), '''\ (width=70, initial_indent='', subsequent_indent='', expand_tabs=True, replace_whitespace=True, fix_sentence_endings=False, break_long_words=True, -<<<<<<< local drop_whitespace=True, break_on_hyphens=True, tabsize=8, *, max_lines=None, placeholder=' [...]')''') -======= - drop_whitespace=True, break_on_hyphens=True, tabsize=8)''') ->>>>>>> other def test_docline_truncation(self): def f(): pass -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 03:35:42 2014 From: python-checkins at python.org (terry.reedy) Date: Mon, 27 Jan 2014 03:35:42 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSWRsZWxpYi5jYWxs?= =?utf-8?q?tips=3A_add_test_of_starred_first_parameters=2E_They_should_not?= =?utf-8?q?_be?= Message-ID: <3fCFSG4KqTz7LjW@mail.python.org> http://hg.python.org/cpython/rev/0fb73e66fb8b changeset: 88750:0fb73e66fb8b branch: 2.7 parent: 88745:87e7a59d0d8e user: Terry Jan Reedy date: Sun Jan 26 21:34:25 2014 -0500 summary: Idlelib.calltips: add test of starred first parameters. They should not be removed even for bound methods. (Inspect.signature does, see 20401.) files: Lib/idlelib/idle_test/test_calltips.py | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -120,6 +120,16 @@ (tc.__call__, '(ci)'), (tc, '(ci)'), (TC.cm, "(a)"),): self.assertEqual(signature(meth), mtip + "\ndoc") + def test_starred_parameter(self): + # test that starred first parameter is *not* removed from argspec + class C: + def m1(*args): pass + def m2(**kwds): pass + c = C() + for meth, mtip in ((C.m1, '(*args)'), (c.m1, "(*args)"), + (C.m2, "(**kwds)"), (c.m2, "(**kwds)"),): + self.assertEqual(signature(meth), mtip) + def test_no_docstring(self): def nd(s): pass TC.nd = nd -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 03:35:43 2014 From: python-checkins at python.org (terry.reedy) Date: Mon, 27 Jan 2014 03:35:43 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSWRsZWxpYi5jYWxs?= =?utf-8?q?tips=3A_add_test_of_starred_first_parameters=2E_They_should_not?= =?utf-8?q?_be?= Message-ID: <3fCFSH5n5xz7LjW@mail.python.org> http://hg.python.org/cpython/rev/9ac2016815c9 changeset: 88751:9ac2016815c9 branch: 3.3 parent: 88746:bebc8fd20e97 user: Terry Jan Reedy date: Sun Jan 26 21:34:33 2014 -0500 summary: Idlelib.calltips: add test of starred first parameters. They should not be removed even for bound methods. (Inspect.signature does, see 20401.) files: Lib/idlelib/idle_test/test_calltips.py | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -122,6 +122,16 @@ (tc.__call__, '(ci)'), (tc, '(ci)'), (TC.cm, "(a)"),): self.assertEqual(signature(meth), mtip + "\ndoc") + def test_starred_parameter(self): + # test that starred first parameter is *not* removed from argspec + class C: + def m1(*args): pass + def m2(**kwds): pass + c = C() + for meth, mtip in ((C.m1, '(*args)'), (c.m1, "(*args)"), + (C.m2, "(**kwds)"), (c.m2, "(**kwds)"),): + self.assertEqual(signature(meth), mtip) + def test_non_ascii_name(self): # test that re works to delete a first parameter name that # includes non-ascii chars, such as various forms of A. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 03:35:45 2014 From: python-checkins at python.org (terry.reedy) Date: Mon, 27 Jan 2014 03:35:45 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E3?= Message-ID: <3fCFSK03Sqz7Llb@mail.python.org> http://hg.python.org/cpython/rev/8d572bf526e6 changeset: 88752:8d572bf526e6 parent: 88749:21c5e6b4f68b parent: 88751:9ac2016815c9 user: Terry Jan Reedy date: Sun Jan 26 21:35:22 2014 -0500 summary: Merge with 3.3 files: Lib/idlelib/idle_test/test_calltips.py | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -123,6 +123,16 @@ (tc.__call__, '(ci)'), (tc, '(ci)'), (TC.cm, "(a)"),): self.assertEqual(signature(meth), mtip + "\ndoc") + def test_starred_parameter(self): + # test that starred first parameter is *not* removed from argspec + class C: + def m1(*args): pass + def m2(**kwds): pass + c = C() + for meth, mtip in ((C.m1, '(*args)'), (c.m1, "(*args)"), + (C.m2, "(**kwds)"), (c.m2, "(**kwds)"),): + self.assertEqual(signature(meth), mtip) + def test_non_ascii_name(self): # test that re works to delete a first parameter name that # includes non-ascii chars, such as various forms of A. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 04:22:31 2014 From: python-checkins at python.org (nick.coghlan) Date: Mon, 27 Jan 2014 04:22:31 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Incorporate_PEP_462_feedback?= Message-ID: <3fCGVH220wz7Lkf@mail.python.org> http://hg.python.org/peps/rev/6bb993cca12c changeset: 5357:6bb993cca12c user: Nick Coghlan date: Mon Jan 27 13:22:21 2014 +1000 summary: Incorporate PEP 462 feedback files: pep-0462.txt | 136 +++++++++++++++++++++++++++++--------- 1 files changed, 102 insertions(+), 34 deletions(-) diff --git a/pep-0462.txt b/pep-0462.txt --- a/pep-0462.txt +++ b/pep-0462.txt @@ -7,6 +7,7 @@ Type: Process Content-Type: text/x-rst Created: 23-Jan-2014 +Post-History: 25-Jan-2014, 27-Jan-2014 Abstract @@ -139,7 +140,7 @@ failures prior to a release) and for the developers themselves (since it creates significant pressure to fix any failures we inadvertently introduce right *now*, rather than at a more convenient time). -* For new contributors, a core developer spending time actually getting +* For other contributors, a core developer spending time actually getting changes merged is a developer that isn't reviewing and discussing patches on the issue tracker or otherwise helping others to contribute effectively. It is especially frustrating for contributors that are accustomed to the @@ -221,9 +222,10 @@ that will be a very good day). However, the merge queue itself is a very powerful concept that should -directly address several of the issues described above. +directly address several of the issues described in the Rationale above. .. _Zuul: http://ci.openstack.org/zuul/ +.. _Elastic recheck: http://status.openstack.org/elastic-recheck/> Deferred Proposals @@ -234,15 +236,39 @@ * Running preliminary "check" tests against patches posted to Gerrit. * Creation of updated release artefacts and republishing documentation when changes are merged -* Using ElasticSearch in conjunction with a spam filter to monitor test - output and suggest the specific intermittent failure that may have - caused a test to fail, rather than requiring users to search logs manually +* The `Elastic recheck`_ feature that uses ElasticSearch in conjunction with + a spam filter to monitor test output and suggest the specific intermittent + failure that may have caused a test to fail, rather than requiring users + to search logs manually While these are possibilities worth exploring in the future (and one of the possible benefits I see to seeking closer coordination with the OpenStack Infrastructure team), I don't see them as offering quite the same kind of fundamental workflow improvement that merge gating appears to provide. +However, it may be that the last is needed to handle intermittent test +failures in the gate effectively, in which case it may need to be +considered as a possible part of the initial deployment. + + +Suggested Variants +================== + +Terry Reedy has suggested doing an initial filter which specifically looks +for approved documentation-only patches (~700 of the 4000+ open CPython +issues are pure documentation updates). This approach would avoid several +of the issues related to flaky tests and cross-platform testing, while +still allowing the rest of the automation flows to be worked out (such as +how to push a patch into the merge queue). + +The one downside to this approach is that Zuul wouldn't have complete +control of the merge process as it usually expects, so there would +potentially be additional coordination needed around that. + +It may be worth keeping this approach as a fallback option if the initial +deployment proves to have more trouble with test reliability than is +anticipated. + Perceived Benefits ================== @@ -261,8 +287,8 @@ With the bulk of the time investment moved to the review process, this also encourages "development for reviewability" - smaller, easier to review -patches, since the overhead of running the tests five times rather than once -will be incurred by Zuul rather than by the core developers. +patches, since the overhead of running the tests multiple times will be +incurred by Zuul rather than by the core developers. However, removing this time sink from the core development team should also improve the experience of CPython development for other contributors, as it @@ -282,6 +308,13 @@ the other sprint participants than it is on things that are sufficiently mechanical that a computer can (and should) handle them. +Finally, with most of the ways to make a mistake when committing a change +automated out of existence, there are substantially fewer new things to +learn when a contributor is nominated to become a core developer. This +should have a dual benefit, both in making the existing core developers more +comfortable with granting that additional level of responsibility, and in +making new contributors more comforable with exercising it. + Technical Challenges ==================== @@ -292,21 +325,39 @@ in some of our existing tools. -Rietveld vs Gerrit ------------------- +Rietveld/Roundup vs Gerrit +-------------------------- Rietveld does not currently include a voting/approval feature that is equivalent to Gerrit's. For CPython, we wouldn't need anything as sophisticated as Gerrit's voting system - a simple core-developer-only "Approved" marker to trigger action from Zuul should suffice. The -core-developer-or-not flag is available in Roundup, which may require -further additions to the existing integration between the two tools. +core-developer-or-not flag is available in Roundup, as is the flag +indicating whether or not the uploader of a patch has signed a PSF +Contributor Licensing Agreement, which may require further additions to +the existing integration between the two tools. Rietveld may also require some changes to allow the uploader of a patch to indicate which branch it is intended for. -There would also be an additional Zuul trigger plugin needed to monitor -Rietveld activity rather than Gerrit. +We would likely also want to improve the existing patch handling, +in particular looking at how the Roundup/Reitveld integration handles cases +where it can't figure out a suitable base version to use when generating +the review (if Rietveld gains the ability to nominate a particular target +repository and branch for a patch, then this may be relatively easy to +resolve). + +Some of the existing Zuul triggers work by monitoring for particular comments +(in particular, recheck/reverify comments to ask Zuul to try merging a +change again if it was previously rejected due to an unrelated intermittent +failure). We will likely also want similar explicit triggers for Rietveld. + +The current Zuul plugins for Gerrit work by monitoring the Gerrit activity +stream for particular events. If Rietveld has no equivalent, we will need +to add something suitable for the events we would like to trigger on. + +There would also be development effort needed to create a Zuul plugin +that monitors Rietveld activity rather than Gerrit. Mercurial vs Gerrit/git @@ -332,9 +383,14 @@ Buildbot vs Jenkins ------------------- -As far as I am aware, Zuul's interaction with the CI system is also -pluggable, so this should only require creating a Buildbot plugin to use -instead of the Jenkins one. +Zuul's interaction with the CI system is also pluggable, using Gearman +as the `preferred interface `__. +Accordingly, adapting the CI jobs to run in Buildbot rather than Jenkins +should just be a matter of writing a Gearman client that can process the +requests from Zuul and pass them on to the Buildbot master. Zuul uses the +pure Python `gear client library `__ to +communicate with Gearman, and this library should also be useful to handle +the Buildbot side of things. Note that, in the initial iteration, I am proposing that we *do not* attempt to pipeline test execution. This means Zuul would be running in @@ -345,28 +401,26 @@ the result to come back before moving on to the second patch in the queue. If we ultimately decide that this is not sufficient, and we need to start -using the CI pipelining features of Zuul, then we may need to look at using -Jenkins test runs to control the gating process. Due to the differences -in the client/server architectures between Jenkins and Buildbot, the -initial feedback from the OpenStack infrastructure team is that it is likely -to be difficult to adapt the way Zuul controls the CI pipelining process in -Jenkins to control Buildbot instead. +using the CI pipelining features of Zuul, then we may need to look at moving +the test execution to dynamically provisioned cloud images, rather than +relying on volunteer maintained statically provisioned systems as we do +currently. The OpenStack CI infrastructure team are exploring the idea of +replacing their current use of Jenkins masters with a simpler pure Python +test runner, so if we find that we can't get Buildbot to effectively +support the pipelined testing model, we'd likely participate in that +effort rather than setting up a Jenkins instance for CPython. -If that latter step occurs, it would likely make sense to look at moving the -test execution to dynamically provisioned cloud images, rather than relying -on volunteer maintained statically provisioned systems as we do currently. - -In this case, the main technical risk would become Zuul's handling of testing -on platforms other than Linux (our stable buildbots currently cover Windows, -Mac OS X, FreeBSD and OpenIndiana in addition to a couple of different Linux -variants). +In this case, the main technical risk would be a matter of ensuring we +support testing on platforms other than Linux (as our stable buildbots +currently cover Windows, Mac OS X, FreeBSD and OpenIndiana in addition to a +couple of different Linux variants). In such a scenario, the Buildbot fleet would still have a place in doing "check" runs against the master repository (either periodically or for every commit), even if it did not play a part in the merge gating process. More unusual configurations (such as building without threads, or without SSL/TLS support) would likely still be handled that way rather than being -included in the gate criteria. +included in the gate criteria (at least initially, anyway). Handling of maintenance branches @@ -426,7 +480,19 @@ Some tests, especially timing tests, exhibit intermittent failures on the existing Buildbot fleet. In particular, test systems running as VMs may -sometimes exhibit timing failures +sometimes exhibit timing failures when the VM host is under higher than +normal load. + +The OpenStack CI infrastructure includes a number of additional features to +help deal with intermittent failures, the most basic of which is simply +allowing developers to request that merging a patch be tried again when the +original failure appears to be due to a known intermittent failure (whether +that intermittent failure is in OpenStack itself or just in a flaky test). + +The more sophisticated `Elastic recheck`_ feature may be worth considering, +especially since the output of the CPython test suite is substantially +simpler than that from OpenStack's more complex multi-service testing, and +hence likely even more amenable to automated analysis. Social Challenges @@ -437,7 +503,7 @@ automated by the proposal should create a strong incentive for the existing developers to go along with the idea. -I believe two specific features may be needed to assure existing +I believe three specific features may be needed to assure existing developers that there are no downsides to the automation of this workflow: * Only requiring approval from a single core developer to incorporate a @@ -489,7 +555,9 @@ ================ Thanks to Jesse Noller, Alex Gaynor and James Blair for providing valuable -feedback on a preliminary draft of this proposal. +feedback on a preliminary draft of this proposal, and to James and Monty +Taylor for additional technical feedback following publication of the +initial draft. Copyright -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jan 27 04:28:01 2014 From: python-checkins at python.org (terry.reedy) Date: Mon, 27 Jan 2014 04:28:01 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3NzIx?= =?utf-8?q?=3A_Remove_non-functional_configuration_dialog_help_button_unti?= =?utf-8?q?l_we?= Message-ID: <3fCGcd62RYz7LkX@mail.python.org> http://hg.python.org/cpython/rev/3d343dfe6269 changeset: 88753:3d343dfe6269 branch: 2.7 parent: 88750:0fb73e66fb8b user: Terry Jan Reedy date: Sun Jan 26 22:24:17 2014 -0500 summary: Issue #17721: Remove non-functional configuration dialog help button until we make it actually gives some help when clicked. Patch by Guilherme Sim?es. files: Lib/idlelib/configDialog.py | 9 +++++---- Misc/NEWS | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Lib/idlelib/configDialog.py b/Lib/idlelib/configDialog.py --- a/Lib/idlelib/configDialog.py +++ b/Lib/idlelib/configDialog.py @@ -78,9 +78,10 @@ else: paddingArgs={'padx':6, 'pady':3} - self.buttonHelp = Button(frameActionButtons,text='Help', - command=self.Help,takefocus=FALSE, - **paddingArgs) +# Comment out button creation and packing until implement self.Help +## self.buttonHelp = Button(frameActionButtons,text='Help', +## command=self.Help,takefocus=FALSE, +## **paddingArgs) self.buttonOk = Button(frameActionButtons,text='Ok', command=self.Ok,takefocus=FALSE, **paddingArgs) @@ -94,7 +95,7 @@ self.CreatePageHighlight() self.CreatePageKeys() self.CreatePageGeneral() - self.buttonHelp.pack(side=RIGHT,padx=5) +## self.buttonHelp.pack(side=RIGHT,padx=5) self.buttonOk.pack(side=LEFT,padx=5) self.buttonApply.pack(side=LEFT,padx=5) self.buttonCancel.pack(side=LEFT,padx=5) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -189,6 +189,9 @@ IDLE ---- +- Issue #17721: Remove non-functional configuration dialog help button until we + make it actually gives some help when clicked. Patch by Guilherme Sim?es. + - Issue #17390: Add Python version to Idle editor window title bar. Original patches by Edmond Burnett and Kent Johnson. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 04:28:03 2014 From: python-checkins at python.org (terry.reedy) Date: Mon, 27 Jan 2014 04:28:03 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3NzIx?= =?utf-8?q?=3A_Remove_non-functional_configuration_dialog_help_button_unti?= =?utf-8?q?l_we?= Message-ID: <3fCGcg0SYBz7Llb@mail.python.org> http://hg.python.org/cpython/rev/6e4b94019eae changeset: 88754:6e4b94019eae branch: 3.3 parent: 88751:9ac2016815c9 user: Terry Jan Reedy date: Sun Jan 26 22:24:26 2014 -0500 summary: Issue #17721: Remove non-functional configuration dialog help button until we make it actually gives some help when clicked. Patch by Guilherme Sim?es. files: Lib/idlelib/configDialog.py | 9 +++++---- Misc/NEWS | 5 ++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/configDialog.py b/Lib/idlelib/configDialog.py --- a/Lib/idlelib/configDialog.py +++ b/Lib/idlelib/configDialog.py @@ -82,9 +82,10 @@ else: extraKwds=dict(padx=6, pady=3) - self.buttonHelp = Button(frameActionButtons,text='Help', - command=self.Help,takefocus=FALSE, - **extraKwds) +# Comment out button creation and packing until implement self.Help +## self.buttonHelp = Button(frameActionButtons,text='Help', +## command=self.Help,takefocus=FALSE, +## **extraKwds) self.buttonOk = Button(frameActionButtons,text='Ok', command=self.Ok,takefocus=FALSE, **extraKwds) @@ -98,7 +99,7 @@ self.CreatePageHighlight() self.CreatePageKeys() self.CreatePageGeneral() - self.buttonHelp.pack(side=RIGHT,padx=5) +## self.buttonHelp.pack(side=RIGHT,padx=5) self.buttonOk.pack(side=LEFT,padx=5) self.buttonApply.pack(side=LEFT,padx=5) self.buttonCancel.pack(side=LEFT,padx=5) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -276,7 +276,10 @@ IDLE ---- ---Issue #17390: Add Python version to Idle editor window title bar. +- Issue #17721: Remove non-functional configuration dialog help button until we + make it actually gives some help when clicked. Patch by Guilherme Sim?es. + +- Issue #17390: Add Python version to Idle editor window title bar. Original patches by Edmond Burnett and Kent Johnson. - Issue #18960: IDLE now ignores the source encoding declaration on the second -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 04:28:04 2014 From: python-checkins at python.org (terry.reedy) Date: Mon, 27 Jan 2014 04:28:04 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317721=3A_Remove_non-functional_configuration_di?= =?utf-8?q?alog_help_button_until_we?= Message-ID: <3fCGch20Gwz7Llv@mail.python.org> http://hg.python.org/cpython/rev/be9843012124 changeset: 88755:be9843012124 parent: 88752:8d572bf526e6 parent: 88754:6e4b94019eae user: Terry Jan Reedy date: Sun Jan 26 22:27:38 2014 -0500 summary: Issue #17721: Remove non-functional configuration dialog help button until we make it actually gives some help when clicked. Patch by Guilherme Sim?es. files: Lib/idlelib/configDialog.py | 9 +++++---- Misc/NEWS | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Lib/idlelib/configDialog.py b/Lib/idlelib/configDialog.py --- a/Lib/idlelib/configDialog.py +++ b/Lib/idlelib/configDialog.py @@ -82,9 +82,10 @@ else: extraKwds=dict(padx=6, pady=3) - self.buttonHelp = Button(frameActionButtons,text='Help', - command=self.Help,takefocus=FALSE, - **extraKwds) +# Comment out button creation and packing until implement self.Help +## self.buttonHelp = Button(frameActionButtons,text='Help', +## command=self.Help,takefocus=FALSE, +## **extraKwds) self.buttonOk = Button(frameActionButtons,text='Ok', command=self.Ok,takefocus=FALSE, **extraKwds) @@ -98,7 +99,7 @@ self.CreatePageHighlight() self.CreatePageKeys() self.CreatePageGeneral() - self.buttonHelp.pack(side=RIGHT,padx=5) +## self.buttonHelp.pack(side=RIGHT,padx=5) self.buttonOk.pack(side=LEFT,padx=5) self.buttonApply.pack(side=LEFT,padx=5) self.buttonCancel.pack(side=LEFT,padx=5) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -143,6 +143,9 @@ IDLE ---- +- Issue #17721: Remove non-functional configuration dialog help button until we + make it actually gives some help when clicked. Patch by Guilherme Sim?es. + - Issue #17390: Add Python version to Idle editor window title bar. Original patches by Edmond Burnett and Kent Johnson. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 04:58:52 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 27 Jan 2014 04:58:52 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_eliminate_redu?= =?utf-8?q?ndancy_between_yield_stmt_and_yield_expr_docs_=28closes_=231270?= =?utf-8?q?4=29?= Message-ID: <3fCHJD3RF4z7Lkf@mail.python.org> http://hg.python.org/cpython/rev/e02da391741f changeset: 88756:e02da391741f branch: 3.3 parent: 88754:6e4b94019eae user: Benjamin Peterson date: Sun Jan 26 22:52:08 2014 -0500 summary: eliminate redundancy between yield stmt and yield expr docs (closes #12704) Patch by Nikolaus Rath. files: Doc/reference/expressions.rst | 99 ++++++++++----------- Doc/reference/simple_stmts.rst | 57 +++--------- 2 files changed, 62 insertions(+), 94 deletions(-) diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -319,27 +319,25 @@ yield_atom: "(" `yield_expression` ")" yield_expression: "yield" [`expression_list` | "from" `expression`] -The :keyword:`yield` expression is only used when defining a :term:`generator` -function, -and can only be used in the body of a function definition. Using a -:keyword:`yield` expression in a function definition is sufficient to cause that -definition to create a generator function instead of a normal function. +The yield expression is only used when defining a :term:`generator` function and +thus can only be used in the body of a function definition. Using a yield +expression in a function's body causes that function to be a generator. When a generator function is called, it returns an iterator known as a generator. That generator then controls the execution of a generator function. The execution starts when one of the generator's methods is called. At that -time, the execution proceeds to the first :keyword:`yield` expression, where it -is suspended again, returning the value of :token:`expression_list` to -generator's caller. By suspended we mean that all local state is retained, -including the current bindings of local variables, the instruction pointer, and -the internal evaluation stack. When the execution is resumed by calling one of -the generator's methods, the function can proceed exactly as if the -:keyword:`yield` expression was just another external call. The value of the -:keyword:`yield` expression after resuming depends on the method which resumed -the execution. If :meth:`~generator.__next__` is used (typically via either a -:keyword:`for` or the :func:`next` builtin) then the result is :const:`None`, -otherwise, if :meth:`~generator.send` is used, then the result will be the -value passed in to that method. +time, the execution proceeds to the first yield expression, where it is +suspended again, returning the value of :token:`expression_list` to generator's +caller. By suspended, we mean that all local state is retained, including the +current bindings of local variables, the instruction pointer, and the internal +evaluation stack. When the execution is resumed by calling one of the +generator's methods, the function can proceed exactly as if the yield expression +was just another external call. The value of the yield expression after +resuming depends on the method which resumed the execution. If +:meth:`~generator.__next__` is used (typically via either a :keyword:`for` or +the :func:`next` builtin) then the result is :const:`None`. Otherwise, if +:meth:`~generator.send` is used, then the result will be the value passed in to +that method. .. index:: single: coroutine @@ -349,11 +347,11 @@ where should the execution continue after it yields; the control is always transferred to the generator's caller. -:keyword:`yield` expressions are allowed in the :keyword:`try` clause of a -:keyword:`try` ... :keyword:`finally` construct. If the generator is not -resumed before it is finalized (by reaching a zero reference count or by being -garbage collected), the generator-iterator's :meth:`~generator.close` method -will be called, allowing any pending :keyword:`finally` clauses to execute. +yield expressions are allowed in the :keyword:`try` clause of a :keyword:`try` +... :keyword:`finally` construct. If the generator is not resumed before it is +finalized (by reaching a zero reference count or by being garbage collected), +the generator-iterator's :meth:`~generator.close` method will be called, +allowing any pending :keyword:`finally` clauses to execute. When ``yield from `` is used, it treats the supplied expression as a subiterator. All values produced by that subiterator are passed directly @@ -373,12 +371,24 @@ .. versionchanged:: 3.3 Added ``yield from `` to delegate control flow to a subiterator -The parentheses can be omitted when the :keyword:`yield` expression is the -sole expression on the right hand side of an assignment statement. +The parentheses may be omitted when the yield expression is the sole expression +on the right hand side of an assignment statement. + +.. seealso:: + + :pep:`0255` - Simple Generators + The proposal for adding generators and the :keyword:`yield` statement to Python. + + :pep:`0342` - Coroutines via Enhanced Generators + The proposal to enhance the API and syntax of generators, making them + usable as simple coroutines. + + :pep:`0380` - Syntax for Delegating to a Subgenerator + The proposal to introduce the :token:`yield_from` syntax, making delegation + to sub-generators easy. .. index:: object: generator - Generator-iterator methods ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -395,13 +405,12 @@ .. method:: generator.__next__() Starts the execution of a generator function or resumes it at the last - executed :keyword:`yield` expression. When a generator function is resumed - with a :meth:`~generator.__next__` method, the current :keyword:`yield` - expression always evaluates to :const:`None`. The execution then continues - to the next :keyword:`yield` expression, where the generator is suspended - again, and the value of the :token:`expression_list` is returned to - :meth:`next`'s caller. - If the generator exits without yielding another value, a :exc:`StopIteration` + executed yield expression. When a generator function is resumed with a + :meth:`~generator.__next__` method, the current yield expression always + evaluates to :const:`None`. The execution then continues to the next yield + expression, where the generator is suspended again, and the value of the + :token:`expression_list` is returned to :meth:`next`'s caller. If the + generator exits without yielding another value, a :exc:`StopIteration` exception is raised. This method is normally called implicitly, e.g. by a :keyword:`for` loop, or @@ -411,12 +420,12 @@ .. method:: generator.send(value) Resumes the execution and "sends" a value into the generator function. The - ``value`` argument becomes the result of the current :keyword:`yield` - expression. The :meth:`send` method returns the next value yielded by the - generator, or raises :exc:`StopIteration` if the generator exits without - yielding another value. When :meth:`send` is called to start the generator, - it must be called with :const:`None` as the argument, because there is no - :keyword:`yield` expression that could receive the value. + *value* argument becomes the result of the current yield expression. The + :meth:`send` method returns the next value yielded by the generator, or + raises :exc:`StopIteration` if the generator exits without yielding another + value. When :meth:`send` is called to start the generator, it must be called + with :const:`None` as the argument, because there is no yield expression that + could receive the value. .. method:: generator.throw(type[, value[, traceback]]) @@ -478,20 +487,6 @@ Python." -.. seealso:: - - :pep:`0255` - Simple Generators - The proposal for adding generators and the :keyword:`yield` statement to Python. - - :pep:`0342` - Coroutines via Enhanced Generators - The proposal to enhance the API and syntax of generators, making them - usable as simple coroutines. - - :pep:`0380` - Syntax for Delegating to a Subgenerator - The proposal to introduce the :token:`yield_from` syntax, making delegation - to sub-generators easy. - - .. _primaries: Primaries diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -445,53 +445,26 @@ .. productionlist:: yield_stmt: `yield_expression` -The :keyword:`yield` statement is only used when defining a generator function, -and is only used in the body of the generator function. Using a :keyword:`yield` -statement in a function definition is sufficient to cause that definition to -create a generator function instead of a normal function. +A :keyword:`yield` statement is semantically equivalent to a :ref:`yield +expression `. The yield statement can be used to omit the parentheses +that would otherwise be required in the equivalent yield expression +statement. For example, the yield statements :: -When a generator function is called, it returns an iterator known as a generator -iterator, or more commonly, a generator. The body of the generator function is -executed by calling the :func:`next` function on the generator repeatedly until -it raises an exception. + yield + yield from -When a :keyword:`yield` statement is executed, the state of the generator is -frozen and the value of :token:`expression_list` is returned to :meth:`next`'s -caller. By "frozen" we mean that all local state is retained, including the -current bindings of local variables, the instruction pointer, and the internal -evaluation stack: enough information is saved so that the next time :func:`next` -is invoked, the function can proceed exactly as if the :keyword:`yield` -statement were just another external call. +are equivalent to the yield expression statements :: -The :keyword:`yield` statement is allowed in the :keyword:`try` clause of a -:keyword:`try` ... :keyword:`finally` construct. If the generator is not -resumed before it is finalized (by reaching a zero reference count or by being -garbage collected), the generator-iterator's :meth:`close` method will be -called, allowing any pending :keyword:`finally` clauses to execute. + (yield ) + (yield from ) -When ``yield from `` is used, it treats the supplied expression as -a subiterator, producing values from it until the underlying iterator is -exhausted. +Yield expressions and statements are only used when defining a :term:`generator` +function, and are only used in the body of the generator function. Using yield +in a function definition is sufficient to cause that definition to create a +generator function instead of a normal function. - .. versionchanged:: 3.3 - Added ``yield from `` to delegate control flow to a subiterator - -For full details of :keyword:`yield` semantics, refer to the :ref:`yieldexpr` -section. - -.. seealso:: - - :pep:`0255` - Simple Generators - The proposal for adding generators and the :keyword:`yield` statement to Python. - - :pep:`0342` - Coroutines via Enhanced Generators - The proposal to enhance the API and syntax of generators, making them - usable as simple coroutines. - - :pep:`0380` - Syntax for Delegating to a Subgenerator - The proposal to introduce the :token:`yield_from` syntax, making delegation - to sub-generators easy. - +For full details of :keyword:`yield` semantics, refer to the +:ref:`yieldexpr` section. .. _raise: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 04:58:54 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 27 Jan 2014 04:58:54 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge_3=2E3_=28closes_=2312704=29?= Message-ID: <3fCHJG0p5qz7LlL@mail.python.org> http://hg.python.org/cpython/rev/c6b4a5354c23 changeset: 88757:c6b4a5354c23 parent: 88755:be9843012124 parent: 88756:e02da391741f user: Benjamin Peterson date: Sun Jan 26 22:58:42 2014 -0500 summary: merge 3.3 (closes #12704) files: Doc/reference/expressions.rst | 99 ++++++++++----------- Doc/reference/simple_stmts.rst | 57 +++--------- 2 files changed, 62 insertions(+), 94 deletions(-) diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -319,27 +319,25 @@ yield_atom: "(" `yield_expression` ")" yield_expression: "yield" [`expression_list` | "from" `expression`] -The :keyword:`yield` expression is only used when defining a :term:`generator` -function, -and can only be used in the body of a function definition. Using a -:keyword:`yield` expression in a function definition is sufficient to cause that -definition to create a generator function instead of a normal function. +The yield expression is only used when defining a :term:`generator` function and +thus can only be used in the body of a function definition. Using a yield +expression in a function's body causes that function to be a generator. When a generator function is called, it returns an iterator known as a generator. That generator then controls the execution of a generator function. The execution starts when one of the generator's methods is called. At that -time, the execution proceeds to the first :keyword:`yield` expression, where it -is suspended again, returning the value of :token:`expression_list` to -generator's caller. By suspended we mean that all local state is retained, -including the current bindings of local variables, the instruction pointer, and -the internal evaluation stack. When the execution is resumed by calling one of -the generator's methods, the function can proceed exactly as if the -:keyword:`yield` expression was just another external call. The value of the -:keyword:`yield` expression after resuming depends on the method which resumed -the execution. If :meth:`~generator.__next__` is used (typically via either a -:keyword:`for` or the :func:`next` builtin) then the result is :const:`None`, -otherwise, if :meth:`~generator.send` is used, then the result will be the -value passed in to that method. +time, the execution proceeds to the first yield expression, where it is +suspended again, returning the value of :token:`expression_list` to generator's +caller. By suspended, we mean that all local state is retained, including the +current bindings of local variables, the instruction pointer, and the internal +evaluation stack. When the execution is resumed by calling one of the +generator's methods, the function can proceed exactly as if the yield expression +was just another external call. The value of the yield expression after +resuming depends on the method which resumed the execution. If +:meth:`~generator.__next__` is used (typically via either a :keyword:`for` or +the :func:`next` builtin) then the result is :const:`None`. Otherwise, if +:meth:`~generator.send` is used, then the result will be the value passed in to +that method. .. index:: single: coroutine @@ -349,11 +347,11 @@ where should the execution continue after it yields; the control is always transferred to the generator's caller. -:keyword:`yield` expressions are allowed in the :keyword:`try` clause of a -:keyword:`try` ... :keyword:`finally` construct. If the generator is not -resumed before it is finalized (by reaching a zero reference count or by being -garbage collected), the generator-iterator's :meth:`~generator.close` method -will be called, allowing any pending :keyword:`finally` clauses to execute. +yield expressions are allowed in the :keyword:`try` clause of a :keyword:`try` +... :keyword:`finally` construct. If the generator is not resumed before it is +finalized (by reaching a zero reference count or by being garbage collected), +the generator-iterator's :meth:`~generator.close` method will be called, +allowing any pending :keyword:`finally` clauses to execute. When ``yield from `` is used, it treats the supplied expression as a subiterator. All values produced by that subiterator are passed directly @@ -373,12 +371,24 @@ .. versionchanged:: 3.3 Added ``yield from `` to delegate control flow to a subiterator -The parentheses can be omitted when the :keyword:`yield` expression is the -sole expression on the right hand side of an assignment statement. +The parentheses may be omitted when the yield expression is the sole expression +on the right hand side of an assignment statement. + +.. seealso:: + + :pep:`0255` - Simple Generators + The proposal for adding generators and the :keyword:`yield` statement to Python. + + :pep:`0342` - Coroutines via Enhanced Generators + The proposal to enhance the API and syntax of generators, making them + usable as simple coroutines. + + :pep:`0380` - Syntax for Delegating to a Subgenerator + The proposal to introduce the :token:`yield_from` syntax, making delegation + to sub-generators easy. .. index:: object: generator - Generator-iterator methods ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -395,13 +405,12 @@ .. method:: generator.__next__() Starts the execution of a generator function or resumes it at the last - executed :keyword:`yield` expression. When a generator function is resumed - with a :meth:`~generator.__next__` method, the current :keyword:`yield` - expression always evaluates to :const:`None`. The execution then continues - to the next :keyword:`yield` expression, where the generator is suspended - again, and the value of the :token:`expression_list` is returned to - :meth:`next`'s caller. - If the generator exits without yielding another value, a :exc:`StopIteration` + executed yield expression. When a generator function is resumed with a + :meth:`~generator.__next__` method, the current yield expression always + evaluates to :const:`None`. The execution then continues to the next yield + expression, where the generator is suspended again, and the value of the + :token:`expression_list` is returned to :meth:`next`'s caller. If the + generator exits without yielding another value, a :exc:`StopIteration` exception is raised. This method is normally called implicitly, e.g. by a :keyword:`for` loop, or @@ -411,12 +420,12 @@ .. method:: generator.send(value) Resumes the execution and "sends" a value into the generator function. The - ``value`` argument becomes the result of the current :keyword:`yield` - expression. The :meth:`send` method returns the next value yielded by the - generator, or raises :exc:`StopIteration` if the generator exits without - yielding another value. When :meth:`send` is called to start the generator, - it must be called with :const:`None` as the argument, because there is no - :keyword:`yield` expression that could receive the value. + *value* argument becomes the result of the current yield expression. The + :meth:`send` method returns the next value yielded by the generator, or + raises :exc:`StopIteration` if the generator exits without yielding another + value. When :meth:`send` is called to start the generator, it must be called + with :const:`None` as the argument, because there is no yield expression that + could receive the value. .. method:: generator.throw(type[, value[, traceback]]) @@ -478,20 +487,6 @@ Python." -.. seealso:: - - :pep:`0255` - Simple Generators - The proposal for adding generators and the :keyword:`yield` statement to Python. - - :pep:`0342` - Coroutines via Enhanced Generators - The proposal to enhance the API and syntax of generators, making them - usable as simple coroutines. - - :pep:`0380` - Syntax for Delegating to a Subgenerator - The proposal to introduce the :token:`yield_from` syntax, making delegation - to sub-generators easy. - - .. _primaries: Primaries diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -445,53 +445,26 @@ .. productionlist:: yield_stmt: `yield_expression` -The :keyword:`yield` statement is only used when defining a generator function, -and is only used in the body of the generator function. Using a :keyword:`yield` -statement in a function definition is sufficient to cause that definition to -create a generator function instead of a normal function. +A :keyword:`yield` statement is semantically equivalent to a :ref:`yield +expression `. The yield statement can be used to omit the parentheses +that would otherwise be required in the equivalent yield expression +statement. For example, the yield statements :: -When a generator function is called, it returns an iterator known as a generator -iterator, or more commonly, a generator. The body of the generator function is -executed by calling the :func:`next` function on the generator repeatedly until -it raises an exception. + yield + yield from -When a :keyword:`yield` statement is executed, the state of the generator is -frozen and the value of :token:`expression_list` is returned to :meth:`next`'s -caller. By "frozen" we mean that all local state is retained, including the -current bindings of local variables, the instruction pointer, and the internal -evaluation stack: enough information is saved so that the next time :func:`next` -is invoked, the function can proceed exactly as if the :keyword:`yield` -statement were just another external call. +are equivalent to the yield expression statements :: -The :keyword:`yield` statement is allowed in the :keyword:`try` clause of a -:keyword:`try` ... :keyword:`finally` construct. If the generator is not -resumed before it is finalized (by reaching a zero reference count or by being -garbage collected), the generator-iterator's :meth:`close` method will be -called, allowing any pending :keyword:`finally` clauses to execute. + (yield ) + (yield from ) -When ``yield from `` is used, it treats the supplied expression as -a subiterator, producing values from it until the underlying iterator is -exhausted. +Yield expressions and statements are only used when defining a :term:`generator` +function, and are only used in the body of the generator function. Using yield +in a function definition is sufficient to cause that definition to create a +generator function instead of a normal function. - .. versionchanged:: 3.3 - Added ``yield from `` to delegate control flow to a subiterator - -For full details of :keyword:`yield` semantics, refer to the :ref:`yieldexpr` -section. - -.. seealso:: - - :pep:`0255` - Simple Generators - The proposal for adding generators and the :keyword:`yield` statement to Python. - - :pep:`0342` - Coroutines via Enhanced Generators - The proposal to enhance the API and syntax of generators, making them - usable as simple coroutines. - - :pep:`0380` - Syntax for Delegating to a Subgenerator - The proposal to introduce the :token:`yield_from` syntax, making delegation - to sub-generators easy. - +For full details of :keyword:`yield` semantics, refer to the +:ref:`yieldexpr` section. .. _raise: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 05:08:54 2014 From: python-checkins at python.org (nick.coghlan) Date: Mon, 27 Jan 2014 05:08:54 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Fix_typo?= Message-ID: <3fCHWp4R7hz7Lmg@mail.python.org> http://hg.python.org/peps/rev/d7aeda570aa0 changeset: 5358:d7aeda570aa0 user: Nick Coghlan date: Mon Jan 27 14:08:35 2014 +1000 summary: Fix typo files: pep-0462.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0462.txt b/pep-0462.txt --- a/pep-0462.txt +++ b/pep-0462.txt @@ -313,7 +313,7 @@ learn when a contributor is nominated to become a core developer. This should have a dual benefit, both in making the existing core developers more comfortable with granting that additional level of responsibility, and in -making new contributors more comforable with exercising it. +making new contributors more comfortable with exercising it. Technical Challenges -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jan 27 05:34:30 2014 From: python-checkins at python.org (nick.coghlan) Date: Mon, 27 Jan 2014 05:34:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_462=3A_Add_section_on_pos?= =?utf-8?q?sible_Mercurial_integration?= Message-ID: <3fCJ5L0H7bz7Ljb@mail.python.org> http://hg.python.org/peps/rev/112e98ba3718 changeset: 5359:112e98ba3718 user: Nick Coghlan date: Mon Jan 27 14:34:20 2014 +1000 summary: PEP 462: Add section on possible Mercurial integration files: pep-0462.txt | 25 +++++++++++++++++++++++++ 1 files changed, 25 insertions(+), 0 deletions(-) diff --git a/pep-0462.txt b/pep-0462.txt --- a/pep-0462.txt +++ b/pep-0462.txt @@ -495,6 +495,31 @@ hence likely even more amenable to automated analysis. +Enhancing Mercurial/Rietveld/Roundup integration +------------------------------------------------ + +One useful part of the OpenStack workflow is the "git review" plugin, +which makes it relatively easy to push a branch from a local git clone up +to Gerrit for review. + +It seems that it should be possible to create a plugin that similarly +integrates Mercurial queues with Rietveld and Roundup, allowing a draft +patch to be uploaded as easily as running a command like "hg qpost" with a +suitable .hgqpost configuration file checked in to the source repo. + +(There's an existing `hg review `__, +plugin hence the suggestion of ``hg qpost`` as an alternate command) + +It would also be good to work directly with the Mercurial folks to come up +with a tailored CPython-specific tutorial for using Mercurial queues and +other extensions to work effectively with the CPython repository structure. +We have some of that already in the developer guide, but I've come to believe +that we may want to start getting more opinionated as to which extensions +we recommend using, especially for users that have previously learned +``git`` and need to know which extensions to enable to gain a similar level +of flexibility in their local workflow from Mercurial. + + Social Challenges ================= -- Repository URL: http://hg.python.org/peps From tjreedy at udel.edu Mon Jan 27 06:28:15 2014 From: tjreedy at udel.edu (Terry Reedy) Date: Mon, 27 Jan 2014 00:28:15 -0500 Subject: [Python-checkins] peps: Incorporate PEP 462 feedback In-Reply-To: <3fCGVH220wz7Lkf@mail.python.org> References: <3fCGVH220wz7Lkf@mail.python.org> Message-ID: <52E5EE6F.8010300@udel.edu> On 1/26/2014 10:22 PM, nick.coghlan wrote: > +Terry Reedy has suggested doing an initial filter which specifically looks > +for approved documentation-only patches (~700 of the 4000+ open CPython > +issues are pure documentation updates). This approach would avoid several > +of the issues related to flaky tests and cross-platform testing, while > +still allowing the rest of the automation flows to be worked out (such as > +how to push a patch into the merge queue). > + > +The one downside to this approach is that Zuul wouldn't have complete > +control of the merge process as it usually expects, so there would > +potentially be additional coordination needed around that. An essential part of my idea is that Zuul *would* have complete control while pushing doc patches to avoid the otherwise inevitable push races. Initially, this would be for a part of every day. While it has control, I would expect it to push doc patches at intervals of perhaps a minute, or even more rapidly with parallel testing. (Since doc patch rarely interfere and would be expected to apply after pre-testing, little speculative testing would need to be tossed.) > +It may be worth keeping this approach as a fallback option if the initial > +deployment proves to have more trouble with test reliability than is > +anticipated. I think a doc queue should be a permanent part of the system. There would always be doc-only patches -- and I suspect even more than now. One of the types of jobs on the main queue could be a periodic 'push all pending doc patches' job. I would then think we should try splitting code + doc patches into a code patch, pushed first, and a doc patch, added to the doc queue if the code patch succeeded. Terry From python-checkins at python.org Mon Jan 27 07:28:48 2014 From: python-checkins at python.org (larry.hastings) Date: Mon, 27 Jan 2014 07:28:48 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Documentation_fixes=2C_inc?= =?utf-8?q?luding_fixing_=22suspicious=22_problems=2E?= Message-ID: <3fCLdD2slhz7Ljy@mail.python.org> http://hg.python.org/cpython/rev/d968fa8d8f3e changeset: 88758:d968fa8d8f3e parent: 88722:0ae768637a07 user: Larry Hastings date: Sun Jan 26 00:42:02 2014 -0800 summary: Documentation fixes, including fixing "suspicious" problems. files: Doc/howto/clinic.rst | 118 ++++++----- Doc/tools/sphinxext/susp-ignored.csv | 6 +- Lib/pydoc_data/topics.py | 148 +++++++------- 3 files changed, 143 insertions(+), 129 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -149,7 +149,7 @@ 1. Find a Python builtin that calls either :c:func:`PyArg_ParseTuple` or :c:func:`PyArg_ParseTupleAndKeywords`, and hasn't been converted to work with Argument Clinic yet. - For my example I'm using ``pickle.Pickler.dump()``. + For my example I'm using ``_pickle.Pickler.dump()``. 2. If the call to the ``PyArg_Parse`` function uses any of the following format units:: @@ -214,7 +214,7 @@ Sample:: /*[clinic input] - pickle.Pickler.dump + _pickle.Pickler.dump Write a pickled representation of obj to the open file. [clinic start generated code]*/ @@ -227,23 +227,28 @@ the top. (In our sample code we'll just show the two blocks next to each other.) - Sample:: - - /*[clinic input] - module pickle - class pickle.Pickler - [clinic start generated code]*/ - - /*[clinic input] - pickle.Pickler.dump - - Write a pickled representation of obj to the open file. - [clinic start generated code]*/ - The name of the class and module should be the same as the one seen by Python. Check the name defined in the :c:type:`PyModuleDef` or :c:type:`PyTypeObject` as appropriate. + When you declare a class, you must also specify two aspects of its type + in C: the type declaration you'd use for a pointer to an instance of + this class, and a pointer to the :c:type:`PyTypeObject` for this class. + + Sample:: + + /*[clinic input] + module _pickle + class _pickle.Pickler "PicklerObject *" "&Pickler_Type" + [clinic start generated code]*/ + + /*[clinic input] + _pickle.Pickler.dump + + Write a pickled representation of obj to the open file. + [clinic start generated code]*/ + + 8. Declare each of the parameters to the function. Each parameter @@ -286,13 +291,13 @@ Sample:: - /*[clinic input] - module pickle - class pickle.Pickler - [clinic start generated code]*/ + /*[clinic input] + module _pickle + class _pickle.Pickler "PicklerObject *" "&Pickler_Type" + [clinic start generated code]*/ - /*[clinic input] - pickle.Pickler.dump + /*[clinic input] + _pickle.Pickler.dump obj: 'O' @@ -309,7 +314,7 @@ itself before the first keyword-only argument, indented the same as the parameter lines. - (``pickle.Pickler.dump`` has neither, so our sample is unchanged.) + (``_pickle.Pickler.dump`` has neither, so our sample is unchanged.) 10. If the existing C function calls :c:func:`PyArg_ParseTuple` @@ -327,12 +332,12 @@ Sample:: /*[clinic input] - module pickle - class pickle.Pickler + module _pickle + class _pickle.Pickler "PicklerObject *" "&Pickler_Type" [clinic start generated code]*/ /*[clinic input] - pickle.Pickler.dump + _pickle.Pickler.dump obj: 'O' / @@ -354,12 +359,12 @@ Sample:: /*[clinic input] - module pickle - class pickle.Pickler + module _pickle + class _pickle.Pickler "PicklerObject *" "&Pickler_Type" [clinic start generated code]*/ /*[clinic input] - pickle.Pickler.dump + _pickle.Pickler.dump obj: 'O' The object to be pickled. @@ -373,13 +378,13 @@ the file in your text editor to see:: /*[clinic input] - module pickle - class pickle.Pickler + module _pickle + class _pickle.Pickler "PicklerObject *" "&Pickler_Type" [clinic start generated code]*/ /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ /*[clinic input] - pickle.Pickler.dump + _pickle.Pickler.dump obj: 'O' The object to be pickled. @@ -388,12 +393,12 @@ Write a pickled representation of obj to the open file. [clinic start generated code]*/ - PyDoc_STRVAR(pickle_Pickler_dump__doc__, + PyDoc_STRVAR(_pickle_Pickler_dump__doc__, "Write a pickled representation of obj to the open file.\n" "\n" ... static PyObject * - pickle_Pickler_dump_impl(PyObject *self, PyObject *obj) + _pickle_Pickler_dump_impl(PicklerObject *self, PyObject *obj) /*[clinic end generated code: checksum=3bd30745bf206a48f8b576a1da3d90f55a0a4187]*/ Obviously, if Argument Clinic didn't produce any output, it's because @@ -428,8 +433,8 @@ macro defining the appropriate static :c:type:`PyMethodDef` structure for this builtin:: - #define _PICKLE_PICKLER_DUMP_METHODDEF \ - {"dump", (PyCFunction)_pickle_Pickler_dump, METH_O, _pickle_Pickler_dump__doc__}, + #define __PICKLE_PICKLER_DUMP_METHODDEF \ + {"dump", (PyCFunction)__pickle_Pickler_dump, METH_O, __pickle_Pickler_dump__doc__}, This static structure should be *exactly* the same as the existing static :c:type:`PyMethodDef` structure for this builtin. @@ -463,13 +468,13 @@ Sample:: /*[clinic input] - module pickle - class pickle.Pickler + module _pickle + class _pickle.Pickler "PicklerObject *" "&Pickler_Type" [clinic start generated code]*/ /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ /*[clinic input] - pickle.Pickler.dump + _pickle.Pickler.dump obj: 'O' The object to be pickled. @@ -478,12 +483,12 @@ Write a pickled representation of obj to the open file. [clinic start generated code]*/ - PyDoc_STRVAR(pickle_Pickler_dump__doc__, + PyDoc_STRVAR(__pickle_Pickler_dump__doc__, "Write a pickled representation of obj to the open file.\n" "\n" ... static PyObject * - pickle_Pickler_dump_impl(PyObject *self, PyObject *obj) + _pickle_Pickler_dump_impl(PicklerObject *self, PyObject *obj) /*[clinic end generated code: checksum=3bd30745bf206a48f8b576a1da3d90f55a0a4187]*/ { /* Check whether the Pickler was initialized correctly (issue3664). @@ -515,8 +520,8 @@ Sample:: static struct PyMethodDef Pickler_methods[] = { - _PICKLE_PICKLER_DUMP_METHODDEF - _PICKLE_PICKLER_CLEAR_MEMO_METHODDEF + __PICKLE_PICKLER_DUMP_METHODDEF + __PICKLE_PICKLER_CLEAR_MEMO_METHODDEF {NULL, NULL} /* sentinel */ }; @@ -1106,15 +1111,16 @@ ------------------------ Argument Clinic automatically adds a "self" parameter for you -using a default converter. However, you can override +using a default converter. It automatically sets the ``type`` +of this parameter to the "pointer to an instance" you specified +when you declared the type. However, you can override Argument Clinic's converter and specify one yourself. Just add your own ``self`` parameter as the first parameter in a block, and ensure that its converter is an instance of ``self_converter`` or a subclass thereof. -What's the point? This lets you automatically cast ``self`` -from ``PyObject *`` to a custom type, just like ``object()`` -does with its ``type`` parameter. +What's the point? This lets you override the type of ``self``, +or give it a different default name. How do you specify the custom type you want to cast ``self`` to? If you only have one or two functions with the same type for ``self``, @@ -1502,6 +1508,8 @@ and ``docstring_prototype``, write the ``impl_definition`` to ``block``, and write everything else to ``file``. + The default filename is ``"{dirname}/clinic/{basename}.h"``. + ``buffer`` Save up all most of the output from Clinic, to be written into your file near the end. For Python files implementing modules @@ -1554,7 +1562,7 @@ This creates a new destination with name ```` and type ````. -There are five destination types:: +There are five destination types: ``suppress`` Throws the text away. @@ -1575,12 +1583,18 @@ The template can use three strings internally that will be replaced by bits of the filename: - {filename} - The full filename. + {path} + The full path to the file, including directory and full filename. + {dirname} + The name of the directory the file is in. {basename} - Everything up to but not including the last '.'. - {extension} - The last '.' and everything after it. + Just the name of the file, not including the directory. + {basename_root} + Basename with the extension clipped off + (everything up to but not including the last '.'). + {basename_extension} + The last '.' and everything after it. If the basename + does not contain a period, this will be the empty string. If there are no periods in the filename, {basename} and {filename} are the same, and {extension} is empty. "{basename}{extension}" diff --git a/Doc/tools/sphinxext/susp-ignored.csv b/Doc/tools/sphinxext/susp-ignored.csv --- a/Doc/tools/sphinxext/susp-ignored.csv +++ b/Doc/tools/sphinxext/susp-ignored.csv @@ -79,9 +79,8 @@ howto/logging,,:This,DEBUG:root:This message should go to the log file howto/logging,,:This,DEBUG:This message should appear on the console howto/logging,,:Watch,WARNING:root:Watch out! -howto/pyporting,75,::,# make sure to use :: Python *and* :: Python :: 3 so -howto/pyporting,75,::,"'Programming Language :: Python'," -howto/pyporting,75,::,'Programming Language :: Python :: 3' +howto/pyporting,,::,Programming Language :: Python :: 2 +howto/pyporting,,::,Programming Language :: Python :: 3 howto/regex,,::, howto/regex,,:foo,(?:foo) howto/urllib2,,:example,"for example ""joe at password:example.com""" @@ -278,6 +277,7 @@ whatsnew/3.2,,:location,zope9-location = ${zope9:location} whatsnew/3.2,,:prefix,zope-conf = ${custom:prefix}/etc/zope.conf whatsnew/changelog,,:platform,:platform: +whatsnew/changelog,,:gz,": TarFile opened with external fileobj and ""w:gz"" mode didn't" whatsnew/changelog,,:PythonCmd,"With Tk < 8.5 _tkinter.c:PythonCmd() raised UnicodeDecodeError, caused" whatsnew/changelog,,::,": Fix FTP tests for IPv6, bind to ""::1"" instead of ""localhost""." whatsnew/changelog,,::,": Use ""127.0.0.1"" or ""::1"" instead of ""localhost"" as much as" 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,79 +1,79 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Sun Jan 5 04:33:19 2014 -topics = {'assert': '\nThe ``assert`` statement\n************************\n\nAssert statements are a convenient way to insert debugging assertions\ninto a program:\n\n assert_stmt ::= "assert" expression ["," expression]\n\nThe simple form, ``assert expression``, is equivalent to\n\n if __debug__:\n if not expression: raise AssertionError\n\nThe extended form, ``assert expression1, expression2``, is equivalent\nto\n\n if __debug__:\n if not expression1: raise AssertionError(expression2)\n\nThese equivalences assume that ``__debug__`` and ``AssertionError``\nrefer to the built-in variables with those names. In the current\nimplementation, the built-in variable ``__debug__`` is ``True`` under\nnormal circumstances, ``False`` when optimization is requested\n(command line option -O). The current code generator emits no code\nfor an assert statement when optimization is requested at compile\ntime. Note that it is unnecessary to include the source code for the\nexpression that failed in the error message; it will be displayed as\npart of the stack trace.\n\nAssignments to ``__debug__`` are illegal. The value for the built-in\nvariable is determined when the interpreter starts.\n', - 'assignment': '\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The object\n must be an iterable with the same number of items as there are\n targets in the target list, and the items are assigned, from left to\n right, to the corresponding targets.\n\n * If the target list contains one target prefixed with an asterisk,\n called a "starred" target: The object must be a sequence with at\n least as many items as there are targets in the target list, minus\n one. The first items of the sequence are assigned, from left to\n right, to the targets before the starred target. The final items\n of the sequence are assigned to the targets after the starred\n target. A list of the remaining items in the sequence is then\n assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of items\n as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a ``global`` or ``nonlocal``\n statement in the current code block: the name is bound to the\n object in the current local namespace.\n\n * Otherwise: the name is bound to the object in the global namespace\n or the outer namespace determined by ``nonlocal``, respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in square\n brackets: The object must be an iterable with the same number of\n items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, ``TypeError`` is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily ``AttributeError``).\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n ``a.x`` can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target ``a.x`` is\n always set as an instance attribute, creating it if necessary.\n Thus, the two occurrences of ``a.x`` do not necessarily refer to the\n same attribute: if the RHS expression refers to a class attribute,\n the LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with ``property()``.\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, ``IndexError`` is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the ``__setitem__()`` method is called\n with appropriate arguments.\n\n* If the target is a slicing: The primary expression in the reference\n is evaluated. It should yield a mutable sequence object (such as a\n list). The assigned object should be a sequence object of the same\n type. Next, the lower and upper bound expressions are evaluated,\n insofar they are present; defaults are zero and the sequence\'s\n length. The bounds should evaluate to integers. If either bound is\n negative, the sequence\'s length is added to it. The resulting\n bounds are clipped to lie between zero and the sequence\'s length,\n inclusive. Finally, the sequence object is asked to replace the\n slice with the items of the assigned sequence. The length of the\n slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the object\n allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nWARNING: Although the definition of assignment implies that overlaps\nbetween the left-hand side and the right-hand side are \'safe\' (for\nexample ``a, b = b, a`` swaps two variables), overlaps *within* the\ncollection of assigned-to variables are not safe! For instance, the\nfollowing program prints ``[0, 2]``:\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2\n print(x)\n\nSee also:\n\n **PEP 3132** - Extended Iterable Unpacking\n The specification for the ``*target`` feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', - 'atom-identifiers': '\nIdentifiers (Names)\n*******************\n\nAn identifier occurring as an atom is a name. See section\n*Identifiers and keywords* for lexical definition and section *Naming\nand binding* for documentation of naming and binding.\n\nWhen the name is bound to an object, evaluation of the atom yields\nthat object. When a name is not bound, an attempt to evaluate it\nraises a ``NameError`` exception.\n\n**Private name mangling:** When an identifier that textually occurs in\na class definition begins with two or more underscore characters and\ndoes not end in two or more underscores, it is considered a *private\nname* of that class. Private names are transformed to a longer form\nbefore code is generated for them. The transformation inserts the\nclass name, with leading underscores removed and a single underscore\ninserted, in front of the name. For example, the identifier\n``__spam`` occurring in a class named ``Ham`` will be transformed to\n``_Ham__spam``. This transformation is independent of the syntactical\ncontext in which the identifier is used. If the transformed name is\nextremely long (longer than 255 characters), implementation defined\ntruncation may happen. If the class name consists only of underscores,\nno transformation is done.\n', +# Autogenerated by Sphinx on Sun Jan 26 00:05:40 2014 +topics = {'assert': '\nThe "assert" statement\n**********************\n\nAssert statements are a convenient way to insert debugging assertions\ninto a program:\n\n assert_stmt ::= "assert" expression ["," expression]\n\nThe simple form, "assert expression", is equivalent to\n\n if __debug__:\n if not expression: raise AssertionError\n\nThe extended form, "assert expression1, expression2", is equivalent to\n\n if __debug__:\n if not expression1: raise AssertionError(expression2)\n\nThese equivalences assume that "__debug__" and "AssertionError" refer\nto the built-in variables with those names. In the current\nimplementation, the built-in variable "__debug__" is "True" under\nnormal circumstances, "False" when optimization is requested (command\nline option -O). The current code generator emits no code for an\nassert statement when optimization is requested at compile time. Note\nthat it is unnecessary to include the source code for the expression\nthat failed in the error message; it will be displayed as part of the\nstack trace.\n\nAssignments to "__debug__" are illegal. The value for the built-in\nvariable is determined when the interpreter starts.\n', + 'assignment': '\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The\n object must be an iterable with the same number of items as there\n are targets in the target list, and the items are assigned, from\n left to right, to the corresponding targets.\n\n * If the target list contains one target prefixed with an\n asterisk, called a "starred" target: The object must be a sequence\n with at least as many items as there are targets in the target\n list, minus one. The first items of the sequence are assigned,\n from left to right, to the targets before the starred target. The\n final items of the sequence are assigned to the targets after the\n starred target. A list of the remaining items in the sequence is\n then assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of\n items as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a "global" or "nonlocal" statement\n in the current code block: the name is bound to the object in the\n current local namespace.\n\n * Otherwise: the name is bound to the object in the global\n namespace or the outer namespace determined by "nonlocal",\n respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in\n square brackets: The object must be an iterable with the same number\n of items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, "TypeError" is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily "AttributeError").\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n "a.x" can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target "a.x" is always\n set as an instance attribute, creating it if necessary. Thus, the\n two occurrences of "a.x" do not necessarily refer to the same\n attribute: if the RHS expression refers to a class attribute, the\n LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with "property()".\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, "IndexError" is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the "__setitem__()" method is called with\n appropriate arguments.\n\n* If the target is a slicing: The primary expression in the\n reference is evaluated. It should yield a mutable sequence object\n (such as a list). The assigned object should be a sequence object\n of the same type. Next, the lower and upper bound expressions are\n evaluated, insofar they are present; defaults are zero and the\n sequence\'s length. The bounds should evaluate to integers. If\n either bound is negative, the sequence\'s length is added to it. The\n resulting bounds are clipped to lie between zero and the sequence\'s\n length, inclusive. Finally, the sequence object is asked to replace\n the slice with the items of the assigned sequence. The length of\n the slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the object\n allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nWARNING: Although the definition of assignment implies that overlaps\nbetween the left-hand side and the right-hand side are \'safe\' (for\nexample "a, b = b, a" swaps two variables), overlaps *within* the\ncollection of assigned-to variables are not safe! For instance, the\nfollowing program prints "[0, 2]":\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2\n print(x)\n\nSee also: **PEP 3132** - Extended Iterable Unpacking\n\n The specification for the "*target" feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like "x += 1" can be rewritten as\n"x = x + 1" to achieve a similar, but not exactly equal effect. In the\naugmented version, "x" is only evaluated once. Also, when possible,\nthe actual operation is performed *in-place*, meaning that rather than\ncreating a new object and assigning that to the target, the old object\nis modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', + 'atom-identifiers': '\nIdentifiers (Names)\n*******************\n\nAn identifier occurring as an atom is a name. See section\n*Identifiers and keywords* for lexical definition and section *Naming\nand binding* for documentation of naming and binding.\n\nWhen the name is bound to an object, evaluation of the atom yields\nthat object. When a name is not bound, an attempt to evaluate it\nraises a "NameError" exception.\n\n**Private name mangling:** When an identifier that textually occurs in\na class definition begins with two or more underscore characters and\ndoes not end in two or more underscores, it is considered a *private\nname* of that class. Private names are transformed to a longer form\nbefore code is generated for them. The transformation inserts the\nclass name, with leading underscores removed and a single underscore\ninserted, in front of the name. For example, the identifier "__spam"\noccurring in a class named "Ham" will be transformed to "_Ham__spam".\nThis transformation is independent of the syntactical context in which\nthe identifier is used. If the transformed name is extremely long\n(longer than 255 characters), implementation defined truncation may\nhappen. If the class name consists only of underscores, no\ntransformation is done.\n', 'atom-literals': "\nLiterals\n********\n\nPython supports string and bytes literals and various numeric\nliterals:\n\n literal ::= stringliteral | bytesliteral\n | integer | floatnumber | imagnumber\n\nEvaluation of a literal yields an object of the given type (string,\nbytes, integer, floating point number, complex number) with the given\nvalue. The value may be approximated in the case of floating point\nand imaginary (complex) literals. See section *Literals* for details.\n\nAll literals correspond to immutable data types, and hence the\nobject's identity is less important than its value. Multiple\nevaluations of literals with the same value (either the same\noccurrence in the program text or a different occurrence) may obtain\nthe same object or a different object with the same value.\n", - 'attribute-access': '\nCustomizing attribute access\n****************************\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A sequence must be\n returned. ``dir()`` converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n========================\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n====================\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n=========\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n--------------------------\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``bytes`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n', - 'attribute-references': '\nAttribute references\n********************\n\nAn attribute reference is a primary followed by a period and a name:\n\n attributeref ::= primary "." identifier\n\nThe primary must evaluate to an object of a type that supports\nattribute references, which most objects do. This object is then\nasked to produce the attribute whose name is the identifier (which can\nbe customized by overriding the ``__getattr__()`` method). If this\nattribute is not available, the exception ``AttributeError`` is\nraised. Otherwise, the type and value of the object produced is\ndetermined by the object. Multiple evaluations of the same attribute\nreference may yield different objects.\n', - 'augassign': '\nAugmented assignment statements\n*******************************\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', - 'binary': '\nBinary arithmetic operations\n****************************\n\nThe binary arithmetic operations have the conventional priority\nlevels. Note that some of these operations also apply to certain non-\nnumeric types. Apart from the power operator, there are only two\nlevels, one for multiplicative operators and one for additive\noperators:\n\n m_expr ::= u_expr | m_expr "*" u_expr | m_expr "//" u_expr | m_expr "/" u_expr\n | m_expr "%" u_expr\n a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr\n\nThe ``*`` (multiplication) operator yields the product of its\narguments. The arguments must either both be numbers, or one argument\nmust be an integer and the other must be a sequence. In the former\ncase, the numbers are converted to a common type and then multiplied\ntogether. In the latter case, sequence repetition is performed; a\nnegative repetition factor yields an empty sequence.\n\nThe ``/`` (division) and ``//`` (floor division) operators yield the\nquotient of their arguments. The numeric arguments are first\nconverted to a common type. Division of integers yields a float, while\nfloor division of integers results in an integer; the result is that\nof mathematical division with the \'floor\' function applied to the\nresult. Division by zero raises the ``ZeroDivisionError`` exception.\n\nThe ``%`` (modulo) operator yields the remainder from the division of\nthe first argument by the second. The numeric arguments are first\nconverted to a common type. A zero right argument raises the\n``ZeroDivisionError`` exception. The arguments may be floating point\nnumbers, e.g., ``3.14%0.7`` equals ``0.34`` (since ``3.14`` equals\n``4*0.7 + 0.34``.) The modulo operator always yields a result with\nthe same sign as its second operand (or zero); the absolute value of\nthe result is strictly smaller than the absolute value of the second\noperand [1].\n\nThe floor division and modulo operators are connected by the following\nidentity: ``x == (x//y)*y + (x%y)``. Floor division and modulo are\nalso connected with the built-in function ``divmod()``: ``divmod(x, y)\n== (x//y, x%y)``. [2].\n\nIn addition to performing the modulo operation on numbers, the ``%``\noperator is also overloaded by string objects to perform old-style\nstring formatting (also known as interpolation). The syntax for\nstring formatting is described in the Python Library Reference,\nsection *printf-style String Formatting*.\n\nThe floor division operator, the modulo operator, and the ``divmod()``\nfunction are not defined for complex numbers. Instead, convert to a\nfloating point number using the ``abs()`` function if appropriate.\n\nThe ``+`` (addition) operator yields the sum of its arguments. The\narguments must either both be numbers or both sequences of the same\ntype. In the former case, the numbers are converted to a common type\nand then added together. In the latter case, the sequences are\nconcatenated.\n\nThe ``-`` (subtraction) operator yields the difference of its\narguments. The numeric arguments are first converted to a common\ntype.\n', - 'bitwise': '\nBinary bitwise operations\n*************************\n\nEach of the three bitwise operations has a different priority level:\n\n and_expr ::= shift_expr | and_expr "&" shift_expr\n xor_expr ::= and_expr | xor_expr "^" and_expr\n or_expr ::= xor_expr | or_expr "|" xor_expr\n\nThe ``&`` operator yields the bitwise AND of its arguments, which must\nbe integers.\n\nThe ``^`` operator yields the bitwise XOR (exclusive OR) of its\narguments, which must be integers.\n\nThe ``|`` operator yields the bitwise (inclusive) OR of its arguments,\nwhich must be integers.\n', - 'bltin-code-objects': '\nCode Objects\n************\n\nCode objects are used by the implementation to represent "pseudo-\ncompiled" executable Python code such as a function body. They differ\nfrom function objects because they don\'t contain a reference to their\nglobal execution environment. Code objects are returned by the built-\nin ``compile()`` function and can be extracted from function objects\nthrough their ``__code__`` attribute. See also the ``code`` module.\n\nA code object can be executed or evaluated by passing it (instead of a\nsource string) to the ``exec()`` or ``eval()`` built-in functions.\n\nSee *The standard type hierarchy* for more information.\n', - 'bltin-ellipsis-object': '\nThe Ellipsis Object\n*******************\n\nThis object is commonly used by slicing (see *Slicings*). It supports\nno special operations. There is exactly one ellipsis object, named\n``Ellipsis`` (a built-in name). ``type(Ellipsis)()`` produces the\n``Ellipsis`` singleton.\n\nIt is written as ``Ellipsis`` or ``...``.\n', - 'bltin-null-object': "\nThe Null Object\n***************\n\nThis object is returned by functions that don't explicitly return a\nvalue. It supports no special operations. There is exactly one null\nobject, named ``None`` (a built-in name). ``type(None)()`` produces\nthe same singleton.\n\nIt is written as ``None``.\n", - 'bltin-type-objects': "\nType Objects\n************\n\nType objects represent the various object types. An object's type is\naccessed by the built-in function ``type()``. There are no special\noperations on types. The standard module ``types`` defines names for\nall standard built-in types.\n\nTypes are written like this: ````.\n", - 'booleans': '\nBoolean operations\n******************\n\n or_test ::= and_test | or_test "or" and_test\n and_test ::= not_test | and_test "and" not_test\n not_test ::= comparison | "not" not_test\n\nIn the context of Boolean operations, and also when expressions are\nused by control flow statements, the following values are interpreted\nas false: ``False``, ``None``, numeric zero of all types, and empty\nstrings and containers (including strings, tuples, lists,\ndictionaries, sets and frozensets). All other values are interpreted\nas true. User-defined objects can customize their truth value by\nproviding a ``__bool__()`` method.\n\nThe operator ``not`` yields ``True`` if its argument is false,\n``False`` otherwise.\n\nThe expression ``x and y`` first evaluates *x*; if *x* is false, its\nvalue is returned; otherwise, *y* is evaluated and the resulting value\nis returned.\n\nThe expression ``x or y`` first evaluates *x*; if *x* is true, its\nvalue is returned; otherwise, *y* is evaluated and the resulting value\nis returned.\n\n(Note that neither ``and`` nor ``or`` restrict the value and type they\nreturn to ``False`` and ``True``, but rather return the last evaluated\nargument. This is sometimes useful, e.g., if ``s`` is a string that\nshould be replaced by a default value if it is empty, the expression\n``s or \'foo\'`` yields the desired value. Because ``not`` has to\ninvent a value anyway, it does not bother to return a value of the\nsame type as its argument, so e.g., ``not \'foo\'`` yields ``False``,\nnot ``\'\'``.)\n', - 'break': '\nThe ``break`` statement\n***********************\n\n break_stmt ::= "break"\n\n``break`` may only occur syntactically nested in a ``for`` or\n``while`` loop, but not nested in a function or class definition\nwithin that loop.\n\nIt terminates the nearest enclosing loop, skipping the optional\n``else`` clause if the loop has one.\n\nIf a ``for`` loop is terminated by ``break``, the loop control target\nkeeps its current value.\n\nWhen ``break`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nleaving the loop.\n', - 'callable-types': '\nEmulating callable objects\n**************************\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n', - 'calls': '\nCalls\n*****\n\nA call calls a callable object (e.g., a *function*) with a possibly\nempty series of *arguments*:\n\n call ::= primary "(" [argument_list [","] | comprehension] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," keyword_arguments] ["," "**" expression]\n | "*" expression ["," keyword_arguments] ["," "**" expression]\n | "**" expression\n positional_arguments ::= expression ("," expression)*\n keyword_arguments ::= keyword_item ("," keyword_item)*\n keyword_item ::= identifier "=" expression\n\nA trailing comma may be present after the positional and keyword\narguments but does not affect the semantics.\n\nThe primary must evaluate to a callable object (user-defined\nfunctions, built-in functions, methods of built-in objects, class\nobjects, methods of class instances, and all objects having a\n``__call__()`` method are callable). All argument expressions are\nevaluated before the call is attempted. Please refer to section\n*Function definitions* for the syntax of formal *parameter* lists.\n\nIf keyword arguments are present, they are first converted to\npositional arguments, as follows. First, a list of unfilled slots is\ncreated for the formal parameters. If there are N positional\narguments, they are placed in the first N slots. Next, for each\nkeyword argument, the identifier is used to determine the\ncorresponding slot (if the identifier is the same as the first formal\nparameter name, the first slot is used, and so on). If the slot is\nalready filled, a ``TypeError`` exception is raised. Otherwise, the\nvalue of the argument is placed in the slot, filling it (even if the\nexpression is ``None``, it fills the slot). When all arguments have\nbeen processed, the slots that are still unfilled are filled with the\ncorresponding default value from the function definition. (Default\nvalues are calculated, once, when the function is defined; thus, a\nmutable object such as a list or dictionary used as default value will\nbe shared by all calls that don\'t specify an argument value for the\ncorresponding slot; this should usually be avoided.) If there are any\nunfilled slots for which no default value is specified, a\n``TypeError`` exception is raised. Otherwise, the list of filled\nslots is used as the argument list for the call.\n\n**CPython implementation detail:** An implementation may provide\nbuilt-in functions whose positional parameters do not have names, even\nif they are \'named\' for the purpose of documentation, and which\ntherefore cannot be supplied by keyword. In CPython, this is the case\nfor functions implemented in C that use ``PyArg_ParseTuple()`` to\nparse their arguments.\n\nIf there are more positional arguments than there are formal parameter\nslots, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``*identifier`` is present; in this case, that formal\nparameter receives a tuple containing the excess positional arguments\n(or an empty tuple if there were no excess positional arguments).\n\nIf any keyword argument does not correspond to a formal parameter\nname, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``**identifier`` is present; in this case, that\nformal parameter receives a dictionary containing the excess keyword\narguments (using the keywords as keys and the argument values as\ncorresponding values), or a (new) empty dictionary if there were no\nexcess keyword arguments.\n\nIf the syntax ``*expression`` appears in the function call,\n``expression`` must evaluate to an iterable. Elements from this\niterable are treated as if they were additional positional arguments;\nif there are positional arguments *x1*, ..., *xN*, and ``expression``\nevaluates to a sequence *y1*, ..., *yM*, this is equivalent to a call\nwith M+N positional arguments *x1*, ..., *xN*, *y1*, ..., *yM*.\n\nA consequence of this is that although the ``*expression`` syntax may\nappear *after* some keyword arguments, it is processed *before* the\nkeyword arguments (and the ``**expression`` argument, if any -- see\nbelow). So:\n\n >>> def f(a, b):\n ... print(a, b)\n ...\n >>> f(b=1, *(2,))\n 2 1\n >>> f(a=1, *(2,))\n Traceback (most recent call last):\n File "", line 1, in ?\n TypeError: f() got multiple values for keyword argument \'a\'\n >>> f(1, *(2,))\n 1 2\n\nIt is unusual for both keyword arguments and the ``*expression``\nsyntax to be used in the same call, so in practice this confusion does\nnot arise.\n\nIf the syntax ``**expression`` appears in the function call,\n``expression`` must evaluate to a mapping, the contents of which are\ntreated as additional keyword arguments. In the case of a keyword\nappearing in both ``expression`` and as an explicit keyword argument,\na ``TypeError`` exception is raised.\n\nFormal parameters using the syntax ``*identifier`` or ``**identifier``\ncannot be used as positional argument slots or as keyword argument\nnames.\n\nA call always returns some value, possibly ``None``, unless it raises\nan exception. How this value is computed depends on the type of the\ncallable object.\n\nIf it is---\n\na user-defined function:\n The code block for the function is executed, passing it the\n argument list. The first thing the code block will do is bind the\n formal parameters to the arguments; this is described in section\n *Function definitions*. When the code block executes a ``return``\n statement, this specifies the return value of the function call.\n\na built-in function or method:\n The result is up to the interpreter; see *Built-in Functions* for\n the descriptions of built-in functions and methods.\n\na class object:\n A new instance of that class is returned.\n\na class instance method:\n The corresponding user-defined function is called, with an argument\n list that is one longer than the argument list of the call: the\n instance becomes the first argument.\n\na class instance:\n The class must define a ``__call__()`` method; the effect is then\n the same as if that method was called.\n', - 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [parameter_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless there\n is a ``finally`` clause which happens to raise another exception.\n That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', - 'comparisons': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like ``a < b < c`` have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: ``True`` or ``False``.\n\nComparisons can be chained arbitrarily, e.g., ``x < y <= z`` is\nequivalent to ``x < y and y <= z``, except that ``y`` is evaluated\nonly once (but in both cases ``z`` is not evaluated at all when ``x <\ny`` is found to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then ``a op1 b op2 c ... y\nopN z`` is equivalent to ``a op1 b and b op2 c and ... y opN z``,\nexcept that each expression is evaluated at most once.\n\nNote that ``a op1 b op2 c`` doesn\'t imply any kind of comparison\nbetween *a* and *c*, so that, e.g., ``x < y > z`` is perfectly legal\n(though perhaps not pretty).\n\nThe operators ``<``, ``>``, ``==``, ``>=``, ``<=``, and ``!=`` compare\nthe values of two objects. The objects need not have the same type.\nIf both are numbers, they are converted to a common type. Otherwise,\nthe ``==`` and ``!=`` operators *always* consider objects of different\ntypes to be unequal, while the ``<``, ``>``, ``>=`` and ``<=``\noperators raise a ``TypeError`` when comparing objects of different\ntypes that do not implement these operators for the given pair of\ntypes. You can control comparison behavior of objects of non-built-in\ntypes by defining rich comparison methods like ``__gt__()``, described\nin section *Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values ``float(\'NaN\')`` and ``Decimal(\'NaN\')`` are special. The\n are identical to themselves, ``x is x`` but are not equal to\n themselves, ``x != x``. Additionally, comparing any value to a\n not-a-number value will return ``False``. For example, both ``3 <\n float(\'NaN\')`` and ``float(\'NaN\') < 3`` will return ``False``.\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric equivalents\n (the result of the built-in function ``ord()``) of their characters.\n [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison of\n corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, ``[1,2,x] <= [1,2,y]`` has the\n same value as ``x <= y``. If the corresponding element does not\n exist, the shorter sequence is ordered first (for example, ``[1,2] <\n [1,2,3]``).\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same ``(key, value)`` pairs. Order comparisons ``(\'<\', \'<=\', \'>=\',\n \'>\')`` raise ``TypeError``.\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets ``{1,2}`` and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, ``min()``, ``max()``, and ``sorted()`` produce\n undefined results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they are\n the same object; the choice whether one object is considered smaller\n or larger than another one is made arbitrarily but consistently\n within one execution of a program.\n\nComparison of objects of the differing types depends on whether either\nof the types provide explicit support for the comparison. Most\nnumeric types can be compared with one another. When cross-type\ncomparison is not supported, the comparison method returns\n``NotImplemented``.\n\nThe operators ``in`` and ``not in`` test for membership. ``x in s``\nevaluates to true if *x* is a member of *s*, and false otherwise. ``x\nnot in s`` returns the negation of ``x in s``. All built-in sequences\nand set types support this as well as dictionary, for which ``in``\ntests whether a the dictionary has a given key. For container types\nsuch as list, tuple, set, frozenset, dict, or collections.deque, the\nexpression ``x in y`` is equivalent to ``any(x is e or x == e for e in\ny)``.\n\nFor the string and bytes types, ``x in y`` is true if and only if *x*\nis a substring of *y*. An equivalent test is ``y.find(x) != -1``.\nEmpty strings are always considered to be a substring of any other\nstring, so ``"" in "abc"`` will return ``True``.\n\nFor user-defined classes which define the ``__contains__()`` method,\n``x in y`` is true if and only if ``y.__contains__(x)`` is true.\n\nFor user-defined classes which do not define ``__contains__()`` but do\ndefine ``__iter__()``, ``x in y`` is true if some value ``z`` with ``x\n== z`` is produced while iterating over ``y``. If an exception is\nraised during the iteration, it is as if ``in`` raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n``__getitem__()``, ``x in y`` is true if and only if there is a non-\nnegative integer index *i* such that ``x == y[i]``, and all lower\ninteger indices do not raise ``IndexError`` exception. (If any other\nexception is raised, it is as if ``in`` raised that exception).\n\nThe operator ``not in`` is defined to have the inverse true value of\n``in``.\n\nThe operators ``is`` and ``is not`` test for object identity: ``x is\ny`` is true if and only if *x* and *y* are the same object. ``x is\nnot y`` yields the inverse truth value. [4]\n', - 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe ``if``, ``while`` and ``for`` statements implement traditional\ncontrol flow constructs. ``try`` specifies exception handlers and/or\ncleanup code for a group of statements, while the ``with`` statement\nallows the execution of initialization and finalization code around a\nblock of code. Function and class definitions are also syntactically\ncompound statements.\n\nCompound statements consist of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which ``if`` clause a following ``else`` clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n``print()`` calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a ``NEWLINE`` possibly followed by\na ``DEDENT``. Also note that optional continuation clauses always\nbegin with a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling ``else``\' problem is solved in Python by\nrequiring nested ``if`` statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe ``if`` statement\n====================\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n\n\nThe ``while`` statement\n=======================\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n\n\nThe ``for`` statement\n=====================\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe ``try`` statement\n=====================\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception it is re-raised at the end of\nthe ``finally`` clause. If the ``finally`` clause raises another\nexception, the saved exception is set as the context of the new\nexception. If the ``finally`` clause executes a ``return`` or\n``break`` statement, the saved exception is discarded:\n\n def f():\n try:\n 1/0\n finally:\n return 42\n\n >>> f()\n 42\n\nThe exception information is not available to the program during\nexecution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe ``with`` statement\n======================\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the ``with_item``)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__exit__()`` is loaded for later use.\n\n3. The context manager\'s ``__enter__()`` method is invoked.\n\n4. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)* ["," "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more *parameters* have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding *argument* may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated from left to right when the\nfunction definition is executed.** This means that the expression is\nevaluated once, when the function is defined, and that the same "pre-\ncomputed" value is used for each call. This is especially important\nto understand when a default parameter is a mutable object, such as a\nlist or a dictionary: if the function modifies the object (e.g. by\nappending an item to a list), the default value is in effect modified.\nThis is generally not what was intended. A way around this is to use\n``None`` as the default, and explicitly test for it in the body of the\nfunction, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda\nexpressions, described in section *Lambdas*. Note that the lambda\nexpression is merely a shorthand for a simplified function definition;\na function defined in a "``def``" statement can be passed around or\nassigned to another name just like a function defined by a lambda\nexpression. The "``def``" form is actually more powerful since it\nallows the execution of multiple statements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nstatement executed inside a function definition defines a local\nfunction that can be returned or passed around. Free variables used\nin the nested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\nSee also:\n\n **PEP 3107** - Function Annotations\n The original specification for function annotations.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [parameter_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless there\n is a ``finally`` clause which happens to raise another exception.\n That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', - 'context-managers': '\nWith Statement Context Managers\n*******************************\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n', - 'continue': '\nThe ``continue`` statement\n**************************\n\n continue_stmt ::= "continue"\n\n``continue`` may only occur syntactically nested in a ``for`` or\n``while`` loop, but not nested in a function or class definition or\n``finally`` clause within that loop. It continues with the next cycle\nof the nearest enclosing loop.\n\nWhen ``continue`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nstarting the next loop cycle.\n', - 'conversions': '\nArithmetic conversions\n**********************\n\nWhen a description of an arithmetic operator below uses the phrase\n"the numeric arguments are converted to a common type," this means\nthat the operator implementation for built-in types works that way:\n\n* If either argument is a complex number, the other is converted to\n complex;\n\n* otherwise, if either argument is a floating point number, the other\n is converted to floating point;\n\n* otherwise, both must be integers and no conversion is necessary.\n\nSome additional rules apply for certain operators (e.g., a string left\nargument to the \'%\' operator). Extensions must define their own\nconversion behavior.\n', - 'customization': '\nBasic customization\n*******************\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected and cleaned up when the cyclic garbage collector is\n enabled (it\'s on by default). Refer to the documentation for the\n ``gc`` module for more information about this topic.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by ``str(object)`` and the built-in functions ``format()``\n and ``print()`` to compute the "informal" or nicely printable\n string representation of an object. The return value must be a\n *string* object.\n\n This method differs from ``object.__repr__()`` in that there is no\n expectation that ``__str__()`` return a valid Python expression: a\n more convenient or concise representation can be used.\n\n The default implementation defined by the built-in type ``object``\n calls ``object.__repr__()``.\n\nobject.__bytes__(self)\n\n Called by ``bytes()`` to compute a byte-string representation of an\n object. This should return a ``bytes`` object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``str.format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see ``functools.total_ordering()``.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n Note: ``hash()`` truncates the value returned from an object\'s custom\n ``__hash__()`` method to the size of a ``Py_ssize_t``. This is\n typically 8 bytes on 64-bit builds and 4 bytes on 32-bit builds.\n If an object\'s ``__hash__()`` must interoperate on builds of\n different bit sizes, be sure to check the width on all supported\n builds. An easy way to do this is with ``python -c "import sys;\n print(sys.hash_info.width)"``\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns an appropriate value such\n that ``x == y`` implies both that ``x is y`` and ``hash(x) ==\n hash(y)``.\n\n A class that overrides ``__eq__()`` and does not define\n ``__hash__()`` will have its ``__hash__()`` implicitly set to\n ``None``. When the ``__hash__()`` method of a class is ``None``,\n instances of the class will raise an appropriate ``TypeError`` when\n a program attempts to retrieve their hash value, and will also be\n correctly identified as unhashable when checking ``isinstance(obj,\n collections.Hashable``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``.\n\n If a class that does not override ``__eq__()`` wishes to suppress\n hash support, it should include ``__hash__ = None`` in the class\n definition. A class which defines its own ``__hash__()`` that\n explicitly raises a ``TypeError`` would be incorrectly identified\n as hashable by an ``isinstance(obj, collections.Hashable)`` call.\n\n Note: By default, the ``__hash__()`` values of str, bytes and datetime\n objects are "salted" with an unpredictable random value.\n Although they remain constant within an individual Python\n process, they are not predictable between repeated invocations of\n Python.This is intended to provide protection against a denial-\n of-service caused by carefully-chosen inputs that exploit the\n worst case performance of a dict insertion, O(n^2) complexity.\n See http://www.ocert.org/advisories/ocert-2011-003.html for\n details.Changing hash values affects the iteration order of\n dicts, sets and other mappings. Python has never made guarantees\n about this ordering (and it typically varies between 32-bit and\n 64-bit builds).See also ``PYTHONHASHSEED``.\n\n Changed in version 3.3: Hash randomization is enabled by default.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n', - 'debugger': '\n``pdb`` --- The Python Debugger\n*******************************\n\nThe module ``pdb`` defines an interactive source code debugger for\nPython programs. It supports setting (conditional) breakpoints and\nsingle stepping at the source line level, inspection of stack frames,\nsource code listing, and evaluation of arbitrary Python code in the\ncontext of any stack frame. It also supports post-mortem debugging\nand can be called under program control.\n\nThe debugger is extensible -- it is actually defined as the class\n``Pdb``. This is currently undocumented but easily understood by\nreading the source. The extension interface uses the modules ``bdb``\nand ``cmd``.\n\nThe debugger\'s prompt is ``(Pdb)``. Typical usage to run a program\nunder control of the debugger is:\n\n >>> import pdb\n >>> import mymodule\n >>> pdb.run(\'mymodule.test()\')\n > (0)?()\n (Pdb) continue\n > (1)?()\n (Pdb) continue\n NameError: \'spam\'\n > (1)?()\n (Pdb)\n\nChanged in version 3.3: Tab-completion via the ``readline`` module is\navailable for commands and command arguments, e.g. the current global\nand local names are offered as arguments of the ``p`` command.\n\n``pdb.py`` can also be invoked as a script to debug other scripts.\nFor example:\n\n python3 -m pdb myscript.py\n\nWhen invoked as a script, pdb will automatically enter post-mortem\ndebugging if the program being debugged exits abnormally. After post-\nmortem debugging (or after normal exit of the program), pdb will\nrestart the program. Automatic restarting preserves pdb\'s state (such\nas breakpoints) and in most cases is more useful than quitting the\ndebugger upon program\'s exit.\n\nNew in version 3.2: ``pdb.py`` now accepts a ``-c`` option that\nexecutes commands as if given in a ``.pdbrc`` file, see *Debugger\nCommands*.\n\nThe typical usage to break into the debugger from a running program is\nto insert\n\n import pdb; pdb.set_trace()\n\nat the location you want to break into the debugger. You can then\nstep through the code following this statement, and continue running\nwithout the debugger using the ``continue`` command.\n\nThe typical usage to inspect a crashed program is:\n\n >>> import pdb\n >>> import mymodule\n >>> mymodule.test()\n Traceback (most recent call last):\n File "", line 1, in ?\n File "./mymodule.py", line 4, in test\n test2()\n File "./mymodule.py", line 3, in test2\n print(spam)\n NameError: spam\n >>> pdb.pm()\n > ./mymodule.py(3)test2()\n -> print(spam)\n (Pdb)\n\nThe module defines the following functions; each enters the debugger\nin a slightly different way:\n\npdb.run(statement, globals=None, locals=None)\n\n Execute the *statement* (given as a string or a code object) under\n debugger control. The debugger prompt appears before any code is\n executed; you can set breakpoints and type ``continue``, or you can\n step through the statement using ``step`` or ``next`` (all these\n commands are explained below). The optional *globals* and *locals*\n arguments specify the environment in which the code is executed; by\n default the dictionary of the module ``__main__`` is used. (See\n the explanation of the built-in ``exec()`` or ``eval()``\n functions.)\n\npdb.runeval(expression, globals=None, locals=None)\n\n Evaluate the *expression* (given as a string or a code object)\n under debugger control. When ``runeval()`` returns, it returns the\n value of the expression. Otherwise this function is similar to\n ``run()``.\n\npdb.runcall(function, *args, **kwds)\n\n Call the *function* (a function or method object, not a string)\n with the given arguments. When ``runcall()`` returns, it returns\n whatever the function call returned. The debugger prompt appears\n as soon as the function is entered.\n\npdb.set_trace()\n\n Enter the debugger at the calling stack frame. This is useful to\n hard-code a breakpoint at a given point in a program, even if the\n code is not otherwise being debugged (e.g. when an assertion\n fails).\n\npdb.post_mortem(traceback=None)\n\n Enter post-mortem debugging of the given *traceback* object. If no\n *traceback* is given, it uses the one of the exception that is\n currently being handled (an exception must be being handled if the\n default is to be used).\n\npdb.pm()\n\n Enter post-mortem debugging of the traceback found in\n ``sys.last_traceback``.\n\nThe ``run*`` functions and ``set_trace()`` are aliases for\ninstantiating the ``Pdb`` class and calling the method of the same\nname. If you want to access further features, you have to do this\nyourself:\n\nclass class pdb.Pdb(completekey=\'tab\', stdin=None, stdout=None, skip=None, nosigint=False)\n\n ``Pdb`` is the debugger class.\n\n The *completekey*, *stdin* and *stdout* arguments are passed to the\n underlying ``cmd.Cmd`` class; see the description there.\n\n The *skip* argument, if given, must be an iterable of glob-style\n module name patterns. The debugger will not step into frames that\n originate in a module that matches one of these patterns. [1]\n\n By default, Pdb sets a handler for the SIGINT signal (which is sent\n when the user presses Ctrl-C on the console) when you give a\n ``continue`` command. This allows you to break into the debugger\n again by pressing Ctrl-C. If you want Pdb not to touch the SIGINT\n handler, set *nosigint* tot true.\n\n Example call to enable tracing with *skip*:\n\n import pdb; pdb.Pdb(skip=[\'django.*\']).set_trace()\n\n New in version 3.1: The *skip* argument.\n\n New in version 3.2: The *nosigint* argument. Previously, a SIGINT\n handler was never set by Pdb.\n\n run(statement, globals=None, locals=None)\n runeval(expression, globals=None, locals=None)\n runcall(function, *args, **kwds)\n set_trace()\n\n See the documentation for the functions explained above.\n\n\nDebugger Commands\n=================\n\nThe commands recognized by the debugger are listed below. Most\ncommands can be abbreviated to one or two letters as indicated; e.g.\n``h(elp)`` means that either ``h`` or ``help`` can be used to enter\nthe help command (but not ``he`` or ``hel``, nor ``H`` or ``Help`` or\n``HELP``). Arguments to commands must be separated by whitespace\n(spaces or tabs). Optional arguments are enclosed in square brackets\n(``[]``) in the command syntax; the square brackets must not be typed.\nAlternatives in the command syntax are separated by a vertical bar\n(``|``).\n\nEntering a blank line repeats the last command entered. Exception: if\nthe last command was a ``list`` command, the next 11 lines are listed.\n\nCommands that the debugger doesn\'t recognize are assumed to be Python\nstatements and are executed in the context of the program being\ndebugged. Python statements can also be prefixed with an exclamation\npoint (``!``). This is a powerful way to inspect the program being\ndebugged; it is even possible to change a variable or call a function.\nWhen an exception occurs in such a statement, the exception name is\nprinted but the debugger\'s state is not changed.\n\nThe debugger supports *aliases*. Aliases can have parameters which\nallows one a certain level of adaptability to the context under\nexamination.\n\nMultiple commands may be entered on a single line, separated by\n``;;``. (A single ``;`` is not used as it is the separator for\nmultiple commands in a line that is passed to the Python parser.) No\nintelligence is applied to separating the commands; the input is split\nat the first ``;;`` pair, even if it is in the middle of a quoted\nstring.\n\nIf a file ``.pdbrc`` exists in the user\'s home directory or in the\ncurrent directory, it is read in and executed as if it had been typed\nat the debugger prompt. This is particularly useful for aliases. If\nboth files exist, the one in the home directory is read first and\naliases defined there can be overridden by the local file.\n\nChanged in version 3.2: ``.pdbrc`` can now contain commands that\ncontinue debugging, such as ``continue`` or ``next``. Previously,\nthese commands had no effect.\n\nh(elp) [command]\n\n Without argument, print the list of available commands. With a\n *command* as argument, print help about that command. ``help pdb``\n displays the full documentation (the docstring of the ``pdb``\n module). Since the *command* argument must be an identifier,\n ``help exec`` must be entered to get help on the ``!`` command.\n\nw(here)\n\n Print a stack trace, with the most recent frame at the bottom. An\n arrow indicates the current frame, which determines the context of\n most commands.\n\nd(own) [count]\n\n Move the current frame *count* (default one) levels down in the\n stack trace (to a newer frame).\n\nu(p) [count]\n\n Move the current frame *count* (default one) levels up in the stack\n trace (to an older frame).\n\nb(reak) [([filename:]lineno | function) [, condition]]\n\n With a *lineno* argument, set a break there in the current file.\n With a *function* argument, set a break at the first executable\n statement within that function. The line number may be prefixed\n with a filename and a colon, to specify a breakpoint in another\n file (probably one that hasn\'t been loaded yet). The file is\n searched on ``sys.path``. Note that each breakpoint is assigned a\n number to which all the other breakpoint commands refer.\n\n If a second argument is present, it is an expression which must\n evaluate to true before the breakpoint is honored.\n\n Without argument, list all breaks, including for each breakpoint,\n the number of times that breakpoint has been hit, the current\n ignore count, and the associated condition if any.\n\ntbreak [([filename:]lineno | function) [, condition]]\n\n Temporary breakpoint, which is removed automatically when it is\n first hit. The arguments are the same as for ``break``.\n\ncl(ear) [filename:lineno | bpnumber [bpnumber ...]]\n\n With a *filename:lineno* argument, clear all the breakpoints at\n this line. With a space separated list of breakpoint numbers, clear\n those breakpoints. Without argument, clear all breaks (but first\n ask confirmation).\n\ndisable [bpnumber [bpnumber ...]]\n\n Disable the breakpoints given as a space separated list of\n breakpoint numbers. Disabling a breakpoint means it cannot cause\n the program to stop execution, but unlike clearing a breakpoint, it\n remains in the list of breakpoints and can be (re-)enabled.\n\nenable [bpnumber [bpnumber ...]]\n\n Enable the breakpoints specified.\n\nignore bpnumber [count]\n\n Set the ignore count for the given breakpoint number. If count is\n omitted, the ignore count is set to 0. A breakpoint becomes active\n when the ignore count is zero. When non-zero, the count is\n decremented each time the breakpoint is reached and the breakpoint\n is not disabled and any associated condition evaluates to true.\n\ncondition bpnumber [condition]\n\n Set a new *condition* for the breakpoint, an expression which must\n evaluate to true before the breakpoint is honored. If *condition*\n is absent, any existing condition is removed; i.e., the breakpoint\n is made unconditional.\n\ncommands [bpnumber]\n\n Specify a list of commands for breakpoint number *bpnumber*. The\n commands themselves appear on the following lines. Type a line\n containing just ``end`` to terminate the commands. An example:\n\n (Pdb) commands 1\n (com) p some_variable\n (com) end\n (Pdb)\n\n To remove all commands from a breakpoint, type commands and follow\n it immediately with ``end``; that is, give no commands.\n\n With no *bpnumber* argument, commands refers to the last breakpoint\n set.\n\n You can use breakpoint commands to start your program up again.\n Simply use the continue command, or step, or any other command that\n resumes execution.\n\n Specifying any command resuming execution (currently continue,\n step, next, return, jump, quit and their abbreviations) terminates\n the command list (as if that command was immediately followed by\n end). This is because any time you resume execution (even with a\n simple next or step), you may encounter another breakpoint--which\n could have its own command list, leading to ambiguities about which\n list to execute.\n\n If you use the \'silent\' command in the command list, the usual\n message about stopping at a breakpoint is not printed. This may be\n desirable for breakpoints that are to print a specific message and\n then continue. If none of the other commands print anything, you\n see no sign that the breakpoint was reached.\n\ns(tep)\n\n Execute the current line, stop at the first possible occasion\n (either in a function that is called or on the next line in the\n current function).\n\nn(ext)\n\n Continue execution until the next line in the current function is\n reached or it returns. (The difference between ``next`` and\n ``step`` is that ``step`` stops inside a called function, while\n ``next`` executes called functions at (nearly) full speed, only\n stopping at the next line in the current function.)\n\nunt(il) [lineno]\n\n Without argument, continue execution until the line with a number\n greater than the current one is reached.\n\n With a line number, continue execution until a line with a number\n greater or equal to that is reached. In both cases, also stop when\n the current frame returns.\n\n Changed in version 3.2: Allow giving an explicit line number.\n\nr(eturn)\n\n Continue execution until the current function returns.\n\nc(ont(inue))\n\n Continue execution, only stop when a breakpoint is encountered.\n\nj(ump) lineno\n\n Set the next line that will be executed. Only available in the\n bottom-most frame. This lets you jump back and execute code again,\n or jump forward to skip code that you don\'t want to run.\n\n It should be noted that not all jumps are allowed -- for instance\n it is not possible to jump into the middle of a ``for`` loop or out\n of a ``finally`` clause.\n\nl(ist) [first[, last]]\n\n List source code for the current file. Without arguments, list 11\n lines around the current line or continue the previous listing.\n With ``.`` as argument, list 11 lines around the current line.\n With one argument, list 11 lines around at that line. With two\n arguments, list the given range; if the second argument is less\n than the first, it is interpreted as a count.\n\n The current line in the current frame is indicated by ``->``. If\n an exception is being debugged, the line where the exception was\n originally raised or propagated is indicated by ``>>``, if it\n differs from the current line.\n\n New in version 3.2: The ``>>`` marker.\n\nll | longlist\n\n List all source code for the current function or frame.\n Interesting lines are marked as for ``list``.\n\n New in version 3.2.\n\na(rgs)\n\n Print the argument list of the current function.\n\np expression\n\n Evaluate the *expression* in the current context and print its\n value.\n\n Note: ``print()`` can also be used, but is not a debugger command ---\n this executes the Python ``print()`` function.\n\npp expression\n\n Like the ``p`` command, except the value of the expression is\n pretty-printed using the ``pprint`` module.\n\nwhatis expression\n\n Print the type of the *expression*.\n\nsource expression\n\n Try to get source code for the given object and display it.\n\n New in version 3.2.\n\ndisplay [expression]\n\n Display the value of the expression if it changed, each time\n execution stops in the current frame.\n\n Without expression, list all display expressions for the current\n frame.\n\n New in version 3.2.\n\nundisplay [expression]\n\n Do not display the expression any more in the current frame.\n Without expression, clear all display expressions for the current\n frame.\n\n New in version 3.2.\n\ninteract\n\n Start an interative interpreter (using the ``code`` module) whose\n global namespace contains all the (global and local) names found in\n the current scope.\n\n New in version 3.2.\n\nalias [name [command]]\n\n Create an alias called *name* that executes *command*. The command\n must *not* be enclosed in quotes. Replaceable parameters can be\n indicated by ``%1``, ``%2``, and so on, while ``%*`` is replaced by\n all the parameters. If no command is given, the current alias for\n *name* is shown. If no arguments are given, all aliases are listed.\n\n Aliases may be nested and can contain anything that can be legally\n typed at the pdb prompt. Note that internal pdb commands *can* be\n overridden by aliases. Such a command is then hidden until the\n alias is removed. Aliasing is recursively applied to the first\n word of the command line; all other words in the line are left\n alone.\n\n As an example, here are two useful aliases (especially when placed\n in the ``.pdbrc`` file):\n\n # Print instance variables (usage "pi classInst")\n alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k])\n # Print instance variables in self\n alias ps pi self\n\nunalias name\n\n Delete the specified alias.\n\n! statement\n\n Execute the (one-line) *statement* in the context of the current\n stack frame. The exclamation point can be omitted unless the first\n word of the statement resembles a debugger command. To set a\n global variable, you can prefix the assignment command with a\n ``global`` statement on the same line, e.g.:\n\n (Pdb) global list_options; list_options = [\'-l\']\n (Pdb)\n\nrun [args ...]\nrestart [args ...]\n\n Restart the debugged Python program. If an argument is supplied,\n it is split with ``shlex`` and the result is used as the new\n ``sys.argv``. History, breakpoints, actions and debugger options\n are preserved. ``restart`` is an alias for ``run``.\n\nq(uit)\n\n Quit from the debugger. The program being executed is aborted.\n\n-[ Footnotes ]-\n\n[1] Whether a frame is considered to originate in a certain module is\n determined by the ``__name__`` in the frame globals.\n', - 'del': '\nThe ``del`` statement\n*********************\n\n del_stmt ::= "del" target_list\n\nDeletion is recursively defined very similar to the way assignment is\ndefined. Rather than spelling it out in full details, here are some\nhints.\n\nDeletion of a target list recursively deletes each target, from left\nto right.\n\nDeletion of a name removes the binding of that name from the local or\nglobal namespace, depending on whether the name occurs in a ``global``\nstatement in the same code block. If the name is unbound, a\n``NameError`` exception will be raised.\n\nDeletion of attribute references, subscriptions and slicings is passed\nto the primary object involved; deletion of a slicing is in general\nequivalent to assignment of an empty slice of the right type (but even\nthis is determined by the sliced object).\n\nChanged in version 3.2: Previously it was illegal to delete a name\nfrom the local namespace if it occurs as a free variable in a nested\nblock.\n', + 'attribute-access': '\nCustomizing attribute access\n****************************\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of "x.name") for\nclass instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for "self"). "name" is the attribute name. This\n method should return the (computed) attribute value or raise an\n "AttributeError" exception.\n\n Note that if the attribute is found through the normal mechanism,\n "__getattr__()" is not called. (This is an intentional asymmetry\n between "__getattr__()" and "__setattr__()".) This is done both for\n efficiency reasons and because otherwise "__getattr__()" would have\n no way to access other attributes of the instance. Note that at\n least for instance variables, you can fake total control by not\n inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n "__getattribute__()" method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines "__getattr__()",\n the latter will not be called unless "__getattribute__()" either\n calls it explicitly or raises an "AttributeError". This method\n should return the (computed) attribute value or raise an\n "AttributeError" exception. In order to avoid infinite recursion in\n this method, its implementation should always call the base class\n method with the same name to access any attributes it needs, for\n example, "object.__getattribute__(self, name)".\n\n Note: This method may still be bypassed when looking up special\n methods as the result of implicit invocation via language syntax\n or built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If "__setattr__()" wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n "object.__setattr__(self, name, value)".\n\nobject.__delattr__(self, name)\n\n Like "__setattr__()" but for attribute deletion instead of\n assignment. This should only be implemented if "del obj.name" is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when "dir()" is called on the object. A sequence must be\n returned. "dir()" converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n========================\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' "__dict__".\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or "None" when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an "AttributeError"\n exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n====================\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: "__get__()", "__set__()", and\n"__delete__()". If any of those methods are defined for an object, it\nis said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, "a.x" has a\nlookup chain starting with "a.__dict__[\'x\']", then\n"type(a).__dict__[\'x\']", and continuing through the base classes of\n"type(a)" excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, "a.x". How\nthe arguments are assembled depends on "a":\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: "x.__get__(a)".\n\nInstance Binding\n If binding to an object instance, "a.x" is transformed into the\n call: "type(a).__dict__[\'x\'].__get__(a, type(a))".\n\nClass Binding\n If binding to a class, "A.x" is transformed into the call:\n "A.__dict__[\'x\'].__get__(None, A)".\n\nSuper Binding\n If "a" is an instance of "super", then the binding "super(B,\n obj).m()" searches "obj.__class__.__mro__" for the base class "A"\n immediately preceding "B" and then invokes the descriptor with the\n call: "A.__dict__[\'m\'].__get__(obj, obj.__class__)".\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of "__get__()", "__set__()" and "__delete__()". If it\ndoes not define "__get__()", then accessing the attribute will return\nthe descriptor object itself unless there is a value in the object\'s\ninstance dictionary. If the descriptor defines "__set__()" and/or\n"__delete__()", it is a data descriptor; if it defines neither, it is\na non-data descriptor. Normally, data descriptors define both\n"__get__()" and "__set__()", while non-data descriptors have just the\n"__get__()" method. Data descriptors with "__set__()" and "__get__()"\ndefined always override a redefinition in an instance dictionary. In\ncontrast, non-data descriptors can be overridden by instances.\n\nPython methods (including "staticmethod()" and "classmethod()") are\nimplemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe "property()" function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n=========\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n--------------------------\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises "AttributeError". If\n dynamic assignment of new variables is desired, then add\n "\'__dict__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes\n defining *__slots__* do not support weak references to its\n instances. If weak reference support is needed, then add\n "\'__weakref__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the\n instance variable defined by the base class slot is inaccessible\n (except by retrieving its descriptor directly from the base class).\n This renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as "int", "bytes" and "tuple".\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings\n may also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n', + 'attribute-references': '\nAttribute references\n********************\n\nAn attribute reference is a primary followed by a period and a name:\n\n attributeref ::= primary "." identifier\n\nThe primary must evaluate to an object of a type that supports\nattribute references, which most objects do. This object is then\nasked to produce the attribute whose name is the identifier (which can\nbe customized by overriding the "__getattr__()" method). If this\nattribute is not available, the exception "AttributeError" is raised.\nOtherwise, the type and value of the object produced is determined by\nthe object. Multiple evaluations of the same attribute reference may\nyield different objects.\n', + 'augassign': '\nAugmented assignment statements\n*******************************\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like "x += 1" can be rewritten as\n"x = x + 1" to achieve a similar, but not exactly equal effect. In the\naugmented version, "x" is only evaluated once. Also, when possible,\nthe actual operation is performed *in-place*, meaning that rather than\ncreating a new object and assigning that to the target, the old object\nis modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', + 'binary': '\nBinary arithmetic operations\n****************************\n\nThe binary arithmetic operations have the conventional priority\nlevels. Note that some of these operations also apply to certain non-\nnumeric types. Apart from the power operator, there are only two\nlevels, one for multiplicative operators and one for additive\noperators:\n\n m_expr ::= u_expr | m_expr "*" u_expr | m_expr "//" u_expr | m_expr "/" u_expr\n | m_expr "%" u_expr\n a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr\n\nThe "*" (multiplication) operator yields the product of its arguments.\nThe arguments must either both be numbers, or one argument must be an\ninteger and the other must be a sequence. In the former case, the\nnumbers are converted to a common type and then multiplied together.\nIn the latter case, sequence repetition is performed; a negative\nrepetition factor yields an empty sequence.\n\nThe "/" (division) and "//" (floor division) operators yield the\nquotient of their arguments. The numeric arguments are first\nconverted to a common type. Division of integers yields a float, while\nfloor division of integers results in an integer; the result is that\nof mathematical division with the \'floor\' function applied to the\nresult. Division by zero raises the "ZeroDivisionError" exception.\n\nThe "%" (modulo) operator yields the remainder from the division of\nthe first argument by the second. The numeric arguments are first\nconverted to a common type. A zero right argument raises the\n"ZeroDivisionError" exception. The arguments may be floating point\nnumbers, e.g., "3.14%0.7" equals "0.34" (since "3.14" equals "4*0.7 +\n0.34".) The modulo operator always yields a result with the same sign\nas its second operand (or zero); the absolute value of the result is\nstrictly smaller than the absolute value of the second operand [1].\n\nThe floor division and modulo operators are connected by the following\nidentity: "x == (x//y)*y + (x%y)". Floor division and modulo are also\nconnected with the built-in function "divmod()": "divmod(x, y) ==\n(x//y, x%y)". [2].\n\nIn addition to performing the modulo operation on numbers, the "%"\noperator is also overloaded by string objects to perform old-style\nstring formatting (also known as interpolation). The syntax for\nstring formatting is described in the Python Library Reference,\nsection *printf-style String Formatting*.\n\nThe floor division operator, the modulo operator, and the "divmod()"\nfunction are not defined for complex numbers. Instead, convert to a\nfloating point number using the "abs()" function if appropriate.\n\nThe "+" (addition) operator yields the sum of its arguments. The\narguments must either both be numbers or both sequences of the same\ntype. In the former case, the numbers are converted to a common type\nand then added together. In the latter case, the sequences are\nconcatenated.\n\nThe "-" (subtraction) operator yields the difference of its arguments.\nThe numeric arguments are first converted to a common type.\n', + 'bitwise': '\nBinary bitwise operations\n*************************\n\nEach of the three bitwise operations has a different priority level:\n\n and_expr ::= shift_expr | and_expr "&" shift_expr\n xor_expr ::= and_expr | xor_expr "^" and_expr\n or_expr ::= xor_expr | or_expr "|" xor_expr\n\nThe "&" operator yields the bitwise AND of its arguments, which must\nbe integers.\n\nThe "^" operator yields the bitwise XOR (exclusive OR) of its\narguments, which must be integers.\n\nThe "|" operator yields the bitwise (inclusive) OR of its arguments,\nwhich must be integers.\n', + 'bltin-code-objects': '\nCode Objects\n************\n\nCode objects are used by the implementation to represent "pseudo-\ncompiled" executable Python code such as a function body. They differ\nfrom function objects because they don\'t contain a reference to their\nglobal execution environment. Code objects are returned by the built-\nin "compile()" function and can be extracted from function objects\nthrough their "__code__" attribute. See also the "code" module.\n\nA code object can be executed or evaluated by passing it (instead of a\nsource string) to the "exec()" or "eval()" built-in functions.\n\nSee *The standard type hierarchy* for more information.\n', + 'bltin-ellipsis-object': '\nThe Ellipsis Object\n*******************\n\nThis object is commonly used by slicing (see *Slicings*). It supports\nno special operations. There is exactly one ellipsis object, named\n"Ellipsis" (a built-in name). "type(Ellipsis)()" produces the\n"Ellipsis" singleton.\n\nIt is written as "Ellipsis" or "...".\n', + 'bltin-null-object': '\nThe Null Object\n***************\n\nThis object is returned by functions that don\'t explicitly return a\nvalue. It supports no special operations. There is exactly one null\nobject, named "None" (a built-in name). "type(None)()" produces the\nsame singleton.\n\nIt is written as "None".\n', + 'bltin-type-objects': '\nType Objects\n************\n\nType objects represent the various object types. An object\'s type is\naccessed by the built-in function "type()". There are no special\noperations on types. The standard module "types" defines names for\nall standard built-in types.\n\nTypes are written like this: "".\n', + 'booleans': '\nBoolean operations\n******************\n\n or_test ::= and_test | or_test "or" and_test\n and_test ::= not_test | and_test "and" not_test\n not_test ::= comparison | "not" not_test\n\nIn the context of Boolean operations, and also when expressions are\nused by control flow statements, the following values are interpreted\nas false: "False", "None", numeric zero of all types, and empty\nstrings and containers (including strings, tuples, lists,\ndictionaries, sets and frozensets). All other values are interpreted\nas true. User-defined objects can customize their truth value by\nproviding a "__bool__()" method.\n\nThe operator "not" yields "True" if its argument is false, "False"\notherwise.\n\nThe expression "x and y" first evaluates *x*; if *x* is false, its\nvalue is returned; otherwise, *y* is evaluated and the resulting value\nis returned.\n\nThe expression "x or y" first evaluates *x*; if *x* is true, its value\nis returned; otherwise, *y* is evaluated and the resulting value is\nreturned.\n\n(Note that neither "and" nor "or" restrict the value and type they\nreturn to "False" and "True", but rather return the last evaluated\nargument. This is sometimes useful, e.g., if "s" is a string that\nshould be replaced by a default value if it is empty, the expression\n"s or \'foo\'" yields the desired value. Because "not" has to invent a\nvalue anyway, it does not bother to return a value of the same type as\nits argument, so e.g., "not \'foo\'" yields "False", not "\'\'".)\n', + 'break': '\nThe "break" statement\n*********************\n\n break_stmt ::= "break"\n\n"break" may only occur syntactically nested in a "for" or "while"\nloop, but not nested in a function or class definition within that\nloop.\n\nIt terminates the nearest enclosing loop, skipping the optional "else"\nclause if the loop has one.\n\nIf a "for" loop is terminated by "break", the loop control target\nkeeps its current value.\n\nWhen "break" passes control out of a "try" statement with a "finally"\nclause, that "finally" clause is executed before really leaving the\nloop.\n', + 'callable-types': '\nEmulating callable objects\n**************************\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, "x(arg1, arg2, ...)" is a shorthand for\n "x.__call__(arg1, arg2, ...)".\n', + 'calls': '\nCalls\n*****\n\nA call calls a callable object (e.g., a *function*) with a possibly\nempty series of *arguments*:\n\n call ::= primary "(" [argument_list [","] | comprehension] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," keyword_arguments] ["," "**" expression]\n | "*" expression ["," keyword_arguments] ["," "**" expression]\n | "**" expression\n positional_arguments ::= expression ("," expression)*\n keyword_arguments ::= keyword_item ("," keyword_item)*\n keyword_item ::= identifier "=" expression\n\nA trailing comma may be present after the positional and keyword\narguments but does not affect the semantics.\n\nThe primary must evaluate to a callable object (user-defined\nfunctions, built-in functions, methods of built-in objects, class\nobjects, methods of class instances, and all objects having a\n"__call__()" method are callable). All argument expressions are\nevaluated before the call is attempted. Please refer to section\n*Function definitions* for the syntax of formal *parameter* lists.\n\nIf keyword arguments are present, they are first converted to\npositional arguments, as follows. First, a list of unfilled slots is\ncreated for the formal parameters. If there are N positional\narguments, they are placed in the first N slots. Next, for each\nkeyword argument, the identifier is used to determine the\ncorresponding slot (if the identifier is the same as the first formal\nparameter name, the first slot is used, and so on). If the slot is\nalready filled, a "TypeError" exception is raised. Otherwise, the\nvalue of the argument is placed in the slot, filling it (even if the\nexpression is "None", it fills the slot). When all arguments have\nbeen processed, the slots that are still unfilled are filled with the\ncorresponding default value from the function definition. (Default\nvalues are calculated, once, when the function is defined; thus, a\nmutable object such as a list or dictionary used as default value will\nbe shared by all calls that don\'t specify an argument value for the\ncorresponding slot; this should usually be avoided.) If there are any\nunfilled slots for which no default value is specified, a "TypeError"\nexception is raised. Otherwise, the list of filled slots is used as\nthe argument list for the call.\n\n**CPython implementation detail:** An implementation may provide\nbuilt-in functions whose positional parameters do not have names, even\nif they are \'named\' for the purpose of documentation, and which\ntherefore cannot be supplied by keyword. In CPython, this is the case\nfor functions implemented in C that use "PyArg_ParseTuple()" to parse\ntheir arguments.\n\nIf there are more positional arguments than there are formal parameter\nslots, a "TypeError" exception is raised, unless a formal parameter\nusing the syntax "*identifier" is present; in this case, that formal\nparameter receives a tuple containing the excess positional arguments\n(or an empty tuple if there were no excess positional arguments).\n\nIf any keyword argument does not correspond to a formal parameter\nname, a "TypeError" exception is raised, unless a formal parameter\nusing the syntax "**identifier" is present; in this case, that formal\nparameter receives a dictionary containing the excess keyword\narguments (using the keywords as keys and the argument values as\ncorresponding values), or a (new) empty dictionary if there were no\nexcess keyword arguments.\n\nIf the syntax "*expression" appears in the function call, "expression"\nmust evaluate to an iterable. Elements from this iterable are treated\nas if they were additional positional arguments; if there are\npositional arguments *x1*, ..., *xN*, and "expression" evaluates to a\nsequence *y1*, ..., *yM*, this is equivalent to a call with M+N\npositional arguments *x1*, ..., *xN*, *y1*, ..., *yM*.\n\nA consequence of this is that although the "*expression" syntax may\nappear *after* some keyword arguments, it is processed *before* the\nkeyword arguments (and the "**expression" argument, if any -- see\nbelow). So:\n\n >>> def f(a, b):\n ... print(a, b)\n ...\n >>> f(b=1, *(2,))\n 2 1\n >>> f(a=1, *(2,))\n Traceback (most recent call last):\n File "", line 1, in ?\n TypeError: f() got multiple values for keyword argument \'a\'\n >>> f(1, *(2,))\n 1 2\n\nIt is unusual for both keyword arguments and the "*expression" syntax\nto be used in the same call, so in practice this confusion does not\narise.\n\nIf the syntax "**expression" appears in the function call,\n"expression" must evaluate to a mapping, the contents of which are\ntreated as additional keyword arguments. In the case of a keyword\nappearing in both "expression" and as an explicit keyword argument, a\n"TypeError" exception is raised.\n\nFormal parameters using the syntax "*identifier" or "**identifier"\ncannot be used as positional argument slots or as keyword argument\nnames.\n\nA call always returns some value, possibly "None", unless it raises an\nexception. How this value is computed depends on the type of the\ncallable object.\n\nIf it is---\n\na user-defined function:\n The code block for the function is executed, passing it the\n argument list. The first thing the code block will do is bind the\n formal parameters to the arguments; this is described in section\n *Function definitions*. When the code block executes a "return"\n statement, this specifies the return value of the function call.\n\na built-in function or method:\n The result is up to the interpreter; see *Built-in Functions* for\n the descriptions of built-in functions and methods.\n\na class object:\n A new instance of that class is returned.\n\na class instance method:\n The corresponding user-defined function is called, with an argument\n list that is one longer than the argument list of the call: the\n instance becomes the first argument.\n\na class instance:\n The class must define a "__call__()" method; the effect is then the\n same as if that method was called.\n', + 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [parameter_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class "object"; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with "self.name = value". Both class and\ninstance attributes are accessible through the notation ""self.name"",\nand an instance attribute hides a class attribute with the same name\nwhen accessed in this way. Class attributes can be used as defaults\nfor instance attributes, but using mutable values there can lead to\nunexpected results. *Descriptors* can be used to create instance\nvariables with different implementation details.\n\nSee also: **PEP 3115** - Metaclasses in Python 3 **PEP 3129** -\n Class Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless\n there is a "finally" clause which happens to raise another\n exception. That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of\n an exception or the execution of a "return", "continue", or\n "break" statement.\n\n[3] A string literal appearing as the first statement in the\n function body is transformed into the function\'s "__doc__"\n attribute and therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s "__doc__" item and\n therefore the class\'s *docstring*.\n', + 'comparisons': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like "a < b < c" have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: "True" or "False".\n\nComparisons can be chained arbitrarily, e.g., "x < y <= z" is\nequivalent to "x < y and y <= z", except that "y" is evaluated only\nonce (but in both cases "z" is not evaluated at all when "x < y" is\nfound to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then "a op1 b op2 c ... y\nopN z" is equivalent to "a op1 b and b op2 c and ... y opN z", except\nthat each expression is evaluated at most once.\n\nNote that "a op1 b op2 c" doesn\'t imply any kind of comparison between\n*a* and *c*, so that, e.g., "x < y > z" is perfectly legal (though\nperhaps not pretty).\n\nThe operators "<", ">", "==", ">=", "<=", and "!=" compare the values\nof two objects. The objects need not have the same type. If both are\nnumbers, they are converted to a common type. Otherwise, the "==" and\n"!=" operators *always* consider objects of different types to be\nunequal, while the "<", ">", ">=" and "<=" operators raise a\n"TypeError" when comparing objects of different types that do not\nimplement these operators for the given pair of types. You can\ncontrol comparison behavior of objects of non-built-in types by\ndefining rich comparison methods like "__gt__()", described in section\n*Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values "float(\'NaN\')" and "Decimal(\'NaN\')" are special. The\n are identical to themselves, "x is x" but are not equal to\n themselves, "x != x". Additionally, comparing any value to a\n not-a-number value will return "False". For example, both "3 <\n float(\'NaN\')" and "float(\'NaN\') < 3" will return "False".\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric\n equivalents (the result of the built-in function "ord()") of their\n characters. [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison\n of corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, "[1,2,x] <= [1,2,y]" has the same\n value as "x <= y". If the corresponding element does not exist, the\n shorter sequence is ordered first (for example, "[1,2] < [1,2,3]").\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same "(key, value)" pairs. Order comparisons "(\'<\', \'<=\', \'>=\',\n \'>\')" raise "TypeError".\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets "{1,2}" and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, "min()", "max()", and "sorted()" produce undefined\n results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they\n are the same object; the choice whether one object is considered\n smaller or larger than another one is made arbitrarily but\n consistently within one execution of a program.\n\nComparison of objects of the differing types depends on whether either\nof the types provide explicit support for the comparison. Most\nnumeric types can be compared with one another. When cross-type\ncomparison is not supported, the comparison method returns\n"NotImplemented".\n\nThe operators "in" and "not in" test for membership. "x in s"\nevaluates to true if *x* is a member of *s*, and false otherwise. "x\nnot in s" returns the negation of "x in s". All built-in sequences\nand set types support this as well as dictionary, for which "in" tests\nwhether a the dictionary has a given key. For container types such as\nlist, tuple, set, frozenset, dict, or collections.deque, the\nexpression "x in y" is equivalent to "any(x is e or x == e for e in\ny)".\n\nFor the string and bytes types, "x in y" is true if and only if *x* is\na substring of *y*. An equivalent test is "y.find(x) != -1". Empty\nstrings are always considered to be a substring of any other string,\nso """ in "abc"" will return "True".\n\nFor user-defined classes which define the "__contains__()" method, "x\nin y" is true if and only if "y.__contains__(x)" is true.\n\nFor user-defined classes which do not define "__contains__()" but do\ndefine "__iter__()", "x in y" is true if some value "z" with "x == z"\nis produced while iterating over "y". If an exception is raised\nduring the iteration, it is as if "in" raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n"__getitem__()", "x in y" is true if and only if there is a non-\nnegative integer index *i* such that "x == y[i]", and all lower\ninteger indices do not raise "IndexError" exception. (If any other\nexception is raised, it is as if "in" raised that exception).\n\nThe operator "not in" is defined to have the inverse true value of\n"in".\n\nThe operators "is" and "is not" test for object identity: "x is y" is\ntrue if and only if *x* and *y* are the same object. "x is not y"\nyields the inverse truth value. [4]\n', + 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe "if", "while" and "for" statements implement traditional control\nflow constructs. "try" specifies exception handlers and/or cleanup\ncode for a group of statements, while the "with" statement allows the\nexecution of initialization and finalization code around a block of\ncode. Function and class definitions are also syntactically compound\nstatements.\n\nCompound statements consist of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which "if" clause a following "else" clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n"print()" calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a "NEWLINE" possibly followed by a\n"DEDENT". Also note that optional continuation clauses always begin\nwith a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling "else"\' problem is solved in Python by\nrequiring nested "if" statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe "if" statement\n==================\n\nThe "if" statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the "if" statement is executed or evaluated).\nIf all expressions are false, the suite of the "else" clause, if\npresent, is executed.\n\n\nThe "while" statement\n=====================\n\nThe "while" statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the "else" clause, if present, is executed\nand the loop terminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and goes back\nto testing the expression.\n\n\nThe "for" statement\n===================\n\nThe "for" statement is used to iterate over the elements of a sequence\n(such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n"expression_list". The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a "StopIteration" exception),\nthe suite in the "else" clause, if present, is executed, and the loop\nterminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and continues\nwith the next item, or with the "else" clause if there was no next\nitem.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function "range()" returns an\niterator of integers suitable to emulate the effect of Pascal\'s "for i\n:= a to b do"; e.g., "list(range(3))" returns the list "[0, 1, 2]".\n\nNote: There is a subtlety when the sequence is being modified by the\n loop (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe "try" statement\n===================\n\nThe "try" statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe "except" clause(s) specify one or more exception handlers. When no\nexception occurs in the "try" clause, no exception handler is\nexecuted. When an exception occurs in the "try" suite, a search for an\nexception handler is started. This search inspects the except clauses\nin turn until one is found that matches the exception. An expression-\nless except clause, if present, must be last; it matches any\nexception. For an except clause with an expression, that expression\nis evaluated, and the clause matches the exception if the resulting\nobject is "compatible" with the exception. An object is compatible\nwith an exception if it is the class or a base class of the exception\nobject or a tuple containing an item compatible with the exception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire "try" statement raised\nthe exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the "as" keyword in that except clause, if\npresent, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using "as target", it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the "sys" module and can be access via\n"sys.exc_info()". "sys.exc_info()" returns a 3-tuple consisting of the\nexception class, the exception instance and a traceback object (see\nsection *The standard type hierarchy*) identifying the point in the\nprogram where the exception occurred. "sys.exc_info()" values are\nrestored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional "else" clause is executed if and when control flows off\nthe end of the "try" clause. [2] Exceptions in the "else" clause are\nnot handled by the preceding "except" clauses.\n\nIf "finally" is present, it specifies a \'cleanup\' handler. The "try"\nclause is executed, including any "except" and "else" clauses. If an\nexception occurs in any of the clauses and is not handled, the\nexception is temporarily saved. The "finally" clause is executed. If\nthere is a saved exception it is re-raised at the end of the "finally"\nclause. If the "finally" clause raises another exception, the saved\nexception is set as the context of the new exception. If the "finally"\nclause executes a "return" or "break" statement, the saved exception\nis discarded:\n\n def f():\n try:\n 1/0\n finally:\n return 42\n\n >>> f()\n 42\n\nThe exception information is not available to the program during\nexecution of the "finally" clause.\n\nWhen a "return", "break" or "continue" statement is executed in the\n"try" suite of a "try"..."finally" statement, the "finally" clause is\nalso executed \'on the way out.\' A "continue" statement is illegal in\nthe "finally" clause. (The reason is a problem with the current\nimplementation --- this restriction may be lifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the "raise" statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe "with" statement\n====================\n\nThe "with" statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common "try"..."except"..."finally"\nusage patterns to be encapsulated for convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the "with" statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the "with_item")\n is evaluated to obtain a context manager.\n\n2. The context manager\'s "__exit__()" is loaded for later use.\n\n3. The context manager\'s "__enter__()" method is invoked.\n\n4. If a target was included in the "with" statement, the return\n value from "__enter__()" is assigned to it.\n\n Note: The "with" statement guarantees that if the "__enter__()"\n method returns without an error, then "__exit__()" will always be\n called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s "__exit__()" method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to "__exit__()". Otherwise, three\n "None" arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the "__exit__()" method was false, the exception is reraised.\n If the return value was true, the exception is suppressed, and\n execution continues with the statement following the "with"\n statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from "__exit__()" is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple "with" statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)* ["," "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more *parameters* have the form *parameter* "="\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding *argument* may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the ""*"" must also have a default value --- this\nis a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated from left to right when the\nfunction definition is executed.** This means that the expression is\nevaluated once, when the function is defined, and that the same "pre-\ncomputed" value is used for each call. This is especially important\nto understand when a default parameter is a mutable object, such as a\nlist or a dictionary: if the function modifies the object (e.g. by\nappending an item to a list), the default value is in effect modified.\nThis is generally not what was intended. A way around this is to use\n"None" as the default, and explicitly test for it in the body of the\nfunction, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n""*identifier"" is present, it is initialized to a tuple receiving any\nexcess positional parameters, defaulting to the empty tuple. If the\nform ""**identifier"" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after ""*"" or ""*identifier"" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "": expression"" following\nthe parameter name. Any parameter may have an annotation even those\nof the form "*identifier" or "**identifier". Functions may have\n"return" annotation of the form ""-> expression"" after the parameter\nlist. These annotations can be any valid Python expression and are\nevaluated when the function definition is executed. Annotations may\nbe evaluated in a different order than they appear in the source code.\nThe presence of annotations does not change the semantics of a\nfunction. The annotation values are available as values of a\ndictionary keyed by the parameters\' names in the "__annotations__"\nattribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda\nexpressions, described in section *Lambdas*. Note that the lambda\nexpression is merely a shorthand for a simplified function definition;\na function defined in a ""def"" statement can be passed around or\nassigned to another name just like a function defined by a lambda\nexpression. The ""def"" form is actually more powerful since it\nallows the execution of multiple statements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A ""def""\nstatement executed inside a function definition defines a local\nfunction that can be returned or passed around. Free variables used\nin the nested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\nSee also: **PEP 3107** - Function Annotations\n\n The original specification for function annotations.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [parameter_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class "object"; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with "self.name = value". Both class and\ninstance attributes are accessible through the notation ""self.name"",\nand an instance attribute hides a class attribute with the same name\nwhen accessed in this way. Class attributes can be used as defaults\nfor instance attributes, but using mutable values there can lead to\nunexpected results. *Descriptors* can be used to create instance\nvariables with different implementation details.\n\nSee also: **PEP 3115** - Metaclasses in Python 3 **PEP 3129** -\n Class Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack unless\n there is a "finally" clause which happens to raise another\n exception. That new exception causes the old one to be lost.\n\n[2] Currently, control "flows off the end" except in the case of\n an exception or the execution of a "return", "continue", or\n "break" statement.\n\n[3] A string literal appearing as the first statement in the\n function body is transformed into the function\'s "__doc__"\n attribute and therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s "__doc__" item and\n therefore the class\'s *docstring*.\n', + 'context-managers': '\nWith Statement Context Managers\n*******************************\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a "with" statement. The context manager\nhandles the entry into, and the exit from, the desired runtime context\nfor the execution of the block of code. Context managers are normally\ninvoked using the "with" statement (described in section *The with\nstatement*), but can also be used by directly invoking their methods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The "with"\n statement will bind this method\'s return value to the target(s)\n specified in the "as" clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be "None".\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that "__exit__()" methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n', + 'continue': '\nThe "continue" statement\n************************\n\n continue_stmt ::= "continue"\n\n"continue" may only occur syntactically nested in a "for" or "while"\nloop, but not nested in a function or class definition or "finally"\nclause within that loop. It continues with the next cycle of the\nnearest enclosing loop.\n\nWhen "continue" passes control out of a "try" statement with a\n"finally" clause, that "finally" clause is executed before really\nstarting the next loop cycle.\n', + 'conversions': '\nArithmetic conversions\n**********************\n\nWhen a description of an arithmetic operator below uses the phrase\n"the numeric arguments are converted to a common type," this means\nthat the operator implementation for built-in types works that way:\n\n* If either argument is a complex number, the other is converted to\n complex;\n\n* otherwise, if either argument is a floating point number, the\n other is converted to floating point;\n\n* otherwise, both must be integers and no conversion is necessary.\n\nSome additional rules apply for certain operators (e.g., a string left\nargument to the \'%\' operator). Extensions must define their own\nconversion behavior.\n', + 'customization': '\nBasic customization\n*******************\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. "__new__()" is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of "__new__()" should be the new object instance (usually an\n instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s "__new__()" method using\n "super(currentclass, cls).__new__(cls[, ...])" with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If "__new__()" returns an instance of *cls*, then the new\n instance\'s "__init__()" method will be invoked like\n "__init__(self[, ...])", where *self* is the new instance and the\n remaining arguments are the same as were passed to "__new__()".\n\n If "__new__()" does not return an instance of *cls*, then the new\n instance\'s "__init__()" method will not be invoked.\n\n "__new__()" is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n "__init__()" method, the derived class\'s "__init__()" method, if\n any, must explicitly call it to ensure proper initialization of the\n base class part of the instance; for example:\n "BaseClass.__init__(self, [args...])". As a special constraint on\n constructors, no value may be returned; doing so will cause a\n "TypeError" to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a "__del__()" method, the\n derived class\'s "__del__()" method, if any, must explicitly call it\n to ensure proper deletion of the base class part of the instance.\n Note that it is possible (though not recommended!) for the\n "__del__()" method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n "__del__()" methods are called for objects that still exist when\n the interpreter exits.\n\n Note: "del x" doesn\'t directly call "x.__del__()" --- the former\n decrements the reference count for "x" by one, and the latter is\n only called when "x"\'s reference count reaches zero. Some common\n situations that may prevent the reference count of an object from\n going to zero include: circular references between objects (e.g.,\n a doubly-linked list or a tree data structure with parent and\n child pointers); a reference to the object on the stack frame of\n a function that caught an exception (the traceback stored in\n "sys.exc_info()[2]" keeps the stack frame alive); or a reference\n to the object on the stack frame that raised an unhandled\n exception in interactive mode (the traceback stored in\n "sys.last_traceback" keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing "None" in\n "sys.last_traceback". Circular references which are garbage are\n detected and cleaned up when the cyclic garbage collector is\n enabled (it\'s on by default). Refer to the documentation for the\n "gc" module for more information about this topic.\n\n Warning: Due to the precarious circumstances under which\n "__del__()" methods are invoked, exceptions that occur during\n their execution are ignored, and a warning is printed to\n "sys.stderr" instead. Also, when "__del__()" is invoked in\n response to a module being deleted (e.g., when execution of the\n program is done), other globals referenced by the "__del__()"\n method may already have been deleted or in the process of being\n torn down (e.g. the import machinery shutting down). For this\n reason, "__del__()" methods should do the absolute minimum needed\n to maintain external invariants. Starting with version 1.5,\n Python guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the "__del__()" method is called.\n\nobject.__repr__(self)\n\n Called by the "repr()" built-in function to compute the "official"\n string representation of an object. If at all possible, this\n should look like a valid Python expression that could be used to\n recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n "<...some useful description...>" should be returned. The return\n value must be a string object. If a class defines "__repr__()" but\n not "__str__()", then "__repr__()" is also used when an "informal"\n string representation of instances of that class is required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by "str(object)" and the built-in functions "format()" and\n "print()" to compute the "informal" or nicely printable string\n representation of an object. The return value must be a *string*\n object.\n\n This method differs from "object.__repr__()" in that there is no\n expectation that "__str__()" return a valid Python expression: a\n more convenient or concise representation can be used.\n\n The default implementation defined by the built-in type "object"\n calls "object.__repr__()".\n\nobject.__bytes__(self)\n\n Called by "bytes()" to compute a byte-string representation of an\n object. This should return a "bytes" object.\n\nobject.__format__(self, format_spec)\n\n Called by the "format()" built-in function (and by extension, the\n "str.format()" method of class "str") to produce a "formatted"\n string representation of an object. The "format_spec" argument is a\n string that contains a description of the formatting options\n desired. The interpretation of the "format_spec" argument is up to\n the type implementing "__format__()", however most classes will\n either delegate formatting to one of the built-in types, or use a\n similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: "xy" calls\n "x.__gt__(y)", and "x>=y" calls "x.__ge__(y)".\n\n A rich comparison method may return the singleton "NotImplemented"\n if it does not implement the operation for a given pair of\n arguments. By convention, "False" and "True" are returned for a\n successful comparison. However, these methods can return any value,\n so if the comparison operator is used in a Boolean context (e.g.,\n in the condition of an "if" statement), Python will call "bool()"\n on the value to determine if the result is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of "x==y" does not imply that "x!=y" is false.\n Accordingly, when defining "__eq__()", one should also define\n "__ne__()" so that the operators will behave as expected. See the\n paragraph on "__hash__()" for some important notes on creating\n *hashable* objects which support custom comparison operations and\n are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, "__lt__()" and "__gt__()" are each other\'s\n reflection, "__le__()" and "__ge__()" are each other\'s reflection,\n and "__eq__()" and "__ne__()" are their own reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see "functools.total_ordering()".\n\nobject.__hash__(self)\n\n Called by built-in function "hash()" and for operations on members\n of hashed collections including "set", "frozenset", and "dict".\n "__hash__()" should return an integer. The only required property\n is that objects which compare equal have the same hash value; it is\n advised to somehow mix together (e.g. using exclusive or) the hash\n values for the components of the object that also play a part in\n comparison of objects.\n\n Note: "hash()" truncates the value returned from an object\'s\n custom "__hash__()" method to the size of a "Py_ssize_t". This\n is typically 8 bytes on 64-bit builds and 4 bytes on 32-bit\n builds. If an object\'s "__hash__()" must interoperate on builds\n of different bit sizes, be sure to check the width on all\n supported builds. An easy way to do this is with "python -c\n "import sys; print(sys.hash_info.width)""\n\n If a class does not define an "__eq__()" method it should not\n define a "__hash__()" operation either; if it defines "__eq__()"\n but not "__hash__()", its instances will not be usable as items in\n hashable collections. If a class defines mutable objects and\n implements an "__eq__()" method, it should not implement\n "__hash__()", since the implementation of hashable collections\n requires that a key\'s hash value is immutable (if the object\'s hash\n value changes, it will be in the wrong hash bucket).\n\n User-defined classes have "__eq__()" and "__hash__()" methods by\n default; with them, all objects compare unequal (except with\n themselves) and "x.__hash__()" returns an appropriate value such\n that "x == y" implies both that "x is y" and "hash(x) == hash(y)".\n\n A class that overrides "__eq__()" and does not define "__hash__()"\n will have its "__hash__()" implicitly set to "None". When the\n "__hash__()" method of a class is "None", instances of the class\n will raise an appropriate "TypeError" when a program attempts to\n retrieve their hash value, and will also be correctly identified as\n unhashable when checking "isinstance(obj, collections.Hashable").\n\n If a class that overrides "__eq__()" needs to retain the\n implementation of "__hash__()" from a parent class, the interpreter\n must be told this explicitly by setting "__hash__ =\n .__hash__".\n\n If a class that does not override "__eq__()" wishes to suppress\n hash support, it should include "__hash__ = None" in the class\n definition. A class which defines its own "__hash__()" that\n explicitly raises a "TypeError" would be incorrectly identified as\n hashable by an "isinstance(obj, collections.Hashable)" call.\n\n Note: By default, the "__hash__()" values of str, bytes and\n datetime objects are "salted" with an unpredictable random value.\n Although they remain constant within an individual Python\n process, they are not predictable between repeated invocations of\n Python.This is intended to provide protection against a denial-\n of-service caused by carefully-chosen inputs that exploit the\n worst case performance of a dict insertion, O(n^2) complexity.\n See http://www.ocert.org/advisories/ocert-2011-003.html for\n details.Changing hash values affects the iteration order of\n dicts, sets and other mappings. Python has never made guarantees\n about this ordering (and it typically varies between 32-bit and\n 64-bit builds).See also "PYTHONHASHSEED".\n\n Changed in version 3.3: Hash randomization is enabled by default.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n "bool()"; should return "False" or "True". When this method is not\n defined, "__len__()" is called, if it is defined, and the object is\n considered true if its result is nonzero. If a class defines\n neither "__len__()" nor "__bool__()", all its instances are\n considered true.\n', + 'debugger': '\n"pdb" --- The Python Debugger\n*****************************\n\nThe module "pdb" defines an interactive source code debugger for\nPython programs. It supports setting (conditional) breakpoints and\nsingle stepping at the source line level, inspection of stack frames,\nsource code listing, and evaluation of arbitrary Python code in the\ncontext of any stack frame. It also supports post-mortem debugging\nand can be called under program control.\n\nThe debugger is extensible -- it is actually defined as the class\n"Pdb". This is currently undocumented but easily understood by reading\nthe source. The extension interface uses the modules "bdb" and "cmd".\n\nThe debugger\'s prompt is "(Pdb)". Typical usage to run a program under\ncontrol of the debugger is:\n\n >>> import pdb\n >>> import mymodule\n >>> pdb.run(\'mymodule.test()\')\n > (0)?()\n (Pdb) continue\n > (1)?()\n (Pdb) continue\n NameError: \'spam\'\n > (1)?()\n (Pdb)\n\nChanged in version 3.3: Tab-completion via the "readline" module is\navailable for commands and command arguments, e.g. the current global\nand local names are offered as arguments of the "p" command.\n\n"pdb.py" can also be invoked as a script to debug other scripts. For\nexample:\n\n python3 -m pdb myscript.py\n\nWhen invoked as a script, pdb will automatically enter post-mortem\ndebugging if the program being debugged exits abnormally. After post-\nmortem debugging (or after normal exit of the program), pdb will\nrestart the program. Automatic restarting preserves pdb\'s state (such\nas breakpoints) and in most cases is more useful than quitting the\ndebugger upon program\'s exit.\n\nNew in version 3.2: "pdb.py" now accepts a "-c" option that executes\ncommands as if given in a ".pdbrc" file, see *Debugger Commands*.\n\nThe typical usage to break into the debugger from a running program is\nto insert\n\n import pdb; pdb.set_trace()\n\nat the location you want to break into the debugger. You can then\nstep through the code following this statement, and continue running\nwithout the debugger using the "continue" command.\n\nThe typical usage to inspect a crashed program is:\n\n >>> import pdb\n >>> import mymodule\n >>> mymodule.test()\n Traceback (most recent call last):\n File "", line 1, in ?\n File "./mymodule.py", line 4, in test\n test2()\n File "./mymodule.py", line 3, in test2\n print(spam)\n NameError: spam\n >>> pdb.pm()\n > ./mymodule.py(3)test2()\n -> print(spam)\n (Pdb)\n\nThe module defines the following functions; each enters the debugger\nin a slightly different way:\n\npdb.run(statement, globals=None, locals=None)\n\n Execute the *statement* (given as a string or a code object) under\n debugger control. The debugger prompt appears before any code is\n executed; you can set breakpoints and type "continue", or you can\n step through the statement using "step" or "next" (all these\n commands are explained below). The optional *globals* and *locals*\n arguments specify the environment in which the code is executed; by\n default the dictionary of the module "__main__" is used. (See the\n explanation of the built-in "exec()" or "eval()" functions.)\n\npdb.runeval(expression, globals=None, locals=None)\n\n Evaluate the *expression* (given as a string or a code object)\n under debugger control. When "runeval()" returns, it returns the\n value of the expression. Otherwise this function is similar to\n "run()".\n\npdb.runcall(function, *args, **kwds)\n\n Call the *function* (a function or method object, not a string)\n with the given arguments. When "runcall()" returns, it returns\n whatever the function call returned. The debugger prompt appears\n as soon as the function is entered.\n\npdb.set_trace()\n\n Enter the debugger at the calling stack frame. This is useful to\n hard-code a breakpoint at a given point in a program, even if the\n code is not otherwise being debugged (e.g. when an assertion\n fails).\n\npdb.post_mortem(traceback=None)\n\n Enter post-mortem debugging of the given *traceback* object. If no\n *traceback* is given, it uses the one of the exception that is\n currently being handled (an exception must be being handled if the\n default is to be used).\n\npdb.pm()\n\n Enter post-mortem debugging of the traceback found in\n "sys.last_traceback".\n\nThe "run*" functions and "set_trace()" are aliases for instantiating\nthe "Pdb" class and calling the method of the same name. If you want\nto access further features, you have to do this yourself:\n\nclass class pdb.Pdb(completekey=\'tab\', stdin=None, stdout=None, skip=None, nosigint=False)\n\n "Pdb" is the debugger class.\n\n The *completekey*, *stdin* and *stdout* arguments are passed to the\n underlying "cmd.Cmd" class; see the description there.\n\n The *skip* argument, if given, must be an iterable of glob-style\n module name patterns. The debugger will not step into frames that\n originate in a module that matches one of these patterns. [1]\n\n By default, Pdb sets a handler for the SIGINT signal (which is sent\n when the user presses Ctrl-C on the console) when you give a\n "continue" command. This allows you to break into the debugger\n again by pressing Ctrl-C. If you want Pdb not to touch the SIGINT\n handler, set *nosigint* tot true.\n\n Example call to enable tracing with *skip*:\n\n import pdb; pdb.Pdb(skip=[\'django.*\']).set_trace()\n\n New in version 3.1: The *skip* argument.\n\n New in version 3.2: The *nosigint* argument. Previously, a SIGINT\n handler was never set by Pdb.\n\n run(statement, globals=None, locals=None)\n runeval(expression, globals=None, locals=None)\n runcall(function, *args, **kwds)\n set_trace()\n\n See the documentation for the functions explained above.\n\n\nDebugger Commands\n=================\n\nThe commands recognized by the debugger are listed below. Most\ncommands can be abbreviated to one or two letters as indicated; e.g.\n"h(elp)" means that either "h" or "help" can be used to enter the help\ncommand (but not "he" or "hel", nor "H" or "Help" or "HELP").\nArguments to commands must be separated by whitespace (spaces or\ntabs). Optional arguments are enclosed in square brackets ("[]") in\nthe command syntax; the square brackets must not be typed.\nAlternatives in the command syntax are separated by a vertical bar\n("|").\n\nEntering a blank line repeats the last command entered. Exception: if\nthe last command was a "list" command, the next 11 lines are listed.\n\nCommands that the debugger doesn\'t recognize are assumed to be Python\nstatements and are executed in the context of the program being\ndebugged. Python statements can also be prefixed with an exclamation\npoint ("!"). This is a powerful way to inspect the program being\ndebugged; it is even possible to change a variable or call a function.\nWhen an exception occurs in such a statement, the exception name is\nprinted but the debugger\'s state is not changed.\n\nThe debugger supports *aliases*. Aliases can have parameters which\nallows one a certain level of adaptability to the context under\nexamination.\n\nMultiple commands may be entered on a single line, separated by ";;".\n(A single ";" is not used as it is the separator for multiple commands\nin a line that is passed to the Python parser.) No intelligence is\napplied to separating the commands; the input is split at the first\n";;" pair, even if it is in the middle of a quoted string.\n\nIf a file ".pdbrc" exists in the user\'s home directory or in the\ncurrent directory, it is read in and executed as if it had been typed\nat the debugger prompt. This is particularly useful for aliases. If\nboth files exist, the one in the home directory is read first and\naliases defined there can be overridden by the local file.\n\nChanged in version 3.2: ".pdbrc" can now contain commands that\ncontinue debugging, such as "continue" or "next". Previously, these\ncommands had no effect.\n\nh(elp) [command]\n\n Without argument, print the list of available commands. With a\n *command* as argument, print help about that command. "help pdb"\n displays the full documentation (the docstring of the "pdb"\n module). Since the *command* argument must be an identifier, "help\n exec" must be entered to get help on the "!" command.\n\nw(here)\n\n Print a stack trace, with the most recent frame at the bottom. An\n arrow indicates the current frame, which determines the context of\n most commands.\n\nd(own) [count]\n\n Move the current frame *count* (default one) levels down in the\n stack trace (to a newer frame).\n\nu(p) [count]\n\n Move the current frame *count* (default one) levels up in the stack\n trace (to an older frame).\n\nb(reak) [([filename:]lineno | function) [, condition]]\n\n With a *lineno* argument, set a break there in the current file.\n With a *function* argument, set a break at the first executable\n statement within that function. The line number may be prefixed\n with a filename and a colon, to specify a breakpoint in another\n file (probably one that hasn\'t been loaded yet). The file is\n searched on "sys.path". Note that each breakpoint is assigned a\n number to which all the other breakpoint commands refer.\n\n If a second argument is present, it is an expression which must\n evaluate to true before the breakpoint is honored.\n\n Without argument, list all breaks, including for each breakpoint,\n the number of times that breakpoint has been hit, the current\n ignore count, and the associated condition if any.\n\ntbreak [([filename:]lineno | function) [, condition]]\n\n Temporary breakpoint, which is removed automatically when it is\n first hit. The arguments are the same as for "break".\n\ncl(ear) [filename:lineno | bpnumber [bpnumber ...]]\n\n With a *filename:lineno* argument, clear all the breakpoints at\n this line. With a space separated list of breakpoint numbers, clear\n those breakpoints. Without argument, clear all breaks (but first\n ask confirmation).\n\ndisable [bpnumber [bpnumber ...]]\n\n Disable the breakpoints given as a space separated list of\n breakpoint numbers. Disabling a breakpoint means it cannot cause\n the program to stop execution, but unlike clearing a breakpoint, it\n remains in the list of breakpoints and can be (re-)enabled.\n\nenable [bpnumber [bpnumber ...]]\n\n Enable the breakpoints specified.\n\nignore bpnumber [count]\n\n Set the ignore count for the given breakpoint number. If count is\n omitted, the ignore count is set to 0. A breakpoint becomes active\n when the ignore count is zero. When non-zero, the count is\n decremented each time the breakpoint is reached and the breakpoint\n is not disabled and any associated condition evaluates to true.\n\ncondition bpnumber [condition]\n\n Set a new *condition* for the breakpoint, an expression which must\n evaluate to true before the breakpoint is honored. If *condition*\n is absent, any existing condition is removed; i.e., the breakpoint\n is made unconditional.\n\ncommands [bpnumber]\n\n Specify a list of commands for breakpoint number *bpnumber*. The\n commands themselves appear on the following lines. Type a line\n containing just "end" to terminate the commands. An example:\n\n (Pdb) commands 1\n (com) p some_variable\n (com) end\n (Pdb)\n\n To remove all commands from a breakpoint, type commands and follow\n it immediately with "end"; that is, give no commands.\n\n With no *bpnumber* argument, commands refers to the last breakpoint\n set.\n\n You can use breakpoint commands to start your program up again.\n Simply use the continue command, or step, or any other command that\n resumes execution.\n\n Specifying any command resuming execution (currently continue,\n step, next, return, jump, quit and their abbreviations) terminates\n the command list (as if that command was immediately followed by\n end). This is because any time you resume execution (even with a\n simple next or step), you may encounter another breakpoint--which\n could have its own command list, leading to ambiguities about which\n list to execute.\n\n If you use the \'silent\' command in the command list, the usual\n message about stopping at a breakpoint is not printed. This may be\n desirable for breakpoints that are to print a specific message and\n then continue. If none of the other commands print anything, you\n see no sign that the breakpoint was reached.\n\ns(tep)\n\n Execute the current line, stop at the first possible occasion\n (either in a function that is called or on the next line in the\n current function).\n\nn(ext)\n\n Continue execution until the next line in the current function is\n reached or it returns. (The difference between "next" and "step"\n is that "step" stops inside a called function, while "next"\n executes called functions at (nearly) full speed, only stopping at\n the next line in the current function.)\n\nunt(il) [lineno]\n\n Without argument, continue execution until the line with a number\n greater than the current one is reached.\n\n With a line number, continue execution until a line with a number\n greater or equal to that is reached. In both cases, also stop when\n the current frame returns.\n\n Changed in version 3.2: Allow giving an explicit line number.\n\nr(eturn)\n\n Continue execution until the current function returns.\n\nc(ont(inue))\n\n Continue execution, only stop when a breakpoint is encountered.\n\nj(ump) lineno\n\n Set the next line that will be executed. Only available in the\n bottom-most frame. This lets you jump back and execute code again,\n or jump forward to skip code that you don\'t want to run.\n\n It should be noted that not all jumps are allowed -- for instance\n it is not possible to jump into the middle of a "for" loop or out\n of a "finally" clause.\n\nl(ist) [first[, last]]\n\n List source code for the current file. Without arguments, list 11\n lines around the current line or continue the previous listing.\n With "." as argument, list 11 lines around the current line. With\n one argument, list 11 lines around at that line. With two\n arguments, list the given range; if the second argument is less\n than the first, it is interpreted as a count.\n\n The current line in the current frame is indicated by "->". If an\n exception is being debugged, the line where the exception was\n originally raised or propagated is indicated by ">>", if it differs\n from the current line.\n\n New in version 3.2: The ">>" marker.\n\nll | longlist\n\n List all source code for the current function or frame.\n Interesting lines are marked as for "list".\n\n New in version 3.2.\n\na(rgs)\n\n Print the argument list of the current function.\n\np expression\n\n Evaluate the *expression* in the current context and print its\n value.\n\n Note: "print()" can also be used, but is not a debugger command\n --- this executes the Python "print()" function.\n\npp expression\n\n Like the "p" command, except the value of the expression is pretty-\n printed using the "pprint" module.\n\nwhatis expression\n\n Print the type of the *expression*.\n\nsource expression\n\n Try to get source code for the given object and display it.\n\n New in version 3.2.\n\ndisplay [expression]\n\n Display the value of the expression if it changed, each time\n execution stops in the current frame.\n\n Without expression, list all display expressions for the current\n frame.\n\n New in version 3.2.\n\nundisplay [expression]\n\n Do not display the expression any more in the current frame.\n Without expression, clear all display expressions for the current\n frame.\n\n New in version 3.2.\n\ninteract\n\n Start an interative interpreter (using the "code" module) whose\n global namespace contains all the (global and local) names found in\n the current scope.\n\n New in version 3.2.\n\nalias [name [command]]\n\n Create an alias called *name* that executes *command*. The command\n must *not* be enclosed in quotes. Replaceable parameters can be\n indicated by "%1", "%2", and so on, while "%*" is replaced by all\n the parameters. If no command is given, the current alias for\n *name* is shown. If no arguments are given, all aliases are listed.\n\n Aliases may be nested and can contain anything that can be legally\n typed at the pdb prompt. Note that internal pdb commands *can* be\n overridden by aliases. Such a command is then hidden until the\n alias is removed. Aliasing is recursively applied to the first\n word of the command line; all other words in the line are left\n alone.\n\n As an example, here are two useful aliases (especially when placed\n in the ".pdbrc" file):\n\n # Print instance variables (usage "pi classInst")\n alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k])\n # Print instance variables in self\n alias ps pi self\n\nunalias name\n\n Delete the specified alias.\n\n! statement\n\n Execute the (one-line) *statement* in the context of the current\n stack frame. The exclamation point can be omitted unless the first\n word of the statement resembles a debugger command. To set a\n global variable, you can prefix the assignment command with a\n "global" statement on the same line, e.g.:\n\n (Pdb) global list_options; list_options = [\'-l\']\n (Pdb)\n\nrun [args ...]\nrestart [args ...]\n\n Restart the debugged Python program. If an argument is supplied,\n it is split with "shlex" and the result is used as the new\n "sys.argv". History, breakpoints, actions and debugger options are\n preserved. "restart" is an alias for "run".\n\nq(uit)\n\n Quit from the debugger. The program being executed is aborted.\n\n-[ Footnotes ]-\n\n[1] Whether a frame is considered to originate in a certain module\n is determined by the "__name__" in the frame globals.\n', + 'del': '\nThe "del" statement\n*******************\n\n del_stmt ::= "del" target_list\n\nDeletion is recursively defined very similar to the way assignment is\ndefined. Rather than spelling it out in full details, here are some\nhints.\n\nDeletion of a target list recursively deletes each target, from left\nto right.\n\nDeletion of a name removes the binding of that name from the local or\nglobal namespace, depending on whether the name occurs in a "global"\nstatement in the same code block. If the name is unbound, a\n"NameError" exception will be raised.\n\nDeletion of attribute references, subscriptions and slicings is passed\nto the primary object involved; deletion of a slicing is in general\nequivalent to assignment of an empty slice of the right type (but even\nthis is determined by the sliced object).\n\nChanged in version 3.2: Previously it was illegal to delete a name\nfrom the local namespace if it occurs as a free variable in a nested\nblock.\n', 'dict': '\nDictionary displays\n*******************\n\nA dictionary display is a possibly empty series of key/datum pairs\nenclosed in curly braces:\n\n dict_display ::= "{" [key_datum_list | dict_comprehension] "}"\n key_datum_list ::= key_datum ("," key_datum)* [","]\n key_datum ::= expression ":" expression\n dict_comprehension ::= expression ":" expression comp_for\n\nA dictionary display yields a new dictionary object.\n\nIf a comma-separated sequence of key/datum pairs is given, they are\nevaluated from left to right to define the entries of the dictionary:\neach key object is used as a key into the dictionary to store the\ncorresponding datum. This means that you can specify the same key\nmultiple times in the key/datum list, and the final dictionary\'s value\nfor that key will be the last one given.\n\nA dict comprehension, in contrast to list and set comprehensions,\nneeds two expressions separated with a colon followed by the usual\n"for" and "if" clauses. When the comprehension is run, the resulting\nkey and value elements are inserted in the new dictionary in the order\nthey are produced.\n\nRestrictions on the types of the key values are listed earlier in\nsection *The standard type hierarchy*. (To summarize, the key type\nshould be *hashable*, which excludes all mutable objects.) Clashes\nbetween duplicate keys are not detected; the last datum (textually\nrightmost in the display) stored for a given key value prevails.\n', - 'dynamic-features': '\nInteraction with dynamic features\n*********************************\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n', - 'else': '\nThe ``if`` statement\n********************\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n', - 'exceptions': '\nExceptions\n**********\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the ``raise`` statement. Exception\nhandlers are specified with the ``try`` ... ``except`` statement. The\n``finally`` clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n``SystemExit``.\n\nExceptions are identified by class instances. The ``except`` clause\nis selected depending on the class of the instance: it must reference\nthe class of the instance or a base class thereof. The instance can\nbe received by the handler and can carry additional information about\nthe exceptional condition.\n\nNote: Exception messages are not part of the Python API. Their contents\n may change from one version of Python to the next without warning\n and should not be relied on by code which will run under multiple\n versions of the interpreter.\n\nSee also the description of the ``try`` statement in section *The try\nstatement* and ``raise`` statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by these\n operations is not available at the time the module is compiled.\n', - 'execmodel': '\nExecution model\n***************\n\n\nNaming and binding\n==================\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\non the interpreter command line the first argument) is a code block.\nA script command (a command specified on the interpreter command line\nwith the \'**-c**\' option) is a code block. The string argument passed\nto the built-in functions ``eval()`` and ``exec()`` is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block\'s execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block\'s *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as ``nonlocal``. If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a ``NameError`` exception is raised.\nIf the name refers to a local variable that has not been bound, a\n``UnboundLocalError`` exception is raised. ``UnboundLocalError`` is a\nsubclass of ``NameError``.\n\nThe following constructs bind names: formal parameters to functions,\n``import`` statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, ``for`` loop header, or\nafter ``as`` in a ``with`` statement or ``except`` clause. The\n``import`` statement of the form ``from ... import *`` binds all names\ndefined in the imported module, except those beginning with an\nunderscore. This form may only be used at the module level.\n\nA target occurring in a ``del`` statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name).\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the ``global`` statement occurs within a block, all uses of the\nname specified in the statement refer to the binding of that name in\nthe top-level namespace. Names are resolved in the top-level\nnamespace by searching the global namespace, i.e. the namespace of the\nmodule containing the code block, and the builtins namespace, the\nnamespace of the module ``builtins``. The global namespace is\nsearched first. If the name is not found there, the builtins\nnamespace is searched. The global statement must precede all uses of\nthe name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name ``__builtins__`` in its\nglobal namespace; this should be a dictionary or a module (in the\nlatter case the module\'s dictionary is used). By default, when in the\n``__main__`` module, ``__builtins__`` is the built-in module\n``builtins``; when in any other module, ``__builtins__`` is an alias\nfor the dictionary of the ``builtins`` module itself.\n``__builtins__`` can be set to a user-created dictionary to create a\nweak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n``__builtins__``; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should ``import``\nthe ``builtins`` module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n``__main__``.\n\nThe ``global`` statement has the same scope as a name binding\noperation in the same block. If the nearest enclosing scope for a\nfree variable contains a global statement, the free variable is\ntreated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n---------------------------------\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n\n\nExceptions\n==========\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the ``raise`` statement. Exception\nhandlers are specified with the ``try`` ... ``except`` statement. The\n``finally`` clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n``SystemExit``.\n\nExceptions are identified by class instances. The ``except`` clause\nis selected depending on the class of the instance: it must reference\nthe class of the instance or a base class thereof. The instance can\nbe received by the handler and can carry additional information about\nthe exceptional condition.\n\nNote: Exception messages are not part of the Python API. Their contents\n may change from one version of Python to the next without warning\n and should not be relied on by code which will run under multiple\n versions of the interpreter.\n\nSee also the description of the ``try`` statement in section *The try\nstatement* and ``raise`` statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by these\n operations is not available at the time the module is compiled.\n', - 'exprlists': '\nExpression lists\n****************\n\n expression_list ::= expression ( "," expression )* [","]\n\nAn expression list containing at least one comma yields a tuple. The\nlength of the tuple is the number of expressions in the list. The\nexpressions are evaluated from left to right.\n\nThe trailing comma is required only to create a single tuple (a.k.a. a\n*singleton*); it is optional in all other cases. A single expression\nwithout a trailing comma doesn\'t create a tuple, but rather yields the\nvalue of that expression. (To create an empty tuple, use an empty pair\nof parentheses: ``()``.)\n', - 'floating': '\nFloating point literals\n***********************\n\nFloating point literals are described by the following lexical\ndefinitions:\n\n floatnumber ::= pointfloat | exponentfloat\n pointfloat ::= [intpart] fraction | intpart "."\n exponentfloat ::= (intpart | pointfloat) exponent\n intpart ::= digit+\n fraction ::= "." digit+\n exponent ::= ("e" | "E") ["+" | "-"] digit+\n\nNote that the integer and exponent parts are always interpreted using\nradix 10. For example, ``077e010`` is legal, and denotes the same\nnumber as ``77e10``. The allowed range of floating point literals is\nimplementation-dependent. Some examples of floating point literals:\n\n 3.14 10. .001 1e100 3.14e-10 0e0\n\nNote that numeric literals do not include a sign; a phrase like ``-1``\nis actually an expression composed of the unary operator ``-`` and the\nliteral ``1``.\n', - 'for': '\nThe ``for`` statement\n*********************\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n', - 'formatstrings': '\nFormat String Syntax\n********************\n\nThe ``str.format()`` method and the ``Formatter`` class share the same\nsyntax for format strings (although in the case of ``Formatter``,\nsubclasses can define their own format string syntax).\n\nFormat strings contain "replacement fields" surrounded by curly braces\n``{}``. Anything that is not contained in braces is considered literal\ntext, which is copied unchanged to the output. If you need to include\na brace character in the literal text, it can be escaped by doubling:\n``{{`` and ``}}``.\n\nThe grammar for a replacement field is as follows:\n\n replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}"\n field_name ::= arg_name ("." attribute_name | "[" element_index "]")*\n arg_name ::= [identifier | integer]\n attribute_name ::= identifier\n element_index ::= integer | index_string\n index_string ::= +\n conversion ::= "r" | "s" | "a"\n format_spec ::= \n\nIn less formal terms, the replacement field can start with a\n*field_name* that specifies the object whose value is to be formatted\nand inserted into the output instead of the replacement field. The\n*field_name* is optionally followed by a *conversion* field, which is\npreceded by an exclamation point ``\'!\'``, and a *format_spec*, which\nis preceded by a colon ``\':\'``. These specify a non-default format\nfor the replacement value.\n\nSee also the *Format Specification Mini-Language* section.\n\nThe *field_name* itself begins with an *arg_name* that is either a\nnumber or a keyword. If it\'s a number, it refers to a positional\nargument, and if it\'s a keyword, it refers to a named keyword\nargument. If the numerical arg_names in a format string are 0, 1, 2,\n... in sequence, they can all be omitted (not just some) and the\nnumbers 0, 1, 2, ... will be automatically inserted in that order.\nBecause *arg_name* is not quote-delimited, it is not possible to\nspecify arbitrary dictionary keys (e.g., the strings ``\'10\'`` or\n``\':-]\'``) within a format string. The *arg_name* can be followed by\nany number of index or attribute expressions. An expression of the\nform ``\'.name\'`` selects the named attribute using ``getattr()``,\nwhile an expression of the form ``\'[index]\'`` does an index lookup\nusing ``__getitem__()``.\n\nChanged in version 3.1: The positional argument specifiers can be\nomitted, so ``\'{} {}\'`` is equivalent to ``\'{0} {1}\'``.\n\nSome simple format string examples:\n\n "First, thou shalt count to {0}" # References first positional argument\n "Bring me a {}" # Implicitly references the first positional argument\n "From {} to {}" # Same as "From {0} to {1}"\n "My quest is {name}" # References keyword argument \'name\'\n "Weight in tons {0.weight}" # \'weight\' attribute of first positional arg\n "Units destroyed: {players[0]}" # First element of keyword argument \'players\'.\n\nThe *conversion* field causes a type coercion before formatting.\nNormally, the job of formatting a value is done by the\n``__format__()`` method of the value itself. However, in some cases\nit is desirable to force a type to be formatted as a string,\noverriding its own definition of formatting. By converting the value\nto a string before calling ``__format__()``, the normal formatting\nlogic is bypassed.\n\nThree conversion flags are currently supported: ``\'!s\'`` which calls\n``str()`` on the value, ``\'!r\'`` which calls ``repr()`` and ``\'!a\'``\nwhich calls ``ascii()``.\n\nSome examples:\n\n "Harold\'s a clever {0!s}" # Calls str() on the argument first\n "Bring out the holy {name!r}" # Calls repr() on the argument first\n "More {!a}" # Calls ascii() on the argument first\n\nThe *format_spec* field contains a specification of how the value\nshould be presented, including such details as field width, alignment,\npadding, decimal precision and so on. Each value type can define its\nown "formatting mini-language" or interpretation of the *format_spec*.\n\nMost built-in types support a common formatting mini-language, which\nis described in the next section.\n\nA *format_spec* field can also include nested replacement fields\nwithin it. These nested replacement fields can contain only a field\nname; conversion flags and format specifications are not allowed. The\nreplacement fields within the format_spec are substituted before the\n*format_spec* string is interpreted. This allows the formatting of a\nvalue to be dynamically specified.\n\nSee the *Format examples* section for some examples.\n\n\nFormat Specification Mini-Language\n==================================\n\n"Format specifications" are used within replacement fields contained\nwithin a format string to define how individual values are presented\n(see *Format String Syntax*). They can also be passed directly to the\nbuilt-in ``format()`` function. Each formattable type may define how\nthe format specification is to be interpreted.\n\nMost built-in types implement the following options for format\nspecifications, although some of the formatting options are only\nsupported by the numeric types.\n\nA general convention is that an empty format string (``""``) produces\nthe same result as if you had called ``str()`` on the value. A non-\nempty format string typically modifies the result.\n\nThe general form of a *standard format specifier* is:\n\n format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]\n fill ::= \n align ::= "<" | ">" | "=" | "^"\n sign ::= "+" | "-" | " "\n width ::= integer\n precision ::= integer\n type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"\n\nIf a valid *align* value is specified, it can be preceded by a *fill*\ncharacter that can be any character and defaults to a space if\nomitted. Note that it is not possible to use ``{`` and ``}`` as *fill*\nchar while using the ``str.format()`` method; this limitation however\ndoesn\'t affect the ``format()`` function.\n\nThe meaning of the various alignment options is as follows:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'<\'`` | Forces the field to be left-aligned within the available |\n | | space (this is the default for most objects). |\n +-----------+------------------------------------------------------------+\n | ``\'>\'`` | Forces the field to be right-aligned within the available |\n | | space (this is the default for numbers). |\n +-----------+------------------------------------------------------------+\n | ``\'=\'`` | Forces the padding to be placed after the sign (if any) |\n | | but before the digits. This is used for printing fields |\n | | in the form \'+000000120\'. This alignment option is only |\n | | valid for numeric types. |\n +-----------+------------------------------------------------------------+\n | ``\'^\'`` | Forces the field to be centered within the available |\n | | space. |\n +-----------+------------------------------------------------------------+\n\nNote that unless a minimum field width is defined, the field width\nwill always be the same size as the data to fill it, so that the\nalignment option has no meaning in this case.\n\nThe *sign* option is only valid for number types, and can be one of\nthe following:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'+\'`` | indicates that a sign should be used for both positive as |\n | | well as negative numbers. |\n +-----------+------------------------------------------------------------+\n | ``\'-\'`` | indicates that a sign should be used only for negative |\n | | numbers (this is the default behavior). |\n +-----------+------------------------------------------------------------+\n | space | indicates that a leading space should be used on positive |\n | | numbers, and a minus sign on negative numbers. |\n +-----------+------------------------------------------------------------+\n\nThe ``\'#\'`` option causes the "alternate form" to be used for the\nconversion. The alternate form is defined differently for different\ntypes. This option is only valid for integer, float, complex and\nDecimal types. For integers, when binary, octal, or hexadecimal output\nis used, this option adds the prefix respective ``\'0b\'``, ``\'0o\'``, or\n``\'0x\'`` to the output value. For floats, complex and Decimal the\nalternate form causes the result of the conversion to always contain a\ndecimal-point character, even if no digits follow it. Normally, a\ndecimal-point character appears in the result of these conversions\nonly if a digit follows it. In addition, for ``\'g\'`` and ``\'G\'``\nconversions, trailing zeros are not removed from the result.\n\nThe ``\',\'`` option signals the use of a comma for a thousands\nseparator. For a locale aware separator, use the ``\'n\'`` integer\npresentation type instead.\n\nChanged in version 3.1: Added the ``\',\'`` option (see also **PEP\n378**).\n\n*width* is a decimal integer defining the minimum field width. If not\nspecified, then the field width will be determined by the content.\n\nPreceding the *width* field by a zero (``\'0\'``) character enables\nsign-aware zero-padding for numeric types. This is equivalent to a\n*fill* character of ``\'0\'`` with an *alignment* type of ``\'=\'``.\n\nThe *precision* is a decimal number indicating how many digits should\nbe displayed after the decimal point for a floating point value\nformatted with ``\'f\'`` and ``\'F\'``, or before and after the decimal\npoint for a floating point value formatted with ``\'g\'`` or ``\'G\'``.\nFor non-number types the field indicates the maximum field size - in\nother words, how many characters will be used from the field content.\nThe *precision* is not allowed for integer values.\n\nFinally, the *type* determines how the data should be presented.\n\nThe available string presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'s\'`` | String format. This is the default type for strings and |\n | | may be omitted. |\n +-----------+------------------------------------------------------------+\n | None | The same as ``\'s\'``. |\n +-----------+------------------------------------------------------------+\n\nThe available integer presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'b\'`` | Binary format. Outputs the number in base 2. |\n +-----------+------------------------------------------------------------+\n | ``\'c\'`` | Character. Converts the integer to the corresponding |\n | | unicode character before printing. |\n +-----------+------------------------------------------------------------+\n | ``\'d\'`` | Decimal Integer. Outputs the number in base 10. |\n +-----------+------------------------------------------------------------+\n | ``\'o\'`` | Octal format. Outputs the number in base 8. |\n +-----------+------------------------------------------------------------+\n | ``\'x\'`` | Hex format. Outputs the number in base 16, using lower- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | ``\'X\'`` | Hex format. Outputs the number in base 16, using upper- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | ``\'n\'`` | Number. This is the same as ``\'d\'``, except that it uses |\n | | the current locale setting to insert the appropriate |\n | | number separator characters. |\n +-----------+------------------------------------------------------------+\n | None | The same as ``\'d\'``. |\n +-----------+------------------------------------------------------------+\n\nIn addition to the above presentation types, integers can be formatted\nwith the floating point presentation types listed below (except\n``\'n\'`` and None). When doing so, ``float()`` is used to convert the\ninteger to a floating point number before formatting.\n\nThe available presentation types for floating point and decimal values\nare:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'e\'`` | Exponent notation. Prints the number in scientific |\n | | notation using the letter \'e\' to indicate the exponent. |\n | | The default precision is ``6``. |\n +-----------+------------------------------------------------------------+\n | ``\'E\'`` | Exponent notation. Same as ``\'e\'`` except it uses an upper |\n | | case \'E\' as the separator character. |\n +-----------+------------------------------------------------------------+\n | ``\'f\'`` | Fixed point. Displays the number as a fixed-point number. |\n | | The default precision is ``6``. |\n +-----------+------------------------------------------------------------+\n | ``\'F\'`` | Fixed point. Same as ``\'f\'``, but converts ``nan`` to |\n | | ``NAN`` and ``inf`` to ``INF``. |\n +-----------+------------------------------------------------------------+\n | ``\'g\'`` | General format. For a given precision ``p >= 1``, this |\n | | rounds the number to ``p`` significant digits and then |\n | | formats the result in either fixed-point format or in |\n | | scientific notation, depending on its magnitude. The |\n | | precise rules are as follows: suppose that the result |\n | | formatted with presentation type ``\'e\'`` and precision |\n | | ``p-1`` would have exponent ``exp``. Then if ``-4 <= exp |\n | | < p``, the number is formatted with presentation type |\n | | ``\'f\'`` and precision ``p-1-exp``. Otherwise, the number |\n | | is formatted with presentation type ``\'e\'`` and precision |\n | | ``p-1``. In both cases insignificant trailing zeros are |\n | | removed from the significand, and the decimal point is |\n | | also removed if there are no remaining digits following |\n | | it. Positive and negative infinity, positive and negative |\n | | zero, and nans, are formatted as ``inf``, ``-inf``, ``0``, |\n | | ``-0`` and ``nan`` respectively, regardless of the |\n | | precision. A precision of ``0`` is treated as equivalent |\n | | to a precision of ``1``. The default precision is ``6``. |\n +-----------+------------------------------------------------------------+\n | ``\'G\'`` | General format. Same as ``\'g\'`` except switches to ``\'E\'`` |\n | | if the number gets too large. The representations of |\n | | infinity and NaN are uppercased, too. |\n +-----------+------------------------------------------------------------+\n | ``\'n\'`` | Number. This is the same as ``\'g\'``, except that it uses |\n | | the current locale setting to insert the appropriate |\n | | number separator characters. |\n +-----------+------------------------------------------------------------+\n | ``\'%\'`` | Percentage. Multiplies the number by 100 and displays in |\n | | fixed (``\'f\'``) format, followed by a percent sign. |\n +-----------+------------------------------------------------------------+\n | None | Similar to ``\'g\'``, except with at least one digit past |\n | | the decimal point and a default precision of 12. This is |\n | | intended to match ``str()``, except you can add the other |\n | | format modifiers. |\n +-----------+------------------------------------------------------------+\n\n\nFormat examples\n===============\n\nThis section contains examples of the new format syntax and comparison\nwith the old ``%``-formatting.\n\nIn most of the cases the syntax is similar to the old\n``%``-formatting, with the addition of the ``{}`` and with ``:`` used\ninstead of ``%``. For example, ``\'%03.2f\'`` can be translated to\n``\'{:03.2f}\'``.\n\nThe new format syntax also supports new and different options, shown\nin the follow examples.\n\nAccessing arguments by position:\n\n >>> \'{0}, {1}, {2}\'.format(\'a\', \'b\', \'c\')\n \'a, b, c\'\n >>> \'{}, {}, {}\'.format(\'a\', \'b\', \'c\') # 3.1+ only\n \'a, b, c\'\n >>> \'{2}, {1}, {0}\'.format(\'a\', \'b\', \'c\')\n \'c, b, a\'\n >>> \'{2}, {1}, {0}\'.format(*\'abc\') # unpacking argument sequence\n \'c, b, a\'\n >>> \'{0}{1}{0}\'.format(\'abra\', \'cad\') # arguments\' indices can be repeated\n \'abracadabra\'\n\nAccessing arguments by name:\n\n >>> \'Coordinates: {latitude}, {longitude}\'.format(latitude=\'37.24N\', longitude=\'-115.81W\')\n \'Coordinates: 37.24N, -115.81W\'\n >>> coord = {\'latitude\': \'37.24N\', \'longitude\': \'-115.81W\'}\n >>> \'Coordinates: {latitude}, {longitude}\'.format(**coord)\n \'Coordinates: 37.24N, -115.81W\'\n\nAccessing arguments\' attributes:\n\n >>> c = 3-5j\n >>> (\'The complex number {0} is formed from the real part {0.real} \'\n ... \'and the imaginary part {0.imag}.\').format(c)\n \'The complex number (3-5j) is formed from the real part 3.0 and the imaginary part -5.0.\'\n >>> class Point:\n ... def __init__(self, x, y):\n ... self.x, self.y = x, y\n ... def __str__(self):\n ... return \'Point({self.x}, {self.y})\'.format(self=self)\n ...\n >>> str(Point(4, 2))\n \'Point(4, 2)\'\n\nAccessing arguments\' items:\n\n >>> coord = (3, 5)\n >>> \'X: {0[0]}; Y: {0[1]}\'.format(coord)\n \'X: 3; Y: 5\'\n\nReplacing ``%s`` and ``%r``:\n\n >>> "repr() shows quotes: {!r}; str() doesn\'t: {!s}".format(\'test1\', \'test2\')\n "repr() shows quotes: \'test1\'; str() doesn\'t: test2"\n\nAligning the text and specifying a width:\n\n >>> \'{:<30}\'.format(\'left aligned\')\n \'left aligned \'\n >>> \'{:>30}\'.format(\'right aligned\')\n \' right aligned\'\n >>> \'{:^30}\'.format(\'centered\')\n \' centered \'\n >>> \'{:*^30}\'.format(\'centered\') # use \'*\' as a fill char\n \'***********centered***********\'\n\nReplacing ``%+f``, ``%-f``, and ``% f`` and specifying a sign:\n\n >>> \'{:+f}; {:+f}\'.format(3.14, -3.14) # show it always\n \'+3.140000; -3.140000\'\n >>> \'{: f}; {: f}\'.format(3.14, -3.14) # show a space for positive numbers\n \' 3.140000; -3.140000\'\n >>> \'{:-f}; {:-f}\'.format(3.14, -3.14) # show only the minus -- same as \'{:f}; {:f}\'\n \'3.140000; -3.140000\'\n\nReplacing ``%x`` and ``%o`` and converting the value to different\nbases:\n\n >>> # format also supports binary numbers\n >>> "int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}".format(42)\n \'int: 42; hex: 2a; oct: 52; bin: 101010\'\n >>> # with 0x, 0o, or 0b as prefix:\n >>> "int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42)\n \'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010\'\n\nUsing the comma as a thousands separator:\n\n >>> \'{:,}\'.format(1234567890)\n \'1,234,567,890\'\n\nExpressing a percentage:\n\n >>> points = 19\n >>> total = 22\n >>> \'Correct answers: {:.2%}\'.format(points/total)\n \'Correct answers: 86.36%\'\n\nUsing type-specific formatting:\n\n >>> import datetime\n >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)\n >>> \'{:%Y-%m-%d %H:%M:%S}\'.format(d)\n \'2010-07-04 12:15:58\'\n\nNesting arguments and more complex examples:\n\n >>> for align, text in zip(\'<^>\', [\'left\', \'center\', \'right\']):\n ... \'{0:{fill}{align}16}\'.format(text, fill=align, align=align)\n ...\n \'left<<<<<<<<<<<<\'\n \'^^^^^center^^^^^\'\n \'>>>>>>>>>>>right\'\n >>>\n >>> octets = [192, 168, 0, 1]\n >>> \'{:02X}{:02X}{:02X}{:02X}\'.format(*octets)\n \'C0A80001\'\n >>> int(_, 16)\n 3232235521\n >>>\n >>> width = 5\n >>> for num in range(5,12): #doctest: +NORMALIZE_WHITESPACE\n ... for base in \'dXob\':\n ... print(\'{0:{width}{base}}\'.format(num, base=base, width=width), end=\' \')\n ... print()\n ...\n 5 5 5 101\n 6 6 6 110\n 7 7 7 111\n 8 8 10 1000\n 9 9 11 1001\n 10 A 12 1010\n 11 B 13 1011\n', - 'function': '\nFunction definitions\n********************\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)* ["," "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more *parameters* have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding *argument* may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated from left to right when the\nfunction definition is executed.** This means that the expression is\nevaluated once, when the function is defined, and that the same "pre-\ncomputed" value is used for each call. This is especially important\nto understand when a default parameter is a mutable object, such as a\nlist or a dictionary: if the function modifies the object (e.g. by\nappending an item to a list), the default value is in effect modified.\nThis is generally not what was intended. A way around this is to use\n``None`` as the default, and explicitly test for it in the body of the\nfunction, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda\nexpressions, described in section *Lambdas*. Note that the lambda\nexpression is merely a shorthand for a simplified function definition;\na function defined in a "``def``" statement can be passed around or\nassigned to another name just like a function defined by a lambda\nexpression. The "``def``" form is actually more powerful since it\nallows the execution of multiple statements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nstatement executed inside a function definition defines a local\nfunction that can be returned or passed around. Free variables used\nin the nested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\nSee also:\n\n **PEP 3107** - Function Annotations\n The original specification for function annotations.\n', - 'global': '\nThe ``global`` statement\n************************\n\n global_stmt ::= "global" identifier ("," identifier)*\n\nThe ``global`` statement is a declaration which holds for the entire\ncurrent code block. It means that the listed identifiers are to be\ninterpreted as globals. It would be impossible to assign to a global\nvariable without ``global``, although free variables may refer to\nglobals without being declared global.\n\nNames listed in a ``global`` statement must not be used in the same\ncode block textually preceding that ``global`` statement.\n\nNames listed in a ``global`` statement must not be defined as formal\nparameters or in a ``for`` loop control target, ``class`` definition,\nfunction definition, or ``import`` statement.\n\n**CPython implementation detail:** The current implementation does not\nenforce the latter two restrictions, but programs should not abuse\nthis freedom, as future implementations may enforce them or silently\nchange the meaning of the program.\n\n**Programmer\'s note:** the ``global`` is a directive to the parser.\nIt applies only to code parsed at the same time as the ``global``\nstatement. In particular, a ``global`` statement contained in a string\nor code object supplied to the built-in ``exec()`` function does not\naffect the code block *containing* the function call, and code\ncontained in such a string is unaffected by ``global`` statements in\nthe code containing the function call. The same applies to the\n``eval()`` and ``compile()`` functions.\n', - 'id-classes': '\nReserved classes of identifiers\n*******************************\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n``_*``\n Not imported by ``from module import *``. The special identifier\n ``_`` is used in the interactive interpreter to store the result of\n the last evaluation; it is stored in the ``builtins`` module. When\n not in interactive mode, ``_`` has no special meaning and is not\n defined. See section *The import statement*.\n\n Note: The name ``_`` is often used in conjunction with\n internationalization; refer to the documentation for the\n ``gettext`` module for more information on this convention.\n\n``__*__``\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of ``__*__`` names, in any context, that does\n not follow explicitly documented use, is subject to breakage\n without warning.\n\n``__*``\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', - 'identifiers': '\nIdentifiers and keywords\n************************\n\nIdentifiers (also referred to as *names*) are described by the\nfollowing lexical definitions.\n\nThe syntax of identifiers in Python is based on the Unicode standard\nannex UAX-31, with elaboration and changes as defined below; see also\n**PEP 3131** for further details.\n\nWithin the ASCII range (U+0001..U+007F), the valid characters for\nidentifiers are the same as in Python 2.x: the uppercase and lowercase\nletters ``A`` through ``Z``, the underscore ``_`` and, except for the\nfirst character, the digits ``0`` through ``9``.\n\nPython 3.0 introduces additional characters from outside the ASCII\nrange (see **PEP 3131**). For these characters, the classification\nuses the version of the Unicode Character Database as included in the\n``unicodedata`` module.\n\nIdentifiers are unlimited in length. Case is significant.\n\n identifier ::= xid_start xid_continue*\n id_start ::= \n id_continue ::= \n xid_start ::= \n xid_continue ::= \n\nThe Unicode category codes mentioned above stand for:\n\n* *Lu* - uppercase letters\n\n* *Ll* - lowercase letters\n\n* *Lt* - titlecase letters\n\n* *Lm* - modifier letters\n\n* *Lo* - other letters\n\n* *Nl* - letter numbers\n\n* *Mn* - nonspacing marks\n\n* *Mc* - spacing combining marks\n\n* *Nd* - decimal numbers\n\n* *Pc* - connector punctuations\n\n* *Other_ID_Start* - explicit list of characters in PropList.txt to\n support backwards compatibility\n\n* *Other_ID_Continue* - likewise\n\nAll identifiers are converted into the normal form NFKC while parsing;\ncomparison of identifiers is based on NFKC.\n\nA non-normative HTML file listing all valid identifier characters for\nUnicode 4.1 can be found at http://www.dcl.hpi.uni-\npotsdam.de/home/loewis/table-3131.html.\n\n\nKeywords\n========\n\nThe following identifiers are used as reserved words, or *keywords* of\nthe language, and cannot be used as ordinary identifiers. They must\nbe spelled exactly as written here:\n\n False class finally is return\n None continue for lambda try\n True def from nonlocal while\n and del global not with\n as elif if or yield\n assert else import pass\n break except in raise\n\n\nReserved classes of identifiers\n===============================\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n``_*``\n Not imported by ``from module import *``. The special identifier\n ``_`` is used in the interactive interpreter to store the result of\n the last evaluation; it is stored in the ``builtins`` module. When\n not in interactive mode, ``_`` has no special meaning and is not\n defined. See section *The import statement*.\n\n Note: The name ``_`` is often used in conjunction with\n internationalization; refer to the documentation for the\n ``gettext`` module for more information on this convention.\n\n``__*__``\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of ``__*__`` names, in any context, that does\n not follow explicitly documented use, is subject to breakage\n without warning.\n\n``__*``\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', - 'if': '\nThe ``if`` statement\n********************\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n', - 'imaginary': '\nImaginary literals\n******************\n\nImaginary literals are described by the following lexical definitions:\n\n imagnumber ::= (floatnumber | intpart) ("j" | "J")\n\nAn imaginary literal yields a complex number with a real part of 0.0.\nComplex numbers are represented as a pair of floating point numbers\nand have the same restrictions on their range. To create a complex\nnumber with a nonzero real part, add a floating point number to it,\ne.g., ``(3+4j)``. Some examples of imaginary literals:\n\n 3.14j 10.j 10j .001j 1e100j 3.14e-10j\n', - 'import': '\nThe ``import`` statement\n************************\n\n import_stmt ::= "import" module ["as" name] ( "," module ["as" name] )*\n | "from" relative_module "import" identifier ["as" name]\n ( "," identifier ["as" name] )*\n | "from" relative_module "import" "(" identifier ["as" name]\n ( "," identifier ["as" name] )* [","] ")"\n | "from" module "import" "*"\n module ::= (identifier ".")* identifier\n relative_module ::= "."* module | "."+\n name ::= identifier\n\nThe basic import statement (no ``from`` clause) is executed in two\nsteps:\n\n1. find a module, loading and initializing it if necessary\n\n2. define a name or names in the local namespace for the scope where\n the ``import`` statement occurs.\n\nWhen the statement contains multiple clauses (separated by commas) the\ntwo steps are carried out separately for each clause, just as though\nthe clauses had been separated out into individiual import statements.\n\nThe details of the first step, finding and loading modules is\ndescribed in greater detail in the section on the *import system*,\nwhich also describes the various types of packages and modules that\ncan be imported, as well as all the hooks that can be used to\ncustomize the import system. Note that failures in this step may\nindicate either that the module could not be located, *or* that an\nerror occurred while initializing the module, which includes execution\nof the module\'s code.\n\nIf the requested module is retrieved successfully, it will be made\navailable in the local namespace in one of three ways:\n\n* If the module name is followed by ``as``, then the name following\n ``as`` is bound directly to the imported module.\n\n* If no other name is specified, and the module being imported is a\n top level module, the module\'s name is bound in the local namespace\n as a reference to the imported module\n\n* If the module being imported is *not* a top level module, then the\n name of the top level package that contains the module is bound in\n the local namespace as a reference to the top level package. The\n imported module must be accessed using its full qualified name\n rather than directly\n\nThe ``from`` form uses a slightly more complex process:\n\n1. find the module specified in the ``from`` clause loading and\n initializing it if necessary;\n\n2. for each of the identifiers specified in the ``import`` clauses:\n\n 1. check if the imported module has an attribute by that name\n\n 2. if not, attempt to import a submodule with that name and then\n check the imported module again for that attribute\n\n 3. if the attribute is not found, ``ImportError`` is raised.\n\n 4. otherwise, a reference to that value is bound in the local\n namespace, using the name in the ``as`` clause if it is present,\n otherwise using the attribute name\n\nExamples:\n\n import foo # foo imported and bound locally\n import foo.bar.baz # foo.bar.baz imported, foo bound locally\n import foo.bar.baz as fbb # foo.bar.baz imported and bound as fbb\n from foo.bar import baz # foo.bar.baz imported and bound as baz\n from foo import attr # foo imported and foo.attr bound as attr\n\nIf the list of identifiers is replaced by a star (``\'*\'``), all public\nnames defined in the module are bound in the local namespace for the\nscope where the ``import`` statement occurs.\n\nThe *public names* defined by a module are determined by checking the\nmodule\'s namespace for a variable named ``__all__``; if defined, it\nmust be a sequence of strings which are names defined or imported by\nthat module. The names given in ``__all__`` are all considered public\nand are required to exist. If ``__all__`` is not defined, the set of\npublic names includes all names found in the module\'s namespace which\ndo not begin with an underscore character (``\'_\'``). ``__all__``\nshould contain the entire public API. It is intended to avoid\naccidentally exporting items that are not part of the API (such as\nlibrary modules which were imported and used within the module).\n\nThe ``from`` form with ``*`` may only occur in a module scope. The\nwild card form of import --- ``import *`` --- is only allowed at the\nmodule level. Attempting to use it in class or function definitions\nwill raise a ``SyntaxError``.\n\nWhen specifying what module to import you do not have to specify the\nabsolute name of the module. When a module or package is contained\nwithin another package it is possible to make a relative import within\nthe same top package without having to mention the package name. By\nusing leading dots in the specified module or package after ``from``\nyou can specify how high to traverse up the current package hierarchy\nwithout specifying exact names. One leading dot means the current\npackage where the module making the import exists. Two dots means up\none package level. Three dots is up two levels, etc. So if you execute\n``from . import mod`` from a module in the ``pkg`` package then you\nwill end up importing ``pkg.mod``. If you execute ``from ..subpkg2\nimport mod`` from within ``pkg.subpkg1`` you will import\n``pkg.subpkg2.mod``. The specification for relative imports is\ncontained within **PEP 328**.\n\n``importlib.import_module()`` is provided to support applications that\ndetermine which modules need to be loaded dynamically.\n\n\nFuture statements\n=================\n\nA *future statement* is a directive to the compiler that a particular\nmodule should be compiled using syntax or semantics that will be\navailable in a specified future release of Python. The future\nstatement is intended to ease migration to future versions of Python\nthat introduce incompatible changes to the language. It allows use of\nthe new features on a per-module basis before the release in which the\nfeature becomes standard.\n\n future_statement ::= "from" "__future__" "import" feature ["as" name]\n ("," feature ["as" name])*\n | "from" "__future__" "import" "(" feature ["as" name]\n ("," feature ["as" name])* [","] ")"\n feature ::= identifier\n name ::= identifier\n\nA future statement must appear near the top of the module. The only\nlines that can appear before a future statement are:\n\n* the module docstring (if any),\n\n* comments,\n\n* blank lines, and\n\n* other future statements.\n\nThe features recognized by Python 3.0 are ``absolute_import``,\n``division``, ``generators``, ``unicode_literals``,\n``print_function``, ``nested_scopes`` and ``with_statement``. They\nare all redundant because they are always enabled, and only kept for\nbackwards compatibility.\n\nA future statement is recognized and treated specially at compile\ntime: Changes to the semantics of core constructs are often\nimplemented by generating different code. It may even be the case\nthat a new feature introduces new incompatible syntax (such as a new\nreserved word), in which case the compiler may need to parse the\nmodule differently. Such decisions cannot be pushed off until\nruntime.\n\nFor any given release, the compiler knows which feature names have\nbeen defined, and raises a compile-time error if a future statement\ncontains a feature not known to it.\n\nThe direct runtime semantics are the same as for any import statement:\nthere is a standard module ``__future__``, described later, and it\nwill be imported in the usual way at the time the future statement is\nexecuted.\n\nThe interesting runtime semantics depend on the specific feature\nenabled by the future statement.\n\nNote that there is nothing special about the statement:\n\n import __future__ [as name]\n\nThat is not a future statement; it\'s an ordinary import statement with\nno special semantics or syntax restrictions.\n\nCode compiled by calls to the built-in functions ``exec()`` and\n``compile()`` that occur in a module ``M`` containing a future\nstatement will, by default, use the new syntax or semantics associated\nwith the future statement. This can be controlled by optional\narguments to ``compile()`` --- see the documentation of that function\nfor details.\n\nA future statement typed at an interactive interpreter prompt will\ntake effect for the rest of the interpreter session. If an\ninterpreter is started with the *-i* option, is passed a script name\nto execute, and the script includes a future statement, it will be in\neffect in the interactive session started after the script is\nexecuted.\n\nSee also:\n\n **PEP 236** - Back to the __future__\n The original proposal for the __future__ mechanism.\n', - 'in': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like ``a < b < c`` have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: ``True`` or ``False``.\n\nComparisons can be chained arbitrarily, e.g., ``x < y <= z`` is\nequivalent to ``x < y and y <= z``, except that ``y`` is evaluated\nonly once (but in both cases ``z`` is not evaluated at all when ``x <\ny`` is found to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then ``a op1 b op2 c ... y\nopN z`` is equivalent to ``a op1 b and b op2 c and ... y opN z``,\nexcept that each expression is evaluated at most once.\n\nNote that ``a op1 b op2 c`` doesn\'t imply any kind of comparison\nbetween *a* and *c*, so that, e.g., ``x < y > z`` is perfectly legal\n(though perhaps not pretty).\n\nThe operators ``<``, ``>``, ``==``, ``>=``, ``<=``, and ``!=`` compare\nthe values of two objects. The objects need not have the same type.\nIf both are numbers, they are converted to a common type. Otherwise,\nthe ``==`` and ``!=`` operators *always* consider objects of different\ntypes to be unequal, while the ``<``, ``>``, ``>=`` and ``<=``\noperators raise a ``TypeError`` when comparing objects of different\ntypes that do not implement these operators for the given pair of\ntypes. You can control comparison behavior of objects of non-built-in\ntypes by defining rich comparison methods like ``__gt__()``, described\nin section *Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values ``float(\'NaN\')`` and ``Decimal(\'NaN\')`` are special. The\n are identical to themselves, ``x is x`` but are not equal to\n themselves, ``x != x``. Additionally, comparing any value to a\n not-a-number value will return ``False``. For example, both ``3 <\n float(\'NaN\')`` and ``float(\'NaN\') < 3`` will return ``False``.\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric equivalents\n (the result of the built-in function ``ord()``) of their characters.\n [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison of\n corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, ``[1,2,x] <= [1,2,y]`` has the\n same value as ``x <= y``. If the corresponding element does not\n exist, the shorter sequence is ordered first (for example, ``[1,2] <\n [1,2,3]``).\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same ``(key, value)`` pairs. Order comparisons ``(\'<\', \'<=\', \'>=\',\n \'>\')`` raise ``TypeError``.\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets ``{1,2}`` and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, ``min()``, ``max()``, and ``sorted()`` produce\n undefined results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they are\n the same object; the choice whether one object is considered smaller\n or larger than another one is made arbitrarily but consistently\n within one execution of a program.\n\nComparison of objects of the differing types depends on whether either\nof the types provide explicit support for the comparison. Most\nnumeric types can be compared with one another. When cross-type\ncomparison is not supported, the comparison method returns\n``NotImplemented``.\n\nThe operators ``in`` and ``not in`` test for membership. ``x in s``\nevaluates to true if *x* is a member of *s*, and false otherwise. ``x\nnot in s`` returns the negation of ``x in s``. All built-in sequences\nand set types support this as well as dictionary, for which ``in``\ntests whether a the dictionary has a given key. For container types\nsuch as list, tuple, set, frozenset, dict, or collections.deque, the\nexpression ``x in y`` is equivalent to ``any(x is e or x == e for e in\ny)``.\n\nFor the string and bytes types, ``x in y`` is true if and only if *x*\nis a substring of *y*. An equivalent test is ``y.find(x) != -1``.\nEmpty strings are always considered to be a substring of any other\nstring, so ``"" in "abc"`` will return ``True``.\n\nFor user-defined classes which define the ``__contains__()`` method,\n``x in y`` is true if and only if ``y.__contains__(x)`` is true.\n\nFor user-defined classes which do not define ``__contains__()`` but do\ndefine ``__iter__()``, ``x in y`` is true if some value ``z`` with ``x\n== z`` is produced while iterating over ``y``. If an exception is\nraised during the iteration, it is as if ``in`` raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n``__getitem__()``, ``x in y`` is true if and only if there is a non-\nnegative integer index *i* such that ``x == y[i]``, and all lower\ninteger indices do not raise ``IndexError`` exception. (If any other\nexception is raised, it is as if ``in`` raised that exception).\n\nThe operator ``not in`` is defined to have the inverse true value of\n``in``.\n\nThe operators ``is`` and ``is not`` test for object identity: ``x is\ny`` is true if and only if *x* and *y* are the same object. ``x is\nnot y`` yields the inverse truth value. [4]\n', + 'dynamic-features': '\nInteraction with dynamic features\n*********************************\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- "import *" --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a "SyntaxError".\n\nThe "eval()" and "exec()" functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe "exec()" and "eval()" functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n', + 'else': '\nThe "if" statement\n******************\n\nThe "if" statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the "if" statement is executed or evaluated).\nIf all expressions are false, the suite of the "else" clause, if\npresent, is executed.\n', + 'exceptions': '\nExceptions\n**********\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the "raise" statement. Exception\nhandlers are specified with the "try" ... "except" statement. The\n"finally" clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n"SystemExit".\n\nExceptions are identified by class instances. The "except" clause is\nselected depending on the class of the instance: it must reference the\nclass of the instance or a base class thereof. The instance can be\nreceived by the handler and can carry additional information about the\nexceptional condition.\n\nNote: Exception messages are not part of the Python API. Their\n contents may change from one version of Python to the next without\n warning and should not be relied on by code which will run under\n multiple versions of the interpreter.\n\nSee also the description of the "try" statement in section *The try\nstatement* and "raise" statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by\n these operations is not available at the time the module is\n compiled.\n', + 'execmodel': '\nExecution model\n***************\n\n\nNaming and binding\n==================\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\non the interpreter command line the first argument) is a code block.\nA script command (a command specified on the interpreter command line\nwith the \'**-c**\' option) is a code block. The string argument passed\nto the built-in functions "eval()" and "exec()" is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block\'s execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block\'s *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as "nonlocal". If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a "NameError" exception is raised.\nIf the name refers to a local variable that has not been bound, a\n"UnboundLocalError" exception is raised. "UnboundLocalError" is a\nsubclass of "NameError".\n\nThe following constructs bind names: formal parameters to functions,\n"import" statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, "for" loop header, or after\n"as" in a "with" statement or "except" clause. The "import" statement\nof the form "from ... import *" binds all names defined in the\nimported module, except those beginning with an underscore. This form\nmay only be used at the module level.\n\nA target occurring in a "del" statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name).\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the "global" statement occurs within a block, all uses of the name\nspecified in the statement refer to the binding of that name in the\ntop-level namespace. Names are resolved in the top-level namespace by\nsearching the global namespace, i.e. the namespace of the module\ncontaining the code block, and the builtins namespace, the namespace\nof the module "builtins". The global namespace is searched first. If\nthe name is not found there, the builtins namespace is searched. The\nglobal statement must precede all uses of the name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name "__builtins__" in its global\nnamespace; this should be a dictionary or a module (in the latter case\nthe module\'s dictionary is used). By default, when in the "__main__"\nmodule, "__builtins__" is the built-in module "builtins"; when in any\nother module, "__builtins__" is an alias for the dictionary of the\n"builtins" module itself. "__builtins__" can be set to a user-created\ndictionary to create a weak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n"__builtins__"; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should "import"\nthe "builtins" module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n"__main__".\n\nThe "global" statement has the same scope as a name binding operation\nin the same block. If the nearest enclosing scope for a free variable\ncontains a global statement, the free variable is treated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n---------------------------------\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- "import *" --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a "SyntaxError".\n\nThe "eval()" and "exec()" functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe "exec()" and "eval()" functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n\n\nExceptions\n==========\n\nExceptions are a means of breaking out of the normal flow of control\nof a code block in order to handle errors or other exceptional\nconditions. An exception is *raised* at the point where the error is\ndetected; it may be *handled* by the surrounding code block or by any\ncode block that directly or indirectly invoked the code block where\nthe error occurred.\n\nThe Python interpreter raises an exception when it detects a run-time\nerror (such as division by zero). A Python program can also\nexplicitly raise an exception with the "raise" statement. Exception\nhandlers are specified with the "try" ... "except" statement. The\n"finally" clause of such a statement can be used to specify cleanup\ncode which does not handle the exception, but is executed whether an\nexception occurred or not in the preceding code.\n\nPython uses the "termination" model of error handling: an exception\nhandler can find out what happened and continue execution at an outer\nlevel, but it cannot repair the cause of the error and retry the\nfailing operation (except by re-entering the offending piece of code\nfrom the top).\n\nWhen an exception is not handled at all, the interpreter terminates\nexecution of the program, or returns to its interactive main loop. In\neither case, it prints a stack backtrace, except when the exception is\n"SystemExit".\n\nExceptions are identified by class instances. The "except" clause is\nselected depending on the class of the instance: it must reference the\nclass of the instance or a base class thereof. The instance can be\nreceived by the handler and can carry additional information about the\nexceptional condition.\n\nNote: Exception messages are not part of the Python API. Their\n contents may change from one version of Python to the next without\n warning and should not be relied on by code which will run under\n multiple versions of the interpreter.\n\nSee also the description of the "try" statement in section *The try\nstatement* and "raise" statement in section *The raise statement*.\n\n-[ Footnotes ]-\n\n[1] This limitation occurs because the code that is executed by\n these operations is not available at the time the module is\n compiled.\n', + 'exprlists': '\nExpression lists\n****************\n\n expression_list ::= expression ( "," expression )* [","]\n\nAn expression list containing at least one comma yields a tuple. The\nlength of the tuple is the number of expressions in the list. The\nexpressions are evaluated from left to right.\n\nThe trailing comma is required only to create a single tuple (a.k.a. a\n*singleton*); it is optional in all other cases. A single expression\nwithout a trailing comma doesn\'t create a tuple, but rather yields the\nvalue of that expression. (To create an empty tuple, use an empty pair\nof parentheses: "()".)\n', + 'floating': '\nFloating point literals\n***********************\n\nFloating point literals are described by the following lexical\ndefinitions:\n\n floatnumber ::= pointfloat | exponentfloat\n pointfloat ::= [intpart] fraction | intpart "."\n exponentfloat ::= (intpart | pointfloat) exponent\n intpart ::= digit+\n fraction ::= "." digit+\n exponent ::= ("e" | "E") ["+" | "-"] digit+\n\nNote that the integer and exponent parts are always interpreted using\nradix 10. For example, "077e010" is legal, and denotes the same number\nas "77e10". The allowed range of floating point literals is\nimplementation-dependent. Some examples of floating point literals:\n\n 3.14 10. .001 1e100 3.14e-10 0e0\n\nNote that numeric literals do not include a sign; a phrase like "-1"\nis actually an expression composed of the unary operator "-" and the\nliteral "1".\n', + 'for': '\nThe "for" statement\n*******************\n\nThe "for" statement is used to iterate over the elements of a sequence\n(such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n"expression_list". The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a "StopIteration" exception),\nthe suite in the "else" clause, if present, is executed, and the loop\nterminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and continues\nwith the next item, or with the "else" clause if there was no next\nitem.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function "range()" returns an\niterator of integers suitable to emulate the effect of Pascal\'s "for i\n:= a to b do"; e.g., "list(range(3))" returns the list "[0, 1, 2]".\n\nNote: There is a subtlety when the sequence is being modified by the\n loop (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n', + 'formatstrings': '\nFormat String Syntax\n********************\n\nThe "str.format()" method and the "Formatter" class share the same\nsyntax for format strings (although in the case of "Formatter",\nsubclasses can define their own format string syntax).\n\nFormat strings contain "replacement fields" surrounded by curly braces\n"{}". Anything that is not contained in braces is considered literal\ntext, which is copied unchanged to the output. If you need to include\na brace character in the literal text, it can be escaped by doubling:\n"{{" and "}}".\n\nThe grammar for a replacement field is as follows:\n\n replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}"\n field_name ::= arg_name ("." attribute_name | "[" element_index "]")*\n arg_name ::= [identifier | integer]\n attribute_name ::= identifier\n element_index ::= integer | index_string\n index_string ::= +\n conversion ::= "r" | "s" | "a"\n format_spec ::= \n\nIn less formal terms, the replacement field can start with a\n*field_name* that specifies the object whose value is to be formatted\nand inserted into the output instead of the replacement field. The\n*field_name* is optionally followed by a *conversion* field, which is\npreceded by an exclamation point "\'!\'", and a *format_spec*, which is\npreceded by a colon "\':\'". These specify a non-default format for the\nreplacement value.\n\nSee also the *Format Specification Mini-Language* section.\n\nThe *field_name* itself begins with an *arg_name* that is either a\nnumber or a keyword. If it\'s a number, it refers to a positional\nargument, and if it\'s a keyword, it refers to a named keyword\nargument. If the numerical arg_names in a format string are 0, 1, 2,\n... in sequence, they can all be omitted (not just some) and the\nnumbers 0, 1, 2, ... will be automatically inserted in that order.\nBecause *arg_name* is not quote-delimited, it is not possible to\nspecify arbitrary dictionary keys (e.g., the strings "\'10\'" or\n"\':-]\'") within a format string. The *arg_name* can be followed by any\nnumber of index or attribute expressions. An expression of the form\n"\'.name\'" selects the named attribute using "getattr()", while an\nexpression of the form "\'[index]\'" does an index lookup using\n"__getitem__()".\n\nChanged in version 3.1: The positional argument specifiers can be\nomitted, so "\'{} {}\'" is equivalent to "\'{0} {1}\'".\n\nSome simple format string examples:\n\n "First, thou shalt count to {0}" # References first positional argument\n "Bring me a {}" # Implicitly references the first positional argument\n "From {} to {}" # Same as "From {0} to {1}"\n "My quest is {name}" # References keyword argument \'name\'\n "Weight in tons {0.weight}" # \'weight\' attribute of first positional arg\n "Units destroyed: {players[0]}" # First element of keyword argument \'players\'.\n\nThe *conversion* field causes a type coercion before formatting.\nNormally, the job of formatting a value is done by the "__format__()"\nmethod of the value itself. However, in some cases it is desirable to\nforce a type to be formatted as a string, overriding its own\ndefinition of formatting. By converting the value to a string before\ncalling "__format__()", the normal formatting logic is bypassed.\n\nThree conversion flags are currently supported: "\'!s\'" which calls\n"str()" on the value, "\'!r\'" which calls "repr()" and "\'!a\'" which\ncalls "ascii()".\n\nSome examples:\n\n "Harold\'s a clever {0!s}" # Calls str() on the argument first\n "Bring out the holy {name!r}" # Calls repr() on the argument first\n "More {!a}" # Calls ascii() on the argument first\n\nThe *format_spec* field contains a specification of how the value\nshould be presented, including such details as field width, alignment,\npadding, decimal precision and so on. Each value type can define its\nown "formatting mini-language" or interpretation of the *format_spec*.\n\nMost built-in types support a common formatting mini-language, which\nis described in the next section.\n\nA *format_spec* field can also include nested replacement fields\nwithin it. These nested replacement fields can contain only a field\nname; conversion flags and format specifications are not allowed. The\nreplacement fields within the format_spec are substituted before the\n*format_spec* string is interpreted. This allows the formatting of a\nvalue to be dynamically specified.\n\nSee the *Format examples* section for some examples.\n\n\nFormat Specification Mini-Language\n==================================\n\n"Format specifications" are used within replacement fields contained\nwithin a format string to define how individual values are presented\n(see *Format String Syntax*). They can also be passed directly to the\nbuilt-in "format()" function. Each formattable type may define how\nthe format specification is to be interpreted.\n\nMost built-in types implement the following options for format\nspecifications, although some of the formatting options are only\nsupported by the numeric types.\n\nA general convention is that an empty format string ("""") produces\nthe same result as if you had called "str()" on the value. A non-empty\nformat string typically modifies the result.\n\nThe general form of a *standard format specifier* is:\n\n format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]\n fill ::= \n align ::= "<" | ">" | "=" | "^"\n sign ::= "+" | "-" | " "\n width ::= integer\n precision ::= integer\n type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"\n\nIf a valid *align* value is specified, it can be preceded by a *fill*\ncharacter that can be any character and defaults to a space if\nomitted. Note that it is not possible to use "{" and "}" as *fill*\nchar while using the "str.format()" method; this limitation however\ndoesn\'t affect the "format()" function.\n\nThe meaning of the various alignment options is as follows:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | "\'<\'" | Forces the field to be left-aligned within the available |\n +-----------+------------------------------------------------------------+\n | "\'>\'" | Forces the field to be right-aligned within the available |\n +-----------+------------------------------------------------------------+\n | "\'=\'" | Forces the padding to be placed after the sign (if any) |\n +-----------+------------------------------------------------------------+\n | "\'^\'" | Forces the field to be centered within the available |\n +-----------+------------------------------------------------------------+\n\nNote that unless a minimum field width is defined, the field width\nwill always be the same size as the data to fill it, so that the\nalignment option has no meaning in this case.\n\nThe *sign* option is only valid for number types, and can be one of\nthe following:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | "\'+\'" | indicates that a sign should be used for both positive as |\n +-----------+------------------------------------------------------------+\n | "\'-\'" | indicates that a sign should be used only for negative |\n +-----------+------------------------------------------------------------+\n | space | indicates that a leading space should be used on positive |\n +-----------+------------------------------------------------------------+\n\nThe "\'#\'" option causes the "alternate form" to be used for the\nconversion. The alternate form is defined differently for different\ntypes. This option is only valid for integer, float, complex and\nDecimal types. For integers, when binary, octal, or hexadecimal output\nis used, this option adds the prefix respective "\'0b\'", "\'0o\'", or\n"\'0x\'" to the output value. For floats, complex and Decimal the\nalternate form causes the result of the conversion to always contain a\ndecimal-point character, even if no digits follow it. Normally, a\ndecimal-point character appears in the result of these conversions\nonly if a digit follows it. In addition, for "\'g\'" and "\'G\'"\nconversions, trailing zeros are not removed from the result.\n\nThe "\',\'" option signals the use of a comma for a thousands separator.\nFor a locale aware separator, use the "\'n\'" integer presentation type\ninstead.\n\nChanged in version 3.1: Added the "\',\'" option (see also **PEP 378**).\n\n*width* is a decimal integer defining the minimum field width. If not\nspecified, then the field width will be determined by the content.\n\nPreceding the *width* field by a zero ("\'0\'") character enables sign-\naware zero-padding for numeric types. This is equivalent to a *fill*\ncharacter of "\'0\'" with an *alignment* type of "\'=\'".\n\nThe *precision* is a decimal number indicating how many digits should\nbe displayed after the decimal point for a floating point value\nformatted with "\'f\'" and "\'F\'", or before and after the decimal point\nfor a floating point value formatted with "\'g\'" or "\'G\'". For non-\nnumber types the field indicates the maximum field size - in other\nwords, how many characters will be used from the field content. The\n*precision* is not allowed for integer values.\n\nFinally, the *type* determines how the data should be presented.\n\nThe available string presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | "\'s\'" | String format. This is the default type for strings and |\n +-----------+------------------------------------------------------------+\n | None | The same as "\'s\'". |\n +-----------+------------------------------------------------------------+\n\nThe available integer presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | "\'b\'" | Binary format. Outputs the number in base 2. |\n +-----------+------------------------------------------------------------+\n | "\'c\'" | Character. Converts the integer to the corresponding |\n +-----------+------------------------------------------------------------+\n | "\'d\'" | Decimal Integer. Outputs the number in base 10. |\n +-----------+------------------------------------------------------------+\n | "\'o\'" | Octal format. Outputs the number in base 8. |\n +-----------+------------------------------------------------------------+\n | "\'x\'" | Hex format. Outputs the number in base 16, using lower- |\n +-----------+------------------------------------------------------------+\n | "\'X\'" | Hex format. Outputs the number in base 16, using upper- |\n +-----------+------------------------------------------------------------+\n | "\'n\'" | Number. This is the same as "\'d\'", except that it uses the |\n +-----------+------------------------------------------------------------+\n | None | The same as "\'d\'". |\n +-----------+------------------------------------------------------------+\n\nIn addition to the above presentation types, integers can be formatted\nwith the floating point presentation types listed below (except "\'n\'"\nand None). When doing so, "float()" is used to convert the integer to\na floating point number before formatting.\n\nThe available presentation types for floating point and decimal values\nare:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | "\'e\'" | Exponent notation. Prints the number in scientific |\n +-----------+------------------------------------------------------------+\n | "\'E\'" | Exponent notation. Same as "\'e\'" except it uses an upper |\n +-----------+------------------------------------------------------------+\n | "\'f\'" | Fixed point. Displays the number as a fixed-point number. |\n +-----------+------------------------------------------------------------+\n | "\'F\'" | Fixed point. Same as "\'f\'", but converts "nan" to "NAN" |\n +-----------+------------------------------------------------------------+\n | "\'g\'" | General format. For a given precision "p >= 1", this |\n +-----------+------------------------------------------------------------+\n | "\'G\'" | General format. Same as "\'g\'" except switches to "\'E\'" if |\n +-----------+------------------------------------------------------------+\n | "\'n\'" | Number. This is the same as "\'g\'", except that it uses the |\n +-----------+------------------------------------------------------------+\n | "\'%\'" | Percentage. Multiplies the number by 100 and displays in |\n +-----------+------------------------------------------------------------+\n | None | Similar to "\'g\'", except with at least one digit past the |\n +-----------+------------------------------------------------------------+\n\n\nFormat examples\n===============\n\nThis section contains examples of the new format syntax and comparison\nwith the old "%"-formatting.\n\nIn most of the cases the syntax is similar to the old "%"-formatting,\nwith the addition of the "{}" and with ":" used instead of "%". For\nexample, "\'%03.2f\'" can be translated to "\'{:03.2f}\'".\n\nThe new format syntax also supports new and different options, shown\nin the follow examples.\n\nAccessing arguments by position:\n\n >>> \'{0}, {1}, {2}\'.format(\'a\', \'b\', \'c\')\n \'a, b, c\'\n >>> \'{}, {}, {}\'.format(\'a\', \'b\', \'c\') # 3.1+ only\n \'a, b, c\'\n >>> \'{2}, {1}, {0}\'.format(\'a\', \'b\', \'c\')\n \'c, b, a\'\n >>> \'{2}, {1}, {0}\'.format(*\'abc\') # unpacking argument sequence\n \'c, b, a\'\n >>> \'{0}{1}{0}\'.format(\'abra\', \'cad\') # arguments\' indices can be repeated\n \'abracadabra\'\n\nAccessing arguments by name:\n\n >>> \'Coordinates: {latitude}, {longitude}\'.format(latitude=\'37.24N\', longitude=\'-115.81W\')\n \'Coordinates: 37.24N, -115.81W\'\n >>> coord = {\'latitude\': \'37.24N\', \'longitude\': \'-115.81W\'}\n >>> \'Coordinates: {latitude}, {longitude}\'.format(**coord)\n \'Coordinates: 37.24N, -115.81W\'\n\nAccessing arguments\' attributes:\n\n >>> c = 3-5j\n >>> (\'The complex number {0} is formed from the real part {0.real} \'\n ... \'and the imaginary part {0.imag}.\').format(c)\n \'The complex number (3-5j) is formed from the real part 3.0 and the imaginary part -5.0.\'\n >>> class Point:\n ... def __init__(self, x, y):\n ... self.x, self.y = x, y\n ... def __str__(self):\n ... return \'Point({self.x}, {self.y})\'.format(self=self)\n ...\n >>> str(Point(4, 2))\n \'Point(4, 2)\'\n\nAccessing arguments\' items:\n\n >>> coord = (3, 5)\n >>> \'X: {0[0]}; Y: {0[1]}\'.format(coord)\n \'X: 3; Y: 5\'\n\nReplacing "%s" and "%r":\n\n >>> "repr() shows quotes: {!r}; str() doesn\'t: {!s}".format(\'test1\', \'test2\')\n "repr() shows quotes: \'test1\'; str() doesn\'t: test2"\n\nAligning the text and specifying a width:\n\n >>> \'{:<30}\'.format(\'left aligned\')\n \'left aligned \'\n >>> \'{:>30}\'.format(\'right aligned\')\n \' right aligned\'\n >>> \'{:^30}\'.format(\'centered\')\n \' centered \'\n >>> \'{:*^30}\'.format(\'centered\') # use \'*\' as a fill char\n \'***********centered***********\'\n\nReplacing "%+f", "%-f", and "% f" and specifying a sign:\n\n >>> \'{:+f}; {:+f}\'.format(3.14, -3.14) # show it always\n \'+3.140000; -3.140000\'\n >>> \'{: f}; {: f}\'.format(3.14, -3.14) # show a space for positive numbers\n \' 3.140000; -3.140000\'\n >>> \'{:-f}; {:-f}\'.format(3.14, -3.14) # show only the minus -- same as \'{:f}; {:f}\'\n \'3.140000; -3.140000\'\n\nReplacing "%x" and "%o" and converting the value to different bases:\n\n >>> # format also supports binary numbers\n >>> "int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}".format(42)\n \'int: 42; hex: 2a; oct: 52; bin: 101010\'\n >>> # with 0x, 0o, or 0b as prefix:\n >>> "int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42)\n \'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010\'\n\nUsing the comma as a thousands separator:\n\n >>> \'{:,}\'.format(1234567890)\n \'1,234,567,890\'\n\nExpressing a percentage:\n\n >>> points = 19\n >>> total = 22\n >>> \'Correct answers: {:.2%}\'.format(points/total)\n \'Correct answers: 86.36%\'\n\nUsing type-specific formatting:\n\n >>> import datetime\n >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)\n >>> \'{:%Y-%m-%d %H:%M:%S}\'.format(d)\n \'2010-07-04 12:15:58\'\n\nNesting arguments and more complex examples:\n\n >>> for align, text in zip(\'<^>\', [\'left\', \'center\', \'right\']):\n ... \'{0:{fill}{align}16}\'.format(text, fill=align, align=align)\n ...\n \'left<<<<<<<<<<<<\'\n \'^^^^^center^^^^^\'\n \'>>>>>>>>>>>right\'\n >>>\n >>> octets = [192, 168, 0, 1]\n >>> \'{:02X}{:02X}{:02X}{:02X}\'.format(*octets)\n \'C0A80001\'\n >>> int(_, 16)\n 3232235521\n >>>\n >>> width = 5\n >>> for num in range(5,12): #doctest: +NORMALIZE_WHITESPACE\n ... for base in \'dXob\':\n ... print(\'{0:{width}{base}}\'.format(num, base=base, width=width), end=\' \')\n ... print()\n ...\n 5 5 5 101\n 6 6 6 110\n 7 7 7 111\n 8 8 10 1000\n 9 9 11 1001\n 10 A 12 1010\n 11 B 13 1011\n', + 'function': '\nFunction definitions\n********************\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)* ["," "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more *parameters* have the form *parameter* "="\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding *argument* may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the ""*"" must also have a default value --- this\nis a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated from left to right when the\nfunction definition is executed.** This means that the expression is\nevaluated once, when the function is defined, and that the same "pre-\ncomputed" value is used for each call. This is especially important\nto understand when a default parameter is a mutable object, such as a\nlist or a dictionary: if the function modifies the object (e.g. by\nappending an item to a list), the default value is in effect modified.\nThis is generally not what was intended. A way around this is to use\n"None" as the default, and explicitly test for it in the body of the\nfunction, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n""*identifier"" is present, it is initialized to a tuple receiving any\nexcess positional parameters, defaulting to the empty tuple. If the\nform ""**identifier"" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after ""*"" or ""*identifier"" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "": expression"" following\nthe parameter name. Any parameter may have an annotation even those\nof the form "*identifier" or "**identifier". Functions may have\n"return" annotation of the form ""-> expression"" after the parameter\nlist. These annotations can be any valid Python expression and are\nevaluated when the function definition is executed. Annotations may\nbe evaluated in a different order than they appear in the source code.\nThe presence of annotations does not change the semantics of a\nfunction. The annotation values are available as values of a\ndictionary keyed by the parameters\' names in the "__annotations__"\nattribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda\nexpressions, described in section *Lambdas*. Note that the lambda\nexpression is merely a shorthand for a simplified function definition;\na function defined in a ""def"" statement can be passed around or\nassigned to another name just like a function defined by a lambda\nexpression. The ""def"" form is actually more powerful since it\nallows the execution of multiple statements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A ""def""\nstatement executed inside a function definition defines a local\nfunction that can be returned or passed around. Free variables used\nin the nested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\nSee also: **PEP 3107** - Function Annotations\n\n The original specification for function annotations.\n', + 'global': '\nThe "global" statement\n**********************\n\n global_stmt ::= "global" identifier ("," identifier)*\n\nThe "global" statement is a declaration which holds for the entire\ncurrent code block. It means that the listed identifiers are to be\ninterpreted as globals. It would be impossible to assign to a global\nvariable without "global", although free variables may refer to\nglobals without being declared global.\n\nNames listed in a "global" statement must not be used in the same code\nblock textually preceding that "global" statement.\n\nNames listed in a "global" statement must not be defined as formal\nparameters or in a "for" loop control target, "class" definition,\nfunction definition, or "import" statement.\n\n**CPython implementation detail:** The current implementation does not\nenforce the latter two restrictions, but programs should not abuse\nthis freedom, as future implementations may enforce them or silently\nchange the meaning of the program.\n\n**Programmer\'s note:** the "global" is a directive to the parser. It\napplies only to code parsed at the same time as the "global"\nstatement. In particular, a "global" statement contained in a string\nor code object supplied to the built-in "exec()" function does not\naffect the code block *containing* the function call, and code\ncontained in such a string is unaffected by "global" statements in the\ncode containing the function call. The same applies to the "eval()"\nand "compile()" functions.\n', + 'id-classes': '\nReserved classes of identifiers\n*******************************\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n"_*"\n Not imported by "from module import *". The special identifier "_"\n is used in the interactive interpreter to store the result of the\n last evaluation; it is stored in the "builtins" module. When not\n in interactive mode, "_" has no special meaning and is not defined.\n See section *The import statement*.\n\n Note: The name "_" is often used in conjunction with\n internationalization; refer to the documentation for the\n "gettext" module for more information on this convention.\n\n"__*__"\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of "__*__" names, in any context, that does not\n follow explicitly documented use, is subject to breakage without\n warning.\n\n"__*"\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', + 'identifiers': '\nIdentifiers and keywords\n************************\n\nIdentifiers (also referred to as *names*) are described by the\nfollowing lexical definitions.\n\nThe syntax of identifiers in Python is based on the Unicode standard\nannex UAX-31, with elaboration and changes as defined below; see also\n**PEP 3131** for further details.\n\nWithin the ASCII range (U+0001..U+007F), the valid characters for\nidentifiers are the same as in Python 2.x: the uppercase and lowercase\nletters "A" through "Z", the underscore "_" and, except for the first\ncharacter, the digits "0" through "9".\n\nPython 3.0 introduces additional characters from outside the ASCII\nrange (see **PEP 3131**). For these characters, the classification\nuses the version of the Unicode Character Database as included in the\n"unicodedata" module.\n\nIdentifiers are unlimited in length. Case is significant.\n\n identifier ::= xid_start xid_continue*\n id_start ::= \n id_continue ::= \n xid_start ::= \n xid_continue ::= \n\nThe Unicode category codes mentioned above stand for:\n\n* *Lu* - uppercase letters\n\n* *Ll* - lowercase letters\n\n* *Lt* - titlecase letters\n\n* *Lm* - modifier letters\n\n* *Lo* - other letters\n\n* *Nl* - letter numbers\n\n* *Mn* - nonspacing marks\n\n* *Mc* - spacing combining marks\n\n* *Nd* - decimal numbers\n\n* *Pc* - connector punctuations\n\n* *Other_ID_Start* - explicit list of characters in PropList.txt to\n support backwards compatibility\n\n* *Other_ID_Continue* - likewise\n\nAll identifiers are converted into the normal form NFKC while parsing;\ncomparison of identifiers is based on NFKC.\n\nA non-normative HTML file listing all valid identifier characters for\nUnicode 4.1 can be found at http://www.dcl.hpi.uni-\npotsdam.de/home/loewis/table-3131.html.\n\n\nKeywords\n========\n\nThe following identifiers are used as reserved words, or *keywords* of\nthe language, and cannot be used as ordinary identifiers. They must\nbe spelled exactly as written here:\n\n False class finally is return\n None continue for lambda try\n True def from nonlocal while\n and del global not with\n as elif if or yield\n assert else import pass\n break except in raise\n\n\nReserved classes of identifiers\n===============================\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n"_*"\n Not imported by "from module import *". The special identifier "_"\n is used in the interactive interpreter to store the result of the\n last evaluation; it is stored in the "builtins" module. When not\n in interactive mode, "_" has no special meaning and is not defined.\n See section *The import statement*.\n\n Note: The name "_" is often used in conjunction with\n internationalization; refer to the documentation for the\n "gettext" module for more information on this convention.\n\n"__*__"\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of "__*__" names, in any context, that does not\n follow explicitly documented use, is subject to breakage without\n warning.\n\n"__*"\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', + 'if': '\nThe "if" statement\n******************\n\nThe "if" statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the "if" statement is executed or evaluated).\nIf all expressions are false, the suite of the "else" clause, if\npresent, is executed.\n', + 'imaginary': '\nImaginary literals\n******************\n\nImaginary literals are described by the following lexical definitions:\n\n imagnumber ::= (floatnumber | intpart) ("j" | "J")\n\nAn imaginary literal yields a complex number with a real part of 0.0.\nComplex numbers are represented as a pair of floating point numbers\nand have the same restrictions on their range. To create a complex\nnumber with a nonzero real part, add a floating point number to it,\ne.g., "(3+4j)". Some examples of imaginary literals:\n\n 3.14j 10.j 10j .001j 1e100j 3.14e-10j\n', + 'import': '\nThe "import" statement\n**********************\n\n import_stmt ::= "import" module ["as" name] ( "," module ["as" name] )*\n | "from" relative_module "import" identifier ["as" name]\n ( "," identifier ["as" name] )*\n | "from" relative_module "import" "(" identifier ["as" name]\n ( "," identifier ["as" name] )* [","] ")"\n | "from" module "import" "*"\n module ::= (identifier ".")* identifier\n relative_module ::= "."* module | "."+\n name ::= identifier\n\nThe basic import statement (no "from" clause) is executed in two\nsteps:\n\n1. find a module, loading and initializing it if necessary\n\n2. define a name or names in the local namespace for the scope\n where the "import" statement occurs.\n\nWhen the statement contains multiple clauses (separated by commas) the\ntwo steps are carried out separately for each clause, just as though\nthe clauses had been separated out into individiual import statements.\n\nThe details of the first step, finding and loading modules is\ndescribed in greater detail in the section on the *import system*,\nwhich also describes the various types of packages and modules that\ncan be imported, as well as all the hooks that can be used to\ncustomize the import system. Note that failures in this step may\nindicate either that the module could not be located, *or* that an\nerror occurred while initializing the module, which includes execution\nof the module\'s code.\n\nIf the requested module is retrieved successfully, it will be made\navailable in the local namespace in one of three ways:\n\n* If the module name is followed by "as", then the name following\n "as" is bound directly to the imported module.\n\n* If no other name is specified, and the module being imported is a\n top level module, the module\'s name is bound in the local namespace\n as a reference to the imported module\n\n* If the module being imported is *not* a top level module, then the\n name of the top level package that contains the module is bound in\n the local namespace as a reference to the top level package. The\n imported module must be accessed using its full qualified name\n rather than directly\n\nThe "from" form uses a slightly more complex process:\n\n1. find the module specified in the "from" clause loading and\n initializing it if necessary;\n\n2. for each of the identifiers specified in the "import" clauses:\n\n 1. check if the imported module has an attribute by that name\n\n 2. if not, attempt to import a submodule with that name and then\n check the imported module again for that attribute\n\n 3. if the attribute is not found, "ImportError" is raised.\n\n 4. otherwise, a reference to that value is bound in the local\n namespace, using the name in the "as" clause if it is present,\n otherwise using the attribute name\n\nExamples:\n\n import foo # foo imported and bound locally\n import foo.bar.baz # foo.bar.baz imported, foo bound locally\n import foo.bar.baz as fbb # foo.bar.baz imported and bound as fbb\n from foo.bar import baz # foo.bar.baz imported and bound as baz\n from foo import attr # foo imported and foo.attr bound as attr\n\nIf the list of identifiers is replaced by a star ("\'*\'"), all public\nnames defined in the module are bound in the local namespace for the\nscope where the "import" statement occurs.\n\nThe *public names* defined by a module are determined by checking the\nmodule\'s namespace for a variable named "__all__"; if defined, it must\nbe a sequence of strings which are names defined or imported by that\nmodule. The names given in "__all__" are all considered public and\nare required to exist. If "__all__" is not defined, the set of public\nnames includes all names found in the module\'s namespace which do not\nbegin with an underscore character ("\'_\'"). "__all__" should contain\nthe entire public API. It is intended to avoid accidentally exporting\nitems that are not part of the API (such as library modules which were\nimported and used within the module).\n\nThe "from" form with "*" may only occur in a module scope. The wild\ncard form of import --- "import *" --- is only allowed at the module\nlevel. Attempting to use it in class or function definitions will\nraise a "SyntaxError".\n\nWhen specifying what module to import you do not have to specify the\nabsolute name of the module. When a module or package is contained\nwithin another package it is possible to make a relative import within\nthe same top package without having to mention the package name. By\nusing leading dots in the specified module or package after "from" you\ncan specify how high to traverse up the current package hierarchy\nwithout specifying exact names. One leading dot means the current\npackage where the module making the import exists. Two dots means up\none package level. Three dots is up two levels, etc. So if you execute\n"from . import mod" from a module in the "pkg" package then you will\nend up importing "pkg.mod". If you execute "from ..subpkg2 import mod"\nfrom within "pkg.subpkg1" you will import "pkg.subpkg2.mod". The\nspecification for relative imports is contained within **PEP 328**.\n\n"importlib.import_module()" is provided to support applications that\ndetermine which modules need to be loaded dynamically.\n\n\nFuture statements\n=================\n\nA *future statement* is a directive to the compiler that a particular\nmodule should be compiled using syntax or semantics that will be\navailable in a specified future release of Python. The future\nstatement is intended to ease migration to future versions of Python\nthat introduce incompatible changes to the language. It allows use of\nthe new features on a per-module basis before the release in which the\nfeature becomes standard.\n\n future_statement ::= "from" "__future__" "import" feature ["as" name]\n ("," feature ["as" name])*\n | "from" "__future__" "import" "(" feature ["as" name]\n ("," feature ["as" name])* [","] ")"\n feature ::= identifier\n name ::= identifier\n\nA future statement must appear near the top of the module. The only\nlines that can appear before a future statement are:\n\n* the module docstring (if any),\n\n* comments,\n\n* blank lines, and\n\n* other future statements.\n\nThe features recognized by Python 3.0 are "absolute_import",\n"division", "generators", "unicode_literals", "print_function",\n"nested_scopes" and "with_statement". They are all redundant because\nthey are always enabled, and only kept for backwards compatibility.\n\nA future statement is recognized and treated specially at compile\ntime: Changes to the semantics of core constructs are often\nimplemented by generating different code. It may even be the case\nthat a new feature introduces new incompatible syntax (such as a new\nreserved word), in which case the compiler may need to parse the\nmodule differently. Such decisions cannot be pushed off until\nruntime.\n\nFor any given release, the compiler knows which feature names have\nbeen defined, and raises a compile-time error if a future statement\ncontains a feature not known to it.\n\nThe direct runtime semantics are the same as for any import statement:\nthere is a standard module "__future__", described later, and it will\nbe imported in the usual way at the time the future statement is\nexecuted.\n\nThe interesting runtime semantics depend on the specific feature\nenabled by the future statement.\n\nNote that there is nothing special about the statement:\n\n import __future__ [as name]\n\nThat is not a future statement; it\'s an ordinary import statement with\nno special semantics or syntax restrictions.\n\nCode compiled by calls to the built-in functions "exec()" and\n"compile()" that occur in a module "M" containing a future statement\nwill, by default, use the new syntax or semantics associated with the\nfuture statement. This can be controlled by optional arguments to\n"compile()" --- see the documentation of that function for details.\n\nA future statement typed at an interactive interpreter prompt will\ntake effect for the rest of the interpreter session. If an\ninterpreter is started with the *-i* option, is passed a script name\nto execute, and the script includes a future statement, it will be in\neffect in the interactive session started after the script is\nexecuted.\n\nSee also: **PEP 236** - Back to the __future__\n\n The original proposal for the __future__ mechanism.\n', + 'in': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like "a < b < c" have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: "True" or "False".\n\nComparisons can be chained arbitrarily, e.g., "x < y <= z" is\nequivalent to "x < y and y <= z", except that "y" is evaluated only\nonce (but in both cases "z" is not evaluated at all when "x < y" is\nfound to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then "a op1 b op2 c ... y\nopN z" is equivalent to "a op1 b and b op2 c and ... y opN z", except\nthat each expression is evaluated at most once.\n\nNote that "a op1 b op2 c" doesn\'t imply any kind of comparison between\n*a* and *c*, so that, e.g., "x < y > z" is perfectly legal (though\nperhaps not pretty).\n\nThe operators "<", ">", "==", ">=", "<=", and "!=" compare the values\nof two objects. The objects need not have the same type. If both are\nnumbers, they are converted to a common type. Otherwise, the "==" and\n"!=" operators *always* consider objects of different types to be\nunequal, while the "<", ">", ">=" and "<=" operators raise a\n"TypeError" when comparing objects of different types that do not\nimplement these operators for the given pair of types. You can\ncontrol comparison behavior of objects of non-built-in types by\ndefining rich comparison methods like "__gt__()", described in section\n*Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values "float(\'NaN\')" and "Decimal(\'NaN\')" are special. The\n are identical to themselves, "x is x" but are not equal to\n themselves, "x != x". Additionally, comparing any value to a\n not-a-number value will return "False". For example, both "3 <\n float(\'NaN\')" and "float(\'NaN\') < 3" will return "False".\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric\n equivalents (the result of the built-in function "ord()") of their\n characters. [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison\n of corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, "[1,2,x] <= [1,2,y]" has the same\n value as "x <= y". If the corresponding element does not exist, the\n shorter sequence is ordered first (for example, "[1,2] < [1,2,3]").\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same "(key, value)" pairs. Order comparisons "(\'<\', \'<=\', \'>=\',\n \'>\')" raise "TypeError".\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets "{1,2}" and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, "min()", "max()", and "sorted()" produce undefined\n results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they\n are the same object; the choice whether one object is considered\n smaller or larger than another one is made arbitrarily but\n consistently within one execution of a program.\n\nComparison of objects of the differing types depends on whether either\nof the types provide explicit support for the comparison. Most\nnumeric types can be compared with one another. When cross-type\ncomparison is not supported, the comparison method returns\n"NotImplemented".\n\nThe operators "in" and "not in" test for membership. "x in s"\nevaluates to true if *x* is a member of *s*, and false otherwise. "x\nnot in s" returns the negation of "x in s". All built-in sequences\nand set types support this as well as dictionary, for which "in" tests\nwhether a the dictionary has a given key. For container types such as\nlist, tuple, set, frozenset, dict, or collections.deque, the\nexpression "x in y" is equivalent to "any(x is e or x == e for e in\ny)".\n\nFor the string and bytes types, "x in y" is true if and only if *x* is\na substring of *y*. An equivalent test is "y.find(x) != -1". Empty\nstrings are always considered to be a substring of any other string,\nso """ in "abc"" will return "True".\n\nFor user-defined classes which define the "__contains__()" method, "x\nin y" is true if and only if "y.__contains__(x)" is true.\n\nFor user-defined classes which do not define "__contains__()" but do\ndefine "__iter__()", "x in y" is true if some value "z" with "x == z"\nis produced while iterating over "y". If an exception is raised\nduring the iteration, it is as if "in" raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n"__getitem__()", "x in y" is true if and only if there is a non-\nnegative integer index *i* such that "x == y[i]", and all lower\ninteger indices do not raise "IndexError" exception. (If any other\nexception is raised, it is as if "in" raised that exception).\n\nThe operator "not in" is defined to have the inverse true value of\n"in".\n\nThe operators "is" and "is not" test for object identity: "x is y" is\ntrue if and only if *x* and *y* are the same object. "x is not y"\nyields the inverse truth value. [4]\n', 'integers': '\nInteger literals\n****************\n\nInteger literals are described by the following lexical definitions:\n\n integer ::= decimalinteger | octinteger | hexinteger | bininteger\n decimalinteger ::= nonzerodigit digit* | "0"+\n nonzerodigit ::= "1"..."9"\n digit ::= "0"..."9"\n octinteger ::= "0" ("o" | "O") octdigit+\n hexinteger ::= "0" ("x" | "X") hexdigit+\n bininteger ::= "0" ("b" | "B") bindigit+\n octdigit ::= "0"..."7"\n hexdigit ::= digit | "a"..."f" | "A"..."F"\n bindigit ::= "0" | "1"\n\nThere is no limit for the length of integer literals apart from what\ncan be stored in available memory.\n\nNote that leading zeros in a non-zero decimal number are not allowed.\nThis is for disambiguation with C-style octal literals, which Python\nused before version 3.0.\n\nSome examples of integer literals:\n\n 7 2147483647 0o177 0b100110111\n 3 79228162514264337593543950336 0o377 0x100000000\n 79228162514264337593543950336 0xdeadbeef\n', - 'lambda': '\nLambdas\n*******\n\n lambda_expr ::= "lambda" [parameter_list]: expression\n lambda_expr_nocond ::= "lambda" [parameter_list]: expression_nocond\n\nLambda expressions (sometimes called lambda forms) have the same\nsyntactic position as expressions. They are a shorthand to create\nanonymous functions; the expression ``lambda arguments: expression``\nyields a function object. The unnamed object behaves like a function\nobject defined with\n\n def (arguments):\n return expression\n\nSee section *Function definitions* for the syntax of parameter lists.\nNote that functions created with lambda expressions cannot contain\nstatements or annotations.\n', + 'lambda': '\nLambdas\n*******\n\n lambda_expr ::= "lambda" [parameter_list]: expression\n lambda_expr_nocond ::= "lambda" [parameter_list]: expression_nocond\n\nLambda expressions (sometimes called lambda forms) have the same\nsyntactic position as expressions. They are a shorthand to create\nanonymous functions; the expression "lambda arguments: expression"\nyields a function object. The unnamed object behaves like a function\nobject defined with\n\n def (arguments):\n return expression\n\nSee section *Function definitions* for the syntax of parameter lists.\nNote that functions created with lambda expressions cannot contain\nstatements or annotations.\n', 'lists': '\nList displays\n*************\n\nA list display is a possibly empty series of expressions enclosed in\nsquare brackets:\n\n list_display ::= "[" [expression_list | comprehension] "]"\n\nA list display yields a new list object, the contents being specified\nby either a list of expressions or a comprehension. When a comma-\nseparated list of expressions is supplied, its elements are evaluated\nfrom left to right and placed into the list object in that order.\nWhen a comprehension is supplied, the list is constructed from the\nelements resulting from the comprehension.\n', - 'naming': "\nNaming and binding\n******************\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\non the interpreter command line the first argument) is a code block.\nA script command (a command specified on the interpreter command line\nwith the '**-c**' option) is a code block. The string argument passed\nto the built-in functions ``eval()`` and ``exec()`` is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block's execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block's *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as ``nonlocal``. If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a ``NameError`` exception is raised.\nIf the name refers to a local variable that has not been bound, a\n``UnboundLocalError`` exception is raised. ``UnboundLocalError`` is a\nsubclass of ``NameError``.\n\nThe following constructs bind names: formal parameters to functions,\n``import`` statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, ``for`` loop header, or\nafter ``as`` in a ``with`` statement or ``except`` clause. The\n``import`` statement of the form ``from ... import *`` binds all names\ndefined in the imported module, except those beginning with an\nunderscore. This form may only be used at the module level.\n\nA target occurring in a ``del`` statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name).\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the ``global`` statement occurs within a block, all uses of the\nname specified in the statement refer to the binding of that name in\nthe top-level namespace. Names are resolved in the top-level\nnamespace by searching the global namespace, i.e. the namespace of the\nmodule containing the code block, and the builtins namespace, the\nnamespace of the module ``builtins``. The global namespace is\nsearched first. If the name is not found there, the builtins\nnamespace is searched. The global statement must precede all uses of\nthe name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name ``__builtins__`` in its\nglobal namespace; this should be a dictionary or a module (in the\nlatter case the module's dictionary is used). By default, when in the\n``__main__`` module, ``__builtins__`` is the built-in module\n``builtins``; when in any other module, ``__builtins__`` is an alias\nfor the dictionary of the ``builtins`` module itself.\n``__builtins__`` can be set to a user-created dictionary to create a\nweak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n``__builtins__``; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should ``import``\nthe ``builtins`` module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n``__main__``.\n\nThe ``global`` statement has the same scope as a name binding\noperation in the same block. If the nearest enclosing scope for a\nfree variable contains a global statement, the free variable is\ntreated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n=================================\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n", - 'nonlocal': '\nThe ``nonlocal`` statement\n**************************\n\n nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*\n\nThe ``nonlocal`` statement causes the listed identifiers to refer to\npreviously bound variables in the nearest enclosing scope. This is\nimportant because the default behavior for binding is to search the\nlocal namespace first. The statement allows encapsulated code to\nrebind variables outside of the local scope besides the global\n(module) scope.\n\nNames listed in a ``nonlocal`` statement, unlike to those listed in a\n``global`` statement, must refer to pre-existing bindings in an\nenclosing scope (the scope in which a new binding should be created\ncannot be determined unambiguously).\n\nNames listed in a ``nonlocal`` statement must not collide with pre-\nexisting bindings in the local scope.\n\nSee also:\n\n **PEP 3104** - Access to Names in Outer Scopes\n The specification for the ``nonlocal`` statement.\n', - 'numbers': "\nNumeric literals\n****************\n\nThere are three types of numeric literals: integers, floating point\nnumbers, and imaginary numbers. There are no complex literals\n(complex numbers can be formed by adding a real number and an\nimaginary number).\n\nNote that numeric literals do not include a sign; a phrase like ``-1``\nis actually an expression composed of the unary operator '``-``' and\nthe literal ``1``.\n", - 'numeric-types': "\nEmulating numeric types\n***********************\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [2] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand's type is a subclass of the left operand's\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand's\n non-reflected method. This behavior allows subclasses to\n override their ancestors' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n", - 'objects': '\nObjects, values and types\n*************************\n\n*Objects* are Python\'s abstraction for data. All data in a Python\nprogram is represented by objects or by relations between objects. (In\na sense, and in conformance to Von Neumann\'s model of a "stored\nprogram computer," code is also represented by objects.)\n\nEvery object has an identity, a type and a value. An object\'s\n*identity* never changes once it has been created; you may think of it\nas the object\'s address in memory. The \'``is``\' operator compares the\nidentity of two objects; the ``id()`` function returns an integer\nrepresenting its identity.\n\n**CPython implementation detail:** For CPython, ``id(x)`` is the\nmemory address where ``x`` is stored.\n\nAn object\'s type determines the operations that the object supports\n(e.g., "does it have a length?") and also defines the possible values\nfor objects of that type. The ``type()`` function returns an object\'s\ntype (which is an object itself). Like its identity, an object\'s\n*type* is also unchangeable. [1]\n\nThe *value* of some objects can change. Objects whose value can\nchange are said to be *mutable*; objects whose value is unchangeable\nonce they are created are called *immutable*. (The value of an\nimmutable container object that contains a reference to a mutable\nobject can change when the latter\'s value is changed; however the\ncontainer is still considered immutable, because the collection of\nobjects it contains cannot be changed. So, immutability is not\nstrictly the same as having an unchangeable value, it is more subtle.)\nAn object\'s mutability is determined by its type; for instance,\nnumbers, strings and tuples are immutable, while dictionaries and\nlists are mutable.\n\nObjects are never explicitly destroyed; however, when they become\nunreachable they may be garbage-collected. An implementation is\nallowed to postpone garbage collection or omit it altogether --- it is\na matter of implementation quality how garbage collection is\nimplemented, as long as no objects are collected that are still\nreachable.\n\n**CPython implementation detail:** CPython currently uses a reference-\ncounting scheme with (optional) delayed detection of cyclically linked\ngarbage, which collects most objects as soon as they become\nunreachable, but is not guaranteed to collect garbage containing\ncircular references. See the documentation of the ``gc`` module for\ninformation on controlling the collection of cyclic garbage. Other\nimplementations act differently and CPython may change. Do not depend\non immediate finalization of objects when they become unreachable (ex:\nalways close files).\n\nNote that the use of the implementation\'s tracing or debugging\nfacilities may keep objects alive that would normally be collectable.\nAlso note that catching an exception with a \'``try``...``except``\'\nstatement may keep objects alive.\n\nSome objects contain references to "external" resources such as open\nfiles or windows. It is understood that these resources are freed\nwhen the object is garbage-collected, but since garbage collection is\nnot guaranteed to happen, such objects also provide an explicit way to\nrelease the external resource, usually a ``close()`` method. Programs\nare strongly recommended to explicitly close such objects. The\n\'``try``...``finally``\' statement and the \'``with``\' statement provide\nconvenient ways to do this.\n\nSome objects contain references to other objects; these are called\n*containers*. Examples of containers are tuples, lists and\ndictionaries. The references are part of a container\'s value. In\nmost cases, when we talk about the value of a container, we imply the\nvalues, not the identities of the contained objects; however, when we\ntalk about the mutability of a container, only the identities of the\nimmediately contained objects are implied. So, if an immutable\ncontainer (like a tuple) contains a reference to a mutable object, its\nvalue changes if that mutable object is changed.\n\nTypes affect almost all aspects of object behavior. Even the\nimportance of object identity is affected in some sense: for immutable\ntypes, operations that compute new values may actually return a\nreference to any existing object with the same type and value, while\nfor mutable objects this is not allowed. E.g., after ``a = 1; b =\n1``, ``a`` and ``b`` may or may not refer to the same object with the\nvalue one, depending on the implementation, but after ``c = []; d =\n[]``, ``c`` and ``d`` are guaranteed to refer to two different,\nunique, newly created empty lists. (Note that ``c = d = []`` assigns\nthe same object to both ``c`` and ``d``.)\n', - 'operator-summary': '\nOperator precedence\n*******************\n\nThe following table summarizes the operator precedences in Python,\nfrom lowest precedence (least binding) to highest precedence (most\nbinding). Operators in the same box have the same precedence. Unless\nthe syntax is explicitly given, operators are binary. Operators in\nthe same box group left to right (except for comparisons, including\ntests, which all have the same precedence and chain from left to right\n--- see section *Comparisons* --- and exponentiation, which groups\nfrom right to left).\n\n+-------------------------------------------------+---------------------------------------+\n| Operator | Description |\n+=================================================+=======================================+\n| ``lambda`` | Lambda expression |\n+-------------------------------------------------+---------------------------------------+\n| ``if`` -- ``else`` | Conditional expression |\n+-------------------------------------------------+---------------------------------------+\n| ``or`` | Boolean OR |\n+-------------------------------------------------+---------------------------------------+\n| ``and`` | Boolean AND |\n+-------------------------------------------------+---------------------------------------+\n| ``not`` ``x`` | Boolean NOT |\n+-------------------------------------------------+---------------------------------------+\n| ``in``, ``not in``, ``is``, ``is not``, ``<``, | Comparisons, including membership |\n| ``<=``, ``>``, ``>=``, ``!=``, ``==`` | tests and identity tests |\n+-------------------------------------------------+---------------------------------------+\n| ``|`` | Bitwise OR |\n+-------------------------------------------------+---------------------------------------+\n| ``^`` | Bitwise XOR |\n+-------------------------------------------------+---------------------------------------+\n| ``&`` | Bitwise AND |\n+-------------------------------------------------+---------------------------------------+\n| ``<<``, ``>>`` | Shifts |\n+-------------------------------------------------+---------------------------------------+\n| ``+``, ``-`` | Addition and subtraction |\n+-------------------------------------------------+---------------------------------------+\n| ``*``, ``/``, ``//``, ``%`` | Multiplication, division, remainder |\n| | [5] |\n+-------------------------------------------------+---------------------------------------+\n| ``+x``, ``-x``, ``~x`` | Positive, negative, bitwise NOT |\n+-------------------------------------------------+---------------------------------------+\n| ``**`` | Exponentiation [6] |\n+-------------------------------------------------+---------------------------------------+\n| ``x[index]``, ``x[index:index]``, | Subscription, slicing, call, |\n| ``x(arguments...)``, ``x.attribute`` | attribute reference |\n+-------------------------------------------------+---------------------------------------+\n| ``(expressions...)``, ``[expressions...]``, | Binding or tuple display, list |\n| ``{key: value...}``, ``{expressions...}`` | display, dictionary display, set |\n| | display |\n+-------------------------------------------------+---------------------------------------+\n\n-[ Footnotes ]-\n\n[1] While ``abs(x%y) < abs(y)`` is true mathematically, for floats it\n may not be true numerically due to roundoff. For example, and\n assuming a platform on which a Python float is an IEEE 754 double-\n precision number, in order that ``-1e-100 % 1e100`` have the same\n sign as ``1e100``, the computed result is ``-1e-100 + 1e100``,\n which is numerically exactly equal to ``1e100``. The function\n ``math.fmod()`` returns a result whose sign matches the sign of\n the first argument instead, and so returns ``-1e-100`` in this\n case. Which approach is more appropriate depends on the\n application.\n\n[2] If x is very close to an exact integer multiple of y, it\'s\n possible for ``x//y`` to be one larger than ``(x-x%y)//y`` due to\n rounding. In such cases, Python returns the latter result, in\n order to preserve that ``divmod(x,y)[0] * y + x % y`` be very\n close to ``x``.\n\n[3] While comparisons between strings make sense at the byte level,\n they may be counter-intuitive to users. For example, the strings\n ``"\\u00C7"`` and ``"\\u0327\\u0043"`` compare differently, even\n though they both represent the same unicode character (LATIN\n CAPITAL LETTER C WITH CEDILLA). To compare strings in a human\n recognizable way, compare using ``unicodedata.normalize()``.\n\n[4] Due to automatic garbage-collection, free lists, and the dynamic\n nature of descriptors, you may notice seemingly unusual behaviour\n in certain uses of the ``is`` operator, like those involving\n comparisons between instance methods, or constants. Check their\n documentation for more info.\n\n[5] The ``%`` operator is also used for string formatting; the same\n precedence applies.\n\n[6] The power operator ``**`` binds less tightly than an arithmetic or\n bitwise unary operator on its right, that is, ``2**-1`` is\n ``0.5``.\n', - 'pass': '\nThe ``pass`` statement\n**********************\n\n pass_stmt ::= "pass"\n\n``pass`` is a null operation --- when it is executed, nothing happens.\nIt is useful as a placeholder when a statement is required\nsyntactically, but no code needs to be executed, for example:\n\n def f(arg): pass # a function that does nothing (yet)\n\n class C: pass # a class with no methods (yet)\n', - 'power': '\nThe power operator\n******************\n\nThe power operator binds more tightly than unary operators on its\nleft; it binds less tightly than unary operators on its right. The\nsyntax is:\n\n power ::= primary ["**" u_expr]\n\nThus, in an unparenthesized sequence of power and unary operators, the\noperators are evaluated from right to left (this does not constrain\nthe evaluation order for the operands): ``-1**2`` results in ``-1``.\n\nThe power operator has the same semantics as the built-in ``pow()``\nfunction, when called with two arguments: it yields its left argument\nraised to the power of its right argument. The numeric arguments are\nfirst converted to a common type, and the result is of that type.\n\nFor int operands, the result has the same type as the operands unless\nthe second argument is negative; in that case, all arguments are\nconverted to float and a float result is delivered. For example,\n``10**2`` returns ``100``, but ``10**-2`` returns ``0.01``.\n\nRaising ``0.0`` to a negative power results in a\n``ZeroDivisionError``. Raising a negative number to a fractional power\nresults in a ``complex`` number. (In earlier versions it raised a\n``ValueError``.)\n', - 'raise': '\nThe ``raise`` statement\n***********************\n\n raise_stmt ::= "raise" [expression ["from" expression]]\n\nIf no expressions are present, ``raise`` re-raises the last exception\nthat was active in the current scope. If no exception is active in\nthe current scope, a ``RuntimeError`` exception is raised indicating\nthat this is an error.\n\nOtherwise, ``raise`` evaluates the first expression as the exception\nobject. It must be either a subclass or an instance of\n``BaseException``. If it is a class, the exception instance will be\nobtained when needed by instantiating the class with no arguments.\n\nThe *type* of the exception is the exception instance\'s class, the\n*value* is the instance itself.\n\nA traceback object is normally created automatically when an exception\nis raised and attached to it as the ``__traceback__`` attribute, which\nis writable. You can create an exception and set your own traceback in\none step using the ``with_traceback()`` exception method (which\nreturns the same exception instance, with its traceback set to its\nargument), like so:\n\n raise Exception("foo occurred").with_traceback(tracebackobj)\n\nThe ``from`` clause is used for exception chaining: if given, the\nsecond *expression* must be another exception class or instance, which\nwill then be attached to the raised exception as the ``__cause__``\nattribute (which is writable). If the raised exception is not\nhandled, both exceptions will be printed:\n\n >>> try:\n ... print(1 / 0)\n ... except Exception as exc:\n ... raise RuntimeError("Something bad happened") from exc\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n The above exception was the direct cause of the following exception:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nA similar mechanism works implicitly if an exception is raised inside\nan exception handler: the previous exception is then attached as the\nnew exception\'s ``__context__`` attribute:\n\n >>> try:\n ... print(1 / 0)\n ... except:\n ... raise RuntimeError("Something bad happened")\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n During handling of the above exception, another exception occurred:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information about handling exceptions is in section\n*The try statement*.\n', - 'return': '\nThe ``return`` statement\n************************\n\n return_stmt ::= "return" [expression_list]\n\n``return`` may only occur syntactically nested in a function\ndefinition, not within a nested class definition.\n\nIf an expression list is present, it is evaluated, else ``None`` is\nsubstituted.\n\n``return`` leaves the current function call with the expression list\n(or ``None``) as return value.\n\nWhen ``return`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nleaving the function.\n\nIn a generator function, the ``return`` statement indicates that the\ngenerator is done and will cause ``StopIteration`` to be raised. The\nreturned value (if any) is used as an argument to construct\n``StopIteration`` and becomes the ``StopIteration.value`` attribute.\n', - 'sequence-types': "\nEmulating container types\n*************************\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python's standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping's keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn't define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nobject.__length_hint__(self)\n\n Called to implement ``operator.length_hint()``. Should return an\n estimated length for the object (which may be greater or less than\n the actual length). The length must be an integer ``>=`` 0. This\n method is purely an optimization and is never required for\n correctness.\n\n New in version 3.4.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` built-in will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don't define ``__contains__()``, the membership\n test first tries iteration via ``__iter__()``, then the old\n sequence iteration protocol via ``__getitem__()``, see *this\n section in the language reference*.\n", - 'shifting': '\nShifting operations\n*******************\n\nThe shifting operations have lower priority than the arithmetic\noperations:\n\n shift_expr ::= a_expr | shift_expr ( "<<" | ">>" ) a_expr\n\nThese operators accept integers as arguments. They shift the first\nargument to the left or right by the number of bits given by the\nsecond argument.\n\nA right shift by *n* bits is defined as floor division by\n``pow(2,n)``. A left shift by *n* bits is defined as multiplication\nwith ``pow(2,n)``.\n\nNote: In the current implementation, the right-hand operand is required to\n be at most ``sys.maxsize``. If the right-hand operand is larger\n than ``sys.maxsize`` an ``OverflowError`` exception is raised.\n', - 'slicings': '\nSlicings\n********\n\nA slicing selects a range of items in a sequence object (e.g., a\nstring, tuple or list). Slicings may be used as expressions or as\ntargets in assignment or ``del`` statements. The syntax for a\nslicing:\n\n slicing ::= primary "[" slice_list "]"\n slice_list ::= slice_item ("," slice_item)* [","]\n slice_item ::= expression | proper_slice\n proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" [stride] ]\n lower_bound ::= expression\n upper_bound ::= expression\n stride ::= expression\n\nThere is ambiguity in the formal syntax here: anything that looks like\nan expression list also looks like a slice list, so any subscription\ncan be interpreted as a slicing. Rather than further complicating the\nsyntax, this is disambiguated by defining that in this case the\ninterpretation as a subscription takes priority over the\ninterpretation as a slicing (this is the case if the slice list\ncontains no proper slice).\n\nThe semantics for a slicing are as follows. The primary must evaluate\nto a mapping object, and it is indexed (using the same\n``__getitem__()`` method as normal subscription) with a key that is\nconstructed from the slice list, as follows. If the slice list\ncontains at least one comma, the key is a tuple containing the\nconversion of the slice items; otherwise, the conversion of the lone\nslice item is the key. The conversion of a slice item that is an\nexpression is that expression. The conversion of a proper slice is a\nslice object (see section *The standard type hierarchy*) whose\n``start``, ``stop`` and ``step`` attributes are the values of the\nexpressions given as lower bound, upper bound and stride,\nrespectively, substituting ``None`` for missing expressions.\n', - 'specialattrs': '\nSpecial Attributes\n******************\n\nThe implementation adds a few special read-only attributes to several\nobject types, where they are relevant. Some of these are not reported\nby the ``dir()`` built-in function.\n\nobject.__dict__\n\n A dictionary or other mapping object used to store an object\'s\n (writable) attributes.\n\ninstance.__class__\n\n The class to which a class instance belongs.\n\nclass.__bases__\n\n The tuple of base classes of a class object.\n\nclass.__name__\n\n The name of the class or type.\n\nclass.__qualname__\n\n The *qualified name* of the class or type.\n\n New in version 3.3.\n\nclass.__mro__\n\n This attribute is a tuple of classes that are considered when\n looking for base classes during method resolution.\n\nclass.mro()\n\n This method can be overridden by a metaclass to customize the\n method resolution order for its instances. It is called at class\n instantiation, and its result is stored in ``__mro__``.\n\nclass.__subclasses__()\n\n Each class keeps a list of weak references to its immediate\n subclasses. This method returns a list of all those references\n still alive. Example:\n\n >>> int.__subclasses__()\n []\n\n-[ Footnotes ]-\n\n[1] Additional information on these special methods may be found in\n the Python Reference Manual (*Basic customization*).\n\n[2] As a consequence, the list ``[1, 2]`` is considered equal to\n ``[1.0, 2.0]``, and similarly for tuples.\n\n[3] They must have since the parser can\'t tell the type of the\n operands.\n\n[4] Cased characters are those with general category property being\n one of "Lu" (Letter, uppercase), "Ll" (Letter, lowercase), or "Lt"\n (Letter, titlecase).\n\n[5] To format only a tuple you should therefore provide a singleton\n tuple whose only element is the tuple to be formatted.\n', - 'specialnames': '\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named ``__getitem__()``, and ``x`` is an instance of this\nclass, then ``x[i]`` is roughly equivalent to ``type(x).__getitem__(x,\ni)``. Except where mentioned, attempts to execute an operation raise\nan exception when no appropriate method is defined (typically\n``AttributeError`` or ``TypeError``).\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n``NodeList`` interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected and cleaned up when the cyclic garbage collector is\n enabled (it\'s on by default). Refer to the documentation for the\n ``gc`` module for more information about this topic.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by ``str(object)`` and the built-in functions ``format()``\n and ``print()`` to compute the "informal" or nicely printable\n string representation of an object. The return value must be a\n *string* object.\n\n This method differs from ``object.__repr__()`` in that there is no\n expectation that ``__str__()`` return a valid Python expression: a\n more convenient or concise representation can be used.\n\n The default implementation defined by the built-in type ``object``\n calls ``object.__repr__()``.\n\nobject.__bytes__(self)\n\n Called by ``bytes()`` to compute a byte-string representation of an\n object. This should return a ``bytes`` object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``str.format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see ``functools.total_ordering()``.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n Note: ``hash()`` truncates the value returned from an object\'s custom\n ``__hash__()`` method to the size of a ``Py_ssize_t``. This is\n typically 8 bytes on 64-bit builds and 4 bytes on 32-bit builds.\n If an object\'s ``__hash__()`` must interoperate on builds of\n different bit sizes, be sure to check the width on all supported\n builds. An easy way to do this is with ``python -c "import sys;\n print(sys.hash_info.width)"``\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns an appropriate value such\n that ``x == y`` implies both that ``x is y`` and ``hash(x) ==\n hash(y)``.\n\n A class that overrides ``__eq__()`` and does not define\n ``__hash__()`` will have its ``__hash__()`` implicitly set to\n ``None``. When the ``__hash__()`` method of a class is ``None``,\n instances of the class will raise an appropriate ``TypeError`` when\n a program attempts to retrieve their hash value, and will also be\n correctly identified as unhashable when checking ``isinstance(obj,\n collections.Hashable``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``.\n\n If a class that does not override ``__eq__()`` wishes to suppress\n hash support, it should include ``__hash__ = None`` in the class\n definition. A class which defines its own ``__hash__()`` that\n explicitly raises a ``TypeError`` would be incorrectly identified\n as hashable by an ``isinstance(obj, collections.Hashable)`` call.\n\n Note: By default, the ``__hash__()`` values of str, bytes and datetime\n objects are "salted" with an unpredictable random value.\n Although they remain constant within an individual Python\n process, they are not predictable between repeated invocations of\n Python.This is intended to provide protection against a denial-\n of-service caused by carefully-chosen inputs that exploit the\n worst case performance of a dict insertion, O(n^2) complexity.\n See http://www.ocert.org/advisories/ocert-2011-003.html for\n details.Changing hash values affects the iteration order of\n dicts, sets and other mappings. Python has never made guarantees\n about this ordering (and it typically varies between 32-bit and\n 64-bit builds).See also ``PYTHONHASHSEED``.\n\n Changed in version 3.3: Hash randomization is enabled by default.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A sequence must be\n returned. ``dir()`` converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, obj.__class__)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``bytes`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using ``type()``. The class body\nis executed in a new namespace and the class name is bound locally to\nthe result of ``type(name, bases, namespace)``.\n\nThe class creation process can be customised by passing the\n``metaclass`` keyword argument in the class definition line, or by\ninheriting from an existing class that included such an argument. In\nthe following example, both ``MyClass`` and ``MySubclass`` are\ninstances of ``Meta``:\n\n class Meta(type):\n pass\n\n class MyClass(metaclass=Meta):\n pass\n\n class MySubclass(MyClass):\n pass\n\nAny other keyword arguments that are specified in the class definition\nare passed through to all metaclass operations described below.\n\nWhen a class definition is executed, the following steps occur:\n\n* the appropriate metaclass is determined\n\n* the class namespace is prepared\n\n* the class body is executed\n\n* the class object is created\n\n\nDetermining the appropriate metaclass\n-------------------------------------\n\nThe appropriate metaclass for a class definition is determined as\nfollows:\n\n* if no bases and no explicit metaclass are given, then ``type()`` is\n used\n\n* if an explicit metaclass is given and it is *not* an instance of\n ``type()``, then it is used directly as the metaclass\n\n* if an instance of ``type()`` is given as the explicit metaclass, or\n bases are defined, then the most derived metaclass is used\n\nThe most derived metaclass is selected from the explicitly specified\nmetaclass (if any) and the metaclasses (i.e. ``type(cls)``) of all\nspecified base classes. The most derived metaclass is one which is a\nsubtype of *all* of these candidate metaclasses. If none of the\ncandidate metaclasses meets that criterion, then the class definition\nwill fail with ``TypeError``.\n\n\nPreparing the class namespace\n-----------------------------\n\nOnce the appropriate metaclass has been identified, then the class\nnamespace is prepared. If the metaclass has a ``__prepare__``\nattribute, it is called as ``namespace = metaclass.__prepare__(name,\nbases, **kwds)`` (where the additional keyword arguments, if any, come\nfrom the class definition).\n\nIf the metaclass has no ``__prepare__`` attribute, then the class\nnamespace is initialised as an empty ``dict()`` instance.\n\nSee also:\n\n **PEP 3115** - Metaclasses in Python 3000\n Introduced the ``__prepare__`` namespace hook\n\n\nExecuting the class body\n------------------------\n\nThe class body is executed (approximately) as ``exec(body, globals(),\nnamespace)``. The key difference from a normal call to ``exec()`` is\nthat lexical scoping allows the class body (including any methods) to\nreference names from the current and outer scopes when the class\ndefinition occurs inside a function.\n\nHowever, even when the class definition occurs inside the function,\nmethods defined inside the class still cannot see names defined at the\nclass scope. Class variables must be accessed through the first\nparameter of instance or class methods, and cannot be accessed at all\nfrom static methods.\n\n\nCreating the class object\n-------------------------\n\nOnce the class namespace has been populated by executing the class\nbody, the class object is created by calling ``metaclass(name, bases,\nnamespace, **kwds)`` (the additional keywords passed here are the same\nas those passed to ``__prepare__``).\n\nThis class object is the one that will be referenced by the zero-\nargument form of ``super()``. ``__class__`` is an implicit closure\nreference created by the compiler if any methods in a class body refer\nto either ``__class__`` or ``super``. This allows the zero argument\nform of ``super()`` to correctly identify the class being defined\nbased on lexical scoping, while the class or instance that was used to\nmake the current call is identified based on the first argument passed\nto the method.\n\nAfter the class object is created, it is passed to the class\ndecorators included in the class definition (if any) and the resulting\nobject is bound in the local namespace as the defined class.\n\nSee also:\n\n **PEP 3135** - New super\n Describes the implicit ``__class__`` closure reference\n\n\nMetaclass example\n-----------------\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored include logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n``collections.OrderedDict`` to remember the order that class members\nwere defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, namespace, **kwds):\n result = type.__new__(cls, name, bases, dict(namespace))\n result.members = tuple(namespace)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s ``__prepare__()`` method which returns an\nempty ``collections.OrderedDict``. That mapping records the methods\nand attributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s ``__new__()`` method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called ``members``.\n\n\nCustomizing instance and subclass checks\n========================================\n\nThe following methods are used to override the default behavior of the\n``isinstance()`` and ``issubclass()`` built-in functions.\n\nIn particular, the metaclass ``abc.ABCMeta`` implements these methods\nin order to allow the addition of Abstract Base Classes (ABCs) as\n"virtual base classes" to any class or type (including built-in\ntypes), including other ABCs.\n\nclass.__instancecheck__(self, instance)\n\n Return true if *instance* should be considered a (direct or\n indirect) instance of *class*. If defined, called to implement\n ``isinstance(instance, class)``.\n\nclass.__subclasscheck__(self, subclass)\n\n Return true if *subclass* should be considered a (direct or\n indirect) subclass of *class*. If defined, called to implement\n ``issubclass(subclass, class)``.\n\nNote that these methods are looked up on the type (metaclass) of a\nclass. They cannot be defined as class methods in the actual class.\nThis is consistent with the lookup of special methods that are called\non instances, only in this case the instance is itself a class.\n\nSee also:\n\n **PEP 3119** - Introducing Abstract Base Classes\n Includes the specification for customizing ``isinstance()`` and\n ``issubclass()`` behavior through ``__instancecheck__()`` and\n ``__subclasscheck__()``, with motivation for this functionality\n in the context of adding Abstract Base Classes (see the ``abc``\n module) to the language.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python\'s standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping\'s keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn\'t define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nobject.__length_hint__(self)\n\n Called to implement ``operator.length_hint()``. Should return an\n estimated length for the object (which may be greater or less than\n the actual length). The length must be an integer ``>=`` 0. This\n method is purely an optimization and is never required for\n correctness.\n\n New in version 3.4.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` built-in will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define ``__contains__()``, the membership\n test first tries iteration via ``__iter__()``, then the old\n sequence iteration protocol via ``__getitem__()``, see *this\n section in the language reference*.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [2] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left operand\'s\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand\'s\n non-reflected method. This behavior allows subclasses to\n override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C:\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as ``__hash__()`` and ``__repr__()`` that are implemented\nby all objects, including type objects. If the implicit lookup of\nthese methods used the conventional lookup process, they would fail\nwhen invoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe ``__getattribute__()`` method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the ``__getattribute__()`` machinery in this fashion\nprovides significant scope for speed optimisations within the\ninterpreter, at the cost of some flexibility in the handling of\nspecial methods (the special method *must* be set on the class object\nitself in order to be consistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type, under\n certain controlled conditions. It generally isn\'t a good idea\n though, since it can lead to some very strange behaviour if it is\n handled incorrectly.\n\n[2] For operands of the same type, it is assumed that if the non-\n reflected method (such as ``__add__()``) fails the operation is\n not supported, which is why the reflected method is not called.\n', - 'string-methods': '\nString Methods\n**************\n\nStrings implement all of the *common* sequence operations, along with\nthe additional methods described below.\n\nStrings also support two styles of string formatting, one providing a\nlarge degree of flexibility and customization (see ``str.format()``,\n*Format String Syntax* and *String Formatting*) and the other based on\nC ``printf`` style formatting that handles a narrower range of types\nand is slightly harder to use correctly, but is often faster for the\ncases it can handle (*printf-style String Formatting*).\n\nThe *Text Processing Services* section of the standard library covers\na number of other modules that provide various text related utilities\n(including regular expression support in the ``re`` module).\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.casefold()\n\n Return a casefolded copy of the string. Casefolded strings may be\n used for caseless matching.\n\n Casefolding is similar to lowercasing but more aggressive because\n it is intended to remove all case distinctions in a string. For\n example, the German lowercase letter ``\'\xc3\x9f\'`` is equivalent to\n ``"ss"``. Since it is already lowercase, ``lower()`` would do\n nothing to ``\'\xc3\x9f\'``; ``casefold()`` converts it to ``"ss"``.\n\n The casefolding algorithm is described in section 3.13 of the\n Unicode Standard.\n\n New in version 3.3.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is ``\'utf-8\'``. *errors* may be given to set a different\n error handling scheme. The default for *errors* is ``\'strict\'``,\n meaning that encoding errors raise a ``UnicodeError``. Other\n possible values are ``\'ignore\'``, ``\'replace\'``,\n ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs(tabsize=8)\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. Tab positions occur every *tabsize* characters\n (default is 8, giving tab positions at columns 0, 8, 16 and so on).\n To expand the string, the current column is set to zero and the\n string is examined character by character. If the character is a\n tab (``\\t``), one or more space characters are inserted in the\n result until the current column is equal to the next tab position.\n (The tab character itself is not copied.) If the character is a\n newline (``\\n``) or return (``\\r``), it is copied and the current\n column is reset to zero. Any other character is copied unchanged\n and the current column is incremented by one regardless of how the\n character is represented when printed.\n\n >>> \'01\\t012\\t0123\\t01234\'.expandtabs()\n \'01 012 0123 01234\'\n >>> \'01\\t012\\t0123\\t01234\'.expandtabs(4)\n \'01 012 0123 01234\'\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\n Note: The ``find()`` method should be used only if you need to know the\n position of *sub*. To check if *sub* is a substring or not, use\n the ``in`` operator:\n\n >>> \'Py\' in \'Python\'\n True\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces ``{}``. Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to ``str.format(**mapping)``, except that ``mapping`` is\n used directly and not copied to a ``dict``. This is useful if for\n example ``mapping`` is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character\n ``c`` is alphanumeric if one of the following returns ``True``:\n ``c.isalpha()``, ``c.isdecimal()``, ``c.isdigit()``, or\n ``c.isnumeric()``.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that can be used to\n form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\n Use ``keyword.iskeyword()`` to test for reserved identifiers such\n as ``def`` and ``class``.\n\nstr.islower()\n\n Return true if all cased characters [4] in the string are lowercase\n and there is at least one cased character, false otherwise.\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters [4] in the string are uppercase\n and there is at least one cased character, false otherwise.\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *iterable*, including ``bytes`` objects.\n The separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than or\n equal to ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string with all the cased characters [4]\n converted to lowercase.\n\n The lowercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than or\n equal to ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified or ``-1``, then there is\n no limit on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. This method uses the *universal newlines* approach to\n splitting lines. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\n For example, ``\'ab c\\n\\nde fg\\rkl\\r\\n\'.splitlines()`` returns\n ``[\'ab c\', \'\', \'de fg\', \'kl\']``, while the same call with\n ``splitlines(True)`` returns ``[\'ab c\\n\', \'\\n\', \'de fg\\r\',\n \'kl\\r\\n\']``.\n\n Unlike ``split()`` when a delimiter string *sep* is given, this\n method returns an empty list for the empty string, and a terminal\n line break does not result in an extra line.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa. Note that it is not necessarily true that\n ``s.swapcase().swapcase() == s``.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n ... return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n ... lambda mo: mo.group(0)[0].upper() +\n ... mo.group(0)[1:].lower(),\n ... s)\n ...\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string with all the cased characters [4]\n converted to uppercase. Note that ``str.upper().isupper()`` might\n be ``False`` if ``s`` contains uncased characters or if the Unicode\n category of the resulting character(s) is not "Lu" (Letter,\n uppercase), but e.g. "Lt" (Letter, titlecase).\n\n The uppercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than or equal to ``len(s)``.\n', - 'strings': '\nString and Bytes literals\n*************************\n\nString literals are described by the following lexical definitions:\n\n stringliteral ::= [stringprefix](shortstring | longstring)\n stringprefix ::= "r" | "u" | "R" | "U"\n shortstring ::= "\'" shortstringitem* "\'" | \'"\' shortstringitem* \'"\'\n longstring ::= "\'\'\'" longstringitem* "\'\'\'" | \'"""\' longstringitem* \'"""\'\n shortstringitem ::= shortstringchar | stringescapeseq\n longstringitem ::= longstringchar | stringescapeseq\n shortstringchar ::= \n longstringchar ::= \n stringescapeseq ::= "\\" \n\n bytesliteral ::= bytesprefix(shortbytes | longbytes)\n bytesprefix ::= "b" | "B" | "br" | "Br" | "bR" | "BR" | "rb" | "rB" | "Rb" | "RB"\n shortbytes ::= "\'" shortbytesitem* "\'" | \'"\' shortbytesitem* \'"\'\n longbytes ::= "\'\'\'" longbytesitem* "\'\'\'" | \'"""\' longbytesitem* \'"""\'\n shortbytesitem ::= shortbyteschar | bytesescapeseq\n longbytesitem ::= longbyteschar | bytesescapeseq\n shortbyteschar ::= \n longbyteschar ::= \n bytesescapeseq ::= "\\" \n\nOne syntactic restriction not indicated by these productions is that\nwhitespace is not allowed between the ``stringprefix`` or\n``bytesprefix`` and the rest of the literal. The source character set\nis defined by the encoding declaration; it is UTF-8 if no encoding\ndeclaration is given in the source file; see section *Encoding\ndeclarations*.\n\nIn plain English: Both types of literals can be enclosed in matching\nsingle quotes (``\'``) or double quotes (``"``). They can also be\nenclosed in matching groups of three single or double quotes (these\nare generally referred to as *triple-quoted strings*). The backslash\n(``\\``) character is used to escape characters that otherwise have a\nspecial meaning, such as newline, backslash itself, or the quote\ncharacter.\n\nBytes literals are always prefixed with ``\'b\'`` or ``\'B\'``; they\nproduce an instance of the ``bytes`` type instead of the ``str`` type.\nThey may only contain ASCII characters; bytes with a numeric value of\n128 or greater must be expressed with escapes.\n\nAs of Python 3.3 it is possible again to prefix unicode strings with a\n``u`` prefix to simplify maintenance of dual 2.x and 3.x codebases.\n\nBoth string and bytes literals may optionally be prefixed with a\nletter ``\'r\'`` or ``\'R\'``; such strings are called *raw strings* and\ntreat backslashes as literal characters. As a result, in string\nliterals, ``\'\\U\'`` and ``\'\\u\'`` escapes in raw strings are not treated\nspecially. Given that Python 2.x\'s raw unicode literals behave\ndifferently than Python 3.x\'s the ``\'ur\'`` syntax is not supported.\n\n New in version 3.3: The ``\'rb\'`` prefix of raw bytes literals has\n been added as a synonym of ``\'br\'``.\n\n New in version 3.3: Support for the unicode legacy literal\n (``u\'value\'``) was reintroduced to simplify the maintenance of dual\n Python 2.x and 3.x codebases. See **PEP 414** for more information.\n\nIn triple-quoted strings, unescaped newlines and quotes are allowed\n(and are retained), except that three unescaped quotes in a row\nterminate the string. (A "quote" is the character used to open the\nstring, i.e. either ``\'`` or ``"``.)\n\nUnless an ``\'r\'`` or ``\'R\'`` prefix is present, escape sequences in\nstrings are interpreted according to rules similar to those used by\nStandard C. The recognized escape sequences are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\newline`` | Backslash and newline ignored | |\n+-------------------+-----------------------------------+---------+\n| ``\\\\`` | Backslash (``\\``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\\'`` | Single quote (``\'``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\"`` | Double quote (``"``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\a`` | ASCII Bell (BEL) | |\n+-------------------+-----------------------------------+---------+\n| ``\\b`` | ASCII Backspace (BS) | |\n+-------------------+-----------------------------------+---------+\n| ``\\f`` | ASCII Formfeed (FF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\n`` | ASCII Linefeed (LF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\r`` | ASCII Carriage Return (CR) | |\n+-------------------+-----------------------------------+---------+\n| ``\\t`` | ASCII Horizontal Tab (TAB) | |\n+-------------------+-----------------------------------+---------+\n| ``\\v`` | ASCII Vertical Tab (VT) | |\n+-------------------+-----------------------------------+---------+\n| ``\\ooo`` | Character with octal value *ooo* | (1,3) |\n+-------------------+-----------------------------------+---------+\n| ``\\xhh`` | Character with hex value *hh* | (2,3) |\n+-------------------+-----------------------------------+---------+\n\nEscape sequences only recognized in string literals are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\N{name}`` | Character named *name* in the | (4) |\n| | Unicode database | |\n+-------------------+-----------------------------------+---------+\n| ``\\uxxxx`` | Character with 16-bit hex value | (5) |\n| | *xxxx* | |\n+-------------------+-----------------------------------+---------+\n| ``\\Uxxxxxxxx`` | Character with 32-bit hex value | (6) |\n| | *xxxxxxxx* | |\n+-------------------+-----------------------------------+---------+\n\nNotes:\n\n1. As in Standard C, up to three octal digits are accepted.\n\n2. Unlike in Standard C, exactly two hex digits are required.\n\n3. In a bytes literal, hexadecimal and octal escapes denote the byte\n with the given value. In a string literal, these escapes denote a\n Unicode character with the given value.\n\n4. Changed in version 3.3: Support for name aliases [1] has been\n added.\n\n5. Individual code units which form parts of a surrogate pair can be\n encoded using this escape sequence. Exactly four hex digits are\n required.\n\n6. Any Unicode character can be encoded this way. Exactly eight hex\n digits are required.\n\nUnlike Standard C, all unrecognized escape sequences are left in the\nstring unchanged, i.e., *the backslash is left in the string*. (This\nbehavior is useful when debugging: if an escape sequence is mistyped,\nthe resulting output is more easily recognized as broken.) It is also\nimportant to note that the escape sequences only recognized in string\nliterals fall into the category of unrecognized escapes for bytes\nliterals.\n\nEven in a raw string, string quotes can be escaped with a backslash,\nbut the backslash remains in the string; for example, ``r"\\""`` is a\nvalid string literal consisting of two characters: a backslash and a\ndouble quote; ``r"\\"`` is not a valid string literal (even a raw\nstring cannot end in an odd number of backslashes). Specifically, *a\nraw string cannot end in a single backslash* (since the backslash\nwould escape the following quote character). Note also that a single\nbackslash followed by a newline is interpreted as those two characters\nas part of the string, *not* as a line continuation.\n', - 'subscriptions': '\nSubscriptions\n*************\n\nA subscription selects an item of a sequence (string, tuple or list)\nor mapping (dictionary) object:\n\n subscription ::= primary "[" expression_list "]"\n\nThe primary must evaluate to an object that supports subscription,\ne.g. a list or dictionary. User-defined objects can support\nsubscription by defining a ``__getitem__()`` method.\n\nFor built-in objects, there are two types of objects that support\nsubscription:\n\nIf the primary is a mapping, the expression list must evaluate to an\nobject whose value is one of the keys of the mapping, and the\nsubscription selects the value in the mapping that corresponds to that\nkey. (The expression list is a tuple except if it has exactly one\nitem.)\n\nIf the primary is a sequence, the expression (list) must evaluate to\nan integer or a slice (as discussed in the following section).\n\nThe formal syntax makes no special provision for negative indices in\nsequences; however, built-in sequences all provide a ``__getitem__()``\nmethod that interprets negative indices by adding the length of the\nsequence to the index (so that ``x[-1]`` selects the last item of\n``x``). The resulting value must be a nonnegative integer less than\nthe number of items in the sequence, and the subscription selects the\nitem whose index is that value (counting from zero). Since the support\nfor negative indices and slicing occurs in the object\'s\n``__getitem__()`` method, subclasses overriding this method will need\nto explicitly add that support.\n\nA string\'s items are characters. A character is not a separate data\ntype but a string of exactly one character.\n', - 'truth': "\nTruth Value Testing\n*******************\n\nAny object can be tested for truth value, for use in an ``if`` or\n``while`` condition or as operand of the Boolean operations below. The\nfollowing values are considered false:\n\n* ``None``\n\n* ``False``\n\n* zero of any numeric type, for example, ``0``, ``0.0``, ``0j``.\n\n* any empty sequence, for example, ``''``, ``()``, ``[]``.\n\n* any empty mapping, for example, ``{}``.\n\n* instances of user-defined classes, if the class defines a\n ``__bool__()`` or ``__len__()`` method, when that method returns the\n integer zero or ``bool`` value ``False``. [1]\n\nAll other values are considered true --- so objects of many types are\nalways true.\n\nOperations and built-in functions that have a Boolean result always\nreturn ``0`` or ``False`` for false and ``1`` or ``True`` for true,\nunless otherwise stated. (Important exception: the Boolean operations\n``or`` and ``and`` always return one of their operands.)\n", - 'try': '\nThe ``try`` statement\n*********************\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting of\nthe exception class, the exception instance and a traceback object\n(see section *The standard type hierarchy*) identifying the point in\nthe program where the exception occurred. ``sys.exc_info()`` values\nare restored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception it is re-raised at the end of\nthe ``finally`` clause. If the ``finally`` clause raises another\nexception, the saved exception is set as the context of the new\nexception. If the ``finally`` clause executes a ``return`` or\n``break`` statement, the saved exception is discarded:\n\n def f():\n try:\n 1/0\n finally:\n return 42\n\n >>> f()\n 42\n\nThe exception information is not available to the program during\nexecution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n', - 'types': '\nThe standard type hierarchy\n***************************\n\nBelow is a list of the types that are built into Python. Extension\nmodules (written in C, Java, or other languages, depending on the\nimplementation) can define additional types. Future versions of\nPython may add types to the type hierarchy (e.g., rational numbers,\nefficiently stored arrays of integers, etc.), although such additions\nwill often be provided via the standard library instead.\n\nSome of the type descriptions below contain a paragraph listing\n\'special attributes.\' These are attributes that provide access to the\nimplementation and are not intended for general use. Their definition\nmay change in the future.\n\nNone\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name ``None``.\n It is used to signify the absence of a value in many situations,\n e.g., it is returned from functions that don\'t explicitly return\n anything. Its truth value is false.\n\nNotImplemented\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name\n ``NotImplemented``. Numeric methods and rich comparison methods may\n return this value if they do not implement the operation for the\n operands provided. (The interpreter will then try the reflected\n operation, or some other fallback, depending on the operator.) Its\n truth value is true.\n\nEllipsis\n This type has a single value. There is a single object with this\n value. This object is accessed through the literal ``...`` or the\n built-in name ``Ellipsis``. Its truth value is true.\n\n``numbers.Number``\n These are created by numeric literals and returned as results by\n arithmetic operators and arithmetic built-in functions. Numeric\n objects are immutable; once created their value never changes.\n Python numbers are of course strongly related to mathematical\n numbers, but subject to the limitations of numerical representation\n in computers.\n\n Python distinguishes between integers, floating point numbers, and\n complex numbers:\n\n ``numbers.Integral``\n These represent elements from the mathematical set of integers\n (positive and negative).\n\n There are two types of integers:\n\n Integers (``int``)\n\n These represent numbers in an unlimited range, subject to\n available (virtual) memory only. For the purpose of shift\n and mask operations, a binary representation is assumed, and\n negative numbers are represented in a variant of 2\'s\n complement which gives the illusion of an infinite string of\n sign bits extending to the left.\n\n Booleans (``bool``)\n These represent the truth values False and True. The two\n objects representing the values ``False`` and ``True`` are\n the only Boolean objects. The Boolean type is a subtype of\n the integer type, and Boolean values behave like the values 0\n and 1, respectively, in almost all contexts, the exception\n being that when converted to a string, the strings\n ``"False"`` or ``"True"`` are returned, respectively.\n\n The rules for integer representation are intended to give the\n most meaningful interpretation of shift and mask operations\n involving negative integers.\n\n ``numbers.Real`` (``float``)\n These represent machine-level double precision floating point\n numbers. You are at the mercy of the underlying machine\n architecture (and C or Java implementation) for the accepted\n range and handling of overflow. Python does not support single-\n precision floating point numbers; the savings in processor and\n memory usage that are usually the reason for using these is\n dwarfed by the overhead of using objects in Python, so there is\n no reason to complicate the language with two kinds of floating\n point numbers.\n\n ``numbers.Complex`` (``complex``)\n These represent complex numbers as a pair of machine-level\n double precision floating point numbers. The same caveats apply\n as for floating point numbers. The real and imaginary parts of a\n complex number ``z`` can be retrieved through the read-only\n attributes ``z.real`` and ``z.imag``.\n\nSequences\n These represent finite ordered sets indexed by non-negative\n numbers. The built-in function ``len()`` returns the number of\n items of a sequence. When the length of a sequence is *n*, the\n index set contains the numbers 0, 1, ..., *n*-1. Item *i* of\n sequence *a* is selected by ``a[i]``.\n\n Sequences also support slicing: ``a[i:j]`` selects all items with\n index *k* such that *i* ``<=`` *k* ``<`` *j*. When used as an\n expression, a slice is a sequence of the same type. This implies\n that the index set is renumbered so that it starts at 0.\n\n Some sequences also support "extended slicing" with a third "step"\n parameter: ``a[i:j:k]`` selects all items of *a* with index *x*\n where ``x = i + n*k``, *n* ``>=`` ``0`` and *i* ``<=`` *x* ``<``\n *j*.\n\n Sequences are distinguished according to their mutability:\n\n Immutable sequences\n An object of an immutable sequence type cannot change once it is\n created. (If the object contains references to other objects,\n these other objects may be mutable and may be changed; however,\n the collection of objects directly referenced by an immutable\n object cannot change.)\n\n The following types are immutable sequences:\n\n Strings\n A string is a sequence of values that represent Unicode\n codepoints. All the codepoints in range ``U+0000 - U+10FFFF``\n can be represented in a string. Python doesn\'t have a\n ``chr`` type, and every character in the string is\n represented as a string object with length ``1``. The built-\n in function ``ord()`` converts a character to its codepoint\n (as an integer); ``chr()`` converts an integer in range ``0 -\n 10FFFF`` to the corresponding character. ``str.encode()`` can\n be used to convert a ``str`` to ``bytes`` using the given\n encoding, and ``bytes.decode()`` can be used to achieve the\n opposite.\n\n Tuples\n The items of a tuple are arbitrary Python objects. Tuples of\n two or more items are formed by comma-separated lists of\n expressions. A tuple of one item (a \'singleton\') can be\n formed by affixing a comma to an expression (an expression by\n itself does not create a tuple, since parentheses must be\n usable for grouping of expressions). An empty tuple can be\n formed by an empty pair of parentheses.\n\n Bytes\n A bytes object is an immutable array. The items are 8-bit\n bytes, represented by integers in the range 0 <= x < 256.\n Bytes literals (like ``b\'abc\'``) and the built-in function\n ``bytes()`` can be used to construct bytes objects. Also,\n bytes objects can be decoded to strings via the ``decode()``\n method.\n\n Mutable sequences\n Mutable sequences can be changed after they are created. The\n subscription and slicing notations can be used as the target of\n assignment and ``del`` (delete) statements.\n\n There are currently two intrinsic mutable sequence types:\n\n Lists\n The items of a list are arbitrary Python objects. Lists are\n formed by placing a comma-separated list of expressions in\n square brackets. (Note that there are no special cases needed\n to form lists of length 0 or 1.)\n\n Byte Arrays\n A bytearray object is a mutable array. They are created by\n the built-in ``bytearray()`` constructor. Aside from being\n mutable (and hence unhashable), byte arrays otherwise provide\n the same interface and functionality as immutable bytes\n objects.\n\n The extension module ``array`` provides an additional example of\n a mutable sequence type, as does the ``collections`` module.\n\nSet types\n These represent unordered, finite sets of unique, immutable\n objects. As such, they cannot be indexed by any subscript. However,\n they can be iterated over, and the built-in function ``len()``\n returns the number of items in a set. Common uses for sets are fast\n membership testing, removing duplicates from a sequence, and\n computing mathematical operations such as intersection, union,\n difference, and symmetric difference.\n\n For set elements, the same immutability rules apply as for\n dictionary keys. Note that numeric types obey the normal rules for\n numeric comparison: if two numbers compare equal (e.g., ``1`` and\n ``1.0``), only one of them can be contained in a set.\n\n There are currently two intrinsic set types:\n\n Sets\n These represent a mutable set. They are created by the built-in\n ``set()`` constructor and can be modified afterwards by several\n methods, such as ``add()``.\n\n Frozen sets\n These represent an immutable set. They are created by the\n built-in ``frozenset()`` constructor. As a frozenset is\n immutable and *hashable*, it can be used again as an element of\n another set, or as a dictionary key.\n\nMappings\n These represent finite sets of objects indexed by arbitrary index\n sets. The subscript notation ``a[k]`` selects the item indexed by\n ``k`` from the mapping ``a``; this can be used in expressions and\n as the target of assignments or ``del`` statements. The built-in\n function ``len()`` returns the number of items in a mapping.\n\n There is currently a single intrinsic mapping type:\n\n Dictionaries\n These represent finite sets of objects indexed by nearly\n arbitrary values. The only types of values not acceptable as\n keys are values containing lists or dictionaries or other\n mutable types that are compared by value rather than by object\n identity, the reason being that the efficient implementation of\n dictionaries requires a key\'s hash value to remain constant.\n Numeric types used for keys obey the normal rules for numeric\n comparison: if two numbers compare equal (e.g., ``1`` and\n ``1.0``) then they can be used interchangeably to index the same\n dictionary entry.\n\n Dictionaries are mutable; they can be created by the ``{...}``\n notation (see section *Dictionary displays*).\n\n The extension modules ``dbm.ndbm`` and ``dbm.gnu`` provide\n additional examples of mapping types, as does the\n ``collections`` module.\n\nCallable types\n These are the types to which the function call operation (see\n section *Calls*) can be applied:\n\n User-defined functions\n A user-defined function object is created by a function\n definition (see section *Function definitions*). It should be\n called with an argument list containing the same number of items\n as the function\'s formal parameter list.\n\n Special attributes:\n\n +---------------------------+---------------------------------+-------------+\n | Attribute | Meaning | |\n +===========================+=================================+=============+\n | ``__doc__`` | The function\'s documentation | Writable |\n | | string, or ``None`` if | |\n | | unavailable | |\n +---------------------------+---------------------------------+-------------+\n | ``__name__`` | The function\'s name | Writable |\n +---------------------------+---------------------------------+-------------+\n | ``__qualname__`` | The function\'s *qualified name* | Writable |\n | | New in version 3.3. | |\n +---------------------------+---------------------------------+-------------+\n | ``__module__`` | The name of the module the | Writable |\n | | function was defined in, or | |\n | | ``None`` if unavailable. | |\n +---------------------------+---------------------------------+-------------+\n | ``__defaults__`` | A tuple containing default | Writable |\n | | argument values for those | |\n | | arguments that have defaults, | |\n | | or ``None`` if no arguments | |\n | | have a default value | |\n +---------------------------+---------------------------------+-------------+\n | ``__code__`` | The code object representing | Writable |\n | | the compiled function body. | |\n +---------------------------+---------------------------------+-------------+\n | ``__globals__`` | A reference to the dictionary | Read-only |\n | | that holds the function\'s | |\n | | global variables --- the global | |\n | | namespace of the module in | |\n | | which the function was defined. | |\n +---------------------------+---------------------------------+-------------+\n | ``__dict__`` | The namespace supporting | Writable |\n | | arbitrary function attributes. | |\n +---------------------------+---------------------------------+-------------+\n | ``__closure__`` | ``None`` or a tuple of cells | Read-only |\n | | that contain bindings for the | |\n | | function\'s free variables. | |\n +---------------------------+---------------------------------+-------------+\n | ``__annotations__`` | A dict containing annotations | Writable |\n | | of parameters. The keys of the | |\n | | dict are the parameter names, | |\n | | and ``\'return\'`` for the return | |\n | | annotation, if provided. | |\n +---------------------------+---------------------------------+-------------+\n | ``__kwdefaults__`` | A dict containing defaults for | Writable |\n | | keyword-only parameters. | |\n +---------------------------+---------------------------------+-------------+\n\n Most of the attributes labelled "Writable" check the type of the\n assigned value.\n\n Function objects also support getting and setting arbitrary\n attributes, which can be used, for example, to attach metadata\n to functions. Regular attribute dot-notation is used to get and\n set such attributes. *Note that the current implementation only\n supports function attributes on user-defined functions. Function\n attributes on built-in functions may be supported in the\n future.*\n\n Additional information about a function\'s definition can be\n retrieved from its code object; see the description of internal\n types below.\n\n Instance methods\n An instance method object combines a class, a class instance and\n any callable object (normally a user-defined function).\n\n Special read-only attributes: ``__self__`` is the class instance\n object, ``__func__`` is the function object; ``__doc__`` is the\n method\'s documentation (same as ``__func__.__doc__``);\n ``__name__`` is the method name (same as ``__func__.__name__``);\n ``__module__`` is the name of the module the method was defined\n in, or ``None`` if unavailable.\n\n Methods also support accessing (but not setting) the arbitrary\n function attributes on the underlying function object.\n\n User-defined method objects may be created when getting an\n attribute of a class (perhaps via an instance of that class), if\n that attribute is a user-defined function object or a class\n method object.\n\n When an instance method object is created by retrieving a user-\n defined function object from a class via one of its instances,\n its ``__self__`` attribute is the instance, and the method\n object is said to be bound. The new method\'s ``__func__``\n attribute is the original function object.\n\n When a user-defined method object is created by retrieving\n another method object from a class or instance, the behaviour is\n the same as for a function object, except that the ``__func__``\n attribute of the new instance is not the original method object\n but its ``__func__`` attribute.\n\n When an instance method object is created by retrieving a class\n method object from a class or instance, its ``__self__``\n attribute is the class itself, and its ``__func__`` attribute is\n the function object underlying the class method.\n\n When an instance method object is called, the underlying\n function (``__func__``) is called, inserting the class instance\n (``__self__``) in front of the argument list. For instance,\n when ``C`` is a class which contains a definition for a function\n ``f()``, and ``x`` is an instance of ``C``, calling ``x.f(1)``\n is equivalent to calling ``C.f(x, 1)``.\n\n When an instance method object is derived from a class method\n object, the "class instance" stored in ``__self__`` will\n actually be the class itself, so that calling either ``x.f(1)``\n or ``C.f(1)`` is equivalent to calling ``f(C,1)`` where ``f`` is\n the underlying function.\n\n Note that the transformation from function object to instance\n method object happens each time the attribute is retrieved from\n the instance. In some cases, a fruitful optimization is to\n assign the attribute to a local variable and call that local\n variable. Also notice that this transformation only happens for\n user-defined functions; other callable objects (and all non-\n callable objects) are retrieved without transformation. It is\n also important to note that user-defined functions which are\n attributes of a class instance are not converted to bound\n methods; this *only* happens when the function is an attribute\n of the class.\n\n Generator functions\n A function or method which uses the ``yield`` statement (see\n section *The yield statement*) is called a *generator function*.\n Such a function, when called, always returns an iterator object\n which can be used to execute the body of the function: calling\n the iterator\'s ``iterator.__next__()`` method will cause the\n function to execute until it provides a value using the\n ``yield`` statement. When the function executes a ``return``\n statement or falls off the end, a ``StopIteration`` exception is\n raised and the iterator will have reached the end of the set of\n values to be returned.\n\n Built-in functions\n A built-in function object is a wrapper around a C function.\n Examples of built-in functions are ``len()`` and ``math.sin()``\n (``math`` is a standard built-in module). The number and type of\n the arguments are determined by the C function. Special read-\n only attributes: ``__doc__`` is the function\'s documentation\n string, or ``None`` if unavailable; ``__name__`` is the\n function\'s name; ``__self__`` is set to ``None`` (but see the\n next item); ``__module__`` is the name of the module the\n function was defined in or ``None`` if unavailable.\n\n Built-in methods\n This is really a different disguise of a built-in function, this\n time containing an object passed to the C function as an\n implicit extra argument. An example of a built-in method is\n ``alist.append()``, assuming *alist* is a list object. In this\n case, the special read-only attribute ``__self__`` is set to the\n object denoted by *alist*.\n\n Classes\n Classes are callable. These objects normally act as factories\n for new instances of themselves, but variations are possible for\n class types that override ``__new__()``. The arguments of the\n call are passed to ``__new__()`` and, in the typical case, to\n ``__init__()`` to initialize the new instance.\n\n Class Instances\n Instances of arbitrary classes can be made callable by defining\n a ``__call__()`` method in their class.\n\nModules\n Modules are a basic organizational unit of Python code, and are\n created by the *import system* as invoked either by the ``import``\n statement (see ``import``), or by calling functions such as\n ``importlib.import_module()`` and built-in ``__import__()``. A\n module object has a namespace implemented by a dictionary object\n (this is the dictionary referenced by the ``__globals__`` attribute\n of functions defined in the module). Attribute references are\n translated to lookups in this dictionary, e.g., ``m.x`` is\n equivalent to ``m.__dict__["x"]``. A module object does not contain\n the code object used to initialize the module (since it isn\'t\n needed once the initialization is done).\n\n Attribute assignment updates the module\'s namespace dictionary,\n e.g., ``m.x = 1`` is equivalent to ``m.__dict__["x"] = 1``.\n\n Special read-only attribute: ``__dict__`` is the module\'s namespace\n as a dictionary object.\n\n **CPython implementation detail:** Because of the way CPython\n clears module dictionaries, the module dictionary will be cleared\n when the module falls out of scope even if the dictionary still has\n live references. To avoid this, copy the dictionary or keep the\n module around while using its dictionary directly.\n\n Predefined (writable) attributes: ``__name__`` is the module\'s\n name; ``__doc__`` is the module\'s documentation string, or ``None``\n if unavailable; ``__file__`` is the pathname of the file from which\n the module was loaded, if it was loaded from a file. The\n ``__file__`` attribute may be missing for certain types of modules,\n such as C modules that are statically linked into the interpreter;\n for extension modules loaded dynamically from a shared library, it\n is the pathname of the shared library file.\n\nCustom classes\n Custom class types are typically created by class definitions (see\n section *Class definitions*). A class has a namespace implemented\n by a dictionary object. Class attribute references are translated\n to lookups in this dictionary, e.g., ``C.x`` is translated to\n ``C.__dict__["x"]`` (although there are a number of hooks which\n allow for other means of locating attributes). When the attribute\n name is not found there, the attribute search continues in the base\n classes. This search of the base classes uses the C3 method\n resolution order which behaves correctly even in the presence of\n \'diamond\' inheritance structures where there are multiple\n inheritance paths leading back to a common ancestor. Additional\n details on the C3 MRO used by Python can be found in the\n documentation accompanying the 2.3 release at\n http://www.python.org/download/releases/2.3/mro/.\n\n When a class attribute reference (for class ``C``, say) would yield\n a class method object, it is transformed into an instance method\n object whose ``__self__`` attributes is ``C``. When it would yield\n a static method object, it is transformed into the object wrapped\n by the static method object. See section *Implementing Descriptors*\n for another way in which attributes retrieved from a class may\n differ from those actually contained in its ``__dict__``.\n\n Class attribute assignments update the class\'s dictionary, never\n the dictionary of a base class.\n\n A class object can be called (see above) to yield a class instance\n (see below).\n\n Special attributes: ``__name__`` is the class name; ``__module__``\n is the module name in which the class was defined; ``__dict__`` is\n the dictionary containing the class\'s namespace; ``__bases__`` is a\n tuple (possibly empty or a singleton) containing the base classes,\n in the order of their occurrence in the base class list;\n ``__doc__`` is the class\'s documentation string, or None if\n undefined.\n\nClass instances\n A class instance is created by calling a class object (see above).\n A class instance has a namespace implemented as a dictionary which\n is the first place in which attribute references are searched.\n When an attribute is not found there, and the instance\'s class has\n an attribute by that name, the search continues with the class\n attributes. If a class attribute is found that is a user-defined\n function object, it is transformed into an instance method object\n whose ``__self__`` attribute is the instance. Static method and\n class method objects are also transformed; see above under\n "Classes". See section *Implementing Descriptors* for another way\n in which attributes of a class retrieved via its instances may\n differ from the objects actually stored in the class\'s\n ``__dict__``. If no class attribute is found, and the object\'s\n class has a ``__getattr__()`` method, that is called to satisfy the\n lookup.\n\n Attribute assignments and deletions update the instance\'s\n dictionary, never a class\'s dictionary. If the class has a\n ``__setattr__()`` or ``__delattr__()`` method, this is called\n instead of updating the instance dictionary directly.\n\n Class instances can pretend to be numbers, sequences, or mappings\n if they have methods with certain special names. See section\n *Special method names*.\n\n Special attributes: ``__dict__`` is the attribute dictionary;\n ``__class__`` is the instance\'s class.\n\nI/O objects (also known as file objects)\n A *file object* represents an open file. Various shortcuts are\n available to create file objects: the ``open()`` built-in function,\n and also ``os.popen()``, ``os.fdopen()``, and the ``makefile()``\n method of socket objects (and perhaps by other functions or methods\n provided by extension modules).\n\n The objects ``sys.stdin``, ``sys.stdout`` and ``sys.stderr`` are\n initialized to file objects corresponding to the interpreter\'s\n standard input, output and error streams; they are all open in text\n mode and therefore follow the interface defined by the\n ``io.TextIOBase`` abstract class.\n\nInternal types\n A few types used internally by the interpreter are exposed to the\n user. Their definitions may change with future versions of the\n interpreter, but they are mentioned here for completeness.\n\n Code objects\n Code objects represent *byte-compiled* executable Python code,\n or *bytecode*. The difference between a code object and a\n function object is that the function object contains an explicit\n reference to the function\'s globals (the module in which it was\n defined), while a code object contains no context; also the\n default argument values are stored in the function object, not\n in the code object (because they represent values calculated at\n run-time). Unlike function objects, code objects are immutable\n and contain no references (directly or indirectly) to mutable\n objects.\n\n Special read-only attributes: ``co_name`` gives the function\n name; ``co_argcount`` is the number of positional arguments\n (including arguments with default values); ``co_nlocals`` is the\n number of local variables used by the function (including\n arguments); ``co_varnames`` is a tuple containing the names of\n the local variables (starting with the argument names);\n ``co_cellvars`` is a tuple containing the names of local\n variables that are referenced by nested functions;\n ``co_freevars`` is a tuple containing the names of free\n variables; ``co_code`` is a string representing the sequence of\n bytecode instructions; ``co_consts`` is a tuple containing the\n literals used by the bytecode; ``co_names`` is a tuple\n containing the names used by the bytecode; ``co_filename`` is\n the filename from which the code was compiled;\n ``co_firstlineno`` is the first line number of the function;\n ``co_lnotab`` is a string encoding the mapping from bytecode\n offsets to line numbers (for details see the source code of the\n interpreter); ``co_stacksize`` is the required stack size\n (including local variables); ``co_flags`` is an integer encoding\n a number of flags for the interpreter.\n\n The following flag bits are defined for ``co_flags``: bit\n ``0x04`` is set if the function uses the ``*arguments`` syntax\n to accept an arbitrary number of positional arguments; bit\n ``0x08`` is set if the function uses the ``**keywords`` syntax\n to accept arbitrary keyword arguments; bit ``0x20`` is set if\n the function is a generator.\n\n Future feature declarations (``from __future__ import\n division``) also use bits in ``co_flags`` to indicate whether a\n code object was compiled with a particular feature enabled: bit\n ``0x2000`` is set if the function was compiled with future\n division enabled; bits ``0x10`` and ``0x1000`` were used in\n earlier versions of Python.\n\n Other bits in ``co_flags`` are reserved for internal use.\n\n If a code object represents a function, the first item in\n ``co_consts`` is the documentation string of the function, or\n ``None`` if undefined.\n\n Frame objects\n Frame objects represent execution frames. They may occur in\n traceback objects (see below).\n\n Special read-only attributes: ``f_back`` is to the previous\n stack frame (towards the caller), or ``None`` if this is the\n bottom stack frame; ``f_code`` is the code object being executed\n in this frame; ``f_locals`` is the dictionary used to look up\n local variables; ``f_globals`` is used for global variables;\n ``f_builtins`` is used for built-in (intrinsic) names;\n ``f_lasti`` gives the precise instruction (this is an index into\n the bytecode string of the code object).\n\n Special writable attributes: ``f_trace``, if not ``None``, is a\n function called at the start of each source code line (this is\n used by the debugger); ``f_lineno`` is the current line number\n of the frame --- writing to this from within a trace function\n jumps to the given line (only for the bottom-most frame). A\n debugger can implement a Jump command (aka Set Next Statement)\n by writing to f_lineno.\n\n Frame objects support one method:\n\n frame.clear()\n\n This method clears all references to local variables held by\n the frame. Also, if the frame belonged to a generator, the\n generator is finalized. This helps break reference cycles\n involving frame objects (for example when catching an\n exception and storing its traceback for later use).\n\n ``RuntimeError`` is raised if the frame is currently\n executing.\n\n New in version 3.4.\n\n Traceback objects\n Traceback objects represent a stack trace of an exception. A\n traceback object is created when an exception occurs. When the\n search for an exception handler unwinds the execution stack, at\n each unwound level a traceback object is inserted in front of\n the current traceback. When an exception handler is entered,\n the stack trace is made available to the program. (See section\n *The try statement*.) It is accessible as the third item of the\n tuple returned by ``sys.exc_info()``. When the program contains\n no suitable handler, the stack trace is written (nicely\n formatted) to the standard error stream; if the interpreter is\n interactive, it is also made available to the user as\n ``sys.last_traceback``.\n\n Special read-only attributes: ``tb_next`` is the next level in\n the stack trace (towards the frame where the exception\n occurred), or ``None`` if there is no next level; ``tb_frame``\n points to the execution frame of the current level;\n ``tb_lineno`` gives the line number where the exception\n occurred; ``tb_lasti`` indicates the precise instruction. The\n line number and last instruction in the traceback may differ\n from the line number of its frame object if the exception\n occurred in a ``try`` statement with no matching except clause\n or with a finally clause.\n\n Slice objects\n Slice objects are used to represent slices for ``__getitem__()``\n methods. They are also created by the built-in ``slice()``\n function.\n\n Special read-only attributes: ``start`` is the lower bound;\n ``stop`` is the upper bound; ``step`` is the step value; each is\n ``None`` if omitted. These attributes can have any type.\n\n Slice objects support one method:\n\n slice.indices(self, length)\n\n This method takes a single integer argument *length* and\n computes information about the slice that the slice object\n would describe if applied to a sequence of *length* items.\n It returns a tuple of three integers; respectively these are\n the *start* and *stop* indices and the *step* or stride\n length of the slice. Missing or out-of-bounds indices are\n handled in a manner consistent with regular slices.\n\n Static method objects\n Static method objects provide a way of defeating the\n transformation of function objects to method objects described\n above. A static method object is a wrapper around any other\n object, usually a user-defined method object. When a static\n method object is retrieved from a class or a class instance, the\n object actually returned is the wrapped object, which is not\n subject to any further transformation. Static method objects are\n not themselves callable, although the objects they wrap usually\n are. Static method objects are created by the built-in\n ``staticmethod()`` constructor.\n\n Class method objects\n A class method object, like a static method object, is a wrapper\n around another object that alters the way in which that object\n is retrieved from classes and class instances. The behaviour of\n class method objects upon such retrieval is described above,\n under "User-defined methods". Class method objects are created\n by the built-in ``classmethod()`` constructor.\n', - 'typesfunctions': '\nFunctions\n*********\n\nFunction objects are created by function definitions. The only\noperation on a function object is to call it: ``func(argument-list)``.\n\nThere are really two flavors of function objects: built-in functions\nand user-defined functions. Both support the same operation (to call\nthe function), but the implementation is different, hence the\ndifferent object types.\n\nSee *Function definitions* for more information.\n', - 'typesmapping': '\nMapping Types --- ``dict``\n**************************\n\nA *mapping* object maps *hashable* values to arbitrary objects.\nMappings are mutable objects. There is currently only one standard\nmapping type, the *dictionary*. (For other containers see the built-\nin ``list``, ``set``, and ``tuple`` classes, and the ``collections``\nmodule.)\n\nA dictionary\'s keys are *almost* arbitrary values. Values that are\nnot *hashable*, that is, values containing lists, dictionaries or\nother mutable types (that are compared by value rather than by object\nidentity) may not be used as keys. Numeric types used for keys obey\nthe normal rules for numeric comparison: if two numbers compare equal\n(such as ``1`` and ``1.0``) then they can be used interchangeably to\nindex the same dictionary entry. (Note however, that since computers\nstore floating-point numbers as approximations it is usually unwise to\nuse them as dictionary keys.)\n\nDictionaries can be created by placing a comma-separated list of\n``key: value`` pairs within braces, for example: ``{\'jack\': 4098,\n\'sjoerd\': 4127}`` or ``{4098: \'jack\', 4127: \'sjoerd\'}``, or by the\n``dict`` constructor.\n\nclass class dict(**kwarg)\nclass class dict(mapping, **kwarg)\nclass class dict(iterable, **kwarg)\n\n Return a new dictionary initialized from an optional positional\n argument and a possibly empty set of keyword arguments.\n\n If no positional argument is given, an empty dictionary is created.\n If a positional argument is given and it is a mapping object, a\n dictionary is created with the same key-value pairs as the mapping\n object. Otherwise, the positional argument must be an *iterator*\n object. Each item in the iterable must itself be an iterator with\n exactly two objects. The first object of each item becomes a key\n in the new dictionary, and the second object the corresponding\n value. If a key occurs more than once, the last value for that key\n becomes the corresponding value in the new dictionary.\n\n If keyword arguments are given, the keyword arguments and their\n values are added to the dictionary created from the positional\n argument. If a key being added is already present, the value from\n the keyword argument replaces the value from the positional\n argument.\n\n To illustrate, the following examples all return a dictionary equal\n to ``{"one": 1, "two": 2, "three": 3}``:\n\n >>> a = dict(one=1, two=2, three=3)\n >>> b = {\'one\': 1, \'two\': 2, \'three\': 3}\n >>> c = dict(zip([\'one\', \'two\', \'three\'], [1, 2, 3]))\n >>> d = dict([(\'two\', 2), (\'one\', 1), (\'three\', 3)])\n >>> e = dict({\'three\': 3, \'one\': 1, \'two\': 2})\n >>> a == b == c == d == e\n True\n\n Providing keyword arguments as in the first example only works for\n keys that are valid Python identifiers. Otherwise, any valid keys\n can be used.\n\n These are the operations that dictionaries support (and therefore,\n custom mapping types should support too):\n\n len(d)\n\n Return the number of items in the dictionary *d*.\n\n d[key]\n\n Return the item of *d* with key *key*. Raises a ``KeyError`` if\n *key* is not in the map.\n\n If a subclass of dict defines a method ``__missing__()``, if the\n key *key* is not present, the ``d[key]`` operation calls that\n method with the key *key* as argument. The ``d[key]`` operation\n then returns or raises whatever is returned or raised by the\n ``__missing__(key)`` call if the key is not present. No other\n operations or methods invoke ``__missing__()``. If\n ``__missing__()`` is not defined, ``KeyError`` is raised.\n ``__missing__()`` must be a method; it cannot be an instance\n variable:\n\n >>> class Counter(dict):\n ... def __missing__(self, key):\n ... return 0\n >>> c = Counter()\n >>> c[\'red\']\n 0\n >>> c[\'red\'] += 1\n >>> c[\'red\']\n 1\n\n See ``collections.Counter`` for a complete implementation\n including other methods helpful for accumulating and managing\n tallies.\n\n d[key] = value\n\n Set ``d[key]`` to *value*.\n\n del d[key]\n\n Remove ``d[key]`` from *d*. Raises a ``KeyError`` if *key* is\n not in the map.\n\n key in d\n\n Return ``True`` if *d* has a key *key*, else ``False``.\n\n key not in d\n\n Equivalent to ``not key in d``.\n\n iter(d)\n\n Return an iterator over the keys of the dictionary. This is a\n shortcut for ``iter(d.keys())``.\n\n clear()\n\n Remove all items from the dictionary.\n\n copy()\n\n Return a shallow copy of the dictionary.\n\n classmethod fromkeys(seq[, value])\n\n Create a new dictionary with keys from *seq* and values set to\n *value*.\n\n ``fromkeys()`` is a class method that returns a new dictionary.\n *value* defaults to ``None``.\n\n get(key[, default])\n\n Return the value for *key* if *key* is in the dictionary, else\n *default*. If *default* is not given, it defaults to ``None``,\n so that this method never raises a ``KeyError``.\n\n items()\n\n Return a new view of the dictionary\'s items (``(key, value)``\n pairs). See the *documentation of view objects*.\n\n keys()\n\n Return a new view of the dictionary\'s keys. See the\n *documentation of view objects*.\n\n pop(key[, default])\n\n If *key* is in the dictionary, remove it and return its value,\n else return *default*. If *default* is not given and *key* is\n not in the dictionary, a ``KeyError`` is raised.\n\n popitem()\n\n Remove and return an arbitrary ``(key, value)`` pair from the\n dictionary.\n\n ``popitem()`` is useful to destructively iterate over a\n dictionary, as often used in set algorithms. If the dictionary\n is empty, calling ``popitem()`` raises a ``KeyError``.\n\n setdefault(key[, default])\n\n If *key* is in the dictionary, return its value. If not, insert\n *key* with a value of *default* and return *default*. *default*\n defaults to ``None``.\n\n update([other])\n\n Update the dictionary with the key/value pairs from *other*,\n overwriting existing keys. Return ``None``.\n\n ``update()`` accepts either another dictionary object or an\n iterable of key/value pairs (as tuples or other iterables of\n length two). If keyword arguments are specified, the dictionary\n is then updated with those key/value pairs: ``d.update(red=1,\n blue=2)``.\n\n values()\n\n Return a new view of the dictionary\'s values. See the\n *documentation of view objects*.\n\nSee also:\n\n ``types.MappingProxyType`` can be used to create a read-only view\n of a ``dict``.\n\n\nDictionary view objects\n=======================\n\nThe objects returned by ``dict.keys()``, ``dict.values()`` and\n``dict.items()`` are *view objects*. They provide a dynamic view on\nthe dictionary\'s entries, which means that when the dictionary\nchanges, the view reflects these changes.\n\nDictionary views can be iterated over to yield their respective data,\nand support membership tests:\n\nlen(dictview)\n\n Return the number of entries in the dictionary.\n\niter(dictview)\n\n Return an iterator over the keys, values or items (represented as\n tuples of ``(key, value)``) in the dictionary.\n\n Keys and values are iterated over in an arbitrary order which is\n non-random, varies across Python implementations, and depends on\n the dictionary\'s history of insertions and deletions. If keys,\n values and items views are iterated over with no intervening\n modifications to the dictionary, the order of items will directly\n correspond. This allows the creation of ``(value, key)`` pairs\n using ``zip()``: ``pairs = zip(d.values(), d.keys())``. Another\n way to create the same list is ``pairs = [(v, k) for (k, v) in\n d.items()]``.\n\n Iterating views while adding or deleting entries in the dictionary\n may raise a ``RuntimeError`` or fail to iterate over all entries.\n\nx in dictview\n\n Return ``True`` if *x* is in the underlying dictionary\'s keys,\n values or items (in the latter case, *x* should be a ``(key,\n value)`` tuple).\n\nKeys views are set-like since their entries are unique and hashable.\nIf all values are hashable, so that ``(key, value)`` pairs are unique\nand hashable, then the items view is also set-like. (Values views are\nnot treated as set-like since the entries are generally not unique.)\nFor set-like views, all of the operations defined for the abstract\nbase class ``collections.abc.Set`` are available (for example, ``==``,\n``<``, or ``^``).\n\nAn example of dictionary view usage:\n\n >>> dishes = {\'eggs\': 2, \'sausage\': 1, \'bacon\': 1, \'spam\': 500}\n >>> keys = dishes.keys()\n >>> values = dishes.values()\n\n >>> # iteration\n >>> n = 0\n >>> for val in values:\n ... n += val\n >>> print(n)\n 504\n\n >>> # keys and values are iterated over in the same order\n >>> list(keys)\n [\'eggs\', \'bacon\', \'sausage\', \'spam\']\n >>> list(values)\n [2, 1, 1, 500]\n\n >>> # view objects are dynamic and reflect dict changes\n >>> del dishes[\'eggs\']\n >>> del dishes[\'sausage\']\n >>> list(keys)\n [\'spam\', \'bacon\']\n\n >>> # set operations\n >>> keys & {\'eggs\', \'bacon\', \'salad\'}\n {\'bacon\'}\n >>> keys ^ {\'sausage\', \'juice\'}\n {\'juice\', \'sausage\', \'bacon\', \'spam\'}\n', - 'typesmethods': '\nMethods\n*******\n\nMethods are functions that are called using the attribute notation.\nThere are two flavors: built-in methods (such as ``append()`` on\nlists) and class instance methods. Built-in methods are described\nwith the types that support them.\n\nIf you access a method (a function defined in a class namespace)\nthrough an instance, you get a special object: a *bound method* (also\ncalled *instance method*) object. When called, it will add the\n``self`` argument to the argument list. Bound methods have two\nspecial read-only attributes: ``m.__self__`` is the object on which\nthe method operates, and ``m.__func__`` is the function implementing\nthe method. Calling ``m(arg-1, arg-2, ..., arg-n)`` is completely\nequivalent to calling ``m.__func__(m.__self__, arg-1, arg-2, ...,\narg-n)``.\n\nLike function objects, bound method objects support getting arbitrary\nattributes. However, since method attributes are actually stored on\nthe underlying function object (``meth.__func__``), setting method\nattributes on bound methods is disallowed. Attempting to set an\nattribute on a method results in an ``AttributeError`` being raised.\nIn order to set a method attribute, you need to explicitly set it on\nthe underlying function object:\n\n >>> class C:\n ... def method(self):\n ... pass\n ...\n >>> c = C()\n >>> c.method.whoami = \'my name is method\' # can\'t set on the method\n Traceback (most recent call last):\n File "", line 1, in \n AttributeError: \'method\' object has no attribute \'whoami\'\n >>> c.method.__func__.whoami = \'my name is method\'\n >>> c.method.whoami\n \'my name is method\'\n\nSee *The standard type hierarchy* for more information.\n', - 'typesmodules': "\nModules\n*******\n\nThe only special operation on a module is attribute access:\n``m.name``, where *m* is a module and *name* accesses a name defined\nin *m*'s symbol table. Module attributes can be assigned to. (Note\nthat the ``import`` statement is not, strictly speaking, an operation\non a module object; ``import foo`` does not require a module object\nnamed *foo* to exist, rather it requires an (external) *definition*\nfor a module named *foo* somewhere.)\n\nA special attribute of every module is ``__dict__``. This is the\ndictionary containing the module's symbol table. Modifying this\ndictionary will actually change the module's symbol table, but direct\nassignment to the ``__dict__`` attribute is not possible (you can\nwrite ``m.__dict__['a'] = 1``, which defines ``m.a`` to be ``1``, but\nyou can't write ``m.__dict__ = {}``). Modifying ``__dict__`` directly\nis not recommended.\n\nModules built into the interpreter are written like this: ````. If loaded from a file, they are written as\n````.\n", - 'typesseq': '\nSequence Types --- ``list``, ``tuple``, ``range``\n*************************************************\n\nThere are three basic sequence types: lists, tuples, and range\nobjects. Additional sequence types tailored for processing of *binary\ndata* and *text strings* are described in dedicated sections.\n\n\nCommon Sequence Operations\n==========================\n\nThe operations in the following table are supported by most sequence\ntypes, both mutable and immutable. The ``collections.abc.Sequence``\nABC is provided to make it easier to correctly implement these\noperations on custom sequence types.\n\nThis table lists the sequence operations sorted in ascending priority\n(operations in the same box have the same priority). In the table,\n*s* and *t* are sequences of the same type, *n*, *i*, *j* and *k* are\nintegers and *x* is an arbitrary object that meets any type and value\nrestrictions imposed by *s*.\n\nThe ``in`` and ``not in`` operations have the same priorities as the\ncomparison operations. The ``+`` (concatenation) and ``*``\n(repetition) operations have the same priority as the corresponding\nnumeric operations.\n\n+----------------------------+----------------------------------+------------+\n| Operation | Result | Notes |\n+============================+==================================+============+\n| ``x in s`` | ``True`` if an item of *s* is | (1) |\n| | equal to *x*, else ``False`` | |\n+----------------------------+----------------------------------+------------+\n| ``x not in s`` | ``False`` if an item of *s* is | (1) |\n| | equal to *x*, else ``True`` | |\n+----------------------------+----------------------------------+------------+\n| ``s + t`` | the concatenation of *s* and *t* | (6)(7) |\n+----------------------------+----------------------------------+------------+\n| ``s * n`` or ``n * s`` | *n* shallow copies of *s* | (2)(7) |\n| | concatenated | |\n+----------------------------+----------------------------------+------------+\n| ``s[i]`` | *i*th item of *s*, origin 0 | (3) |\n+----------------------------+----------------------------------+------------+\n| ``s[i:j]`` | slice of *s* from *i* to *j* | (3)(4) |\n+----------------------------+----------------------------------+------------+\n| ``s[i:j:k]`` | slice of *s* from *i* to *j* | (3)(5) |\n| | with step *k* | |\n+----------------------------+----------------------------------+------------+\n| ``len(s)`` | length of *s* | |\n+----------------------------+----------------------------------+------------+\n| ``min(s)`` | smallest item of *s* | |\n+----------------------------+----------------------------------+------------+\n| ``max(s)`` | largest item of *s* | |\n+----------------------------+----------------------------------+------------+\n| ``s.index(x[, i[, j]])`` | index of the first occurrence of | (8) |\n| | *x* in *s* (at or after index | |\n| | *i* and before index *j*) | |\n+----------------------------+----------------------------------+------------+\n| ``s.count(x)`` | total number of occurrences of | |\n| | *x* in *s* | |\n+----------------------------+----------------------------------+------------+\n\nSequences of the same type also support comparisons. In particular,\ntuples and lists are compared lexicographically by comparing\ncorresponding elements. This means that to compare equal, every\nelement must compare equal and the two sequences must be of the same\ntype and have the same length. (For full details see *Comparisons* in\nthe language reference.)\n\nNotes:\n\n1. While the ``in`` and ``not in`` operations are used only for simple\n containment testing in the general case, some specialised sequences\n (such as ``str``, ``bytes`` and ``bytearray``) also use them for\n subsequence testing:\n\n >>> "gg" in "eggs"\n True\n\n2. Values of *n* less than ``0`` are treated as ``0`` (which yields an\n empty sequence of the same type as *s*). Note also that the copies\n are shallow; nested structures are not copied. This often haunts\n new Python programmers; consider:\n\n >>> lists = [[]] * 3\n >>> lists\n [[], [], []]\n >>> lists[0].append(3)\n >>> lists\n [[3], [3], [3]]\n\n What has happened is that ``[[]]`` is a one-element list containing\n an empty list, so all three elements of ``[[]] * 3`` are (pointers\n to) this single empty list. Modifying any of the elements of\n ``lists`` modifies this single list. You can create a list of\n different lists this way:\n\n >>> lists = [[] for i in range(3)]\n >>> lists[0].append(3)\n >>> lists[1].append(5)\n >>> lists[2].append(7)\n >>> lists\n [[3], [5], [7]]\n\n3. If *i* or *j* is negative, the index is relative to the end of the\n string: ``len(s) + i`` or ``len(s) + j`` is substituted. But note\n that ``-0`` is still ``0``.\n\n4. The slice of *s* from *i* to *j* is defined as the sequence of\n items with index *k* such that ``i <= k < j``. If *i* or *j* is\n greater than ``len(s)``, use ``len(s)``. If *i* is omitted or\n ``None``, use ``0``. If *j* is omitted or ``None``, use\n ``len(s)``. If *i* is greater than or equal to *j*, the slice is\n empty.\n\n5. The slice of *s* from *i* to *j* with step *k* is defined as the\n sequence of items with index ``x = i + n*k`` such that ``0 <= n <\n (j-i)/k``. In other words, the indices are ``i``, ``i+k``,\n ``i+2*k``, ``i+3*k`` and so on, stopping when *j* is reached (but\n never including *j*). If *i* or *j* is greater than ``len(s)``,\n use ``len(s)``. If *i* or *j* are omitted or ``None``, they become\n "end" values (which end depends on the sign of *k*). Note, *k*\n cannot be zero. If *k* is ``None``, it is treated like ``1``.\n\n6. Concatenating immutable sequences always results in a new object.\n This means that building up a sequence by repeated concatenation\n will have a quadratic runtime cost in the total sequence length.\n To get a linear runtime cost, you must switch to one of the\n alternatives below:\n\n * if concatenating ``str`` objects, you can build a list and use\n ``str.join()`` at the end or else write to a ``io.StringIO``\n instance and retrieve its value when complete\n\n * if concatenating ``bytes`` objects, you can similarly use\n ``bytes.join()`` or ``io.BytesIO``, or you can do in-place\n concatenation with a ``bytearray`` object. ``bytearray`` objects\n are mutable and have an efficient overallocation mechanism\n\n * if concatenating ``tuple`` objects, extend a ``list`` instead\n\n * for other types, investigate the relevant class documentation\n\n7. Some sequence types (such as ``range``) only support item sequences\n that follow specific patterns, and hence don\'t support sequence\n concatenation or repetition.\n\n8. ``index`` raises ``ValueError`` when *x* is not found in *s*. When\n supported, the additional arguments to the index method allow\n efficient searching of subsections of the sequence. Passing the\n extra arguments is roughly equivalent to using ``s[i:j].index(x)``,\n only without copying any data and with the returned index being\n relative to the start of the sequence rather than the start of the\n slice.\n\n\nImmutable Sequence Types\n========================\n\nThe only operation that immutable sequence types generally implement\nthat is not also implemented by mutable sequence types is support for\nthe ``hash()`` built-in.\n\nThis support allows immutable sequences, such as ``tuple`` instances,\nto be used as ``dict`` keys and stored in ``set`` and ``frozenset``\ninstances.\n\nAttempting to hash an immutable sequence that contains unhashable\nvalues will result in ``TypeError``.\n\n\nMutable Sequence Types\n======================\n\nThe operations in the following table are defined on mutable sequence\ntypes. The ``collections.abc.MutableSequence`` ABC is provided to make\nit easier to correctly implement these operations on custom sequence\ntypes.\n\nIn the table *s* is an instance of a mutable sequence type, *t* is any\niterable object and *x* is an arbitrary object that meets any type and\nvalue restrictions imposed by *s* (for example, ``bytearray`` only\naccepts integers that meet the value restriction ``0 <= x <= 255``).\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | appends *x* to the end of the | |\n| | sequence (same as | |\n| | ``s[len(s):len(s)] = [x]``) | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.clear()`` | removes all items from ``s`` | (5) |\n| | (same as ``del s[:]``) | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.copy()`` | creates a shallow copy of ``s`` | (5) |\n| | (same as ``s[:]``) | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(t)`` | extends *s* with the contents of | |\n| | *t* (same as ``s[len(s):len(s)] | |\n| | = t``) | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | inserts *x* into *s* at the | |\n| | index given by *i* (same as | |\n| | ``s[i:i] = [x]``) | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | retrieves the item at *i* and | (2) |\n| | also removes it from *s* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | remove the first item from *s* | (3) |\n| | where ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (4) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. The optional argument *i* defaults to ``-1``, so that by default\n the last item is removed and returned.\n\n3. ``remove`` raises ``ValueError`` when *x* is not found in *s*.\n\n4. The ``reverse()`` method modifies the sequence in place for economy\n of space when reversing a large sequence. To remind users that it\n operates by side effect, it does not return the reversed sequence.\n\n5. ``clear()`` and ``copy()`` are included for consistency with the\n interfaces of mutable containers that don\'t support slicing\n operations (such as ``dict`` and ``set``)\n\n New in version 3.3: ``clear()`` and ``copy()`` methods.\n\n\nLists\n=====\n\nLists are mutable sequences, typically used to store collections of\nhomogeneous items (where the precise degree of similarity will vary by\napplication).\n\nclass class list([iterable])\n\n Lists may be constructed in several ways:\n\n * Using a pair of square brackets to denote the empty list: ``[]``\n\n * Using square brackets, separating items with commas: ``[a]``,\n ``[a, b, c]``\n\n * Using a list comprehension: ``[x for x in iterable]``\n\n * Using the type constructor: ``list()`` or ``list(iterable)``\n\n The constructor builds a list whose items are the same and in the\n same order as *iterable*\'s items. *iterable* may be either a\n sequence, a container that supports iteration, or an iterator\n object. If *iterable* is already a list, a copy is made and\n returned, similar to ``iterable[:]``. For example, ``list(\'abc\')``\n returns ``[\'a\', \'b\', \'c\']`` and ``list( (1, 2, 3) )`` returns ``[1,\n 2, 3]``. If no argument is given, the constructor creates a new\n empty list, ``[]``.\n\n Many other operations also produce lists, including the\n ``sorted()`` built-in.\n\n Lists implement all of the *common* and *mutable* sequence\n operations. Lists also provide the following additional method:\n\n sort(*, key=None, reverse=None)\n\n This method sorts the list in place, using only ``<``\n comparisons between items. Exceptions are not suppressed - if\n any comparison operations fail, the entire sort operation will\n fail (and the list will likely be left in a partially modified\n state).\n\n ``sort()`` accepts two arguments that can only be passed by\n keyword (*keyword-only arguments*):\n\n *key* specifies a function of one argument that is used to\n extract a comparison key from each list element (for example,\n ``key=str.lower``). The key corresponding to each item in the\n list is calculated once and then used for the entire sorting\n process. The default value of ``None`` means that list items are\n sorted directly without calculating a separate key value.\n\n The ``functools.cmp_to_key()`` utility is available to convert a\n 2.x style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n This method modifies the sequence in place for economy of space\n when sorting a large sequence. To remind users that it operates\n by side effect, it does not return the sorted sequence (use\n ``sorted()`` to explicitly request a new sorted list instance).\n\n The ``sort()`` method is guaranteed to be stable. A sort is\n stable if it guarantees not to change the relative order of\n elements that compare equal --- this is helpful for sorting in\n multiple passes (for example, sort by department, then by salary\n grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises ``ValueError`` if it can\n detect that the list has been mutated during a sort.\n\n\nTuples\n======\n\nTuples are immutable sequences, typically used to store collections of\nheterogeneous data (such as the 2-tuples produced by the\n``enumerate()`` built-in). Tuples are also used for cases where an\nimmutable sequence of homogeneous data is needed (such as allowing\nstorage in a ``set`` or ``dict`` instance).\n\nclass class tuple([iterable])\n\n Tuples may be constructed in a number of ways:\n\n * Using a pair of parentheses to denote the empty tuple: ``()``\n\n * Using a trailing comma for a singleton tuple: ``a,`` or ``(a,)``\n\n * Separating items with commas: ``a, b, c`` or ``(a, b, c)``\n\n * Using the ``tuple()`` built-in: ``tuple()`` or\n ``tuple(iterable)``\n\n The constructor builds a tuple whose items are the same and in the\n same order as *iterable*\'s items. *iterable* may be either a\n sequence, a container that supports iteration, or an iterator\n object. If *iterable* is already a tuple, it is returned\n unchanged. For example, ``tuple(\'abc\')`` returns ``(\'a\', \'b\',\n \'c\')`` and ``tuple( [1, 2, 3] )`` returns ``(1, 2, 3)``. If no\n argument is given, the constructor creates a new empty tuple,\n ``()``.\n\n Note that it is actually the comma which makes a tuple, not the\n parentheses. The parentheses are optional, except in the empty\n tuple case, or when they are needed to avoid syntactic ambiguity.\n For example, ``f(a, b, c)`` is a function call with three\n arguments, while ``f((a, b, c))`` is a function call with a 3-tuple\n as the sole argument.\n\n Tuples implement all of the *common* sequence operations.\n\nFor heterogeneous collections of data where access by name is clearer\nthan access by index, ``collections.namedtuple()`` may be a more\nappropriate choice than a simple tuple object.\n\n\nRanges\n======\n\nThe ``range`` type represents an immutable sequence of numbers and is\ncommonly used for looping a specific number of times in ``for`` loops.\n\nclass class range(stop)\nclass class range(start, stop[, step])\n\n The arguments to the range constructor must be integers (either\n built-in ``int`` or any object that implements the ``__index__``\n special method). If the *step* argument is omitted, it defaults to\n ``1``. If the *start* argument is omitted, it defaults to ``0``. If\n *step* is zero, ``ValueError`` is raised.\n\n For a positive *step*, the contents of a range ``r`` are determined\n by the formula ``r[i] = start + step*i`` where ``i >= 0`` and\n ``r[i] < stop``.\n\n For a negative *step*, the contents of the range are still\n determined by the formula ``r[i] = start + step*i``, but the\n constraints are ``i >= 0`` and ``r[i] > stop``.\n\n A range object will be empty if ``r[0]`` does not meet the value\n constraint. Ranges do support negative indices, but these are\n interpreted as indexing from the end of the sequence determined by\n the positive indices.\n\n Ranges containing absolute values larger than ``sys.maxsize`` are\n permitted but some features (such as ``len()``) may raise\n ``OverflowError``.\n\n Range examples:\n\n >>> list(range(10))\n [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n >>> list(range(1, 11))\n [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n >>> list(range(0, 30, 5))\n [0, 5, 10, 15, 20, 25]\n >>> list(range(0, 10, 3))\n [0, 3, 6, 9]\n >>> list(range(0, -10, -1))\n [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]\n >>> list(range(0))\n []\n >>> list(range(1, 0))\n []\n\n Ranges implement all of the *common* sequence operations except\n concatenation and repetition (due to the fact that range objects\n can only represent sequences that follow a strict pattern and\n repetition and concatenation will usually violate that pattern).\n\nThe advantage of the ``range`` type over a regular ``list`` or\n``tuple`` is that a ``range`` object will always take the same (small)\namount of memory, no matter the size of the range it represents (as it\nonly stores the ``start``, ``stop`` and ``step`` values, calculating\nindividual items and subranges as needed).\n\nRange objects implement the ``collections.abc.Sequence`` ABC, and\nprovide features such as containment tests, element index lookup,\nslicing and support for negative indices (see *Sequence Types ---\nlist, tuple, range*):\n\n>>> r = range(0, 20, 2)\n>>> r\nrange(0, 20, 2)\n>>> 11 in r\nFalse\n>>> 10 in r\nTrue\n>>> r.index(10)\n5\n>>> r[5]\n10\n>>> r[:5]\nrange(0, 10, 2)\n>>> r[-1]\n18\n\nTesting range objects for equality with ``==`` and ``!=`` compares\nthem as sequences. That is, two range objects are considered equal if\nthey represent the same sequence of values. (Note that two range\nobjects that compare equal might have different ``start``, ``stop``\nand ``step`` attributes, for example ``range(0) == range(2, 1, 3)`` or\n``range(0, 3, 2) == range(0, 4, 2)``.)\n\nChanged in version 3.2: Implement the Sequence ABC. Support slicing\nand negative indices. Test ``int`` objects for membership in constant\ntime instead of iterating through all items.\n\nChanged in version 3.3: Define \'==\' and \'!=\' to compare range objects\nbased on the sequence of values they define (instead of comparing\nbased on object identity).\n\nNew in version 3.3: The ``start``, ``stop`` and ``step`` attributes.\n', - 'typesseq-mutable': "\nMutable Sequence Types\n**********************\n\nThe operations in the following table are defined on mutable sequence\ntypes. The ``collections.abc.MutableSequence`` ABC is provided to make\nit easier to correctly implement these operations on custom sequence\ntypes.\n\nIn the table *s* is an instance of a mutable sequence type, *t* is any\niterable object and *x* is an arbitrary object that meets any type and\nvalue restrictions imposed by *s* (for example, ``bytearray`` only\naccepts integers that meet the value restriction ``0 <= x <= 255``).\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | appends *x* to the end of the | |\n| | sequence (same as | |\n| | ``s[len(s):len(s)] = [x]``) | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.clear()`` | removes all items from ``s`` | (5) |\n| | (same as ``del s[:]``) | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.copy()`` | creates a shallow copy of ``s`` | (5) |\n| | (same as ``s[:]``) | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(t)`` | extends *s* with the contents of | |\n| | *t* (same as ``s[len(s):len(s)] | |\n| | = t``) | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | inserts *x* into *s* at the | |\n| | index given by *i* (same as | |\n| | ``s[i:i] = [x]``) | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | retrieves the item at *i* and | (2) |\n| | also removes it from *s* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | remove the first item from *s* | (3) |\n| | where ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (4) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. The optional argument *i* defaults to ``-1``, so that by default\n the last item is removed and returned.\n\n3. ``remove`` raises ``ValueError`` when *x* is not found in *s*.\n\n4. The ``reverse()`` method modifies the sequence in place for economy\n of space when reversing a large sequence. To remind users that it\n operates by side effect, it does not return the reversed sequence.\n\n5. ``clear()`` and ``copy()`` are included for consistency with the\n interfaces of mutable containers that don't support slicing\n operations (such as ``dict`` and ``set``)\n\n New in version 3.3: ``clear()`` and ``copy()`` methods.\n", - 'unary': '\nUnary arithmetic and bitwise operations\n***************************************\n\nAll unary arithmetic and bitwise operations have the same priority:\n\n u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr\n\nThe unary ``-`` (minus) operator yields the negation of its numeric\nargument.\n\nThe unary ``+`` (plus) operator yields its numeric argument unchanged.\n\nThe unary ``~`` (invert) operator yields the bitwise inversion of its\ninteger argument. The bitwise inversion of ``x`` is defined as\n``-(x+1)``. It only applies to integral numbers.\n\nIn all three cases, if the argument does not have the proper type, a\n``TypeError`` exception is raised.\n', - 'while': '\nThe ``while`` statement\n***********************\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n', - 'with': '\nThe ``with`` statement\n**********************\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the ``with_item``)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__exit__()`` is loaded for later use.\n\n3. The context manager\'s ``__enter__()`` method is invoked.\n\n4. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n', - 'yield': '\nThe ``yield`` statement\n***********************\n\n yield_stmt ::= yield_expression\n\nThe ``yield`` statement is only used when defining a generator\nfunction, and is only used in the body of the generator function.\nUsing a ``yield`` statement in a function definition is sufficient to\ncause that definition to create a generator function instead of a\nnormal function.\n\nWhen a generator function is called, it returns an iterator known as a\ngenerator iterator, or more commonly, a generator. The body of the\ngenerator function is executed by calling the ``next()`` function on\nthe generator repeatedly until it raises an exception.\n\nWhen a ``yield`` statement is executed, the state of the generator is\nfrozen and the value of ``expression_list`` is returned to\n``next()``\'s caller. By "frozen" we mean that all local state is\nretained, including the current bindings of local variables, the\ninstruction pointer, and the internal evaluation stack: enough\ninformation is saved so that the next time ``next()`` is invoked, the\nfunction can proceed exactly as if the ``yield`` statement were just\nanother external call.\n\nThe ``yield`` statement is allowed in the ``try`` clause of a ``try``\n... ``finally`` construct. If the generator is not resumed before it\nis finalized (by reaching a zero reference count or by being garbage\ncollected), the generator-iterator\'s ``close()`` method will be\ncalled, allowing any pending ``finally`` clauses to execute.\n\nWhen ``yield from `` is used, it treats the supplied expression\nas a subiterator, producing values from it until the underlying\niterator is exhausted.\n\n Changed in version 3.3: Added ``yield from `` to delegate\n control flow to a subiterator\n\nFor full details of ``yield`` semantics, refer to the *Yield\nexpressions* section.\n\nSee also:\n\n **PEP 0255** - Simple Generators\n The proposal for adding generators and the ``yield`` statement\n to Python.\n\n **PEP 0342** - Coroutines via Enhanced Generators\n The proposal to enhance the API and syntax of generators, making\n them usable as simple coroutines.\n\n **PEP 0380** - Syntax for Delegating to a Subgenerator\n The proposal to introduce the ``yield_from`` syntax, making\n delegation to sub-generators easy.\n'} + 'naming': '\nNaming and binding\n******************\n\n*Names* refer to objects. Names are introduced by name binding\noperations. Each occurrence of a name in the program text refers to\nthe *binding* of that name established in the innermost function block\ncontaining the use.\n\nA *block* is a piece of Python program text that is executed as a\nunit. The following are blocks: a module, a function body, and a class\ndefinition. Each command typed interactively is a block. A script\nfile (a file given as standard input to the interpreter or specified\non the interpreter command line the first argument) is a code block.\nA script command (a command specified on the interpreter command line\nwith the \'**-c**\' option) is a code block. The string argument passed\nto the built-in functions "eval()" and "exec()" is a code block.\n\nA code block is executed in an *execution frame*. A frame contains\nsome administrative information (used for debugging) and determines\nwhere and how execution continues after the code block\'s execution has\ncompleted.\n\nA *scope* defines the visibility of a name within a block. If a local\nvariable is defined in a block, its scope includes that block. If the\ndefinition occurs in a function block, the scope extends to any blocks\ncontained within the defining one, unless a contained block introduces\na different binding for the name. The scope of names defined in a\nclass block is limited to the class block; it does not extend to the\ncode blocks of methods -- this includes comprehensions and generator\nexpressions since they are implemented using a function scope. This\nmeans that the following will fail:\n\n class A:\n a = 42\n b = list(a + i for i in range(10))\n\nWhen a name is used in a code block, it is resolved using the nearest\nenclosing scope. The set of all such scopes visible to a code block\nis called the block\'s *environment*.\n\nIf a name is bound in a block, it is a local variable of that block,\nunless declared as "nonlocal". If a name is bound at the module\nlevel, it is a global variable. (The variables of the module code\nblock are local and global.) If a variable is used in a code block\nbut not defined there, it is a *free variable*.\n\nWhen a name is not found at all, a "NameError" exception is raised.\nIf the name refers to a local variable that has not been bound, a\n"UnboundLocalError" exception is raised. "UnboundLocalError" is a\nsubclass of "NameError".\n\nThe following constructs bind names: formal parameters to functions,\n"import" statements, class and function definitions (these bind the\nclass or function name in the defining block), and targets that are\nidentifiers if occurring in an assignment, "for" loop header, or after\n"as" in a "with" statement or "except" clause. The "import" statement\nof the form "from ... import *" binds all names defined in the\nimported module, except those beginning with an underscore. This form\nmay only be used at the module level.\n\nA target occurring in a "del" statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name).\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the "global" statement occurs within a block, all uses of the name\nspecified in the statement refer to the binding of that name in the\ntop-level namespace. Names are resolved in the top-level namespace by\nsearching the global namespace, i.e. the namespace of the module\ncontaining the code block, and the builtins namespace, the namespace\nof the module "builtins". The global namespace is searched first. If\nthe name is not found there, the builtins namespace is searched. The\nglobal statement must precede all uses of the name.\n\nThe builtins namespace associated with the execution of a code block\nis actually found by looking up the name "__builtins__" in its global\nnamespace; this should be a dictionary or a module (in the latter case\nthe module\'s dictionary is used). By default, when in the "__main__"\nmodule, "__builtins__" is the built-in module "builtins"; when in any\nother module, "__builtins__" is an alias for the dictionary of the\n"builtins" module itself. "__builtins__" can be set to a user-created\ndictionary to create a weak form of restricted execution.\n\n**CPython implementation detail:** Users should not touch\n"__builtins__"; it is strictly an implementation detail. Users\nwanting to override values in the builtins namespace should "import"\nthe "builtins" module and modify its attributes appropriately.\n\nThe namespace for a module is automatically created the first time a\nmodule is imported. The main module for a script is always called\n"__main__".\n\nThe "global" statement has the same scope as a name binding operation\nin the same block. If the nearest enclosing scope for a free variable\ncontains a global statement, the free variable is treated as a global.\n\nA class definition is an executable statement that may use and define\nnames. These references follow the normal rules for name resolution.\nThe namespace of the class definition becomes the attribute dictionary\nof the class. Names defined at the class scope are not visible in\nmethods.\n\n\nInteraction with dynamic features\n=================================\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- "import *" --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a "SyntaxError".\n\nThe "eval()" and "exec()" functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe "exec()" and "eval()" functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n', + 'nonlocal': '\nThe "nonlocal" statement\n************************\n\n nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*\n\nThe "nonlocal" statement causes the listed identifiers to refer to\npreviously bound variables in the nearest enclosing scope. This is\nimportant because the default behavior for binding is to search the\nlocal namespace first. The statement allows encapsulated code to\nrebind variables outside of the local scope besides the global\n(module) scope.\n\nNames listed in a "nonlocal" statement, unlike to those listed in a\n"global" statement, must refer to pre-existing bindings in an\nenclosing scope (the scope in which a new binding should be created\ncannot be determined unambiguously).\n\nNames listed in a "nonlocal" statement must not collide with pre-\nexisting bindings in the local scope.\n\nSee also: **PEP 3104** - Access to Names in Outer Scopes\n\n The specification for the "nonlocal" statement.\n', + 'numbers': '\nNumeric literals\n****************\n\nThere are three types of numeric literals: integers, floating point\nnumbers, and imaginary numbers. There are no complex literals\n(complex numbers can be formed by adding a real number and an\nimaginary number).\n\nNote that numeric literals do not include a sign; a phrase like "-1"\nis actually an expression composed of the unary operator \'"-"\' and the\nliteral "1".\n', + 'numeric-types': '\nEmulating numeric types\n***********************\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "/", "//", "%", "divmod()", "pow()",\n "**", "<<", ">>", "&", "^", "|"). For instance, to evaluate the\n expression "x + y", where *x* is an instance of a class that has an\n "__add__()" method, "x.__add__(y)" is called. The "__divmod__()"\n method should be the equivalent to using "__floordiv__()" and\n "__mod__()"; it should not be related to "__truediv__()". Note\n that "__pow__()" should be defined to accept an optional third\n argument if the ternary version of the built-in "pow()" function is\n to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return "NotImplemented".\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "/", "//", "%", "divmod()", "pow()",\n "**", "<<", ">>", "&", "^", "|") with reflected (swapped) operands.\n These functions are only called if the left operand does not\n support the corresponding operation and the operands are of\n different types. [2] For instance, to evaluate the expression "x -\n y", where *y* is an instance of a class that has an "__rsub__()"\n method, "y.__rsub__(x)" is called if "x.__sub__(y)" returns\n *NotImplemented*.\n\n Note that ternary "pow()" will not try calling "__rpow__()" (the\n coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left\n operand\'s type and that subclass provides the reflected method\n for the operation, this method will be called before the left\n operand\'s non-reflected method. This behavior allows subclasses\n to override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments ("+=", "-=", "*=", "/=", "//=", "%=", "**=", "<<=",\n ">>=", "&=", "^=", "|="). These methods should attempt to do the\n operation in-place (modifying *self*) and return the result (which\n could be, but does not have to be, *self*). If a specific method\n is not defined, the augmented assignment falls back to the normal\n methods. For instance, to execute the statement "x += y", where\n *x* is an instance of a class that has an "__iadd__()" method,\n "x.__iadd__(y)" is called. If *x* is an instance of a class that\n does not define a "__iadd__()" method, "x.__add__(y)" and\n "y.__radd__(x)" are considered, as with the evaluation of "x + y".\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations ("-", "+",\n "abs()" and "~").\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions "complex()", "int()",\n "float()" and "round()". Should return a value of the appropriate\n type.\n\nobject.__index__(self)\n\n Called to implement "operator.index()", and whenever Python needs\n to losslessly convert the numeric object to an integer object (such\n as in slicing, or in the built-in "bin()", "hex()" and "oct()"\n functions). Presence of this method indicates that the numeric\n object is an integer type. Must return an integer.\n\n Note: When "__index__()" is defined, "__int__()" should also be\n defined, and both shuld return the same value, in order to have a\n coherent integer type class.\n', + 'objects': '\nObjects, values and types\n*************************\n\n*Objects* are Python\'s abstraction for data. All data in a Python\nprogram is represented by objects or by relations between objects. (In\na sense, and in conformance to Von Neumann\'s model of a "stored\nprogram computer," code is also represented by objects.)\n\nEvery object has an identity, a type and a value. An object\'s\n*identity* never changes once it has been created; you may think of it\nas the object\'s address in memory. The \'"is"\' operator compares the\nidentity of two objects; the "id()" function returns an integer\nrepresenting its identity.\n\n**CPython implementation detail:** For CPython, "id(x)" is the memory\naddress where "x" is stored.\n\nAn object\'s type determines the operations that the object supports\n(e.g., "does it have a length?") and also defines the possible values\nfor objects of that type. The "type()" function returns an object\'s\ntype (which is an object itself). Like its identity, an object\'s\n*type* is also unchangeable. [1]\n\nThe *value* of some objects can change. Objects whose value can\nchange are said to be *mutable*; objects whose value is unchangeable\nonce they are created are called *immutable*. (The value of an\nimmutable container object that contains a reference to a mutable\nobject can change when the latter\'s value is changed; however the\ncontainer is still considered immutable, because the collection of\nobjects it contains cannot be changed. So, immutability is not\nstrictly the same as having an unchangeable value, it is more subtle.)\nAn object\'s mutability is determined by its type; for instance,\nnumbers, strings and tuples are immutable, while dictionaries and\nlists are mutable.\n\nObjects are never explicitly destroyed; however, when they become\nunreachable they may be garbage-collected. An implementation is\nallowed to postpone garbage collection or omit it altogether --- it is\na matter of implementation quality how garbage collection is\nimplemented, as long as no objects are collected that are still\nreachable.\n\n**CPython implementation detail:** CPython currently uses a reference-\ncounting scheme with (optional) delayed detection of cyclically linked\ngarbage, which collects most objects as soon as they become\nunreachable, but is not guaranteed to collect garbage containing\ncircular references. See the documentation of the "gc" module for\ninformation on controlling the collection of cyclic garbage. Other\nimplementations act differently and CPython may change. Do not depend\non immediate finalization of objects when they become unreachable (ex:\nalways close files).\n\nNote that the use of the implementation\'s tracing or debugging\nfacilities may keep objects alive that would normally be collectable.\nAlso note that catching an exception with a \'"try"..."except"\'\nstatement may keep objects alive.\n\nSome objects contain references to "external" resources such as open\nfiles or windows. It is understood that these resources are freed\nwhen the object is garbage-collected, but since garbage collection is\nnot guaranteed to happen, such objects also provide an explicit way to\nrelease the external resource, usually a "close()" method. Programs\nare strongly recommended to explicitly close such objects. The\n\'"try"..."finally"\' statement and the \'"with"\' statement provide\nconvenient ways to do this.\n\nSome objects contain references to other objects; these are called\n*containers*. Examples of containers are tuples, lists and\ndictionaries. The references are part of a container\'s value. In\nmost cases, when we talk about the value of a container, we imply the\nvalues, not the identities of the contained objects; however, when we\ntalk about the mutability of a container, only the identities of the\nimmediately contained objects are implied. So, if an immutable\ncontainer (like a tuple) contains a reference to a mutable object, its\nvalue changes if that mutable object is changed.\n\nTypes affect almost all aspects of object behavior. Even the\nimportance of object identity is affected in some sense: for immutable\ntypes, operations that compute new values may actually return a\nreference to any existing object with the same type and value, while\nfor mutable objects this is not allowed. E.g., after "a = 1; b = 1",\n"a" and "b" may or may not refer to the same object with the value\none, depending on the implementation, but after "c = []; d = []", "c"\nand "d" are guaranteed to refer to two different, unique, newly\ncreated empty lists. (Note that "c = d = []" assigns the same object\nto both "c" and "d".)\n', + 'operator-summary': '\nOperator precedence\n*******************\n\nThe following table summarizes the operator precedences in Python,\nfrom lowest precedence (least binding) to highest precedence (most\nbinding). Operators in the same box have the same precedence. Unless\nthe syntax is explicitly given, operators are binary. Operators in\nthe same box group left to right (except for comparisons, including\ntests, which all have the same precedence and chain from left to right\n--- see section *Comparisons* --- and exponentiation, which groups\nfrom right to left).\n\n+-------------------------------------------------+---------------------------------------+\n| Operator | Description |\n+=================================================+=======================================+\n| "lambda" | Lambda expression |\n+-------------------------------------------------+---------------------------------------+\n| "if" -- "else" | Conditional expression |\n+-------------------------------------------------+---------------------------------------+\n| "or" | Boolean OR |\n+-------------------------------------------------+---------------------------------------+\n| "and" | Boolean AND |\n+-------------------------------------------------+---------------------------------------+\n| "not" "x" | Boolean NOT |\n+-------------------------------------------------+---------------------------------------+\n| "in", "not in", "is", "is not", "<", "<=", ">", | Comparisons, including membership |\n| ">=", "!=", "==" | tests and identity tests |\n+-------------------------------------------------+---------------------------------------+\n| "|" | Bitwise OR |\n+-------------------------------------------------+---------------------------------------+\n| "^" | Bitwise XOR |\n+-------------------------------------------------+---------------------------------------+\n| "&" | Bitwise AND |\n+-------------------------------------------------+---------------------------------------+\n| "<<", ">>" | Shifts |\n+-------------------------------------------------+---------------------------------------+\n| "+", "-" | Addition and subtraction |\n+-------------------------------------------------+---------------------------------------+\n| "*", "/", "//", "%" | Multiplication, division, remainder |\n+-------------------------------------------------+---------------------------------------+\n| "+x", "-x", "~x" | Positive, negative, bitwise NOT |\n+-------------------------------------------------+---------------------------------------+\n| "**" | Exponentiation [6] |\n+-------------------------------------------------+---------------------------------------+\n| "x[index]", "x[index:index]", | Subscription, slicing, call, |\n| "x(arguments...)", "x.attribute" | attribute reference |\n+-------------------------------------------------+---------------------------------------+\n| "(expressions...)", "[expressions...]", "{key: | Binding or tuple display, list |\n| value...}", "{expressions...}" | display, dictionary display, set |\n+-------------------------------------------------+---------------------------------------+\n\n-[ Footnotes ]-\n\n[1] While "abs(x%y) < abs(y)" is true mathematically, for floats\n it may not be true numerically due to roundoff. For example, and\n assuming a platform on which a Python float is an IEEE 754 double-\n precision number, in order that "-1e-100 % 1e100" have the same\n sign as "1e100", the computed result is "-1e-100 + 1e100", which\n is numerically exactly equal to "1e100". The function\n "math.fmod()" returns a result whose sign matches the sign of the\n first argument instead, and so returns "-1e-100" in this case.\n Which approach is more appropriate depends on the application.\n\n[2] If x is very close to an exact integer multiple of y, it\'s\n possible for "x//y" to be one larger than "(x-x%y)//y" due to\n rounding. In such cases, Python returns the latter result, in\n order to preserve that "divmod(x,y)[0] * y + x % y" be very close\n to "x".\n\n[3] While comparisons between strings make sense at the byte\n level, they may be counter-intuitive to users. For example, the\n strings ""\\u00C7"" and ""\\u0327\\u0043"" compare differently, even\n though they both represent the same unicode character (LATIN\n CAPITAL LETTER C WITH CEDILLA). To compare strings in a human\n recognizable way, compare using "unicodedata.normalize()".\n\n[4] Due to automatic garbage-collection, free lists, and the\n dynamic nature of descriptors, you may notice seemingly unusual\n behaviour in certain uses of the "is" operator, like those\n involving comparisons between instance methods, or constants.\n Check their documentation for more info.\n\n[5] The "%" operator is also used for string formatting; the same\n precedence applies.\n\n[6] The power operator "**" binds less tightly than an arithmetic\n or bitwise unary operator on its right, that is, "2**-1" is "0.5".\n', + 'pass': '\nThe "pass" statement\n********************\n\n pass_stmt ::= "pass"\n\n"pass" is a null operation --- when it is executed, nothing happens.\nIt is useful as a placeholder when a statement is required\nsyntactically, but no code needs to be executed, for example:\n\n def f(arg): pass # a function that does nothing (yet)\n\n class C: pass # a class with no methods (yet)\n', + 'power': '\nThe power operator\n******************\n\nThe power operator binds more tightly than unary operators on its\nleft; it binds less tightly than unary operators on its right. The\nsyntax is:\n\n power ::= primary ["**" u_expr]\n\nThus, in an unparenthesized sequence of power and unary operators, the\noperators are evaluated from right to left (this does not constrain\nthe evaluation order for the operands): "-1**2" results in "-1".\n\nThe power operator has the same semantics as the built-in "pow()"\nfunction, when called with two arguments: it yields its left argument\nraised to the power of its right argument. The numeric arguments are\nfirst converted to a common type, and the result is of that type.\n\nFor int operands, the result has the same type as the operands unless\nthe second argument is negative; in that case, all arguments are\nconverted to float and a float result is delivered. For example,\n"10**2" returns "100", but "10**-2" returns "0.01".\n\nRaising "0.0" to a negative power results in a "ZeroDivisionError".\nRaising a negative number to a fractional power results in a "complex"\nnumber. (In earlier versions it raised a "ValueError".)\n', + 'raise': '\nThe "raise" statement\n*********************\n\n raise_stmt ::= "raise" [expression ["from" expression]]\n\nIf no expressions are present, "raise" re-raises the last exception\nthat was active in the current scope. If no exception is active in\nthe current scope, a "RuntimeError" exception is raised indicating\nthat this is an error.\n\nOtherwise, "raise" evaluates the first expression as the exception\nobject. It must be either a subclass or an instance of\n"BaseException". If it is a class, the exception instance will be\nobtained when needed by instantiating the class with no arguments.\n\nThe *type* of the exception is the exception instance\'s class, the\n*value* is the instance itself.\n\nA traceback object is normally created automatically when an exception\nis raised and attached to it as the "__traceback__" attribute, which\nis writable. You can create an exception and set your own traceback in\none step using the "with_traceback()" exception method (which returns\nthe same exception instance, with its traceback set to its argument),\nlike so:\n\n raise Exception("foo occurred").with_traceback(tracebackobj)\n\nThe "from" clause is used for exception chaining: if given, the second\n*expression* must be another exception class or instance, which will\nthen be attached to the raised exception as the "__cause__" attribute\n(which is writable). If the raised exception is not handled, both\nexceptions will be printed:\n\n >>> try:\n ... print(1 / 0)\n ... except Exception as exc:\n ... raise RuntimeError("Something bad happened") from exc\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n The above exception was the direct cause of the following exception:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nA similar mechanism works implicitly if an exception is raised inside\nan exception handler: the previous exception is then attached as the\nnew exception\'s "__context__" attribute:\n\n >>> try:\n ... print(1 / 0)\n ... except:\n ... raise RuntimeError("Something bad happened")\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n During handling of the above exception, another exception occurred:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information about handling exceptions is in section\n*The try statement*.\n', + 'return': '\nThe "return" statement\n**********************\n\n return_stmt ::= "return" [expression_list]\n\n"return" may only occur syntactically nested in a function definition,\nnot within a nested class definition.\n\nIf an expression list is present, it is evaluated, else "None" is\nsubstituted.\n\n"return" leaves the current function call with the expression list (or\n"None") as return value.\n\nWhen "return" passes control out of a "try" statement with a "finally"\nclause, that "finally" clause is executed before really leaving the\nfunction.\n\nIn a generator function, the "return" statement indicates that the\ngenerator is done and will cause "StopIteration" to be raised. The\nreturned value (if any) is used as an argument to construct\n"StopIteration" and becomes the "StopIteration.value" attribute.\n', + 'sequence-types': '\nEmulating container types\n*************************\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which "0 <= k < N" where\n*N* is the length of the sequence, or slice objects, which define a\nrange of items. It is also recommended that mappings provide the\nmethods "keys()", "values()", "items()", "get()", "clear()",\n"setdefault()", "pop()", "popitem()", "copy()", and "update()"\nbehaving similar to those for Python\'s standard dictionary objects.\nThe "collections" module provides a "MutableMapping" abstract base\nclass to help create those methods from a base set of "__getitem__()",\n"__setitem__()", "__delitem__()", and "keys()". Mutable sequences\nshould provide methods "append()", "count()", "index()", "extend()",\n"insert()", "pop()", "remove()", "reverse()" and "sort()", like Python\nstandard list objects. Finally, sequence types should implement\naddition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods "__add__()", "__radd__()",\n"__iadd__()", "__mul__()", "__rmul__()" and "__imul__()" described\nbelow; they should not define other numerical operators. It is\nrecommended that both mappings and sequences implement the\n"__contains__()" method to allow efficient use of the "in" operator;\nfor mappings, "in" should search the mapping\'s keys; for sequences, it\nshould search through the values. It is further recommended that both\nmappings and sequences implement the "__iter__()" method to allow\nefficient iteration through the container; for mappings, "__iter__()"\nshould be the same as "keys()"; for sequences, it should iterate\nthrough the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function "len()". Should return\n the length of the object, an integer ">=" 0. Also, an object that\n doesn\'t define a "__bool__()" method and whose "__len__()" method\n returns zero is considered to be false in a Boolean context.\n\nobject.__length_hint__(self)\n\n Called to implement "operator.length_hint()". Should return an\n estimated length for the object (which may be greater or less than\n the actual length). The length must be an integer ">=" 0. This\n method is purely an optimization and is never required for\n correctness.\n\n New in version 3.4.\n\nNote: Slicing is done exclusively with the following three methods.\n A call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with "None".\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of "self[key]". For sequence types,\n the accepted keys should be integers and slice objects. Note that\n the special interpretation of negative indexes (if the class wishes\n to emulate a sequence type) is up to the "__getitem__()" method. If\n *key* is of an inappropriate type, "TypeError" may be raised; if of\n a value outside the set of indexes for the sequence (after any\n special interpretation of negative values), "IndexError" should be\n raised. For mapping types, if *key* is missing (not in the\n container), "KeyError" should be raised.\n\n Note: "for" loops expect that an "IndexError" will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the "__getitem__()" method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the "__getitem__()" method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method "keys()".\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the "reversed()" built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the "__reversed__()" method is not provided, the "reversed()"\n built-in will fall back to using the sequence protocol ("__len__()"\n and "__getitem__()"). Objects that support the sequence protocol\n should only provide "__reversed__()" if they can provide an\n implementation that is more efficient than the one provided by\n "reversed()".\n\nThe membership test operators ("in" and "not in") are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define "__contains__()", the membership test\n first tries iteration via "__iter__()", then the old sequence\n iteration protocol via "__getitem__()", see *this section in the\n language reference*.\n', + 'shifting': '\nShifting operations\n*******************\n\nThe shifting operations have lower priority than the arithmetic\noperations:\n\n shift_expr ::= a_expr | shift_expr ( "<<" | ">>" ) a_expr\n\nThese operators accept integers as arguments. They shift the first\nargument to the left or right by the number of bits given by the\nsecond argument.\n\nA right shift by *n* bits is defined as floor division by "pow(2,n)".\nA left shift by *n* bits is defined as multiplication with "pow(2,n)".\n\nNote: In the current implementation, the right-hand operand is\n required to be at most "sys.maxsize". If the right-hand operand is\n larger than "sys.maxsize" an "OverflowError" exception is raised.\n', + 'slicings': '\nSlicings\n********\n\nA slicing selects a range of items in a sequence object (e.g., a\nstring, tuple or list). Slicings may be used as expressions or as\ntargets in assignment or "del" statements. The syntax for a slicing:\n\n slicing ::= primary "[" slice_list "]"\n slice_list ::= slice_item ("," slice_item)* [","]\n slice_item ::= expression | proper_slice\n proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" [stride] ]\n lower_bound ::= expression\n upper_bound ::= expression\n stride ::= expression\n\nThere is ambiguity in the formal syntax here: anything that looks like\nan expression list also looks like a slice list, so any subscription\ncan be interpreted as a slicing. Rather than further complicating the\nsyntax, this is disambiguated by defining that in this case the\ninterpretation as a subscription takes priority over the\ninterpretation as a slicing (this is the case if the slice list\ncontains no proper slice).\n\nThe semantics for a slicing are as follows. The primary must evaluate\nto a mapping object, and it is indexed (using the same "__getitem__()"\nmethod as normal subscription) with a key that is constructed from the\nslice list, as follows. If the slice list contains at least one\ncomma, the key is a tuple containing the conversion of the slice\nitems; otherwise, the conversion of the lone slice item is the key.\nThe conversion of a slice item that is an expression is that\nexpression. The conversion of a proper slice is a slice object (see\nsection *The standard type hierarchy*) whose "start", "stop" and\n"step" attributes are the values of the expressions given as lower\nbound, upper bound and stride, respectively, substituting "None" for\nmissing expressions.\n', + 'specialattrs': '\nSpecial Attributes\n******************\n\nThe implementation adds a few special read-only attributes to several\nobject types, where they are relevant. Some of these are not reported\nby the "dir()" built-in function.\n\nobject.__dict__\n\n A dictionary or other mapping object used to store an object\'s\n (writable) attributes.\n\ninstance.__class__\n\n The class to which a class instance belongs.\n\nclass.__bases__\n\n The tuple of base classes of a class object.\n\nclass.__name__\n\n The name of the class or type.\n\nclass.__qualname__\n\n The *qualified name* of the class or type.\n\n New in version 3.3.\n\nclass.__mro__\n\n This attribute is a tuple of classes that are considered when\n looking for base classes during method resolution.\n\nclass.mro()\n\n This method can be overridden by a metaclass to customize the\n method resolution order for its instances. It is called at class\n instantiation, and its result is stored in "__mro__".\n\nclass.__subclasses__()\n\n Each class keeps a list of weak references to its immediate\n subclasses. This method returns a list of all those references\n still alive. Example:\n\n >>> int.__subclasses__()\n []\n\n-[ Footnotes ]-\n\n[1] Additional information on these special methods may be found\n in the Python Reference Manual (*Basic customization*).\n\n[2] As a consequence, the list "[1, 2]" is considered equal to\n "[1.0, 2.0]", and similarly for tuples.\n\n[3] They must have since the parser can\'t tell the type of the\n operands.\n\n[4] Cased characters are those with general category property\n being one of "Lu" (Letter, uppercase), "Ll" (Letter, lowercase),\n or "Lt" (Letter, titlecase).\n\n[5] To format only a tuple you should therefore provide a\n singleton tuple whose only element is the tuple to be formatted.\n', + 'specialnames': '\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named "__getitem__()", and "x" is an instance of this class,\nthen "x[i]" is roughly equivalent to "type(x).__getitem__(x, i)".\nExcept where mentioned, attempts to execute an operation raise an\nexception when no appropriate method is defined (typically\n"AttributeError" or "TypeError").\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n"NodeList" interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. "__new__()" is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of "__new__()" should be the new object instance (usually an\n instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s "__new__()" method using\n "super(currentclass, cls).__new__(cls[, ...])" with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If "__new__()" returns an instance of *cls*, then the new\n instance\'s "__init__()" method will be invoked like\n "__init__(self[, ...])", where *self* is the new instance and the\n remaining arguments are the same as were passed to "__new__()".\n\n If "__new__()" does not return an instance of *cls*, then the new\n instance\'s "__init__()" method will not be invoked.\n\n "__new__()" is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n "__init__()" method, the derived class\'s "__init__()" method, if\n any, must explicitly call it to ensure proper initialization of the\n base class part of the instance; for example:\n "BaseClass.__init__(self, [args...])". As a special constraint on\n constructors, no value may be returned; doing so will cause a\n "TypeError" to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a "__del__()" method, the\n derived class\'s "__del__()" method, if any, must explicitly call it\n to ensure proper deletion of the base class part of the instance.\n Note that it is possible (though not recommended!) for the\n "__del__()" method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n "__del__()" methods are called for objects that still exist when\n the interpreter exits.\n\n Note: "del x" doesn\'t directly call "x.__del__()" --- the former\n decrements the reference count for "x" by one, and the latter is\n only called when "x"\'s reference count reaches zero. Some common\n situations that may prevent the reference count of an object from\n going to zero include: circular references between objects (e.g.,\n a doubly-linked list or a tree data structure with parent and\n child pointers); a reference to the object on the stack frame of\n a function that caught an exception (the traceback stored in\n "sys.exc_info()[2]" keeps the stack frame alive); or a reference\n to the object on the stack frame that raised an unhandled\n exception in interactive mode (the traceback stored in\n "sys.last_traceback" keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing "None" in\n "sys.last_traceback". Circular references which are garbage are\n detected and cleaned up when the cyclic garbage collector is\n enabled (it\'s on by default). Refer to the documentation for the\n "gc" module for more information about this topic.\n\n Warning: Due to the precarious circumstances under which\n "__del__()" methods are invoked, exceptions that occur during\n their execution are ignored, and a warning is printed to\n "sys.stderr" instead. Also, when "__del__()" is invoked in\n response to a module being deleted (e.g., when execution of the\n program is done), other globals referenced by the "__del__()"\n method may already have been deleted or in the process of being\n torn down (e.g. the import machinery shutting down). For this\n reason, "__del__()" methods should do the absolute minimum needed\n to maintain external invariants. Starting with version 1.5,\n Python guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the "__del__()" method is called.\n\nobject.__repr__(self)\n\n Called by the "repr()" built-in function to compute the "official"\n string representation of an object. If at all possible, this\n should look like a valid Python expression that could be used to\n recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n "<...some useful description...>" should be returned. The return\n value must be a string object. If a class defines "__repr__()" but\n not "__str__()", then "__repr__()" is also used when an "informal"\n string representation of instances of that class is required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by "str(object)" and the built-in functions "format()" and\n "print()" to compute the "informal" or nicely printable string\n representation of an object. The return value must be a *string*\n object.\n\n This method differs from "object.__repr__()" in that there is no\n expectation that "__str__()" return a valid Python expression: a\n more convenient or concise representation can be used.\n\n The default implementation defined by the built-in type "object"\n calls "object.__repr__()".\n\nobject.__bytes__(self)\n\n Called by "bytes()" to compute a byte-string representation of an\n object. This should return a "bytes" object.\n\nobject.__format__(self, format_spec)\n\n Called by the "format()" built-in function (and by extension, the\n "str.format()" method of class "str") to produce a "formatted"\n string representation of an object. The "format_spec" argument is a\n string that contains a description of the formatting options\n desired. The interpretation of the "format_spec" argument is up to\n the type implementing "__format__()", however most classes will\n either delegate formatting to one of the built-in types, or use a\n similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: "xy" calls\n "x.__gt__(y)", and "x>=y" calls "x.__ge__(y)".\n\n A rich comparison method may return the singleton "NotImplemented"\n if it does not implement the operation for a given pair of\n arguments. By convention, "False" and "True" are returned for a\n successful comparison. However, these methods can return any value,\n so if the comparison operator is used in a Boolean context (e.g.,\n in the condition of an "if" statement), Python will call "bool()"\n on the value to determine if the result is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of "x==y" does not imply that "x!=y" is false.\n Accordingly, when defining "__eq__()", one should also define\n "__ne__()" so that the operators will behave as expected. See the\n paragraph on "__hash__()" for some important notes on creating\n *hashable* objects which support custom comparison operations and\n are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, "__lt__()" and "__gt__()" are each other\'s\n reflection, "__le__()" and "__ge__()" are each other\'s reflection,\n and "__eq__()" and "__ne__()" are their own reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see "functools.total_ordering()".\n\nobject.__hash__(self)\n\n Called by built-in function "hash()" and for operations on members\n of hashed collections including "set", "frozenset", and "dict".\n "__hash__()" should return an integer. The only required property\n is that objects which compare equal have the same hash value; it is\n advised to somehow mix together (e.g. using exclusive or) the hash\n values for the components of the object that also play a part in\n comparison of objects.\n\n Note: "hash()" truncates the value returned from an object\'s\n custom "__hash__()" method to the size of a "Py_ssize_t". This\n is typically 8 bytes on 64-bit builds and 4 bytes on 32-bit\n builds. If an object\'s "__hash__()" must interoperate on builds\n of different bit sizes, be sure to check the width on all\n supported builds. An easy way to do this is with "python -c\n "import sys; print(sys.hash_info.width)""\n\n If a class does not define an "__eq__()" method it should not\n define a "__hash__()" operation either; if it defines "__eq__()"\n but not "__hash__()", its instances will not be usable as items in\n hashable collections. If a class defines mutable objects and\n implements an "__eq__()" method, it should not implement\n "__hash__()", since the implementation of hashable collections\n requires that a key\'s hash value is immutable (if the object\'s hash\n value changes, it will be in the wrong hash bucket).\n\n User-defined classes have "__eq__()" and "__hash__()" methods by\n default; with them, all objects compare unequal (except with\n themselves) and "x.__hash__()" returns an appropriate value such\n that "x == y" implies both that "x is y" and "hash(x) == hash(y)".\n\n A class that overrides "__eq__()" and does not define "__hash__()"\n will have its "__hash__()" implicitly set to "None". When the\n "__hash__()" method of a class is "None", instances of the class\n will raise an appropriate "TypeError" when a program attempts to\n retrieve their hash value, and will also be correctly identified as\n unhashable when checking "isinstance(obj, collections.Hashable").\n\n If a class that overrides "__eq__()" needs to retain the\n implementation of "__hash__()" from a parent class, the interpreter\n must be told this explicitly by setting "__hash__ =\n .__hash__".\n\n If a class that does not override "__eq__()" wishes to suppress\n hash support, it should include "__hash__ = None" in the class\n definition. A class which defines its own "__hash__()" that\n explicitly raises a "TypeError" would be incorrectly identified as\n hashable by an "isinstance(obj, collections.Hashable)" call.\n\n Note: By default, the "__hash__()" values of str, bytes and\n datetime objects are "salted" with an unpredictable random value.\n Although they remain constant within an individual Python\n process, they are not predictable between repeated invocations of\n Python.This is intended to provide protection against a denial-\n of-service caused by carefully-chosen inputs that exploit the\n worst case performance of a dict insertion, O(n^2) complexity.\n See http://www.ocert.org/advisories/ocert-2011-003.html for\n details.Changing hash values affects the iteration order of\n dicts, sets and other mappings. Python has never made guarantees\n about this ordering (and it typically varies between 32-bit and\n 64-bit builds).See also "PYTHONHASHSEED".\n\n Changed in version 3.3: Hash randomization is enabled by default.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n "bool()"; should return "False" or "True". When this method is not\n defined, "__len__()" is called, if it is defined, and the object is\n considered true if its result is nonzero. If a class defines\n neither "__len__()" nor "__bool__()", all its instances are\n considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of "x.name") for\nclass instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for "self"). "name" is the attribute name. This\n method should return the (computed) attribute value or raise an\n "AttributeError" exception.\n\n Note that if the attribute is found through the normal mechanism,\n "__getattr__()" is not called. (This is an intentional asymmetry\n between "__getattr__()" and "__setattr__()".) This is done both for\n efficiency reasons and because otherwise "__getattr__()" would have\n no way to access other attributes of the instance. Note that at\n least for instance variables, you can fake total control by not\n inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n "__getattribute__()" method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines "__getattr__()",\n the latter will not be called unless "__getattribute__()" either\n calls it explicitly or raises an "AttributeError". This method\n should return the (computed) attribute value or raise an\n "AttributeError" exception. In order to avoid infinite recursion in\n this method, its implementation should always call the base class\n method with the same name to access any attributes it needs, for\n example, "object.__getattribute__(self, name)".\n\n Note: This method may still be bypassed when looking up special\n methods as the result of implicit invocation via language syntax\n or built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If "__setattr__()" wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n "object.__setattr__(self, name, value)".\n\nobject.__delattr__(self, name)\n\n Like "__setattr__()" but for attribute deletion instead of\n assignment. This should only be implemented if "del obj.name" is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when "dir()" is called on the object. A sequence must be\n returned. "dir()" converts the returned sequence to a list and\n sorts it.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in an\n*owner* class (the descriptor must be in either the owner\'s class\ndictionary or in the class dictionary for one of its parents). In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' "__dict__".\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or "None" when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an "AttributeError"\n exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: "__get__()", "__set__()", and\n"__delete__()". If any of those methods are defined for an object, it\nis said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, "a.x" has a\nlookup chain starting with "a.__dict__[\'x\']", then\n"type(a).__dict__[\'x\']", and continuing through the base classes of\n"type(a)" excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, "a.x". How\nthe arguments are assembled depends on "a":\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: "x.__get__(a)".\n\nInstance Binding\n If binding to an object instance, "a.x" is transformed into the\n call: "type(a).__dict__[\'x\'].__get__(a, type(a))".\n\nClass Binding\n If binding to a class, "A.x" is transformed into the call:\n "A.__dict__[\'x\'].__get__(None, A)".\n\nSuper Binding\n If "a" is an instance of "super", then the binding "super(B,\n obj).m()" searches "obj.__class__.__mro__" for the base class "A"\n immediately preceding "B" and then invokes the descriptor with the\n call: "A.__dict__[\'m\'].__get__(obj, obj.__class__)".\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of "__get__()", "__set__()" and "__delete__()". If it\ndoes not define "__get__()", then accessing the attribute will return\nthe descriptor object itself unless there is a value in the object\'s\ninstance dictionary. If the descriptor defines "__set__()" and/or\n"__delete__()", it is a data descriptor; if it defines neither, it is\na non-data descriptor. Normally, data descriptors define both\n"__get__()" and "__set__()", while non-data descriptors have just the\n"__get__()" method. Data descriptors with "__set__()" and "__get__()"\ndefined always override a redefinition in an instance dictionary. In\ncontrast, non-data descriptors can be overridden by instances.\n\nPython methods (including "staticmethod()" and "classmethod()") are\nimplemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe "property()" function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises "AttributeError". If\n dynamic assignment of new variables is desired, then add\n "\'__dict__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes\n defining *__slots__* do not support weak references to its\n instances. If weak reference support is needed, then add\n "\'__weakref__\'" to the sequence of strings in the *__slots__*\n declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the\n instance variable defined by the base class slot is inaccessible\n (except by retrieving its descriptor directly from the base class).\n This renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as "int", "bytes" and "tuple".\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings\n may also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using "type()". The class body is\nexecuted in a new namespace and the class name is bound locally to the\nresult of "type(name, bases, namespace)".\n\nThe class creation process can be customised by passing the\n"metaclass" keyword argument in the class definition line, or by\ninheriting from an existing class that included such an argument. In\nthe following example, both "MyClass" and "MySubclass" are instances\nof "Meta":\n\n class Meta(type):\n pass\n\n class MyClass(metaclass=Meta):\n pass\n\n class MySubclass(MyClass):\n pass\n\nAny other keyword arguments that are specified in the class definition\nare passed through to all metaclass operations described below.\n\nWhen a class definition is executed, the following steps occur:\n\n* the appropriate metaclass is determined\n\n* the class namespace is prepared\n\n* the class body is executed\n\n* the class object is created\n\n\nDetermining the appropriate metaclass\n-------------------------------------\n\nThe appropriate metaclass for a class definition is determined as\nfollows:\n\n* if no bases and no explicit metaclass are given, then "type()" is\n used\n\n* if an explicit metaclass is given and it is *not* an instance of\n "type()", then it is used directly as the metaclass\n\n* if an instance of "type()" is given as the explicit metaclass, or\n bases are defined, then the most derived metaclass is used\n\nThe most derived metaclass is selected from the explicitly specified\nmetaclass (if any) and the metaclasses (i.e. "type(cls)") of all\nspecified base classes. The most derived metaclass is one which is a\nsubtype of *all* of these candidate metaclasses. If none of the\ncandidate metaclasses meets that criterion, then the class definition\nwill fail with "TypeError".\n\n\nPreparing the class namespace\n-----------------------------\n\nOnce the appropriate metaclass has been identified, then the class\nnamespace is prepared. If the metaclass has a "__prepare__" attribute,\nit is called as "namespace = metaclass.__prepare__(name, bases,\n**kwds)" (where the additional keyword arguments, if any, come from\nthe class definition).\n\nIf the metaclass has no "__prepare__" attribute, then the class\nnamespace is initialised as an empty "dict()" instance.\n\nSee also: **PEP 3115** - Metaclasses in Python 3000\n\n Introduced the "__prepare__" namespace hook\n\n\nExecuting the class body\n------------------------\n\nThe class body is executed (approximately) as "exec(body, globals(),\nnamespace)". The key difference from a normal call to "exec()" is that\nlexical scoping allows the class body (including any methods) to\nreference names from the current and outer scopes when the class\ndefinition occurs inside a function.\n\nHowever, even when the class definition occurs inside the function,\nmethods defined inside the class still cannot see names defined at the\nclass scope. Class variables must be accessed through the first\nparameter of instance or class methods, and cannot be accessed at all\nfrom static methods.\n\n\nCreating the class object\n-------------------------\n\nOnce the class namespace has been populated by executing the class\nbody, the class object is created by calling "metaclass(name, bases,\nnamespace, **kwds)" (the additional keywords passed here are the same\nas those passed to "__prepare__").\n\nThis class object is the one that will be referenced by the zero-\nargument form of "super()". "__class__" is an implicit closure\nreference created by the compiler if any methods in a class body refer\nto either "__class__" or "super". This allows the zero argument form\nof "super()" to correctly identify the class being defined based on\nlexical scoping, while the class or instance that was used to make the\ncurrent call is identified based on the first argument passed to the\nmethod.\n\nAfter the class object is created, it is passed to the class\ndecorators included in the class definition (if any) and the resulting\nobject is bound in the local namespace as the defined class.\n\nSee also: **PEP 3135** - New super\n\n Describes the implicit "__class__" closure reference\n\n\nMetaclass example\n-----------------\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored include logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n"collections.OrderedDict" to remember the order that class members\nwere defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, namespace, **kwds):\n result = type.__new__(cls, name, bases, dict(namespace))\n result.members = tuple(namespace)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s "__prepare__()" method which returns an\nempty "collections.OrderedDict". That mapping records the methods and\nattributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s "__new__()" method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called "members".\n\n\nCustomizing instance and subclass checks\n========================================\n\nThe following methods are used to override the default behavior of the\n"isinstance()" and "issubclass()" built-in functions.\n\nIn particular, the metaclass "abc.ABCMeta" implements these methods in\norder to allow the addition of Abstract Base Classes (ABCs) as\n"virtual base classes" to any class or type (including built-in\ntypes), including other ABCs.\n\nclass.__instancecheck__(self, instance)\n\n Return true if *instance* should be considered a (direct or\n indirect) instance of *class*. If defined, called to implement\n "isinstance(instance, class)".\n\nclass.__subclasscheck__(self, subclass)\n\n Return true if *subclass* should be considered a (direct or\n indirect) subclass of *class*. If defined, called to implement\n "issubclass(subclass, class)".\n\nNote that these methods are looked up on the type (metaclass) of a\nclass. They cannot be defined as class methods in the actual class.\nThis is consistent with the lookup of special methods that are called\non instances, only in this case the instance is itself a class.\n\nSee also: **PEP 3119** - Introducing Abstract Base Classes\n\n Includes the specification for customizing "isinstance()" and\n "issubclass()" behavior through "__instancecheck__()" and\n "__subclasscheck__()", with motivation for this functionality in\n the context of adding Abstract Base Classes (see the "abc"\n module) to the language.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, "x(arg1, arg2, ...)" is a shorthand for\n "x.__call__(arg1, arg2, ...)".\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which "0 <= k < N" where\n*N* is the length of the sequence, or slice objects, which define a\nrange of items. It is also recommended that mappings provide the\nmethods "keys()", "values()", "items()", "get()", "clear()",\n"setdefault()", "pop()", "popitem()", "copy()", and "update()"\nbehaving similar to those for Python\'s standard dictionary objects.\nThe "collections" module provides a "MutableMapping" abstract base\nclass to help create those methods from a base set of "__getitem__()",\n"__setitem__()", "__delitem__()", and "keys()". Mutable sequences\nshould provide methods "append()", "count()", "index()", "extend()",\n"insert()", "pop()", "remove()", "reverse()" and "sort()", like Python\nstandard list objects. Finally, sequence types should implement\naddition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods "__add__()", "__radd__()",\n"__iadd__()", "__mul__()", "__rmul__()" and "__imul__()" described\nbelow; they should not define other numerical operators. It is\nrecommended that both mappings and sequences implement the\n"__contains__()" method to allow efficient use of the "in" operator;\nfor mappings, "in" should search the mapping\'s keys; for sequences, it\nshould search through the values. It is further recommended that both\nmappings and sequences implement the "__iter__()" method to allow\nefficient iteration through the container; for mappings, "__iter__()"\nshould be the same as "keys()"; for sequences, it should iterate\nthrough the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function "len()". Should return\n the length of the object, an integer ">=" 0. Also, an object that\n doesn\'t define a "__bool__()" method and whose "__len__()" method\n returns zero is considered to be false in a Boolean context.\n\nobject.__length_hint__(self)\n\n Called to implement "operator.length_hint()". Should return an\n estimated length for the object (which may be greater or less than\n the actual length). The length must be an integer ">=" 0. This\n method is purely an optimization and is never required for\n correctness.\n\n New in version 3.4.\n\nNote: Slicing is done exclusively with the following three methods.\n A call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with "None".\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of "self[key]". For sequence types,\n the accepted keys should be integers and slice objects. Note that\n the special interpretation of negative indexes (if the class wishes\n to emulate a sequence type) is up to the "__getitem__()" method. If\n *key* is of an inappropriate type, "TypeError" may be raised; if of\n a value outside the set of indexes for the sequence (after any\n special interpretation of negative values), "IndexError" should be\n raised. For mapping types, if *key* is missing (not in the\n container), "KeyError" should be raised.\n\n Note: "for" loops expect that an "IndexError" will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the "__getitem__()" method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of "self[key]". Same note as for\n "__getitem__()". This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the "__getitem__()" method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method "keys()".\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the "reversed()" built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the "__reversed__()" method is not provided, the "reversed()"\n built-in will fall back to using the sequence protocol ("__len__()"\n and "__getitem__()"). Objects that support the sequence protocol\n should only provide "__reversed__()" if they can provide an\n implementation that is more efficient than the one provided by\n "reversed()".\n\nThe membership test operators ("in" and "not in") are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define "__contains__()", the membership test\n first tries iteration via "__iter__()", then the old sequence\n iteration protocol via "__getitem__()", see *this section in the\n language reference*.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "/", "//", "%", "divmod()", "pow()",\n "**", "<<", ">>", "&", "^", "|"). For instance, to evaluate the\n expression "x + y", where *x* is an instance of a class that has an\n "__add__()" method, "x.__add__(y)" is called. The "__divmod__()"\n method should be the equivalent to using "__floordiv__()" and\n "__mod__()"; it should not be related to "__truediv__()". Note\n that "__pow__()" should be defined to accept an optional third\n argument if the ternary version of the built-in "pow()" function is\n to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return "NotImplemented".\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations ("+", "-", "*", "/", "//", "%", "divmod()", "pow()",\n "**", "<<", ">>", "&", "^", "|") with reflected (swapped) operands.\n These functions are only called if the left operand does not\n support the corresponding operation and the operands are of\n different types. [2] For instance, to evaluate the expression "x -\n y", where *y* is an instance of a class that has an "__rsub__()"\n method, "y.__rsub__(x)" is called if "x.__sub__(y)" returns\n *NotImplemented*.\n\n Note that ternary "pow()" will not try calling "__rpow__()" (the\n coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left\n operand\'s type and that subclass provides the reflected method\n for the operation, this method will be called before the left\n operand\'s non-reflected method. This behavior allows subclasses\n to override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments ("+=", "-=", "*=", "/=", "//=", "%=", "**=", "<<=",\n ">>=", "&=", "^=", "|="). These methods should attempt to do the\n operation in-place (modifying *self*) and return the result (which\n could be, but does not have to be, *self*). If a specific method\n is not defined, the augmented assignment falls back to the normal\n methods. For instance, to execute the statement "x += y", where\n *x* is an instance of a class that has an "__iadd__()" method,\n "x.__iadd__(y)" is called. If *x* is an instance of a class that\n does not define a "__iadd__()" method, "x.__add__(y)" and\n "y.__radd__(x)" are considered, as with the evaluation of "x + y".\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations ("-", "+",\n "abs()" and "~").\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions "complex()", "int()",\n "float()" and "round()". Should return a value of the appropriate\n type.\n\nobject.__index__(self)\n\n Called to implement "operator.index()", and whenever Python needs\n to losslessly convert the numeric object to an integer object (such\n as in slicing, or in the built-in "bin()", "hex()" and "oct()"\n functions). Presence of this method indicates that the numeric\n object is an integer type. Must return an integer.\n\n Note: When "__index__()" is defined, "__int__()" should also be\n defined, and both shuld return the same value, in order to have a\n coherent integer type class.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a "with" statement. The context manager\nhandles the entry into, and the exit from, the desired runtime context\nfor the execution of the block of code. Context managers are normally\ninvoked using the "with" statement (described in section *The with\nstatement*), but can also be used by directly invoking their methods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The "with"\n statement will bind this method\'s return value to the target(s)\n specified in the "as" clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be "None".\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that "__exit__()" methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C:\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as "__hash__()" and "__repr__()" that are implemented by\nall objects, including type objects. If the implicit lookup of these\nmethods used the conventional lookup process, they would fail when\ninvoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe "__getattribute__()" method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the "__getattribute__()" machinery in this fashion provides\nsignificant scope for speed optimisations within the interpreter, at\nthe cost of some flexibility in the handling of special methods (the\nspecial method *must* be set on the class object itself in order to be\nconsistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type,\n under certain controlled conditions. It generally isn\'t a good\n idea though, since it can lead to some very strange behaviour if\n it is handled incorrectly.\n\n[2] For operands of the same type, it is assumed that if the non-\n reflected method (such as "__add__()") fails the operation is not\n supported, which is why the reflected method is not called.\n', + 'string-methods': '\nString Methods\n**************\n\nStrings implement all of the *common* sequence operations, along with\nthe additional methods described below.\n\nStrings also support two styles of string formatting, one providing a\nlarge degree of flexibility and customization (see "str.format()",\n*Format String Syntax* and *String Formatting*) and the other based on\nC "printf" style formatting that handles a narrower range of types and\nis slightly harder to use correctly, but is often faster for the cases\nit can handle (*printf-style String Formatting*).\n\nThe *Text Processing Services* section of the standard library covers\na number of other modules that provide various text related utilities\n(including regular expression support in the "re" module).\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.casefold()\n\n Return a casefolded copy of the string. Casefolded strings may be\n used for caseless matching.\n\n Casefolding is similar to lowercasing but more aggressive because\n it is intended to remove all case distinctions in a string. For\n example, the German lowercase letter "\'\xc3\x9f\'" is equivalent to ""ss"".\n Since it is already lowercase, "lower()" would do nothing to "\'\xc3\x9f\'";\n "casefold()" converts it to ""ss"".\n\n The casefolding algorithm is described in section 3.13 of the\n Unicode Standard.\n\n New in version 3.3.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is "\'utf-8\'". *errors* may be given to set a different\n error handling scheme. The default for *errors* is "\'strict\'",\n meaning that encoding errors raise a "UnicodeError". Other possible\n values are "\'ignore\'", "\'replace\'", "\'xmlcharrefreplace\'",\n "\'backslashreplace\'" and any other name registered via\n "codecs.register_error()", see section *Codec Base Classes*. For a\n list of possible encodings, see section *Standard Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return "True" if the string ends with the specified *suffix*,\n otherwise return "False". *suffix* can also be a tuple of suffixes\n to look for. With optional *start*, test beginning at that\n position. With optional *end*, stop comparing at that position.\n\nstr.expandtabs(tabsize=8)\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. Tab positions occur every *tabsize* characters\n (default is 8, giving tab positions at columns 0, 8, 16 and so on).\n To expand the string, the current column is set to zero and the\n string is examined character by character. If the character is a\n tab ("\\t"), one or more space characters are inserted in the result\n until the current column is equal to the next tab position. (The\n tab character itself is not copied.) If the character is a newline\n ("\\n") or return ("\\r"), it is copied and the current column is\n reset to zero. Any other character is copied unchanged and the\n current column is incremented by one regardless of how the\n character is represented when printed.\n\n >>> \'01\\t012\\t0123\\t01234\'.expandtabs()\n \'01 012 0123 01234\'\n >>> \'01\\t012\\t0123\\t01234\'.expandtabs(4)\n \'01 012 0123 01234\'\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice "s[start:end]".\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return "-1" if *sub* is not found.\n\n Note: The "find()" method should be used only if you need to know\n the position of *sub*. To check if *sub* is a substring or not,\n use the "in" operator:\n\n >>> \'Py\' in \'Python\'\n True\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces "{}". Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to "str.format(**mapping)", except that "mapping" is used\n directly and not copied to a "dict". This is useful if for example\n "mapping" is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like "find()", but raise "ValueError" when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise. A character "c"\n is alphanumeric if one of the following returns "True":\n "c.isalpha()", "c.isdecimal()", "c.isdigit()", or "c.isnumeric()".\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise. Alphabetic\n characters are those characters defined in the Unicode character\n database as "Letter", i.e., those with general category property\n being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is\n different from the "Alphabetic" property defined in the Unicode\n Standard.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters are those from general category "Nd". This category\n includes digit characters, and all characters that can be used to\n form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise. Digits include decimal\n characters and digits that need special handling, such as the\n compatibility superscript digits. Formally, a digit is a character\n that has the property value Numeric_Type=Digit or\n Numeric_Type=Decimal.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\n Use "keyword.iskeyword()" to test for reserved identifiers such as\n "def" and "class".\n\nstr.islower()\n\n Return true if all cased characters [4] in the string are lowercase\n and there is at least one cased character, false otherwise.\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH. Formally, numeric characters are those with the\n property value Numeric_Type=Digit, Numeric_Type=Decimal or\n Numeric_Type=Numeric.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when "repr()" is\n invoked on a string. It has no bearing on the handling of strings\n written to "sys.stdout" or "sys.stderr".)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise. Whitespace\n characters are those characters defined in the Unicode character\n database as "Other" or "Separator" and those with bidirectional\n property being one of "WS", "B", or "S".\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters [4] in the string are uppercase\n and there is at least one cased character, false otherwise.\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A "TypeError" will be raised if there are\n any non-string values in *iterable*, including "bytes" objects.\n The separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than or\n equal to "len(s)".\n\nstr.lower()\n\n Return a copy of the string with all the cased characters [4]\n converted to lowercase.\n\n The lowercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or "None", the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n "str.translate()".\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within "s[start:end]".\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return "-1" on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like "rfind()" but raises "ValueError" when the substring *sub* is\n not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than or\n equal to "len(s)".\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n "None", any whitespace string is a separator. Except for splitting\n from the right, "rsplit()" behaves like "split()" which is\n described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or "None", the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split(sep=None, maxsplit=-1)\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most "maxsplit+1"\n elements). If *maxsplit* is not specified or "-1", then there is\n no limit on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n "\'1,,2\'.split(\',\')" returns "[\'1\', \'\', \'2\']"). The *sep* argument\n may consist of multiple characters (for example,\n "\'1<>2<>3\'.split(\'<>\')" returns "[\'1\', \'2\', \'3\']"). Splitting an\n empty string with a specified separator returns "[\'\']".\n\n If *sep* is not specified or is "None", a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a "None" separator returns "[]".\n\n For example, "\' 1 2 3 \'.split()" returns "[\'1\', \'2\', \'3\']", and\n "\' 1 2 3 \'.split(None, 1)" returns "[\'1\', \'2 3 \']".\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. This method uses the *universal newlines* approach to\n splitting lines. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\n For example, "\'ab c\\n\\nde fg\\rkl\\r\\n\'.splitlines()" returns "[\'ab\n c\', \'\', \'de fg\', \'kl\']", while the same call with\n "splitlines(True)" returns "[\'ab c\\n\', \'\\n\', \'de fg\\r\', \'kl\\r\\n\']".\n\n Unlike "split()" when a delimiter string *sep* is given, this\n method returns an empty list for the empty string, and a terminal\n line break does not result in an extra line.\n\nstr.startswith(prefix[, start[, end]])\n\n Return "True" if string starts with the *prefix*, otherwise return\n "False". *prefix* can also be a tuple of prefixes to look for.\n With optional *start*, test string beginning at that position.\n With optional *end*, stop comparing string at that position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or "None", the *chars*\n argument defaults to removing whitespace. The *chars* argument is\n not a prefix or suffix; rather, all combinations of its values are\n stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa. Note that it is not necessarily true that\n "s.swapcase().swapcase() == s".\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n ... return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n ... lambda mo: mo.group(0)[0].upper() +\n ... mo.group(0)[1:].lower(),\n ... s)\n ...\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or "None". Unmapped\n characters are left untouched. Characters mapped to "None" are\n deleted.\n\n You can use "str.maketrans()" to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom\n character mapping codec using the "codecs" module (see\n "encodings.cp1251" for an example).\n\nstr.upper()\n\n Return a copy of the string with all the cased characters [4]\n converted to uppercase. Note that "str.upper().isupper()" might be\n "False" if "s" contains uncased characters or if the Unicode\n category of the resulting character(s) is not "Lu" (Letter,\n uppercase), but e.g. "Lt" (Letter, titlecase).\n\n The uppercasing algorithm used is described in section 3.13 of the\n Unicode Standard.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than or equal to "len(s)".\n', + 'strings': '\nString and Bytes literals\n*************************\n\nString literals are described by the following lexical definitions:\n\n stringliteral ::= [stringprefix](shortstring | longstring)\n stringprefix ::= "r" | "u" | "R" | "U"\n shortstring ::= "\'" shortstringitem* "\'" | \'"\' shortstringitem* \'"\'\n longstring ::= "\'\'\'" longstringitem* "\'\'\'" | \'"""\' longstringitem* \'"""\'\n shortstringitem ::= shortstringchar | stringescapeseq\n longstringitem ::= longstringchar | stringescapeseq\n shortstringchar ::= \n longstringchar ::= \n stringescapeseq ::= "\\" \n\n bytesliteral ::= bytesprefix(shortbytes | longbytes)\n bytesprefix ::= "b" | "B" | "br" | "Br" | "bR" | "BR" | "rb" | "rB" | "Rb" | "RB"\n shortbytes ::= "\'" shortbytesitem* "\'" | \'"\' shortbytesitem* \'"\'\n longbytes ::= "\'\'\'" longbytesitem* "\'\'\'" | \'"""\' longbytesitem* \'"""\'\n shortbytesitem ::= shortbyteschar | bytesescapeseq\n longbytesitem ::= longbyteschar | bytesescapeseq\n shortbyteschar ::= \n longbyteschar ::= \n bytesescapeseq ::= "\\" \n\nOne syntactic restriction not indicated by these productions is that\nwhitespace is not allowed between the "stringprefix" or "bytesprefix"\nand the rest of the literal. The source character set is defined by\nthe encoding declaration; it is UTF-8 if no encoding declaration is\ngiven in the source file; see section *Encoding declarations*.\n\nIn plain English: Both types of literals can be enclosed in matching\nsingle quotes ("\'") or double quotes ("""). They can also be enclosed\nin matching groups of three single or double quotes (these are\ngenerally referred to as *triple-quoted strings*). The backslash\n("\\") character is used to escape characters that otherwise have a\nspecial meaning, such as newline, backslash itself, or the quote\ncharacter.\n\nBytes literals are always prefixed with "\'b\'" or "\'B\'"; they produce\nan instance of the "bytes" type instead of the "str" type. They may\nonly contain ASCII characters; bytes with a numeric value of 128 or\ngreater must be expressed with escapes.\n\nAs of Python 3.3 it is possible again to prefix unicode strings with a\n"u" prefix to simplify maintenance of dual 2.x and 3.x codebases.\n\nBoth string and bytes literals may optionally be prefixed with a\nletter "\'r\'" or "\'R\'"; such strings are called *raw strings* and treat\nbackslashes as literal characters. As a result, in string literals,\n"\'\\U\'" and "\'\\u\'" escapes in raw strings are not treated specially.\nGiven that Python 2.x\'s raw unicode literals behave differently than\nPython 3.x\'s the "\'ur\'" syntax is not supported.\n\n New in version 3.3: The "\'rb\'" prefix of raw bytes literals has\n been added as a synonym of "\'br\'".\n\n New in version 3.3: Support for the unicode legacy literal\n ("u\'value\'") was reintroduced to simplify the maintenance of dual\n Python 2.x and 3.x codebases. See **PEP 414** for more information.\n\nIn triple-quoted strings, unescaped newlines and quotes are allowed\n(and are retained), except that three unescaped quotes in a row\nterminate the string. (A "quote" is the character used to open the\nstring, i.e. either "\'" or """.)\n\nUnless an "\'r\'" or "\'R\'" prefix is present, escape sequences in\nstrings are interpreted according to rules similar to those used by\nStandard C. The recognized escape sequences are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n+-------------------+-----------------------------------+---------+\n| "\\ooo" | Character with octal value *ooo* | (1,3) |\n+-------------------+-----------------------------------+---------+\n| "\\xhh" | Character with hex value *hh* | (2,3) |\n+-------------------+-----------------------------------+---------+\n\nEscape sequences only recognized in string literals are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| "\\N{name}" | Character named *name* in the | (4) |\n+-------------------+-----------------------------------+---------+\n| "\\uxxxx" | Character with 16-bit hex value | (5) |\n+-------------------+-----------------------------------+---------+\n| "\\Uxxxxxxxx" | Character with 32-bit hex value | (6) |\n+-------------------+-----------------------------------+---------+\n\nNotes:\n\n1. As in Standard C, up to three octal digits are accepted.\n\n2. Unlike in Standard C, exactly two hex digits are required.\n\n3. In a bytes literal, hexadecimal and octal escapes denote the\n byte with the given value. In a string literal, these escapes\n denote a Unicode character with the given value.\n\n4. Changed in version 3.3: Support for name aliases [1] has been\n added.\n\n5. Individual code units which form parts of a surrogate pair can\n be encoded using this escape sequence. Exactly four hex digits are\n required.\n\n6. Any Unicode character can be encoded this way. Exactly eight\n hex digits are required.\n\nUnlike Standard C, all unrecognized escape sequences are left in the\nstring unchanged, i.e., *the backslash is left in the string*. (This\nbehavior is useful when debugging: if an escape sequence is mistyped,\nthe resulting output is more easily recognized as broken.) It is also\nimportant to note that the escape sequences only recognized in string\nliterals fall into the category of unrecognized escapes for bytes\nliterals.\n\nEven in a raw string, string quotes can be escaped with a backslash,\nbut the backslash remains in the string; for example, "r"\\""" is a\nvalid string literal consisting of two characters: a backslash and a\ndouble quote; "r"\\"" is not a valid string literal (even a raw string\ncannot end in an odd number of backslashes). Specifically, *a raw\nstring cannot end in a single backslash* (since the backslash would\nescape the following quote character). Note also that a single\nbackslash followed by a newline is interpreted as those two characters\nas part of the string, *not* as a line continuation.\n', + 'subscriptions': '\nSubscriptions\n*************\n\nA subscription selects an item of a sequence (string, tuple or list)\nor mapping (dictionary) object:\n\n subscription ::= primary "[" expression_list "]"\n\nThe primary must evaluate to an object that supports subscription,\ne.g. a list or dictionary. User-defined objects can support\nsubscription by defining a "__getitem__()" method.\n\nFor built-in objects, there are two types of objects that support\nsubscription:\n\nIf the primary is a mapping, the expression list must evaluate to an\nobject whose value is one of the keys of the mapping, and the\nsubscription selects the value in the mapping that corresponds to that\nkey. (The expression list is a tuple except if it has exactly one\nitem.)\n\nIf the primary is a sequence, the expression (list) must evaluate to\nan integer or a slice (as discussed in the following section).\n\nThe formal syntax makes no special provision for negative indices in\nsequences; however, built-in sequences all provide a "__getitem__()"\nmethod that interprets negative indices by adding the length of the\nsequence to the index (so that "x[-1]" selects the last item of "x").\nThe resulting value must be a nonnegative integer less than the number\nof items in the sequence, and the subscription selects the item whose\nindex is that value (counting from zero). Since the support for\nnegative indices and slicing occurs in the object\'s "__getitem__()"\nmethod, subclasses overriding this method will need to explicitly add\nthat support.\n\nA string\'s items are characters. A character is not a separate data\ntype but a string of exactly one character.\n', + 'truth': '\nTruth Value Testing\n*******************\n\nAny object can be tested for truth value, for use in an "if" or\n"while" condition or as operand of the Boolean operations below. The\nfollowing values are considered false:\n\n* "None"\n\n* "False"\n\n* zero of any numeric type, for example, "0", "0.0", "0j".\n\n* any empty sequence, for example, "\'\'", "()", "[]".\n\n* any empty mapping, for example, "{}".\n\n* instances of user-defined classes, if the class defines a\n "__bool__()" or "__len__()" method, when that method returns the\n integer zero or "bool" value "False". [1]\n\nAll other values are considered true --- so objects of many types are\nalways true.\n\nOperations and built-in functions that have a Boolean result always\nreturn "0" or "False" for false and "1" or "True" for true, unless\notherwise stated. (Important exception: the Boolean operations "or"\nand "and" always return one of their operands.)\n', + 'try': '\nThe "try" statement\n*******************\n\nThe "try" statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe "except" clause(s) specify one or more exception handlers. When no\nexception occurs in the "try" clause, no exception handler is\nexecuted. When an exception occurs in the "try" suite, a search for an\nexception handler is started. This search inspects the except clauses\nin turn until one is found that matches the exception. An expression-\nless except clause, if present, must be last; it matches any\nexception. For an except clause with an expression, that expression\nis evaluated, and the clause matches the exception if the resulting\nobject is "compatible" with the exception. An object is compatible\nwith an exception if it is the class or a base class of the exception\nobject or a tuple containing an item compatible with the exception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire "try" statement raised\nthe exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the "as" keyword in that except clause, if\npresent, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using "as target", it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the "sys" module and can be access via\n"sys.exc_info()". "sys.exc_info()" returns a 3-tuple consisting of the\nexception class, the exception instance and a traceback object (see\nsection *The standard type hierarchy*) identifying the point in the\nprogram where the exception occurred. "sys.exc_info()" values are\nrestored to their previous values (before the call) when returning\nfrom a function that handled an exception.\n\nThe optional "else" clause is executed if and when control flows off\nthe end of the "try" clause. [2] Exceptions in the "else" clause are\nnot handled by the preceding "except" clauses.\n\nIf "finally" is present, it specifies a \'cleanup\' handler. The "try"\nclause is executed, including any "except" and "else" clauses. If an\nexception occurs in any of the clauses and is not handled, the\nexception is temporarily saved. The "finally" clause is executed. If\nthere is a saved exception it is re-raised at the end of the "finally"\nclause. If the "finally" clause raises another exception, the saved\nexception is set as the context of the new exception. If the "finally"\nclause executes a "return" or "break" statement, the saved exception\nis discarded:\n\n def f():\n try:\n 1/0\n finally:\n return 42\n\n >>> f()\n 42\n\nThe exception information is not available to the program during\nexecution of the "finally" clause.\n\nWhen a "return", "break" or "continue" statement is executed in the\n"try" suite of a "try"..."finally" statement, the "finally" clause is\nalso executed \'on the way out.\' A "continue" statement is illegal in\nthe "finally" clause. (The reason is a problem with the current\nimplementation --- this restriction may be lifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the "raise" statement to\ngenerate exceptions may be found in section *The raise statement*.\n', + 'types': '\nThe standard type hierarchy\n***************************\n\nBelow is a list of the types that are built into Python. Extension\nmodules (written in C, Java, or other languages, depending on the\nimplementation) can define additional types. Future versions of\nPython may add types to the type hierarchy (e.g., rational numbers,\nefficiently stored arrays of integers, etc.), although such additions\nwill often be provided via the standard library instead.\n\nSome of the type descriptions below contain a paragraph listing\n\'special attributes.\' These are attributes that provide access to the\nimplementation and are not intended for general use. Their definition\nmay change in the future.\n\nNone\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name "None". It\n is used to signify the absence of a value in many situations, e.g.,\n it is returned from functions that don\'t explicitly return\n anything. Its truth value is false.\n\nNotImplemented\n This type has a single value. There is a single object with this\n value. This object is accessed through the built-in name\n "NotImplemented". Numeric methods and rich comparison methods may\n return this value if they do not implement the operation for the\n operands provided. (The interpreter will then try the reflected\n operation, or some other fallback, depending on the operator.) Its\n truth value is true.\n\nEllipsis\n This type has a single value. There is a single object with this\n value. This object is accessed through the literal "..." or the\n built-in name "Ellipsis". Its truth value is true.\n\n"numbers.Number"\n These are created by numeric literals and returned as results by\n arithmetic operators and arithmetic built-in functions. Numeric\n objects are immutable; once created their value never changes.\n Python numbers are of course strongly related to mathematical\n numbers, but subject to the limitations of numerical representation\n in computers.\n\n Python distinguishes between integers, floating point numbers, and\n complex numbers:\n\n "numbers.Integral"\n These represent elements from the mathematical set of integers\n (positive and negative).\n\n There are two types of integers:\n\n Integers ("int")\n\n These represent numbers in an unlimited range, subject to\n available (virtual) memory only. For the purpose of shift\n and mask operations, a binary representation is assumed, and\n negative numbers are represented in a variant of 2\'s\n complement which gives the illusion of an infinite string of\n sign bits extending to the left.\n\n Booleans ("bool")\n These represent the truth values False and True. The two\n objects representing the values "False" and "True" are the\n only Boolean objects. The Boolean type is a subtype of the\n integer type, and Boolean values behave like the values 0 and\n 1, respectively, in almost all contexts, the exception being\n that when converted to a string, the strings ""False"" or\n ""True"" are returned, respectively.\n\n The rules for integer representation are intended to give the\n most meaningful interpretation of shift and mask operations\n involving negative integers.\n\n "numbers.Real" ("float")\n These represent machine-level double precision floating point\n numbers. You are at the mercy of the underlying machine\n architecture (and C or Java implementation) for the accepted\n range and handling of overflow. Python does not support single-\n precision floating point numbers; the savings in processor and\n memory usage that are usually the reason for using these is\n dwarfed by the overhead of using objects in Python, so there is\n no reason to complicate the language with two kinds of floating\n point numbers.\n\n "numbers.Complex" ("complex")\n These represent complex numbers as a pair of machine-level\n double precision floating point numbers. The same caveats apply\n as for floating point numbers. The real and imaginary parts of a\n complex number "z" can be retrieved through the read-only\n attributes "z.real" and "z.imag".\n\nSequences\n These represent finite ordered sets indexed by non-negative\n numbers. The built-in function "len()" returns the number of items\n of a sequence. When the length of a sequence is *n*, the index set\n contains the numbers 0, 1, ..., *n*-1. Item *i* of sequence *a* is\n selected by "a[i]".\n\n Sequences also support slicing: "a[i:j]" selects all items with\n index *k* such that *i* "<=" *k* "<" *j*. When used as an\n expression, a slice is a sequence of the same type. This implies\n that the index set is renumbered so that it starts at 0.\n\n Some sequences also support "extended slicing" with a third "step"\n parameter: "a[i:j:k]" selects all items of *a* with index *x* where\n "x = i + n*k", *n* ">=" "0" and *i* "<=" *x* "<" *j*.\n\n Sequences are distinguished according to their mutability:\n\n Immutable sequences\n An object of an immutable sequence type cannot change once it is\n created. (If the object contains references to other objects,\n these other objects may be mutable and may be changed; however,\n the collection of objects directly referenced by an immutable\n object cannot change.)\n\n The following types are immutable sequences:\n\n Strings\n A string is a sequence of values that represent Unicode\n codepoints. All the codepoints in range "U+0000 - U+10FFFF"\n can be represented in a string. Python doesn\'t have a "chr"\n type, and every character in the string is represented as a\n string object with length "1". The built-in function "ord()"\n converts a character to its codepoint (as an integer);\n "chr()" converts an integer in range "0 - 10FFFF" to the\n corresponding character. "str.encode()" can be used to\n convert a "str" to "bytes" using the given encoding, and\n "bytes.decode()" can be used to achieve the opposite.\n\n Tuples\n The items of a tuple are arbitrary Python objects. Tuples of\n two or more items are formed by comma-separated lists of\n expressions. A tuple of one item (a \'singleton\') can be\n formed by affixing a comma to an expression (an expression by\n itself does not create a tuple, since parentheses must be\n usable for grouping of expressions). An empty tuple can be\n formed by an empty pair of parentheses.\n\n Bytes\n A bytes object is an immutable array. The items are 8-bit\n bytes, represented by integers in the range 0 <= x < 256.\n Bytes literals (like "b\'abc\'") and the built-in function\n "bytes()" can be used to construct bytes objects. Also,\n bytes objects can be decoded to strings via the "decode()"\n method.\n\n Mutable sequences\n Mutable sequences can be changed after they are created. The\n subscription and slicing notations can be used as the target of\n assignment and "del" (delete) statements.\n\n There are currently two intrinsic mutable sequence types:\n\n Lists\n The items of a list are arbitrary Python objects. Lists are\n formed by placing a comma-separated list of expressions in\n square brackets. (Note that there are no special cases needed\n to form lists of length 0 or 1.)\n\n Byte Arrays\n A bytearray object is a mutable array. They are created by\n the built-in "bytearray()" constructor. Aside from being\n mutable (and hence unhashable), byte arrays otherwise provide\n the same interface and functionality as immutable bytes\n objects.\n\n The extension module "array" provides an additional example of a\n mutable sequence type, as does the "collections" module.\n\nSet types\n These represent unordered, finite sets of unique, immutable\n objects. As such, they cannot be indexed by any subscript. However,\n they can be iterated over, and the built-in function "len()"\n returns the number of items in a set. Common uses for sets are fast\n membership testing, removing duplicates from a sequence, and\n computing mathematical operations such as intersection, union,\n difference, and symmetric difference.\n\n For set elements, the same immutability rules apply as for\n dictionary keys. Note that numeric types obey the normal rules for\n numeric comparison: if two numbers compare equal (e.g., "1" and\n "1.0"), only one of them can be contained in a set.\n\n There are currently two intrinsic set types:\n\n Sets\n These represent a mutable set. They are created by the built-in\n "set()" constructor and can be modified afterwards by several\n methods, such as "add()".\n\n Frozen sets\n These represent an immutable set. They are created by the\n built-in "frozenset()" constructor. As a frozenset is immutable\n and *hashable*, it can be used again as an element of another\n set, or as a dictionary key.\n\nMappings\n These represent finite sets of objects indexed by arbitrary index\n sets. The subscript notation "a[k]" selects the item indexed by "k"\n from the mapping "a"; this can be used in expressions and as the\n target of assignments or "del" statements. The built-in function\n "len()" returns the number of items in a mapping.\n\n There is currently a single intrinsic mapping type:\n\n Dictionaries\n These represent finite sets of objects indexed by nearly\n arbitrary values. The only types of values not acceptable as\n keys are values containing lists or dictionaries or other\n mutable types that are compared by value rather than by object\n identity, the reason being that the efficient implementation of\n dictionaries requires a key\'s hash value to remain constant.\n Numeric types used for keys obey the normal rules for numeric\n comparison: if two numbers compare equal (e.g., "1" and "1.0")\n then they can be used interchangeably to index the same\n dictionary entry.\n\n Dictionaries are mutable; they can be created by the "{...}"\n notation (see section *Dictionary displays*).\n\n The extension modules "dbm.ndbm" and "dbm.gnu" provide\n additional examples of mapping types, as does the "collections"\n module.\n\nCallable types\n These are the types to which the function call operation (see\n section *Calls*) can be applied:\n\n User-defined functions\n A user-defined function object is created by a function\n definition (see section *Function definitions*). It should be\n called with an argument list containing the same number of items\n as the function\'s formal parameter list.\n\n Special attributes:\n\n +---------------------------+---------------------------------+-------------+\n +===========================+=================================+=============+\n | "__doc__" | The function\'s documentation | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__name__" | The function\'s name | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__qualname__" | The function\'s *qualified name* | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__module__" | The name of the module the | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__defaults__" | A tuple containing default | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__code__" | The code object representing | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__globals__" | A reference to the dictionary | Read-only |\n +---------------------------+---------------------------------+-------------+\n | "__dict__" | The namespace supporting | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__closure__" | "None" or a tuple of cells that | Read-only |\n +---------------------------+---------------------------------+-------------+\n | "__annotations__" | A dict containing annotations | Writable |\n +---------------------------+---------------------------------+-------------+\n | "__kwdefaults__" | A dict containing defaults for | Writable |\n +---------------------------+---------------------------------+-------------+\n\n Most of the attributes labelled "Writable" check the type of the\n assigned value.\n\n Function objects also support getting and setting arbitrary\n attributes, which can be used, for example, to attach metadata\n to functions. Regular attribute dot-notation is used to get and\n set such attributes. *Note that the current implementation only\n supports function attributes on user-defined functions. Function\n attributes on built-in functions may be supported in the\n future.*\n\n Additional information about a function\'s definition can be\n retrieved from its code object; see the description of internal\n types below.\n\n Instance methods\n An instance method object combines a class, a class instance and\n any callable object (normally a user-defined function).\n\n Special read-only attributes: "__self__" is the class instance\n object, "__func__" is the function object; "__doc__" is the\n method\'s documentation (same as "__func__.__doc__"); "__name__"\n is the method name (same as "__func__.__name__"); "__module__"\n is the name of the module the method was defined in, or "None"\n if unavailable.\n\n Methods also support accessing (but not setting) the arbitrary\n function attributes on the underlying function object.\n\n User-defined method objects may be created when getting an\n attribute of a class (perhaps via an instance of that class), if\n that attribute is a user-defined function object or a class\n method object.\n\n When an instance method object is created by retrieving a user-\n defined function object from a class via one of its instances,\n its "__self__" attribute is the instance, and the method object\n is said to be bound. The new method\'s "__func__" attribute is\n the original function object.\n\n When a user-defined method object is created by retrieving\n another method object from a class or instance, the behaviour is\n the same as for a function object, except that the "__func__"\n attribute of the new instance is not the original method object\n but its "__func__" attribute.\n\n When an instance method object is created by retrieving a class\n method object from a class or instance, its "__self__" attribute\n is the class itself, and its "__func__" attribute is the\n function object underlying the class method.\n\n When an instance method object is called, the underlying\n function ("__func__") is called, inserting the class instance\n ("__self__") in front of the argument list. For instance, when\n "C" is a class which contains a definition for a function "f()",\n and "x" is an instance of "C", calling "x.f(1)" is equivalent to\n calling "C.f(x, 1)".\n\n When an instance method object is derived from a class method\n object, the "class instance" stored in "__self__" will actually\n be the class itself, so that calling either "x.f(1)" or "C.f(1)"\n is equivalent to calling "f(C,1)" where "f" is the underlying\n function.\n\n Note that the transformation from function object to instance\n method object happens each time the attribute is retrieved from\n the instance. In some cases, a fruitful optimization is to\n assign the attribute to a local variable and call that local\n variable. Also notice that this transformation only happens for\n user-defined functions; other callable objects (and all non-\n callable objects) are retrieved without transformation. It is\n also important to note that user-defined functions which are\n attributes of a class instance are not converted to bound\n methods; this *only* happens when the function is an attribute\n of the class.\n\n Generator functions\n A function or method which uses the "yield" statement (see\n section *The yield statement*) is called a *generator function*.\n Such a function, when called, always returns an iterator object\n which can be used to execute the body of the function: calling\n the iterator\'s "iterator.__next__()" method will cause the\n function to execute until it provides a value using the "yield"\n statement. When the function executes a "return" statement or\n falls off the end, a "StopIteration" exception is raised and the\n iterator will have reached the end of the set of values to be\n returned.\n\n Built-in functions\n A built-in function object is a wrapper around a C function.\n Examples of built-in functions are "len()" and "math.sin()"\n ("math" is a standard built-in module). The number and type of\n the arguments are determined by the C function. Special read-\n only attributes: "__doc__" is the function\'s documentation\n string, or "None" if unavailable; "__name__" is the function\'s\n name; "__self__" is set to "None" (but see the next item);\n "__module__" is the name of the module the function was defined\n in or "None" if unavailable.\n\n Built-in methods\n This is really a different disguise of a built-in function, this\n time containing an object passed to the C function as an\n implicit extra argument. An example of a built-in method is\n "alist.append()", assuming *alist* is a list object. In this\n case, the special read-only attribute "__self__" is set to the\n object denoted by *alist*.\n\n Classes\n Classes are callable. These objects normally act as factories\n for new instances of themselves, but variations are possible for\n class types that override "__new__()". The arguments of the\n call are passed to "__new__()" and, in the typical case, to\n "__init__()" to initialize the new instance.\n\n Class Instances\n Instances of arbitrary classes can be made callable by defining\n a "__call__()" method in their class.\n\nModules\n Modules are a basic organizational unit of Python code, and are\n created by the *import system* as invoked either by the "import"\n statement (see "import"), or by calling functions such as\n "importlib.import_module()" and built-in "__import__()". A module\n object has a namespace implemented by a dictionary object (this is\n the dictionary referenced by the "__globals__" attribute of\n functions defined in the module). Attribute references are\n translated to lookups in this dictionary, e.g., "m.x" is equivalent\n to "m.__dict__["x"]". A module object does not contain the code\n object used to initialize the module (since it isn\'t needed once\n the initialization is done).\n\n Attribute assignment updates the module\'s namespace dictionary,\n e.g., "m.x = 1" is equivalent to "m.__dict__["x"] = 1".\n\n Special read-only attribute: "__dict__" is the module\'s namespace\n as a dictionary object.\n\n **CPython implementation detail:** Because of the way CPython\n clears module dictionaries, the module dictionary will be cleared\n when the module falls out of scope even if the dictionary still has\n live references. To avoid this, copy the dictionary or keep the\n module around while using its dictionary directly.\n\n Predefined (writable) attributes: "__name__" is the module\'s name;\n "__doc__" is the module\'s documentation string, or "None" if\n unavailable; "__file__" is the pathname of the file from which the\n module was loaded, if it was loaded from a file. The "__file__"\n attribute may be missing for certain types of modules, such as C\n modules that are statically linked into the interpreter; for\n extension modules loaded dynamically from a shared library, it is\n the pathname of the shared library file.\n\nCustom classes\n Custom class types are typically created by class definitions (see\n section *Class definitions*). A class has a namespace implemented\n by a dictionary object. Class attribute references are translated\n to lookups in this dictionary, e.g., "C.x" is translated to\n "C.__dict__["x"]" (although there are a number of hooks which allow\n for other means of locating attributes). When the attribute name is\n not found there, the attribute search continues in the base\n classes. This search of the base classes uses the C3 method\n resolution order which behaves correctly even in the presence of\n \'diamond\' inheritance structures where there are multiple\n inheritance paths leading back to a common ancestor. Additional\n details on the C3 MRO used by Python can be found in the\n documentation accompanying the 2.3 release at\n http://www.python.org/download/releases/2.3/mro/.\n\n When a class attribute reference (for class "C", say) would yield a\n class method object, it is transformed into an instance method\n object whose "__self__" attributes is "C". When it would yield a\n static method object, it is transformed into the object wrapped by\n the static method object. See section *Implementing Descriptors*\n for another way in which attributes retrieved from a class may\n differ from those actually contained in its "__dict__".\n\n Class attribute assignments update the class\'s dictionary, never\n the dictionary of a base class.\n\n A class object can be called (see above) to yield a class instance\n (see below).\n\n Special attributes: "__name__" is the class name; "__module__" is\n the module name in which the class was defined; "__dict__" is the\n dictionary containing the class\'s namespace; "__bases__" is a tuple\n (possibly empty or a singleton) containing the base classes, in the\n order of their occurrence in the base class list; "__doc__" is the\n class\'s documentation string, or None if undefined.\n\nClass instances\n A class instance is created by calling a class object (see above).\n A class instance has a namespace implemented as a dictionary which\n is the first place in which attribute references are searched.\n When an attribute is not found there, and the instance\'s class has\n an attribute by that name, the search continues with the class\n attributes. If a class attribute is found that is a user-defined\n function object, it is transformed into an instance method object\n whose "__self__" attribute is the instance. Static method and\n class method objects are also transformed; see above under\n "Classes". See section *Implementing Descriptors* for another way\n in which attributes of a class retrieved via its instances may\n differ from the objects actually stored in the class\'s "__dict__".\n If no class attribute is found, and the object\'s class has a\n "__getattr__()" method, that is called to satisfy the lookup.\n\n Attribute assignments and deletions update the instance\'s\n dictionary, never a class\'s dictionary. If the class has a\n "__setattr__()" or "__delattr__()" method, this is called instead\n of updating the instance dictionary directly.\n\n Class instances can pretend to be numbers, sequences, or mappings\n if they have methods with certain special names. See section\n *Special method names*.\n\n Special attributes: "__dict__" is the attribute dictionary;\n "__class__" is the instance\'s class.\n\nI/O objects (also known as file objects)\n A *file object* represents an open file. Various shortcuts are\n available to create file objects: the "open()" built-in function,\n and also "os.popen()", "os.fdopen()", and the "makefile()" method\n of socket objects (and perhaps by other functions or methods\n provided by extension modules).\n\n The objects "sys.stdin", "sys.stdout" and "sys.stderr" are\n initialized to file objects corresponding to the interpreter\'s\n standard input, output and error streams; they are all open in text\n mode and therefore follow the interface defined by the\n "io.TextIOBase" abstract class.\n\nInternal types\n A few types used internally by the interpreter are exposed to the\n user. Their definitions may change with future versions of the\n interpreter, but they are mentioned here for completeness.\n\n Code objects\n Code objects represent *byte-compiled* executable Python code,\n or *bytecode*. The difference between a code object and a\n function object is that the function object contains an explicit\n reference to the function\'s globals (the module in which it was\n defined), while a code object contains no context; also the\n default argument values are stored in the function object, not\n in the code object (because they represent values calculated at\n run-time). Unlike function objects, code objects are immutable\n and contain no references (directly or indirectly) to mutable\n objects.\n\n Special read-only attributes: "co_name" gives the function name;\n "co_argcount" is the number of positional arguments (including\n arguments with default values); "co_nlocals" is the number of\n local variables used by the function (including arguments);\n "co_varnames" is a tuple containing the names of the local\n variables (starting with the argument names); "co_cellvars" is a\n tuple containing the names of local variables that are\n referenced by nested functions; "co_freevars" is a tuple\n containing the names of free variables; "co_code" is a string\n representing the sequence of bytecode instructions; "co_consts"\n is a tuple containing the literals used by the bytecode;\n "co_names" is a tuple containing the names used by the bytecode;\n "co_filename" is the filename from which the code was compiled;\n "co_firstlineno" is the first line number of the function;\n "co_lnotab" is a string encoding the mapping from bytecode\n offsets to line numbers (for details see the source code of the\n interpreter); "co_stacksize" is the required stack size\n (including local variables); "co_flags" is an integer encoding a\n number of flags for the interpreter.\n\n The following flag bits are defined for "co_flags": bit "0x04"\n is set if the function uses the "*arguments" syntax to accept an\n arbitrary number of positional arguments; bit "0x08" is set if\n the function uses the "**keywords" syntax to accept arbitrary\n keyword arguments; bit "0x20" is set if the function is a\n generator.\n\n Future feature declarations ("from __future__ import division")\n also use bits in "co_flags" to indicate whether a code object\n was compiled with a particular feature enabled: bit "0x2000" is\n set if the function was compiled with future division enabled;\n bits "0x10" and "0x1000" were used in earlier versions of\n Python.\n\n Other bits in "co_flags" are reserved for internal use.\n\n If a code object represents a function, the first item in\n "co_consts" is the documentation string of the function, or\n "None" if undefined.\n\n Frame objects\n Frame objects represent execution frames. They may occur in\n traceback objects (see below).\n\n Special read-only attributes: "f_back" is to the previous stack\n frame (towards the caller), or "None" if this is the bottom\n stack frame; "f_code" is the code object being executed in this\n frame; "f_locals" is the dictionary used to look up local\n variables; "f_globals" is used for global variables;\n "f_builtins" is used for built-in (intrinsic) names; "f_lasti"\n gives the precise instruction (this is an index into the\n bytecode string of the code object).\n\n Special writable attributes: "f_trace", if not "None", is a\n function called at the start of each source code line (this is\n used by the debugger); "f_lineno" is the current line number of\n the frame --- writing to this from within a trace function jumps\n to the given line (only for the bottom-most frame). A debugger\n can implement a Jump command (aka Set Next Statement) by writing\n to f_lineno.\n\n Frame objects support one method:\n\n frame.clear()\n\n This method clears all references to local variables held by\n the frame. Also, if the frame belonged to a generator, the\n generator is finalized. This helps break reference cycles\n involving frame objects (for example when catching an\n exception and storing its traceback for later use).\n\n "RuntimeError" is raised if the frame is currently executing.\n\n New in version 3.4.\n\n Traceback objects\n Traceback objects represent a stack trace of an exception. A\n traceback object is created when an exception occurs. When the\n search for an exception handler unwinds the execution stack, at\n each unwound level a traceback object is inserted in front of\n the current traceback. When an exception handler is entered,\n the stack trace is made available to the program. (See section\n *The try statement*.) It is accessible as the third item of the\n tuple returned by "sys.exc_info()". When the program contains no\n suitable handler, the stack trace is written (nicely formatted)\n to the standard error stream; if the interpreter is interactive,\n it is also made available to the user as "sys.last_traceback".\n\n Special read-only attributes: "tb_next" is the next level in the\n stack trace (towards the frame where the exception occurred), or\n "None" if there is no next level; "tb_frame" points to the\n execution frame of the current level; "tb_lineno" gives the line\n number where the exception occurred; "tb_lasti" indicates the\n precise instruction. The line number and last instruction in\n the traceback may differ from the line number of its frame\n object if the exception occurred in a "try" statement with no\n matching except clause or with a finally clause.\n\n Slice objects\n Slice objects are used to represent slices for "__getitem__()"\n methods. They are also created by the built-in "slice()"\n function.\n\n Special read-only attributes: "start" is the lower bound; "stop"\n is the upper bound; "step" is the step value; each is "None" if\n omitted. These attributes can have any type.\n\n Slice objects support one method:\n\n slice.indices(self, length)\n\n This method takes a single integer argument *length* and\n computes information about the slice that the slice object\n would describe if applied to a sequence of *length* items.\n It returns a tuple of three integers; respectively these are\n the *start* and *stop* indices and the *step* or stride\n length of the slice. Missing or out-of-bounds indices are\n handled in a manner consistent with regular slices.\n\n Static method objects\n Static method objects provide a way of defeating the\n transformation of function objects to method objects described\n above. A static method object is a wrapper around any other\n object, usually a user-defined method object. When a static\n method object is retrieved from a class or a class instance, the\n object actually returned is the wrapped object, which is not\n subject to any further transformation. Static method objects are\n not themselves callable, although the objects they wrap usually\n are. Static method objects are created by the built-in\n "staticmethod()" constructor.\n\n Class method objects\n A class method object, like a static method object, is a wrapper\n around another object that alters the way in which that object\n is retrieved from classes and class instances. The behaviour of\n class method objects upon such retrieval is described above,\n under "User-defined methods". Class method objects are created\n by the built-in "classmethod()" constructor.\n', + 'typesfunctions': '\nFunctions\n*********\n\nFunction objects are created by function definitions. The only\noperation on a function object is to call it: "func(argument-list)".\n\nThere are really two flavors of function objects: built-in functions\nand user-defined functions. Both support the same operation (to call\nthe function), but the implementation is different, hence the\ndifferent object types.\n\nSee *Function definitions* for more information.\n', + 'typesmapping': '\nMapping Types --- "dict"\n************************\n\nA *mapping* object maps *hashable* values to arbitrary objects.\nMappings are mutable objects. There is currently only one standard\nmapping type, the *dictionary*. (For other containers see the built-\nin "list", "set", and "tuple" classes, and the "collections" module.)\n\nA dictionary\'s keys are *almost* arbitrary values. Values that are\nnot *hashable*, that is, values containing lists, dictionaries or\nother mutable types (that are compared by value rather than by object\nidentity) may not be used as keys. Numeric types used for keys obey\nthe normal rules for numeric comparison: if two numbers compare equal\n(such as "1" and "1.0") then they can be used interchangeably to index\nthe same dictionary entry. (Note however, that since computers store\nfloating-point numbers as approximations it is usually unwise to use\nthem as dictionary keys.)\n\nDictionaries can be created by placing a comma-separated list of "key:\nvalue" pairs within braces, for example: "{\'jack\': 4098, \'sjoerd\':\n4127}" or "{4098: \'jack\', 4127: \'sjoerd\'}", or by the "dict"\nconstructor.\n\nclass class dict(**kwarg)\nclass class dict(mapping, **kwarg)\nclass class dict(iterable, **kwarg)\n\n Return a new dictionary initialized from an optional positional\n argument and a possibly empty set of keyword arguments.\n\n If no positional argument is given, an empty dictionary is created.\n If a positional argument is given and it is a mapping object, a\n dictionary is created with the same key-value pairs as the mapping\n object. Otherwise, the positional argument must be an *iterator*\n object. Each item in the iterable must itself be an iterator with\n exactly two objects. The first object of each item becomes a key\n in the new dictionary, and the second object the corresponding\n value. If a key occurs more than once, the last value for that key\n becomes the corresponding value in the new dictionary.\n\n If keyword arguments are given, the keyword arguments and their\n values are added to the dictionary created from the positional\n argument. If a key being added is already present, the value from\n the keyword argument replaces the value from the positional\n argument.\n\n To illustrate, the following examples all return a dictionary equal\n to "{"one": 1, "two": 2, "three": 3}":\n\n >>> a = dict(one=1, two=2, three=3)\n >>> b = {\'one\': 1, \'two\': 2, \'three\': 3}\n >>> c = dict(zip([\'one\', \'two\', \'three\'], [1, 2, 3]))\n >>> d = dict([(\'two\', 2), (\'one\', 1), (\'three\', 3)])\n >>> e = dict({\'three\': 3, \'one\': 1, \'two\': 2})\n >>> a == b == c == d == e\n True\n\n Providing keyword arguments as in the first example only works for\n keys that are valid Python identifiers. Otherwise, any valid keys\n can be used.\n\n These are the operations that dictionaries support (and therefore,\n custom mapping types should support too):\n\n len(d)\n\n Return the number of items in the dictionary *d*.\n\n d[key]\n\n Return the item of *d* with key *key*. Raises a "KeyError" if\n *key* is not in the map.\n\n If a subclass of dict defines a method "__missing__()", if the\n key *key* is not present, the "d[key]" operation calls that\n method with the key *key* as argument. The "d[key]" operation\n then returns or raises whatever is returned or raised by the\n "__missing__(key)" call if the key is not present. No other\n operations or methods invoke "__missing__()". If "__missing__()"\n is not defined, "KeyError" is raised. "__missing__()" must be a\n method; it cannot be an instance variable:\n\n >>> class Counter(dict):\n ... def __missing__(self, key):\n ... return 0\n >>> c = Counter()\n >>> c[\'red\']\n 0\n >>> c[\'red\'] += 1\n >>> c[\'red\']\n 1\n\n See "collections.Counter" for a complete implementation\n including other methods helpful for accumulating and managing\n tallies.\n\n d[key] = value\n\n Set "d[key]" to *value*.\n\n del d[key]\n\n Remove "d[key]" from *d*. Raises a "KeyError" if *key* is not\n in the map.\n\n key in d\n\n Return "True" if *d* has a key *key*, else "False".\n\n key not in d\n\n Equivalent to "not key in d".\n\n iter(d)\n\n Return an iterator over the keys of the dictionary. This is a\n shortcut for "iter(d.keys())".\n\n clear()\n\n Remove all items from the dictionary.\n\n copy()\n\n Return a shallow copy of the dictionary.\n\n classmethod fromkeys(seq[, value])\n\n Create a new dictionary with keys from *seq* and values set to\n *value*.\n\n "fromkeys()" is a class method that returns a new dictionary.\n *value* defaults to "None".\n\n get(key[, default])\n\n Return the value for *key* if *key* is in the dictionary, else\n *default*. If *default* is not given, it defaults to "None", so\n that this method never raises a "KeyError".\n\n items()\n\n Return a new view of the dictionary\'s items ("(key, value)"\n pairs). See the *documentation of view objects*.\n\n keys()\n\n Return a new view of the dictionary\'s keys. See the\n *documentation of view objects*.\n\n pop(key[, default])\n\n If *key* is in the dictionary, remove it and return its value,\n else return *default*. If *default* is not given and *key* is\n not in the dictionary, a "KeyError" is raised.\n\n popitem()\n\n Remove and return an arbitrary "(key, value)" pair from the\n dictionary.\n\n "popitem()" is useful to destructively iterate over a\n dictionary, as often used in set algorithms. If the dictionary\n is empty, calling "popitem()" raises a "KeyError".\n\n setdefault(key[, default])\n\n If *key* is in the dictionary, return its value. If not, insert\n *key* with a value of *default* and return *default*. *default*\n defaults to "None".\n\n update([other])\n\n Update the dictionary with the key/value pairs from *other*,\n overwriting existing keys. Return "None".\n\n "update()" accepts either another dictionary object or an\n iterable of key/value pairs (as tuples or other iterables of\n length two). If keyword arguments are specified, the dictionary\n is then updated with those key/value pairs: "d.update(red=1,\n blue=2)".\n\n values()\n\n Return a new view of the dictionary\'s values. See the\n *documentation of view objects*.\n\nSee also: "types.MappingProxyType" can be used to create a read-only\n view of a "dict".\n\n\nDictionary view objects\n=======================\n\nThe objects returned by "dict.keys()", "dict.values()" and\n"dict.items()" are *view objects*. They provide a dynamic view on the\ndictionary\'s entries, which means that when the dictionary changes,\nthe view reflects these changes.\n\nDictionary views can be iterated over to yield their respective data,\nand support membership tests:\n\nlen(dictview)\n\n Return the number of entries in the dictionary.\n\niter(dictview)\n\n Return an iterator over the keys, values or items (represented as\n tuples of "(key, value)") in the dictionary.\n\n Keys and values are iterated over in an arbitrary order which is\n non-random, varies across Python implementations, and depends on\n the dictionary\'s history of insertions and deletions. If keys,\n values and items views are iterated over with no intervening\n modifications to the dictionary, the order of items will directly\n correspond. This allows the creation of "(value, key)" pairs using\n "zip()": "pairs = zip(d.values(), d.keys())". Another way to\n create the same list is "pairs = [(v, k) for (k, v) in d.items()]".\n\n Iterating views while adding or deleting entries in the dictionary\n may raise a "RuntimeError" or fail to iterate over all entries.\n\nx in dictview\n\n Return "True" if *x* is in the underlying dictionary\'s keys, values\n or items (in the latter case, *x* should be a "(key, value)"\n tuple).\n\nKeys views are set-like since their entries are unique and hashable.\nIf all values are hashable, so that "(key, value)" pairs are unique\nand hashable, then the items view is also set-like. (Values views are\nnot treated as set-like since the entries are generally not unique.)\nFor set-like views, all of the operations defined for the abstract\nbase class "collections.abc.Set" are available (for example, "==",\n"<", or "^").\n\nAn example of dictionary view usage:\n\n >>> dishes = {\'eggs\': 2, \'sausage\': 1, \'bacon\': 1, \'spam\': 500}\n >>> keys = dishes.keys()\n >>> values = dishes.values()\n\n >>> # iteration\n >>> n = 0\n >>> for val in values:\n ... n += val\n >>> print(n)\n 504\n\n >>> # keys and values are iterated over in the same order\n >>> list(keys)\n [\'eggs\', \'bacon\', \'sausage\', \'spam\']\n >>> list(values)\n [2, 1, 1, 500]\n\n >>> # view objects are dynamic and reflect dict changes\n >>> del dishes[\'eggs\']\n >>> del dishes[\'sausage\']\n >>> list(keys)\n [\'spam\', \'bacon\']\n\n >>> # set operations\n >>> keys & {\'eggs\', \'bacon\', \'salad\'}\n {\'bacon\'}\n >>> keys ^ {\'sausage\', \'juice\'}\n {\'juice\', \'sausage\', \'bacon\', \'spam\'}\n', + 'typesmethods': '\nMethods\n*******\n\nMethods are functions that are called using the attribute notation.\nThere are two flavors: built-in methods (such as "append()" on lists)\nand class instance methods. Built-in methods are described with the\ntypes that support them.\n\nIf you access a method (a function defined in a class namespace)\nthrough an instance, you get a special object: a *bound method* (also\ncalled *instance method*) object. When called, it will add the "self"\nargument to the argument list. Bound methods have two special read-\nonly attributes: "m.__self__" is the object on which the method\noperates, and "m.__func__" is the function implementing the method.\nCalling "m(arg-1, arg-2, ..., arg-n)" is completely equivalent to\ncalling "m.__func__(m.__self__, arg-1, arg-2, ..., arg-n)".\n\nLike function objects, bound method objects support getting arbitrary\nattributes. However, since method attributes are actually stored on\nthe underlying function object ("meth.__func__"), setting method\nattributes on bound methods is disallowed. Attempting to set an\nattribute on a method results in an "AttributeError" being raised. In\norder to set a method attribute, you need to explicitly set it on the\nunderlying function object:\n\n >>> class C:\n ... def method(self):\n ... pass\n ...\n >>> c = C()\n >>> c.method.whoami = \'my name is method\' # can\'t set on the method\n Traceback (most recent call last):\n File "", line 1, in \n AttributeError: \'method\' object has no attribute \'whoami\'\n >>> c.method.__func__.whoami = \'my name is method\'\n >>> c.method.whoami\n \'my name is method\'\n\nSee *The standard type hierarchy* for more information.\n', + 'typesmodules': '\nModules\n*******\n\nThe only special operation on a module is attribute access: "m.name",\nwhere *m* is a module and *name* accesses a name defined in *m*\'s\nsymbol table. Module attributes can be assigned to. (Note that the\n"import" statement is not, strictly speaking, an operation on a module\nobject; "import foo" does not require a module object named *foo* to\nexist, rather it requires an (external) *definition* for a module\nnamed *foo* somewhere.)\n\nA special attribute of every module is "__dict__". This is the\ndictionary containing the module\'s symbol table. Modifying this\ndictionary will actually change the module\'s symbol table, but direct\nassignment to the "__dict__" attribute is not possible (you can write\n"m.__dict__[\'a\'] = 1", which defines "m.a" to be "1", but you can\'t\nwrite "m.__dict__ = {}"). Modifying "__dict__" directly is not\nrecommended.\n\nModules built into the interpreter are written like this: "". If loaded from a file, they are written as\n"".\n', + 'typesseq': '\nSequence Types --- "list", "tuple", "range"\n*******************************************\n\nThere are three basic sequence types: lists, tuples, and range\nobjects. Additional sequence types tailored for processing of *binary\ndata* and *text strings* are described in dedicated sections.\n\n\nCommon Sequence Operations\n==========================\n\nThe operations in the following table are supported by most sequence\ntypes, both mutable and immutable. The "collections.abc.Sequence" ABC\nis provided to make it easier to correctly implement these operations\non custom sequence types.\n\nThis table lists the sequence operations sorted in ascending priority\n(operations in the same box have the same priority). In the table,\n*s* and *t* are sequences of the same type, *n*, *i*, *j* and *k* are\nintegers and *x* is an arbitrary object that meets any type and value\nrestrictions imposed by *s*.\n\nThe "in" and "not in" operations have the same priorities as the\ncomparison operations. The "+" (concatenation) and "*" (repetition)\noperations have the same priority as the corresponding numeric\noperations.\n\n+----------------------------+----------------------------------+------------+\n| Operation | Result | Notes |\n+============================+==================================+============+\n| "x in s" | "True" if an item of *s* is | (1) |\n+----------------------------+----------------------------------+------------+\n| "x not in s" | "False" if an item of *s* is | (1) |\n+----------------------------+----------------------------------+------------+\n| "s + t" | the concatenation of *s* and *t* | (6)(7) |\n+----------------------------+----------------------------------+------------+\n| "s * n" or "n * s" | *n* shallow copies of *s* | (2)(7) |\n+----------------------------+----------------------------------+------------+\n| "s[i]" | *i*th item of *s*, origin 0 | (3) |\n+----------------------------+----------------------------------+------------+\n| "s[i:j]" | slice of *s* from *i* to *j* | (3)(4) |\n+----------------------------+----------------------------------+------------+\n| "s[i:j:k]" | slice of *s* from *i* to *j* | (3)(5) |\n+----------------------------+----------------------------------+------------+\n+----------------------------+----------------------------------+------------+\n+----------------------------+----------------------------------+------------+\n+----------------------------+----------------------------------+------------+\n| "s.index(x[, i[, j]])" | index of the first occurrence of | (8) |\n+----------------------------+----------------------------------+------------+\n+----------------------------+----------------------------------+------------+\n\nSequences of the same type also support comparisons. In particular,\ntuples and lists are compared lexicographically by comparing\ncorresponding elements. This means that to compare equal, every\nelement must compare equal and the two sequences must be of the same\ntype and have the same length. (For full details see *Comparisons* in\nthe language reference.)\n\nNotes:\n\n1. While the "in" and "not in" operations are used only for simple\n containment testing in the general case, some specialised sequences\n (such as "str", "bytes" and "bytearray") also use them for\n subsequence testing:\n\n >>> "gg" in "eggs"\n True\n\n2. Values of *n* less than "0" are treated as "0" (which yields an\n empty sequence of the same type as *s*). Note also that the copies\n are shallow; nested structures are not copied. This often haunts\n new Python programmers; consider:\n\n >>> lists = [[]] * 3\n >>> lists\n [[], [], []]\n >>> lists[0].append(3)\n >>> lists\n [[3], [3], [3]]\n\n What has happened is that "[[]]" is a one-element list containing\n an empty list, so all three elements of "[[]] * 3" are (pointers\n to) this single empty list. Modifying any of the elements of\n "lists" modifies this single list. You can create a list of\n different lists this way:\n\n >>> lists = [[] for i in range(3)]\n >>> lists[0].append(3)\n >>> lists[1].append(5)\n >>> lists[2].append(7)\n >>> lists\n [[3], [5], [7]]\n\n3. If *i* or *j* is negative, the index is relative to the end of\n the string: "len(s) + i" or "len(s) + j" is substituted. But note\n that "-0" is still "0".\n\n4. The slice of *s* from *i* to *j* is defined as the sequence of\n items with index *k* such that "i <= k < j". If *i* or *j* is\n greater than "len(s)", use "len(s)". If *i* is omitted or "None",\n use "0". If *j* is omitted or "None", use "len(s)". If *i* is\n greater than or equal to *j*, the slice is empty.\n\n5. The slice of *s* from *i* to *j* with step *k* is defined as the\n sequence of items with index "x = i + n*k" such that "0 <= n <\n (j-i)/k". In other words, the indices are "i", "i+k", "i+2*k",\n "i+3*k" and so on, stopping when *j* is reached (but never\n including *j*). If *i* or *j* is greater than "len(s)", use\n "len(s)". If *i* or *j* are omitted or "None", they become "end"\n values (which end depends on the sign of *k*). Note, *k* cannot be\n zero. If *k* is "None", it is treated like "1".\n\n6. Concatenating immutable sequences always results in a new\n object. This means that building up a sequence by repeated\n concatenation will have a quadratic runtime cost in the total\n sequence length. To get a linear runtime cost, you must switch to\n one of the alternatives below:\n\n * if concatenating "str" objects, you can build a list and use\n "str.join()" at the end or else write to a "io.StringIO" instance\n and retrieve its value when complete\n\n * if concatenating "bytes" objects, you can similarly use\n "bytes.join()" or "io.BytesIO", or you can do in-place\n concatenation with a "bytearray" object. "bytearray" objects are\n mutable and have an efficient overallocation mechanism\n\n * if concatenating "tuple" objects, extend a "list" instead\n\n * for other types, investigate the relevant class documentation\n\n7. Some sequence types (such as "range") only support item\n sequences that follow specific patterns, and hence don\'t support\n sequence concatenation or repetition.\n\n8. "index" raises "ValueError" when *x* is not found in *s*. When\n supported, the additional arguments to the index method allow\n efficient searching of subsections of the sequence. Passing the\n extra arguments is roughly equivalent to using "s[i:j].index(x)",\n only without copying any data and with the returned index being\n relative to the start of the sequence rather than the start of the\n slice.\n\n\nImmutable Sequence Types\n========================\n\nThe only operation that immutable sequence types generally implement\nthat is not also implemented by mutable sequence types is support for\nthe "hash()" built-in.\n\nThis support allows immutable sequences, such as "tuple" instances, to\nbe used as "dict" keys and stored in "set" and "frozenset" instances.\n\nAttempting to hash an immutable sequence that contains unhashable\nvalues will result in "TypeError".\n\n\nMutable Sequence Types\n======================\n\nThe operations in the following table are defined on mutable sequence\ntypes. The "collections.abc.MutableSequence" ABC is provided to make\nit easier to correctly implement these operations on custom sequence\ntypes.\n\nIn the table *s* is an instance of a mutable sequence type, *t* is any\niterable object and *x* is an arbitrary object that meets any type and\nvalue restrictions imposed by *s* (for example, "bytearray" only\naccepts integers that meet the value restriction "0 <= x <= 255").\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j:k] = t" | the elements of "s[i:j:k]" are | (1) |\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n| "s.clear()" | removes all items from "s" (same | (5) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.copy()" | creates a shallow copy of "s" | (5) |\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n| "s.pop([i])" | retrieves the item at *i* and | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.remove(x)" | remove the first item from *s* | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.reverse()" | reverses the items of *s* in | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. The optional argument *i* defaults to "-1", so that by default\n the last item is removed and returned.\n\n3. "remove" raises "ValueError" when *x* is not found in *s*.\n\n4. The "reverse()" method modifies the sequence in place for\n economy of space when reversing a large sequence. To remind users\n that it operates by side effect, it does not return the reversed\n sequence.\n\n5. "clear()" and "copy()" are included for consistency with the\n interfaces of mutable containers that don\'t support slicing\n operations (such as "dict" and "set")\n\n New in version 3.3: "clear()" and "copy()" methods.\n\n\nLists\n=====\n\nLists are mutable sequences, typically used to store collections of\nhomogeneous items (where the precise degree of similarity will vary by\napplication).\n\nclass class list([iterable])\n\n Lists may be constructed in several ways:\n\n * Using a pair of square brackets to denote the empty list: "[]"\n\n * Using square brackets, separating items with commas: "[a]",\n "[a, b, c]"\n\n * Using a list comprehension: "[x for x in iterable]"\n\n * Using the type constructor: "list()" or "list(iterable)"\n\n The constructor builds a list whose items are the same and in the\n same order as *iterable*\'s items. *iterable* may be either a\n sequence, a container that supports iteration, or an iterator\n object. If *iterable* is already a list, a copy is made and\n returned, similar to "iterable[:]". For example, "list(\'abc\')"\n returns "[\'a\', \'b\', \'c\']" and "list( (1, 2, 3) )" returns "[1, 2,\n 3]". If no argument is given, the constructor creates a new empty\n list, "[]".\n\n Many other operations also produce lists, including the "sorted()"\n built-in.\n\n Lists implement all of the *common* and *mutable* sequence\n operations. Lists also provide the following additional method:\n\n sort(*, key=None, reverse=None)\n\n This method sorts the list in place, using only "<" comparisons\n between items. Exceptions are not suppressed - if any comparison\n operations fail, the entire sort operation will fail (and the\n list will likely be left in a partially modified state).\n\n "sort()" accepts two arguments that can only be passed by\n keyword (*keyword-only arguments*):\n\n *key* specifies a function of one argument that is used to\n extract a comparison key from each list element (for example,\n "key=str.lower"). The key corresponding to each item in the list\n is calculated once and then used for the entire sorting process.\n The default value of "None" means that list items are sorted\n directly without calculating a separate key value.\n\n The "functools.cmp_to_key()" utility is available to convert a\n 2.x style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to "True", then the list\n elements are sorted as if each comparison were reversed.\n\n This method modifies the sequence in place for economy of space\n when sorting a large sequence. To remind users that it operates\n by side effect, it does not return the sorted sequence (use\n "sorted()" to explicitly request a new sorted list instance).\n\n The "sort()" method is guaranteed to be stable. A sort is\n stable if it guarantees not to change the relative order of\n elements that compare equal --- this is helpful for sorting in\n multiple passes (for example, sort by department, then by salary\n grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises "ValueError" if it can detect\n that the list has been mutated during a sort.\n\n\nTuples\n======\n\nTuples are immutable sequences, typically used to store collections of\nheterogeneous data (such as the 2-tuples produced by the "enumerate()"\nbuilt-in). Tuples are also used for cases where an immutable sequence\nof homogeneous data is needed (such as allowing storage in a "set" or\n"dict" instance).\n\nclass class tuple([iterable])\n\n Tuples may be constructed in a number of ways:\n\n * Using a pair of parentheses to denote the empty tuple: "()"\n\n * Using a trailing comma for a singleton tuple: "a," or "(a,)"\n\n * Separating items with commas: "a, b, c" or "(a, b, c)"\n\n * Using the "tuple()" built-in: "tuple()" or "tuple(iterable)"\n\n The constructor builds a tuple whose items are the same and in the\n same order as *iterable*\'s items. *iterable* may be either a\n sequence, a container that supports iteration, or an iterator\n object. If *iterable* is already a tuple, it is returned\n unchanged. For example, "tuple(\'abc\')" returns "(\'a\', \'b\', \'c\')"\n and "tuple( [1, 2, 3] )" returns "(1, 2, 3)". If no argument is\n given, the constructor creates a new empty tuple, "()".\n\n Note that it is actually the comma which makes a tuple, not the\n parentheses. The parentheses are optional, except in the empty\n tuple case, or when they are needed to avoid syntactic ambiguity.\n For example, "f(a, b, c)" is a function call with three arguments,\n while "f((a, b, c))" is a function call with a 3-tuple as the sole\n argument.\n\n Tuples implement all of the *common* sequence operations.\n\nFor heterogeneous collections of data where access by name is clearer\nthan access by index, "collections.namedtuple()" may be a more\nappropriate choice than a simple tuple object.\n\n\nRanges\n======\n\nThe "range" type represents an immutable sequence of numbers and is\ncommonly used for looping a specific number of times in "for" loops.\n\nclass class range(stop)\nclass class range(start, stop[, step])\n\n The arguments to the range constructor must be integers (either\n built-in "int" or any object that implements the "__index__"\n special method). If the *step* argument is omitted, it defaults to\n "1". If the *start* argument is omitted, it defaults to "0". If\n *step* is zero, "ValueError" is raised.\n\n For a positive *step*, the contents of a range "r" are determined\n by the formula "r[i] = start + step*i" where "i >= 0" and "r[i] <\n stop".\n\n For a negative *step*, the contents of the range are still\n determined by the formula "r[i] = start + step*i", but the\n constraints are "i >= 0" and "r[i] > stop".\n\n A range object will be empty if "r[0]" does not meet the value\n constraint. Ranges do support negative indices, but these are\n interpreted as indexing from the end of the sequence determined by\n the positive indices.\n\n Ranges containing absolute values larger than "sys.maxsize" are\n permitted but some features (such as "len()") may raise\n "OverflowError".\n\n Range examples:\n\n >>> list(range(10))\n [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n >>> list(range(1, 11))\n [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n >>> list(range(0, 30, 5))\n [0, 5, 10, 15, 20, 25]\n >>> list(range(0, 10, 3))\n [0, 3, 6, 9]\n >>> list(range(0, -10, -1))\n [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]\n >>> list(range(0))\n []\n >>> list(range(1, 0))\n []\n\n Ranges implement all of the *common* sequence operations except\n concatenation and repetition (due to the fact that range objects\n can only represent sequences that follow a strict pattern and\n repetition and concatenation will usually violate that pattern).\n\nThe advantage of the "range" type over a regular "list" or "tuple" is\nthat a "range" object will always take the same (small) amount of\nmemory, no matter the size of the range it represents (as it only\nstores the "start", "stop" and "step" values, calculating individual\nitems and subranges as needed).\n\nRange objects implement the "collections.abc.Sequence" ABC, and\nprovide features such as containment tests, element index lookup,\nslicing and support for negative indices (see *Sequence Types ---\nlist, tuple, range*):\n\n>>> r = range(0, 20, 2)\n>>> r\nrange(0, 20, 2)\n>>> 11 in r\nFalse\n>>> 10 in r\nTrue\n>>> r.index(10)\n5\n>>> r[5]\n10\n>>> r[:5]\nrange(0, 10, 2)\n>>> r[-1]\n18\n\nTesting range objects for equality with "==" and "!=" compares them as\nsequences. That is, two range objects are considered equal if they\nrepresent the same sequence of values. (Note that two range objects\nthat compare equal might have different "start", "stop" and "step"\nattributes, for example "range(0) == range(2, 1, 3)" or "range(0, 3,\n2) == range(0, 4, 2)".)\n\nChanged in version 3.2: Implement the Sequence ABC. Support slicing\nand negative indices. Test "int" objects for membership in constant\ntime instead of iterating through all items.\n\nChanged in version 3.3: Define \'==\' and \'!=\' to compare range objects\nbased on the sequence of values they define (instead of comparing\nbased on object identity).\n\nNew in version 3.3: The "start", "stop" and "step" attributes.\n', + 'typesseq-mutable': '\nMutable Sequence Types\n**********************\n\nThe operations in the following table are defined on mutable sequence\ntypes. The "collections.abc.MutableSequence" ABC is provided to make\nit easier to correctly implement these operations on custom sequence\ntypes.\n\nIn the table *s* is an instance of a mutable sequence type, *t* is any\niterable object and *x* is an arbitrary object that meets any type and\nvalue restrictions imposed by *s* (for example, "bytearray" only\naccepts integers that meet the value restriction "0 <= x <= 255").\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j:k] = t" | the elements of "s[i:j:k]" are | (1) |\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n| "s.clear()" | removes all items from "s" (same | (5) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.copy()" | creates a shallow copy of "s" | (5) |\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n+--------------------------------+----------------------------------+-----------------------+\n| "s.pop([i])" | retrieves the item at *i* and | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.remove(x)" | remove the first item from *s* | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.reverse()" | reverses the items of *s* in | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. The optional argument *i* defaults to "-1", so that by default\n the last item is removed and returned.\n\n3. "remove" raises "ValueError" when *x* is not found in *s*.\n\n4. The "reverse()" method modifies the sequence in place for\n economy of space when reversing a large sequence. To remind users\n that it operates by side effect, it does not return the reversed\n sequence.\n\n5. "clear()" and "copy()" are included for consistency with the\n interfaces of mutable containers that don\'t support slicing\n operations (such as "dict" and "set")\n\n New in version 3.3: "clear()" and "copy()" methods.\n', + 'unary': '\nUnary arithmetic and bitwise operations\n***************************************\n\nAll unary arithmetic and bitwise operations have the same priority:\n\n u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr\n\nThe unary "-" (minus) operator yields the negation of its numeric\nargument.\n\nThe unary "+" (plus) operator yields its numeric argument unchanged.\n\nThe unary "~" (invert) operator yields the bitwise inversion of its\ninteger argument. The bitwise inversion of "x" is defined as\n"-(x+1)". It only applies to integral numbers.\n\nIn all three cases, if the argument does not have the proper type, a\n"TypeError" exception is raised.\n', + 'while': '\nThe "while" statement\n*********************\n\nThe "while" statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the "else" clause, if present, is executed\nand the loop terminates.\n\nA "break" statement executed in the first suite terminates the loop\nwithout executing the "else" clause\'s suite. A "continue" statement\nexecuted in the first suite skips the rest of the suite and goes back\nto testing the expression.\n', + 'with': '\nThe "with" statement\n********************\n\nThe "with" statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common "try"..."except"..."finally"\nusage patterns to be encapsulated for convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the "with" statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the "with_item")\n is evaluated to obtain a context manager.\n\n2. The context manager\'s "__exit__()" is loaded for later use.\n\n3. The context manager\'s "__enter__()" method is invoked.\n\n4. If a target was included in the "with" statement, the return\n value from "__enter__()" is assigned to it.\n\n Note: The "with" statement guarantees that if the "__enter__()"\n method returns without an error, then "__exit__()" will always be\n called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s "__exit__()" method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to "__exit__()". Otherwise, three\n "None" arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the "__exit__()" method was false, the exception is reraised.\n If the return value was true, the exception is suppressed, and\n execution continues with the statement following the "with"\n statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from "__exit__()" is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple "with" statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also: **PEP 0343** - The "with" statement\n\n The specification, background, and examples for the Python "with"\n statement.\n', + 'yield': '\nThe "yield" statement\n*********************\n\n yield_stmt ::= yield_expression\n\nThe "yield" statement is only used when defining a generator function,\nand is only used in the body of the generator function. Using a\n"yield" statement in a function definition is sufficient to cause that\ndefinition to create a generator function instead of a normal\nfunction.\n\nWhen a generator function is called, it returns an iterator known as a\ngenerator iterator, or more commonly, a generator. The body of the\ngenerator function is executed by calling the "next()" function on the\ngenerator repeatedly until it raises an exception.\n\nWhen a "yield" statement is executed, the state of the generator is\nfrozen and the value of "expression_list" is returned to "next()"\'s\ncaller. By "frozen" we mean that all local state is retained,\nincluding the current bindings of local variables, the instruction\npointer, and the internal evaluation stack: enough information is\nsaved so that the next time "next()" is invoked, the function can\nproceed exactly as if the "yield" statement were just another external\ncall.\n\nThe "yield" statement is allowed in the "try" clause of a "try" ...\n"finally" construct. If the generator is not resumed before it is\nfinalized (by reaching a zero reference count or by being garbage\ncollected), the generator-iterator\'s "close()" method will be called,\nallowing any pending "finally" clauses to execute.\n\nWhen "yield from " is used, it treats the supplied expression as\na subiterator, producing values from it until the underlying iterator\nis exhausted.\n\n Changed in version 3.3: Added "yield from " to delegate\n control flow to a subiterator\n\nFor full details of "yield" semantics, refer to the *Yield\nexpressions* section.\n\nSee also: **PEP 0255** - Simple Generators\n\n The proposal for adding generators and the "yield" statement to\n Python.\n\n **PEP 0342** - Coroutines via Enhanced Generators\n The proposal to enhance the API and syntax of generators, making\n them usable as simple coroutines.\n\n **PEP 0380** - Syntax for Delegating to a Subgenerator\n The proposal to introduce the "yield_from" syntax, making\n delegation to sub-generators easy.\n'} -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 07:28:49 2014 From: python-checkins at python.org (larry.hastings) Date: Mon, 27 Jan 2014 07:28:49 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Version_bump_for_3=2E4=2E0?= =?utf-8?b?YjMu?= Message-ID: <3fCLdF4Xjqz7Ljy@mail.python.org> http://hg.python.org/cpython/rev/a97ce3ecc96a changeset: 88759:a97ce3ecc96a tag: v3.4.0b3 user: Larry Hastings date: Sun Jan 26 00:48:23 2014 -0800 summary: Version bump for 3.4.0b3. files: Include/patchlevel.h | 4 ++-- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/NEWS | 2 +- Misc/RPM/python-3.4.spec | 2 +- README | 2 +- 6 files changed, 7 insertions(+), 7 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 4 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_BETA -#define PY_RELEASE_SERIAL 2 +#define PY_RELEASE_SERIAL 3 /* Version as a string */ -#define PY_VERSION "3.4.0b2+" +#define PY_VERSION "3.4.0b3" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -13,5 +13,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.4.0b2" +__version__ = "3.4.0b3" #--end constants-- diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1,1 +1,1 @@ -IDLE_VERSION = "3.4.0b2" +IDLE_VERSION = "3.4.0b3" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -5,7 +5,7 @@ What's New in Python 3.4.0 Beta 3? ================================== -Release date: 2014-01-25 +Release date: 2014-01-26 Core and Builtins ----------------- diff --git a/Misc/RPM/python-3.4.spec b/Misc/RPM/python-3.4.spec --- a/Misc/RPM/python-3.4.spec +++ b/Misc/RPM/python-3.4.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 3.4.0b2 +%define version 3.4.0b3 %define libvers 3.4 #--end constants-- %define release 1pydotorg diff --git a/README b/README --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Python version 3.4.0 beta 2 +This is Python version 3.4.0 beta 3 =================================== Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 07:28:50 2014 From: python-checkins at python.org (larry.hastings) Date: Mon, 27 Jan 2014 07:28:50 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Added_tag_v3=2E4=2E0b3_for?= =?utf-8?q?_changeset_a97ce3ecc96a?= Message-ID: <3fCLdG6FZsz7LmT@mail.python.org> http://hg.python.org/cpython/rev/447c758cdc26 changeset: 88760:447c758cdc26 user: Larry Hastings date: Sun Jan 26 00:48:46 2014 -0800 summary: Added tag v3.4.0b3 for changeset a97ce3ecc96a files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -124,3 +124,4 @@ e245b0d7209bb6d0e19316e1e2af1aa9c2139104 v3.4.0a4 3405dc9a6afaa0a06dd1f6f182ec5c998dce6f5f v3.4.0b1 ba32913eb13ec545a46dd0ce18035b6c416f0d78 v3.4.0b2 +a97ce3ecc96af79bd2e1ac66ce48d9138e0ca749 v3.4.0b3 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 07:28:52 2014 From: python-checkins at python.org (larry.hastings) Date: Mon, 27 Jan 2014 07:28:52 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Post-release_bump_for_3=2E?= =?utf-8?q?4=2E0_beta_3=2E?= Message-ID: <3fCLdJ0wh6z7LnM@mail.python.org> http://hg.python.org/cpython/rev/8397134b25df changeset: 88761:8397134b25df user: Larry Hastings date: Sun Jan 26 22:27:20 2014 -0800 summary: Post-release bump for 3.4.0 beta 3. 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 3 /* Version as a string */ -#define PY_VERSION "3.4.0b3" +#define PY_VERSION "3.4.0b3+" /*--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.4.0 release candidate 1? +=============================================== + +Release date: 2014-02-09 + +Core and Builtins +----------------- + +Library +------- + + What's New in Python 3.4.0 Beta 3? ================================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 07:28:54 2014 From: python-checkins at python.org (larry.hastings) Date: Mon, 27 Jan 2014 07:28:54 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?b?KTogTWVyZ2Uu?= Message-ID: <3fCLdL1hlkz7LnY@mail.python.org> http://hg.python.org/cpython/rev/a45ad55ea3da changeset: 88762:a45ad55ea3da parent: 88761:8397134b25df parent: 88757:c6b4a5354c23 user: Larry Hastings date: Sun Jan 26 22:28:06 2014 -0800 summary: Merge. files: Doc/c-api/exceptions.rst | 10 + Doc/library/concurrent.futures.rst | 3 +- Doc/reference/expressions.rst | 99 +- Doc/reference/simple_stmts.rst | 57 +- Doc/whatsnew/3.4.rst | 8 + Lib/asyncio/base_subprocess.py | 1 - Lib/asyncio/unix_events.py | 3 - Lib/asyncio/windows_events.py | 3 - Lib/codecs.py | 13 +- Lib/concurrent/futures/_base.py | 6 +- Lib/idlelib/CallTips.py | 15 +- Lib/idlelib/configDialog.py | 9 +- Lib/idlelib/idle_test/test_calltips.py | 56 +- Lib/test/imghdrdata/python.bmp | Bin Lib/test/imghdrdata/python.gif | Bin Lib/test/imghdrdata/python.jpg | Bin Lib/test/imghdrdata/python.pbm | 3 + Lib/test/imghdrdata/python.pgm | Bin Lib/test/imghdrdata/python.png | Bin Lib/test/imghdrdata/python.ppm | Bin Lib/test/imghdrdata/python.ras | Bin Lib/test/imghdrdata/python.sgi | Bin Lib/test/imghdrdata/python.tiff | Bin Lib/test/imghdrdata/python.xbm | 6 + Lib/test/test_codecs.py | 37 +- Lib/test/test_concurrent_futures.py | 7 + Lib/test/test_imghdr.py | 131 +++ Lib/test/test_sundry.py | 2 +- Lib/wsgiref/__init__.py | 2 +- Misc/ACKS | 1 + Misc/NEWS | 22 +- Modules/_pickle.c | 2 +- Modules/audioop.c | 14 +- Modules/binascii.c | 5 + Modules/clinic/binascii.c.h | 32 +- Modules/clinic/zlibmodule.c.h | 411 ++++++++++ Modules/zlibmodule.c | 503 +++++------- Objects/exceptions.c | 7 +- 38 files changed, 1003 insertions(+), 465 deletions(-) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -90,6 +90,16 @@ the class in that case. If the values are already normalized, nothing happens. The delayed normalization is implemented to improve performance. + .. note:: + + This function *does not* implicitly set the ``__traceback__`` + attribute on the exception value. If setting the traceback + appropriately is desired, the following additional snippet is needed:: + + if (tb != NULL) { + PyException_SetTraceback(val, tb); + } + .. c:function:: void PyErr_Clear() diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -371,7 +371,8 @@ Returns an iterator over the :class:`Future` instances (possibly created by different :class:`Executor` instances) given by *fs* that yields futures as - they complete (finished or were cancelled). Any futures that completed + they complete (finished or were cancelled). Any futures given by *fs* that + are duplicated will be returned once. Any futures that completed before :func:`as_completed` is called will be yielded first. The returned iterator raises a :exc:`TimeoutError` if :meth:`~iterator.__next__` is called and the result isn't available after *timeout* seconds from the diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -319,27 +319,25 @@ yield_atom: "(" `yield_expression` ")" yield_expression: "yield" [`expression_list` | "from" `expression`] -The :keyword:`yield` expression is only used when defining a :term:`generator` -function, -and can only be used in the body of a function definition. Using a -:keyword:`yield` expression in a function definition is sufficient to cause that -definition to create a generator function instead of a normal function. +The yield expression is only used when defining a :term:`generator` function and +thus can only be used in the body of a function definition. Using a yield +expression in a function's body causes that function to be a generator. When a generator function is called, it returns an iterator known as a generator. That generator then controls the execution of a generator function. The execution starts when one of the generator's methods is called. At that -time, the execution proceeds to the first :keyword:`yield` expression, where it -is suspended again, returning the value of :token:`expression_list` to -generator's caller. By suspended we mean that all local state is retained, -including the current bindings of local variables, the instruction pointer, and -the internal evaluation stack. When the execution is resumed by calling one of -the generator's methods, the function can proceed exactly as if the -:keyword:`yield` expression was just another external call. The value of the -:keyword:`yield` expression after resuming depends on the method which resumed -the execution. If :meth:`~generator.__next__` is used (typically via either a -:keyword:`for` or the :func:`next` builtin) then the result is :const:`None`, -otherwise, if :meth:`~generator.send` is used, then the result will be the -value passed in to that method. +time, the execution proceeds to the first yield expression, where it is +suspended again, returning the value of :token:`expression_list` to generator's +caller. By suspended, we mean that all local state is retained, including the +current bindings of local variables, the instruction pointer, and the internal +evaluation stack. When the execution is resumed by calling one of the +generator's methods, the function can proceed exactly as if the yield expression +was just another external call. The value of the yield expression after +resuming depends on the method which resumed the execution. If +:meth:`~generator.__next__` is used (typically via either a :keyword:`for` or +the :func:`next` builtin) then the result is :const:`None`. Otherwise, if +:meth:`~generator.send` is used, then the result will be the value passed in to +that method. .. index:: single: coroutine @@ -349,11 +347,11 @@ where should the execution continue after it yields; the control is always transferred to the generator's caller. -:keyword:`yield` expressions are allowed in the :keyword:`try` clause of a -:keyword:`try` ... :keyword:`finally` construct. If the generator is not -resumed before it is finalized (by reaching a zero reference count or by being -garbage collected), the generator-iterator's :meth:`~generator.close` method -will be called, allowing any pending :keyword:`finally` clauses to execute. +yield expressions are allowed in the :keyword:`try` clause of a :keyword:`try` +... :keyword:`finally` construct. If the generator is not resumed before it is +finalized (by reaching a zero reference count or by being garbage collected), +the generator-iterator's :meth:`~generator.close` method will be called, +allowing any pending :keyword:`finally` clauses to execute. When ``yield from `` is used, it treats the supplied expression as a subiterator. All values produced by that subiterator are passed directly @@ -373,12 +371,24 @@ .. versionchanged:: 3.3 Added ``yield from `` to delegate control flow to a subiterator -The parentheses can be omitted when the :keyword:`yield` expression is the -sole expression on the right hand side of an assignment statement. +The parentheses may be omitted when the yield expression is the sole expression +on the right hand side of an assignment statement. + +.. seealso:: + + :pep:`0255` - Simple Generators + The proposal for adding generators and the :keyword:`yield` statement to Python. + + :pep:`0342` - Coroutines via Enhanced Generators + The proposal to enhance the API and syntax of generators, making them + usable as simple coroutines. + + :pep:`0380` - Syntax for Delegating to a Subgenerator + The proposal to introduce the :token:`yield_from` syntax, making delegation + to sub-generators easy. .. index:: object: generator - Generator-iterator methods ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -395,13 +405,12 @@ .. method:: generator.__next__() Starts the execution of a generator function or resumes it at the last - executed :keyword:`yield` expression. When a generator function is resumed - with a :meth:`~generator.__next__` method, the current :keyword:`yield` - expression always evaluates to :const:`None`. The execution then continues - to the next :keyword:`yield` expression, where the generator is suspended - again, and the value of the :token:`expression_list` is returned to - :meth:`next`'s caller. - If the generator exits without yielding another value, a :exc:`StopIteration` + executed yield expression. When a generator function is resumed with a + :meth:`~generator.__next__` method, the current yield expression always + evaluates to :const:`None`. The execution then continues to the next yield + expression, where the generator is suspended again, and the value of the + :token:`expression_list` is returned to :meth:`next`'s caller. If the + generator exits without yielding another value, a :exc:`StopIteration` exception is raised. This method is normally called implicitly, e.g. by a :keyword:`for` loop, or @@ -411,12 +420,12 @@ .. method:: generator.send(value) Resumes the execution and "sends" a value into the generator function. The - ``value`` argument becomes the result of the current :keyword:`yield` - expression. The :meth:`send` method returns the next value yielded by the - generator, or raises :exc:`StopIteration` if the generator exits without - yielding another value. When :meth:`send` is called to start the generator, - it must be called with :const:`None` as the argument, because there is no - :keyword:`yield` expression that could receive the value. + *value* argument becomes the result of the current yield expression. The + :meth:`send` method returns the next value yielded by the generator, or + raises :exc:`StopIteration` if the generator exits without yielding another + value. When :meth:`send` is called to start the generator, it must be called + with :const:`None` as the argument, because there is no yield expression that + could receive the value. .. method:: generator.throw(type[, value[, traceback]]) @@ -478,20 +487,6 @@ Python." -.. seealso:: - - :pep:`0255` - Simple Generators - The proposal for adding generators and the :keyword:`yield` statement to Python. - - :pep:`0342` - Coroutines via Enhanced Generators - The proposal to enhance the API and syntax of generators, making them - usable as simple coroutines. - - :pep:`0380` - Syntax for Delegating to a Subgenerator - The proposal to introduce the :token:`yield_from` syntax, making delegation - to sub-generators easy. - - .. _primaries: Primaries diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -445,53 +445,26 @@ .. productionlist:: yield_stmt: `yield_expression` -The :keyword:`yield` statement is only used when defining a generator function, -and is only used in the body of the generator function. Using a :keyword:`yield` -statement in a function definition is sufficient to cause that definition to -create a generator function instead of a normal function. +A :keyword:`yield` statement is semantically equivalent to a :ref:`yield +expression `. The yield statement can be used to omit the parentheses +that would otherwise be required in the equivalent yield expression +statement. For example, the yield statements :: -When a generator function is called, it returns an iterator known as a generator -iterator, or more commonly, a generator. The body of the generator function is -executed by calling the :func:`next` function on the generator repeatedly until -it raises an exception. + yield + yield from -When a :keyword:`yield` statement is executed, the state of the generator is -frozen and the value of :token:`expression_list` is returned to :meth:`next`'s -caller. By "frozen" we mean that all local state is retained, including the -current bindings of local variables, the instruction pointer, and the internal -evaluation stack: enough information is saved so that the next time :func:`next` -is invoked, the function can proceed exactly as if the :keyword:`yield` -statement were just another external call. +are equivalent to the yield expression statements :: -The :keyword:`yield` statement is allowed in the :keyword:`try` clause of a -:keyword:`try` ... :keyword:`finally` construct. If the generator is not -resumed before it is finalized (by reaching a zero reference count or by being -garbage collected), the generator-iterator's :meth:`close` method will be -called, allowing any pending :keyword:`finally` clauses to execute. + (yield ) + (yield from ) -When ``yield from `` is used, it treats the supplied expression as -a subiterator, producing values from it until the underlying iterator is -exhausted. +Yield expressions and statements are only used when defining a :term:`generator` +function, and are only used in the body of the generator function. Using yield +in a function definition is sufficient to cause that definition to create a +generator function instead of a normal function. - .. versionchanged:: 3.3 - Added ``yield from `` to delegate control flow to a subiterator - -For full details of :keyword:`yield` semantics, refer to the :ref:`yieldexpr` -section. - -.. seealso:: - - :pep:`0255` - Simple Generators - The proposal for adding generators and the :keyword:`yield` statement to Python. - - :pep:`0342` - Coroutines via Enhanced Generators - The proposal to enhance the API and syntax of generators, making them - usable as simple coroutines. - - :pep:`0380` - Syntax for Delegating to a Subgenerator - The proposal to introduce the :token:`yield_from` syntax, making delegation - to sub-generators easy. - +For full details of :keyword:`yield` semantics, refer to the +:ref:`yieldexpr` section. .. _raise: 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 @@ -264,6 +264,9 @@ >>> import codecs >>> codecs.decode(b"abcdefgh", "hex") + Traceback (most recent call last): + File "/usr/lib/python3.4/encodings/hex_codec.py", line 20, in hex_decode + return (binascii.a2b_hex(input), len(input)) binascii.Error: Non-hexadecimal digit found The above exception was the direct cause of the following exception: @@ -273,6 +276,11 @@ binascii.Error: decoding with 'hex' codec failed (Error: Non-hexadecimal digit found) >>> codecs.encode("hello", "bz2") + Traceback (most recent call last): + File "/usr/lib/python3.4/encodings/bz2_codec.py", line 17, in bz2_encode + return (bz2.compress(input), len(input)) + File "/usr/lib/python3.4/bz2.py", line 498, in compress + return comp.compress(data) + comp.flush() TypeError: 'str' does not support the buffer interface The above exception was the direct cause of the following exception: diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -114,7 +114,6 @@ assert returncode is not None, returncode assert self._returncode is None, self._returncode self._returncode = returncode - self._loop._subprocess_closed(self) self._call(self._protocol.process_exited) self._try_finish() 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 @@ -169,9 +169,6 @@ def _child_watcher_callback(self, pid, returncode, transp): self.call_soon_threadsafe(transp._process_exited, returncode) - def _subprocess_closed(self, transp): - pass - def _set_nonblocking(fd): flags = fcntl.fcntl(fd, fcntl.F_GETFL) 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 @@ -178,9 +178,6 @@ yield from transp._post_init() return transp - def _subprocess_closed(self, transport): - pass - class IocpProactor: """Proactor implementation using IOCP.""" diff --git a/Lib/codecs.py b/Lib/codecs.py --- a/Lib/codecs.py +++ b/Lib/codecs.py @@ -475,14 +475,11 @@ # read until we get the required number of characters (if available) while True: # can the request be satisfied from the character buffer? - if chars < 0: - if size < 0: - if self.charbuffer: - break - elif len(self.charbuffer) >= size: + if chars >= 0: + if len(self.charbuffer) >= chars: break - else: - if len(self.charbuffer) >= chars: + elif size >= 0: + if len(self.charbuffer) >= size: break # we need more data if size < 0: @@ -491,6 +488,8 @@ newdata = self.stream.read(size) # decode bytes (those remaining from the last call included) data = self.bytebuffer + newdata + if not data: + break try: newchars, decodedbytes = self.decode(data, self.errors) except UnicodeDecodeError as exc: diff --git a/Lib/concurrent/futures/_base.py b/Lib/concurrent/futures/_base.py --- a/Lib/concurrent/futures/_base.py +++ b/Lib/concurrent/futures/_base.py @@ -181,7 +181,8 @@ Returns: An iterator that yields the given Futures as they complete (finished or - cancelled). + cancelled). If any given Futures are duplicated, they will be returned + once. Raises: TimeoutError: If the entire result iterator could not be generated @@ -190,11 +191,12 @@ if timeout is not None: end_time = timeout + time.time() + fs = set(fs) with _AcquireFutures(fs): finished = set( f for f in fs if f._state in [CANCELLED_AND_NOTIFIED, FINISHED]) - pending = set(fs) - finished + pending = fs - finished waiter = _create_and_install_waiters(fs, _AS_COMPLETED) try: diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -5,16 +5,16 @@ which disappear when you type a closing parenthesis. """ +import __main__ +import inspect import re import sys +import textwrap import types -import inspect from idlelib import CallTipWindow from idlelib.HyperParser import HyperParser -import __main__ - class CallTips: menudefs = [ @@ -117,8 +117,9 @@ return None # The following are used in get_argspec and some in tests -_MAX_COLS = 79 +_MAX_COLS = 85 _MAX_LINES = 5 # enough for bytes +_INDENT = ' '*4 # for wrapped signatures _first_param = re.compile('(?<=\()\w*\,?\s*') _default_callable_argspec = "See source or doc" @@ -149,13 +150,15 @@ isinstance(ob_call, types.MethodType)): argspec = _first_param.sub("", argspec) + lines = (textwrap.wrap(argspec, _MAX_COLS, subsequent_indent=_INDENT) + if len(argspec) > _MAX_COLS else [argspec] if argspec else []) + if isinstance(ob_call, types.MethodType): doc = ob_call.__doc__ else: doc = getattr(ob, "__doc__", "") if doc: - lines = [argspec] if argspec else [] - for line in doc.split('\n', 5)[:_MAX_LINES]: + for line in doc.split('\n', _MAX_LINES)[:_MAX_LINES]: line = line.strip() if not line: break diff --git a/Lib/idlelib/configDialog.py b/Lib/idlelib/configDialog.py --- a/Lib/idlelib/configDialog.py +++ b/Lib/idlelib/configDialog.py @@ -82,9 +82,10 @@ else: extraKwds=dict(padx=6, pady=3) - self.buttonHelp = Button(frameActionButtons,text='Help', - command=self.Help,takefocus=FALSE, - **extraKwds) +# Comment out button creation and packing until implement self.Help +## self.buttonHelp = Button(frameActionButtons,text='Help', +## command=self.Help,takefocus=FALSE, +## **extraKwds) self.buttonOk = Button(frameActionButtons,text='Ok', command=self.Ok,takefocus=FALSE, **extraKwds) @@ -98,7 +99,7 @@ self.CreatePageHighlight() self.CreatePageKeys() self.CreatePageGeneral() - self.buttonHelp.pack(side=RIGHT,padx=5) +## self.buttonHelp.pack(side=RIGHT,padx=5) self.buttonOk.pack(side=LEFT,padx=5) self.buttonApply.pack(side=LEFT,padx=5) self.buttonCancel.pack(side=LEFT,padx=5) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -1,5 +1,6 @@ import unittest import idlelib.CallTips as ct +import textwrap import types default_tip = ct._default_callable_argspec @@ -55,32 +56,45 @@ gtest(list.__new__, 'T.__new__(S, ...) -> a new object with type S, a subtype of T') gtest(list.__init__, - 'Initializes self. See help(type(self)) for accurate signature.') + 'x.__init__(...) initializes x; see help(type(x)) for signature') append_doc = "L.append(object) -> None -- append object to end" gtest(list.append, append_doc) gtest([].append, append_doc) gtest(List.append, append_doc) - gtest(types.MethodType, "Create a bound instance method object.") + gtest(types.MethodType, "method(function, instance)") gtest(SB(), default_tip) + def test_signature_wrap(self): + self.assertEqual(signature(textwrap.TextWrapper), '''\ +(width=70, initial_indent='', subsequent_indent='', expand_tabs=True, + replace_whitespace=True, fix_sentence_endings=False, break_long_words=True, + drop_whitespace=True, break_on_hyphens=True, tabsize=8, *, max_lines=None, + placeholder=' [...]')''') + + def test_docline_truncation(self): + def f(): pass + f.__doc__ = 'a'*300 + self.assertEqual(signature(f), '()\n' + 'a' * (ct._MAX_COLS-3) + '...') + def test_multiline_docstring(self): # Test fewer lines than max. - self.assertEqual(signature(dict), - "dict(mapping) -> new dictionary initialized from a mapping object's\n" - "(key, value) pairs\n" - "dict(iterable) -> new dictionary initialized as if via:\n" - "d = {}\n" - "for k, v in iterable:" - ) + self.assertEqual(signature(list), + "list() -> new empty list\n" + "list(iterable) -> new list initialized from iterable's items") - # Test max lines and line (currently) too long. - self.assertEqual(signature(bytes), -"bytes(string, encoding[, errors]) -> bytes\n" -"bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer\n" -#bytes(int) -> bytes object of size given by the parameter initialized with null bytes -"bytes(int) -> bytes object of size given by the parameter initialized with n...\n" -"bytes() -> empty bytes object") + # Test max lines + self.assertEqual(signature(bytes), '''\ +bytes(iterable_of_ints) -> bytes +bytes(string, encoding[, errors]) -> bytes +bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer +bytes(int) -> bytes object of size given by the parameter initialized with null bytes +bytes() -> empty bytes object''') + + # Test more than max lines + def f(): pass + f.__doc__ = 'a\n' * 15 + self.assertEqual(signature(f), '()' + '\na' * ct._MAX_LINES) def test_functions(self): def t1(): 'doc' @@ -109,6 +123,16 @@ (tc.__call__, '(ci)'), (tc, '(ci)'), (TC.cm, "(a)"),): self.assertEqual(signature(meth), mtip + "\ndoc") + def test_starred_parameter(self): + # test that starred first parameter is *not* removed from argspec + class C: + def m1(*args): pass + def m2(**kwds): pass + c = C() + for meth, mtip in ((C.m1, '(*args)'), (c.m1, "(*args)"), + (C.m2, "(**kwds)"), (c.m2, "(**kwds)"),): + self.assertEqual(signature(meth), mtip) + def test_non_ascii_name(self): # test that re works to delete a first parameter name that # includes non-ascii chars, such as various forms of A. diff --git a/Lib/test/imghdrdata/python.bmp b/Lib/test/imghdrdata/python.bmp new file mode 100644 index 0000000000000000000000000000000000000000..675f95191a45fdb3ae845996d6871b86286f848a GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.gif b/Lib/test/imghdrdata/python.gif new file mode 100644 index 0000000000000000000000000000000000000000..96fd9fef76b10899807d3724c97335f35a03743a GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.jpg b/Lib/test/imghdrdata/python.jpg new file mode 100644 index 0000000000000000000000000000000000000000..21222c09f5a71d9d86a0323e49ebc5da6639b22f GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.pbm b/Lib/test/imghdrdata/python.pbm new file mode 100644 --- /dev/null +++ b/Lib/test/imghdrdata/python.pbm @@ -0,0 +1,3 @@ +P4 +16 16 +????????[??a_?X????????? \ No newline at end of file diff --git a/Lib/test/imghdrdata/python.pgm b/Lib/test/imghdrdata/python.pgm new file mode 100644 index 0000000000000000000000000000000000000000..8349f2a53a9be1d895a561cc0fd31f91d7d42b33 GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.png b/Lib/test/imghdrdata/python.png new file mode 100644 index 0000000000000000000000000000000000000000..1a987f79fcd248a94fcd1c45934136919cc0ffdd GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.ppm b/Lib/test/imghdrdata/python.ppm new file mode 100644 index 0000000000000000000000000000000000000000..7d9cdb3215877b4604de4c177fc81ebb645b8290 GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.ras b/Lib/test/imghdrdata/python.ras new file mode 100644 index 0000000000000000000000000000000000000000..130e96f817ed9dd45f411f2f93e0749a4b33ba49 GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.sgi b/Lib/test/imghdrdata/python.sgi new file mode 100644 index 0000000000000000000000000000000000000000..ffe9081c7a5b67ed14285041fd0650f4010bc36d GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.tiff b/Lib/test/imghdrdata/python.tiff new file mode 100644 index 0000000000000000000000000000000000000000..39d0bfcec02533ade8934a8796aebb8990c9d389 GIT binary patch [stripped] diff --git a/Lib/test/imghdrdata/python.xbm b/Lib/test/imghdrdata/python.xbm new file mode 100644 --- /dev/null +++ b/Lib/test/imghdrdata/python.xbm @@ -0,0 +1,6 @@ +#define python_width 16 +#define python_height 16 +static char python_bits[] = { + 0xDF, 0xFE, 0x8F, 0xFD, 0x5F, 0xFB, 0xAB, 0xFE, 0xB5, 0x8D, 0xDA, 0x8F, + 0xA5, 0x86, 0xFA, 0x83, 0x1A, 0x80, 0x0D, 0x80, 0x0D, 0x80, 0x0F, 0xE0, + 0x0F, 0xF8, 0x0F, 0xF8, 0x0F, 0xFC, 0xFF, 0xFF, }; diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -175,6 +175,40 @@ size*"a", ) + def test_mixed_readline_and_read(self): + lines = ["Humpty Dumpty sat on a wall,\n", + "Humpty Dumpty had a great fall.\r\n", + "All the king's horses and all the king's men\r", + "Couldn't put Humpty together again."] + data = ''.join(lines) + def getreader(): + stream = io.BytesIO(data.encode(self.encoding)) + return codecs.getreader(self.encoding)(stream) + + # Issue #8260: Test readline() followed by read() + f = getreader() + self.assertEqual(f.readline(), lines[0]) + self.assertEqual(f.read(), ''.join(lines[1:])) + self.assertEqual(f.read(), '') + + # Issue #16636: Test readline() followed by readlines() + f = getreader() + self.assertEqual(f.readline(), lines[0]) + self.assertEqual(f.readlines(), lines[1:]) + self.assertEqual(f.read(), '') + + # Test read() followed by read() + f = getreader() + self.assertEqual(f.read(size=40, chars=5), data[:5]) + self.assertEqual(f.read(), data[5:]) + self.assertEqual(f.read(), '') + + # Issue #12446: Test read() followed by readlines() + f = getreader() + self.assertEqual(f.read(size=40, chars=5), data[:5]) + self.assertEqual(f.readlines(), [lines[0][5:]] + lines[1:]) + self.assertEqual(f.read(), '') + def test_bug1175396(self): s = [ '<%!--===================================================\r\n', @@ -2370,8 +2404,6 @@ def test_readline(self): for encoding in bytes_transform_encodings: - if encoding in ['uu_codec', 'zlib_codec']: - continue with self.subTest(encoding=encoding): sin = codecs.encode(b"\x80", encoding) reader = codecs.getreader(encoding)(io.BytesIO(sin)) @@ -2522,6 +2554,7 @@ with self.assertRaisesRegex(exc_type, full_msg) as caught: yield caught self.assertIsInstance(caught.exception.__cause__, exc_type) + self.assertIsNotNone(caught.exception.__cause__.__traceback__) def raise_obj(self, *args, **kwds): # Helper to dynamically change the object raised by a test codec diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -350,6 +350,13 @@ SUCCESSFUL_FUTURE]), completed_futures) + def test_duplicate_futures(self): + # Issue 20367. Duplicate futures should not raise exceptions or give + # duplicate responses. + future1 = self.executor.submit(time.sleep, 2) + completed = [f for f in futures.as_completed([future1,future1])] + self.assertEqual(len(completed), 1) + class ThreadPoolAsCompletedTests(ThreadPoolMixin, AsCompletedTests, unittest.TestCase): pass diff --git a/Lib/test/test_imghdr.py b/Lib/test/test_imghdr.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_imghdr.py @@ -0,0 +1,131 @@ +import imghdr +import io +import os +import unittest +import warnings +from test.support import findfile, TESTFN, unlink + +TEST_FILES = ( + ('python.png', 'png'), + ('python.gif', 'gif'), + ('python.bmp', 'bmp'), + ('python.ppm', 'ppm'), + ('python.pgm', 'pgm'), + ('python.pbm', 'pbm'), + ('python.jpg', 'jpeg'), + ('python.ras', 'rast'), + ('python.sgi', 'rgb'), + ('python.tiff', 'tiff'), + ('python.xbm', 'xbm') +) + +class UnseekableIO(io.FileIO): + def tell(self): + raise io.UnsupportedOperation + + def seek(self, *args, **kwargs): + raise io.UnsupportedOperation + +class TestImghdr(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.testfile = findfile('python.png', subdir='imghdrdata') + with open(cls.testfile, 'rb') as stream: + cls.testdata = stream.read() + + def tearDown(self): + unlink(TESTFN) + + def test_data(self): + for filename, expected in TEST_FILES: + filename = findfile(filename, subdir='imghdrdata') + self.assertEqual(imghdr.what(filename), expected) + with open(filename, 'rb') as stream: + self.assertEqual(imghdr.what(stream), expected) + with open(filename, 'rb') as stream: + data = stream.read() + self.assertEqual(imghdr.what(None, data), expected) + self.assertEqual(imghdr.what(None, bytearray(data)), expected) + + def test_register_test(self): + def test_jumbo(h, file): + if h.startswith(b'eggs'): + return 'ham' + imghdr.tests.append(test_jumbo) + self.addCleanup(imghdr.tests.pop) + self.assertEqual(imghdr.what(None, b'eggs'), 'ham') + + def test_file_pos(self): + with open(TESTFN, 'wb') as stream: + stream.write(b'ababagalamaga') + pos = stream.tell() + stream.write(self.testdata) + with open(TESTFN, 'rb') as stream: + stream.seek(pos) + self.assertEqual(imghdr.what(stream), 'png') + self.assertEqual(stream.tell(), pos) + + def test_bad_args(self): + with self.assertRaises(TypeError): + imghdr.what() + with self.assertRaises(AttributeError): + imghdr.what(None) + with self.assertRaises(TypeError): + imghdr.what(self.testfile, 1) + with self.assertRaises(AttributeError): + imghdr.what(os.fsencode(self.testfile)) + with open(self.testfile, 'rb') as f: + with self.assertRaises(AttributeError): + imghdr.what(f.fileno()) + + def test_invalid_headers(self): + for header in (b'\211PN\r\n', + b'\001\331', + b'\x59\xA6', + b'cutecat', + b'000000JFI', + b'GIF80'): + self.assertIsNone(imghdr.what(None, header)) + + def test_string_data(self): + with warnings.catch_warnings(): + warnings.simplefilter("ignore", BytesWarning) + for filename, _ in TEST_FILES: + filename = findfile(filename, subdir='imghdrdata') + with open(filename, 'rb') as stream: + data = stream.read().decode('latin1') + with self.assertRaises(TypeError): + imghdr.what(io.StringIO(data)) + with self.assertRaises(TypeError): + imghdr.what(None, data) + + def test_missing_file(self): + with self.assertRaises(FileNotFoundError): + imghdr.what('missing') + + def test_closed_file(self): + stream = open(self.testfile, 'rb') + stream.close() + with self.assertRaises(ValueError) as cm: + imghdr.what(stream) + stream = io.BytesIO(self.testdata) + stream.close() + with self.assertRaises(ValueError) as cm: + imghdr.what(stream) + + def test_unseekable(self): + with open(TESTFN, 'wb') as stream: + stream.write(self.testdata) + with UnseekableIO(TESTFN, 'rb') as stream: + with self.assertRaises(io.UnsupportedOperation): + imghdr.what(stream) + + def test_output_stream(self): + with open(TESTFN, 'wb') as stream: + stream.write(self.testdata) + stream.seek(0) + with self.assertRaises(OSError) as cm: + imghdr.what(stream) + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_sundry.py b/Lib/test/test_sundry.py --- a/Lib/test/test_sundry.py +++ b/Lib/test/test_sundry.py @@ -6,7 +6,7 @@ class TestUntestedModules(unittest.TestCase): def test_untested_modules_can_be_imported(self): - untested = ('bdb', 'encodings', 'formatter', 'imghdr', + untested = ('bdb', 'encodings', 'formatter', 'nturl2path', 'tabnanny') with support.check_warnings(quiet=True): for name in untested: diff --git a/Lib/wsgiref/__init__.py b/Lib/wsgiref/__init__.py --- a/Lib/wsgiref/__init__.py +++ b/Lib/wsgiref/__init__.py @@ -1,4 +1,4 @@ -"""wsgiref -- a WSGI (PEP 333) Reference Library +"""wsgiref -- a WSGI (PEP 3333) Reference Library Current Contents: diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -725,6 +725,7 @@ Torsten Landschoff ??ukasz Langa Tino Lange +Glenn Langford Andrew Langmead Detlef Lannert Soren Larsen diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -48,6 +48,16 @@ Library ------- +- Issue #20367: Fix behavior of concurrent.futures.as_completed() for + duplicate arguments. Patch by Glenn Langford. + +- Issue #8260: The read(), readline() and readlines() methods of + codecs.StreamReader returned incomplete data when were called after + readline() or read(size). Based on patch by Amaury Forgeot d'Arc. + +- Issue #20105: the codec exception chaining now correctly sets the + traceback of the original exception as its __traceback__ attribute. + - asyncio: Various improvements and small changes not all covered by issues listed below. E.g. wait_for() now cancels the inner task if the timeout occcurs; tweaked the set of exported symbols; renamed @@ -145,6 +155,9 @@ IDLE ---- +- Issue #17721: Remove non-functional configuration dialog help button until we + make it actually gives some help when clicked. Patch by Guilherme Sim??es. + - Issue #17390: Add Python version to Idle editor window title bar. Original patches by Edmond Burnett and Kent Johnson. @@ -154,9 +167,15 @@ Tests ----- +- Issue #19990: Added tests for the imghdr module. Based on patch by + Claudiu Popa. + - Issue #20358: Tests for curses.window.overlay and curses.window.overwrite no longer specify min{row,col} > max{row,col}. +- Issue #19804: The test_find_mac test in test_uuid is now skipped if the + ifconfig executable is not available. + - Issue #19886: Use better estimated memory requirements for bigmem tests. Tools/Demos @@ -553,9 +572,6 @@ Tests ----- -- Issue #19804: The test_find_mac test in test_uuid is now skipped if the - ifconfig executable is not available. - - Issue #20055: Fix test_shutil under Windows with symlink privileges held. Patch by Vajrasky Kok. diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -6149,7 +6149,7 @@ load(UnpicklerObject *self) { PyObject *value = NULL; - char *s; + char *s = NULL; self->num_marks = 0; self->proto = 0; diff --git a/Modules/audioop.c b/Modules/audioop.c --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -1304,6 +1304,7 @@ "weightA should be >= 1, weightB should be >= 0"); return NULL; } + assert(fragment->len >= 0); if (fragment->len % bytes_per_frame != 0) { PyErr_SetString(AudioopError, "not a whole number of frames"); return NULL; @@ -1370,7 +1371,7 @@ case ceiling(len/inrate) * outrate. */ /* compute ceiling(len/inrate) without overflow */ - Py_ssize_t q = len > 0 ? 1 + (len - 1) / inrate : 0; + Py_ssize_t q = 1 + (len - 1) / inrate; if (outrate > PY_SSIZE_T_MAX / q / bytes_per_frame) str = NULL; else @@ -1608,7 +1609,7 @@ Py_ssize_t i; int step, valpred, delta, index, sign, vpdiff, diff; - PyObject *rv, *str; + PyObject *rv = NULL, *str; int outputbuffer = 0, bufferstep; if (!audioop_check_parameters(fragment->len, width)) @@ -1626,9 +1627,10 @@ index = 0; } else if (!PyTuple_Check(state)) { PyErr_SetString(PyExc_TypeError, "state must be a tuple or None"); - return NULL; - } else if (!PyArg_ParseTuple(state, "ii", &valpred, &index)) - return NULL; + goto exit; + } else if (!PyArg_ParseTuple(state, "ii", &valpred, &index)) { + goto exit; + } step = stepsizeTable[index]; bufferstep = 1; @@ -1704,6 +1706,8 @@ bufferstep = !bufferstep; } rv = Py_BuildValue("(O(ii))", str, valpred, index); + + exit: Py_DECREF(str); return rv; } diff --git a/Modules/binascii.c b/Modules/binascii.c --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -195,6 +195,11 @@ type = 'Py_buffer' converter = 'ascii_buffer_converter' impl_by_reference = True + c_default = "{NULL, NULL}" + + def cleanup(self): + name = self.name + return "".join(["if (", name, ".obj)\n PyBuffer_Release(&", name, ");\n"]) [python start generated code]*/ /*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ diff --git a/Modules/clinic/binascii.c.h b/Modules/clinic/binascii.c.h --- a/Modules/clinic/binascii.c.h +++ b/Modules/clinic/binascii.c.h @@ -16,7 +16,7 @@ binascii_a2b_uu(PyModuleDef *module, PyObject *args) { PyObject *return_value = NULL; - Py_buffer data; + Py_buffer data = {NULL, NULL}; if (!PyArg_ParseTuple(args, "O&:a2b_uu", @@ -25,6 +25,10 @@ return_value = binascii_a2b_uu_impl(module, &data); exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + return return_value; } @@ -72,7 +76,7 @@ binascii_a2b_base64(PyModuleDef *module, PyObject *args) { PyObject *return_value = NULL; - Py_buffer data; + Py_buffer data = {NULL, NULL}; if (!PyArg_ParseTuple(args, "O&:a2b_base64", @@ -81,6 +85,10 @@ return_value = binascii_a2b_base64_impl(module, &data); exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + return return_value; } @@ -128,7 +136,7 @@ binascii_a2b_hqx(PyModuleDef *module, PyObject *args) { PyObject *return_value = NULL; - Py_buffer data; + Py_buffer data = {NULL, NULL}; if (!PyArg_ParseTuple(args, "O&:a2b_hqx", @@ -137,6 +145,10 @@ return_value = binascii_a2b_hqx_impl(module, &data); exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + return return_value; } @@ -350,7 +362,7 @@ binascii_a2b_hex(PyModuleDef *module, PyObject *args) { PyObject *return_value = NULL; - Py_buffer hexstr; + Py_buffer hexstr = {NULL, NULL}; if (!PyArg_ParseTuple(args, "O&:a2b_hex", @@ -359,6 +371,10 @@ return_value = binascii_a2b_hex_impl(module, &hexstr); exit: + /* Cleanup for hexstr */ + if (hexstr.obj) + PyBuffer_Release(&hexstr); + return return_value; } @@ -377,7 +393,7 @@ { PyObject *return_value = NULL; static char *_keywords[] = {"data", "header", NULL}; - Py_buffer data; + Py_buffer data = {NULL, NULL}; int header = 0; if (!PyArg_ParseTupleAndKeywords(args, kwargs, @@ -387,6 +403,10 @@ return_value = binascii_a2b_qp_impl(module, &data, header); exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + return return_value; } @@ -427,4 +447,4 @@ return return_value; } -/*[clinic end generated code: checksum=abe48ca8020fa3ec25e13bd9fa7414f6b3ee2946]*/ +/*[clinic end generated code: checksum=8180e5be47a110ae8c89263a7c12a91d80754f60]*/ diff --git a/Modules/clinic/zlibmodule.c.h b/Modules/clinic/zlibmodule.c.h new file mode 100644 --- /dev/null +++ b/Modules/clinic/zlibmodule.c.h @@ -0,0 +1,411 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(zlib_compress__doc__, +"compress(module, bytes, level=Z_DEFAULT_COMPRESSION)\n" +"Returns a bytes object containing compressed data.\n" +"\n" +" bytes\n" +" Binary data to be compressed.\n" +" level\n" +" Compression level, in 0-9."); + +#define ZLIB_COMPRESS_METHODDEF \ + {"compress", (PyCFunction)zlib_compress, METH_VARARGS, zlib_compress__doc__}, + +static PyObject * +zlib_compress_impl(PyModuleDef *module, Py_buffer *bytes, int level); + +static PyObject * +zlib_compress(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer bytes = {NULL, NULL}; + int level = Z_DEFAULT_COMPRESSION; + + if (!PyArg_ParseTuple(args, + "y*|i:compress", + &bytes, &level)) + goto exit; + return_value = zlib_compress_impl(module, &bytes, level); + +exit: + /* Cleanup for bytes */ + if (bytes.obj) + PyBuffer_Release(&bytes); + + return return_value; +} + +PyDoc_STRVAR(zlib_decompress__doc__, +"decompress(module, data, wbits=MAX_WBITS, bufsize=DEF_BUF_SIZE)\n" +"Returns a bytes object containing the uncompressed data.\n" +"\n" +" data\n" +" Compressed data.\n" +" wbits\n" +" The window buffer size.\n" +" bufsize\n" +" The initial output buffer size."); + +#define ZLIB_DECOMPRESS_METHODDEF \ + {"decompress", (PyCFunction)zlib_decompress, METH_VARARGS, zlib_decompress__doc__}, + +static PyObject * +zlib_decompress_impl(PyModuleDef *module, Py_buffer *data, int wbits, unsigned int bufsize); + +static PyObject * +zlib_decompress(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + int wbits = MAX_WBITS; + unsigned int bufsize = DEF_BUF_SIZE; + + if (!PyArg_ParseTuple(args, + "y*|iO&:decompress", + &data, &wbits, uint_converter, &bufsize)) + goto exit; + return_value = zlib_decompress_impl(module, &data, wbits, bufsize); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(zlib_compressobj__doc__, +"compressobj(module, level=Z_DEFAULT_COMPRESSION, method=DEFLATED, wbits=MAX_WBITS, memLevel=DEF_MEM_LEVEL, strategy=Z_DEFAULT_STRATEGY, zdict=None)\n" +"Return a compressor object.\n" +"\n" +" level\n" +" The compression level (an integer in the range 0-9; default is 6).\n" +" Higher compression levels are slower, but produce smaller results.\n" +" method\n" +" The compression algorithm. If given, this must be DEFLATED.\n" +" wbits\n" +" The base two logarithm of the window size (range: 8..15).\n" +" memLevel\n" +" Controls the amount of memory used for internal compression state.\n" +" Valid values range from 1 to 9. Higher values result in higher memory\n" +" usage, faster compression, and smaller output.\n" +" strategy\n" +" Used to tune the compression algorithm. Possible values are\n" +" Z_DEFAULT_STRATEGY, Z_FILTERED, and Z_HUFFMAN_ONLY.\n" +" zdict\n" +" The predefined compression dictionary - a sequence of bytes\n" +" containing subsequences that are likely to occur in the input data."); + +#define ZLIB_COMPRESSOBJ_METHODDEF \ + {"compressobj", (PyCFunction)zlib_compressobj, METH_VARARGS|METH_KEYWORDS, zlib_compressobj__doc__}, + +static PyObject * +zlib_compressobj_impl(PyModuleDef *module, int level, int method, int wbits, int memLevel, int strategy, Py_buffer *zdict); + +static PyObject * +zlib_compressobj(PyModuleDef *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + static char *_keywords[] = {"level", "method", "wbits", "memLevel", "strategy", "zdict", NULL}; + int level = Z_DEFAULT_COMPRESSION; + int method = DEFLATED; + int wbits = MAX_WBITS; + int memLevel = DEF_MEM_LEVEL; + int strategy = Z_DEFAULT_STRATEGY; + Py_buffer zdict = {NULL, NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "|iiiiiy*:compressobj", _keywords, + &level, &method, &wbits, &memLevel, &strategy, &zdict)) + goto exit; + return_value = zlib_compressobj_impl(module, level, method, wbits, memLevel, strategy, &zdict); + +exit: + /* Cleanup for zdict */ + if (zdict.obj) + PyBuffer_Release(&zdict); + + return return_value; +} + +PyDoc_STRVAR(zlib_decompressobj__doc__, +"decompressobj(module, wbits=MAX_WBITS, zdict=b\'\')\n" +"Return a decompressor object.\n" +"\n" +" wbits\n" +" The window buffer size.\n" +" zdict\n" +" The predefined compression dictionary. This must be the same\n" +" dictionary as used by the compressor that produced the input data."); + +#define ZLIB_DECOMPRESSOBJ_METHODDEF \ + {"decompressobj", (PyCFunction)zlib_decompressobj, METH_VARARGS|METH_KEYWORDS, zlib_decompressobj__doc__}, + +static PyObject * +zlib_decompressobj_impl(PyModuleDef *module, int wbits, PyObject *zdict); + +static PyObject * +zlib_decompressobj(PyModuleDef *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + static char *_keywords[] = {"wbits", "zdict", NULL}; + int wbits = MAX_WBITS; + PyObject *zdict = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "|iO:decompressobj", _keywords, + &wbits, &zdict)) + goto exit; + return_value = zlib_decompressobj_impl(module, wbits, zdict); + +exit: + return return_value; +} + +PyDoc_STRVAR(zlib_Compress_compress__doc__, +"compress(self, data)\n" +"Returns a bytes object containing compressed data.\n" +"\n" +" data\n" +" Binary data to be compressed.\n" +"\n" +"After calling this function, some of the input data may still\n" +"be stored in internal buffers for later processing.\n" +"Call the flush() method to clear these buffers."); + +#define ZLIB_COMPRESS_COMPRESS_METHODDEF \ + {"compress", (PyCFunction)zlib_Compress_compress, METH_VARARGS, zlib_Compress_compress__doc__}, + +static PyObject * +zlib_Compress_compress_impl(compobject *self, Py_buffer *data); + +static PyObject * +zlib_Compress_compress(compobject *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + + if (!PyArg_ParseTuple(args, + "y*:compress", + &data)) + goto exit; + return_value = zlib_Compress_compress_impl(self, &data); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(zlib_Decompress_decompress__doc__, +"decompress(self, data, max_length=0)\n" +"Return a bytes object containing the decompressed version of the data.\n" +"\n" +" data\n" +" The binary data to decompress.\n" +" max_length\n" +" The maximum allowable length of the decompressed data.\n" +" Unconsumed input data will be stored in\n" +" the unconsumed_tail attribute.\n" +"\n" +"After calling this function, some of the input data may still be stored in\n" +"internal buffers for later processing.\n" +"Call the flush() method to clear these buffers."); + +#define ZLIB_DECOMPRESS_DECOMPRESS_METHODDEF \ + {"decompress", (PyCFunction)zlib_Decompress_decompress, METH_VARARGS, zlib_Decompress_decompress__doc__}, + +static PyObject * +zlib_Decompress_decompress_impl(compobject *self, Py_buffer *data, unsigned int max_length); + +static PyObject * +zlib_Decompress_decompress(compobject *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + unsigned int max_length = 0; + + if (!PyArg_ParseTuple(args, + "y*|O&:decompress", + &data, uint_converter, &max_length)) + goto exit; + return_value = zlib_Decompress_decompress_impl(self, &data, max_length); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(zlib_Compress_flush__doc__, +"flush(self, mode=Z_FINISH)\n" +"Return a bytes object containing any remaining compressed data.\n" +"\n" +" mode\n" +" One of the constants Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH.\n" +" If mode == Z_FINISH, the compressor object can no longer be\n" +" used after calling the flush() method. Otherwise, more data\n" +" can still be compressed."); + +#define ZLIB_COMPRESS_FLUSH_METHODDEF \ + {"flush", (PyCFunction)zlib_Compress_flush, METH_VARARGS, zlib_Compress_flush__doc__}, + +static PyObject * +zlib_Compress_flush_impl(compobject *self, int mode); + +static PyObject * +zlib_Compress_flush(compobject *self, PyObject *args) +{ + PyObject *return_value = NULL; + int mode = Z_FINISH; + + if (!PyArg_ParseTuple(args, + "|i:flush", + &mode)) + goto exit; + return_value = zlib_Compress_flush_impl(self, mode); + +exit: + return return_value; +} + +PyDoc_STRVAR(zlib_Compress_copy__doc__, +"copy(self)\n" +"Return a copy of the compression object."); + +#define ZLIB_COMPRESS_COPY_METHODDEF \ + {"copy", (PyCFunction)zlib_Compress_copy, METH_NOARGS, zlib_Compress_copy__doc__}, + +static PyObject * +zlib_Compress_copy_impl(compobject *self); + +static PyObject * +zlib_Compress_copy(compobject *self, PyObject *Py_UNUSED(ignored)) +{ + return zlib_Compress_copy_impl(self); +} + +PyDoc_STRVAR(zlib_Decompress_copy__doc__, +"copy(self)\n" +"Return a copy of the decompression object."); + +#define ZLIB_DECOMPRESS_COPY_METHODDEF \ + {"copy", (PyCFunction)zlib_Decompress_copy, METH_NOARGS, zlib_Decompress_copy__doc__}, + +static PyObject * +zlib_Decompress_copy_impl(compobject *self); + +static PyObject * +zlib_Decompress_copy(compobject *self, PyObject *Py_UNUSED(ignored)) +{ + return zlib_Decompress_copy_impl(self); +} + +PyDoc_STRVAR(zlib_Decompress_flush__doc__, +"flush(self, length=DEF_BUF_SIZE)\n" +"Return a bytes object containing any remaining decompressed data.\n" +"\n" +" length\n" +" the initial size of the output buffer."); + +#define ZLIB_DECOMPRESS_FLUSH_METHODDEF \ + {"flush", (PyCFunction)zlib_Decompress_flush, METH_VARARGS, zlib_Decompress_flush__doc__}, + +static PyObject * +zlib_Decompress_flush_impl(compobject *self, unsigned int length); + +static PyObject * +zlib_Decompress_flush(compobject *self, PyObject *args) +{ + PyObject *return_value = NULL; + unsigned int length = DEF_BUF_SIZE; + + if (!PyArg_ParseTuple(args, + "|O&:flush", + uint_converter, &length)) + goto exit; + return_value = zlib_Decompress_flush_impl(self, length); + +exit: + return return_value; +} + +PyDoc_STRVAR(zlib_adler32__doc__, +"adler32(module, data, value=1)\n" +"Compute an Adler-32 checksum of data.\n" +"\n" +" value\n" +" Starting value of the checksum.\n" +"\n" +"The returned checksum is an integer."); + +#define ZLIB_ADLER32_METHODDEF \ + {"adler32", (PyCFunction)zlib_adler32, METH_VARARGS, zlib_adler32__doc__}, + +static PyObject * +zlib_adler32_impl(PyModuleDef *module, Py_buffer *data, unsigned int value); + +static PyObject * +zlib_adler32(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + unsigned int value = 1; + + if (!PyArg_ParseTuple(args, + "y*|I:adler32", + &data, &value)) + goto exit; + return_value = zlib_adler32_impl(module, &data, value); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} + +PyDoc_STRVAR(zlib_crc32__doc__, +"crc32(module, data, value=0)\n" +"Compute a CRC-32 checksum of data.\n" +"\n" +" value\n" +" Starting value of the checksum.\n" +"\n" +"The returned checksum is an integer."); + +#define ZLIB_CRC32_METHODDEF \ + {"crc32", (PyCFunction)zlib_crc32, METH_VARARGS, zlib_crc32__doc__}, + +static PyObject * +zlib_crc32_impl(PyModuleDef *module, Py_buffer *data, unsigned int value); + +static PyObject * +zlib_crc32(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + unsigned int value = 0; + + if (!PyArg_ParseTuple(args, + "y*|I:crc32", + &data, &value)) + goto exit; + return_value = zlib_crc32_impl(module, &data, value); + +exit: + /* Cleanup for data */ + if (data.obj) + PyBuffer_Release(&data); + + return return_value; +} +/*[clinic end generated code: checksum=04f94bbaf2652717753e237e4021bf6c92ddffdd]*/ diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -28,10 +28,9 @@ #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif -#define DEF_WBITS MAX_WBITS -/* The output buffer will be increased in chunks of DEFAULTALLOC bytes. */ -#define DEFAULTALLOC (16*1024) +/* Initial buffer size. */ +#define DEF_BUF_SIZE (16*1024) static PyTypeObject Comptype; static PyTypeObject Decomptype; @@ -82,42 +81,13 @@ } /*[clinic input] +output preset file module zlib class zlib.Compress "compobject *" "&Comptype" class zlib.Decompress "compobject *" "&Decomptype" [clinic start generated code]*/ /*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ -PyDoc_STRVAR(compressobj__doc__, -"compressobj(level=-1, method=DEFLATED, wbits=15, memlevel=8,\n" -" strategy=Z_DEFAULT_STRATEGY[, zdict])\n" -" -- Return a compressor object.\n" -"\n" -"level is the compression level (an integer in the range 0-9; default is 6).\n" -"Higher compression levels are slower, but produce smaller results.\n" -"\n" -"method is the compression algorithm. If given, this must be DEFLATED.\n" -"\n" -"wbits is the base two logarithm of the window size (range: 8..15).\n" -"\n" -"memlevel controls the amount of memory used for internal compression state.\n" -"Valid values range from 1 to 9. Higher values result in higher memory usage,\n" -"faster compression, and smaller output.\n" -"\n" -"strategy is used to tune the compression algorithm. Possible values are\n" -"Z_DEFAULT_STRATEGY, Z_FILTERED, and Z_HUFFMAN_ONLY.\n" -"\n" -"zdict is the predefined compression dictionary - a sequence of bytes\n" -"containing subsequences that are likely to occur in the input data."); - -PyDoc_STRVAR(decompressobj__doc__, -"decompressobj([wbits[, zdict]]) -- Return a decompressor object.\n" -"\n" -"Optional arg wbits is the window buffer size.\n" -"\n" -"Optional arg zdict is the predefined compression dictionary. This must be\n" -"the same dictionary as used by the compressor that produced the input data."); - static compobject * newcompobject(PyTypeObject *type) { @@ -165,70 +135,20 @@ } /*[clinic input] +zlib.compress -zlib.compress bytes: Py_buffer Binary data to be compressed. - [ - level: int + level: int(c_default="Z_DEFAULT_COMPRESSION") = Z_DEFAULT_COMPRESSION Compression level, in 0-9. - ] / -Returns compressed string. - +Returns a bytes object containing compressed data. [clinic start generated code]*/ -PyDoc_STRVAR(zlib_compress__doc__, -"compress(module, bytes, [level])\n" -"Returns compressed string.\n" -"\n" -" bytes\n" -" Binary data to be compressed.\n" -" level\n" -" Compression level, in 0-9."); - -#define ZLIB_COMPRESS_METHODDEF \ - {"compress", (PyCFunction)zlib_compress, METH_VARARGS, zlib_compress__doc__}, - static PyObject * -zlib_compress_impl(PyModuleDef *module, Py_buffer *bytes, int group_right_1, int level); - -static PyObject * -zlib_compress(PyModuleDef *module, PyObject *args) -{ - PyObject *return_value = NULL; - Py_buffer bytes = {NULL, NULL}; - int group_right_1 = 0; - int level = 0; - - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "y*:compress", &bytes)) - goto exit; - break; - case 2: - if (!PyArg_ParseTuple(args, "y*i:compress", &bytes, &level)) - goto exit; - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "zlib.compress requires 1 to 2 arguments"); - goto exit; - } - return_value = zlib_compress_impl(module, &bytes, group_right_1, level); - -exit: - /* Cleanup for bytes */ - if (bytes.obj) - PyBuffer_Release(&bytes); - - return return_value; -} - -static PyObject * -zlib_compress_impl(PyModuleDef *module, Py_buffer *bytes, int group_right_1, int level) -/*[clinic end generated code: checksum=ce8d4c0a17ecd79c3ffcc032dcdf8ac6830ded1e]*/ +zlib_compress_impl(PyModuleDef *module, Py_buffer *bytes, int level) +/*[clinic end generated code: checksum=5d7dd4588788efd3516e5f4225050d6413632601]*/ { PyObject *ReturnVal = NULL; Byte *input, *output = NULL; @@ -236,9 +156,6 @@ int err; z_stream zst; - if (!group_right_1) - level = Z_DEFAULT_COMPRESSION; - if ((size_t)bytes->len > UINT_MAX) { PyErr_SetString(PyExc_OverflowError, "Size does not fit in an unsigned int"); @@ -312,6 +229,7 @@ class uint_converter(CConverter): type = 'unsigned int' converter = 'uint_converter' + c_ignored_default = "0" [python start generated code]*/ /*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ @@ -347,35 +265,38 @@ return 1; } -PyDoc_STRVAR(decompress__doc__, -"decompress(string[, wbits[, bufsize]]) -- Return decompressed string.\n" -"\n" -"Optional arg wbits is the window buffer size. Optional arg bufsize is\n" -"the initial output buffer size."); +/*[clinic input] +zlib.decompress + + data: Py_buffer + Compressed data. + wbits: int(c_default="MAX_WBITS") = MAX_WBITS + The window buffer size. + bufsize: uint(c_default="DEF_BUF_SIZE") = DEF_BUF_SIZE + The initial output buffer size. + / + +Returns a bytes object containing the uncompressed data. +[clinic start generated code]*/ static PyObject * -PyZlib_decompress(PyObject *self, PyObject *args) +zlib_decompress_impl(PyModuleDef *module, Py_buffer *data, int wbits, unsigned int bufsize) +/*[clinic end generated code: checksum=9e5464e72df9cb5fee73df662dbcaed867e01d32]*/ { PyObject *result_str = NULL; - Py_buffer pinput; Byte *input; unsigned int length; int err; - int wsize=DEF_WBITS; - unsigned int bufsize = DEFAULTALLOC, new_bufsize; + unsigned int new_bufsize; z_stream zst; - if (!PyArg_ParseTuple(args, "y*|iO&:decompress", - &pinput, &wsize, uint_converter, &bufsize)) - return NULL; - - if ((size_t)pinput.len > UINT_MAX) { + if ((size_t)data->len > UINT_MAX) { PyErr_SetString(PyExc_OverflowError, "Size does not fit in an unsigned int"); goto error; } - input = pinput.buf; - length = (unsigned int)pinput.len; + input = data->buf; + length = (unsigned int)data->len; if (bufsize == 0) bufsize = 1; @@ -391,7 +312,7 @@ zst.zfree = PyZlib_Free; zst.next_out = (Byte *)PyBytes_AS_STRING(result_str); zst.next_in = (Byte *)input; - err = inflateInit2(&zst, wsize); + err = inflateInit2(&zst, wbits); switch(err) { case(Z_OK): @@ -457,32 +378,45 @@ if (_PyBytes_Resize(&result_str, zst.total_out) < 0) goto error; - PyBuffer_Release(&pinput); return result_str; error: - PyBuffer_Release(&pinput); Py_XDECREF(result_str); return NULL; } +/*[clinic input] +zlib.compressobj + + level: int(c_default="Z_DEFAULT_COMPRESSION") = Z_DEFAULT_COMPRESSION + The compression level (an integer in the range 0-9; default is 6). + Higher compression levels are slower, but produce smaller results. + method: int(c_default="DEFLATED") = DEFLATED + The compression algorithm. If given, this must be DEFLATED. + wbits: int(c_default="MAX_WBITS") = MAX_WBITS + The base two logarithm of the window size (range: 8..15). + memLevel: int(c_default="DEF_MEM_LEVEL") = DEF_MEM_LEVEL + Controls the amount of memory used for internal compression state. + Valid values range from 1 to 9. Higher values result in higher memory + usage, faster compression, and smaller output. + strategy: int(c_default="Z_DEFAULT_STRATEGY") = Z_DEFAULT_STRATEGY + Used to tune the compression algorithm. Possible values are + Z_DEFAULT_STRATEGY, Z_FILTERED, and Z_HUFFMAN_ONLY. + zdict: Py_buffer = None + The predefined compression dictionary - a sequence of bytes + containing subsequences that are likely to occur in the input data. + +Return a compressor object. +[clinic start generated code]*/ + static PyObject * -PyZlib_compressobj(PyObject *selfptr, PyObject *args, PyObject *kwargs) +zlib_compressobj_impl(PyModuleDef *module, int level, int method, int wbits, int memLevel, int strategy, Py_buffer *zdict) +/*[clinic end generated code: checksum=89e5a6c1449caa9ed76f1baad066600e985151a9]*/ { compobject *self = NULL; - int level=Z_DEFAULT_COMPRESSION, method=DEFLATED; - int wbits=MAX_WBITS, memLevel=DEF_MEM_LEVEL, strategy=0, err; - Py_buffer zdict; - static char *kwlist[] = {"level", "method", "wbits", - "memLevel", "strategy", "zdict", NULL}; + int err; - zdict.buf = NULL; /* Sentinel, so we can tell whether zdict was supplied. */ - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iiiiiy*:compressobj", - kwlist, &level, &method, &wbits, - &memLevel, &strategy, &zdict)) - return NULL; - - if (zdict.buf != NULL && (size_t)zdict.len > UINT_MAX) { + if (zdict->buf != NULL && (size_t)zdict->len > UINT_MAX) { PyErr_SetString(PyExc_OverflowError, "zdict length does not fit in an unsigned int"); goto error; @@ -500,11 +434,11 @@ switch(err) { case (Z_OK): self->is_initialised = 1; - if (zdict.buf == NULL) { + if (zdict->buf == NULL) { goto success; } else { err = deflateSetDictionary(&self->zst, - zdict.buf, (unsigned int)zdict.len); + zdict->buf, (unsigned int)zdict->len); switch (err) { case (Z_OK): goto success; @@ -532,22 +466,28 @@ Py_XDECREF(self); self = NULL; success: - if (zdict.buf != NULL) - PyBuffer_Release(&zdict); return (PyObject*)self; } +/*[clinic input] +zlib.decompressobj + + wbits: int(c_default="MAX_WBITS") = MAX_WBITS + The window buffer size. + zdict: object(c_default="NULL") = b'' + The predefined compression dictionary. This must be the same + dictionary as used by the compressor that produced the input data. + +Return a decompressor object. +[clinic start generated code]*/ + static PyObject * -PyZlib_decompressobj(PyObject *selfptr, PyObject *args, PyObject *kwargs) +zlib_decompressobj_impl(PyModuleDef *module, int wbits, PyObject *zdict) +/*[clinic end generated code: checksum=8ccd583fbd631798566d415933cd44440c8a74b5]*/ { - static char *kwlist[] = {"wbits", "zdict", NULL}; - int wbits=DEF_WBITS, err; + int err; compobject *self; - PyObject *zdict=NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iO:decompressobj", - kwlist, &wbits, &zdict)) - return NULL; if (zdict != NULL && !PyObject_CheckBuffer(zdict)) { PyErr_SetString(PyExc_TypeError, "zdict argument must support the buffer protocol"); @@ -615,37 +555,41 @@ Dealloc(self); } -PyDoc_STRVAR(comp_compress__doc__, -"compress(data) -- Return a string containing data compressed.\n" -"\n" -"After calling this function, some of the input data may still\n" -"be stored in internal buffers for later processing.\n" -"Call the flush() method to clear these buffers."); +/*[clinic input] +zlib.Compress.compress + data: Py_buffer + Binary data to be compressed. + / + +Returns a bytes object containing compressed data. + +After calling this function, some of the input data may still +be stored in internal buffers for later processing. +Call the flush() method to clear these buffers. +[clinic start generated code]*/ static PyObject * -PyZlib_objcompress(compobject *self, PyObject *args) +zlib_Compress_compress_impl(compobject *self, Py_buffer *data) +/*[clinic end generated code: checksum=5d5cd791cbc6a7f4b6de4ec12c085c88d4d3e31c]*/ { int err; unsigned int inplen; - unsigned int length = DEFAULTALLOC, new_length; - PyObject *RetVal = NULL; - Py_buffer pinput; + unsigned int length = DEF_BUF_SIZE, new_length; + PyObject *RetVal; Byte *input; unsigned long start_total_out; - if (!PyArg_ParseTuple(args, "y*:compress", &pinput)) - return NULL; - if ((size_t)pinput.len > UINT_MAX) { + if ((size_t)data->len > UINT_MAX) { PyErr_SetString(PyExc_OverflowError, "Size does not fit in an unsigned int"); - goto error_outer; + return NULL; } - input = pinput.buf; - inplen = (unsigned int)pinput.len; + input = data->buf; + inplen = (unsigned int)data->len; if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) - goto error_outer; + return NULL; ENTER_ZLIB(self); @@ -668,7 +612,7 @@ new_length = UINT_MAX; if (_PyBytes_Resize(&RetVal, new_length) < 0) { Py_CLEAR(RetVal); - goto error; + goto done; } self->zst.next_out = (unsigned char *)PyBytes_AS_STRING(RetVal) + length; @@ -686,18 +630,15 @@ if (err != Z_OK && err != Z_BUF_ERROR) { zlib_error(self->zst, err, "while compressing data"); - Py_DECREF(RetVal); - RetVal = NULL; - goto error; + Py_CLEAR(RetVal); + goto done; } if (_PyBytes_Resize(&RetVal, self->zst.total_out - start_total_out) < 0) { Py_CLEAR(RetVal); } - error: + done: LEAVE_ZLIB(self); - error_outer: - PyBuffer_Release(&pinput); return RetVal; } @@ -745,7 +686,6 @@ } /*[clinic input] - zlib.Decompress.decompress data: Py_buffer @@ -756,61 +696,19 @@ the unconsumed_tail attribute. / -Return a string containing the decompressed version of the data. +Return a bytes object containing the decompressed version of the data. After calling this function, some of the input data may still be stored in internal buffers for later processing. Call the flush() method to clear these buffers. [clinic start generated code]*/ -PyDoc_STRVAR(zlib_Decompress_decompress__doc__, -"decompress(self, data, max_length=0)\n" -"Return a string containing the decompressed version of the data.\n" -"\n" -" data\n" -" The binary data to decompress.\n" -" max_length\n" -" The maximum allowable length of the decompressed data.\n" -" Unconsumed input data will be stored in\n" -" the unconsumed_tail attribute.\n" -"\n" -"After calling this function, some of the input data may still be stored in\n" -"internal buffers for later processing.\n" -"Call the flush() method to clear these buffers."); - -#define ZLIB_DECOMPRESS_DECOMPRESS_METHODDEF \ - {"decompress", (PyCFunction)zlib_Decompress_decompress, METH_VARARGS, zlib_Decompress_decompress__doc__}, - -static PyObject * -zlib_Decompress_decompress_impl(compobject *self, Py_buffer *data, unsigned int max_length); - -static PyObject * -zlib_Decompress_decompress(compobject *self, PyObject *args) -{ - PyObject *return_value = NULL; - Py_buffer data = {NULL, NULL}; - unsigned int max_length = 0; - - if (!PyArg_ParseTuple(args, - "y*|O&:decompress", - &data, uint_converter, &max_length)) - goto exit; - return_value = zlib_Decompress_decompress_impl(self, &data, max_length); - -exit: - /* Cleanup for data */ - if (data.obj) - PyBuffer_Release(&data); - - return return_value; -} - static PyObject * zlib_Decompress_decompress_impl(compobject *self, Py_buffer *data, unsigned int max_length) -/*[clinic end generated code: checksum=b7fd2e3b23430f57f5a84817189575bc46464901]*/ +/*[clinic end generated code: checksum=755cccc9087bfe55486b7e15fa7e2ab60b4c86d6]*/ { int err; - unsigned int old_length, length = DEFAULTALLOC; + unsigned int old_length, length = DEF_BUF_SIZE; PyObject *RetVal = NULL; unsigned long start_total_out; @@ -927,29 +825,31 @@ return RetVal; } -PyDoc_STRVAR(comp_flush__doc__, -"flush( [mode] ) -- Return a string containing any remaining compressed data.\n" -"\n" -"mode can be one of the constants Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH; the\n" -"default value used when mode is not specified is Z_FINISH.\n" -"If mode == Z_FINISH, the compressor object can no longer be used after\n" -"calling the flush() method. Otherwise, more data can still be compressed."); +/*[clinic input] +zlib.Compress.flush + + mode: int(c_default="Z_FINISH") = Z_FINISH + One of the constants Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH. + If mode == Z_FINISH, the compressor object can no longer be + used after calling the flush() method. Otherwise, more data + can still be compressed. + / + +Return a bytes object containing any remaining compressed data. +[clinic start generated code]*/ static PyObject * -PyZlib_flush(compobject *self, PyObject *args) +zlib_Compress_flush_impl(compobject *self, int mode) +/*[clinic end generated code: checksum=a203f4cefc9de727aa1d2ea39d11c0a16c32041a]*/ { int err; - unsigned int length = DEFAULTALLOC, new_length; + unsigned int length = DEF_BUF_SIZE, new_length; PyObject *RetVal; - int flushmode = Z_FINISH; unsigned long start_total_out; - if (!PyArg_ParseTuple(args, "|i:flush", &flushmode)) - return NULL; - /* Flushing with Z_NO_FLUSH is a no-op, so there's no point in doing any work at all; just return an empty string. */ - if (flushmode == Z_NO_FLUSH) { + if (mode == Z_NO_FLUSH) { return PyBytes_FromStringAndSize(NULL, 0); } @@ -964,7 +864,7 @@ self->zst.next_out = (unsigned char *)PyBytes_AS_STRING(RetVal); Py_BEGIN_ALLOW_THREADS - err = deflate(&(self->zst), flushmode); + err = deflate(&(self->zst), mode); Py_END_ALLOW_THREADS /* while Z_OK and the output buffer is full, there might be more output, @@ -984,14 +884,14 @@ length = new_length; Py_BEGIN_ALLOW_THREADS - err = deflate(&(self->zst), flushmode); + err = deflate(&(self->zst), mode); Py_END_ALLOW_THREADS } - /* If flushmode is Z_FINISH, we also have to call deflateEnd() to free + /* If mode is Z_FINISH, we also have to call deflateEnd() to free various data structures. Note we should only get Z_STREAM_END when - flushmode is Z_FINISH, but checking both for safety*/ - if (err == Z_STREAM_END && flushmode == Z_FINISH) { + mode is Z_FINISH, but checking both for safety*/ + if (err == Z_STREAM_END && mode == Z_FINISH) { err = deflateEnd(&(self->zst)); if (err != Z_OK) { zlib_error(self->zst, err, "while finishing compression"); @@ -1031,25 +931,9 @@ Return a copy of the compression object. [clinic start generated code]*/ -PyDoc_STRVAR(zlib_Compress_copy__doc__, -"copy(self)\n" -"Return a copy of the compression object."); - -#define ZLIB_COMPRESS_COPY_METHODDEF \ - {"copy", (PyCFunction)zlib_Compress_copy, METH_NOARGS, zlib_Compress_copy__doc__}, - -static PyObject * -zlib_Compress_copy_impl(compobject *self); - -static PyObject * -zlib_Compress_copy(compobject *self, PyObject *Py_UNUSED(ignored)) -{ - return zlib_Compress_copy_impl(self); -} - static PyObject * zlib_Compress_copy_impl(compobject *self) -/*[clinic end generated code: checksum=7aa841ad51297eb83250f511a76872e88fdc737e]*/ +/*[clinic end generated code: checksum=5144aa153c21e805afa5c19e5b48cf8e6480b5da]*/ { compobject *retval = NULL; int err; @@ -1099,11 +983,15 @@ return NULL; } -PyDoc_STRVAR(decomp_copy__doc__, -"copy() -- Return a copy of the decompression object."); +/*[clinic input] +zlib.Decompress.copy + +Return a copy of the decompression object. +[clinic start generated code]*/ static PyObject * -PyZlib_uncopy(compobject *self) +zlib_Decompress_copy_impl(compobject *self) +/*[clinic end generated code: checksum=02a883a2a510c8ccfeef3f89e317a275bfe8c094]*/ { compobject *retval = NULL; int err; @@ -1155,24 +1043,26 @@ } #endif -PyDoc_STRVAR(decomp_flush__doc__, -"flush( [length] ) -- Return a string containing any remaining\n" -"decompressed data. length, if given, is the initial size of the\n" -"output buffer.\n" -"\n" -"The decompressor object can no longer be used after this call."); +/*[clinic input] +zlib.Decompress.flush + + length: uint(c_default="DEF_BUF_SIZE") = DEF_BUF_SIZE + the initial size of the output buffer. + / + +Return a bytes object containing any remaining decompressed data. +[clinic start generated code]*/ static PyObject * -PyZlib_unflush(compobject *self, PyObject *args) +zlib_Decompress_flush_impl(compobject *self, unsigned int length) +/*[clinic end generated code: checksum=db6fb753ab698e22afe3957c9da9e5e77f4bfc08]*/ { int err; - unsigned int length = DEFAULTALLOC, new_length; + unsigned int new_length; PyObject * retval = NULL; unsigned long start_total_out; Py_ssize_t size; - if (!PyArg_ParseTuple(args, "|O&:flush", uint_converter, &length)) - return NULL; if (length == 0) { PyErr_SetString(PyExc_ValueError, "length must be greater than zero"); return NULL; @@ -1248,12 +1138,12 @@ return retval; } +#include "clinic/zlibmodule.c.h" + static PyMethodDef comp_methods[] = { - {"compress", (binaryfunc)PyZlib_objcompress, METH_VARARGS, - comp_compress__doc__}, - {"flush", (binaryfunc)PyZlib_flush, METH_VARARGS, - comp_flush__doc__}, + ZLIB_COMPRESS_COMPRESS_METHODDEF + ZLIB_COMPRESS_FLUSH_METHODDEF #ifdef HAVE_ZLIB_COPY ZLIB_COMPRESS_COPY_METHODDEF #endif @@ -1263,11 +1153,9 @@ static PyMethodDef Decomp_methods[] = { ZLIB_DECOMPRESS_DECOMPRESS_METHODDEF - {"flush", (binaryfunc)PyZlib_unflush, METH_VARARGS, - decomp_flush__doc__}, + ZLIB_DECOMPRESS_FLUSH_METHODDEF #ifdef HAVE_ZLIB_COPY - {"copy", (PyCFunction)PyZlib_uncopy, METH_NOARGS, - decomp_copy__doc__}, + ZLIB_DECOMPRESS_COPY_METHODDEF #endif {NULL, NULL} }; @@ -1280,95 +1168,95 @@ {NULL}, }; -PyDoc_STRVAR(adler32__doc__, -"adler32(string[, start]) -- Compute an Adler-32 checksum of string.\n" -"\n" -"An optional starting value can be specified. The returned checksum is\n" -"an integer."); +/*[clinic input] +zlib.adler32 + + data: Py_buffer + value: unsigned_int(bitwise=True) = 1 + Starting value of the checksum. + / + +Compute an Adler-32 checksum of data. + +The returned checksum is an integer. +[clinic start generated code]*/ static PyObject * -PyZlib_adler32(PyObject *self, PyObject *args) +zlib_adler32_impl(PyModuleDef *module, Py_buffer *data, unsigned int value) +/*[clinic end generated code: checksum=51d6d75ee655c78af8c968fdb4c11d97e62c67d5]*/ { - unsigned int adler32val = 1; /* adler32(0L, Z_NULL, 0) */ - Py_buffer pbuf; - - if (!PyArg_ParseTuple(args, "y*|I:adler32", &pbuf, &adler32val)) - return NULL; /* Releasing the GIL for very small buffers is inefficient and may lower performance */ - if (pbuf.len > 1024*5) { - unsigned char *buf = pbuf.buf; - Py_ssize_t len = pbuf.len; + if (data->len > 1024*5) { + unsigned char *buf = data->buf; + Py_ssize_t len = data->len; Py_BEGIN_ALLOW_THREADS /* Avoid truncation of length for very large buffers. adler32() takes length as an unsigned int, which may be narrower than Py_ssize_t. */ while ((size_t)len > UINT_MAX) { - adler32val = adler32(adler32val, buf, UINT_MAX); + value = adler32(value, buf, UINT_MAX); buf += (size_t) UINT_MAX; len -= (size_t) UINT_MAX; } - adler32val = adler32(adler32val, buf, (unsigned int)len); + value = adler32(value, buf, (unsigned int)len); Py_END_ALLOW_THREADS } else { - adler32val = adler32(adler32val, pbuf.buf, (unsigned int)pbuf.len); + value = adler32(value, data->buf, (unsigned int)data->len); } - PyBuffer_Release(&pbuf); - return PyLong_FromUnsignedLong(adler32val & 0xffffffffU); + return PyLong_FromUnsignedLong(value & 0xffffffffU); } -PyDoc_STRVAR(crc32__doc__, -"crc32(string[, start]) -- Compute a CRC-32 checksum of string.\n" -"\n" -"An optional starting value can be specified. The returned checksum is\n" -"an integer."); +/*[clinic input] +zlib.crc32 + + data: Py_buffer + value: unsigned_int(bitwise=True) = 0 + Starting value of the checksum. + / + +Compute a CRC-32 checksum of data. + +The returned checksum is an integer. +[clinic start generated code]*/ static PyObject * -PyZlib_crc32(PyObject *self, PyObject *args) +zlib_crc32_impl(PyModuleDef *module, Py_buffer *data, unsigned int value) +/*[clinic end generated code: checksum=c1e986e74fe7b62369998a71a81ebeb9b73e8d4c]*/ { - unsigned int crc32val = 0; /* crc32(0L, Z_NULL, 0) */ - Py_buffer pbuf; int signed_val; - if (!PyArg_ParseTuple(args, "y*|I:crc32", &pbuf, &crc32val)) - return NULL; /* Releasing the GIL for very small buffers is inefficient and may lower performance */ - if (pbuf.len > 1024*5) { - unsigned char *buf = pbuf.buf; - Py_ssize_t len = pbuf.len; + if (data->len > 1024*5) { + unsigned char *buf = data->buf; + Py_ssize_t len = data->len; Py_BEGIN_ALLOW_THREADS /* Avoid truncation of length for very large buffers. crc32() takes length as an unsigned int, which may be narrower than Py_ssize_t. */ while ((size_t)len > UINT_MAX) { - crc32val = crc32(crc32val, buf, UINT_MAX); + value = crc32(value, buf, UINT_MAX); buf += (size_t) UINT_MAX; len -= (size_t) UINT_MAX; } - signed_val = crc32(crc32val, buf, (unsigned int)len); + signed_val = crc32(value, buf, (unsigned int)len); Py_END_ALLOW_THREADS } else { - signed_val = crc32(crc32val, pbuf.buf, (unsigned int)pbuf.len); + signed_val = crc32(value, data->buf, (unsigned int)data->len); } - PyBuffer_Release(&pbuf); return PyLong_FromUnsignedLong(signed_val & 0xffffffffU); } static PyMethodDef zlib_methods[] = { - {"adler32", (PyCFunction)PyZlib_adler32, METH_VARARGS, - adler32__doc__}, + ZLIB_ADLER32_METHODDEF ZLIB_COMPRESS_METHODDEF - {"compressobj", (PyCFunction)PyZlib_compressobj, METH_VARARGS|METH_KEYWORDS, - compressobj__doc__}, - {"crc32", (PyCFunction)PyZlib_crc32, METH_VARARGS, - crc32__doc__}, - {"decompress", (PyCFunction)PyZlib_decompress, METH_VARARGS, - decompress__doc__}, - {"decompressobj", (PyCFunction)PyZlib_decompressobj, METH_VARARGS|METH_KEYWORDS, - decompressobj__doc__}, + ZLIB_COMPRESSOBJ_METHODDEF + ZLIB_CRC32_METHODDEF + ZLIB_DECOMPRESS_METHODDEF + ZLIB_DECOMPRESSOBJ_METHODDEF {NULL, NULL} }; @@ -1482,6 +1370,7 @@ PyModule_AddIntMacro(m, MAX_WBITS); PyModule_AddIntMacro(m, DEFLATED); PyModule_AddIntMacro(m, DEF_MEM_LEVEL); + PyModule_AddIntMacro(m, DEF_BUF_SIZE); PyModule_AddIntMacro(m, Z_BEST_SPEED); PyModule_AddIntMacro(m, Z_BEST_COMPRESSION); PyModule_AddIntMacro(m, Z_DEFAULT_COMPRESSION); diff --git a/Objects/exceptions.c b/Objects/exceptions.c --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -2689,8 +2689,11 @@ * types as well, but that's quite a bit trickier due to the extra * state potentially stored on OSError instances. */ - - Py_XDECREF(tb); + /* Ensure the traceback is set correctly on the existing exception */ + if (tb != NULL) { + PyException_SetTraceback(val, tb); + Py_DECREF(tb); + } #ifdef HAVE_STDARG_PROTOTYPES va_start(vargs, format); -- Repository URL: http://hg.python.org/cpython From ncoghlan at gmail.com Mon Jan 27 07:45:53 2014 From: ncoghlan at gmail.com (Nick Coghlan) Date: Mon, 27 Jan 2014 16:45:53 +1000 Subject: [Python-checkins] peps: Incorporate PEP 462 feedback In-Reply-To: <52E5EE6F.8010300@udel.edu> References: <3fCGVH220wz7Lkf@mail.python.org> <52E5EE6F.8010300@udel.edu> Message-ID: On 27 January 2014 15:28, Terry Reedy wrote: > On 1/26/2014 10:22 PM, nick.coghlan wrote: >> >> +Terry Reedy has suggested doing an initial filter which specifically >> looks >> +for approved documentation-only patches (~700 of the 4000+ open CPython >> +issues are pure documentation updates). This approach would avoid several >> +of the issues related to flaky tests and cross-platform testing, while >> +still allowing the rest of the automation flows to be worked out (such as >> +how to push a patch into the merge queue). >> + >> +The one downside to this approach is that Zuul wouldn't have complete >> +control of the merge process as it usually expects, so there would >> +potentially be additional coordination needed around that. > > > An essential part of my idea is that Zuul *would* have complete control > while pushing doc patches to avoid the otherwise inevitable push races. > Initially, this would be for a part of every day. While it has control, I > would expect it to push doc patches at intervals of perhaps a minute, or > even more rapidly with parallel testing. (Since doc patch rarely interfere > and would be expected to apply after pre-testing, little speculative testing > would need to be tossed.) "Exclusive control some of the time" is not the same thing as "exclusive control". It's not an impossible idea, but certainly not the way Zuul is currently designed to work :) >> +It may be worth keeping this approach as a fallback option if the initial >> +deployment proves to have more trouble with test reliability than is >> +anticipated. > > > I think a doc queue should be a permanent part of the system. There would > always be doc-only patches -- and I suspect even more than now. One of the > types of jobs on the main queue could be a periodic 'push all pending doc > patches' job. I would then think we should try splitting code + doc patches > into a code patch, pushed first, and a doc patch, added to the doc queue if > the code patch succeeded. That seems like added complexity for little gain - note that we can make the *test runner* smart about how it handles doc-only patches, by just checking the docs build and skipping the test run. Cheers, Nick. -- Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia From python-checkins at python.org Mon Jan 27 08:27:05 2014 From: python-checkins at python.org (georg.brandl) Date: Mon, 27 Jan 2014 08:27:05 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?release=3A_hg_touch=3A_use_new_-b_=28?= =?utf-8?q?basedir=29_option?= Message-ID: <3fCMwT5ssfz7Lmg@mail.python.org> http://hg.python.org/release/rev/83a19b262569 changeset: 70:83a19b262569 user: Georg Brandl date: Mon Jan 27 08:27:42 2014 +0100 summary: hg touch: use new -b (basedir) option files: release.py | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/release.py b/release.py --- a/release.py +++ b/release.py @@ -258,7 +258,9 @@ if os.path.isfile('.hgtouch'): # Use "hg touch" if available run_cmd(['hg', '-v', 'touch', '--config', - 'extensions.touch=Tools/hg/hgtouch.py']) + 'extensions.touch=Tools/hg/hgtouch.py', + # need to give basedir path relative to repo root + '-b', os.path.join(tag.text, archivename)]) else: touchables = ['Include/Python-ast.h', 'Python/Python-ast.c'] if os.path.exists('Python/opcode_targets.h'): -- Repository URL: http://hg.python.org/release From python-checkins at python.org Mon Jan 27 08:32:06 2014 From: python-checkins at python.org (georg.brandl) Date: Mon, 27 Jan 2014 08:32:06 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2319966=3A_allow_h?= =?utf-8?q?gtouch_to_operate_on_a_base_dir_that_is_!=3D_the_repo_root=2E?= Message-ID: <3fCN2G5gnyz7Llf@mail.python.org> http://hg.python.org/cpython/rev/0279445c05d5 changeset: 88763:0279445c05d5 user: Georg Brandl date: Mon Jan 27 08:22:49 2014 +0100 summary: Closes #19966: allow hgtouch to operate on a base dir that is != the repo root. files: Tools/hg/hgtouch.py | 35 +++++++++++++++++++++----------- 1 files changed, 23 insertions(+), 12 deletions(-) diff --git a/Tools/hg/hgtouch.py b/Tools/hg/hgtouch.py --- a/Tools/hg/hgtouch.py +++ b/Tools/hg/hgtouch.py @@ -36,12 +36,16 @@ result[o] = inputs return result -def check_rule(ui, repo, modified, output, inputs): +def check_rule(ui, repo, modified, basedir, output, inputs): """Verify that the output is newer than any of the inputs. Return (status, stamp), where status is True if the update succeeded, and stamp is the newest time stamp assigned to any file (might be in - the future).""" - f_output = repo.wjoin(output) + the future). + + If basedir is nonempty, it gives a directory in which the tree is to + be checked. + """ + f_output = repo.wjoin(os.path.join(basedir, output)) try: o_time = os.stat(f_output).st_mtime except OSError: @@ -51,7 +55,7 @@ backdate = None backdate_source = None for i in inputs: - f_i = repo.wjoin(i) + f_i = repo.wjoin(os.path.join(basedir, i)) try: i_time = os.stat(f_i).st_mtime except OSError: @@ -79,8 +83,14 @@ # Nothing to update return True, 0 -def do_touch(ui, repo): - modified = repo.status()[0] +def do_touch(ui, repo, basedir): + if basedir: + if not os.path.isdir(repo.wjoin(basedir)): + ui.warn("Abort: basedir %r does not exist\n" % basedir) + return + modified = [] + else: + modified = repo.status()[0] dependencies = parse_config(repo) success = True tstamp = 0 # newest time stamp assigned @@ -93,8 +103,8 @@ if i in dependencies: hold_back[output] = inputs continue - _success, _tstamp = check_rule(ui, repo, modified, output, inputs) - sucess = success and _success + _success, _tstamp = check_rule(ui, repo, modified, basedir, output, inputs) + success = success and _success tstamp = max(tstamp, _tstamp) # put back held back rules dependencies.update(hold_back) @@ -109,11 +119,12 @@ return False return success -def touch(ui, repo): +def touch(ui, repo, basedir): "touch generated files that are older than their sources after an update." - do_touch(ui, repo) + do_touch(ui, repo, basedir) cmdtable = { - "touch": (touch, [], - "touch generated files according to the .hgtouch configuration") + "touch": (touch, + [('b', 'basedir', '', 'base dir of the tree to apply touching', 'BASEDIR')], + "hg touch [-b BASEDIR]") } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 08:41:27 2014 From: python-checkins at python.org (georg.brandl) Date: Mon, 27 Jan 2014 08:41:27 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_schedule_update_for_3=2E3=2E4?= =?utf-8?b?LzMuMy41?= Message-ID: <3fCNF33ysqz7LnN@mail.python.org> http://hg.python.org/peps/rev/e814f9b29a5e changeset: 5360:e814f9b29a5e user: Georg Brandl date: Mon Jan 27 08:42:07 2014 +0100 summary: schedule update for 3.3.4/3.3.5 files: pep-0398.txt | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 deletions(-) diff --git a/pep-0398.txt b/pep-0398.txt --- a/pep-0398.txt +++ b/pep-0398.txt @@ -85,6 +85,21 @@ - 3.3.3 candidate 2: November 9, 2013 - 3.3.3 final: November 16, 2013 +3.3.4 schedule +-------------- + +- 3.3.4 candidate 1: January 26, 2014 +- 3.3.4 final: February 10, 2014 + +3.3.5 schedule +-------------- + +Python 3.3.5 will be the last regular maintenance release, released at some +point after 3.4.0 final (see :pep:`429`), before 3.3 goes into security-fix +only mode. + +- 3.3.5 candidate 1: around May 2014 +- 3.3.5 final: two weeks later Features for 3.3 ================ -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jan 27 08:48:30 2014 From: python-checkins at python.org (georg.brandl) Date: Mon, 27 Jan 2014 08:48:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_small_date_fix?= Message-ID: <3fCNPB4SCbz7Ln8@mail.python.org> http://hg.python.org/peps/rev/faab28f44e78 changeset: 5361:faab28f44e78 user: Georg Brandl date: Mon Jan 27 08:49:10 2014 +0100 summary: small date fix files: pep-0398.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0398.txt b/pep-0398.txt --- a/pep-0398.txt +++ b/pep-0398.txt @@ -89,7 +89,7 @@ -------------- - 3.3.4 candidate 1: January 26, 2014 -- 3.3.4 final: February 10, 2014 +- 3.3.4 final: February 9, 2014 3.3.5 schedule -------------- -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon Jan 27 09:07:54 2014 From: python-checkins at python.org (christian.heimes) Date: Mon, 27 Jan 2014 09:07:54 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_I_forgot_to_add_a_Misc/NEW?= =?utf-8?q?S_entry_for_issue_=2320394?= Message-ID: <3fCNqZ3Fc4z7Ljb@mail.python.org> http://hg.python.org/cpython/rev/0a406b6fe61f changeset: 88764:0a406b6fe61f user: Christian Heimes date: Mon Jan 27 09:07:45 2014 +0100 summary: I forgot to add a Misc/NEWS entry for issue #20394 files: Misc/NEWS | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -48,6 +48,8 @@ Library ------- +- Issue #20394: Silence Coverity warning in audioop module. + - Issue #20367: Fix behavior of concurrent.futures.as_completed() for duplicate arguments. Patch by Glenn Langford. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 09:13:52 2014 From: python-checkins at python.org (victor.stinner) Date: Mon, 27 Jan 2014 09:13:52 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMzY3?= =?utf-8?q?=3A_Fix_behavior_of_concurrent=2Efutures=2Eas=5Fcompleted=28=29?= =?utf-8?q?_for_duplicate?= Message-ID: <3fCNyS6pQ1z7LkC@mail.python.org> http://hg.python.org/cpython/rev/791b69f9f96d changeset: 88765:791b69f9f96d branch: 3.3 parent: 88756:e02da391741f user: Victor Stinner date: Mon Jan 27 09:11:48 2014 +0100 summary: Issue #20367: Fix behavior of concurrent.futures.as_completed() for duplicate arguments. Patch by Glenn Langford. files: Doc/library/concurrent.futures.rst | 3 ++- Lib/concurrent/futures/_base.py | 6 ++++-- Lib/test/test_concurrent_futures.py | 7 +++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ 5 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -368,7 +368,8 @@ Returns an iterator over the :class:`Future` instances (possibly created by different :class:`Executor` instances) given by *fs* that yields futures as - they complete (finished or were cancelled). Any futures that completed + they complete (finished or were cancelled). Any futures given by *fs* that + are duplicated will be returned once. Any futures that completed before :func:`as_completed` is called will be yielded first. The returned iterator raises a :exc:`TimeoutError` if :meth:`~iterator.__next__` is called and the result isn't available after *timeout* seconds from the diff --git a/Lib/concurrent/futures/_base.py b/Lib/concurrent/futures/_base.py --- a/Lib/concurrent/futures/_base.py +++ b/Lib/concurrent/futures/_base.py @@ -181,7 +181,8 @@ Returns: An iterator that yields the given Futures as they complete (finished or - cancelled). + cancelled). If any given Futures are duplicated, they will be returned + once. Raises: TimeoutError: If the entire result iterator could not be generated @@ -190,11 +191,12 @@ if timeout is not None: end_time = timeout + time.time() + fs = set(fs) with _AcquireFutures(fs): finished = set( f for f in fs if f._state in [CANCELLED_AND_NOTIFIED, FINISHED]) - pending = set(fs) - finished + pending = fs - finished waiter = _create_and_install_waiters(fs, _AS_COMPLETED) try: diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -344,6 +344,13 @@ SUCCESSFUL_FUTURE]), completed_futures) + def test_duplicate_futures(self): + # Issue 20367. Duplicate futures should not raise exceptions or give + # duplicate responses. + future1 = self.executor.submit(time.sleep, 2) + completed = [f for f in futures.as_completed([future1,future1])] + self.assertEqual(len(completed), 1) + class ThreadPoolAsCompletedTests(ThreadPoolMixin, AsCompletedTests, unittest.TestCase): pass diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -703,6 +703,7 @@ Torsten Landschoff ?ukasz Langa Tino Lange +Glenn Langford Andrew Langmead Detlef Lannert Soren Larsen diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -50,6 +50,9 @@ Library ------- +- Issue #20367: Fix behavior of concurrent.futures.as_completed() for + duplicate arguments. Patch by Glenn Langford. + - Issue #8260: The read(), readline() and readlines() methods of codecs.StreamReader returned incomplete data when were called after readline() or read(size). Based on patch by Amaury Forgeot d'Arc. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 09:13:54 2014 From: python-checkins at python.org (victor.stinner) Date: Mon, 27 Jan 2014 09:13:54 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Null_merge_3=2E3_=28patch_already_applied_in_Python_3=2E?= =?utf-8?q?4=29?= Message-ID: <3fCNyV1B3Qz7LkX@mail.python.org> http://hg.python.org/cpython/rev/b3dd6fc2971c changeset: 88766:b3dd6fc2971c parent: 88764:0a406b6fe61f parent: 88765:791b69f9f96d user: Victor Stinner date: Mon Jan 27 09:13:38 2014 +0100 summary: Null merge 3.3 (patch already applied in Python 3.4) files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 09:15:29 2014 From: python-checkins at python.org (gregory.p.smith) Date: Mon, 27 Jan 2014 09:15:29 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE5MDgx?= =?utf-8?q?=3A_Remove_the_zipimporter=2Efiles_reference_as_the_zip_TOC?= Message-ID: <3fCP0K00rzzSW4@mail.python.org> http://hg.python.org/cpython/rev/323cb02abfc6 changeset: 88767:323cb02abfc6 branch: 2.7 parent: 88753:3d343dfe6269 user: Gregory P. Smith date: Mon Jan 27 00:15:10 2014 -0800 summary: Issue #19081: Remove the zipimporter.files reference as the zip TOC caches are module global in the zip_directory_cache. When it is updated due to a changed zip file, all zipimporter instances need to see the same updates TOC cache. This fixes the bug for the overlooked submodule import case from the earlier round of changes. Includes tests that would fail otherwise. It also refactors zipimporter_init in the process to make it a bit easier to read and understand. Less reuse of the same variable for multiple purposes and the local path buffer is malloc'ed instead of consuming a large MAXPATHLEN+2 chunk stack space. files: Lib/test/test_zipimport.py | 121 ++++++++++++++++-- Modules/zipimport.c | 152 +++++++++++++++--------- 2 files changed, 200 insertions(+), 73 deletions(-) diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py --- a/Lib/test/test_zipimport.py +++ b/Lib/test/test_zipimport.py @@ -395,59 +395,144 @@ def setUp(self): zipimport._zip_directory_cache.clear() zipimport._zip_stat_cache.clear() + # save sys.modules so we can unimport everything done by our tests. + self._sys_modules_orig = dict(sys.modules) ImportHooksBaseTestCase.setUp(self) def tearDown(self): ImportHooksBaseTestCase.tearDown(self) + # The closest we can come to un-importing our zipped up test modules. + sys.modules.clear() + sys.modules.update(self._sys_modules_orig) if os.path.exists(TEMP_ZIP): os.remove(TEMP_ZIP) - def testZipFileChangesAfterFirstImport(self): - """Alter the zip file after caching its index and try an import.""" + def setUpZipFileModuleAndTestImports(self): + # Create a .zip file to test with + self.zipfile_path = TEMP_ZIP packdir = TESTPACK + os.sep files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc), packdir + TESTMOD + ".py": (NOW, "test_value = 38\n"), "ziptest_a.py": (NOW, "test_value = 23\n"), "ziptest_b.py": (NOW, "test_value = 42\n"), "ziptest_c.py": (NOW, "test_value = 1337\n")} - zipfile_path = TEMP_ZIP - _write_zip_package(zipfile_path, files) - self.assertTrue(os.path.exists(zipfile_path)) - sys.path.insert(0, zipfile_path) + _write_zip_package(self.zipfile_path, files) + self.assertTrue(os.path.exists(self.zipfile_path)) + sys.path.insert(0, self.zipfile_path) + + self.testpack_testmod = TESTPACK + "." + TESTMOD + + with io.open(self.zipfile_path, "rb") as orig_zip_file: + self.orig_zip_file_contents = orig_zip_file.read() # Import something out of the zipfile and confirm it is correct. - testmod = __import__(TESTPACK + "." + TESTMOD, + testmod = __import__(self.testpack_testmod, globals(), locals(), ["__dummy__"]) self.assertEqual(testmod.test_value, 38) + del sys.modules[TESTPACK] + del sys.modules[self.testpack_testmod] + # Import something else out of the zipfile and confirm it is correct. ziptest_b = __import__("ziptest_b", globals(), locals(), ["test_value"]) self.assertEqual(ziptest_b.test_value, 42) + del sys.modules["ziptest_b"] - # Truncate and fill the zip file with non-zip garbage. - with io.open(zipfile_path, "rb") as orig_zip_file: - orig_zip_file_contents = orig_zip_file.read() - with io.open(zipfile_path, "wb") as byebye_valid_zip_file: + def truncateAndFillZipWithNonZipGarbage(self): + with io.open(self.zipfile_path, "wb") as byebye_valid_zip_file: byebye_valid_zip_file.write(b"Tear down this wall!\n"*1987) + + def restoreZipFileWithDifferentHeaderOffsets(self): + """Make it a valid zipfile with some garbage at the start.""" + # This alters all of the caches offsets within the file. + with io.open(self.zipfile_path, "wb") as new_zip_file: + new_zip_file.write(b"X"*1991) # The year Python was created. + new_zip_file.write(self.orig_zip_file_contents) + + def testZipFileChangesAfterFirstImport(self): + """Alter the zip file after caching its index and try an import.""" + self.setUpZipFileModuleAndTestImports() + # The above call cached the .zip table of contents during its tests. + self.truncateAndFillZipWithNonZipGarbage() # Now that the zipfile has been replaced, import something else from it # which should fail as the file contents are now garbage. with self.assertRaises(ImportError): ziptest_a = __import__("ziptest_a", globals(), locals(), ["test_value"]) + # The code path used by the __import__ call is different than + # that used by import statements. Try these as well. Some of + # these may create new zipimporter instances. We need to + # function properly using the global zipimport caches + # regardless of how many zipimporter instances for the same + # .zip file exist. + with self.assertRaises(ImportError): + import ziptest_a + with self.assertRaises(ImportError): + from ziptest_a import test_value + with self.assertRaises(ImportError): + exec("from {} import {}".format(TESTPACK, TESTMOD)) - # Now lets make it a valid zipfile that has some garbage at the start. - # This alters all of the offsets within the file - with io.open(zipfile_path, "wb") as new_zip_file: - new_zip_file.write(b"X"*1991) # The year Python was created. - new_zip_file.write(orig_zip_file_contents) + # Alters all of the offsets within the file + self.restoreZipFileWithDifferentHeaderOffsets() # Now that the zip file has been "restored" to a valid but different - # zipfile the zipimporter should *successfully* re-read the new zip - # file's end of file central index and be able to import from it again. + # zipfile all zipimporter instances should *successfully* re-read the + # new file's end of file central index and be able to import again. + + # Importing a submodule triggers a different import code path. + exec("import " + self.testpack_testmod) + self.assertEqual(getattr(locals()[TESTPACK], TESTMOD).test_value, 38) + exec("from {} import {}".format(TESTPACK, TESTMOD)) + self.assertEqual(locals()[TESTMOD].test_value, 38) + ziptest_a = __import__("ziptest_a", globals(), locals(), ["test_value"]) self.assertEqual(ziptest_a.test_value, 23) ziptest_c = __import__("ziptest_c", globals(), locals(), ["test_value"]) self.assertEqual(ziptest_c.test_value, 1337) + def testZipFileSubpackageImport(self): + """Import via multiple sys.path entries into parts of the zip.""" + self.setUpZipFileModuleAndTestImports() + # Put a subdirectory within the zip file into the import path. + sys.path.insert(0, self.zipfile_path + os.sep + TESTPACK) + + testmod = __import__(TESTMOD, globals(), locals(), ["test_value"]) + self.assertEqual(testmod.test_value, 38) + del sys.modules[TESTMOD] + exec("from {} import test_value".format(TESTMOD)) + self.assertEqual(test_value, 38) + del sys.modules[TESTMOD] + + # Confirm that imports from the top level of the zip file + # (already in sys.path from the setup call above) still work. + ziptest_a = __import__("ziptest_a", globals(), locals(), ["test_value"]) + self.assertEqual(ziptest_a.test_value, 23) + del sys.modules["ziptest_a"] + import ziptest_c + self.assertEqual(ziptest_c.test_value, 1337) + del sys.modules["ziptest_c"] + + self.truncateAndFillZipWithNonZipGarbage() + # Imports should now fail. + with self.assertRaises(ImportError): + testmod = __import__(TESTMOD, globals(), locals(), ["test_value"]) + with self.assertRaises(ImportError): + exec("from {} import test_value".format(TESTMOD)) + with self.assertRaises(ImportError): + import ziptest_a + + self.restoreZipFileWithDifferentHeaderOffsets() + # Imports should work again, the central directory TOC will be re-read. + testmod = __import__(TESTMOD, globals(), locals(), ["test_value"]) + self.assertEqual(testmod.test_value, 38) + del sys.modules[TESTMOD] + exec("from {} import test_value".format(TESTMOD)) + self.assertEqual(test_value, 38) + + ziptest_a = __import__("ziptest_a", globals(), locals(), ["test_value"]) + self.assertEqual(ziptest_a.test_value, 23) + import ziptest_c + self.assertEqual(ziptest_c.test_value, 1337) + class BadFileZipImportTestCase(unittest.TestCase): def assertZipFailure(self, filename): diff --git a/Modules/zipimport.c b/Modules/zipimport.c --- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -66,30 +66,34 @@ static int zipimporter_init(ZipImporter *self, PyObject *args, PyObject *kwds) { - char *path, *p, *prefix, buf[MAXPATHLEN+2]; + char *path_arg, *path, *p, *prefix, *path_buf; size_t len; if (!_PyArg_NoKeywords("zipimporter()", kwds)) return -1; - if (!PyArg_ParseTuple(args, "s:zipimporter", - &path)) + if (!PyArg_ParseTuple(args, "s:zipimporter", &path_arg)) return -1; - len = strlen(path); + len = strlen(path_arg); if (len == 0) { PyErr_SetString(ZipImportError, "archive path is empty"); return -1; } if (len >= MAXPATHLEN) { - PyErr_SetString(ZipImportError, - "archive path too long"); + PyErr_SetString(ZipImportError, "archive path too long"); return -1; } - strcpy(buf, path); + /* Room for the trailing \0 and room for an extra SEP if needed. */ + path_buf = (char *)PyMem_Malloc(len + 2); + if (path_buf == NULL) { + PyErr_SetString(PyExc_MemoryError, "unable to malloc path buffer"); + return -1; + } + strcpy(path_buf, path_arg); #ifdef ALTSEP - for (p = buf; *p; p++) { + for (p = path_buf; *p; p++) { if (*p == ALTSEP) *p = SEP; } @@ -102,25 +106,25 @@ struct stat statbuf; int rv; - rv = stat(buf, &statbuf); + rv = stat(path_buf, &statbuf); if (rv == 0) { /* it exists */ if (S_ISREG(statbuf.st_mode)) /* it's a file */ - path = buf; + path = path_buf; break; } #else - if (object_exists(buf)) { + if (object_exists(path_buf)) { /* it exists */ - if (isfile(buf)) + if (isfile(path_buf)) /* it's a file */ - path = buf; + path = path_buf; break; } #endif /* back up one path element */ - p = strrchr(buf, SEP); + p = strrchr(path_buf, SEP); if (prefix != NULL) *prefix = SEP; if (p == NULL) @@ -130,48 +134,52 @@ } if (path != NULL) { PyObject *files; + if (Py_VerboseFlag && prefix && prefix[0] != '\0') + PySys_WriteStderr("# zipimport: prefix=%s constructing a " + "zipimporter for %s\n", prefix, path); + /* NOTE(gps): test_zipimport.py never exercises a case where + * prefix is non-empty. When would that ever be possible? + * Are we missing coverage or is prefix simply never needed? + */ files = PyDict_GetItemString(zip_directory_cache, path); if (files == NULL) { PyObject *zip_stat = NULL; - FILE *fp = fopen_rb_and_stat(buf, &zip_stat); + FILE *fp = fopen_rb_and_stat(path, &zip_stat); if (fp == NULL) { PyErr_Format(ZipImportError, "can't open Zip file: " - "'%.200s'", buf); + "'%.200s'", path); Py_XDECREF(zip_stat); - return -1; + goto error; } if (Py_VerboseFlag) PySys_WriteStderr("# zipimport: %s not cached, " "reading TOC.\n", path); - files = read_directory(fp, buf); + files = read_directory(fp, path); fclose(fp); if (files == NULL) { Py_XDECREF(zip_stat); - return -1; + goto error; } if (PyDict_SetItemString(zip_directory_cache, path, files) != 0) { Py_DECREF(files); Py_XDECREF(zip_stat); - return -1; + goto error; } if (zip_stat && PyDict_SetItemString(zip_stat_cache, path, zip_stat) != 0) { Py_DECREF(files); Py_DECREF(zip_stat); - return -1; + goto error; } Py_XDECREF(zip_stat); } - else - Py_INCREF(files); - self->files = files; } else { PyErr_SetString(ZipImportError, "not a Zip file"); - return -1; + goto error; } if (prefix == NULL) @@ -186,33 +194,26 @@ } } - self->archive = PyString_FromString(buf); + self->archive = PyString_FromString(path); if (self->archive == NULL) - return -1; + goto error; self->prefix = PyString_FromString(prefix); if (self->prefix == NULL) - return -1; + goto error; + PyMem_Free(path_buf); return 0; -} - -/* GC support. */ -static int -zipimporter_traverse(PyObject *obj, visitproc visit, void *arg) -{ - ZipImporter *self = (ZipImporter *)obj; - Py_VISIT(self->files); - return 0; +error: + PyMem_Free(path_buf); + return -1; } static void zipimporter_dealloc(ZipImporter *self) { - PyObject_GC_UnTrack(self); Py_XDECREF(self->archive); Py_XDECREF(self->prefix); - Py_XDECREF(self->files); Py_TYPE(self)->tp_free((PyObject *)self); } @@ -292,6 +293,7 @@ char *subname, path[MAXPATHLEN + 1]; int len; struct st_zip_searchorder *zso; + PyObject *files; subname = get_subname(fullname); @@ -299,9 +301,23 @@ if (len < 0) return MI_ERROR; + files = PyDict_GetItem(zip_directory_cache, self->archive); + if (files == NULL) { + /* Some scoundrel has cleared zip_directory_cache out from + * beneath us. Try repopulating it once before giving up. */ + char *unused_archive_name; + FILE *fp = safely_reopen_archive(self, &unused_archive_name); + if (fp == NULL) + return MI_ERROR; + fclose(fp); + files = PyDict_GetItem(zip_directory_cache, self->archive); + if (files == NULL) + return MI_ERROR; + } + for (zso = zip_searchorder; *zso->suffix; zso++) { strcpy(path + len, zso->suffix); - if (PyDict_GetItemString(self->files, path) != NULL) { + if (PyDict_GetItemString(files, path) != NULL) { if (zso->type & IS_PACKAGE) return MI_PACKAGE; else @@ -456,7 +472,7 @@ #ifdef ALTSEP char *p, buf[MAXPATHLEN + 1]; #endif - PyObject *toc_entry, *data; + PyObject *toc_entry, *data, *files; Py_ssize_t len; if (!PyArg_ParseTuple(args, "s:zipimporter.get_data", &path)) @@ -485,7 +501,13 @@ if (fp == NULL) return NULL; - toc_entry = PyDict_GetItemString(self->files, path); + files = PyDict_GetItem(zip_directory_cache, self->archive); + if (files == NULL) { + /* This should never happen as safely_reopen_archive() should + * have repopulated zip_directory_cache if needed. */ + return NULL; + } + toc_entry = PyDict_GetItemString(files, path); if (toc_entry == NULL) { PyErr_SetFromErrnoWithFilename(PyExc_IOError, path); fclose(fp); @@ -512,7 +534,7 @@ zipimporter_get_source(PyObject *obj, PyObject *args) { ZipImporter *self = (ZipImporter *)obj; - PyObject *toc_entry; + PyObject *toc_entry, *files; FILE *fp; char *fullname, *subname, path[MAXPATHLEN+1], *archive; int len; @@ -546,7 +568,13 @@ if (fp == NULL) return NULL; - toc_entry = PyDict_GetItemString(self->files, path); + files = PyDict_GetItem(zip_directory_cache, self->archive); + if (files == NULL) { + /* This should never happen as safely_reopen_archive() should + * have repopulated zip_directory_cache if needed. */ + return NULL; + } + toc_entry = PyDict_GetItemString(files, path); if (toc_entry != NULL) { PyObject *data = get_data(fp, archive, toc_entry); fclose(fp); @@ -666,10 +694,9 @@ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_HAVE_GC, /* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ zipimporter_doc, /* tp_doc */ - zipimporter_traverse, /* tp_traverse */ + 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ @@ -686,7 +713,7 @@ (initproc)zipimporter_init, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ PyType_GenericNew, /* tp_new */ - PyObject_GC_Del, /* tp_free */ + 0, /* tp_free */ }; @@ -830,11 +857,13 @@ fclose(fp); return NULL; } - Py_XDECREF(self->files); /* free the old value. */ - self->files = files; } Py_DECREF(stat_now); - } /* stat succeeded */ + } else { + if (Py_VerboseFlag) + PySys_WriteStderr("# zipimport: os.fstat failed on the " + "open %s file.\n", archive); + } return fp; } @@ -1236,12 +1265,18 @@ static time_t get_mtime_of_source(ZipImporter *self, char *path) { - PyObject *toc_entry; + PyObject *toc_entry, *files; time_t mtime = 0; Py_ssize_t lastchar = strlen(path) - 1; char savechar = path[lastchar]; path[lastchar] = '\0'; /* strip 'c' or 'o' from *.py[co] */ - toc_entry = PyDict_GetItemString(self->files, path); + files = PyDict_GetItem(zip_directory_cache, self->archive); + if (files == NULL) { + /* This should never happen as safely_reopen_archive() from + * our only caller repopulated zip_directory_cache if needed. */ + return 0; + } + toc_entry = PyDict_GetItemString(files, path); if (toc_entry != NULL && PyTuple_Check(toc_entry) && PyTuple_Size(toc_entry) == 8) { /* fetch the time stamp of the .py file for comparison @@ -1304,7 +1339,7 @@ return NULL; for (zso = zip_searchorder; *zso->suffix; zso++) { - PyObject *code = NULL; + PyObject *code = NULL, *files; strcpy(path + len, zso->suffix); if (Py_VerboseFlag > 1) @@ -1312,7 +1347,14 @@ PyString_AsString(self->archive), SEP, path); - toc_entry = PyDict_GetItemString(self->files, path); + files = PyDict_GetItem(zip_directory_cache, self->archive); + if (files == NULL) { + /* This should never happen as safely_reopen_archive() should + * have repopulated zip_directory_cache if needed; and the GIL + * is being held. */ + return NULL; + } + toc_entry = PyDict_GetItemString(files, path); if (toc_entry != NULL) { time_t mtime = 0; int ispackage = zso->type & IS_PACKAGE; -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon Jan 27 09:27:12 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 27 Jan 2014 09:27:12 +0100 Subject: [Python-checkins] Daily reference leaks (21c5e6b4f68b): sum=0 Message-ID: results for 21c5e6b4f68b on branch "default" -------------------------------------------- test_asyncio leaked [0, 0, 4] memory blocks, sum=4 test_site leaked [-2, 0, 0] references, sum=-2 test_site leaked [-2, 0, 0] memory blocks, sum=-2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogGaneZB', '-x'] From python-checkins at python.org Mon Jan 27 10:08:05 2014 From: python-checkins at python.org (victor.stinner) Date: Mon, 27 Jan 2014 10:08:05 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_document_add=5F?= =?utf-8?q?signal=5Fhandler/remove=5Fsignal=5Fhandler=2C_add_an_example_fo?= =?utf-8?q?r?= Message-ID: <3fCQ910tHmz7LjV@mail.python.org> http://hg.python.org/cpython/rev/b128387df61d changeset: 88768:b128387df61d parent: 88766:b3dd6fc2971c user: Victor Stinner date: Mon Jan 27 10:07:50 2014 +0100 summary: asyncio: document add_signal_handler/remove_signal_handler, add an example for signals files: Doc/library/asyncio-eventloop.rst | 47 +++++++++++++++++++ 1 files changed, 47 insertions(+), 0 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 @@ -325,6 +325,29 @@ This method returns a :ref:`coroutine object `. +UNIX signals +------------ + +Availability: UNIX only. + +.. method:: BaseEventLoop.add_signal_handler(signum, callback, \*args) + + Add a handler for a signal. + + Raise :exc:`ValueError` if the signal number is invalid or uncatchable. + Raise :exc:`RuntimeError` if there is a problem setting up the handler. + +.. method:: BaseEventLoop.remove_signal_handler(sig) + + Remove a handler for a signal. + + Return ``True`` if a signal handler was removed, ``False`` if not. + +.. seealso:: + + The :mod:`signal` module. + + Executor -------- @@ -381,3 +404,27 @@ :ref:`Hello World example using a coroutine `. + +Example: Set signal handlers for SIGINT and SIGTERM +--------------------------------------------------- + +Register handlers for signals :py:data:`SIGINT` and :py:data:`SIGTERM`:: + + import asyncio + import functools + import os + import signal + + def ask_exit(signame): + print("got signal %s: exit" % signame) + loop.stop() + + loop = asyncio.get_event_loop() + for signame in ('SIGINT', 'SIGTERM'): + loop.add_signal_handler(getattr(signal, signame), + functools.partial(ask_exit, signame)) + + print("Event loop running forever, press CTRL+c to interrupt.") + print("pid %s: send SIGINT or SIGTERM to exit." % os.getpid()) + loop.run_forever() + -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 10:33:39 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 27 Jan 2014 10:33:39 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320395=3A_Extract_?= =?utf-8?q?generated_clinic_code_in_Modules/=5Fpickle=2Ec_to_separate?= Message-ID: <3fCQkW2BpDz7Ljr@mail.python.org> http://hg.python.org/cpython/rev/1aa8ea187560 changeset: 88769:1aa8ea187560 parent: 88764:0a406b6fe61f user: Serhiy Storchaka date: Mon Jan 27 10:34:22 2014 +0200 summary: Issue #20395: Extract generated clinic code in Modules/_pickle.c to separate file. files: Modules/_pickle.c | 507 +----------------------- Modules/clinic/_pickle.c.h | 457 ++++++++++++++++++++++ 2 files changed, 485 insertions(+), 479 deletions(-) diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -5,6 +5,7 @@ "Optimized C implementation for the Python pickle module."); /*[clinic input] +output preset file module _pickle class _pickle.Pickler "PicklerObject *" "&Pickler_Type" class _pickle.PicklerMemoProxy "PicklerMemoProxyObject *" "&PicklerMemoProxyType" @@ -594,12 +595,23 @@ the name of globals pickled by Python 2.x. */ } UnpicklerObject; +typedef struct { + PyObject_HEAD + PicklerObject *pickler; /* Pickler whose memo table we're proxying. */ +} PicklerMemoProxyObject; + +typedef struct { + PyObject_HEAD + UnpicklerObject *unpickler; +} UnpicklerMemoProxyObject; + /* Forward declarations */ static int save(PicklerObject *, PyObject *, int); static int save_reduce(PicklerObject *, PyObject *, PyObject *); static PyTypeObject Pickler_Type; static PyTypeObject Unpickler_Type; +#include "clinic/_pickle.c.h" /************************************************************************* A custom hashtable mapping void* to Python ints. This is used by the pickler @@ -3871,30 +3883,9 @@ re-using picklers. [clinic start generated code]*/ -PyDoc_STRVAR(_pickle_Pickler_clear_memo__doc__, -"clear_memo(self)\n" -"Clears the pickler\'s \"memo\".\n" -"\n" -"The memo is the data structure that remembers which objects the\n" -"pickler has already seen, so that shared or recursive objects are\n" -"pickled by reference and not by value. This method is useful when\n" -"re-using picklers."); - -#define _PICKLE_PICKLER_CLEAR_MEMO_METHODDEF \ - {"clear_memo", (PyCFunction)_pickle_Pickler_clear_memo, METH_NOARGS, _pickle_Pickler_clear_memo__doc__}, - -static PyObject * -_pickle_Pickler_clear_memo_impl(PicklerObject *self); - -static PyObject * -_pickle_Pickler_clear_memo(PicklerObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _pickle_Pickler_clear_memo_impl(self); -} - static PyObject * _pickle_Pickler_clear_memo_impl(PicklerObject *self) -/*[clinic end generated code: checksum=17b1165d8dcae5a2e90b1703bf5cbbfc26114c5a]*/ +/*[clinic end generated code: checksum=8665c8658aaa094ba9b424d3d7fe0add5e8142ab]*/ { if (self->memo) PyMemoTable_Clear(self->memo); @@ -3912,16 +3903,9 @@ Write a pickled representation of the given object to the open file. [clinic start generated code]*/ -PyDoc_STRVAR(_pickle_Pickler_dump__doc__, -"dump(self, obj)\n" -"Write a pickled representation of the given object to the open file."); - -#define _PICKLE_PICKLER_DUMP_METHODDEF \ - {"dump", (PyCFunction)_pickle_Pickler_dump, METH_O, _pickle_Pickler_dump__doc__}, - static PyObject * _pickle_Pickler_dump(PicklerObject *self, PyObject *obj) -/*[clinic end generated code: checksum=36db7f67c8bc05ca6f17b8ab57c54d64bfd0539e]*/ +/*[clinic end generated code: checksum=87ecad1261e02ac7ad0b051467b61bb058ae55b3]*/ { /* Check whether the Pickler was initialized correctly (issue3664). Developers often forget to call __init__() in their subclasses, which @@ -4024,52 +4008,9 @@ 2, so that the pickle data stream is readable with Python 2. [clinic start generated code]*/ -PyDoc_STRVAR(_pickle_Pickler___init____doc__, -"Pickler(file, protocol=None, fix_imports=True)\n" -"This takes a binary file for writing a pickle data stream.\n" -"\n" -"The optional *protocol* argument tells the pickler to use the given\n" -"protocol; supported protocols are 0, 1, 2, 3 and 4. The default\n" -"protocol is 3; a backward-incompatible protocol designed for Python 3.\n" -"\n" -"Specifying a negative protocol version selects the highest protocol\n" -"version supported. The higher the protocol used, the more recent the\n" -"version of Python needed to read the pickle produced.\n" -"\n" -"The *file* argument must have a write() method that accepts a single\n" -"bytes argument. It can thus be a file object opened for binary\n" -"writing, a io.BytesIO instance, or any other custom object that meets\n" -"this interface.\n" -"\n" -"If *fix_imports* is True and protocol is less than 3, pickle will try\n" -"to map the new Python 3 names to the old module names used in Python\n" -"2, so that the pickle data stream is readable with Python 2."); - -static int -_pickle_Pickler___init___impl(PicklerObject *self, PyObject *file, PyObject *protocol, int fix_imports); - -static int -_pickle_Pickler___init__(PyObject *self, PyObject *args, PyObject *kwargs) -{ - int return_value = -1; - static char *_keywords[] = {"file", "protocol", "fix_imports", NULL}; - PyObject *file; - PyObject *protocol = NULL; - int fix_imports = 1; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O|Op:Pickler", _keywords, - &file, &protocol, &fix_imports)) - goto exit; - return_value = _pickle_Pickler___init___impl((PicklerObject *)self, file, protocol, fix_imports); - -exit: - return return_value; -} - static int _pickle_Pickler___init___impl(PicklerObject *self, PyObject *file, PyObject *protocol, int fix_imports) -/*[clinic end generated code: checksum=b055bf46cfb5b92c1863302d075246a68bd89153]*/ +/*[clinic end generated code: checksum=56e229f3b1f4332fbfe28a33e43dae836a8dab43]*/ { _Py_IDENTIFIER(persistent_id); _Py_IDENTIFIER(dispatch_table); @@ -4131,36 +4072,15 @@ * intentional, as these should be treated as black-box implementation details. */ -typedef struct { - PyObject_HEAD - PicklerObject *pickler; /* Pickler whose memo table we're proxying. */ -} PicklerMemoProxyObject; - /*[clinic input] _pickle.PicklerMemoProxy.clear Remove all items from memo. [clinic start generated code]*/ -PyDoc_STRVAR(_pickle_PicklerMemoProxy_clear__doc__, -"clear(self)\n" -"Remove all items from memo."); - -#define _PICKLE_PICKLERMEMOPROXY_CLEAR_METHODDEF \ - {"clear", (PyCFunction)_pickle_PicklerMemoProxy_clear, METH_NOARGS, _pickle_PicklerMemoProxy_clear__doc__}, - -static PyObject * -_pickle_PicklerMemoProxy_clear_impl(PicklerMemoProxyObject *self); - -static PyObject * -_pickle_PicklerMemoProxy_clear(PicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _pickle_PicklerMemoProxy_clear_impl(self); -} - static PyObject * _pickle_PicklerMemoProxy_clear_impl(PicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=fb4a5ba40918b3eccc9bc1e9d6875cb2737127a9]*/ +/*[clinic end generated code: checksum=5fb9370d48ae8b055fc72518a2b12d1714338078]*/ { if (self->pickler->memo) PyMemoTable_Clear(self->pickler->memo); @@ -4173,25 +4093,9 @@ Copy the memo to a new object. [clinic start generated code]*/ -PyDoc_STRVAR(_pickle_PicklerMemoProxy_copy__doc__, -"copy(self)\n" -"Copy the memo to a new object."); - -#define _PICKLE_PICKLERMEMOPROXY_COPY_METHODDEF \ - {"copy", (PyCFunction)_pickle_PicklerMemoProxy_copy, METH_NOARGS, _pickle_PicklerMemoProxy_copy__doc__}, - -static PyObject * -_pickle_PicklerMemoProxy_copy_impl(PicklerMemoProxyObject *self); - -static PyObject * -_pickle_PicklerMemoProxy_copy(PicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _pickle_PicklerMemoProxy_copy_impl(self); -} - static PyObject * _pickle_PicklerMemoProxy_copy_impl(PicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=3d27d3005725f1828c9a92a38197811c54c64abb]*/ +/*[clinic end generated code: checksum=bb83a919d29225ef55ba0ecfca002369ea4eb8ea]*/ { Py_ssize_t i; PyMemoTable *memo; @@ -4234,25 +4138,9 @@ Implement pickle support. [clinic start generated code]*/ -PyDoc_STRVAR(_pickle_PicklerMemoProxy___reduce____doc__, -"__reduce__(self)\n" -"Implement pickle support."); - -#define _PICKLE_PICKLERMEMOPROXY___REDUCE___METHODDEF \ - {"__reduce__", (PyCFunction)_pickle_PicklerMemoProxy___reduce__, METH_NOARGS, _pickle_PicklerMemoProxy___reduce____doc__}, - -static PyObject * -_pickle_PicklerMemoProxy___reduce___impl(PicklerMemoProxyObject *self); - -static PyObject * -_pickle_PicklerMemoProxy___reduce__(PicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _pickle_PicklerMemoProxy___reduce___impl(self); -} - static PyObject * _pickle_PicklerMemoProxy___reduce___impl(PicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=2682cf8a3a5027def6328419001b086b047d47c8]*/ +/*[clinic end generated code: checksum=bebba1168863ab1d6560ad707d0f4ab41deb722d]*/ { PyObject *reduce_value, *dict_args; PyObject *contents = _pickle_PicklerMemoProxy_copy_impl(self); @@ -6273,29 +6161,9 @@ specified therein. [clinic start generated code]*/ -PyDoc_STRVAR(_pickle_Unpickler_load__doc__, -"load(self)\n" -"Load a pickle.\n" -"\n" -"Read a pickled object representation from the open file object given\n" -"in the constructor, and return the reconstituted object hierarchy\n" -"specified therein."); - -#define _PICKLE_UNPICKLER_LOAD_METHODDEF \ - {"load", (PyCFunction)_pickle_Unpickler_load, METH_NOARGS, _pickle_Unpickler_load__doc__}, - -static PyObject * -_pickle_Unpickler_load_impl(UnpicklerObject *self); - -static PyObject * -_pickle_Unpickler_load(UnpicklerObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _pickle_Unpickler_load_impl(self); -} - static PyObject * _pickle_Unpickler_load_impl(UnpicklerObject *self) -/*[clinic end generated code: checksum=5ccece694e9898856d916e0a87f0133d4537ebb9]*/ +/*[clinic end generated code: checksum=fdcc488aad675b1458b5644180d092b99e6e4fe4]*/ { UnpicklerObject *unpickler = (UnpicklerObject*)self; @@ -6336,43 +6204,9 @@ needed. Both arguments passed are str objects. [clinic start generated code]*/ -PyDoc_STRVAR(_pickle_Unpickler_find_class__doc__, -"find_class(self, module_name, global_name)\n" -"Return an object from a specified module.\n" -"\n" -"If necessary, the module will be imported. Subclasses may override\n" -"this method (e.g. to restrict unpickling of arbitrary classes and\n" -"functions).\n" -"\n" -"This method is called whenever a class or a function object is\n" -"needed. Both arguments passed are str objects."); - -#define _PICKLE_UNPICKLER_FIND_CLASS_METHODDEF \ - {"find_class", (PyCFunction)_pickle_Unpickler_find_class, METH_VARARGS, _pickle_Unpickler_find_class__doc__}, - -static PyObject * -_pickle_Unpickler_find_class_impl(UnpicklerObject *self, PyObject *module_name, PyObject *global_name); - -static PyObject * -_pickle_Unpickler_find_class(UnpicklerObject *self, PyObject *args) -{ - PyObject *return_value = NULL; - PyObject *module_name; - PyObject *global_name; - - if (!PyArg_UnpackTuple(args, "find_class", - 2, 2, - &module_name, &global_name)) - goto exit; - return_value = _pickle_Unpickler_find_class_impl(self, module_name, global_name); - -exit: - return return_value; -} - static PyObject * _pickle_Unpickler_find_class_impl(UnpicklerObject *self, PyObject *module_name, PyObject *global_name) -/*[clinic end generated code: checksum=2b8d5398787c8ac7ea5d45f644433169e441003b]*/ +/*[clinic end generated code: checksum=64c77437e088e188fa0b022a0402d5b2964da8c9]*/ { PyObject *global; PyObject *modules_dict; @@ -6553,55 +6387,9 @@ string instances as bytes objects. [clinic start generated code]*/ -PyDoc_STRVAR(_pickle_Unpickler___init____doc__, -"Unpickler(file, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" -"This takes a binary file for reading a pickle data stream.\n" -"\n" -"The protocol version of the pickle is detected automatically, so no\n" -"protocol argument is needed. Bytes past the pickled object\'s\n" -"representation are ignored.\n" -"\n" -"The argument *file* must have two methods, a read() method that takes\n" -"an integer argument, and a readline() method that requires no\n" -"arguments. Both methods should return bytes. Thus *file* can be a\n" -"binary file object opened for reading, a io.BytesIO object, or any\n" -"other custom object that meets this interface.\n" -"\n" -"Optional keyword arguments are *fix_imports*, *encoding* and *errors*,\n" -"which are used to control compatiblity support for pickle stream\n" -"generated by Python 2. If *fix_imports* is True, pickle will try to\n" -"map the old Python 2 names to the new names used in Python 3. The\n" -"*encoding* and *errors* tell pickle how to decode 8-bit string\n" -"instances pickled by Python 2; these default to \'ASCII\' and \'strict\',\n" -"respectively. The *encoding* can be \'bytes\' to read these 8-bit\n" -"string instances as bytes objects."); - -static int -_pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file, int fix_imports, const char *encoding, const char *errors); - -static int -_pickle_Unpickler___init__(PyObject *self, PyObject *args, PyObject *kwargs) -{ - int return_value = -1; - static char *_keywords[] = {"file", "fix_imports", "encoding", "errors", NULL}; - PyObject *file; - int fix_imports = 1; - const char *encoding = "ASCII"; - const char *errors = "strict"; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O|$pss:Unpickler", _keywords, - &file, &fix_imports, &encoding, &errors)) - goto exit; - return_value = _pickle_Unpickler___init___impl((UnpicklerObject *)self, file, fix_imports, encoding, errors); - -exit: - return return_value; -} - static int _pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file, int fix_imports, const char *encoding, const char *errors) -/*[clinic end generated code: checksum=a8a9dde29eb4ddd538b45099408ea77e01940692]*/ +/*[clinic end generated code: checksum=b9ed1d84d315f3b57f91b878cdd88024ccc2ae89]*/ { _Py_IDENTIFIER(persistent_load); @@ -6657,36 +6445,15 @@ * real-world code like cvs2svn. */ -typedef struct { - PyObject_HEAD - UnpicklerObject *unpickler; -} UnpicklerMemoProxyObject; - /*[clinic input] _pickle.UnpicklerMemoProxy.clear Remove all items from memo. [clinic start generated code]*/ -PyDoc_STRVAR(_pickle_UnpicklerMemoProxy_clear__doc__, -"clear(self)\n" -"Remove all items from memo."); - -#define _PICKLE_UNPICKLERMEMOPROXY_CLEAR_METHODDEF \ - {"clear", (PyCFunction)_pickle_UnpicklerMemoProxy_clear, METH_NOARGS, _pickle_UnpicklerMemoProxy_clear__doc__}, - -static PyObject * -_pickle_UnpicklerMemoProxy_clear_impl(UnpicklerMemoProxyObject *self); - -static PyObject * -_pickle_UnpicklerMemoProxy_clear(UnpicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _pickle_UnpicklerMemoProxy_clear_impl(self); -} - static PyObject * _pickle_UnpicklerMemoProxy_clear_impl(UnpicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=32f6ee47e44405dd587f768f3690d47947bb5a8e]*/ +/*[clinic end generated code: checksum=d20cd43f4ba1fb1f1ba1677fae3ff69b8cc41582]*/ { _Unpickler_MemoCleanup(self->unpickler); self->unpickler->memo = _Unpickler_NewMemo(self->unpickler->memo_size); @@ -6701,25 +6468,9 @@ Copy the memo to a new object. [clinic start generated code]*/ -PyDoc_STRVAR(_pickle_UnpicklerMemoProxy_copy__doc__, -"copy(self)\n" -"Copy the memo to a new object."); - -#define _PICKLE_UNPICKLERMEMOPROXY_COPY_METHODDEF \ - {"copy", (PyCFunction)_pickle_UnpicklerMemoProxy_copy, METH_NOARGS, _pickle_UnpicklerMemoProxy_copy__doc__}, - -static PyObject * -_pickle_UnpicklerMemoProxy_copy_impl(UnpicklerMemoProxyObject *self); - -static PyObject * -_pickle_UnpicklerMemoProxy_copy(UnpicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _pickle_UnpicklerMemoProxy_copy_impl(self); -} - static PyObject * _pickle_UnpicklerMemoProxy_copy_impl(UnpicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=ac3da80efc3b2548aa8b5c5358d0e82e615fce1d]*/ +/*[clinic end generated code: checksum=e12af7e9bc1e4c77df97c1e657d6b8e026a022b7]*/ { Py_ssize_t i; PyObject *new_memo = PyDict_New(); @@ -6755,25 +6506,9 @@ Implement pickling support. [clinic start generated code]*/ -PyDoc_STRVAR(_pickle_UnpicklerMemoProxy___reduce____doc__, -"__reduce__(self)\n" -"Implement pickling support."); - -#define _PICKLE_UNPICKLERMEMOPROXY___REDUCE___METHODDEF \ - {"__reduce__", (PyCFunction)_pickle_UnpicklerMemoProxy___reduce__, METH_NOARGS, _pickle_UnpicklerMemoProxy___reduce____doc__}, - -static PyObject * -_pickle_UnpicklerMemoProxy___reduce___impl(UnpicklerMemoProxyObject *self); - -static PyObject * -_pickle_UnpicklerMemoProxy___reduce__(UnpicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) -{ - return _pickle_UnpicklerMemoProxy___reduce___impl(self); -} - static PyObject * _pickle_UnpicklerMemoProxy___reduce___impl(UnpicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=2373102b7c87d99ba4c4a56b6813d2c84dd61865]*/ +/*[clinic end generated code: checksum=6da34ac048d94cca7604faa72d45992e730882f1]*/ { PyObject *reduce_value; PyObject *constructor_args; @@ -7081,59 +6816,9 @@ 2, so that the pickle data stream is readable with Python 2. [clinic start generated code]*/ -PyDoc_STRVAR(_pickle_dump__doc__, -"dump(module, obj, file, protocol=None, *, fix_imports=True)\n" -"Write a pickled representation of obj to the open file object file.\n" -"\n" -"This is equivalent to ``Pickler(file, protocol).dump(obj)``, but may\n" -"be more efficient.\n" -"\n" -"The optional *protocol* argument tells the pickler to use the given\n" -"protocol supported protocols are 0, 1, 2, 3 and 4. The default\n" -"protocol is 3; a backward-incompatible protocol designed for Python 3.\n" -"\n" -"Specifying a negative protocol version selects the highest protocol\n" -"version supported. The higher the protocol used, the more recent the\n" -"version of Python needed to read the pickle produced.\n" -"\n" -"The *file* argument must have a write() method that accepts a single\n" -"bytes argument. It can thus be a file object opened for binary\n" -"writing, a io.BytesIO instance, or any other custom object that meets\n" -"this interface.\n" -"\n" -"If *fix_imports* is True and protocol is less than 3, pickle will try\n" -"to map the new Python 3 names to the old module names used in Python\n" -"2, so that the pickle data stream is readable with Python 2."); - -#define _PICKLE_DUMP_METHODDEF \ - {"dump", (PyCFunction)_pickle_dump, METH_VARARGS|METH_KEYWORDS, _pickle_dump__doc__}, - -static PyObject * -_pickle_dump_impl(PyModuleDef *module, PyObject *obj, PyObject *file, PyObject *protocol, int fix_imports); - -static PyObject * -_pickle_dump(PyModuleDef *module, PyObject *args, PyObject *kwargs) -{ - PyObject *return_value = NULL; - static char *_keywords[] = {"obj", "file", "protocol", "fix_imports", NULL}; - PyObject *obj; - PyObject *file; - PyObject *protocol = NULL; - int fix_imports = 1; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "OO|O$p:dump", _keywords, - &obj, &file, &protocol, &fix_imports)) - goto exit; - return_value = _pickle_dump_impl(module, obj, file, protocol, fix_imports); - -exit: - return return_value; -} - static PyObject * _pickle_dump_impl(PyModuleDef *module, PyObject *obj, PyObject *file, PyObject *protocol, int fix_imports) -/*[clinic end generated code: checksum=1d4ff873e13eb840ff275d716d8d4c5554af087c]*/ +/*[clinic end generated code: checksum=a606e626d553850d96c286e909a139552d5d4096]*/ { PicklerObject *pickler = _Pickler_New(); @@ -7184,50 +6869,9 @@ Python 2, so that the pickle data stream is readable with Python 2. [clinic start generated code]*/ -PyDoc_STRVAR(_pickle_dumps__doc__, -"dumps(module, obj, protocol=None, *, fix_imports=True)\n" -"Return the pickled representation of the object as a bytes object.\n" -"\n" -"The optional *protocol* argument tells the pickler to use the given\n" -"protocol; supported protocols are 0, 1, 2, 3 and 4. The default\n" -"protocol is 3; a backward-incompatible protocol designed for Python 3.\n" -"\n" -"Specifying a negative protocol version selects the highest protocol\n" -"version supported. The higher the protocol used, the more recent the\n" -"version of Python needed to read the pickle produced.\n" -"\n" -"If *fix_imports* is True and *protocol* is less than 3, pickle will\n" -"try to map the new Python 3 names to the old module names used in\n" -"Python 2, so that the pickle data stream is readable with Python 2."); - -#define _PICKLE_DUMPS_METHODDEF \ - {"dumps", (PyCFunction)_pickle_dumps, METH_VARARGS|METH_KEYWORDS, _pickle_dumps__doc__}, - -static PyObject * -_pickle_dumps_impl(PyModuleDef *module, PyObject *obj, PyObject *protocol, int fix_imports); - -static PyObject * -_pickle_dumps(PyModuleDef *module, PyObject *args, PyObject *kwargs) -{ - PyObject *return_value = NULL; - static char *_keywords[] = {"obj", "protocol", "fix_imports", NULL}; - PyObject *obj; - PyObject *protocol = NULL; - int fix_imports = 1; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O|O$p:dumps", _keywords, - &obj, &protocol, &fix_imports)) - goto exit; - return_value = _pickle_dumps_impl(module, obj, protocol, fix_imports); - -exit: - return return_value; -} - static PyObject * _pickle_dumps_impl(PyModuleDef *module, PyObject *obj, PyObject *protocol, int fix_imports) -/*[clinic end generated code: checksum=9c6c0291ef2d2b0856b7d4caecdcb7bad13a23b3]*/ +/*[clinic end generated code: checksum=777f0deefe5b88ee324d43ab31b2579da7bbf22a]*/ { PyObject *result; PicklerObject *pickler = _Pickler_New(); @@ -7285,61 +6929,9 @@ string instances as bytes objects. [clinic start generated code]*/ -PyDoc_STRVAR(_pickle_load__doc__, -"load(module, file, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" -"Read and return an object from the pickle data stored in a file.\n" -"\n" -"This is equivalent to ``Unpickler(file).load()``, but may be more\n" -"efficient.\n" -"\n" -"The protocol version of the pickle is detected automatically, so no\n" -"protocol argument is needed. Bytes past the pickled object\'s\n" -"representation are ignored.\n" -"\n" -"The argument *file* must have two methods, a read() method that takes\n" -"an integer argument, and a readline() method that requires no\n" -"arguments. Both methods should return bytes. Thus *file* can be a\n" -"binary file object opened for reading, a io.BytesIO object, or any\n" -"other custom object that meets this interface.\n" -"\n" -"Optional keyword arguments are *fix_imports*, *encoding* and *errors*,\n" -"which are used to control compatiblity support for pickle stream\n" -"generated by Python 2. If *fix_imports* is True, pickle will try to\n" -"map the old Python 2 names to the new names used in Python 3. The\n" -"*encoding* and *errors* tell pickle how to decode 8-bit string\n" -"instances pickled by Python 2; these default to \'ASCII\' and \'strict\',\n" -"respectively. The *encoding* can be \'bytes\' to read these 8-bit\n" -"string instances as bytes objects."); - -#define _PICKLE_LOAD_METHODDEF \ - {"load", (PyCFunction)_pickle_load, METH_VARARGS|METH_KEYWORDS, _pickle_load__doc__}, - -static PyObject * -_pickle_load_impl(PyModuleDef *module, PyObject *file, int fix_imports, const char *encoding, const char *errors); - -static PyObject * -_pickle_load(PyModuleDef *module, PyObject *args, PyObject *kwargs) -{ - PyObject *return_value = NULL; - static char *_keywords[] = {"file", "fix_imports", "encoding", "errors", NULL}; - PyObject *file; - int fix_imports = 1; - const char *encoding = "ASCII"; - const char *errors = "strict"; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O|$pss:load", _keywords, - &file, &fix_imports, &encoding, &errors)) - goto exit; - return_value = _pickle_load_impl(module, file, fix_imports, encoding, errors); - -exit: - return return_value; -} - static PyObject * _pickle_load_impl(PyModuleDef *module, PyObject *file, int fix_imports, const char *encoding, const char *errors) -/*[clinic end generated code: checksum=2b5b7e5e3a836cf1c53377ce9274a84a8bceef67]*/ +/*[clinic end generated code: checksum=568c61356c172654a23cf4edb4afffa1dc2a55d9]*/ { PyObject *result; UnpicklerObject *unpickler = _Unpickler_New(); @@ -7390,52 +6982,9 @@ string instances as bytes objects. [clinic start generated code]*/ -PyDoc_STRVAR(_pickle_loads__doc__, -"loads(module, data, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" -"Read and return an object from the given pickle data.\n" -"\n" -"The protocol version of the pickle is detected automatically, so no\n" -"protocol argument is needed. Bytes past the pickled object\'s\n" -"representation are ignored.\n" -"\n" -"Optional keyword arguments are *fix_imports*, *encoding* and *errors*,\n" -"which are used to control compatiblity support for pickle stream\n" -"generated by Python 2. If *fix_imports* is True, pickle will try to\n" -"map the old Python 2 names to the new names used in Python 3. The\n" -"*encoding* and *errors* tell pickle how to decode 8-bit string\n" -"instances pickled by Python 2; these default to \'ASCII\' and \'strict\',\n" -"respectively. The *encoding* can be \'bytes\' to read these 8-bit\n" -"string instances as bytes objects."); - -#define _PICKLE_LOADS_METHODDEF \ - {"loads", (PyCFunction)_pickle_loads, METH_VARARGS|METH_KEYWORDS, _pickle_loads__doc__}, - -static PyObject * -_pickle_loads_impl(PyModuleDef *module, PyObject *data, int fix_imports, const char *encoding, const char *errors); - -static PyObject * -_pickle_loads(PyModuleDef *module, PyObject *args, PyObject *kwargs) -{ - PyObject *return_value = NULL; - static char *_keywords[] = {"data", "fix_imports", "encoding", "errors", NULL}; - PyObject *data; - int fix_imports = 1; - const char *encoding = "ASCII"; - const char *errors = "strict"; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O|$pss:loads", _keywords, - &data, &fix_imports, &encoding, &errors)) - goto exit; - return_value = _pickle_loads_impl(module, data, fix_imports, encoding, errors); - -exit: - return return_value; -} - static PyObject * _pickle_loads_impl(PyModuleDef *module, PyObject *data, int fix_imports, const char *encoding, const char *errors) -/*[clinic end generated code: checksum=7b21a75997c8f6636e4bf48c663b28f2bfd4eb6a]*/ +/*[clinic end generated code: checksum=0b3845ad110b25220ab613e9a1e573194271a337]*/ { PyObject *result; UnpicklerObject *unpickler = _Unpickler_New(); diff --git a/Modules/clinic/_pickle.c.h b/Modules/clinic/_pickle.c.h new file mode 100644 --- /dev/null +++ b/Modules/clinic/_pickle.c.h @@ -0,0 +1,457 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(_pickle_Pickler_clear_memo__doc__, +"clear_memo(self)\n" +"Clears the pickler\'s \"memo\".\n" +"\n" +"The memo is the data structure that remembers which objects the\n" +"pickler has already seen, so that shared or recursive objects are\n" +"pickled by reference and not by value. This method is useful when\n" +"re-using picklers."); + +#define _PICKLE_PICKLER_CLEAR_MEMO_METHODDEF \ + {"clear_memo", (PyCFunction)_pickle_Pickler_clear_memo, METH_NOARGS, _pickle_Pickler_clear_memo__doc__}, + +static PyObject * +_pickle_Pickler_clear_memo_impl(PicklerObject *self); + +static PyObject * +_pickle_Pickler_clear_memo(PicklerObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _pickle_Pickler_clear_memo_impl(self); +} + +PyDoc_STRVAR(_pickle_Pickler_dump__doc__, +"dump(self, obj)\n" +"Write a pickled representation of the given object to the open file."); + +#define _PICKLE_PICKLER_DUMP_METHODDEF \ + {"dump", (PyCFunction)_pickle_Pickler_dump, METH_O, _pickle_Pickler_dump__doc__}, + +PyDoc_STRVAR(_pickle_Pickler___init____doc__, +"Pickler(file, protocol=None, fix_imports=True)\n" +"This takes a binary file for writing a pickle data stream.\n" +"\n" +"The optional *protocol* argument tells the pickler to use the given\n" +"protocol; supported protocols are 0, 1, 2, 3 and 4. The default\n" +"protocol is 3; a backward-incompatible protocol designed for Python 3.\n" +"\n" +"Specifying a negative protocol version selects the highest protocol\n" +"version supported. The higher the protocol used, the more recent the\n" +"version of Python needed to read the pickle produced.\n" +"\n" +"The *file* argument must have a write() method that accepts a single\n" +"bytes argument. It can thus be a file object opened for binary\n" +"writing, a io.BytesIO instance, or any other custom object that meets\n" +"this interface.\n" +"\n" +"If *fix_imports* is True and protocol is less than 3, pickle will try\n" +"to map the new Python 3 names to the old module names used in Python\n" +"2, so that the pickle data stream is readable with Python 2."); + +static int +_pickle_Pickler___init___impl(PicklerObject *self, PyObject *file, PyObject *protocol, int fix_imports); + +static int +_pickle_Pickler___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + static char *_keywords[] = {"file", "protocol", "fix_imports", NULL}; + PyObject *file; + PyObject *protocol = NULL; + int fix_imports = 1; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O|Op:Pickler", _keywords, + &file, &protocol, &fix_imports)) + goto exit; + return_value = _pickle_Pickler___init___impl((PicklerObject *)self, file, protocol, fix_imports); + +exit: + return return_value; +} + +PyDoc_STRVAR(_pickle_PicklerMemoProxy_clear__doc__, +"clear(self)\n" +"Remove all items from memo."); + +#define _PICKLE_PICKLERMEMOPROXY_CLEAR_METHODDEF \ + {"clear", (PyCFunction)_pickle_PicklerMemoProxy_clear, METH_NOARGS, _pickle_PicklerMemoProxy_clear__doc__}, + +static PyObject * +_pickle_PicklerMemoProxy_clear_impl(PicklerMemoProxyObject *self); + +static PyObject * +_pickle_PicklerMemoProxy_clear(PicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _pickle_PicklerMemoProxy_clear_impl(self); +} + +PyDoc_STRVAR(_pickle_PicklerMemoProxy_copy__doc__, +"copy(self)\n" +"Copy the memo to a new object."); + +#define _PICKLE_PICKLERMEMOPROXY_COPY_METHODDEF \ + {"copy", (PyCFunction)_pickle_PicklerMemoProxy_copy, METH_NOARGS, _pickle_PicklerMemoProxy_copy__doc__}, + +static PyObject * +_pickle_PicklerMemoProxy_copy_impl(PicklerMemoProxyObject *self); + +static PyObject * +_pickle_PicklerMemoProxy_copy(PicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _pickle_PicklerMemoProxy_copy_impl(self); +} + +PyDoc_STRVAR(_pickle_PicklerMemoProxy___reduce____doc__, +"__reduce__(self)\n" +"Implement pickle support."); + +#define _PICKLE_PICKLERMEMOPROXY___REDUCE___METHODDEF \ + {"__reduce__", (PyCFunction)_pickle_PicklerMemoProxy___reduce__, METH_NOARGS, _pickle_PicklerMemoProxy___reduce____doc__}, + +static PyObject * +_pickle_PicklerMemoProxy___reduce___impl(PicklerMemoProxyObject *self); + +static PyObject * +_pickle_PicklerMemoProxy___reduce__(PicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _pickle_PicklerMemoProxy___reduce___impl(self); +} + +PyDoc_STRVAR(_pickle_Unpickler_load__doc__, +"load(self)\n" +"Load a pickle.\n" +"\n" +"Read a pickled object representation from the open file object given\n" +"in the constructor, and return the reconstituted object hierarchy\n" +"specified therein."); + +#define _PICKLE_UNPICKLER_LOAD_METHODDEF \ + {"load", (PyCFunction)_pickle_Unpickler_load, METH_NOARGS, _pickle_Unpickler_load__doc__}, + +static PyObject * +_pickle_Unpickler_load_impl(UnpicklerObject *self); + +static PyObject * +_pickle_Unpickler_load(UnpicklerObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _pickle_Unpickler_load_impl(self); +} + +PyDoc_STRVAR(_pickle_Unpickler_find_class__doc__, +"find_class(self, module_name, global_name)\n" +"Return an object from a specified module.\n" +"\n" +"If necessary, the module will be imported. Subclasses may override\n" +"this method (e.g. to restrict unpickling of arbitrary classes and\n" +"functions).\n" +"\n" +"This method is called whenever a class or a function object is\n" +"needed. Both arguments passed are str objects."); + +#define _PICKLE_UNPICKLER_FIND_CLASS_METHODDEF \ + {"find_class", (PyCFunction)_pickle_Unpickler_find_class, METH_VARARGS, _pickle_Unpickler_find_class__doc__}, + +static PyObject * +_pickle_Unpickler_find_class_impl(UnpicklerObject *self, PyObject *module_name, PyObject *global_name); + +static PyObject * +_pickle_Unpickler_find_class(UnpicklerObject *self, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *module_name; + PyObject *global_name; + + if (!PyArg_UnpackTuple(args, "find_class", + 2, 2, + &module_name, &global_name)) + goto exit; + return_value = _pickle_Unpickler_find_class_impl(self, module_name, global_name); + +exit: + return return_value; +} + +PyDoc_STRVAR(_pickle_Unpickler___init____doc__, +"Unpickler(file, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" +"This takes a binary file for reading a pickle data stream.\n" +"\n" +"The protocol version of the pickle is detected automatically, so no\n" +"protocol argument is needed. Bytes past the pickled object\'s\n" +"representation are ignored.\n" +"\n" +"The argument *file* must have two methods, a read() method that takes\n" +"an integer argument, and a readline() method that requires no\n" +"arguments. Both methods should return bytes. Thus *file* can be a\n" +"binary file object opened for reading, a io.BytesIO object, or any\n" +"other custom object that meets this interface.\n" +"\n" +"Optional keyword arguments are *fix_imports*, *encoding* and *errors*,\n" +"which are used to control compatiblity support for pickle stream\n" +"generated by Python 2. If *fix_imports* is True, pickle will try to\n" +"map the old Python 2 names to the new names used in Python 3. The\n" +"*encoding* and *errors* tell pickle how to decode 8-bit string\n" +"instances pickled by Python 2; these default to \'ASCII\' and \'strict\',\n" +"respectively. The *encoding* can be \'bytes\' to read these 8-bit\n" +"string instances as bytes objects."); + +static int +_pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file, int fix_imports, const char *encoding, const char *errors); + +static int +_pickle_Unpickler___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + static char *_keywords[] = {"file", "fix_imports", "encoding", "errors", NULL}; + PyObject *file; + int fix_imports = 1; + const char *encoding = "ASCII"; + const char *errors = "strict"; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O|$pss:Unpickler", _keywords, + &file, &fix_imports, &encoding, &errors)) + goto exit; + return_value = _pickle_Unpickler___init___impl((UnpicklerObject *)self, file, fix_imports, encoding, errors); + +exit: + return return_value; +} + +PyDoc_STRVAR(_pickle_UnpicklerMemoProxy_clear__doc__, +"clear(self)\n" +"Remove all items from memo."); + +#define _PICKLE_UNPICKLERMEMOPROXY_CLEAR_METHODDEF \ + {"clear", (PyCFunction)_pickle_UnpicklerMemoProxy_clear, METH_NOARGS, _pickle_UnpicklerMemoProxy_clear__doc__}, + +static PyObject * +_pickle_UnpicklerMemoProxy_clear_impl(UnpicklerMemoProxyObject *self); + +static PyObject * +_pickle_UnpicklerMemoProxy_clear(UnpicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _pickle_UnpicklerMemoProxy_clear_impl(self); +} + +PyDoc_STRVAR(_pickle_UnpicklerMemoProxy_copy__doc__, +"copy(self)\n" +"Copy the memo to a new object."); + +#define _PICKLE_UNPICKLERMEMOPROXY_COPY_METHODDEF \ + {"copy", (PyCFunction)_pickle_UnpicklerMemoProxy_copy, METH_NOARGS, _pickle_UnpicklerMemoProxy_copy__doc__}, + +static PyObject * +_pickle_UnpicklerMemoProxy_copy_impl(UnpicklerMemoProxyObject *self); + +static PyObject * +_pickle_UnpicklerMemoProxy_copy(UnpicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _pickle_UnpicklerMemoProxy_copy_impl(self); +} + +PyDoc_STRVAR(_pickle_UnpicklerMemoProxy___reduce____doc__, +"__reduce__(self)\n" +"Implement pickling support."); + +#define _PICKLE_UNPICKLERMEMOPROXY___REDUCE___METHODDEF \ + {"__reduce__", (PyCFunction)_pickle_UnpicklerMemoProxy___reduce__, METH_NOARGS, _pickle_UnpicklerMemoProxy___reduce____doc__}, + +static PyObject * +_pickle_UnpicklerMemoProxy___reduce___impl(UnpicklerMemoProxyObject *self); + +static PyObject * +_pickle_UnpicklerMemoProxy___reduce__(UnpicklerMemoProxyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _pickle_UnpicklerMemoProxy___reduce___impl(self); +} + +PyDoc_STRVAR(_pickle_dump__doc__, +"dump(module, obj, file, protocol=None, *, fix_imports=True)\n" +"Write a pickled representation of obj to the open file object file.\n" +"\n" +"This is equivalent to ``Pickler(file, protocol).dump(obj)``, but may\n" +"be more efficient.\n" +"\n" +"The optional *protocol* argument tells the pickler to use the given\n" +"protocol supported protocols are 0, 1, 2, 3 and 4. The default\n" +"protocol is 3; a backward-incompatible protocol designed for Python 3.\n" +"\n" +"Specifying a negative protocol version selects the highest protocol\n" +"version supported. The higher the protocol used, the more recent the\n" +"version of Python needed to read the pickle produced.\n" +"\n" +"The *file* argument must have a write() method that accepts a single\n" +"bytes argument. It can thus be a file object opened for binary\n" +"writing, a io.BytesIO instance, or any other custom object that meets\n" +"this interface.\n" +"\n" +"If *fix_imports* is True and protocol is less than 3, pickle will try\n" +"to map the new Python 3 names to the old module names used in Python\n" +"2, so that the pickle data stream is readable with Python 2."); + +#define _PICKLE_DUMP_METHODDEF \ + {"dump", (PyCFunction)_pickle_dump, METH_VARARGS|METH_KEYWORDS, _pickle_dump__doc__}, + +static PyObject * +_pickle_dump_impl(PyModuleDef *module, PyObject *obj, PyObject *file, PyObject *protocol, int fix_imports); + +static PyObject * +_pickle_dump(PyModuleDef *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + static char *_keywords[] = {"obj", "file", "protocol", "fix_imports", NULL}; + PyObject *obj; + PyObject *file; + PyObject *protocol = NULL; + int fix_imports = 1; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "OO|O$p:dump", _keywords, + &obj, &file, &protocol, &fix_imports)) + goto exit; + return_value = _pickle_dump_impl(module, obj, file, protocol, fix_imports); + +exit: + return return_value; +} + +PyDoc_STRVAR(_pickle_dumps__doc__, +"dumps(module, obj, protocol=None, *, fix_imports=True)\n" +"Return the pickled representation of the object as a bytes object.\n" +"\n" +"The optional *protocol* argument tells the pickler to use the given\n" +"protocol; supported protocols are 0, 1, 2, 3 and 4. The default\n" +"protocol is 3; a backward-incompatible protocol designed for Python 3.\n" +"\n" +"Specifying a negative protocol version selects the highest protocol\n" +"version supported. The higher the protocol used, the more recent the\n" +"version of Python needed to read the pickle produced.\n" +"\n" +"If *fix_imports* is True and *protocol* is less than 3, pickle will\n" +"try to map the new Python 3 names to the old module names used in\n" +"Python 2, so that the pickle data stream is readable with Python 2."); + +#define _PICKLE_DUMPS_METHODDEF \ + {"dumps", (PyCFunction)_pickle_dumps, METH_VARARGS|METH_KEYWORDS, _pickle_dumps__doc__}, + +static PyObject * +_pickle_dumps_impl(PyModuleDef *module, PyObject *obj, PyObject *protocol, int fix_imports); + +static PyObject * +_pickle_dumps(PyModuleDef *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + static char *_keywords[] = {"obj", "protocol", "fix_imports", NULL}; + PyObject *obj; + PyObject *protocol = NULL; + int fix_imports = 1; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O|O$p:dumps", _keywords, + &obj, &protocol, &fix_imports)) + goto exit; + return_value = _pickle_dumps_impl(module, obj, protocol, fix_imports); + +exit: + return return_value; +} + +PyDoc_STRVAR(_pickle_load__doc__, +"load(module, file, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" +"Read and return an object from the pickle data stored in a file.\n" +"\n" +"This is equivalent to ``Unpickler(file).load()``, but may be more\n" +"efficient.\n" +"\n" +"The protocol version of the pickle is detected automatically, so no\n" +"protocol argument is needed. Bytes past the pickled object\'s\n" +"representation are ignored.\n" +"\n" +"The argument *file* must have two methods, a read() method that takes\n" +"an integer argument, and a readline() method that requires no\n" +"arguments. Both methods should return bytes. Thus *file* can be a\n" +"binary file object opened for reading, a io.BytesIO object, or any\n" +"other custom object that meets this interface.\n" +"\n" +"Optional keyword arguments are *fix_imports*, *encoding* and *errors*,\n" +"which are used to control compatiblity support for pickle stream\n" +"generated by Python 2. If *fix_imports* is True, pickle will try to\n" +"map the old Python 2 names to the new names used in Python 3. The\n" +"*encoding* and *errors* tell pickle how to decode 8-bit string\n" +"instances pickled by Python 2; these default to \'ASCII\' and \'strict\',\n" +"respectively. The *encoding* can be \'bytes\' to read these 8-bit\n" +"string instances as bytes objects."); + +#define _PICKLE_LOAD_METHODDEF \ + {"load", (PyCFunction)_pickle_load, METH_VARARGS|METH_KEYWORDS, _pickle_load__doc__}, + +static PyObject * +_pickle_load_impl(PyModuleDef *module, PyObject *file, int fix_imports, const char *encoding, const char *errors); + +static PyObject * +_pickle_load(PyModuleDef *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + static char *_keywords[] = {"file", "fix_imports", "encoding", "errors", NULL}; + PyObject *file; + int fix_imports = 1; + const char *encoding = "ASCII"; + const char *errors = "strict"; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O|$pss:load", _keywords, + &file, &fix_imports, &encoding, &errors)) + goto exit; + return_value = _pickle_load_impl(module, file, fix_imports, encoding, errors); + +exit: + return return_value; +} + +PyDoc_STRVAR(_pickle_loads__doc__, +"loads(module, data, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" +"Read and return an object from the given pickle data.\n" +"\n" +"The protocol version of the pickle is detected automatically, so no\n" +"protocol argument is needed. Bytes past the pickled object\'s\n" +"representation are ignored.\n" +"\n" +"Optional keyword arguments are *fix_imports*, *encoding* and *errors*,\n" +"which are used to control compatiblity support for pickle stream\n" +"generated by Python 2. If *fix_imports* is True, pickle will try to\n" +"map the old Python 2 names to the new names used in Python 3. The\n" +"*encoding* and *errors* tell pickle how to decode 8-bit string\n" +"instances pickled by Python 2; these default to \'ASCII\' and \'strict\',\n" +"respectively. The *encoding* can be \'bytes\' to read these 8-bit\n" +"string instances as bytes objects."); + +#define _PICKLE_LOADS_METHODDEF \ + {"loads", (PyCFunction)_pickle_loads, METH_VARARGS|METH_KEYWORDS, _pickle_loads__doc__}, + +static PyObject * +_pickle_loads_impl(PyModuleDef *module, PyObject *data, int fix_imports, const char *encoding, const char *errors); + +static PyObject * +_pickle_loads(PyModuleDef *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + static char *_keywords[] = {"data", "fix_imports", "encoding", "errors", NULL}; + PyObject *data; + int fix_imports = 1; + const char *encoding = "ASCII"; + const char *errors = "strict"; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O|$pss:loads", _keywords, + &data, &fix_imports, &encoding, &errors)) + goto exit; + return_value = _pickle_loads_impl(module, data, fix_imports, encoding, errors); + +exit: + return return_value; +} +/*[clinic end generated code: checksum=b7a2e1df72bdbc87da3cd0e43a3caa1a879892bb]*/ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 10:33:40 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 27 Jan 2014 10:33:40 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_heads?= Message-ID: <3fCQkX3rnkz7LlP@mail.python.org> http://hg.python.org/cpython/rev/0eec47f9f8a1 changeset: 88770:0eec47f9f8a1 parent: 88769:1aa8ea187560 parent: 88768:b128387df61d user: Serhiy Storchaka date: Mon Jan 27 11:17:48 2014 +0200 summary: Merge heads files: Doc/library/asyncio-eventloop.rst | 47 +++++++++++++++++++ 1 files changed, 47 insertions(+), 0 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 @@ -325,6 +325,29 @@ This method returns a :ref:`coroutine object `. +UNIX signals +------------ + +Availability: UNIX only. + +.. method:: BaseEventLoop.add_signal_handler(signum, callback, \*args) + + Add a handler for a signal. + + Raise :exc:`ValueError` if the signal number is invalid or uncatchable. + Raise :exc:`RuntimeError` if there is a problem setting up the handler. + +.. method:: BaseEventLoop.remove_signal_handler(sig) + + Remove a handler for a signal. + + Return ``True`` if a signal handler was removed, ``False`` if not. + +.. seealso:: + + The :mod:`signal` module. + + Executor -------- @@ -381,3 +404,27 @@ :ref:`Hello World example using a coroutine `. + +Example: Set signal handlers for SIGINT and SIGTERM +--------------------------------------------------- + +Register handlers for signals :py:data:`SIGINT` and :py:data:`SIGTERM`:: + + import asyncio + import functools + import os + import signal + + def ask_exit(signame): + print("got signal %s: exit" % signame) + loop.stop() + + loop = asyncio.get_event_loop() + for signame in ('SIGINT', 'SIGTERM'): + loop.add_signal_handler(getattr(signal, signame), + functools.partial(ask_exit, signame)) + + print("Event loop running forever, press CTRL+c to interrupt.") + print("pid %s: send SIGINT or SIGTERM to exit." % os.getpid()) + loop.run_forever() + -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 10:33:41 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 27 Jan 2014 10:33:41 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE5MDc3?= =?utf-8?q?=3A_tempfile=2ETemporaryDirectory_cleanup_is_now_most_likely?= Message-ID: <3fCQkY6Sgcz7LlS@mail.python.org> http://hg.python.org/cpython/rev/50aa9e3ab9a4 changeset: 88771:50aa9e3ab9a4 branch: 3.3 parent: 88765:791b69f9f96d user: Serhiy Storchaka date: Mon Jan 27 11:18:27 2014 +0200 summary: Issue #19077: tempfile.TemporaryDirectory cleanup is now most likely successful when called during nulling out of modules during shutdown. Misleading exception no longer raised when resource warning is emitted during shutdown. files: Lib/tempfile.py | 97 +++++++++++++------------- Lib/test/test_tempfile.py | 84 ++++++++++------------- Misc/NEWS | 5 + 3 files changed, 89 insertions(+), 97 deletions(-) diff --git a/Lib/tempfile.py b/Lib/tempfile.py --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -27,11 +27,12 @@ # Imports. +import atexit as _atexit import functools as _functools import warnings as _warnings -import sys as _sys import io as _io import os as _os +import shutil as _shutil import errno as _errno from random import Random as _Random @@ -355,10 +356,13 @@ underlying file object, without adding a __del__ method to the temporary file.""" + # Set here since __del__ checks it + file = None + close_called = False + def __init__(self, file, name, delete=True): self.file = file self.name = name - self.close_called = False self.delete = delete # NT provides delete-on-close as a primitive, so we don't need @@ -370,14 +374,13 @@ # that this must be referenced as self.unlink, because the # name TemporaryFileWrapper may also get None'd out before # __del__ is called. - unlink = _os.unlink - def close(self): - if not self.close_called: + def close(self, unlink=_os.unlink): + if not self.close_called and self.file is not None: self.close_called = True self.file.close() if self.delete: - self.unlink(self.name) + unlink(self.name) # Need to ensure the file is deleted on __del__ def __del__(self): @@ -677,9 +680,11 @@ in it are removed. """ + # Handle mkdtemp raising an exception + name = None + _closed = False + def __init__(self, suffix="", prefix=template, dir=None): - self._closed = False - self.name = None # Handle mkdtemp raising an exception self.name = mkdtemp(suffix, prefix, dir) def __repr__(self): @@ -688,23 +693,24 @@ def __enter__(self): return self.name - def cleanup(self, _warn=False): + def cleanup(self, _warn=False, _warnings=_warnings): if self.name and not self._closed: try: + _shutil.rmtree(self.name) + except (TypeError, AttributeError) as ex: + if "None" not in '%s' % (ex,): + raise self._rmtree(self.name) - except (TypeError, AttributeError) as ex: - # Issue #10188: Emit a warning on stderr - # if the directory could not be cleaned - # up due to missing globals - if "None" not in str(ex): - raise - print("ERROR: {!r} while cleaning up {!r}".format(ex, self,), - file=_sys.stderr) - return self._closed = True - if _warn: - self._warn("Implicitly cleaning up {!r}".format(self), - ResourceWarning) + if _warn and _warnings.warn: + try: + _warnings.warn("Implicitly cleaning up {!r}".format(self), + ResourceWarning) + except: + if _is_running: + raise + # Don't raise an exception if modules needed for emitting + # a warning are already cleaned in shutdown process. def __exit__(self, exc, value, tb): self.cleanup() @@ -713,36 +719,27 @@ # Issue a ResourceWarning if implicit cleanup needed self.cleanup(_warn=True) - # XXX (ncoghlan): The following code attempts to make - # this class tolerant of the module nulling out process - # that happens during CPython interpreter shutdown - # Alas, it doesn't actually manage it. See issue #10188 - _listdir = staticmethod(_os.listdir) - _path_join = staticmethod(_os.path.join) - _isdir = staticmethod(_os.path.isdir) - _islink = staticmethod(_os.path.islink) - _remove = staticmethod(_os.remove) - _rmdir = staticmethod(_os.rmdir) - _os_error = OSError - _warn = _warnings.warn - - def _rmtree(self, path): + def _rmtree(self, path, _OSError=OSError, _sep=_os.path.sep, + _listdir=_os.listdir, _remove=_os.remove, _rmdir=_os.rmdir): # Essentially a stripped down version of shutil.rmtree. We can't # use globals because they may be None'ed out at shutdown. - for name in self._listdir(path): - fullname = self._path_join(path, name) - try: - isdir = self._isdir(fullname) and not self._islink(fullname) - except self._os_error: - isdir = False - if isdir: - self._rmtree(fullname) - else: + if not isinstance(path, str): + _sep = _sep.encode() + try: + for name in _listdir(path): + fullname = path + _sep + name try: - self._remove(fullname) - except self._os_error: - pass - try: - self._rmdir(path) - except self._os_error: + _remove(fullname) + except _OSError: + self._rmtree(fullname) + _rmdir(path) + except _OSError: pass + +_is_running = True + +def _on_shutdown(): + global _is_running + _is_running = False + +_atexit.register(_on_shutdown) diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -11,7 +11,7 @@ import weakref import unittest -from test import support +from test import support, script_helper if hasattr(os, 'stat'): @@ -1073,7 +1073,8 @@ self.nameCheck(tmp.name, dir, pre, suf) # Create a subdirectory and some files if recurse: - self.do_create(tmp.name, pre, suf, recurse-1) + d1 = self.do_create(tmp.name, pre, suf, recurse-1) + d1.name = None with open(os.path.join(tmp.name, "test.txt"), "wb") as f: f.write(b"Hello world!") return tmp @@ -1105,7 +1106,7 @@ def test_cleanup_with_symlink_to_a_directory(self): # cleanup() should not follow symlinks to directories (issue #12464) d1 = self.do_create() - d2 = self.do_create() + d2 = self.do_create(recurse=0) # Symlink d1/foo -> d2 os.symlink(d2.name, os.path.join(d1.name, "foo")) @@ -1135,60 +1136,49 @@ finally: os.rmdir(dir) - @unittest.expectedFailure # See issue #10188 def test_del_on_shutdown(self): # A TemporaryDirectory may be cleaned up during shutdown - # Make sure it works with the relevant modules nulled out with self.do_create() as dir: - d = self.do_create(dir=dir) - # Mimic the nulling out of modules that - # occurs during system shutdown - modules = [os, os.path] - if has_stat: - modules.append(stat) - # Currently broken, so suppress the warning - # that is otherwise emitted on stdout - with support.captured_stderr() as err: - with NulledModules(*modules): - d.cleanup() - # Currently broken, so stop spurious exception by - # indicating the object has already been closed - d._closed = True - # And this assert will fail, as expected by the - # unittest decorator... - self.assertFalse(os.path.exists(d.name), - "TemporaryDirectory %s exists after cleanup" % d.name) + for mod in ('os', 'shutil', 'sys', 'tempfile', 'warnings'): + code = """if True: + import os + import shutil + import sys + import tempfile + import warnings + + tmp = tempfile.TemporaryDirectory(dir={dir!r}) + sys.stdout.buffer.write(tmp.name.encode()) + + tmp2 = os.path.join(tmp.name, 'test_dir') + os.mkdir(tmp2) + with open(os.path.join(tmp2, "test.txt"), "w") as f: + f.write("Hello world!") + + {mod}.tmp = tmp + + warnings.filterwarnings("always", category=ResourceWarning) + """.format(dir=dir, mod=mod) + rc, out, err = script_helper.assert_python_ok("-c", code) + tmp_name = out.decode().strip() + self.assertFalse(os.path.exists(tmp_name), + "TemporaryDirectory %s exists after cleanup" % tmp_name) + err = err.decode('utf-8', 'backslashreplace') + self.assertNotIn("Exception ", err) def test_warnings_on_cleanup(self): - # Two kinds of warning on shutdown - # Issue 10888: may write to stderr if modules are nulled out - # ResourceWarning will be triggered by __del__ + # ResourceWarning will be triggered by __del__ with self.do_create() as dir: - if os.sep != '\\': - # Embed a backslash in order to make sure string escaping - # in the displayed error message is dealt with correctly - suffix = '\\check_backslash_handling' - else: - suffix = '' - d = self.do_create(dir=dir, suf=suffix) - - #Check for the Issue 10888 message - modules = [os, os.path] - if has_stat: - modules.append(stat) - with support.captured_stderr() as err: - with NulledModules(*modules): - d.cleanup() - message = err.getvalue().replace('\\\\', '\\') - self.assertIn("while cleaning up", message) - self.assertIn(d.name, message) + d = self.do_create(dir=dir, recurse=3) + name = d.name # Check for the resource warning with support.check_warnings(('Implicitly', ResourceWarning), quiet=False): warnings.filterwarnings("always", category=ResourceWarning) - d.__del__() - self.assertFalse(os.path.exists(d.name), - "TemporaryDirectory %s exists after __del__" % d.name) + del d + support.gc_collect() + self.assertFalse(os.path.exists(name), + "TemporaryDirectory %s exists after __del__" % name) def test_multiple_close(self): # Can be cleaned-up many times without error diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -50,6 +50,11 @@ Library ------- +- Issue #19077: tempfile.TemporaryDirectory cleanup is now most likely + successful when called during nulling out of modules during shutdown. + Misleading exception no longer raised when resource warning is emitted + during shutdown. + - Issue #20367: Fix behavior of concurrent.futures.as_completed() for duplicate arguments. Patch by Glenn Langford. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 10:33:43 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 27 Jan 2014 10:33:43 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2319077=3A_tempfile=2ETemporaryDirectory_cleanup_?= =?utf-8?q?no_longer_fails_when?= Message-ID: <3fCQkb1yN5z7Lk3@mail.python.org> http://hg.python.org/cpython/rev/d792eb3afa58 changeset: 88772:d792eb3afa58 parent: 88770:0eec47f9f8a1 parent: 88771:50aa9e3ab9a4 user: Serhiy Storchaka date: Mon Jan 27 11:21:54 2014 +0200 summary: Issue #19077: tempfile.TemporaryDirectory cleanup no longer fails when called during shutdown. Emitting resource warning in __del__ no longer fails. Original patch by Antoine Pitrou. files: Lib/tempfile.py | 90 ++++++++------------------ Lib/test/test_tempfile.py | 86 +++++++++++-------------- Misc/NEWS | 4 + 3 files changed, 72 insertions(+), 108 deletions(-) diff --git a/Lib/tempfile.py b/Lib/tempfile.py --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -29,11 +29,12 @@ import functools as _functools import warnings as _warnings -import sys as _sys import io as _io import os as _os +import shutil as _shutil import errno as _errno from random import Random as _Random +import weakref as _weakref try: import _thread @@ -335,10 +336,12 @@ underlying file object, without adding a __del__ method to the temporary file.""" + file = None # Set here since __del__ checks it + close_called = False + def __init__(self, file, name, delete=True): self.file = file self.name = name - self.close_called = False self.delete = delete # NT provides delete-on-close as a primitive, so we don't need @@ -350,14 +353,13 @@ # that this must be referenced as self.unlink, because the # name TemporaryFileWrapper may also get None'd out before # __del__ is called. - unlink = _os.unlink - def close(self): - if not self.close_called: + def close(self, unlink=_os.unlink): + if not self.close_called and self.file is not None: self.close_called = True self.file.close() if self.delete: - self.unlink(self.name) + unlink(self.name) # Need to ensure the file is deleted on __del__ def __del__(self): @@ -657,10 +659,23 @@ in it are removed. """ + # Handle mkdtemp raising an exception + name = None + _finalizer = None + _closed = False + def __init__(self, suffix="", prefix=template, dir=None): - self._closed = False - self.name = None # Handle mkdtemp raising an exception self.name = mkdtemp(suffix, prefix, dir) + self._finalizer = _weakref.finalize( + self, self._cleanup, self.name, + warn_message="Implicitly cleaning up {!r}".format(self)) + + @classmethod + def _cleanup(cls, name, warn_message=None): + _shutil.rmtree(name) + if warn_message is not None: + _warnings.warn(warn_message, ResourceWarning) + def __repr__(self): return "<{} {!r}>".format(self.__class__.__name__, self.name) @@ -668,60 +683,13 @@ def __enter__(self): return self.name - def cleanup(self, _warn=False): - if self.name and not self._closed: - try: - self._rmtree(self.name) - except (TypeError, AttributeError) as ex: - # Issue #10188: Emit a warning on stderr - # if the directory could not be cleaned - # up due to missing globals - if "None" not in str(ex): - raise - print("ERROR: {!r} while cleaning up {!r}".format(ex, self,), - file=_sys.stderr) - return - self._closed = True - if _warn: - self._warn("Implicitly cleaning up {!r}".format(self), - ResourceWarning) - def __exit__(self, exc, value, tb): self.cleanup() - def __del__(self): - # Issue a ResourceWarning if implicit cleanup needed - self.cleanup(_warn=True) + def cleanup(self): + if self._finalizer is not None: + self._finalizer.detach() + if self.name is not None and not self._closed: + _shutil.rmtree(self.name) + self._closed = True - # XXX (ncoghlan): The following code attempts to make - # this class tolerant of the module nulling out process - # that happens during CPython interpreter shutdown - # Alas, it doesn't actually manage it. See issue #10188 - _listdir = staticmethod(_os.listdir) - _path_join = staticmethod(_os.path.join) - _isdir = staticmethod(_os.path.isdir) - _islink = staticmethod(_os.path.islink) - _remove = staticmethod(_os.remove) - _rmdir = staticmethod(_os.rmdir) - _warn = _warnings.warn - - def _rmtree(self, path): - # Essentially a stripped down version of shutil.rmtree. We can't - # use globals because they may be None'ed out at shutdown. - for name in self._listdir(path): - fullname = self._path_join(path, name) - try: - isdir = self._isdir(fullname) and not self._islink(fullname) - except OSError: - isdir = False - if isdir: - self._rmtree(fullname) - else: - try: - self._remove(fullname) - except OSError: - pass - try: - self._rmdir(path) - except OSError: - pass diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -11,7 +11,7 @@ import weakref import unittest -from test import support +from test import support, script_helper if hasattr(os, 'stat'): @@ -1088,7 +1088,8 @@ self.nameCheck(tmp.name, dir, pre, suf) # Create a subdirectory and some files if recurse: - self.do_create(tmp.name, pre, suf, recurse-1) + d1 = self.do_create(tmp.name, pre, suf, recurse-1) + d1.name = None with open(os.path.join(tmp.name, "test.txt"), "wb") as f: f.write(b"Hello world!") return tmp @@ -1120,7 +1121,7 @@ def test_cleanup_with_symlink_to_a_directory(self): # cleanup() should not follow symlinks to directories (issue #12464) d1 = self.do_create() - d2 = self.do_create() + d2 = self.do_create(recurse=0) # Symlink d1/foo -> d2 os.symlink(d2.name, os.path.join(d1.name, "foo")) @@ -1150,60 +1151,51 @@ finally: os.rmdir(dir) - @unittest.expectedFailure # See issue #10188 def test_del_on_shutdown(self): # A TemporaryDirectory may be cleaned up during shutdown - # Make sure it works with the relevant modules nulled out with self.do_create() as dir: - d = self.do_create(dir=dir) - # Mimic the nulling out of modules that - # occurs during system shutdown - modules = [os, os.path] - if has_stat: - modules.append(stat) - # Currently broken, so suppress the warning - # that is otherwise emitted on stdout - with support.captured_stderr() as err: - with NulledModules(*modules): - d.cleanup() - # Currently broken, so stop spurious exception by - # indicating the object has already been closed - d._closed = True - # And this assert will fail, as expected by the - # unittest decorator... - self.assertFalse(os.path.exists(d.name), - "TemporaryDirectory %s exists after cleanup" % d.name) + for mod in ('builtins', 'os', 'shutil', 'sys', 'tempfile', 'warnings'): + code = """if True: + import builtins + import os + import shutil + import sys + import tempfile + import warnings + + tmp = tempfile.TemporaryDirectory(dir={dir!r}) + sys.stdout.buffer.write(tmp.name.encode()) + + tmp2 = os.path.join(tmp.name, 'test_dir') + os.mkdir(tmp2) + with open(os.path.join(tmp2, "test.txt"), "w") as f: + f.write("Hello world!") + + {mod}.tmp = tmp + + warnings.filterwarnings("always", category=ResourceWarning) + """.format(dir=dir, mod=mod) + rc, out, err = script_helper.assert_python_ok("-c", code) + tmp_name = out.decode().strip() + self.assertFalse(os.path.exists(tmp_name), + "TemporaryDirectory %s exists after cleanup" % tmp_name) + err = err.decode('utf-8', 'backslashreplace') + self.assertNotIn("Exception ", err) + self.assertIn("ResourceWarning: Implicitly cleaning up", err) def test_warnings_on_cleanup(self): - # Two kinds of warning on shutdown - # Issue 10888: may write to stderr if modules are nulled out - # ResourceWarning will be triggered by __del__ + # ResourceWarning will be triggered by __del__ with self.do_create() as dir: - if os.sep != '\\': - # Embed a backslash in order to make sure string escaping - # in the displayed error message is dealt with correctly - suffix = '\\check_backslash_handling' - else: - suffix = '' - d = self.do_create(dir=dir, suf=suffix) - - #Check for the Issue 10888 message - modules = [os, os.path] - if has_stat: - modules.append(stat) - with support.captured_stderr() as err: - with NulledModules(*modules): - d.cleanup() - message = err.getvalue().replace('\\\\', '\\') - self.assertIn("while cleaning up", message) - self.assertIn(d.name, message) + d = self.do_create(dir=dir, recurse=3) + name = d.name # Check for the resource warning with support.check_warnings(('Implicitly', ResourceWarning), quiet=False): warnings.filterwarnings("always", category=ResourceWarning) - d.__del__() - self.assertFalse(os.path.exists(d.name), - "TemporaryDirectory %s exists after __del__" % d.name) + del d + support.gc_collect() + self.assertFalse(os.path.exists(name), + "TemporaryDirectory %s exists after __del__" % name) def test_multiple_close(self): # Can be cleaned-up many times without error diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -48,6 +48,10 @@ Library ------- +- Issue #19077: tempfile.TemporaryDirectory cleanup no longer fails when + called during shutdown. Emitting resource warning in __del__ no longer fails. + Original patch by Antoine Pitrou. + - Issue #20394: Silence Coverity warning in audioop module. - Issue #20367: Fix behavior of concurrent.futures.as_completed() for -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 10:33:44 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 27 Jan 2014 10:33:44 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Remove_redundant_emty_line?= =?utf-8?q?_at_the_end_of_file=2E?= Message-ID: <3fCQkc3ZBpz7LlS@mail.python.org> http://hg.python.org/cpython/rev/5c9904f8ae60 changeset: 88773:5c9904f8ae60 user: Serhiy Storchaka date: Mon Jan 27 11:27:51 2014 +0200 summary: Remove redundant emty line at the end of file. files: Lib/tempfile.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Lib/tempfile.py b/Lib/tempfile.py --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -692,4 +692,3 @@ if self.name is not None and not self._closed: _shutil.rmtree(self.name) self._closed = True - -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 11:59:05 2014 From: python-checkins at python.org (victor.stinner) Date: Mon, 27 Jan 2014 11:59:05 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_document_the_In?= =?utf-8?q?completeReadError_exception?= Message-ID: <3fCSd55vKTz7LjZ@mail.python.org> http://hg.python.org/cpython/rev/9bff2458b7a0 changeset: 88774:9bff2458b7a0 user: Victor Stinner date: Mon Jan 27 11:58:49 2014 +0100 summary: asyncio: document the IncompleteReadError exception files: Doc/library/asyncio-stream.rst | 21 ++++++++++++++++++++- 1 files changed, 20 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 @@ -98,7 +98,10 @@ .. method:: readexactly(n) - XXX + Read exactly *n* bytes. Raise an :exc:`IncompleteReadError` if the end of + the stream is reached before *n* can be read, the + :attr:`IncompleteReadError.partial` attribute of the exception contains + the partial read bytes. This method returns a :ref:`coroutine object `. @@ -208,6 +211,22 @@ XXX +IncompleteReadError +=================== + +.. exception:: IncompleteReadError + + Incomplete read error. + + .. attribute:: expected + + Total number of expected bytes (:class:`int`). + + .. attribute:: partial + + Read bytes string before the end of stream was reached (:class:`bytes`). + + Example ======= -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 12:18:59 2014 From: python-checkins at python.org (victor.stinner) Date: Mon, 27 Jan 2014 12:18:59 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_IncompleteReadE?= =?utf-8?q?rror_is_a_subclass_of_EOFError?= Message-ID: <3fCT433nvgz7LjW@mail.python.org> http://hg.python.org/cpython/rev/dbad4564cd12 changeset: 88775:dbad4564cd12 user: Victor Stinner date: Mon Jan 27 12:18:49 2014 +0100 summary: asyncio: IncompleteReadError is a subclass of EOFError 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 @@ -216,7 +216,7 @@ .. exception:: IncompleteReadError - Incomplete read error. + Incomplete read error, subclass of :exc:`EOFError`. .. attribute:: expected -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 19:35:41 2014 From: python-checkins at python.org (yury.selivanov) Date: Mon, 27 Jan 2014 19:35:41 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2Egetfile=3A_Don?= =?utf-8?q?=27t_crash_on_classes_without_=27=5F=5Fmodule=5F=5F=27_attribut?= =?utf-8?q?e_=2320372?= Message-ID: <3fCflx3625z7LjV@mail.python.org> http://hg.python.org/cpython/rev/50706164c38f changeset: 88776:50706164c38f user: Yury Selivanov date: Mon Jan 27 13:24:56 2014 -0500 summary: inspect.getfile: Don't crash on classes without '__module__' attribute #20372 Some classes defined in C may not have the '__module__' attribute, so we now handle this case to avoid having unexepected AttributeError. files: Lib/inspect.py | 7 ++++--- Lib/test/test_inspect.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -516,9 +516,10 @@ return object.__file__ raise TypeError('{!r} is a built-in module'.format(object)) if isclass(object): - object = sys.modules.get(object.__module__) - if hasattr(object, '__file__'): - return object.__file__ + if hasattr(object, '__module__'): + object = sys.modules.get(object.__module__) + if hasattr(object, '__file__'): + return object.__file__ raise TypeError('{!r} is a built-in class'.format(object)) if ismethod(object): object = object.__func__ diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -319,6 +319,16 @@ def test_getfile(self): self.assertEqual(inspect.getfile(mod.StupidGit), mod.__file__) + def test_getfile_class_without_module(self): + class CM(type): + @property + def __module__(cls): + raise AttributeError + class C(metaclass=CM): + pass + with self.assertRaises(TypeError): + inspect.getfile(C) + def test_getmodule_recursion(self): from types import ModuleType name = '__inspect_dummy' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 20:27:12 2014 From: python-checkins at python.org (yury.selivanov) Date: Mon, 27 Jan 2014 20:27:12 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_doc/inspect=3A_Clarify_doc?= =?utf-8?q?s_for_=5F=5Fdefaults=5F=5F=2C_add_docs_for_=5F=5Fkwdefaults=5F?= =?utf-8?q?=5F_=2320380?= Message-ID: <3fCgvN2FxWz7LjW@mail.python.org> http://hg.python.org/cpython/rev/fc32459495fc changeset: 88777:fc32459495fc user: Yury Selivanov date: Mon Jan 27 14:26:28 2014 -0500 summary: doc/inspect: Clarify docs for __defaults__, add docs for __kwdefaults__ #20380 files: Doc/library/inspect.rst | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -69,7 +69,12 @@ | | | :term:`bytecode` | +-----------+-----------------+---------------------------+ | | __defaults__ | tuple of any default | -| | | values for arguments | +| | | values for positional or | +| | | keyword parameters | ++-----------+-----------------+---------------------------+ +| | __kwdefaults__ | mapping of any default | +| | | values for keyword-only | +| | | parameters | +-----------+-----------------+---------------------------+ | | __globals__ | global namespace in which | | | | this function was defined | -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 21:08:57 2014 From: python-checkins at python.org (yury.selivanov) Date: Mon, 27 Jan 2014 21:08:57 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2Esignature=3A_Use?= =?utf-8?q?_=27/=27_to_separate_positional-only_parameters_from?= Message-ID: <3fChqY5yXkz7LjP@mail.python.org> http://hg.python.org/cpython/rev/ffe1d684b41e changeset: 88778:ffe1d684b41e user: Yury Selivanov date: Mon Jan 27 15:07:58 2014 -0500 summary: inspect.signature: Use '/' to separate positional-only parameters from the rest in Signature.__str__. #20356 files: Doc/library/inspect.rst | 9 +++- Doc/whatsnew/3.4.rst | 3 + Lib/inspect.py | 53 +++++++++++++++------------ Lib/test/test_inspect.py | 42 +++++++++++++-------- 4 files changed, 64 insertions(+), 43 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -510,9 +510,8 @@ .. attribute:: Parameter.name - The name of the parameter as a string. Must be a valid python identifier - name (with the exception of ``POSITIONAL_ONLY`` parameters, which can have - it set to ``None``). + The name of the parameter as a string. The name must be a valid + Python identifier. .. attribute:: Parameter.default @@ -596,6 +595,10 @@ >>> str(param.replace(default=Parameter.empty, annotation='spam')) "foo:'spam'" + .. versionchanged:: 3.4 + In Python 3.3 Parameter objects were allowed to have ``name`` set + to ``None`` if their ``kind`` was set to ``POSITIONAL_ONLY``. + This is no longer permitted. .. class:: BoundArguments 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 @@ -1488,6 +1488,9 @@ * Support for loading the deprecated ``TYPE_INT64`` has been removed from :mod:`marshal`. (Contributed by Dan Riti in :issue:`15480`.) +* :class:`inspect.Signature`: positional-only parameters are now required + to have a valid name. + Code Cleanups ------------- diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1629,17 +1629,16 @@ self._default = default self._annotation = annotation - if name is None: - if kind != _POSITIONAL_ONLY: - raise ValueError("None is not a valid name for a " - "non-positional-only parameter") - self._name = name - else: - name = str(name) - if kind != _POSITIONAL_ONLY and not name.isidentifier(): - msg = '{!r} is not a valid parameter name'.format(name) - raise ValueError(msg) - self._name = name + if name is _empty: + raise ValueError('name is a required attribute for Parameter') + + if not isinstance(name, str): + raise TypeError("name must be a str, not a {!r}".format(name)) + + if not name.isidentifier(): + raise ValueError('{!r} is not a valid parameter name'.format(name)) + + self._name = name self._partial_kwarg = _partial_kwarg @@ -1683,12 +1682,7 @@ def __str__(self): kind = self.kind - formatted = self._name - if kind == _POSITIONAL_ONLY: - if formatted is None: - formatted = '' - formatted = '<{}>'.format(formatted) # Add annotation and default value if self._annotation is not _empty: @@ -1858,21 +1852,19 @@ for idx, param in enumerate(parameters): kind = param.kind + name = param.name + if kind < top_kind: msg = 'wrong parameter order: {} before {}' - msg = msg.format(top_kind, param.kind) + msg = msg.format(top_kind, kind) raise ValueError(msg) else: top_kind = kind - name = param.name - if name is None: - name = str(idx) - param = param.replace(name=name) - if name in params: msg = 'duplicate parameter name: {!r}'.format(name) raise ValueError(msg) + params[name] = param else: params = OrderedDict(((param.name, param) @@ -2292,11 +2284,21 @@ def __str__(self): result = [] + render_pos_only_separator = False render_kw_only_separator = True - for idx, param in enumerate(self.parameters.values()): + for param in self.parameters.values(): formatted = str(param) kind = param.kind + + if kind == _POSITIONAL_ONLY: + render_pos_only_separator = True + elif render_pos_only_separator: + # It's not a positional-only parameter, and the flag + # is set to 'True' (there were pos-only params before.) + result.append('/') + render_pos_only_separator = False + if kind == _VAR_POSITIONAL: # OK, we have an '*args'-like parameter, so we won't need # a '*' to separate keyword-only arguments @@ -2312,6 +2314,11 @@ result.append(formatted) + if render_pos_only_separator: + # There were only positional-only parameters, hence the + # flag was not reset to 'False' + result.append('/') + rendered = '({})'.format(', '.join(result)) if self.return_annotation is not _empty: diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -2122,6 +2122,7 @@ def test_signature_str_positional_only(self): P = inspect.Parameter + S = inspect.Signature def test(a_po, *, b, **kwargs): return a_po, kwargs @@ -2132,14 +2133,20 @@ test.__signature__ = sig.replace(parameters=new_params) self.assertEqual(str(inspect.signature(test)), - '(, *, b, **kwargs)') - - sig = inspect.signature(test) - new_params = list(sig.parameters.values()) - new_params[0] = new_params[0].replace(name=None) - test.__signature__ = sig.replace(parameters=new_params) - self.assertEqual(str(inspect.signature(test)), - '(<0>, *, b, **kwargs)') + '(a_po, /, *, b, **kwargs)') + + self.assertEqual(str(S(parameters=[P('foo', P.POSITIONAL_ONLY)])), + '(foo, /)') + + self.assertEqual(str(S(parameters=[ + P('foo', P.POSITIONAL_ONLY), + P('bar', P.VAR_KEYWORD)])), + '(foo, /, **bar)') + + self.assertEqual(str(S(parameters=[ + P('foo', P.POSITIONAL_ONLY), + P('bar', P.VAR_POSITIONAL)])), + '(foo, /, *bar)') def test_signature_replace_anno(self): def test() -> 42: @@ -2178,9 +2185,12 @@ with self.assertRaisesRegex(ValueError, 'not a valid parameter name'): inspect.Parameter('1', kind=inspect.Parameter.VAR_KEYWORD) + with self.assertRaisesRegex(TypeError, 'name must be a str'): + inspect.Parameter(None, kind=inspect.Parameter.VAR_KEYWORD) + with self.assertRaisesRegex(ValueError, - 'non-positional-only parameter'): - inspect.Parameter(None, kind=inspect.Parameter.VAR_KEYWORD) + 'is not a valid parameter name'): + inspect.Parameter('$', kind=inspect.Parameter.VAR_KEYWORD) with self.assertRaisesRegex(ValueError, 'cannot have default values'): inspect.Parameter('a', default=42, @@ -2230,7 +2240,8 @@ self.assertEqual(p2.name, 'bar') self.assertNotEqual(p2, p) - with self.assertRaisesRegex(ValueError, 'not a valid parameter name'): + with self.assertRaisesRegex(ValueError, + 'name is a required attribute'): p2 = p2.replace(name=p2.empty) p2 = p2.replace(name='foo', default=None) @@ -2252,14 +2263,11 @@ self.assertEqual(p2, p) def test_signature_parameter_positional_only(self): - p = inspect.Parameter(None, kind=inspect.Parameter.POSITIONAL_ONLY) - self.assertEqual(str(p), '<>') - - p = p.replace(name='1') - self.assertEqual(str(p), '<1>') + with self.assertRaisesRegex(TypeError, 'name must be a str'): + inspect.Parameter(None, kind=inspect.Parameter.POSITIONAL_ONLY) def test_signature_parameter_immutability(self): - p = inspect.Parameter(None, kind=inspect.Parameter.POSITIONAL_ONLY) + p = inspect.Parameter('spam', kind=inspect.Parameter.KEYWORD_ONLY) with self.assertRaises(AttributeError): p.foo = 'bar' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 22:16:45 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 27 Jan 2014 22:16:45 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE5NDU2?= =?utf-8?q?=3A_ntpath=2Ejoin=28=29_now_joins_relative_paths_correctly_when?= =?utf-8?q?_a_drive?= Message-ID: <3fCkKn4msNz7LjV@mail.python.org> http://hg.python.org/cpython/rev/6b314f5c9404 changeset: 88779:6b314f5c9404 branch: 2.7 parent: 88767:323cb02abfc6 user: Serhiy Storchaka date: Mon Jan 27 23:14:51 2014 +0200 summary: Issue #19456: ntpath.join() now joins relative paths correctly when a drive is present. files: Lib/ntpath.py | 79 ++++++++-------------------- Lib/test/test_ntpath.py | 45 ++++++++++++---- Misc/NEWS | 3 + 3 files changed, 60 insertions(+), 67 deletions(-) diff --git a/Lib/ntpath.py b/Lib/ntpath.py --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -59,61 +59,30 @@ # Join two (or more) paths. - -def join(a, *p): - """Join two or more pathname components, inserting "\\" as needed. - If any component is an absolute path, all previous path components - will be discarded.""" - path = a - for b in p: - b_wins = 0 # set to 1 iff b makes path irrelevant - if path == "": - b_wins = 1 - - elif isabs(b): - # This probably wipes out path so far. However, it's more - # complicated if path begins with a drive letter: - # 1. join('c:', '/a') == 'c:/a' - # 2. join('c:/', '/a') == 'c:/a' - # But - # 3. join('c:/a', '/b') == '/b' - # 4. join('c:', 'd:/') = 'd:/' - # 5. join('c:/', 'd:/') = 'd:/' - if path[1:2] != ":" or b[1:2] == ":": - # Path doesn't start with a drive letter, or cases 4 and 5. - b_wins = 1 - - # Else path has a drive letter, and b doesn't but is absolute. - elif len(path) > 3 or (len(path) == 3 and - path[-1] not in "/\\"): - # case 3 - b_wins = 1 - - if b_wins: - path = b - else: - # Join, and ensure there's a separator. - assert len(path) > 0 - if path[-1] in "/\\": - if b and b[0] in "/\\": - path += b[1:] - else: - path += b - elif path[-1] == ":": - path += b - elif b: - if b[0] in "/\\": - path += b - else: - path += "\\" + b - else: - # path is not empty and does not end with a backslash, - # but b is empty; since, e.g., split('a/') produces - # ('a', ''), it's best if join() adds a backslash in - # this case. - path += '\\' - - return path +def join(path, *paths): + """Join two or more pathname components, inserting "\\" as needed.""" + result_drive, result_path = splitdrive(path) + for p in paths: + p_drive, p_path = splitdrive(p) + if p_path and p_path[0] in '\\/': + # Second path is absolute + if p_drive or not result_drive: + result_drive = p_drive + result_path = p_path + continue + elif p_drive and p_drive != result_drive: + if p_drive.lower() != result_drive.lower(): + # Different drives => ignore the first path entirely + result_drive = p_drive + result_path = p_path + continue + # Same drive in different case + result_drive = p_drive + # Second path is relative to the first + if result_path and result_path[-1] not in '\\/': + result_path = result_path + '\\' + result_path = result_path + p_path + return result_drive + result_path # Split a path in a drive specification (a drive letter followed by a diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -85,10 +85,7 @@ tester('ntpath.join("/a")', '/a') tester('ntpath.join("\\a")', '\\a') tester('ntpath.join("a:")', 'a:') - tester('ntpath.join("a:", "b")', 'a:b') - tester('ntpath.join("a:", "/b")', 'a:/b') tester('ntpath.join("a:", "\\b")', 'a:\\b') - tester('ntpath.join("a", "/b")', '/b') tester('ntpath.join("a", "\\b")', '\\b') tester('ntpath.join("a", "b", "c")', 'a\\b\\c') tester('ntpath.join("a\\", "b", "c")', 'a\\b\\c') @@ -96,22 +93,46 @@ tester('ntpath.join("a", "b", "\\c")', '\\c') tester('ntpath.join("d:\\", "\\pleep")', 'd:\\pleep') tester('ntpath.join("d:\\", "a", "b")', 'd:\\a\\b') - tester("ntpath.join('c:', '/a')", 'c:/a') - tester("ntpath.join('c:/', '/a')", 'c:/a') - tester("ntpath.join('c:/a', '/b')", '/b') - tester("ntpath.join('c:', 'd:/')", 'd:/') - tester("ntpath.join('c:/', 'd:/')", 'd:/') - tester("ntpath.join('c:/', 'd:/a/b')", 'd:/a/b') - tester("ntpath.join('')", '') - tester("ntpath.join('', '', '', '', '')", '') - tester("ntpath.join('a')", 'a') tester("ntpath.join('', 'a')", 'a') tester("ntpath.join('', '', '', '', 'a')", 'a') tester("ntpath.join('a', '')", 'a\\') tester("ntpath.join('a', '', '', '', '')", 'a\\') tester("ntpath.join('a\\', '')", 'a\\') tester("ntpath.join('a\\', '', '', '', '')", 'a\\') + tester("ntpath.join('a/', '')", 'a/') + + tester("ntpath.join('a/b', 'x/y')", 'a/b\\x/y') + tester("ntpath.join('/a/b', 'x/y')", '/a/b\\x/y') + tester("ntpath.join('/a/b/', 'x/y')", '/a/b/x/y') + tester("ntpath.join('c:', 'x/y')", 'c:x/y') + tester("ntpath.join('c:a/b', 'x/y')", 'c:a/b\\x/y') + tester("ntpath.join('c:a/b/', 'x/y')", 'c:a/b/x/y') + tester("ntpath.join('c:/', 'x/y')", 'c:/x/y') + tester("ntpath.join('c:/a/b', 'x/y')", 'c:/a/b\\x/y') + tester("ntpath.join('c:/a/b/', 'x/y')", 'c:/a/b/x/y') + #tester("ntpath.join('//computer/share', 'x/y')", '//computer/share\\x/y') + #tester("ntpath.join('//computer/share/', 'x/y')", '//computer/share/x/y') + #tester("ntpath.join('//computer/share/a/b', 'x/y')", '//computer/share/a/b\\x/y') + + tester("ntpath.join('a/b', '/x/y')", '/x/y') + tester("ntpath.join('/a/b', '/x/y')", '/x/y') + tester("ntpath.join('c:', '/x/y')", 'c:/x/y') + tester("ntpath.join('c:a/b', '/x/y')", 'c:/x/y') + tester("ntpath.join('c:/', '/x/y')", 'c:/x/y') + tester("ntpath.join('c:/a/b', '/x/y')", 'c:/x/y') + #tester("ntpath.join('//computer/share', '/x/y')", '//computer/share/x/y') + #tester("ntpath.join('//computer/share/', '/x/y')", '//computer/share/x/y') + #tester("ntpath.join('//computer/share/a', '/x/y')", '//computer/share/x/y') + + tester("ntpath.join('c:', 'C:x/y')", 'C:x/y') + tester("ntpath.join('c:a/b', 'C:x/y')", 'C:a/b\\x/y') + tester("ntpath.join('c:/', 'C:x/y')", 'C:/x/y') + tester("ntpath.join('c:/a/b', 'C:x/y')", 'C:/a/b\\x/y') + + for x in ('', 'a/b', '/a/b', 'c:', 'c:a/b', 'c:/', 'c:/a/b'): + for y in ('d:', 'd:x/y', 'd:/', 'd:/x/y'): + tester("ntpath.join(%r, %r)" % (x, y), y) def test_normpath(self): tester("ntpath.normpath('A//////././//.//B')", r'A\B') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -38,6 +38,9 @@ Library ------- +- Issue #19456: ntpath.join() now joins relative paths correctly when a drive + is present. + - Issue #8260: The read(), readline() and readlines() methods of codecs.StreamReader returned incomplete data when were called after readline() or read(size). Based on patch by Amaury Forgeot d'Arc. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 22:16:47 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 27 Jan 2014 22:16:47 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE5NDU2?= =?utf-8?q?=3A_ntpath=2Ejoin=28=29_now_joins_relative_paths_correctly_when?= =?utf-8?q?_a_drive?= Message-ID: <3fCkKq1Kjwz7LjM@mail.python.org> http://hg.python.org/cpython/rev/f4377699fd47 changeset: 88780:f4377699fd47 branch: 3.3 parent: 88771:50aa9e3ab9a4 user: Serhiy Storchaka date: Mon Jan 27 23:15:14 2014 +0200 summary: Issue #19456: ntpath.join() now joins relative paths correctly when a drive is present. files: Lib/ntpath.py | 106 +++++++-------------------- Lib/test/test_ntpath.py | 63 ++++++++------- Misc/NEWS | 3 + 3 files changed, 66 insertions(+), 106 deletions(-) diff --git a/Lib/ntpath.py b/Lib/ntpath.py --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -104,82 +104,36 @@ # Join two (or more) paths. - -def join(a, *p): - """Join two or more pathname components, inserting "\\" as needed. - If any component is an absolute path, all previous path components - will be discarded.""" - sep = _get_sep(a) - seps = _get_bothseps(a) - colon = _get_colon(a) - path = a - for b in p: - b_wins = 0 # set to 1 iff b makes path irrelevant - if not path: - b_wins = 1 - - elif isabs(b): - # This probably wipes out path so far. However, it's more - # complicated if path begins with a drive letter. You get a+b - # (minus redundant slashes) in these four cases: - # 1. join('c:', '/a') == 'c:/a' - # 2. join('//computer/share', '/a') == '//computer/share/a' - # 3. join('c:/', '/a') == 'c:/a' - # 4. join('//computer/share/', '/a') == '//computer/share/a' - # But b wins in all of these cases: - # 5. join('c:/a', '/b') == '/b' - # 6. join('//computer/share/a', '/b') == '/b' - # 7. join('c:', 'd:/') == 'd:/' - # 8. join('c:', '//computer/share/') == '//computer/share/' - # 9. join('//computer/share', 'd:/') == 'd:/' - # 10. join('//computer/share', '//computer/share/') == '//computer/share/' - # 11. join('c:/', 'd:/') == 'd:/' - # 12. join('c:/', '//computer/share/') == '//computer/share/' - # 13. join('//computer/share/', 'd:/') == 'd:/' - # 14. join('//computer/share/', '//computer/share/') == '//computer/share/' - b_prefix, b_rest = splitdrive(b) - - # if b has a prefix, it always wins. - if b_prefix: - b_wins = 1 - else: - # b doesn't have a prefix. - # but isabs(b) returned true. - # and therefore b_rest[0] must be a slash. - # (but let's check that.) - assert(b_rest and b_rest[0] in seps) - - # so, b still wins if path has a rest that's more than a sep. - # you get a+b if path_rest is empty or only has a sep. - # (see cases 1-4 for times when b loses.) - path_rest = splitdrive(path)[1] - b_wins = path_rest and path_rest not in seps - - if b_wins: - path = b - else: - # Join, and ensure there's a separator. - assert len(path) > 0 - if path[-1:] in seps: - if b and b[:1] in seps: - path += b[1:] - else: - path += b - elif path[-1:] == colon: - path += b - elif b: - if b[:1] in seps: - path += b - else: - path += sep + b - else: - # path is not empty and does not end with a backslash, - # but b is empty; since, e.g., split('a/') produces - # ('a', ''), it's best if join() adds a backslash in - # this case. - path += sep - - return path +def join(path, *paths): + sep = _get_sep(path) + seps = _get_bothseps(path) + colon = _get_colon(path) + result_drive, result_path = splitdrive(path) + for p in paths: + p_drive, p_path = splitdrive(p) + if p_path and p_path[0] in seps: + # Second path is absolute + if p_drive or not result_drive: + result_drive = p_drive + result_path = p_path + continue + elif p_drive and p_drive != result_drive: + if p_drive.lower() != result_drive.lower(): + # Different drives => ignore the first path entirely + result_drive = p_drive + result_path = p_path + continue + # Same drive in different case + result_drive = p_drive + # Second path is relative to the first + if result_path and result_path[-1] not in seps: + result_path = result_path + sep + result_path = result_path + p_path + ## add separator between UNC and non-absolute path + if (result_path and result_path[0] not in seps and + result_drive and result_drive[-1:] != colon): + return result_drive + sep + result_path + return result_drive + result_path # Split a path in a drive specification (a drive letter followed by a diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -126,10 +126,7 @@ tester('ntpath.join("/a")', '/a') tester('ntpath.join("\\a")', '\\a') tester('ntpath.join("a:")', 'a:') - tester('ntpath.join("a:", "b")', 'a:b') - tester('ntpath.join("a:", "/b")', 'a:/b') tester('ntpath.join("a:", "\\b")', 'a:\\b') - tester('ntpath.join("a", "/b")', '/b') tester('ntpath.join("a", "\\b")', '\\b') tester('ntpath.join("a", "b", "c")', 'a\\b\\c') tester('ntpath.join("a\\", "b", "c")', 'a\\b\\c') @@ -137,42 +134,48 @@ tester('ntpath.join("a", "b", "\\c")', '\\c') tester('ntpath.join("d:\\", "\\pleep")', 'd:\\pleep') tester('ntpath.join("d:\\", "a", "b")', 'd:\\a\\b') - tester("ntpath.join('c:', '/a')", 'c:/a') - tester("ntpath.join('c:/', '/a')", 'c:/a') - tester("ntpath.join('c:/a', '/b')", '/b') - tester("ntpath.join('c:', 'd:/')", 'd:/') - tester("ntpath.join('c:/', 'd:/')", 'd:/') - tester("ntpath.join('c:/', 'd:/a/b')", 'd:/a/b') - tester("ntpath.join('')", '') - tester("ntpath.join('', '', '', '', '')", '') - tester("ntpath.join('a')", 'a') tester("ntpath.join('', 'a')", 'a') tester("ntpath.join('', '', '', '', 'a')", 'a') tester("ntpath.join('a', '')", 'a\\') tester("ntpath.join('a', '', '', '', '')", 'a\\') tester("ntpath.join('a\\', '')", 'a\\') tester("ntpath.join('a\\', '', '', '', '')", 'a\\') + tester("ntpath.join('a/', '')", 'a/') - # from comment in ntpath.join - tester("ntpath.join('c:', '/a')", 'c:/a') - tester("ntpath.join('//computer/share', '/a')", '//computer/share/a') - tester("ntpath.join('c:/', '/a')", 'c:/a') - tester("ntpath.join('//computer/share/', '/a')", '//computer/share/a') - tester("ntpath.join('c:/a', '/b')", '/b') - tester("ntpath.join('//computer/share/a', '/b')", '/b') - tester("ntpath.join('c:', 'd:/')", 'd:/') - tester("ntpath.join('c:', '//computer/share/')", '//computer/share/') - tester("ntpath.join('//computer/share', 'd:/')", 'd:/') - tester("ntpath.join('//computer/share', '//computer/share/')", '//computer/share/') - tester("ntpath.join('c:/', 'd:/')", 'd:/') - tester("ntpath.join('c:/', '//computer/share/')", '//computer/share/') - tester("ntpath.join('//computer/share/', 'd:/')", 'd:/') - tester("ntpath.join('//computer/share/', '//computer/share/')", '//computer/share/') + tester("ntpath.join('a/b', 'x/y')", 'a/b\\x/y') + tester("ntpath.join('/a/b', 'x/y')", '/a/b\\x/y') + tester("ntpath.join('/a/b/', 'x/y')", '/a/b/x/y') + tester("ntpath.join('c:', 'x/y')", 'c:x/y') + tester("ntpath.join('c:a/b', 'x/y')", 'c:a/b\\x/y') + tester("ntpath.join('c:a/b/', 'x/y')", 'c:a/b/x/y') + tester("ntpath.join('c:/', 'x/y')", 'c:/x/y') + tester("ntpath.join('c:/a/b', 'x/y')", 'c:/a/b\\x/y') + tester("ntpath.join('c:/a/b/', 'x/y')", 'c:/a/b/x/y') + tester("ntpath.join('//computer/share', 'x/y')", '//computer/share\\x/y') + tester("ntpath.join('//computer/share/', 'x/y')", '//computer/share/x/y') + tester("ntpath.join('//computer/share/a/b', 'x/y')", '//computer/share/a/b\\x/y') - tester("ntpath.join('c:', '//computer/share/')", '//computer/share/') - tester("ntpath.join('c:/', '//computer/share/')", '//computer/share/') - tester("ntpath.join('c:/', '//computer/share/a/b')", '//computer/share/a/b') + tester("ntpath.join('a/b', '/x/y')", '/x/y') + tester("ntpath.join('/a/b', '/x/y')", '/x/y') + tester("ntpath.join('c:', '/x/y')", 'c:/x/y') + tester("ntpath.join('c:a/b', '/x/y')", 'c:/x/y') + tester("ntpath.join('c:/', '/x/y')", 'c:/x/y') + tester("ntpath.join('c:/a/b', '/x/y')", 'c:/x/y') + tester("ntpath.join('//computer/share', '/x/y')", '//computer/share/x/y') + tester("ntpath.join('//computer/share/', '/x/y')", '//computer/share/x/y') + tester("ntpath.join('//computer/share/a', '/x/y')", '//computer/share/x/y') + + tester("ntpath.join('c:', 'C:x/y')", 'C:x/y') + tester("ntpath.join('c:a/b', 'C:x/y')", 'C:a/b\\x/y') + tester("ntpath.join('c:/', 'C:x/y')", 'C:/x/y') + tester("ntpath.join('c:/a/b', 'C:x/y')", 'C:/a/b\\x/y') + + for x in ('', 'a/b', '/a/b', 'c:', 'c:a/b', 'c:/', 'c:/a/b', + '//computer/share', '//computer/share/', '//computer/share/a/b'): + for y in ('d:', 'd:x/y', 'd:/', 'd:/x/y', + '//machine/common', '//machine/common/', '//machine/common/x/y'): + tester("ntpath.join(%r, %r)" % (x, y), y) tester("ntpath.join('\\\\computer\\share\\', 'a', 'b')", '\\\\computer\\share\\a\\b') tester("ntpath.join('\\\\computer\\share', 'a', 'b')", '\\\\computer\\share\\a\\b') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -50,6 +50,9 @@ Library ------- +- Issue #19456: ntpath.join() now joins relative paths correctly when a drive + is present. + - Issue #19077: tempfile.TemporaryDirectory cleanup is now most likely successful when called during nulling out of modules during shutdown. Misleading exception no longer raised when resource warning is emitted -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 22:16:49 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 27 Jan 2014 22:16:49 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2319456=3A_ntpath=2Ejoin=28=29_now_joins_relative?= =?utf-8?q?_paths_correctly_when_a_drive?= Message-ID: <3fCkKs5SKJz7Lk2@mail.python.org> http://hg.python.org/cpython/rev/7ce464ba615a changeset: 88781:7ce464ba615a parent: 88778:ffe1d684b41e parent: 88780:f4377699fd47 user: Serhiy Storchaka date: Mon Jan 27 23:16:28 2014 +0200 summary: Issue #19456: ntpath.join() now joins relative paths correctly when a drive is present. files: Lib/ntpath.py | 106 +++++++-------------------- Lib/test/test_ntpath.py | 63 ++++++++------- Misc/NEWS | 3 + 3 files changed, 66 insertions(+), 106 deletions(-) diff --git a/Lib/ntpath.py b/Lib/ntpath.py --- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -101,82 +101,36 @@ # Join two (or more) paths. - -def join(a, *p): - """Join two or more pathname components, inserting "\\" as needed. - If any component is an absolute path, all previous path components - will be discarded.""" - sep = _get_sep(a) - seps = _get_bothseps(a) - colon = _get_colon(a) - path = a - for b in p: - b_wins = 0 # set to 1 iff b makes path irrelevant - if not path: - b_wins = 1 - - elif isabs(b): - # This probably wipes out path so far. However, it's more - # complicated if path begins with a drive letter. You get a+b - # (minus redundant slashes) in these four cases: - # 1. join('c:', '/a') == 'c:/a' - # 2. join('//computer/share', '/a') == '//computer/share/a' - # 3. join('c:/', '/a') == 'c:/a' - # 4. join('//computer/share/', '/a') == '//computer/share/a' - # But b wins in all of these cases: - # 5. join('c:/a', '/b') == '/b' - # 6. join('//computer/share/a', '/b') == '/b' - # 7. join('c:', 'd:/') == 'd:/' - # 8. join('c:', '//computer/share/') == '//computer/share/' - # 9. join('//computer/share', 'd:/') == 'd:/' - # 10. join('//computer/share', '//computer/share/') == '//computer/share/' - # 11. join('c:/', 'd:/') == 'd:/' - # 12. join('c:/', '//computer/share/') == '//computer/share/' - # 13. join('//computer/share/', 'd:/') == 'd:/' - # 14. join('//computer/share/', '//computer/share/') == '//computer/share/' - b_prefix, b_rest = splitdrive(b) - - # if b has a prefix, it always wins. - if b_prefix: - b_wins = 1 - else: - # b doesn't have a prefix. - # but isabs(b) returned true. - # and therefore b_rest[0] must be a slash. - # (but let's check that.) - assert(b_rest and b_rest[0] in seps) - - # so, b still wins if path has a rest that's more than a sep. - # you get a+b if path_rest is empty or only has a sep. - # (see cases 1-4 for times when b loses.) - path_rest = splitdrive(path)[1] - b_wins = path_rest and path_rest not in seps - - if b_wins: - path = b - else: - # Join, and ensure there's a separator. - assert len(path) > 0 - if path[-1:] in seps: - if b and b[:1] in seps: - path += b[1:] - else: - path += b - elif path[-1:] == colon: - path += b - elif b: - if b[:1] in seps: - path += b - else: - path += sep + b - else: - # path is not empty and does not end with a backslash, - # but b is empty; since, e.g., split('a/') produces - # ('a', ''), it's best if join() adds a backslash in - # this case. - path += sep - - return path +def join(path, *paths): + sep = _get_sep(path) + seps = _get_bothseps(path) + colon = _get_colon(path) + result_drive, result_path = splitdrive(path) + for p in paths: + p_drive, p_path = splitdrive(p) + if p_path and p_path[0] in seps: + # Second path is absolute + if p_drive or not result_drive: + result_drive = p_drive + result_path = p_path + continue + elif p_drive and p_drive != result_drive: + if p_drive.lower() != result_drive.lower(): + # Different drives => ignore the first path entirely + result_drive = p_drive + result_path = p_path + continue + # Same drive in different case + result_drive = p_drive + # Second path is relative to the first + if result_path and result_path[-1] not in seps: + result_path = result_path + sep + result_path = result_path + p_path + ## add separator between UNC and non-absolute path + if (result_path and result_path[0] not in seps and + result_drive and result_drive[-1:] != colon): + return result_drive + sep + result_path + return result_drive + result_path # Split a path in a drive specification (a drive letter followed by a diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -126,10 +126,7 @@ tester('ntpath.join("/a")', '/a') tester('ntpath.join("\\a")', '\\a') tester('ntpath.join("a:")', 'a:') - tester('ntpath.join("a:", "b")', 'a:b') - tester('ntpath.join("a:", "/b")', 'a:/b') tester('ntpath.join("a:", "\\b")', 'a:\\b') - tester('ntpath.join("a", "/b")', '/b') tester('ntpath.join("a", "\\b")', '\\b') tester('ntpath.join("a", "b", "c")', 'a\\b\\c') tester('ntpath.join("a\\", "b", "c")', 'a\\b\\c') @@ -137,42 +134,48 @@ tester('ntpath.join("a", "b", "\\c")', '\\c') tester('ntpath.join("d:\\", "\\pleep")', 'd:\\pleep') tester('ntpath.join("d:\\", "a", "b")', 'd:\\a\\b') - tester("ntpath.join('c:', '/a')", 'c:/a') - tester("ntpath.join('c:/', '/a')", 'c:/a') - tester("ntpath.join('c:/a', '/b')", '/b') - tester("ntpath.join('c:', 'd:/')", 'd:/') - tester("ntpath.join('c:/', 'd:/')", 'd:/') - tester("ntpath.join('c:/', 'd:/a/b')", 'd:/a/b') - tester("ntpath.join('')", '') - tester("ntpath.join('', '', '', '', '')", '') - tester("ntpath.join('a')", 'a') tester("ntpath.join('', 'a')", 'a') tester("ntpath.join('', '', '', '', 'a')", 'a') tester("ntpath.join('a', '')", 'a\\') tester("ntpath.join('a', '', '', '', '')", 'a\\') tester("ntpath.join('a\\', '')", 'a\\') tester("ntpath.join('a\\', '', '', '', '')", 'a\\') + tester("ntpath.join('a/', '')", 'a/') - # from comment in ntpath.join - tester("ntpath.join('c:', '/a')", 'c:/a') - tester("ntpath.join('//computer/share', '/a')", '//computer/share/a') - tester("ntpath.join('c:/', '/a')", 'c:/a') - tester("ntpath.join('//computer/share/', '/a')", '//computer/share/a') - tester("ntpath.join('c:/a', '/b')", '/b') - tester("ntpath.join('//computer/share/a', '/b')", '/b') - tester("ntpath.join('c:', 'd:/')", 'd:/') - tester("ntpath.join('c:', '//computer/share/')", '//computer/share/') - tester("ntpath.join('//computer/share', 'd:/')", 'd:/') - tester("ntpath.join('//computer/share', '//computer/share/')", '//computer/share/') - tester("ntpath.join('c:/', 'd:/')", 'd:/') - tester("ntpath.join('c:/', '//computer/share/')", '//computer/share/') - tester("ntpath.join('//computer/share/', 'd:/')", 'd:/') - tester("ntpath.join('//computer/share/', '//computer/share/')", '//computer/share/') + tester("ntpath.join('a/b', 'x/y')", 'a/b\\x/y') + tester("ntpath.join('/a/b', 'x/y')", '/a/b\\x/y') + tester("ntpath.join('/a/b/', 'x/y')", '/a/b/x/y') + tester("ntpath.join('c:', 'x/y')", 'c:x/y') + tester("ntpath.join('c:a/b', 'x/y')", 'c:a/b\\x/y') + tester("ntpath.join('c:a/b/', 'x/y')", 'c:a/b/x/y') + tester("ntpath.join('c:/', 'x/y')", 'c:/x/y') + tester("ntpath.join('c:/a/b', 'x/y')", 'c:/a/b\\x/y') + tester("ntpath.join('c:/a/b/', 'x/y')", 'c:/a/b/x/y') + tester("ntpath.join('//computer/share', 'x/y')", '//computer/share\\x/y') + tester("ntpath.join('//computer/share/', 'x/y')", '//computer/share/x/y') + tester("ntpath.join('//computer/share/a/b', 'x/y')", '//computer/share/a/b\\x/y') - tester("ntpath.join('c:', '//computer/share/')", '//computer/share/') - tester("ntpath.join('c:/', '//computer/share/')", '//computer/share/') - tester("ntpath.join('c:/', '//computer/share/a/b')", '//computer/share/a/b') + tester("ntpath.join('a/b', '/x/y')", '/x/y') + tester("ntpath.join('/a/b', '/x/y')", '/x/y') + tester("ntpath.join('c:', '/x/y')", 'c:/x/y') + tester("ntpath.join('c:a/b', '/x/y')", 'c:/x/y') + tester("ntpath.join('c:/', '/x/y')", 'c:/x/y') + tester("ntpath.join('c:/a/b', '/x/y')", 'c:/x/y') + tester("ntpath.join('//computer/share', '/x/y')", '//computer/share/x/y') + tester("ntpath.join('//computer/share/', '/x/y')", '//computer/share/x/y') + tester("ntpath.join('//computer/share/a', '/x/y')", '//computer/share/x/y') + + tester("ntpath.join('c:', 'C:x/y')", 'C:x/y') + tester("ntpath.join('c:a/b', 'C:x/y')", 'C:a/b\\x/y') + tester("ntpath.join('c:/', 'C:x/y')", 'C:/x/y') + tester("ntpath.join('c:/a/b', 'C:x/y')", 'C:/a/b\\x/y') + + for x in ('', 'a/b', '/a/b', 'c:', 'c:a/b', 'c:/', 'c:/a/b', + '//computer/share', '//computer/share/', '//computer/share/a/b'): + for y in ('d:', 'd:x/y', 'd:/', 'd:/x/y', + '//machine/common', '//machine/common/', '//machine/common/x/y'): + tester("ntpath.join(%r, %r)" % (x, y), y) tester("ntpath.join('\\\\computer\\share\\', 'a', 'b')", '\\\\computer\\share\\a\\b') tester("ntpath.join('\\\\computer\\share', 'a', 'b')", '\\\\computer\\share\\a\\b') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -48,6 +48,9 @@ Library ------- +- Issue #19456: ntpath.join() now joins relative paths correctly when a drive + is present. + - Issue #19077: tempfile.TemporaryDirectory cleanup no longer fails when called during shutdown. Emitting resource warning in __del__ no longer fails. Original patch by Antoine Pitrou. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 23:02:13 2014 From: python-checkins at python.org (victor.stinner) Date: Mon, 27 Jan 2014 23:02:13 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio_doc=3A_subprocess?= =?utf-8?q?=5Fexec/subprocess=5Fshell_are_not_available_on_Windows?= Message-ID: <3fClLF3Rq4z7LjX@mail.python.org> http://hg.python.org/cpython/rev/868da4813af2 changeset: 88782:868da4813af2 user: Victor Stinner date: Mon Jan 27 23:01:41 2014 +0100 summary: asyncio doc: subprocess_exec/subprocess_shell are not available on Windows files: Doc/library/asyncio-eventloop.rst | 4 ++++ 1 files changed, 4 insertions(+), 0 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 @@ -294,6 +294,8 @@ See the constructor of the :class:`subprocess.Popen` class for parameters. + Availability: Unix. + .. method:: BaseEventLoop.subprocess_shell(protocol_factory, cmd, \*, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=False, shell=True, bufsize=0, \*\*kwargs) XXX @@ -302,6 +304,8 @@ See the constructor of the :class:`subprocess.Popen` class for parameters. + Availability: Unix. + .. method:: BaseEventLoop.connect_read_pipe(protocol_factory, pipe) Register read pipe in eventloop. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon Jan 27 23:29:06 2014 From: python-checkins at python.org (yury.selivanov) Date: Mon, 27 Jan 2014 23:29:06 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2Esignature=3A_Add?= =?utf-8?q?_support_for_=27functools=2Epartialmethod=27_=2320223?= Message-ID: <3fClxG3pgKz7LjV@mail.python.org> http://hg.python.org/cpython/rev/baedc256999a changeset: 88783:baedc256999a user: Yury Selivanov date: Mon Jan 27 17:28:37 2014 -0500 summary: inspect.signature: Add support for 'functools.partialmethod' #20223 files: Lib/functools.py | 1 + Lib/inspect.py | 107 ++++++++++++++++---------- Lib/test/test_inspect.py | 27 ++++++ 3 files changed, 95 insertions(+), 40 deletions(-) diff --git a/Lib/functools.py b/Lib/functools.py --- a/Lib/functools.py +++ b/Lib/functools.py @@ -290,6 +290,7 @@ call_args = (cls_or_self,) + self.args + tuple(rest) return self.func(*call_args, **call_keywords) _method.__isabstractmethod__ = self.__isabstractmethod__ + _method._partialmethod = self return _method def __get__(self, obj, cls): diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1440,6 +1440,51 @@ return meth +def _get_partial_signature(wrapped_sig, partial, extra_args=()): + new_params = OrderedDict(wrapped_sig.parameters.items()) + + partial_args = partial.args or () + partial_keywords = partial.keywords or {} + + if extra_args: + partial_args = extra_args + partial_args + + try: + ba = wrapped_sig.bind_partial(*partial_args, **partial_keywords) + except TypeError as ex: + msg = 'partial object {!r} has incorrect arguments'.format(partial) + raise ValueError(msg) from ex + + for arg_name, arg_value in ba.arguments.items(): + param = new_params[arg_name] + if arg_name in partial_keywords: + # We set a new default value, because the following code + # is correct: + # + # >>> def foo(a): print(a) + # >>> print(partial(partial(foo, a=10), a=20)()) + # 20 + # >>> print(partial(partial(foo, a=10), a=20)(a=30)) + # 30 + # + # So, with 'partial' objects, passing a keyword argument is + # like setting a new default value for the corresponding + # parameter + # + # We also mark this parameter with '_partial_kwarg' + # flag. Later, in '_bind', the 'default' value of this + # parameter will be added to 'kwargs', to simulate + # the 'functools.partial' real call. + new_params[arg_name] = param.replace(default=arg_value, + _partial_kwarg=True) + + elif (param.kind not in (_VAR_KEYWORD, _VAR_POSITIONAL) and + not param._partial_kwarg): + new_params.pop(arg_name) + + return wrapped_sig.replace(parameters=new_params.values()) + + def signature(obj): '''Get a signature object for the passed callable.''' @@ -1470,50 +1515,32 @@ if sig is not None: return sig + try: + partialmethod = obj._partialmethod + except AttributeError: + pass + else: + # Unbound partialmethod (see functools.partialmethod) + # This means, that we need to calculate the signature + # as if it's a regular partial object, but taking into + # account that the first positional argument + # (usually `self`, or `cls`) will not be passed + # automatically (as for boundmethods) + + wrapped_sig = signature(partialmethod.func) + sig = _get_partial_signature(wrapped_sig, partialmethod, (None,)) + + first_wrapped_param = tuple(wrapped_sig.parameters.values())[0] + new_params = (first_wrapped_param,) + tuple(sig.parameters.values()) + + return sig.replace(parameters=new_params) + if isinstance(obj, types.FunctionType): return Signature.from_function(obj) if isinstance(obj, functools.partial): - sig = signature(obj.func) - - new_params = OrderedDict(sig.parameters.items()) - - partial_args = obj.args or () - partial_keywords = obj.keywords or {} - try: - ba = sig.bind_partial(*partial_args, **partial_keywords) - except TypeError as ex: - msg = 'partial object {!r} has incorrect arguments'.format(obj) - raise ValueError(msg) from ex - - for arg_name, arg_value in ba.arguments.items(): - param = new_params[arg_name] - if arg_name in partial_keywords: - # We set a new default value, because the following code - # is correct: - # - # >>> def foo(a): print(a) - # >>> print(partial(partial(foo, a=10), a=20)()) - # 20 - # >>> print(partial(partial(foo, a=10), a=20)(a=30)) - # 30 - # - # So, with 'partial' objects, passing a keyword argument is - # like setting a new default value for the corresponding - # parameter - # - # We also mark this parameter with '_partial_kwarg' - # flag. Later, in '_bind', the 'default' value of this - # parameter will be added to 'kwargs', to simulate - # the 'functools.partial' real call. - new_params[arg_name] = param.replace(default=arg_value, - _partial_kwarg=True) - - elif (param.kind not in (_VAR_KEYWORD, _VAR_POSITIONAL) and - not param._partial_kwarg): - new_params.pop(arg_name) - - return sig.replace(parameters=new_params.values()) + wrapped_sig = signature(obj.func) + return _get_partial_signature(wrapped_sig, obj) sig = None if isinstance(obj, type): diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1877,6 +1877,33 @@ ba = inspect.signature(_foo).bind(12, 14) self.assertEqual(_foo(*ba.args, **ba.kwargs), (12, 14, 13)) + def test_signature_on_partialmethod(self): + from functools import partialmethod + + class Spam: + def test(): + pass + ham = partialmethod(test) + + with self.assertRaisesRegex(ValueError, "has incorrect arguments"): + inspect.signature(Spam.ham) + + class Spam: + def test(it, a, *, c) -> 'spam': + pass + ham = partialmethod(test, c=1) + + self.assertEqual(self.signature(Spam.ham), + ((('it', ..., ..., 'positional_or_keyword'), + ('a', ..., ..., 'positional_or_keyword'), + ('c', 1, ..., 'keyword_only')), + 'spam')) + + self.assertEqual(self.signature(Spam().ham), + ((('a', ..., ..., 'positional_or_keyword'), + ('c', 1, ..., 'keyword_only')), + 'spam')) + def test_signature_on_decorated(self): import functools -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 28 00:09:35 2014 From: python-checkins at python.org (victor.stinner) Date: Tue, 28 Jan 2014 00:09:35 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_remove_temporar?= =?utf-8?q?y_aliases?= Message-ID: <3fCmqz1Wkvz7Ljd@mail.python.org> http://hg.python.org/cpython/rev/a0ecf4155087 changeset: 88784:a0ecf4155087 user: Victor Stinner date: Tue Jan 28 00:09:24 2014 +0100 summary: asyncio: remove temporary aliases files: Lib/asyncio/queues.py | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-) diff --git a/Lib/asyncio/queues.py b/Lib/asyncio/queues.py --- a/Lib/asyncio/queues.py +++ b/Lib/asyncio/queues.py @@ -22,12 +22,6 @@ pass -# Un-exported aliases for temporary backward compatibility. -# Will disappear soon. -Full = QueueFull -Empty = QueueEmpty - - class Queue: """A queue, useful for coordinating producer and consumer coroutines. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 28 01:31:12 2014 From: python-checkins at python.org (yury.selivanov) Date: Tue, 28 Jan 2014 01:31:12 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2Esignature=3A_Sup?= =?utf-8?q?port_classes_without_user-defined_=5F=5Finit=5F=5F/=5F=5Fnew=5F?= =?utf-8?q?=5F_=2320308?= Message-ID: <3fCpf82tHrz7LjW@mail.python.org> http://hg.python.org/cpython/rev/b9ca2019bcb9 changeset: 88785:b9ca2019bcb9 user: Yury Selivanov date: Mon Jan 27 19:29:45 2014 -0500 summary: inspect.signature: Support classes without user-defined __init__/__new__ #20308 files: Lib/inspect.py | 11 +++++++++++ Lib/test/test_inspect.py | 14 ++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 28 insertions(+), 0 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1561,6 +1561,17 @@ init = _get_user_defined_method(obj, '__init__') if init is not None: sig = signature(init) + + if sig is None: + if type in obj.__mro__: + # 'obj' is a metaclass without user-defined __init__ + # or __new__. Return a signature of 'type' builtin. + return signature(type) + else: + # We have a class (not metaclass), but no user-defined + # __init__ or __new__ for it + return signature(object) + elif not isinstance(obj, _NonUserDefinedCallables): # An object with __call__ # We also check that the 'obj' is not an instance of diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -2045,6 +2045,20 @@ ('bar', 2, ..., "keyword_only")), ...)) + # Test classes without user-defined __init__ or __new__ + class C: pass + self.assertEqual(str(inspect.signature(C)), '()') + class D(C): pass + self.assertEqual(str(inspect.signature(D)), '()') + + # Test meta-classes without user-defined __init__ or __new__ + class C(type): pass + self.assertEqual(str(inspect.signature(C)), + '(object_or_name, bases, dict)') + class D(C): pass + self.assertEqual(str(inspect.signature(D)), + '(object_or_name, bases, dict)') + def test_signature_on_callable_objects(self): class Foo: def __call__(self, a): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #20308: inspect.signature now works on classes without user-defined + __init__ or __new__ methods. + What's New in Python 3.4.0 Beta 3? ================================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 28 01:40:36 2014 From: python-checkins at python.org (yury.selivanov) Date: Tue, 28 Jan 2014 01:40:36 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_NEWS=3A_Add_few_missing_ne?= =?utf-8?q?ws_items?= Message-ID: <3fCps00jcXzS64@mail.python.org> http://hg.python.org/cpython/rev/6f8d79ceb758 changeset: 88786:6f8d79ceb758 user: Yury Selivanov date: Mon Jan 27 19:40:07 2014 -0500 summary: NEWS: Add few missing news items files: Misc/NEWS | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -16,6 +16,16 @@ - Issue #20308: inspect.signature now works on classes without user-defined __init__ or __new__ methods. +- Issue #20372: inspect.getfile (and a bunch of other inspect functions that + use it) doesn't crash with unexpected AttributeError on classes defined in C + without __module__. + +- Issue #20356: inspect.signature formatting uses '/' to separate + positional-only parameters from others. + +- Issue #20223: inspect.signature now supports methods defined with + functools.partialmethods. + What's New in Python 3.4.0 Beta 3? ================================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 28 02:28:37 2014 From: python-checkins at python.org (victor.stinner) Date: Tue, 28 Jan 2014 02:28:37 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio_doc=3A_list_Window?= =?utf-8?q?s_and_Mac_OS_X_limitations_and_explain_how_to_work?= Message-ID: <3fCqwP1WGfz7LjM@mail.python.org> http://hg.python.org/cpython/rev/403565c0e5de changeset: 88787:403565c0e5de user: Victor Stinner date: Tue Jan 28 02:24:22 2014 +0100 summary: asyncio doc: list Windows and Mac OS X limitations and explain how to work around them files: Doc/library/asyncio-eventloop.rst | 17 +++++++++++++---- 1 files changed, 13 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 @@ -286,6 +286,19 @@ Run subprocesses asynchronously using the :mod:`subprocess` module. +.. note:: + + On Windows, the default event loop uses + :class:`selectors.SelectSelector` which only supports sockets. The + :class:`ProactorEventLoop` should be used instead. + +.. note:: + + On Mac OS X older than Maverick (10.9), :class:`selectors.KqueueSelector` + does not support character devices like PTY, whereas it is used by the + default event loop. The :class:`SelectorEventLoop` can be used with + :class:`SelectSelector` to handle character devices. + .. method:: BaseEventLoop.subprocess_exec(protocol_factory, \*args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=False, shell=False, bufsize=0, \*\*kwargs) XXX @@ -294,8 +307,6 @@ See the constructor of the :class:`subprocess.Popen` class for parameters. - Availability: Unix. - .. method:: BaseEventLoop.subprocess_shell(protocol_factory, cmd, \*, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=False, shell=True, bufsize=0, \*\*kwargs) XXX @@ -304,8 +315,6 @@ See the constructor of the :class:`subprocess.Popen` class for parameters. - Availability: Unix. - .. method:: BaseEventLoop.connect_read_pipe(protocol_factory, pipe) Register read pipe in eventloop. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 28 03:03:39 2014 From: python-checkins at python.org (ned.deily) Date: Tue, 28 Jan 2014 03:03:39 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_doc_reference_to_OS_X_?= =?utf-8?q?10=2E9_Mavericks=2E?= Message-ID: <3fCrhq5Fc7z7LjW@mail.python.org> http://hg.python.org/cpython/rev/6b37e6aff9ef changeset: 88788:6b37e6aff9ef user: Ned Deily date: Mon Jan 27 19:03:07 2014 -0700 summary: Fix doc reference to OS X 10.9 Mavericks. files: Doc/library/asyncio-eventloop.rst | 2 +- 1 files changed, 1 insertions(+), 1 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 @@ -294,7 +294,7 @@ .. note:: - On Mac OS X older than Maverick (10.9), :class:`selectors.KqueueSelector` + On Mac OS X older than 10.9 (Mavericks), :class:`selectors.KqueueSelector` does not support character devices like PTY, whereas it is used by the default event loop. The :class:`SelectorEventLoop` can be used with :class:`SelectSelector` to handle character devices. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 28 07:07:19 2014 From: python-checkins at python.org (gregory.p.smith) Date: Tue, 28 Jan 2014 07:07:19 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Refactor_the_n?= =?utf-8?q?ew_test_for_issue19081_to_exec_import_statements_into_a?= Message-ID: <3fCy5z3sNjz7LkK@mail.python.org> http://hg.python.org/cpython/rev/d140e3f41796 changeset: 88789:d140e3f41796 branch: 2.7 parent: 88779:6b314f5c9404 user: Gregory P. Smith date: Mon Jan 27 22:06:51 2014 -0800 summary: Refactor the new test for issue19081 to exec import statements into a test_ns dict instead of the actual globals() and locals(). Suggested after review by Thomas Wouters. files: Lib/test/test_zipimport.py | 24 ++++++++++++++---------- 1 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py --- a/Lib/test/test_zipimport.py +++ b/Lib/test/test_zipimport.py @@ -469,7 +469,7 @@ with self.assertRaises(ImportError): from ziptest_a import test_value with self.assertRaises(ImportError): - exec("from {} import {}".format(TESTPACK, TESTMOD)) + exec("from {} import {}".format(TESTPACK, TESTMOD), {}) # Alters all of the offsets within the file self.restoreZipFileWithDifferentHeaderOffsets() @@ -479,10 +479,12 @@ # new file's end of file central index and be able to import again. # Importing a submodule triggers a different import code path. - exec("import " + self.testpack_testmod) - self.assertEqual(getattr(locals()[TESTPACK], TESTMOD).test_value, 38) - exec("from {} import {}".format(TESTPACK, TESTMOD)) - self.assertEqual(locals()[TESTMOD].test_value, 38) + test_ns = {} + exec("import " + self.testpack_testmod, test_ns) + self.assertEqual(getattr(test_ns[TESTPACK], TESTMOD).test_value, 38) + test_ns = {} + exec("from {} import {}".format(TESTPACK, TESTMOD), test_ns) + self.assertEqual(test_ns[TESTMOD].test_value, 38) ziptest_a = __import__("ziptest_a", globals(), locals(), ["test_value"]) self.assertEqual(ziptest_a.test_value, 23) @@ -498,8 +500,9 @@ testmod = __import__(TESTMOD, globals(), locals(), ["test_value"]) self.assertEqual(testmod.test_value, 38) del sys.modules[TESTMOD] - exec("from {} import test_value".format(TESTMOD)) - self.assertEqual(test_value, 38) + test_ns = {} + exec("from {} import test_value".format(TESTMOD), test_ns) + self.assertEqual(test_ns["test_value"], 38) del sys.modules[TESTMOD] # Confirm that imports from the top level of the zip file @@ -516,7 +519,7 @@ with self.assertRaises(ImportError): testmod = __import__(TESTMOD, globals(), locals(), ["test_value"]) with self.assertRaises(ImportError): - exec("from {} import test_value".format(TESTMOD)) + exec("from {} import test_value".format(TESTMOD), {}) with self.assertRaises(ImportError): import ziptest_a @@ -525,8 +528,9 @@ testmod = __import__(TESTMOD, globals(), locals(), ["test_value"]) self.assertEqual(testmod.test_value, 38) del sys.modules[TESTMOD] - exec("from {} import test_value".format(TESTMOD)) - self.assertEqual(test_value, 38) + test_ns = {} + exec("from {} import test_value".format(TESTMOD), test_ns) + self.assertEqual(test_ns['test_value'], 38) ziptest_a = __import__("ziptest_a", globals(), locals(), ["test_value"]) self.assertEqual(ziptest_a.test_value, 23) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 28 07:43:42 2014 From: python-checkins at python.org (gregory.p.smith) Date: Tue, 28 Jan 2014 07:43:42 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Remove_inaccur?= =?utf-8?q?ate_comment_and_a_the_related_recently_added?= Message-ID: <3fCyvy3n5Yz7LjN@mail.python.org> http://hg.python.org/cpython/rev/f9c54ada1b32 changeset: 88790:f9c54ada1b32 branch: 2.7 user: Gregory P. Smith date: Mon Jan 27 22:43:25 2014 -0800 summary: Remove inaccurate comment and a the related recently added Py_VerboseFlag print that can never be triggered. prefix[0] is always equal to 0 at this point in the code. files: Modules/zipimport.c | 7 ------- 1 files changed, 0 insertions(+), 7 deletions(-) diff --git a/Modules/zipimport.c b/Modules/zipimport.c --- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -134,13 +134,6 @@ } if (path != NULL) { PyObject *files; - if (Py_VerboseFlag && prefix && prefix[0] != '\0') - PySys_WriteStderr("# zipimport: prefix=%s constructing a " - "zipimporter for %s\n", prefix, path); - /* NOTE(gps): test_zipimport.py never exercises a case where - * prefix is non-empty. When would that ever be possible? - * Are we missing coverage or is prefix simply never needed? - */ files = PyDict_GetItemString(zip_directory_cache, path); if (files == NULL) { PyObject *zip_stat = NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 28 09:30:04 2014 From: python-checkins at python.org (gregory.p.smith) Date: Tue, 28 Jan 2014 09:30:04 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Remove_unneede?= =?utf-8?q?d_use_of_globals=28=29_and_locals=28=29_in_test_on_imports?= Message-ID: <3fD1Gh69B5z7Lpx@mail.python.org> http://hg.python.org/cpython/rev/ca5431a434d6 changeset: 88791:ca5431a434d6 branch: 2.7 user: Gregory P. Smith date: Tue Jan 28 00:29:46 2014 -0800 summary: Remove unneeded use of globals() and locals() in test on imports introduced with the issue19081 tests. files: Lib/test/test_zipimport.py | 17 ++++++++--------- 1 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py --- a/Lib/test/test_zipimport.py +++ b/Lib/test/test_zipimport.py @@ -456,8 +456,7 @@ # Now that the zipfile has been replaced, import something else from it # which should fail as the file contents are now garbage. with self.assertRaises(ImportError): - ziptest_a = __import__("ziptest_a", globals(), locals(), - ["test_value"]) + ziptest_a = __import__("ziptest_a", {}, {}, ["test_value"]) # The code path used by the __import__ call is different than # that used by import statements. Try these as well. Some of # these may create new zipimporter instances. We need to @@ -486,9 +485,9 @@ exec("from {} import {}".format(TESTPACK, TESTMOD), test_ns) self.assertEqual(test_ns[TESTMOD].test_value, 38) - ziptest_a = __import__("ziptest_a", globals(), locals(), ["test_value"]) + ziptest_a = __import__("ziptest_a", {}, {}, ["test_value"]) self.assertEqual(ziptest_a.test_value, 23) - ziptest_c = __import__("ziptest_c", globals(), locals(), ["test_value"]) + ziptest_c = __import__("ziptest_c", {}, {}, ["test_value"]) self.assertEqual(ziptest_c.test_value, 1337) def testZipFileSubpackageImport(self): @@ -497,7 +496,7 @@ # Put a subdirectory within the zip file into the import path. sys.path.insert(0, self.zipfile_path + os.sep + TESTPACK) - testmod = __import__(TESTMOD, globals(), locals(), ["test_value"]) + testmod = __import__(TESTMOD, {}, {}, ["test_value"]) self.assertEqual(testmod.test_value, 38) del sys.modules[TESTMOD] test_ns = {} @@ -507,7 +506,7 @@ # Confirm that imports from the top level of the zip file # (already in sys.path from the setup call above) still work. - ziptest_a = __import__("ziptest_a", globals(), locals(), ["test_value"]) + ziptest_a = __import__("ziptest_a", {}, {}, ["test_value"]) self.assertEqual(ziptest_a.test_value, 23) del sys.modules["ziptest_a"] import ziptest_c @@ -517,7 +516,7 @@ self.truncateAndFillZipWithNonZipGarbage() # Imports should now fail. with self.assertRaises(ImportError): - testmod = __import__(TESTMOD, globals(), locals(), ["test_value"]) + testmod = __import__(TESTMOD, {}, {}, ["test_value"]) with self.assertRaises(ImportError): exec("from {} import test_value".format(TESTMOD), {}) with self.assertRaises(ImportError): @@ -525,14 +524,14 @@ self.restoreZipFileWithDifferentHeaderOffsets() # Imports should work again, the central directory TOC will be re-read. - testmod = __import__(TESTMOD, globals(), locals(), ["test_value"]) + testmod = __import__(TESTMOD, {}, {}, ["test_value"]) self.assertEqual(testmod.test_value, 38) del sys.modules[TESTMOD] test_ns = {} exec("from {} import test_value".format(TESTMOD), test_ns) self.assertEqual(test_ns['test_value'], 38) - ziptest_a = __import__("ziptest_a", globals(), locals(), ["test_value"]) + ziptest_a = __import__("ziptest_a", {}, {}, ["test_value"]) self.assertEqual(ziptest_a.test_value, 23) import ziptest_c self.assertEqual(ziptest_c.test_value, 1337) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue Jan 28 09:37:55 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 28 Jan 2014 09:37:55 +0100 Subject: [Python-checkins] Daily reference leaks (6b37e6aff9ef): sum=0 Message-ID: results for 6b37e6aff9ef on branch "default" -------------------------------------------- test_site leaked [-2, 0, 2] references, sum=0 test_site leaked [-2, 0, 2] memory blocks, sum=0 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogPdMVnL', '-x'] From python-checkins at python.org Tue Jan 28 13:38:01 2014 From: python-checkins at python.org (nick.coghlan) Date: Tue, 28 Jan 2014 13:38:01 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Include_version_epochs_in_PEP?= =?utf-8?q?_440?= Message-ID: <3fD6mn0Kkpz7Llp@mail.python.org> http://hg.python.org/peps/rev/a71810168398 changeset: 5362:a71810168398 user: Nick Coghlan date: Tue Jan 28 22:37:42 2014 +1000 summary: Include version epochs in PEP 440 files: pep-0440.txt | 75 ++++++++++++++++++++++++++++++++++++--- 1 files changed, 68 insertions(+), 7 deletions(-) diff --git a/pep-0440.txt b/pep-0440.txt --- a/pep-0440.txt +++ b/pep-0440.txt @@ -9,7 +9,8 @@ Type: Standards Track Content-Type: text/x-rst Created: 18 Mar 2013 -Post-History: 30 Mar 2013, 27 May 2013, 20 Jun 2013, 21 Dec 2013 +Post-History: 30 Mar 2013, 27 May 2013, 20 Jun 2013, + 21 Dec 2013, 28 Jan 2014 Replaces: 386 @@ -71,7 +72,7 @@ Public version identifiers MUST comply with the following scheme:: - N[.N]+[{a|b|c|rc}N][.postN][.devN] + [N:]N(.N)*[{a|b|c|rc}N][.postN][.devN] Public version identifiers MUST NOT include leading or trailing whitespace. @@ -81,9 +82,10 @@ this scheme. Installation tools MAY warn the user when non-compliant or ambiguous versions are detected. -Public version identifiers are separated into up to four segments: +Public version identifiers are separated into up to five segments: -* Release segment: ``N[.N]+`` +* Epoch segment: ``N:`` +* Release segment: ``N(.N)*`` * Pre-release segment: ``{a|b|c|rc}N`` * Post-release segment: ``.postN`` * Development release segment: ``.devN`` @@ -354,6 +356,41 @@ notation for full maintenance releases which may include code changes. +Version epochs +-------------- + +If included in a version identifier, the epoch appears before all other +components, separated from the release segment by a colon:: + + E:X.Y # Version identifier with epoch + +If no explicit epoch is given, the implicit epoch is ``0``. + +Most version identifiers will not include an epoch, as an explicit epoch is +only needed if a project *changes* the way it handles version numbering in +a way that means the normal version ordering rules will give the wrong +answer. For example, if a project is using date based versions like +``2014.04`` and would like to switch to semantic versions like ``1.0``, then +the new releases would be identified as *older* than the date based releases +when using the normal sorting scheme:: + + 1.0 + 1.1 + 2.0 + 2013.10 + 2014.04 + +However, by specifying an explicit epoch, the sort order can be changed +appropriately, as all versions from a later epoch are sorted after versions +from an earlier epoch:: + + 2013.10 + 2014.04 + 1:1.0 + 1:1.1 + 1:2.0 + + Examples of compliant version schemes ------------------------------------- @@ -435,6 +472,10 @@ automatically process distribution metadata, rather than developers of Python distributions deciding on a versioning scheme. +The epoch segment of version identifiers MUST be sorted according to the +numeric value of the given epoch. If no epoch segment is present, the +implicit numeric value is ``0``. + The release segment of version identifiers MUST be sorted in the same order as Python's tuple sorting when the release segment is parsed as follows:: @@ -592,9 +633,9 @@ character indicating the version of the database within that year. This can be translated to a compliant public version identifier as -``.``, where the serial starts at zero (for the 'a' -release) and is incremented with each subsequent database update within the -year. +``.``, where the serial starts at zero or one (for the +'a' release) and is incremented with each subsequent database +update within the year. As with other translated version identifiers, the corresponding Olson database version could be recorded in the source label field. @@ -1169,6 +1210,21 @@ projects with less stable APIs. +Adding version epochs +--------------------- + +Version epochs are added for the same reason they are part of other +versioning schemes, such as those of the Fedora and Debian Linux +distributions: to allow projects to gracefully change their approach to +numbering releases, without having a new release appear to have a lower +version number than previous releases and without having to change the name +of the project. + +In particular, supporting version epochs allows a project that was previously +using date based versioning to switch to semantic versioning by specifying +a new version epoch. + + Adding direct references ------------------------ @@ -1215,6 +1271,11 @@ the PEP requires that the integrator suffix of the candidate version be ignored when no integrator suffix is present in the version specifier clause. +The hyphen is chosen primarily for readability of local version identifiers. +While the wheel format also uses hyphens as separators between components, +the escaping rules defined in PEP 427 will convert the hyphen in a local +version identifier to an underscore before using it in a wheel filename. + This change is designed to ensure that an integrator provided version like ``pip 1.5-1`` will still satisfy a version specifier like ``pip (== 1.1)``. -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Jan 28 14:00:30 2014 From: python-checkins at python.org (larry.hastings) Date: Tue, 28 Jan 2014 14:00:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320326=3A_Argument?= =?utf-8?q?_Clinic_now_uses_a_simple=2C_unique_signature_to?= Message-ID: <3fD7Gk2Rl7z7LjZ@mail.python.org> http://hg.python.org/cpython/rev/d6311829da15 changeset: 88792:d6311829da15 parent: 88788:6b37e6aff9ef user: Larry Hastings date: Tue Jan 28 05:00:08 2014 -0800 summary: Issue #20326: Argument Clinic now uses a simple, unique signature to annotate text signatures in docstrings, resulting in fewer false positives. "self" parameters are also explicitly marked, allowing inspect.Signature() to authoritatively detect (and skip) said parameters. Issue #20326: Argument Clinic now generates separate checksums for the input and output sections of the block, allowing external tools to verify that the input has not changed (and thus the output is not out-of-date). files: Include/object.h | 6 +- Lib/idlelib/idle_test/test_calltips.py | 4 +- Lib/inspect.py | 21 +- Lib/test/test_capi.py | 2 +- Lib/test/test_generators.py | 4 +- Lib/test/test_genexps.py | 4 +- Misc/NEWS | 9 + Modules/_bz2module.c | 12 +- Modules/_cryptmodule.c | 6 +- Modules/_cursesmodule.c | 4 +- Modules/_datetimemodule.c | 6 +- Modules/_dbmmodule.c | 10 +- Modules/_lzmamodule.c | 18 +- Modules/_lzmamodule.clinic.c | 2 +- Modules/_opcode.c | 4 +- Modules/_pickle.c | 34 +- Modules/_sre.c | 4 +- Modules/_testcapimodule.c | 8 +- Modules/_weakref.c | 6 +- Modules/audioop.c | 54 +- Modules/binascii.c | 32 +- Modules/clinic/_bz2module.c.h | 12 +- Modules/clinic/_lzmamodule.c.h | 16 +- Modules/clinic/_pickle.c.h | 34 +- Modules/clinic/audioop.c.h | 54 +- Modules/clinic/binascii.c.h | 30 +- Modules/clinic/zlibmodule.c.h | 26 +- Modules/posixmodule.c | 16 +- Modules/unicodedata.c | 6 +- Modules/zlibmodule.c | 28 +- Objects/descrobject.c | 24 +- Objects/dictobject.c | 10 +- Objects/methodobject.c | 8 +- Objects/typeobject.c | 152 ++++----- Objects/unicodeobject.c | 6 +- Python/import.c | 52 +- Tools/clinic/clinic.py | 195 ++++++++++-- 37 files changed, 502 insertions(+), 417 deletions(-) diff --git a/Include/object.h b/Include/object.h --- a/Include/object.h +++ b/Include/object.h @@ -493,10 +493,8 @@ PyAPI_FUNC(void) PyType_Modified(PyTypeObject *); #ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) -_PyType_GetDocFromInternalDoc(const char *, const char *); -PyAPI_FUNC(PyObject *) -_PyType_GetTextSignatureFromInternalDoc(const char *, const char *); +PyAPI_FUNC(PyObject *) _PyType_GetDocFromInternalDoc(const char *); +PyAPI_FUNC(PyObject *) _PyType_GetTextSignatureFromInternalDoc(const char *); #endif /* Generic operations on objects */ diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -54,9 +54,9 @@ gtest(List, List.__doc__) gtest(list.__new__, - 'T.__new__(S, ...) -> a new object with type S, a subtype of T') + 'Create and return a new object. See help(type) for accurate signature.') gtest(list.__init__, - 'x.__init__(...) initializes x; see help(type(x)) for signature') + 'Initialize self. See help(type(self)) for accurate signature.') append_doc = "L.append(object) -> None -- append object to end" gtest(list.append, append_doc) gtest([].append, append_doc) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1998,6 +1998,10 @@ else: kind = Parameter.POSITIONAL_OR_KEYWORD + first_parameter_is_self = s.startswith("($") + if first_parameter_is_self: + s = '(' + s[2:] + s = "def foo" + s + ": pass" try: @@ -2102,18 +2106,11 @@ kind = Parameter.VAR_KEYWORD p(f.args.kwarg, empty) - if parameters and (hasattr(func, '__self__') or - isinstance(func, _WrapperDescriptor,) or - ismethoddescriptor(func) - ): - name = parameters[0].name - if name not in ('self', 'module', 'type'): - pass - elif getattr(func, '__self__', None): - # strip off self (it's already been bound) - p = parameters.pop(0) - if not p.name in ('self', 'module', 'type'): - raise ValueError('Unexpected name ' + repr(p.name) + ', expected self/module/cls/type') + if first_parameter_is_self: + assert parameters + if getattr(func, '__self__', None): + # strip off self, it's already been bound + parameters.pop(0) else: # for builtins, self parameter is always positional-only! p = parameters[0].replace(kind=Parameter.POSITIONAL_ONLY) 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 @@ -125,7 +125,7 @@ self.assertEqual(_testcapi.docstring_no_signature.__text_signature__, None) self.assertEqual(_testcapi.docstring_with_invalid_signature.__doc__, - "docstring_with_invalid_signature (module, boo)\n" + "sig= (module, boo)\n" "\n" "This docstring has an invalid signature." ) diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -436,8 +436,8 @@ >>> [s for s in dir(i) if not s.startswith('_')] ['close', 'gi_code', 'gi_frame', 'gi_running', 'send', 'throw'] >>> from test.support import HAVE_DOCSTRINGS ->>> print(i.__next__.__doc__ if HAVE_DOCSTRINGS else 'Implements next(self).') -Implements next(self). +>>> print(i.__next__.__doc__ if HAVE_DOCSTRINGS else 'Implement next(self).') +Implement next(self). >>> iter(i) is i True >>> import types diff --git a/Lib/test/test_genexps.py b/Lib/test/test_genexps.py --- a/Lib/test/test_genexps.py +++ b/Lib/test/test_genexps.py @@ -222,8 +222,8 @@ True >>> from test.support import HAVE_DOCSTRINGS - >>> print(g.__next__.__doc__ if HAVE_DOCSTRINGS else 'Implements next(self).') - Implements next(self). + >>> print(g.__next__.__doc__ if HAVE_DOCSTRINGS else 'Implement next(self).') + Implement next(self). >>> import types >>> isinstance(g, types.GeneratorType) True diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -203,6 +203,15 @@ Tools/Demos ----------- +- Issue #20326: Argument Clinic now uses a simple, unique signature to + annotate text signatures in docstrings, resulting in fewer false + positives. "self" parameters are also explicitly marked, allowing + inspect.Signature() to authoritatively detect (and skip) said parameters. + +- Issue #20326: Argument Clinic now generates separate checksums for the + input and output sections of the block, allowing external tools to verify + that the input has not changed (and thus the output is not out-of-date). + - Issue #20390: Argument Clinic's "file" output preset now defaults to "{dirname}/clinic/{basename}.h". diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -204,7 +204,7 @@ class _bz2.BZ2Compressor "BZ2Compressor *" "&BZ2Compressor_Type" class _bz2.BZ2Decompressor "BZ2Decompressor *" "&BZ2Decompressor_Type" [clinic start generated code]*/ -/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e3b139924f5e18cc]*/ #include "clinic/_bz2module.c.h" @@ -224,7 +224,7 @@ static PyObject * _bz2_BZ2Compressor_compress_impl(BZ2Compressor *self, Py_buffer *data) -/*[clinic end generated code: checksum=59365426e941fbcc4c7a4d0eef85ca7e19196eaa]*/ +/*[clinic end generated code: output=59365426e941fbcc input=85c963218070fc4c]*/ { PyObject *result = NULL; @@ -249,7 +249,7 @@ static PyObject * _bz2_BZ2Compressor_flush_impl(BZ2Compressor *self) -/*[clinic end generated code: checksum=3ef03fc1b092a701b382b97096c7fd50db87190b]*/ +/*[clinic end generated code: output=3ef03fc1b092a701 input=d64405d3c6f76691]*/ { PyObject *result = NULL; @@ -304,7 +304,7 @@ static int _bz2_BZ2Compressor___init___impl(BZ2Compressor *self, int compresslevel) -/*[clinic end generated code: checksum=c4e6adfd02963827075a1cc9309dc6df184b1246]*/ +/*[clinic end generated code: output=c4e6adfd02963827 input=4e1ff7b8394b6e9a]*/ { int bzerror; @@ -484,7 +484,7 @@ static PyObject * _bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data) -/*[clinic end generated code: checksum=086e4b99e60cb3f67c0481959591eae0735320bc]*/ +/*[clinic end generated code: output=086e4b99e60cb3f6 input=616c2a6db5269961]*/ { PyObject *result = NULL; @@ -515,7 +515,7 @@ static int _bz2_BZ2Decompressor___init___impl(BZ2Decompressor *self) -/*[clinic end generated code: checksum=e4d2b9bb866ab8f1f4a8bb786ddb5b614ce323c0]*/ +/*[clinic end generated code: output=e4d2b9bb866ab8f1 input=95f6500dcda60088]*/ { int bzerror; diff --git a/Modules/_cryptmodule.c b/Modules/_cryptmodule.c --- a/Modules/_cryptmodule.c +++ b/Modules/_cryptmodule.c @@ -10,7 +10,7 @@ /*[clinic input] module crypt [clinic start generated code]*/ -/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c6252cf4f2f2ae81]*/ /*[clinic input] @@ -30,7 +30,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(crypt_crypt__doc__, -"crypt(module, word, salt)\n" +"sig=($module, word, salt)\n" "Hash a *word* with the given *salt* and return the hashed password.\n" "\n" "*word* will usually be a user\'s password. *salt* (either a random 2 or 16\n" @@ -63,7 +63,7 @@ static PyObject * crypt_crypt_impl(PyModuleDef *module, const char *word, const char *salt) -/*[clinic end generated code: checksum=dbfe26a21eb335abefe6a0bbd0a682ea22b9adc0]*/ +/*[clinic end generated code: output=c7443257e03fca92 input=4d93b6d0f41fbf58]*/ { /* On some platforms (AtheOS) crypt returns NULL for an invalid salt. Return None in that case. XXX Maybe raise an exception? */ diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -138,7 +138,7 @@ module curses class curses.window "PyCursesWindowObject *" "&PyCursesWindow_Type" [clinic start generated code]*/ -/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=88c860abdbb50e0c]*/ /* Definition of exception curses.error */ @@ -651,7 +651,7 @@ static PyObject * curses_window_addch_impl(PyCursesWindowObject *self, int group_left_1, int x, int y, PyObject *ch, int group_right_1, long attr) -/*[clinic end generated code: checksum=e1cdbd4f4e42fc6b36fd4755d7e4bd5b58751ea1]*/ +/*[clinic end generated code: output=e1cdbd4f4e42fc6b input=fe7e3711d5bbf1f6]*/ { PyCursesWindowObject *cwself = (PyCursesWindowObject *)self; int coordinates_group = group_left_1; diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -20,7 +20,7 @@ module datetime class datetime.datetime "PyDateTime_DateTime *" "&PyDateTime_DateTimeType" [clinic start generated code]*/ -/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=78142cb64b9e98bc]*/ /* We require that C int be at least 32 bits, and use int virtually * everywhere. In just a few cases we use a temp long, where a Python @@ -4159,7 +4159,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(datetime_datetime_now__doc__, -"now(type, tz=None)\n" +"sig=($type, tz=None)\n" "Returns new datetime object representing current time local to tz.\n" "\n" " tz\n" @@ -4192,7 +4192,7 @@ static PyObject * datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz) -/*[clinic end generated code: checksum=a6d3ad2c0ab6389075289af3467f7b8eb13f5f5c]*/ +/*[clinic end generated code: output=c8a47308483e579a input=80d09869c5267d00]*/ { PyObject *self; diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c --- a/Modules/_dbmmodule.c +++ b/Modules/_dbmmodule.c @@ -32,7 +32,7 @@ module dbm class dbm.dbm "dbmobject *" "&Dbmtype" [clinic start generated code]*/ -/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=92450564684a69a3]*/ typedef struct { PyObject_HEAD @@ -55,7 +55,7 @@ def converter_init(self): self.name = 'dp' [python start generated code]*/ -/*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=8a69ac1827811128]*/ static PyObject * newdbmobject(const char *file, int flags, int mode) @@ -319,7 +319,7 @@ static PyObject * dbm_dbm_get_impl(dbmobject *dp, const char *key, Py_ssize_clean_t key_length, int group_right_1, PyObject *default_value) -/*[clinic end generated code: checksum=31d5180d6b36f1eafea78ec4391adf3559916379]*/ +/*[clinic end generated code: output=31d5180d6b36f1ea input=43a561dc2bd1db3b]*/ { datum dbm_key, val; @@ -462,7 +462,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(dbmopen__doc__, -"open(module, filename, flags=\'r\', mode=0o666)\n" +"sig=($module, filename, flags=\'r\', mode=0o666)\n" "Return a database object.\n" "\n" " filename\n" @@ -499,7 +499,7 @@ static PyObject * dbmopen_impl(PyModuleDef *module, const char *filename, const char *flags, int mode) -/*[clinic end generated code: checksum=9efae7d3c3b67a365011bf4e463e918901ba6c79]*/ +/*[clinic end generated code: output=a1da6a481d9d332b input=6499ab0fab1333ac]*/ { int iflags; diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -475,7 +475,7 @@ class _lzma.LZMACompressor "Compressor *" "&Compressor_type" class _lzma.LZMADecompressor "Decompressor *" "&Decompressor_type" [clinic start generated code]*/ -/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=f17afc786525d6c2]*/ #include "clinic/_lzmamodule.c.h" @@ -496,7 +496,7 @@ ' PyMem_Free(%(name)s.options);\n') % {'name': name} [python start generated code]*/ -/*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=74fe7631ce377a94]*/ /* LZMACompressor class. */ @@ -560,7 +560,7 @@ static PyObject * _lzma_LZMACompressor_compress_impl(Compressor *self, Py_buffer *data) -/*[clinic end generated code: checksum=31f615136963e00f26f8be33440ec1e3604565ba]*/ +/*[clinic end generated code: output=31f615136963e00f input=8b60cb13e0ce6420]*/ { PyObject *result = NULL; @@ -587,7 +587,7 @@ static PyObject * _lzma_LZMACompressor_flush_impl(Compressor *self) -/*[clinic end generated code: checksum=fec21f3e22504f500606ba60e1ba70d79eb22188]*/ +/*[clinic end generated code: output=fec21f3e22504f50 input=3060fb26f9b4042c]*/ { PyObject *result = NULL; @@ -959,7 +959,7 @@ static PyObject * _lzma_LZMADecompressor_decompress_impl(Decompressor *self, Py_buffer *data) -/*[clinic end generated code: checksum=d86e78da7ff0ff219d511275b16b79476da8922e]*/ +/*[clinic end generated code: output=d86e78da7ff0ff21 input=50c4768b821bf0ef]*/ { PyObject *result = NULL; @@ -1024,7 +1024,7 @@ static int _lzma_LZMADecompressor___init___impl(Decompressor *self, int format, PyObject *memlimit, PyObject *filters) -/*[clinic end generated code: checksum=9b119f6f2cc2d7a8e5be41c164a6c080ee82d0c2]*/ +/*[clinic end generated code: output=9b119f6f2cc2d7a8 input=458ca6132ef29801]*/ { const uint32_t decoder_flags = LZMA_TELL_ANY_CHECK | LZMA_TELL_NO_CHECK; uint64_t memlimit_ = UINT64_MAX; @@ -1203,7 +1203,7 @@ static PyObject * _lzma_is_check_supported_impl(PyModuleDef *module, int check_id) -/*[clinic end generated code: checksum=bb828e90e00ad96ed61f66719c2fca7fde637418]*/ +/*[clinic end generated code: output=bb828e90e00ad96e input=5518297b97b2318f]*/ { return PyBool_FromLong(lzma_check_is_supported(check_id)); } @@ -1221,7 +1221,7 @@ static PyObject * _lzma__encode_filter_properties_impl(PyModuleDef *module, lzma_filter filter) -/*[clinic end generated code: checksum=b5fe690acd6b61d1abfc32f522ada5bdcf9b13da]*/ +/*[clinic end generated code: output=b5fe690acd6b61d1 input=d4c64f1b557c77d4]*/ { lzma_ret lzret; uint32_t encoded_size; @@ -1261,7 +1261,7 @@ static PyObject * _lzma__decode_filter_properties_impl(PyModuleDef *module, lzma_vli filter_id, Py_buffer *encoded_props) -/*[clinic end generated code: checksum=235f7f5345d48744dcd21f781dafbbf05a717538]*/ +/*[clinic end generated code: output=235f7f5345d48744 input=246410800782160c]*/ { lzma_filter filter; lzma_ret lzret; diff --git a/Modules/_lzmamodule.clinic.c b/Modules/_lzmamodule.clinic.c --- a/Modules/_lzmamodule.clinic.c +++ b/Modules/_lzmamodule.clinic.c @@ -228,4 +228,4 @@ return return_value; } -/*[clinic end generated code: checksum=b4b90dcbd0c9c349c3a94e26a7eecf71aab179a0]*/ +/*[clinic end generated code: output=b4b90dcbd0c9c349 input=a9049054013a1b77]*/ diff --git a/Modules/_opcode.c b/Modules/_opcode.c --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -4,7 +4,7 @@ /*[clinic input] module _opcode [clinic start generated code]*/ -/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=117442e66eb376e6]*/ /*[clinic input] @@ -64,7 +64,7 @@ static int _opcode_stack_effect_impl(PyModuleDef *module, int opcode, int group_right_1, int oparg) -/*[clinic end generated code: checksum=4689140ffda2494a123ea2593fb63445fb039774]*/ +/*[clinic end generated code: output=4689140ffda2494a input=056816407c3d4284]*/ { int effect; if (HAS_ARG(opcode)) { diff --git a/Modules/_pickle.c b/Modules/_pickle.c --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -12,7 +12,7 @@ class _pickle.Unpickler "UnpicklerObject *" "&Unpickler_Type" class _pickle.UnpicklerMemoProxy "UnpicklerMemoProxyObject *" "&UnpicklerMemoProxyType" [clinic start generated code]*/ -/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=11c45248a41dd3fc]*/ /* Bump this when new opcodes are added to the pickle protocol. */ enum { @@ -3885,7 +3885,7 @@ static PyObject * _pickle_Pickler_clear_memo_impl(PicklerObject *self) -/*[clinic end generated code: checksum=8665c8658aaa094ba9b424d3d7fe0add5e8142ab]*/ +/*[clinic end generated code: output=8665c8658aaa094b input=01bdad52f3d93e56]*/ { if (self->memo) PyMemoTable_Clear(self->memo); @@ -3905,7 +3905,7 @@ static PyObject * _pickle_Pickler_dump(PicklerObject *self, PyObject *obj) -/*[clinic end generated code: checksum=87ecad1261e02ac7ad0b051467b61bb058ae55b3]*/ +/*[clinic end generated code: output=87ecad1261e02ac7 input=552eb1c0f52260d9]*/ { /* Check whether the Pickler was initialized correctly (issue3664). Developers often forget to call __init__() in their subclasses, which @@ -4010,7 +4010,7 @@ static int _pickle_Pickler___init___impl(PicklerObject *self, PyObject *file, PyObject *protocol, int fix_imports) -/*[clinic end generated code: checksum=56e229f3b1f4332fbfe28a33e43dae836a8dab43]*/ +/*[clinic end generated code: output=56e229f3b1f4332f input=b8cdeb7e3f5ee674]*/ { _Py_IDENTIFIER(persistent_id); _Py_IDENTIFIER(dispatch_table); @@ -4080,7 +4080,7 @@ static PyObject * _pickle_PicklerMemoProxy_clear_impl(PicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=5fb9370d48ae8b055fc72518a2b12d1714338078]*/ +/*[clinic end generated code: output=5fb9370d48ae8b05 input=ccc186dacd0f1405]*/ { if (self->pickler->memo) PyMemoTable_Clear(self->pickler->memo); @@ -4095,7 +4095,7 @@ static PyObject * _pickle_PicklerMemoProxy_copy_impl(PicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=bb83a919d29225ef55ba0ecfca002369ea4eb8ea]*/ +/*[clinic end generated code: output=bb83a919d29225ef input=b73043485ac30b36]*/ { Py_ssize_t i; PyMemoTable *memo; @@ -4140,7 +4140,7 @@ static PyObject * _pickle_PicklerMemoProxy___reduce___impl(PicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=bebba1168863ab1d6560ad707d0f4ab41deb722d]*/ +/*[clinic end generated code: output=bebba1168863ab1d input=2f7c540e24b7aae4]*/ { PyObject *reduce_value, *dict_args; PyObject *contents = _pickle_PicklerMemoProxy_copy_impl(self); @@ -6163,7 +6163,7 @@ static PyObject * _pickle_Unpickler_load_impl(UnpicklerObject *self) -/*[clinic end generated code: checksum=fdcc488aad675b1458b5644180d092b99e6e4fe4]*/ +/*[clinic end generated code: output=fdcc488aad675b14 input=acbb91a42fa9b7b9]*/ { UnpicklerObject *unpickler = (UnpicklerObject*)self; @@ -6206,7 +6206,7 @@ static PyObject * _pickle_Unpickler_find_class_impl(UnpicklerObject *self, PyObject *module_name, PyObject *global_name) -/*[clinic end generated code: checksum=64c77437e088e188fa0b022a0402d5b2964da8c9]*/ +/*[clinic end generated code: output=64c77437e088e188 input=e2e6a865de093ef4]*/ { PyObject *global; PyObject *modules_dict; @@ -6389,7 +6389,7 @@ static int _pickle_Unpickler___init___impl(UnpicklerObject *self, PyObject *file, int fix_imports, const char *encoding, const char *errors) -/*[clinic end generated code: checksum=b9ed1d84d315f3b57f91b878cdd88024ccc2ae89]*/ +/*[clinic end generated code: output=b9ed1d84d315f3b5 input=30b4dc9e976b890c]*/ { _Py_IDENTIFIER(persistent_load); @@ -6453,7 +6453,7 @@ static PyObject * _pickle_UnpicklerMemoProxy_clear_impl(UnpicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=d20cd43f4ba1fb1f1ba1677fae3ff69b8cc41582]*/ +/*[clinic end generated code: output=d20cd43f4ba1fb1f input=b1df7c52e7afd9bd]*/ { _Unpickler_MemoCleanup(self->unpickler); self->unpickler->memo = _Unpickler_NewMemo(self->unpickler->memo_size); @@ -6470,7 +6470,7 @@ static PyObject * _pickle_UnpicklerMemoProxy_copy_impl(UnpicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=e12af7e9bc1e4c77df97c1e657d6b8e026a022b7]*/ +/*[clinic end generated code: output=e12af7e9bc1e4c77 input=97769247ce032c1d]*/ { Py_ssize_t i; PyObject *new_memo = PyDict_New(); @@ -6508,7 +6508,7 @@ static PyObject * _pickle_UnpicklerMemoProxy___reduce___impl(UnpicklerMemoProxyObject *self) -/*[clinic end generated code: checksum=6da34ac048d94cca7604faa72d45992e730882f1]*/ +/*[clinic end generated code: output=6da34ac048d94cca input=6920862413407199]*/ { PyObject *reduce_value; PyObject *constructor_args; @@ -6818,7 +6818,7 @@ static PyObject * _pickle_dump_impl(PyModuleDef *module, PyObject *obj, PyObject *file, PyObject *protocol, int fix_imports) -/*[clinic end generated code: checksum=a606e626d553850d96c286e909a139552d5d4096]*/ +/*[clinic end generated code: output=a606e626d553850d input=e9e5fdd48de92eae]*/ { PicklerObject *pickler = _Pickler_New(); @@ -6871,7 +6871,7 @@ static PyObject * _pickle_dumps_impl(PyModuleDef *module, PyObject *obj, PyObject *protocol, int fix_imports) -/*[clinic end generated code: checksum=777f0deefe5b88ee324d43ab31b2579da7bbf22a]*/ +/*[clinic end generated code: output=777f0deefe5b88ee input=293dbeda181580b7]*/ { PyObject *result; PicklerObject *pickler = _Pickler_New(); @@ -6931,7 +6931,7 @@ static PyObject * _pickle_load_impl(PyModuleDef *module, PyObject *file, int fix_imports, const char *encoding, const char *errors) -/*[clinic end generated code: checksum=568c61356c172654a23cf4edb4afffa1dc2a55d9]*/ +/*[clinic end generated code: output=568c61356c172654 input=da97372e38e510a6]*/ { PyObject *result; UnpicklerObject *unpickler = _Unpickler_New(); @@ -6984,7 +6984,7 @@ static PyObject * _pickle_loads_impl(PyModuleDef *module, PyObject *data, int fix_imports, const char *encoding, const char *errors) -/*[clinic end generated code: checksum=0b3845ad110b25220ab613e9a1e573194271a337]*/ +/*[clinic end generated code: output=0b3845ad110b2522 input=f57f0fdaa2b4cb8b]*/ { PyObject *result; UnpicklerObject *unpickler = _Unpickler_New(); diff --git a/Modules/_sre.c b/Modules/_sre.c --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -540,7 +540,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(pattern_match__doc__, -"match(self, pattern, pos=0, endpos=sys.maxsize)\n" +"sig=($self, pattern, pos=0, endpos=sys.maxsize)\n" "Matches zero or more characters at the beginning of the string."); #define PATTERN_MATCH_METHODDEF \ @@ -570,7 +570,7 @@ static PyObject * pattern_match_impl(PatternObject *self, PyObject *pattern, Py_ssize_t pos, Py_ssize_t endpos) -/*[clinic end generated code: checksum=4a3865d13638cb7c13dcae1fe58c1a9c35071998]*/ +/*[clinic end generated code: output=9f5b785661677848 input=26f9fd31befe46b9]*/ { SRE_STATE state; Py_ssize_t status; diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2851,18 +2851,18 @@ ); PyDoc_STRVAR(docstring_with_invalid_signature, -"docstring_with_invalid_signature (module, boo)\n" +"sig= (module, boo)\n" "\n" "This docstring has an invalid signature." ); PyDoc_STRVAR(docstring_with_signature, -"docstring_with_signature(module, sig)\n" +"sig=(module, sig)\n" "This docstring has a valid signature." ); PyDoc_STRVAR(docstring_with_signature_and_extra_newlines, -"docstring_with_signature_and_extra_newlines(module, parameter)\n" +"sig=(module, parameter)\n" "\n" "\n" "\n" @@ -2870,7 +2870,7 @@ ); PyDoc_STRVAR(docstring_with_signature_with_defaults, -"docstring_with_signature_with_defaults(module, s='avocado', b=b'bytes', d=3.14, i=35, n=None, t=True, f=False, local=the_number_three, sys=sys.maxsize, exp=sys.maxsize - 1)\n" +"sig=(module, s='avocado', b=b'bytes', d=3.14, i=35, n=None, t=True, f=False, local=the_number_three, sys=sys.maxsize, exp=sys.maxsize - 1)\n" "\n" "\n" "\n" diff --git a/Modules/_weakref.c b/Modules/_weakref.c --- a/Modules/_weakref.c +++ b/Modules/_weakref.c @@ -7,7 +7,7 @@ /*[clinic input] module _weakref [clinic start generated code]*/ -/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ffec73b85846596d]*/ /*[clinic input] @@ -20,7 +20,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_weakref_getweakrefcount__doc__, -"getweakrefcount(module, object)\n" +"sig=($module, object)\n" "Return the number of weak references to \'object\'."); #define _WEAKREF_GETWEAKREFCOUNT_METHODDEF \ @@ -46,7 +46,7 @@ static Py_ssize_t _weakref_getweakrefcount_impl(PyModuleDef *module, PyObject *object) -/*[clinic end generated code: checksum=dd8ba0730babf263d3db78d260ea7eacf6eb3735]*/ +/*[clinic end generated code: output=ef51baac56180816 input=cedb69711b6a2507]*/ { PyWeakReference **list; diff --git a/Modules/audioop.c b/Modules/audioop.c --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -394,7 +394,7 @@ output preset file module audioop [clinic start generated code]*/ -/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=5619f935f269199a]*/ /*[clinic input] audioop.getsample @@ -409,7 +409,7 @@ static PyObject * audioop_getsample_impl(PyModuleDef *module, Py_buffer *fragment, int width, Py_ssize_t index) -/*[clinic end generated code: checksum=f4482497e6f6e78fe88451c19a288837099d6eef]*/ +/*[clinic end generated code: output=f4482497e6f6e78f input=88edbe2871393549]*/ { int val; @@ -435,7 +435,7 @@ static PyObject * audioop_max_impl(PyModuleDef *module, Py_buffer *fragment, int width) -/*[clinic end generated code: checksum=85047ee1001f230518386b16148955ba9be4874f]*/ +/*[clinic end generated code: output=85047ee1001f2305 input=32bea5ea0ac8c223]*/ { Py_ssize_t i; unsigned int absval, max = 0; @@ -463,7 +463,7 @@ static PyObject * audioop_minmax_impl(PyModuleDef *module, Py_buffer *fragment, int width) -/*[clinic end generated code: checksum=ae8f5513c64fd569849adbbcc5fcd4d8f399da1b]*/ +/*[clinic end generated code: output=ae8f5513c64fd569 input=89848e9b927a0696]*/ { Py_ssize_t i; /* -1 trick below is needed on Windows to support -0x80000000 without @@ -492,7 +492,7 @@ static PyObject * audioop_avg_impl(PyModuleDef *module, Py_buffer *fragment, int width) -/*[clinic end generated code: checksum=7fccd645c95f4860899f6b3aaab269e3e58806e1]*/ +/*[clinic end generated code: output=7fccd645c95f4860 input=1114493c7611334d]*/ { Py_ssize_t i; int avg; @@ -521,7 +521,7 @@ static PyObject * audioop_rms_impl(PyModuleDef *module, Py_buffer *fragment, int width) -/*[clinic end generated code: checksum=7b398702c81b709d87aba3f0635eeb3fc1b0a1a4]*/ +/*[clinic end generated code: output=7b398702c81b709d input=4cc57c6c94219d78]*/ { Py_ssize_t i; unsigned int res; @@ -595,7 +595,7 @@ static PyObject * audioop_findfit_impl(PyModuleDef *module, Py_buffer *fragment, Py_buffer *reference) -/*[clinic end generated code: checksum=505fd04d4244db31044abb5c114a5e8f9c45b171]*/ +/*[clinic end generated code: output=505fd04d4244db31 input=62c305605e183c9a]*/ { const short *cp1, *cp2; Py_ssize_t len1, len2; @@ -663,7 +663,7 @@ static PyObject * audioop_findfactor_impl(PyModuleDef *module, Py_buffer *fragment, Py_buffer *reference) -/*[clinic end generated code: checksum=ddf35a1e57575ce4acbc000104810d9fdde8eba5]*/ +/*[clinic end generated code: output=ddf35a1e57575ce4 input=816680301d012b21]*/ { const short *cp1, *cp2; Py_ssize_t len; @@ -704,7 +704,7 @@ static PyObject * audioop_findmax_impl(PyModuleDef *module, Py_buffer *fragment, Py_ssize_t length) -/*[clinic end generated code: checksum=21d0c2a1e5655134f7460b7fd49ee4ba1e5fdb13]*/ +/*[clinic end generated code: output=21d0c2a1e5655134 input=2f304801ed42383c]*/ { const short *cp1; Py_ssize_t len1; @@ -757,7 +757,7 @@ static PyObject * audioop_avgpp_impl(PyModuleDef *module, Py_buffer *fragment, int width) -/*[clinic end generated code: checksum=06c8380fd6e34207f4b58d6c3d4b5ebc7afe138d]*/ +/*[clinic end generated code: output=06c8380fd6e34207 input=0b3cceeae420a7d9]*/ { Py_ssize_t i; int prevval, prevextremevalid = 0, prevextreme = 0; @@ -814,7 +814,7 @@ static PyObject * audioop_maxpp_impl(PyModuleDef *module, Py_buffer *fragment, int width) -/*[clinic end generated code: checksum=c300c0bd7e8535c07e128bbaac211c69744f750b]*/ +/*[clinic end generated code: output=c300c0bd7e8535c0 input=671a13e1518f80a1]*/ { Py_ssize_t i; int prevval, prevextremevalid = 0, prevextreme = 0; @@ -867,7 +867,7 @@ static PyObject * audioop_cross_impl(PyModuleDef *module, Py_buffer *fragment, int width) -/*[clinic end generated code: checksum=99e6572d7d7cdbf1b5372090308201c62d518a43]*/ +/*[clinic end generated code: output=99e6572d7d7cdbf1 input=b1b3f15b83f6b41a]*/ { Py_ssize_t i; int prevval; @@ -898,7 +898,7 @@ static PyObject * audioop_mul_impl(PyModuleDef *module, Py_buffer *fragment, int width, double factor) -/*[clinic end generated code: checksum=a697ebbd5852d38f941d52127a5b38e4f8cd5540]*/ +/*[clinic end generated code: output=a697ebbd5852d38f input=c726667baa157d3c]*/ { signed char *ncp; Py_ssize_t i; @@ -939,7 +939,7 @@ static PyObject * audioop_tomono_impl(PyModuleDef *module, Py_buffer *fragment, int width, double lfactor, double rfactor) -/*[clinic end generated code: checksum=436e7710521661dd541ec177ee53e6b0ee340182]*/ +/*[clinic end generated code: output=436e7710521661dd input=c4ec949b3f4dddfa]*/ { signed char *cp, *ncp; Py_ssize_t len, i; @@ -987,7 +987,7 @@ static PyObject * audioop_tostereo_impl(PyModuleDef *module, Py_buffer *fragment, int width, double lfactor, double rfactor) -/*[clinic end generated code: checksum=6ff50681c87f4c1cbe4c394c4186ae8ae91b5c0d]*/ +/*[clinic end generated code: output=6ff50681c87f4c1c input=27b6395ebfdff37a]*/ { signed char *ncp; Py_ssize_t i; @@ -1034,7 +1034,7 @@ static PyObject * audioop_add_impl(PyModuleDef *module, Py_buffer *fragment1, Py_buffer *fragment2, int width) -/*[clinic end generated code: checksum=f9218bf9ea75c3f1e4b2ed5ffdfd631354e8fdfe]*/ +/*[clinic end generated code: output=f9218bf9ea75c3f1 input=4a8d4bae4c1605c7]*/ { signed char *ncp; Py_ssize_t i; @@ -1092,7 +1092,7 @@ static PyObject * audioop_bias_impl(PyModuleDef *module, Py_buffer *fragment, int width, int bias) -/*[clinic end generated code: checksum=8ec80b3f5d510a51a85e89e8c0a73070697f2ab4]*/ +/*[clinic end generated code: output=8ec80b3f5d510a51 input=2b5cce5c3bb4838c]*/ { signed char *ncp; Py_ssize_t i; @@ -1151,7 +1151,7 @@ static PyObject * audioop_reverse_impl(PyModuleDef *module, Py_buffer *fragment, int width) -/*[clinic end generated code: checksum=6ec3c91337f5925eaf17a7b8b907120102b6fb72]*/ +/*[clinic end generated code: output=6ec3c91337f5925e input=668f890cf9f9d225]*/ { unsigned char *ncp; Py_ssize_t i; @@ -1184,7 +1184,7 @@ static PyObject * audioop_byteswap_impl(PyModuleDef *module, Py_buffer *fragment, int width) -/*[clinic end generated code: checksum=bfe4aa584b7a3f5bd818cf79f83fa73e612cc9b8]*/ +/*[clinic end generated code: output=bfe4aa584b7a3f5b input=fae7611ceffa5c82]*/ { unsigned char *ncp; Py_ssize_t i; @@ -1219,7 +1219,7 @@ static PyObject * audioop_lin2lin_impl(PyModuleDef *module, Py_buffer *fragment, int width, int newwidth) -/*[clinic end generated code: checksum=3f9468a74472a93e2054a9da0ea1bbc39fe23e84]*/ +/*[clinic end generated code: output=3f9468a74472a93e input=5ce08c8aa2f24d96]*/ { unsigned char *ncp; Py_ssize_t i, j; @@ -1276,7 +1276,7 @@ static PyObject * audioop_ratecv_impl(PyModuleDef *module, Py_buffer *fragment, int width, int nchannels, int inrate, int outrate, PyObject *state, int weightA, int weightB) -/*[clinic end generated code: checksum=5585dddc4b5ff2363877076f4c6616df8d3e6f14]*/ +/*[clinic end generated code: output=5585dddc4b5ff236 input=aff3acdc94476191]*/ { char *cp, *ncp; Py_ssize_t len; @@ -1455,7 +1455,7 @@ static PyObject * audioop_lin2ulaw_impl(PyModuleDef *module, Py_buffer *fragment, int width) -/*[clinic end generated code: checksum=26263cc877c5e1bc84fede972fb59499a82d949c]*/ +/*[clinic end generated code: output=26263cc877c5e1bc input=2450d1b870b6bac2]*/ { unsigned char *ncp; Py_ssize_t i; @@ -1488,7 +1488,7 @@ static PyObject * audioop_ulaw2lin_impl(PyModuleDef *module, Py_buffer *fragment, int width) -/*[clinic end generated code: checksum=9864cb34e3a1d87689f830d4c95cdcaae9a44561]*/ +/*[clinic end generated code: output=9864cb34e3a1d876 input=45d53ddce5be7d06]*/ { unsigned char *cp; signed char *ncp; @@ -1528,7 +1528,7 @@ static PyObject * audioop_lin2alaw_impl(PyModuleDef *module, Py_buffer *fragment, int width) -/*[clinic end generated code: checksum=d5bf14bd0fe6fdcd4b0d604ccdf257097eb2419e]*/ +/*[clinic end generated code: output=d5bf14bd0fe6fdcd input=ffb1ef8bb39da945]*/ { unsigned char *ncp; Py_ssize_t i; @@ -1561,7 +1561,7 @@ static PyObject * audioop_alaw2lin_impl(PyModuleDef *module, Py_buffer *fragment, int width) -/*[clinic end generated code: checksum=d2b604ddd036e1cd4bb95b5553626b44302db48a]*/ +/*[clinic end generated code: output=d2b604ddd036e1cd input=4140626046cd1772]*/ { unsigned char *cp; signed char *ncp; @@ -1603,7 +1603,7 @@ static PyObject * audioop_lin2adpcm_impl(PyModuleDef *module, Py_buffer *fragment, int width, PyObject *state) -/*[clinic end generated code: checksum=4654c29d2731fafe35e7aa1e3d261361dbbbcc3b]*/ +/*[clinic end generated code: output=4654c29d2731fafe input=12919d549b90c90a]*/ { signed char *ncp; Py_ssize_t i; @@ -1725,7 +1725,7 @@ static PyObject * audioop_adpcm2lin_impl(PyModuleDef *module, Py_buffer *fragment, int width, PyObject *state) -/*[clinic end generated code: checksum=371965cdcc0aa69ba970e8bc5662b30d45bcc38d]*/ +/*[clinic end generated code: output=371965cdcc0aa69b input=f5221144f5ca9ef0]*/ { signed char *cp; signed char *ncp; diff --git a/Modules/binascii.c b/Modules/binascii.c --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -187,7 +187,7 @@ output preset file module binascii [clinic start generated code]*/ -/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=44c6f840ce708f0c]*/ /*[python input] @@ -202,7 +202,7 @@ return "".join(["if (", name, ".obj)\n PyBuffer_Release(&", name, ");\n"]) [python start generated code]*/ -/*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=3eb7b63610da92cd]*/ static int ascii_buffer_converter(PyObject *arg, Py_buffer *buf) @@ -254,7 +254,7 @@ static PyObject * binascii_a2b_uu_impl(PyModuleDef *module, Py_buffer *data) -/*[clinic end generated code: checksum=5779f39b0b48459ff0f7a365d7e69b57422e2a4a]*/ +/*[clinic end generated code: output=5779f39b0b48459f input=7cafeaf73df63d1c]*/ { unsigned char *ascii_data, *bin_data; int leftbits = 0; @@ -340,7 +340,7 @@ static PyObject * binascii_b2a_uu_impl(PyModuleDef *module, Py_buffer *data) -/*[clinic end generated code: checksum=181021b69bb9a4149fffa98aa3ed57b59ffa38cb]*/ +/*[clinic end generated code: output=181021b69bb9a414 input=00fdf458ce8b465b]*/ { unsigned char *ascii_data, *bin_data; int leftbits = 0; @@ -427,7 +427,7 @@ static PyObject * binascii_a2b_base64_impl(PyModuleDef *module, Py_buffer *data) -/*[clinic end generated code: checksum=3e351b702bed56d249caa4aa0f1bb3fae7546025]*/ +/*[clinic end generated code: output=3e351b702bed56d2 input=5872acf6e1cac243]*/ { unsigned char *ascii_data, *bin_data; int leftbits = 0; @@ -535,7 +535,7 @@ static PyObject * binascii_b2a_base64_impl(PyModuleDef *module, Py_buffer *data) -/*[clinic end generated code: checksum=3cd61fbee2913285e253bc5415c9d052b0c5dd96]*/ +/*[clinic end generated code: output=3cd61fbee2913285 input=14ec4e47371174a9]*/ { unsigned char *ascii_data, *bin_data; int leftbits = 0; @@ -602,7 +602,7 @@ static PyObject * binascii_a2b_hqx_impl(PyModuleDef *module, Py_buffer *data) -/*[clinic end generated code: checksum=60bcdbbd28b105cd7091d98e70a6e458f8039e9e]*/ +/*[clinic end generated code: output=60bcdbbd28b105cd input=0d914c680e0eed55]*/ { unsigned char *ascii_data, *bin_data; int leftbits = 0; @@ -685,7 +685,7 @@ static PyObject * binascii_rlecode_hqx_impl(PyModuleDef *module, Py_buffer *data) -/*[clinic end generated code: checksum=0905da344dbf064855925c3a0fb83ec11ca33e8b]*/ +/*[clinic end generated code: output=0905da344dbf0648 input=e1f1712447a82b09]*/ { unsigned char *in_data, *out_data; PyObject *rv; @@ -749,7 +749,7 @@ static PyObject * binascii_b2a_hqx_impl(PyModuleDef *module, Py_buffer *data) -/*[clinic end generated code: checksum=5a987810d5e3cdbb0eb415eba8907c022342fe15]*/ +/*[clinic end generated code: output=5a987810d5e3cdbb input=9596ebe019fe12ba]*/ { unsigned char *ascii_data, *bin_data; int leftbits = 0; @@ -806,7 +806,7 @@ static PyObject * binascii_rledecode_hqx_impl(PyModuleDef *module, Py_buffer *data) -/*[clinic end generated code: checksum=f7afd89b789946ab50e31d595c695d5cad7e27e3]*/ +/*[clinic end generated code: output=f7afd89b789946ab input=54cdd49fc014402c]*/ { unsigned char *in_data, *out_data; unsigned char in_byte, in_repeat; @@ -920,7 +920,7 @@ static int binascii_crc_hqx_impl(PyModuleDef *module, Py_buffer *data, int crc) -/*[clinic end generated code: checksum=634dac18dfa863d738833b5a0886eca93c034c0c]*/ +/*[clinic end generated code: output=634dac18dfa863d7 input=68060931b2f51c8a]*/ { unsigned char *bin_data; unsigned int ucrc = (unsigned int)crc; @@ -1068,7 +1068,7 @@ static unsigned int binascii_crc32_impl(PyModuleDef *module, Py_buffer *data, unsigned int crc) -/*[clinic end generated code: checksum=620a961643393c4f2a1fb273fda2acb43970c3f5]*/ +/*[clinic end generated code: output=620a961643393c4f input=bbe340bc99d25aa8]*/ #ifdef USE_ZLIB_CRC32 /* This was taken from zlibmodule.c PyZlib_crc32 (but is PY_SSIZE_T_CLEAN) */ @@ -1116,7 +1116,7 @@ static PyObject * binascii_b2a_hex_impl(PyModuleDef *module, Py_buffer *data) -/*[clinic end generated code: checksum=179318922c2f8fdaee0d4d3283758aec8e8741a5]*/ +/*[clinic end generated code: output=179318922c2f8fda input=96423cfa299ff3b1]*/ { char* argbuf; Py_ssize_t arglen; @@ -1177,7 +1177,7 @@ static PyObject * binascii_a2b_hex_impl(PyModuleDef *module, Py_buffer *hexstr) -/*[clinic end generated code: checksum=d61da452b5c6d2903c32c3e90e6a97221b25989b]*/ +/*[clinic end generated code: output=d61da452b5c6d290 input=9e1e7f2f94db24fd]*/ { char* argbuf; Py_ssize_t arglen; @@ -1248,7 +1248,7 @@ static PyObject * binascii_a2b_qp_impl(PyModuleDef *module, Py_buffer *data, int header) -/*[clinic end generated code: checksum=a44ef8827035211431d0906a76dbfe97e59a5079]*/ +/*[clinic end generated code: output=a44ef88270352114 input=5187a0d3d8e54f3b]*/ { Py_ssize_t in, out; char ch; @@ -1354,7 +1354,7 @@ static PyObject * binascii_b2a_qp_impl(PyModuleDef *module, Py_buffer *data, int quotetabs, int istext, int header) -/*[clinic end generated code: checksum=ff2991ba640fff3e67ac63205801c7173a0366cd]*/ +/*[clinic end generated code: output=ff2991ba640fff3e input=7f2a9aaa008e92b2]*/ { Py_ssize_t in, out; unsigned char *databuf, *odata; diff --git a/Modules/clinic/_bz2module.c.h b/Modules/clinic/_bz2module.c.h --- a/Modules/clinic/_bz2module.c.h +++ b/Modules/clinic/_bz2module.c.h @@ -3,7 +3,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_bz2_BZ2Compressor_compress__doc__, -"compress(self, data)\n" +"sig=($self, data)\n" "Provide data to the compressor object.\n" "\n" "Returns a chunk of compressed data if possible, or b\'\' otherwise.\n" @@ -38,7 +38,7 @@ } PyDoc_STRVAR(_bz2_BZ2Compressor_flush__doc__, -"flush(self)\n" +"sig=($self)\n" "Finish the compression process.\n" "\n" "Returns the compressed data left in internal buffers.\n" @@ -58,7 +58,7 @@ } PyDoc_STRVAR(_bz2_BZ2Compressor___init____doc__, -"BZ2Compressor(compresslevel=9)\n" +"sig=(compresslevel=9)\n" "Create a compressor object for compressing data incrementally.\n" "\n" " compresslevel\n" @@ -89,7 +89,7 @@ } PyDoc_STRVAR(_bz2_BZ2Decompressor_decompress__doc__, -"decompress(self, data)\n" +"sig=($self, data)\n" "Provide data to the decompressor object.\n" "\n" "Returns a chunk of decompressed data if possible, or b\'\' otherwise.\n" @@ -125,7 +125,7 @@ } PyDoc_STRVAR(_bz2_BZ2Decompressor___init____doc__, -"BZ2Decompressor()\n" +"sig=()\n" "Create a decompressor object for decompressing data incrementally.\n" "\n" "For one-shot decompression, use the decompress() function instead."); @@ -149,4 +149,4 @@ exit: return return_value; } -/*[clinic end generated code: checksum=4ade1dba3921a8bd8a614e5417f7654d8fb10be5]*/ +/*[clinic end generated code: output=aca4f6329c1c773a input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_lzmamodule.c.h b/Modules/clinic/_lzmamodule.c.h --- a/Modules/clinic/_lzmamodule.c.h +++ b/Modules/clinic/_lzmamodule.c.h @@ -3,7 +3,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_lzma_LZMACompressor_compress__doc__, -"compress(self, data)\n" +"sig=($self, data)\n" "Provide data to the compressor object.\n" "\n" "Returns a chunk of compressed data if possible, or b\'\' otherwise.\n" @@ -38,7 +38,7 @@ } PyDoc_STRVAR(_lzma_LZMACompressor_flush__doc__, -"flush(self)\n" +"sig=($self)\n" "Finish the compression process.\n" "\n" "Returns the compressed data left in internal buffers.\n" @@ -58,7 +58,7 @@ } PyDoc_STRVAR(_lzma_LZMADecompressor_decompress__doc__, -"decompress(self, data)\n" +"sig=($self, data)\n" "Provide data to the decompressor object.\n" "\n" "Returns a chunk of decompressed data if possible, or b\'\' otherwise.\n" @@ -94,7 +94,7 @@ } PyDoc_STRVAR(_lzma_LZMADecompressor___init____doc__, -"LZMADecompressor(format=FORMAT_AUTO, memlimit=None, filters=None)\n" +"sig=(format=FORMAT_AUTO, memlimit=None, filters=None)\n" "Create a decompressor object for decompressing data incrementally.\n" "\n" " format\n" @@ -137,7 +137,7 @@ } PyDoc_STRVAR(_lzma_is_check_supported__doc__, -"is_check_supported(module, check_id)\n" +"sig=($module, check_id)\n" "Test whether the given integrity check is supported.\n" "\n" "Always returns True for CHECK_NONE and CHECK_CRC32."); @@ -165,7 +165,7 @@ } PyDoc_STRVAR(_lzma__encode_filter_properties__doc__, -"_encode_filter_properties(module, filter)\n" +"sig=($module, filter)\n" "Return a bytes object encoding the options (properties) of the filter specified by *filter* (a dict).\n" "\n" "The result does not include the filter ID itself, only the options."); @@ -197,7 +197,7 @@ } PyDoc_STRVAR(_lzma__decode_filter_properties__doc__, -"_decode_filter_properties(module, filter_id, encoded_props)\n" +"sig=($module, filter_id, encoded_props)\n" "Return a bytes object encoding the options (properties) of the filter specified by *filter* (a dict).\n" "\n" "The result does not include the filter ID itself, only the options."); @@ -228,4 +228,4 @@ return return_value; } -/*[clinic end generated code: checksum=b4b90dcbd0c9c349c3a94e26a7eecf71aab179a0]*/ +/*[clinic end generated code: output=fe63bc798a5c5c55 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_pickle.c.h b/Modules/clinic/_pickle.c.h --- a/Modules/clinic/_pickle.c.h +++ b/Modules/clinic/_pickle.c.h @@ -3,7 +3,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_pickle_Pickler_clear_memo__doc__, -"clear_memo(self)\n" +"sig=($self)\n" "Clears the pickler\'s \"memo\".\n" "\n" "The memo is the data structure that remembers which objects the\n" @@ -24,14 +24,14 @@ } PyDoc_STRVAR(_pickle_Pickler_dump__doc__, -"dump(self, obj)\n" +"sig=($self, obj)\n" "Write a pickled representation of the given object to the open file."); #define _PICKLE_PICKLER_DUMP_METHODDEF \ {"dump", (PyCFunction)_pickle_Pickler_dump, METH_O, _pickle_Pickler_dump__doc__}, PyDoc_STRVAR(_pickle_Pickler___init____doc__, -"Pickler(file, protocol=None, fix_imports=True)\n" +"sig=(file, protocol=None, fix_imports=True)\n" "This takes a binary file for writing a pickle data stream.\n" "\n" "The optional *protocol* argument tells the pickler to use the given\n" @@ -74,7 +74,7 @@ } PyDoc_STRVAR(_pickle_PicklerMemoProxy_clear__doc__, -"clear(self)\n" +"sig=($self)\n" "Remove all items from memo."); #define _PICKLE_PICKLERMEMOPROXY_CLEAR_METHODDEF \ @@ -90,7 +90,7 @@ } PyDoc_STRVAR(_pickle_PicklerMemoProxy_copy__doc__, -"copy(self)\n" +"sig=($self)\n" "Copy the memo to a new object."); #define _PICKLE_PICKLERMEMOPROXY_COPY_METHODDEF \ @@ -106,7 +106,7 @@ } PyDoc_STRVAR(_pickle_PicklerMemoProxy___reduce____doc__, -"__reduce__(self)\n" +"sig=($self)\n" "Implement pickle support."); #define _PICKLE_PICKLERMEMOPROXY___REDUCE___METHODDEF \ @@ -122,7 +122,7 @@ } PyDoc_STRVAR(_pickle_Unpickler_load__doc__, -"load(self)\n" +"sig=($self)\n" "Load a pickle.\n" "\n" "Read a pickled object representation from the open file object given\n" @@ -142,7 +142,7 @@ } PyDoc_STRVAR(_pickle_Unpickler_find_class__doc__, -"find_class(self, module_name, global_name)\n" +"sig=($self, module_name, global_name)\n" "Return an object from a specified module.\n" "\n" "If necessary, the module will be imported. Subclasses may override\n" @@ -176,7 +176,7 @@ } PyDoc_STRVAR(_pickle_Unpickler___init____doc__, -"Unpickler(file, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" +"sig=(file, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" "This takes a binary file for reading a pickle data stream.\n" "\n" "The protocol version of the pickle is detected automatically, so no\n" @@ -222,7 +222,7 @@ } PyDoc_STRVAR(_pickle_UnpicklerMemoProxy_clear__doc__, -"clear(self)\n" +"sig=($self)\n" "Remove all items from memo."); #define _PICKLE_UNPICKLERMEMOPROXY_CLEAR_METHODDEF \ @@ -238,7 +238,7 @@ } PyDoc_STRVAR(_pickle_UnpicklerMemoProxy_copy__doc__, -"copy(self)\n" +"sig=($self)\n" "Copy the memo to a new object."); #define _PICKLE_UNPICKLERMEMOPROXY_COPY_METHODDEF \ @@ -254,7 +254,7 @@ } PyDoc_STRVAR(_pickle_UnpicklerMemoProxy___reduce____doc__, -"__reduce__(self)\n" +"sig=($self)\n" "Implement pickling support."); #define _PICKLE_UNPICKLERMEMOPROXY___REDUCE___METHODDEF \ @@ -270,7 +270,7 @@ } PyDoc_STRVAR(_pickle_dump__doc__, -"dump(module, obj, file, protocol=None, *, fix_imports=True)\n" +"sig=($module, obj, file, protocol=None, *, fix_imports=True)\n" "Write a pickled representation of obj to the open file object file.\n" "\n" "This is equivalent to ``Pickler(file, protocol).dump(obj)``, but may\n" @@ -320,7 +320,7 @@ } PyDoc_STRVAR(_pickle_dumps__doc__, -"dumps(module, obj, protocol=None, *, fix_imports=True)\n" +"sig=($module, obj, protocol=None, *, fix_imports=True)\n" "Return the pickled representation of the object as a bytes object.\n" "\n" "The optional *protocol* argument tells the pickler to use the given\n" @@ -361,7 +361,7 @@ } PyDoc_STRVAR(_pickle_load__doc__, -"load(module, file, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" +"sig=($module, file, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" "Read and return an object from the pickle data stored in a file.\n" "\n" "This is equivalent to ``Unpickler(file).load()``, but may be more\n" @@ -413,7 +413,7 @@ } PyDoc_STRVAR(_pickle_loads__doc__, -"loads(module, data, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" +"sig=($module, data, *, fix_imports=True, encoding=\'ASCII\', errors=\'strict\')\n" "Read and return an object from the given pickle data.\n" "\n" "The protocol version of the pickle is detected automatically, so no\n" @@ -454,4 +454,4 @@ exit: return return_value; } -/*[clinic end generated code: checksum=b7a2e1df72bdbc87da3cd0e43a3caa1a879892bb]*/ +/*[clinic end generated code: output=c59d4dafc2646f11 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/audioop.c.h b/Modules/clinic/audioop.c.h --- a/Modules/clinic/audioop.c.h +++ b/Modules/clinic/audioop.c.h @@ -3,7 +3,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(audioop_getsample__doc__, -"getsample(module, fragment, width, index)\n" +"sig=($module, fragment, width, index)\n" "Return the value of sample index from the fragment."); #define AUDIOOP_GETSAMPLE_METHODDEF \ @@ -35,7 +35,7 @@ } PyDoc_STRVAR(audioop_max__doc__, -"max(module, fragment, width)\n" +"sig=($module, fragment, width)\n" "Return the maximum of the absolute value of all samples in a fragment."); #define AUDIOOP_MAX_METHODDEF \ @@ -66,7 +66,7 @@ } PyDoc_STRVAR(audioop_minmax__doc__, -"minmax(module, fragment, width)\n" +"sig=($module, fragment, width)\n" "Return the minimum and maximum values of all samples in the sound fragment."); #define AUDIOOP_MINMAX_METHODDEF \ @@ -97,7 +97,7 @@ } PyDoc_STRVAR(audioop_avg__doc__, -"avg(module, fragment, width)\n" +"sig=($module, fragment, width)\n" "Return the average over all samples in the fragment."); #define AUDIOOP_AVG_METHODDEF \ @@ -128,7 +128,7 @@ } PyDoc_STRVAR(audioop_rms__doc__, -"rms(module, fragment, width)\n" +"sig=($module, fragment, width)\n" "Return the root-mean-square of the fragment, i.e. sqrt(sum(S_i^2)/n)."); #define AUDIOOP_RMS_METHODDEF \ @@ -159,7 +159,7 @@ } PyDoc_STRVAR(audioop_findfit__doc__, -"findfit(module, fragment, reference)\n" +"sig=($module, fragment, reference)\n" "Try to match reference as well as possible to a portion of fragment."); #define AUDIOOP_FINDFIT_METHODDEF \ @@ -193,7 +193,7 @@ } PyDoc_STRVAR(audioop_findfactor__doc__, -"findfactor(module, fragment, reference)\n" +"sig=($module, fragment, reference)\n" "Return a factor F such that rms(add(fragment, mul(reference, -F))) is minimal."); #define AUDIOOP_FINDFACTOR_METHODDEF \ @@ -227,7 +227,7 @@ } PyDoc_STRVAR(audioop_findmax__doc__, -"findmax(module, fragment, length)\n" +"sig=($module, fragment, length)\n" "Search fragment for a slice of specified number of samples with maximum energy."); #define AUDIOOP_FINDMAX_METHODDEF \ @@ -258,7 +258,7 @@ } PyDoc_STRVAR(audioop_avgpp__doc__, -"avgpp(module, fragment, width)\n" +"sig=($module, fragment, width)\n" "Return the average peak-peak value over all samples in the fragment."); #define AUDIOOP_AVGPP_METHODDEF \ @@ -289,7 +289,7 @@ } PyDoc_STRVAR(audioop_maxpp__doc__, -"maxpp(module, fragment, width)\n" +"sig=($module, fragment, width)\n" "Return the maximum peak-peak value in the sound fragment."); #define AUDIOOP_MAXPP_METHODDEF \ @@ -320,7 +320,7 @@ } PyDoc_STRVAR(audioop_cross__doc__, -"cross(module, fragment, width)\n" +"sig=($module, fragment, width)\n" "Return the number of zero crossings in the fragment passed as an argument."); #define AUDIOOP_CROSS_METHODDEF \ @@ -351,7 +351,7 @@ } PyDoc_STRVAR(audioop_mul__doc__, -"mul(module, fragment, width, factor)\n" +"sig=($module, fragment, width, factor)\n" "Return a fragment that has all samples in the original fragment multiplied by the floating-point value factor."); #define AUDIOOP_MUL_METHODDEF \ @@ -383,7 +383,7 @@ } PyDoc_STRVAR(audioop_tomono__doc__, -"tomono(module, fragment, width, lfactor, rfactor)\n" +"sig=($module, fragment, width, lfactor, rfactor)\n" "Convert a stereo fragment to a mono fragment."); #define AUDIOOP_TOMONO_METHODDEF \ @@ -416,7 +416,7 @@ } PyDoc_STRVAR(audioop_tostereo__doc__, -"tostereo(module, fragment, width, lfactor, rfactor)\n" +"sig=($module, fragment, width, lfactor, rfactor)\n" "Generate a stereo fragment from a mono fragment."); #define AUDIOOP_TOSTEREO_METHODDEF \ @@ -449,7 +449,7 @@ } PyDoc_STRVAR(audioop_add__doc__, -"add(module, fragment1, fragment2, width)\n" +"sig=($module, fragment1, fragment2, width)\n" "Return a fragment which is the addition of the two samples passed as parameters."); #define AUDIOOP_ADD_METHODDEF \ @@ -484,7 +484,7 @@ } PyDoc_STRVAR(audioop_bias__doc__, -"bias(module, fragment, width, bias)\n" +"sig=($module, fragment, width, bias)\n" "Return a fragment that is the original fragment with a bias added to each sample."); #define AUDIOOP_BIAS_METHODDEF \ @@ -516,7 +516,7 @@ } PyDoc_STRVAR(audioop_reverse__doc__, -"reverse(module, fragment, width)\n" +"sig=($module, fragment, width)\n" "Reverse the samples in a fragment and returns the modified fragment."); #define AUDIOOP_REVERSE_METHODDEF \ @@ -547,7 +547,7 @@ } PyDoc_STRVAR(audioop_byteswap__doc__, -"byteswap(module, fragment, width)\n" +"sig=($module, fragment, width)\n" "Convert big-endian samples to little-endian and vice versa."); #define AUDIOOP_BYTESWAP_METHODDEF \ @@ -578,7 +578,7 @@ } PyDoc_STRVAR(audioop_lin2lin__doc__, -"lin2lin(module, fragment, width, newwidth)\n" +"sig=($module, fragment, width, newwidth)\n" "Convert samples between 1-, 2-, 3- and 4-byte formats."); #define AUDIOOP_LIN2LIN_METHODDEF \ @@ -610,7 +610,7 @@ } PyDoc_STRVAR(audioop_ratecv__doc__, -"ratecv(module, fragment, width, nchannels, inrate, outrate, state, weightA=1, weightB=0)\n" +"sig=($module, fragment, width, nchannels, inrate, outrate, state, weightA=1, weightB=0)\n" "Convert the frame rate of the input fragment."); #define AUDIOOP_RATECV_METHODDEF \ @@ -647,7 +647,7 @@ } PyDoc_STRVAR(audioop_lin2ulaw__doc__, -"lin2ulaw(module, fragment, width)\n" +"sig=($module, fragment, width)\n" "Convert samples in the audio fragment to u-LAW encoding."); #define AUDIOOP_LIN2ULAW_METHODDEF \ @@ -678,7 +678,7 @@ } PyDoc_STRVAR(audioop_ulaw2lin__doc__, -"ulaw2lin(module, fragment, width)\n" +"sig=($module, fragment, width)\n" "Convert sound fragments in u-LAW encoding to linearly encoded sound fragments."); #define AUDIOOP_ULAW2LIN_METHODDEF \ @@ -709,7 +709,7 @@ } PyDoc_STRVAR(audioop_lin2alaw__doc__, -"lin2alaw(module, fragment, width)\n" +"sig=($module, fragment, width)\n" "Convert samples in the audio fragment to a-LAW encoding."); #define AUDIOOP_LIN2ALAW_METHODDEF \ @@ -740,7 +740,7 @@ } PyDoc_STRVAR(audioop_alaw2lin__doc__, -"alaw2lin(module, fragment, width)\n" +"sig=($module, fragment, width)\n" "Convert sound fragments in a-LAW encoding to linearly encoded sound fragments."); #define AUDIOOP_ALAW2LIN_METHODDEF \ @@ -771,7 +771,7 @@ } PyDoc_STRVAR(audioop_lin2adpcm__doc__, -"lin2adpcm(module, fragment, width, state)\n" +"sig=($module, fragment, width, state)\n" "Convert samples to 4 bit Intel/DVI ADPCM encoding."); #define AUDIOOP_LIN2ADPCM_METHODDEF \ @@ -803,7 +803,7 @@ } PyDoc_STRVAR(audioop_adpcm2lin__doc__, -"adpcm2lin(module, fragment, width, state)\n" +"sig=($module, fragment, width, state)\n" "Decode an Intel/DVI ADPCM coded fragment to a linear fragment."); #define AUDIOOP_ADPCM2LIN_METHODDEF \ @@ -833,4 +833,4 @@ return return_value; } -/*[clinic end generated code: checksum=0d9fa2c5719e996b169f808350016cd622799562]*/ +/*[clinic end generated code: output=ee7e58cfd3d0d5a6 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/binascii.c.h b/Modules/clinic/binascii.c.h --- a/Modules/clinic/binascii.c.h +++ b/Modules/clinic/binascii.c.h @@ -3,7 +3,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(binascii_a2b_uu__doc__, -"a2b_uu(module, data)\n" +"sig=($module, data)\n" "Decode a line of uuencoded data."); #define BINASCII_A2B_UU_METHODDEF \ @@ -33,7 +33,7 @@ } PyDoc_STRVAR(binascii_b2a_uu__doc__, -"b2a_uu(module, data)\n" +"sig=($module, data)\n" "Uuencode line of data."); #define BINASCII_B2A_UU_METHODDEF \ @@ -63,7 +63,7 @@ } PyDoc_STRVAR(binascii_a2b_base64__doc__, -"a2b_base64(module, data)\n" +"sig=($module, data)\n" "Decode a line of base64 data."); #define BINASCII_A2B_BASE64_METHODDEF \ @@ -93,7 +93,7 @@ } PyDoc_STRVAR(binascii_b2a_base64__doc__, -"b2a_base64(module, data)\n" +"sig=($module, data)\n" "Base64-code line of data."); #define BINASCII_B2A_BASE64_METHODDEF \ @@ -123,7 +123,7 @@ } PyDoc_STRVAR(binascii_a2b_hqx__doc__, -"a2b_hqx(module, data)\n" +"sig=($module, data)\n" "Decode .hqx coding."); #define BINASCII_A2B_HQX_METHODDEF \ @@ -153,7 +153,7 @@ } PyDoc_STRVAR(binascii_rlecode_hqx__doc__, -"rlecode_hqx(module, data)\n" +"sig=($module, data)\n" "Binhex RLE-code binary data."); #define BINASCII_RLECODE_HQX_METHODDEF \ @@ -183,7 +183,7 @@ } PyDoc_STRVAR(binascii_b2a_hqx__doc__, -"b2a_hqx(module, data)\n" +"sig=($module, data)\n" "Encode .hqx data."); #define BINASCII_B2A_HQX_METHODDEF \ @@ -213,7 +213,7 @@ } PyDoc_STRVAR(binascii_rledecode_hqx__doc__, -"rledecode_hqx(module, data)\n" +"sig=($module, data)\n" "Decode hexbin RLE-coded string."); #define BINASCII_RLEDECODE_HQX_METHODDEF \ @@ -243,7 +243,7 @@ } PyDoc_STRVAR(binascii_crc_hqx__doc__, -"crc_hqx(module, data, crc)\n" +"sig=($module, data, crc)\n" "Compute hqx CRC incrementally."); #define BINASCII_CRC_HQX_METHODDEF \ @@ -278,7 +278,7 @@ } PyDoc_STRVAR(binascii_crc32__doc__, -"crc32(module, data, crc=0)\n" +"sig=($module, data, crc=0)\n" "Compute CRC-32 incrementally."); #define BINASCII_CRC32_METHODDEF \ @@ -313,7 +313,7 @@ } PyDoc_STRVAR(binascii_b2a_hex__doc__, -"b2a_hex(module, data)\n" +"sig=($module, data)\n" "Hexadecimal representation of binary data.\n" "\n" "The return value is a bytes object. This function is also\n" @@ -346,7 +346,7 @@ } PyDoc_STRVAR(binascii_a2b_hex__doc__, -"a2b_hex(module, hexstr)\n" +"sig=($module, hexstr)\n" "Binary data of hexadecimal representation.\n" "\n" "hexstr must contain an even number of hex digits (upper or lower case).\n" @@ -379,7 +379,7 @@ } PyDoc_STRVAR(binascii_a2b_qp__doc__, -"a2b_qp(module, data, header=False)\n" +"sig=($module, data, header=False)\n" "Decode a string of qp-encoded data."); #define BINASCII_A2B_QP_METHODDEF \ @@ -411,7 +411,7 @@ } PyDoc_STRVAR(binascii_b2a_qp__doc__, -"b2a_qp(module, data, quotetabs=False, istext=True, header=False)\n" +"sig=($module, data, quotetabs=False, istext=True, header=False)\n" "Encode a string using quoted-printable encoding.\n" "\n" "On encoding, when istext is set, newlines are not encoded, and white\n" @@ -447,4 +447,4 @@ return return_value; } -/*[clinic end generated code: checksum=8180e5be47a110ae8c89263a7c12a91d80754f60]*/ +/*[clinic end generated code: output=831a8ccc9f984001 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/zlibmodule.c.h b/Modules/clinic/zlibmodule.c.h --- a/Modules/clinic/zlibmodule.c.h +++ b/Modules/clinic/zlibmodule.c.h @@ -3,7 +3,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(zlib_compress__doc__, -"compress(module, bytes, level=Z_DEFAULT_COMPRESSION)\n" +"sig=($module, bytes, level=Z_DEFAULT_COMPRESSION)\n" "Returns a bytes object containing compressed data.\n" "\n" " bytes\n" @@ -39,7 +39,7 @@ } PyDoc_STRVAR(zlib_decompress__doc__, -"decompress(module, data, wbits=MAX_WBITS, bufsize=DEF_BUF_SIZE)\n" +"sig=($module, data, wbits=MAX_WBITS, bufsize=DEF_BUF_SIZE)\n" "Returns a bytes object containing the uncompressed data.\n" "\n" " data\n" @@ -78,7 +78,7 @@ } PyDoc_STRVAR(zlib_compressobj__doc__, -"compressobj(module, level=Z_DEFAULT_COMPRESSION, method=DEFLATED, wbits=MAX_WBITS, memLevel=DEF_MEM_LEVEL, strategy=Z_DEFAULT_STRATEGY, zdict=None)\n" +"sig=($module, level=Z_DEFAULT_COMPRESSION, method=DEFLATED, wbits=MAX_WBITS, memLevel=DEF_MEM_LEVEL, strategy=Z_DEFAULT_STRATEGY, zdict=None)\n" "Return a compressor object.\n" "\n" " level\n" @@ -132,7 +132,7 @@ } PyDoc_STRVAR(zlib_decompressobj__doc__, -"decompressobj(module, wbits=MAX_WBITS, zdict=b\'\')\n" +"sig=($module, wbits=MAX_WBITS, zdict=b\'\')\n" "Return a decompressor object.\n" "\n" " wbits\n" @@ -166,7 +166,7 @@ } PyDoc_STRVAR(zlib_Compress_compress__doc__, -"compress(self, data)\n" +"sig=($self, data)\n" "Returns a bytes object containing compressed data.\n" "\n" " data\n" @@ -203,7 +203,7 @@ } PyDoc_STRVAR(zlib_Decompress_decompress__doc__, -"decompress(self, data, max_length=0)\n" +"sig=($self, data, max_length=0)\n" "Return a bytes object containing the decompressed version of the data.\n" "\n" " data\n" @@ -245,7 +245,7 @@ } PyDoc_STRVAR(zlib_Compress_flush__doc__, -"flush(self, mode=Z_FINISH)\n" +"sig=($self, mode=Z_FINISH)\n" "Return a bytes object containing any remaining compressed data.\n" "\n" " mode\n" @@ -277,7 +277,7 @@ } PyDoc_STRVAR(zlib_Compress_copy__doc__, -"copy(self)\n" +"sig=($self)\n" "Return a copy of the compression object."); #define ZLIB_COMPRESS_COPY_METHODDEF \ @@ -293,7 +293,7 @@ } PyDoc_STRVAR(zlib_Decompress_copy__doc__, -"copy(self)\n" +"sig=($self)\n" "Return a copy of the decompression object."); #define ZLIB_DECOMPRESS_COPY_METHODDEF \ @@ -309,7 +309,7 @@ } PyDoc_STRVAR(zlib_Decompress_flush__doc__, -"flush(self, length=DEF_BUF_SIZE)\n" +"sig=($self, length=DEF_BUF_SIZE)\n" "Return a bytes object containing any remaining decompressed data.\n" "\n" " length\n" @@ -338,7 +338,7 @@ } PyDoc_STRVAR(zlib_adler32__doc__, -"adler32(module, data, value=1)\n" +"sig=($module, data, value=1)\n" "Compute an Adler-32 checksum of data.\n" "\n" " value\n" @@ -374,7 +374,7 @@ } PyDoc_STRVAR(zlib_crc32__doc__, -"crc32(module, data, value=0)\n" +"sig=($module, data, value=0)\n" "Compute a CRC-32 checksum of data.\n" "\n" " value\n" @@ -408,4 +408,4 @@ return return_value; } -/*[clinic end generated code: checksum=04f94bbaf2652717753e237e4021bf6c92ddffdd]*/ +/*[clinic end generated code: output=ad23316b49faf7e6 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -184,7 +184,7 @@ /*[clinic input] module os [clinic start generated code]*/ -/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=8cff096d1133288f]*/ #ifndef _MSC_VER @@ -2397,7 +2397,7 @@ [python start generated code]*/ -/*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=d702d58a8469cc7d]*/ /*[clinic input] @@ -2430,7 +2430,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(os_stat__doc__, -"stat(module, path, *, dir_fd=None, follow_symlinks=True)\n" +"sig=($module, path, *, dir_fd=None, follow_symlinks=True)\n" "Perform a stat system call on the given path.\n" "\n" " path\n" @@ -2481,7 +2481,7 @@ static PyObject * os_stat_impl(PyModuleDef *module, path_t *path, int dir_fd, int follow_symlinks) -/*[clinic end generated code: checksum=09cc91b4947f9e3b9335c8be998bb7c56f7f8b40]*/ +/*[clinic end generated code: output=33b6ee92cd1b98de input=5ae155bd475fd20a]*/ { return posix_do_stat("stat", path, dir_fd, follow_symlinks); } @@ -2562,7 +2562,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(os_access__doc__, -"access(module, path, mode, *, dir_fd=None, effective_ids=False, follow_symlinks=True)\n" +"sig=($module, path, mode, *, dir_fd=None, effective_ids=False, follow_symlinks=True)\n" "Use the real uid/gid to test for access to a path.\n" "\n" " path\n" @@ -2622,7 +2622,7 @@ static PyObject * os_access_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd, int effective_ids, int follow_symlinks) -/*[clinic end generated code: checksum=6483a51e1fee83da4f8e41cbc8054a701cfed1c5]*/ +/*[clinic end generated code: output=33b3fafc61e778e1 input=2e2e7594371f5b7e]*/ { PyObject *return_value = NULL; @@ -2718,7 +2718,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(os_ttyname__doc__, -"ttyname(module, fd)\n" +"sig=($module, fd)\n" "Return the name of the terminal device connected to \'fd\'.\n" "\n" " fd\n" @@ -2752,7 +2752,7 @@ static char * os_ttyname_impl(PyModuleDef *module, int fd) -/*[clinic end generated code: checksum=11bbb8b7969155f54bb8a1ec35ac1ebdfd4b0fec]*/ +/*[clinic end generated code: output=c3083e665d4d11b9 input=5f72ca83e76b3b45]*/ { char *ret; diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -21,7 +21,7 @@ module unicodedata class unicodedata.UCD 'PreviousDBVersion *' '&UCD_Type' [clinic start generated code]*/ -/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6dac153082d150bc]*/ /* character properties */ @@ -129,7 +129,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(unicodedata_UCD_decimal__doc__, -"decimal(self, unichr, default=None)\n" +"sig=($self, unichr, default=None)\n" "Converts a Unicode character into its equivalent decimal value.\n" "\n" "Returns the decimal value assigned to the Unicode character unichr\n" @@ -161,7 +161,7 @@ static PyObject * unicodedata_UCD_decimal_impl(PreviousDBVersion *self, PyUnicodeObject *unichr, PyObject *default_value) -/*[clinic end generated code: checksum=e1371a1a016e19fdd3cd2c1af1d1832df095f50b]*/ +/*[clinic end generated code: output=a3ad5de9393acb2f input=c25c9d2b4de076b1]*/ { int have_old = 0; long rc; diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -86,7 +86,7 @@ class zlib.Compress "compobject *" "&Comptype" class zlib.Decompress "compobject *" "&Decomptype" [clinic start generated code]*/ -/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=bfd4c340573ba91d]*/ static compobject * newcompobject(PyTypeObject *type) @@ -148,7 +148,7 @@ static PyObject * zlib_compress_impl(PyModuleDef *module, Py_buffer *bytes, int level) -/*[clinic end generated code: checksum=5d7dd4588788efd3516e5f4225050d6413632601]*/ +/*[clinic end generated code: output=5d7dd4588788efd3 input=be3abe9934bda4b3]*/ { PyObject *ReturnVal = NULL; Byte *input, *output = NULL; @@ -232,7 +232,7 @@ c_ignored_default = "0" [python start generated code]*/ -/*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=22263855f7a3ebfd]*/ static int uint_converter(PyObject *obj, void *ptr) @@ -281,7 +281,7 @@ static PyObject * zlib_decompress_impl(PyModuleDef *module, Py_buffer *data, int wbits, unsigned int bufsize) -/*[clinic end generated code: checksum=9e5464e72df9cb5fee73df662dbcaed867e01d32]*/ +/*[clinic end generated code: output=9e5464e72df9cb5f input=0f4b9abb7103f50e]*/ { PyObject *result_str = NULL; Byte *input; @@ -411,7 +411,7 @@ static PyObject * zlib_compressobj_impl(PyModuleDef *module, int level, int method, int wbits, int memLevel, int strategy, Py_buffer *zdict) -/*[clinic end generated code: checksum=89e5a6c1449caa9ed76f1baad066600e985151a9]*/ +/*[clinic end generated code: output=89e5a6c1449caa9e input=b034847f8821f6af]*/ { compobject *self = NULL; int err; @@ -483,7 +483,7 @@ static PyObject * zlib_decompressobj_impl(PyModuleDef *module, int wbits, PyObject *zdict) -/*[clinic end generated code: checksum=8ccd583fbd631798566d415933cd44440c8a74b5]*/ +/*[clinic end generated code: output=8ccd583fbd631798 input=67f05145a6920127]*/ { int err; compobject *self; @@ -571,7 +571,7 @@ static PyObject * zlib_Compress_compress_impl(compobject *self, Py_buffer *data) -/*[clinic end generated code: checksum=5d5cd791cbc6a7f4b6de4ec12c085c88d4d3e31c]*/ +/*[clinic end generated code: output=5d5cd791cbc6a7f4 input=0d95908d6e64fab8]*/ { int err; unsigned int inplen; @@ -705,7 +705,7 @@ static PyObject * zlib_Decompress_decompress_impl(compobject *self, Py_buffer *data, unsigned int max_length) -/*[clinic end generated code: checksum=755cccc9087bfe55486b7e15fa7e2ab60b4c86d6]*/ +/*[clinic end generated code: output=755cccc9087bfe55 input=02cfc047377cec86]*/ { int err; unsigned int old_length, length = DEF_BUF_SIZE; @@ -840,7 +840,7 @@ static PyObject * zlib_Compress_flush_impl(compobject *self, int mode) -/*[clinic end generated code: checksum=a203f4cefc9de727aa1d2ea39d11c0a16c32041a]*/ +/*[clinic end generated code: output=a203f4cefc9de727 input=6982996afe0772d8]*/ { int err; unsigned int length = DEF_BUF_SIZE, new_length; @@ -933,7 +933,7 @@ static PyObject * zlib_Compress_copy_impl(compobject *self) -/*[clinic end generated code: checksum=5144aa153c21e805afa5c19e5b48cf8e6480b5da]*/ +/*[clinic end generated code: output=5144aa153c21e805 input=c656351f94b82718]*/ { compobject *retval = NULL; int err; @@ -991,7 +991,7 @@ static PyObject * zlib_Decompress_copy_impl(compobject *self) -/*[clinic end generated code: checksum=02a883a2a510c8ccfeef3f89e317a275bfe8c094]*/ +/*[clinic end generated code: output=02a883a2a510c8cc input=ba6c3e96712a596b]*/ { compobject *retval = NULL; int err; @@ -1055,7 +1055,7 @@ static PyObject * zlib_Decompress_flush_impl(compobject *self, unsigned int length) -/*[clinic end generated code: checksum=db6fb753ab698e22afe3957c9da9e5e77f4bfc08]*/ +/*[clinic end generated code: output=db6fb753ab698e22 input=fe7954136712c353]*/ { int err; unsigned int new_length; @@ -1183,7 +1183,7 @@ static PyObject * zlib_adler32_impl(PyModuleDef *module, Py_buffer *data, unsigned int value) -/*[clinic end generated code: checksum=51d6d75ee655c78af8c968fdb4c11d97e62c67d5]*/ +/*[clinic end generated code: output=51d6d75ee655c78a input=6ff4557872160e88]*/ { /* Releasing the GIL for very small buffers is inefficient and may lower performance */ @@ -1222,7 +1222,7 @@ static PyObject * zlib_crc32_impl(PyModuleDef *module, Py_buffer *data, unsigned int value) -/*[clinic end generated code: checksum=c1e986e74fe7b62369998a71a81ebeb9b73e8d4c]*/ +/*[clinic end generated code: output=c1e986e74fe7b623 input=26c3ed430fa00b4c]*/ { int signed_val; diff --git a/Objects/descrobject.c b/Objects/descrobject.c --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -353,17 +353,13 @@ static PyObject * method_get_doc(PyMethodDescrObject *descr, void *closure) { - const char *name = descr->d_method->ml_name; - const char *doc = descr->d_method->ml_doc; - return _PyType_GetDocFromInternalDoc(name, doc); + return _PyType_GetDocFromInternalDoc(descr->d_method->ml_doc); } static PyObject * method_get_text_signature(PyMethodDescrObject *descr, void *closure) { - const char *name = descr->d_method->ml_name; - const char *doc = descr->d_method->ml_doc; - return _PyType_GetTextSignatureFromInternalDoc(name, doc); + return _PyType_GetTextSignatureFromInternalDoc(descr->d_method->ml_doc); } static PyObject * @@ -470,17 +466,13 @@ static PyObject * wrapperdescr_get_doc(PyWrapperDescrObject *descr, void *closure) { - const char *name = descr->d_base->name; - const char *doc = descr->d_base->doc; - return _PyType_GetDocFromInternalDoc(name, doc); + return _PyType_GetDocFromInternalDoc(descr->d_base->doc); } static PyObject * wrapperdescr_get_text_signature(PyWrapperDescrObject *descr, void *closure) { - const char *name = descr->d_base->name; - const char *doc = descr->d_base->doc; - return _PyType_GetTextSignatureFromInternalDoc(name, doc); + return _PyType_GetTextSignatureFromInternalDoc(descr->d_base->doc); } static PyGetSetDef wrapperdescr_getset[] = { @@ -1159,17 +1151,13 @@ static PyObject * wrapper_doc(wrapperobject *wp, void *closure) { - const char *name = wp->descr->d_base->name; - const char *doc = wp->descr->d_base->doc; - return _PyType_GetDocFromInternalDoc(name, doc); + return _PyType_GetDocFromInternalDoc(wp->descr->d_base->doc); } static PyObject * wrapper_text_signature(wrapperobject *wp, void *closure) { - const char *name = wp->descr->d_base->name; - const char *doc = wp->descr->d_base->doc; - return _PyType_GetTextSignatureFromInternalDoc(name, doc); + return _PyType_GetTextSignatureFromInternalDoc(wp->descr->d_base->doc); } static PyObject * diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -72,7 +72,7 @@ /*[clinic input] class dict "PyDictObject *" "&PyDict_Type" [clinic start generated code]*/ -/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=f157a5a0ce9589d6]*/ typedef struct { /* Cached hash code of me_key. */ @@ -1702,7 +1702,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(dict_fromkeys__doc__, -"fromkeys(type, iterable, value=None)\n" +"sig=($type, iterable, value=None)\n" "Returns a new dict with keys from iterable and values equal to value."); #define DICT_FROMKEYS_METHODDEF \ @@ -1730,7 +1730,7 @@ static PyObject * dict_fromkeys_impl(PyTypeObject *type, PyObject *iterable, PyObject *value) -/*[clinic end generated code: checksum=008269e1774a379b356841548c04061fd78a9542]*/ +/*[clinic end generated code: output=aff6e583703dbeba input=b85a667f9bf4669d]*/ { PyObject *it; /* iter(seq) */ PyObject *key; @@ -2209,7 +2209,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(dict___contains____doc__, -"__contains__(self, key)\n" +"sig=($self, key)\n" "True if D has a key k, else False."); #define DICT___CONTAINS___METHODDEF \ @@ -2217,7 +2217,7 @@ static PyObject * dict___contains__(PyDictObject *self, PyObject *key) -/*[clinic end generated code: checksum=744ca54369dda9815a596304087f1b37fafa5960]*/ +/*[clinic end generated code: output=c654684a6d880281 input=b852b2a19b51ab24]*/ { register PyDictObject *mp = self; Py_hash_t hash; diff --git a/Objects/methodobject.c b/Objects/methodobject.c --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -182,17 +182,13 @@ static PyObject * meth_get__text_signature__(PyCFunctionObject *m, void *closure) { - const char *name = m->m_ml->ml_name; - const char *doc = m->m_ml->ml_doc; - return _PyType_GetTextSignatureFromInternalDoc(name, doc); + return _PyType_GetTextSignatureFromInternalDoc(m->m_ml->ml_doc); } static PyObject * meth_get__doc__(PyCFunctionObject *m, void *closure) { - const char *name = m->m_ml->ml_name; - const char *doc = m->m_ml->ml_doc; - return _PyType_GetDocFromInternalDoc(name, doc); + return _PyType_GetDocFromInternalDoc(m->m_ml->ml_doc); } static PyObject * diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -60,18 +60,11 @@ * otherwise returns NULL. */ static const char * -find_signature(const char *name, const char *doc) -{ - size_t length; - if (!doc || !name) - return NULL; - length = strlen(name); - if (strncmp(doc, name, length)) - return NULL; - doc += length; - if (*doc != '(') - return NULL; - return doc; +find_signature(const char *doc) +{ + if (doc && !strncmp(doc, "sig=(", 5)) + return doc + 4; + return NULL; } /* @@ -94,9 +87,9 @@ } static const char * -_PyType_DocWithoutSignature(const char *name, const char *internal_doc) -{ - const char *signature = find_signature(name, internal_doc); +_PyType_DocWithoutSignature(const char *internal_doc) +{ + const char *signature = find_signature(internal_doc); if (signature) return skip_eols(skip_signature(signature)); @@ -104,9 +97,9 @@ } PyObject * -_PyType_GetDocFromInternalDoc(const char *name, const char *internal_doc) -{ - const char *doc = _PyType_DocWithoutSignature(name, internal_doc); +_PyType_GetDocFromInternalDoc(const char *internal_doc) +{ + const char *doc = _PyType_DocWithoutSignature(internal_doc); if (!doc) { Py_INCREF(Py_None); @@ -117,9 +110,9 @@ } PyObject * -_PyType_GetTextSignatureFromInternalDoc(const char *name, const char *internal_doc) -{ - const char *signature = find_signature(name, internal_doc); +_PyType_GetTextSignatureFromInternalDoc(const char *internal_doc) +{ + const char *signature = find_signature(internal_doc); const char *doc; if (!signature) { @@ -706,9 +699,7 @@ { PyObject *result; if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE) && type->tp_doc != NULL) { - const char *name = type->tp_name; - const char *doc = type->tp_doc; - return _PyType_GetDocFromInternalDoc(name, doc); + return _PyType_GetDocFromInternalDoc(type->tp_doc); } result = _PyDict_GetItemId(type->tp_dict, &PyId___doc__); if (result == NULL) { @@ -728,9 +719,7 @@ static PyObject * type_get_text_signature(PyTypeObject *type, void *context) { - const char *name = type->tp_name; - const char *doc = type->tp_doc; - return _PyType_GetTextSignatureFromInternalDoc(name, doc); + return _PyType_GetTextSignatureFromInternalDoc(type->tp_doc); } static int @@ -2608,7 +2597,7 @@ /* need to make a copy of the docstring slot, which usually points to a static string literal */ if (slot->slot == Py_tp_doc) { - const char *old_doc = _PyType_DocWithoutSignature(spec->name, slot->pfunc); + const char *old_doc = _PyType_DocWithoutSignature(slot->pfunc); size_t len = strlen(old_doc)+1; char *tp_doc = PyObject_MALLOC(len); if (tp_doc == NULL) { @@ -3000,7 +2989,7 @@ PyDoc_STRVAR(type_doc, /* this text signature cannot be accurate yet. will fix. --larry */ -"type(object_or_name, bases, dict)\n" +"sig=(object_or_name, bases, dict)\n" "type(object) -> the object's type\n" "type(name, bases, dict) -> a new type"); @@ -4196,7 +4185,7 @@ PyObject_GenericSetAttr, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - PyDoc_STR("object()\nThe most base type"), /* tp_doc */ + PyDoc_STR("sig=()\nThe most base type"), /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ object_richcompare, /* tp_richcompare */ @@ -4663,7 +4652,7 @@ */ if (_PyDict_GetItemId(type->tp_dict, &PyId___doc__) == NULL) { if (type->tp_doc != NULL) { - const char *old_doc = _PyType_DocWithoutSignature(type->tp_name, type->tp_doc); + const char *old_doc = _PyType_DocWithoutSignature(type->tp_doc); PyObject *doc = PyUnicode_FromString(old_doc); if (doc == NULL) goto error; @@ -5325,8 +5314,9 @@ static struct PyMethodDef tp_new_methoddef[] = { {"__new__", (PyCFunction)tp_new_wrapper, METH_VARARGS|METH_KEYWORDS, - PyDoc_STR("T.__new__(S, ...) -> " - "a new object with type S, a subtype of T")}, + PyDoc_STR("sig=($type, *args, **kwargs)\n" + "Create and return a new object. " + "See help(type) for accurate signature.")}, {0} }; @@ -6098,22 +6088,22 @@ ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, DOC) #define UNSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, \ - NAME "(self)\n" DOC) + "sig=($self)\n" DOC) #define IBSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, \ - NAME "(self, value)\nReturns self" DOC "value.") + "sig=($self, value)\nReturn self" DOC "value.") #define BINSLOT(NAME, SLOT, FUNCTION, DOC) \ ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_l, \ - NAME "(self, value)\nReturns self" DOC "value.") + "sig=($self, value)\nReturn self" DOC "value.") #define RBINSLOT(NAME, SLOT, FUNCTION, DOC) \ ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r, \ - NAME "(self, value)\nReturns value" DOC "self.") + "sig=($self, value)\nReturn value" DOC "self.") #define BINSLOTNOTINFIX(NAME, SLOT, FUNCTION, DOC) \ ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_l, \ - NAME "(self, value)\n" DOC) + "sig=($self, value)\n" DOC) #define RBINSLOTNOTINFIX(NAME, SLOT, FUNCTION, DOC) \ ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r, \ - NAME "(self, value)\n" DOC) + "sig=($self, value)\n" DOC) static slotdef slotdefs[] = { TPSLOT("__getattribute__", tp_getattr, NULL, NULL, ""), @@ -6121,52 +6111,52 @@ TPSLOT("__setattr__", tp_setattr, NULL, NULL, ""), TPSLOT("__delattr__", tp_setattr, NULL, NULL, ""), TPSLOT("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc, - "__repr__(self)\nReturns repr(self)."), + "sig=($self)\nReturn repr(self)."), TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc, - "__hash__(self)\nReturns hash(self)."), + "sig=($self)\nReturn hash(self)."), FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call, - "__call__(self, *args, **kwargs)\nCalls self as a function.", + "sig=($self, *args, **kwargs)\nCall self as a function.", PyWrapperFlag_KEYWORDS), TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc, - "__str__(self)\nReturns str(self)."), + "sig=($self)\nReturn str(self)."), TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook, wrap_binaryfunc, - "__getattribute__(self, name)\nReturns getattr(self, name)."), + "sig=($self, name)\nReturn getattr(self, name)."), TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL, ""), TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr, - "__setattr__(self, name, value)\nImplements setattr(self, name, value)."), + "sig=($self, name, value)\nImplement setattr(self, name, value)."), TPSLOT("__delattr__", tp_setattro, slot_tp_setattro, wrap_delattr, - "__delattr__(self, name)\nImplements delattr(self, name)."), + "sig=($self, name)\nImplement delattr(self, name)."), TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare, richcmp_lt, - "__lt__(self, value)\nReturns selfvalue."), + "sig=($self, value)\nReturn self>value."), TPSLOT("__ge__", tp_richcompare, slot_tp_richcompare, richcmp_ge, - "__ge__(self, value)\nReturns self>=value."), + "sig=($self, value)\nReturn self>=value."), TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc, - "__iter__(self)\nImplements iter(self)."), + "sig=($self)\nImplement iter(self)."), TPSLOT("__next__", tp_iternext, slot_tp_iternext, wrap_next, - "__next__(self)\nImplements next(self)."), + "sig=($self)\nImplement next(self)."), TPSLOT("__get__", tp_descr_get, slot_tp_descr_get, wrap_descr_get, - "__get__(self, instance, owner)\nCalled to get an attribute of instance, which is of type owner."), + "sig=($self, instance, owner)\nReturn an attribute of instance, which is of type owner."), TPSLOT("__set__", tp_descr_set, slot_tp_descr_set, wrap_descr_set, - "__set__(self, instance, value)\nSets an attribute of instance to value."), + "sig=($self, instance, value)\nSet an attribute of instance to value."), TPSLOT("__delete__", tp_descr_set, slot_tp_descr_set, wrap_descr_delete, - "__delete__(instance)\nDeletes an attribute of instance."), + "sig=(instance)\nDelete an attribute of instance."), FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)wrap_init, - "__init__(self, *args, **kwargs)\n" - "Initializes self. See help(type(self)) for accurate signature.", + "sig=($self, *args, **kwargs)\n" + "Initialize self. See help(type(self)) for accurate signature.", PyWrapperFlag_KEYWORDS), TPSLOT("__new__", tp_new, slot_tp_new, NULL, - "__new__(cls, *args, **kwargs)\n" - "Creates new object. See help(cls) for accurate signature."), + "sig=(type, *args, **kwargs)\n" + "Create and return new object. See help(type) for accurate signature."), TPSLOT("__del__", tp_finalize, slot_tp_finalize, (wrapperfunc)wrap_del, ""), BINSLOT("__add__", nb_add, slot_nb_add, @@ -6186,13 +6176,13 @@ RBINSLOT("__rmod__", nb_remainder, slot_nb_remainder, "%"), BINSLOTNOTINFIX("__divmod__", nb_divmod, slot_nb_divmod, - "__divmod__(self, value)\nReturns divmod(self, value)."), + "Return divmod(self, value)."), RBINSLOTNOTINFIX("__rdivmod__", nb_divmod, slot_nb_divmod, - "__rdivmod__(self, value)\nReturns divmod(value, self)."), + "Return divmod(value, self)."), NBSLOT("__pow__", nb_power, slot_nb_power, wrap_ternaryfunc, - "__pow__(self, value, mod=None)\nReturns pow(self, value, mod)."), + "sig=($self, value, mod=None)\nReturn pow(self, value, mod)."), NBSLOT("__rpow__", nb_power, slot_nb_power, wrap_ternaryfunc_r, - "__rpow__(self, value, mod=None)\nReturns pow(value, self, mod)."), + "sig=($self, value, mod=None)\nReturn pow(value, self, mod)."), UNSLOT("__neg__", nb_negative, slot_nb_negative, wrap_unaryfunc, "-self"), UNSLOT("__pos__", nb_positive, slot_nb_positive, wrap_unaryfunc, "+self"), UNSLOT("__abs__", nb_absolute, slot_nb_absolute, wrap_unaryfunc, @@ -6243,48 +6233,48 @@ IBSLOT("__itruediv__", nb_inplace_true_divide, slot_nb_inplace_true_divide, wrap_binaryfunc, "/"), NBSLOT("__index__", nb_index, slot_nb_index, wrap_unaryfunc, - "__index__(self)\n" - "Returns self converted to an integer, if self is suitable" + "sig=($self)\n" + "Return self converted to an integer, if self is suitable" "for use as an index into a list."), MPSLOT("__len__", mp_length, slot_mp_length, wrap_lenfunc, - "__len__(self)\nReturns len(self)."), + "sig=($self)\nReturn len(self)."), MPSLOT("__getitem__", mp_subscript, slot_mp_subscript, wrap_binaryfunc, - "__getitem__(self, key)\nReturns self[key]."), + "sig=($self, key)\nReturn self[key]."), MPSLOT("__setitem__", mp_ass_subscript, slot_mp_ass_subscript, wrap_objobjargproc, - "__setitem__(self, key, value)\nSets self[key] to value."), + "sig=($self, key, value)\nSet self[key] to value."), MPSLOT("__delitem__", mp_ass_subscript, slot_mp_ass_subscript, wrap_delitem, - "__delitem__(key)\nDeletes self[key]."), + "sig=(key)\nDelete self[key]."), SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc, - "__len__(self)\nReturns len(self)."), + "sig=($self)\nReturn len(self)."), /* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL. The logic in abstract.c always falls back to nb_add/nb_multiply in this case. Defining both the nb_* and the sq_* slots to call the user-defined methods has unexpected side-effects, as shown by test_descr.notimplemented() */ SQSLOT("__add__", sq_concat, NULL, wrap_binaryfunc, - "__add__(self, value)\nReturns self+value."), + "sig=($self, value)\nReturn self+value."), SQSLOT("__mul__", sq_repeat, NULL, wrap_indexargfunc, - "__mul__(self, value)\nReturns self*value.n"), + "sig=($self, value)\nReturn self*value.n"), SQSLOT("__rmul__", sq_repeat, NULL, wrap_indexargfunc, - "__rmul__(self, value)\nReturns self*value."), + "sig=($self, value)\nReturn self*value."), SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item, - "__getitem__(self, key)\nReturns self[key]."), + "sig=($self, key)\nReturn self[key]."), SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_setitem, - "__setitem__(self, key, value)\nSets self[key] to value."), + "sig=($self, key, value)\nSet self[key] to value."), SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_delitem, - "__delitem__(self, key)\nDeletes self[key]."), + "sig=($self, key)\nDelete self[key]."), SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc, - "__contains__(self, key)\nReturns key in self."), + "sig=($self, key)\nReturn key in self."), SQSLOT("__iadd__", sq_inplace_concat, NULL, wrap_binaryfunc, - "__iadd__(self, value)\nImplements self+=value."), + "sig=($self, value)\nImplement self+=value."), SQSLOT("__imul__", sq_inplace_repeat, NULL, wrap_indexargfunc, - "__imul__(self, value)\nImplements self*=value."), + "sig=($self, value)\nImplement self*=value."), {NULL} }; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -50,7 +50,7 @@ /*[clinic input] class str "PyUnicodeObject *" "&PyUnicode_Type" [clinic start generated code]*/ -/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=604e916854800fa8]*/ /* --- Globals ------------------------------------------------------------ @@ -12885,7 +12885,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(unicode_maketrans__doc__, -"maketrans(x, y=None, z=None)\n" +"sig=(x, y=None, z=None)\n" "Return a translation table usable for str.translate().\n" "\n" "If there is only one argument, it must be a dictionary mapping Unicode\n" @@ -12922,7 +12922,7 @@ static PyObject * unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z) -/*[clinic end generated code: checksum=90a3de8c494b304687e1e0d7e5fa8ba78eac6533]*/ +/*[clinic end generated code: output=ca001ac83ed32269 input=7bfbf529a293c6c5]*/ { PyObject *new = NULL, *key, *value; Py_ssize_t i = 0; diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -34,7 +34,7 @@ /*[clinic input] module _imp [clinic start generated code]*/ -/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=9c332475d8686284]*/ /*[python input] class fs_unicode_converter(CConverter): @@ -42,7 +42,7 @@ converter = 'PyUnicode_FSDecoder' [python start generated code]*/ -/*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=9d6786230166006e]*/ /* Initialize things */ @@ -232,7 +232,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_lock_held__doc__, -"lock_held(module)\n" +"sig=($module)\n" "Return True if the import lock is currently held, else False.\n" "\n" "On platforms without threads, return False."); @@ -251,7 +251,7 @@ static PyObject * _imp_lock_held_impl(PyModuleDef *module) -/*[clinic end generated code: checksum=17172a9917d389dd1564e2108fec34d23aecb6c2]*/ +/*[clinic end generated code: output=5ce46d12a8e4c469 input=9b088f9b217d9bdf]*/ { #ifdef WITH_THREAD return PyBool_FromLong(import_lock_thread != -1); @@ -270,7 +270,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_acquire_lock__doc__, -"acquire_lock(module)\n" +"sig=($module)\n" "Acquires the interpreter\'s import lock for the current thread.\n" "\n" "This lock should be used by import hooks to ensure thread-safety when importing\n" @@ -290,7 +290,7 @@ static PyObject * _imp_acquire_lock_impl(PyModuleDef *module) -/*[clinic end generated code: checksum=20db30e18f6b8758386fe06907edb3f8e43080d7]*/ +/*[clinic end generated code: output=b0dd6a132ad25961 input=4a2d4381866d5fdc]*/ { #ifdef WITH_THREAD _PyImport_AcquireLock(); @@ -308,7 +308,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_release_lock__doc__, -"release_lock(module)\n" +"sig=($module)\n" "Release the interpreter\'s import lock.\n" "\n" "On platforms without threads, this function does nothing."); @@ -327,7 +327,7 @@ static PyObject * _imp_release_lock_impl(PyModuleDef *module) -/*[clinic end generated code: checksum=17749fd7752d2c392447a1f83c5d371f54d7ebd3]*/ +/*[clinic end generated code: output=b1e6e9d723cf5f89 input=934fb11516dd778b]*/ { #ifdef WITH_THREAD if (_PyImport_ReleaseLock() < 0) { @@ -927,7 +927,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp__fix_co_filename__doc__, -"_fix_co_filename(module, code, path)\n" +"sig=($module, code, path)\n" "Changes code.co_filename to specify the passed-in file path.\n" "\n" " code\n" @@ -960,7 +960,7 @@ static PyObject * _imp__fix_co_filename_impl(PyModuleDef *module, PyCodeObject *code, PyObject *path) -/*[clinic end generated code: checksum=d32cf2b2e0480c714f909921cc9e55d763b39dd5]*/ +/*[clinic end generated code: output=3fe5b5a1b0d497df input=895ba50e78b82f05]*/ { update_compiled_module(code, path); @@ -1823,7 +1823,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_extension_suffixes__doc__, -"extension_suffixes(module)\n" +"sig=($module)\n" "Returns the list of file suffixes used to identify extension modules."); #define _IMP_EXTENSION_SUFFIXES_METHODDEF \ @@ -1840,7 +1840,7 @@ static PyObject * _imp_extension_suffixes_impl(PyModuleDef *module) -/*[clinic end generated code: checksum=625c8f11a5bbd4b85373f0a54f7f3ef19c55beb4]*/ +/*[clinic end generated code: output=c1bcfbddabefa00a input=ecdeeecfcb6f839e]*/ { PyObject *list; const char *suffix; @@ -1878,7 +1878,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_init_builtin__doc__, -"init_builtin(module, name)\n" +"sig=($module, name)\n" "Initializes a built-in module."); #define _IMP_INIT_BUILTIN_METHODDEF \ @@ -1905,7 +1905,7 @@ static PyObject * _imp_init_builtin_impl(PyModuleDef *module, PyObject *name) -/*[clinic end generated code: checksum=a4e4805a523757cd3ddfeec6e5b16740678fed6a]*/ +/*[clinic end generated code: output=02437efd4668f53e input=f934d2231ec52a2e]*/ { int ret; PyObject *m; @@ -1932,7 +1932,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_init_frozen__doc__, -"init_frozen(module, name)\n" +"sig=($module, name)\n" "Initializes a frozen module."); #define _IMP_INIT_FROZEN_METHODDEF \ @@ -1959,7 +1959,7 @@ static PyObject * _imp_init_frozen_impl(PyModuleDef *module, PyObject *name) -/*[clinic end generated code: checksum=2a58c119dd3e121cf5a9924f936cfd7b40253c12]*/ +/*[clinic end generated code: output=20cea421af513afe input=13019adfc04f3fb3]*/ { int ret; PyObject *m; @@ -1986,7 +1986,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_get_frozen_object__doc__, -"get_frozen_object(module, name)\n" +"sig=($module, name)\n" "Create a code object for a frozen module."); #define _IMP_GET_FROZEN_OBJECT_METHODDEF \ @@ -2013,7 +2013,7 @@ static PyObject * _imp_get_frozen_object_impl(PyModuleDef *module, PyObject *name) -/*[clinic end generated code: checksum=94c9108b58dda80d187fef21275a009bd0f91e96]*/ +/*[clinic end generated code: output=f00d01ae30ec842f input=ed689bc05358fdbd]*/ { return get_frozen_object(name); } @@ -2028,7 +2028,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_is_frozen_package__doc__, -"is_frozen_package(module, name)\n" +"sig=($module, name)\n" "Returns True if the module name is of a frozen package."); #define _IMP_IS_FROZEN_PACKAGE_METHODDEF \ @@ -2055,7 +2055,7 @@ static PyObject * _imp_is_frozen_package_impl(PyModuleDef *module, PyObject *name) -/*[clinic end generated code: checksum=17a342b94dbe859cdfc361bc8a6bc1b3cb163364]*/ +/*[clinic end generated code: output=35c78f2448c6fcff input=81b6cdecd080fbb8]*/ { return is_frozen_package(name); } @@ -2070,7 +2070,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_is_builtin__doc__, -"is_builtin(module, name)\n" +"sig=($module, name)\n" "Returns True if the module name corresponds to a built-in module."); #define _IMP_IS_BUILTIN_METHODDEF \ @@ -2097,7 +2097,7 @@ static PyObject * _imp_is_builtin_impl(PyModuleDef *module, PyObject *name) -/*[clinic end generated code: checksum=51c6139dcfd9bee1f40980ea68b7797f8489d69a]*/ +/*[clinic end generated code: output=641689f833347f66 input=86befdac021dd1c7]*/ { return PyLong_FromLong(is_builtin(name)); } @@ -2112,7 +2112,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_is_frozen__doc__, -"is_frozen(module, name)\n" +"sig=($module, name)\n" "Returns True if the module name corresponds to a frozen module."); #define _IMP_IS_FROZEN_METHODDEF \ @@ -2139,7 +2139,7 @@ static PyObject * _imp_is_frozen_impl(PyModuleDef *module, PyObject *name) -/*[clinic end generated code: checksum=4b079fb45a495835056ea5604735d552d222be5c]*/ +/*[clinic end generated code: output=0f80c7a3f283a686 input=7301dbca1897d66b]*/ { const struct _frozen *p; @@ -2161,7 +2161,7 @@ [clinic start generated code]*/ PyDoc_STRVAR(_imp_load_dynamic__doc__, -"load_dynamic(module, name, path, file=None)\n" +"sig=($module, name, path, file=None)\n" "Loads an extension module."); #define _IMP_LOAD_DYNAMIC_METHODDEF \ @@ -2190,7 +2190,7 @@ static PyObject * _imp_load_dynamic_impl(PyModuleDef *module, PyObject *name, PyObject *path, PyObject *file) -/*[clinic end generated code: checksum=63e051fd0d0350c785bf185be41b0892f9920622]*/ +/*[clinic end generated code: output=8f33f48dc6252948 input=af64f06e4bad3526]*/ { PyObject *mod; FILE *fp; diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -19,6 +19,7 @@ import pprint import re import shlex +import string import sys import tempfile import textwrap @@ -98,7 +99,7 @@ if clinic: if filename is None: filename = clinic.filename - if clinic.block_parser and (line_number is None): + if getattr(clinic, 'block_parser', None) and (line_number is None): line_number = clinic.block_parser.line_number if filename is not None: add(' in file "' + filename + '"') @@ -335,6 +336,22 @@ self.cleanup = [] +class FormatCounterFormatter(string.Formatter): + """ + This counts how many instances of each formatter + "replacement string" appear in the format string. + + e.g. after evaluating "string {a}, {b}, {c}, {a}" + the counts dict would now look like + {'a': 2, 'b': 1, 'c': 1} + """ + def __init__(self): + self.counts = collections.Counter() + + def get_value(self, key, args, kwargs): + self.counts[key] += 1 + return '' + class Language(metaclass=abc.ABCMeta): start_line = "" @@ -347,18 +364,59 @@ pass def validate(self): - def assert_only_one(field, token='dsl_name'): - line = getattr(self, field) - token = '{' + token + '}' - if len(line.split(token)) != 2: - fail(self.__class__.__name__ + " " + field + " must contain " + token + " exactly once!") + def assert_only_one(attr, *additional_fields): + """ + Ensures that the string found at getattr(self, attr) + contains exactly one formatter replacement string for + each valid field. The list of valid fields is + ['dsl_name'] extended by additional_fields. + + e.g. + self.fmt = "{dsl_name} {a} {b}" + + # this passes + self.assert_only_one('fmt', 'a', 'b') + + # this fails, the format string has a {b} in it + self.assert_only_one('fmt', 'a') + + # this fails, the format string doesn't have a {c} in it + self.assert_only_one('fmt', 'a', 'b', 'c') + + # this fails, the format string has two {a}s in it, + # it must contain exactly one + self.fmt2 = '{dsl_name} {a} {a}' + self.assert_only_one('fmt2', 'a') + + """ + fields = ['dsl_name'] + fields.extend(additional_fields) + line = getattr(self, attr) + fcf = FormatCounterFormatter() + fcf.format(line) + def local_fail(should_be_there_but_isnt): + if should_be_there_but_isnt: + fail("{} {} must contain {{{}}} exactly once!".format( + self.__class__.__name__, attr, name)) + else: + fail("{} {} must not contain {{{}}}!".format( + self.__class__.__name__, attr, name)) + + for name, count in fcf.counts.items(): + if name in fields: + if count > 1: + local_fail(True) + else: + local_fail(False) + for name in fields: + if fcf.counts.get(name) != 1: + local_fail(True) + assert_only_one('start_line') assert_only_one('stop_line') - assert_only_one('checksum_line') - assert_only_one('checksum_line', 'checksum') - - if len(self.body_prefix.split('{dsl_name}')) >= 3: - fail(self.__class__.__name__ + " body_prefix may contain " + token + " once at most!") + + field = "arguments" if "{arguments}" in self.checksum_line else "checksum" + assert_only_one('checksum_line', field) @@ -368,7 +426,7 @@ start_line = "#/*[{dsl_name} input]" body_prefix = "#" stop_line = "#[{dsl_name} start generated code]*/" - checksum_line = "#/*[{dsl_name} end generated code: checksum={checksum}]*/" + checksum_line = "#/*[{dsl_name} end generated code: {arguments}]*/" def permute_left_option_groups(l): @@ -438,7 +496,7 @@ start_line = "/*[{dsl_name} input]" body_prefix = "" stop_line = "[{dsl_name} start generated code]*/" - checksum_line = "/*[{dsl_name} end generated code: checksum={checksum}]*/" + checksum_line = "/*[{dsl_name} end generated code: {arguments}]*/" def render(self, clinic, signatures): function = None @@ -1103,10 +1161,12 @@ sys.stdout = saved_stdout -def create_regex(before, after): +def create_regex(before, after, word=True): """Create an re object for matching marker lines.""" - pattern = r'^{}(\w+){}$' - return re.compile(pattern.format(re.escape(before), re.escape(after))) + group_re = "\w+" if word else ".+" + pattern = r'^{}({}){}$' + pattern = pattern.format(re.escape(before), group_re, re.escape(after)) + return re.compile(pattern) class Block: @@ -1164,6 +1224,16 @@ self.indent = indent self.preindent = preindent + def __repr__(self): + dsl_name = self.dsl_name or "text" + def summarize(s): + s = repr(s) + if len(s) > 30: + return s[:26] + "..." + s[0] + return s + return "".join(( + "")) + class BlockParser: """ @@ -1264,29 +1334,43 @@ if self.last_dsl_name == dsl_name: checksum_re = self.last_checksum_re else: - before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, checksum='{checksum}').partition('{checksum}') - assert _ == '{checksum}' - checksum_re = create_regex(before, after) + before, _, after = self.language.checksum_line.format(dsl_name=dsl_name, arguments='{arguments}').partition('{arguments}') + assert _ == '{arguments}' + checksum_re = create_regex(before, after, word=False) self.last_dsl_name = dsl_name self.last_checksum_re = checksum_re # scan forward for checksum line output_add, output_output = text_accumulator() - checksum = None + arguments = None while self.input: line = self._line() match = checksum_re.match(line.lstrip()) - checksum = match.group(1) if match else None - if checksum: + arguments = match.group(1) if match else None + if arguments: break output_add(line) if self.is_start_line(line): break output = output_output() - if checksum: + if arguments: + d = {} + for field in shlex.split(arguments): + name, equals, value = field.partition('=') + if not equals: + fail("Mangled Argument Clinic marker line: {!r}".format(line)) + d[name.strip()] = value.strip() + if self.verify: - computed = compute_checksum(output) + if 'input' in d: + checksum = d['output'] + input_checksum = d['input'] + else: + checksum = d['checksum'] + input_checksum = None + + computed = compute_checksum(output, len(checksum)) if checksum != computed: fail("Checksum mismatch!\nExpected: {}\nComputed: {}\n" "Suggested fix: remove all generated code including " @@ -1336,13 +1420,15 @@ write(self.language.stop_line.format(dsl_name=dsl_name)) write("\n") + input = ''.join(block.input) output = ''.join(block.output) if output: if not output.endswith('\n'): output += '\n' write(output) - write(self.language.checksum_line.format(dsl_name=dsl_name, checksum=compute_checksum(output))) + arguments="output={} input={}".format(compute_checksum(output, 16), compute_checksum(input, 16)) + write(self.language.checksum_line.format(dsl_name=dsl_name, arguments=arguments)) write("\n") def write(self, text): @@ -1468,7 +1554,7 @@ """ - def __init__(self, language, printer=None, *, verify=True, filename=None): + def __init__(self, language, printer=None, *, force=False, verify=True, filename=None): # maps strings to Parser objects. # (instantiated from the "parsers" global.) self.parsers = {} @@ -1477,6 +1563,7 @@ fail("Custom printers are broken right now") self.printer = printer or BlockPrinter(language) self.verify = verify + self.force = force self.filename = filename self.modules = collections.OrderedDict() self.classes = collections.OrderedDict() @@ -1594,11 +1681,12 @@ fail("Can't write to destination {}, " "can't make directory {}!".format( destination.filename, dirname)) - with open(destination.filename, "rt") as f: - parser_2 = BlockParser(f.read(), language=self.language) - blocks = list(parser_2) - if (len(blocks) != 1) or (blocks[0].input != 'preserve\n'): - fail("Modified destination file " + repr(destination.filename) + ", not overwriting!") + if self.verify: + with open(destination.filename, "rt") as f: + parser_2 = BlockParser(f.read(), language=self.language) + blocks = list(parser_2) + if (len(blocks) != 1) or (blocks[0].input != 'preserve\n'): + fail("Modified destination file " + repr(destination.filename) + ", not overwriting!") except FileNotFoundError: pass @@ -1658,7 +1746,7 @@ return module, cls -def parse_file(filename, *, verify=True, output=None, encoding='utf-8'): +def parse_file(filename, *, force=False, verify=True, output=None, encoding='utf-8'): extension = os.path.splitext(filename)[1][1:] if not extension: fail("Can't extract file type for file " + repr(filename)) @@ -1668,13 +1756,13 @@ except KeyError: fail("Can't identify file type for file " + repr(filename)) - clinic = Clinic(language, verify=verify, filename=filename) + clinic = Clinic(language, force=force, verify=verify, filename=filename) with open(filename, 'r', encoding=encoding) as f: raw = f.read() cooked = clinic.parse(raw) - if cooked == raw: + if (cooked == raw) and not force: return directory = os.path.dirname(filename) or '.' @@ -1687,9 +1775,12 @@ os.replace(tmpfilename, output or filename) -def compute_checksum(input): +def compute_checksum(input, length=None): input = input or '' - return hashlib.sha1(input.encode('utf-8')).hexdigest() + s = hashlib.sha1(input.encode('utf-8')).hexdigest() + if length: + s = s[:length] + return s @@ -1826,7 +1917,8 @@ module, cls=None, c_basename=None, full_name=None, return_converter, return_annotation=_empty, - docstring=None, kind=CALLABLE, coexist=False): + docstring=None, kind=CALLABLE, coexist=False, + suppress_signature=False): self.parameters = parameters or collections.OrderedDict() self.return_annotation = return_annotation self.name = name @@ -1840,6 +1932,7 @@ self.kind = kind self.coexist = coexist self.self_converter = None + self.suppress_signature = suppress_signature @property def methoddef_flags(self): @@ -3520,6 +3613,7 @@ else: fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)") self.group += 1 + self.function.suppress_signature = True elif symbol == ']': if not self.group: fail("Function " + self.function.name + " has a ] without a matching [.") @@ -3615,11 +3709,14 @@ ## docstring first line ## - if new_or_init: - assert f.cls - add(f.cls.name) + if not f.suppress_signature: + add('sig=') else: - add(f.name) + if new_or_init: + assert f.cls + add(f.cls.name) + else: + add(f.name) add('(') # populate "right_bracket_count" field for every parameter @@ -3673,7 +3770,17 @@ add_comma = True name = p.converter.signature_name or p.name - a = [name] + + a = [] + if isinstance(p.converter, self_converter) and not f.suppress_signature: + # annotate first parameter as being a "self". + # + # if inspect.Signature gets this function, and it's already bound, + # the self parameter will be stripped off. + # + # if it's not bound, it should be marked as positional-only. + a.append('$') + a.append(name) if p.converter.is_optional(): a.append('=') value = p.converter.py_default @@ -3915,7 +4022,7 @@ path = os.path.join(root, filename) if ns.verbose: print(path) - parse_file(path, verify=not ns.force) + parse_file(path, force=ns.force, verify=not ns.force) return if not ns.filename: @@ -3931,7 +4038,7 @@ for filename in ns.filename: if ns.verbose: print(filename) - parse_file(filename, output=ns.output, verify=not ns.force) + parse_file(filename, output=ns.output, force=ns.force, verify=not ns.force) if __name__ == "__main__": -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 28 14:26:53 2014 From: python-checkins at python.org (nick.coghlan) Date: Tue, 28 Jan 2014 14:26:53 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Clarify_purelib_vs_platlib_in?= =?utf-8?q?_PEP_427?= Message-ID: <3fD7s96lYGz7Ljc@mail.python.org> http://hg.python.org/peps/rev/8a53c2356865 changeset: 5363:8a53c2356865 user: Nick Coghlan date: Tue Jan 28 23:21:43 2014 +1000 summary: Clarify purelib vs platlib in PEP 427 files: pep-0427.txt | 11 ++++++----- 1 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pep-0427.txt b/pep-0427.txt --- a/pep-0427.txt +++ b/pep-0427.txt @@ -367,18 +367,19 @@ update system. Wheel only provides the building block. What's the deal with "purelib" vs. "platlib"? - Wheel preserves the historic "purelib" vs. "platlib" distinction - even though both map to the same install location in any system the - author could find. + Wheel preserves the "purelib" vs. "platlib" distinction, which is + significant on some platforms. For example, Fedora installs pure + Python packages to '/usr/lib/pythonX.Y/site-packages' and platform + dependent packages to '/usr/lib64/pythonX.Y/site-packages'. - For example, a wheel with "Root-Is-Purelib: false" with all its files + A wheel with "Root-Is-Purelib: false" with all its files in ``{name}-{version}.data/purelib`` is equivalent to a wheel with "Root-Is-Purelib: true" with those same files in the root, and it is legal to have files in both the "purelib" and "platlib" categories. In practice a wheel should have only one of "purelib" or "platlib" depending on whether it is pure Python or not and those files should - be at the root. + be at the root with the appropriate setting given for "Root-is-purelib". References ========== -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Jan 28 14:26:55 2014 From: python-checkins at python.org (nick.coghlan) Date: Tue, 28 Jan 2014 14:26:55 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Clarify_wheels_support_zipimp?= =?utf-8?q?ort?= Message-ID: <3fD7sC0z0mz7Ljh@mail.python.org> http://hg.python.org/peps/rev/811e34eda04c changeset: 5364:811e34eda04c user: Nick Coghlan date: Tue Jan 28 23:26:43 2014 +1000 summary: Clarify wheels support zipimport files: pep-0427.txt | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/pep-0427.txt b/pep-0427.txt --- a/pep-0427.txt +++ b/pep-0427.txt @@ -381,6 +381,14 @@ depending on whether it is pure Python or not and those files should be at the root with the appropriate setting given for "Root-is-purelib". +Is it possible to import Python code directly from a wheel file? + Yes, the wheel format is deliberately designed to be compatible with + Python's support for importing from zip files. While not all wheels + will support being used that way (for example, if they include C + extensions), most pure Python wheels can be used that way just by + placing their name on ``sys.path``. + + References ========== -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue Jan 28 15:05:36 2014 From: python-checkins at python.org (stefan.krah) Date: Tue, 28 Jan 2014 15:05:36 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=239709=3A_Revert_97?= =?utf-8?q?fb852c5c26=2E_Many_extensions_are_not_using_PyMODINIT=5FFUNC=2E?= Message-ID: <3fD8jr5mzZz7LjP@mail.python.org> http://hg.python.org/cpython/rev/69827c2ab9d0 changeset: 88793:69827c2ab9d0 user: Stefan Krah date: Tue Jan 28 15:04:40 2014 +0100 summary: Issue #9709: Revert 97fb852c5c26. Many extensions are not using PyMODINIT_FUNC. files: Lib/distutils/command/build_ext.py | 2 +- 1 files changed, 1 insertions(+), 1 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 @@ -538,7 +538,7 @@ library_dirs=ext.library_dirs, runtime_library_dirs=ext.runtime_library_dirs, extra_postargs=extra_args, - export_symbols=ext.export_symbols, + export_symbols=self.get_export_symbols(ext), debug=self.debug, build_temp=self.build_temp, target_lang=language) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 28 15:18:12 2014 From: python-checkins at python.org (jason.coombs) Date: Tue, 28 Jan 2014 15:18:12 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320411=3A_Use_read?= =?utf-8?q?line=2Eget=5Fcurrent=5Fhistory=5Flength_to_check_for_the_presen?= =?utf-8?q?ce?= Message-ID: <3fD90N4YPPz7Ljh@mail.python.org> http://hg.python.org/cpython/rev/ca6efeedfc0e changeset: 88794:ca6efeedfc0e user: Jason R. Coombs date: Tue Jan 28 09:06:58 2014 -0500 summary: Issue #20411: Use readline.get_current_history_length to check for the presence of a history, rather than get_history_item, which assumes a history is present. files: Lib/site.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/site.py b/Lib/site.py --- a/Lib/site.py +++ b/Lib/site.py @@ -409,7 +409,7 @@ # want to ignore the exception. pass - if readline.get_history_item(1) is None: + if readline.get_current_history_length() == 0: # If no history was loaded, default to .python_history. # The guard is necessary to avoid doubling history size at # each interpreter exit when readline was already configured -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 28 18:20:05 2014 From: python-checkins at python.org (yury.selivanov) Date: Tue, 28 Jan 2014 18:20:05 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2Etests=3A_Remove_?= =?utf-8?q?redundant_unittest?= Message-ID: <3fDF2F71GczSZT@mail.python.org> http://hg.python.org/cpython/rev/72d9d000163e changeset: 88795:72d9d000163e user: Yury Selivanov date: Tue Jan 28 12:19:52 2014 -0500 summary: inspect.tests: Remove redundant unittest The removed unittest duplicates the other one (test_signature_on_builtins_no_signature) files: Lib/test/test_inspect.py | 5 ----- 1 files changed, 0 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1593,11 +1593,6 @@ ('kwargs', ..., int, "var_keyword")), ...)) - def test_signature_on_unsupported_builtins(self): - with self.assertRaisesRegex(ValueError, 'no signature found'): - # min simply doesn't have a signature (yet) - inspect.signature(min) - @unittest.skipIf(MISSING_C_DOCSTRINGS, "Signature information for builtins requires docstrings") def test_signature_on_builtins(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 28 18:26:42 2014 From: python-checkins at python.org (yury.selivanov) Date: Tue, 28 Jan 2014 18:26:42 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2Esignature=3A_Han?= =?utf-8?q?dle_bound_methods_with_=27=28*args=29=27_signature_correctly?= Message-ID: <3fDF9t12gFz7Lk7@mail.python.org> http://hg.python.org/cpython/rev/3544827d42e6 changeset: 88796:3544827d42e6 user: Yury Selivanov date: Tue Jan 28 12:26:24 2014 -0500 summary: inspect.signature: Handle bound methods with '(*args)' signature correctly #20401 files: Lib/inspect.py | 39 ++++++++++++++++++++++++--- Lib/test/test_inspect.py | 25 ++++++++++++++--- 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1440,7 +1440,11 @@ return meth -def _get_partial_signature(wrapped_sig, partial, extra_args=()): +def _signature_get_partial(wrapped_sig, partial, extra_args=()): + # Internal helper to calculate how 'wrapped_sig' signature will + # look like after applying a 'functools.partial' object (or alike) + # on it. + new_params = OrderedDict(wrapped_sig.parameters.items()) partial_args = partial.args or () @@ -1485,6 +1489,31 @@ return wrapped_sig.replace(parameters=new_params.values()) +def _signature_bound_method(sig): + # Internal helper to transform signatures for unbound + # functions to bound methods + + params = tuple(sig.parameters.values()) + + if not params or params[0].kind in (_VAR_KEYWORD, _KEYWORD_ONLY): + raise ValueError('invalid method signature') + + kind = params[0].kind + if kind in (_POSITIONAL_OR_KEYWORD, _POSITIONAL_ONLY): + # Drop first parameter: + # '(p1, p2[, ...])' -> '(p2[, ...])' + params = params[1:] + else: + if kind is not _VAR_POSITIONAL: + # Unless we add a new parameter type we never + # get here + raise ValueError('invalid argument type') + # It's a var-positional parameter. + # Do nothing. '(*args[, ...])' -> '(*args[, ...])' + + return sig.replace(parameters=params) + + def signature(obj): '''Get a signature object for the passed callable.''' @@ -1502,7 +1531,7 @@ # In this case we skip the first parameter of the underlying # function (usually `self` or `cls`). sig = signature(obj.__func__) - return sig.replace(parameters=tuple(sig.parameters.values())[1:]) + return _signature_bound_method(sig) # Was this function wrapped by a decorator? obj = unwrap(obj, stop=(lambda f: hasattr(f, "__signature__"))) @@ -1528,7 +1557,7 @@ # automatically (as for boundmethods) wrapped_sig = signature(partialmethod.func) - sig = _get_partial_signature(wrapped_sig, partialmethod, (None,)) + sig = _signature_get_partial(wrapped_sig, partialmethod, (None,)) first_wrapped_param = tuple(wrapped_sig.parameters.values())[0] new_params = (first_wrapped_param,) + tuple(sig.parameters.values()) @@ -1540,7 +1569,7 @@ if isinstance(obj, functools.partial): wrapped_sig = signature(obj.func) - return _get_partial_signature(wrapped_sig, obj) + return _signature_get_partial(wrapped_sig, obj) sig = None if isinstance(obj, type): @@ -1584,7 +1613,7 @@ if sig is not None: # For classes and objects we skip the first parameter of their # __call__, __new__, or __init__ methods - return sig.replace(parameters=tuple(sig.parameters.values())[1:]) + return _signature_bound_method(sig) if isinstance(obj, types.BuiltinFunctionType): # Raise a nicer error message for builtins diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1669,16 +1669,31 @@ def test_signature_on_method(self): class Test: - def foo(self, arg1, arg2=1) -> int: + def __init__(*args): pass - - meth = Test().foo - - self.assertEqual(self.signature(meth), + def m1(self, arg1, arg2=1) -> int: + pass + def m2(*args): + pass + def __call__(*, a): + pass + + self.assertEqual(self.signature(Test().m1), ((('arg1', ..., ..., "positional_or_keyword"), ('arg2', 1, ..., "positional_or_keyword")), int)) + self.assertEqual(self.signature(Test().m2), + ((('args', ..., ..., "var_positional"),), + ...)) + + self.assertEqual(self.signature(Test), + ((('args', ..., ..., "var_positional"),), + ...)) + + with self.assertRaisesRegex(ValueError, 'invalid method signature'): + self.signature(Test()) + def test_signature_on_classmethod(self): class Test: @classmethod -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 28 22:40:06 2014 From: python-checkins at python.org (yury.selivanov) Date: Tue, 28 Jan 2014 22:40:06 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=3A_Fix_docstrings_?= =?utf-8?q?for_Parameter_=26_Signature_classes?= Message-ID: <3fDLpG5QGvz7LjZ@mail.python.org> http://hg.python.org/cpython/rev/d3a4e17c5058 changeset: 88797:d3a4e17c5058 user: Yury Selivanov date: Tue Jan 28 16:39:25 2014 -0500 summary: inspect: Fix docstrings for Parameter & Signature classes files: Lib/inspect.py | 8 +++++--- 1 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1660,10 +1660,12 @@ The name of the parameter as a string. * default : object The default value for the parameter if specified. If the - parameter has no default value, this attribute is not set. + parameter has no default value, this attribute is set to + `Parameter.empty`. * annotation The annotation for the parameter if specified. If the - parameter has no annotation, this attribute is not set. + parameter has no annotation, this attribute is set to + `Parameter.empty`. * kind : str Describes how argument values are bound to the parameter. Possible values: `Parameter.POSITIONAL_ONLY`, @@ -1888,7 +1890,7 @@ * return_annotation : object The annotation for the return type of the function if specified. If the function has no annotation for its return type, this - attribute is not set. + attribute is set to `Signature.empty`. * bind(*args, **kwargs) -> BoundArguments Creates a mapping from positional and keyword arguments to parameters. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 28 23:28:59 2014 From: python-checkins at python.org (yury.selivanov) Date: Tue, 28 Jan 2014 23:28:59 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2ESignature=2Ebind?= =?utf-8?q?=3A_Fix_pos-only_params_with_defaults=3B_fix_*args_in_named?= Message-ID: <3fDMtg6wYtz7LkM@mail.python.org> http://hg.python.org/cpython/rev/9cb32426d580 changeset: 88798:9cb32426d580 user: Yury Selivanov date: Tue Jan 28 17:27:39 2014 -0500 summary: inspect.Signature.bind: Fix pos-only params with defaults; fix *args in named args #19140 Initial patch by Yann Kaiser (epsy). files: Lib/inspect.py | 16 ++++++++-------- Lib/test/test_inspect.py | 25 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -2258,6 +2258,8 @@ parameters_ex = (param,) break else: + # No default, not VAR_KEYWORD, not VAR_POSITIONAL, + # not in `kwargs` if partial: parameters_ex = (param,) break @@ -2296,19 +2298,17 @@ # keyword arguments kwargs_param = None for param in itertools.chain(parameters_ex, parameters): - if param.kind == _POSITIONAL_ONLY: - # This should never happen in case of a properly built - # Signature object (but let's have this check here - # to ensure correct behaviour just in case) - raise TypeError('{arg!r} parameter is positional only, ' - 'but was passed as a keyword'. \ - format(arg=param.name)) - if param.kind == _VAR_KEYWORD: # Memorize that we have a '**kwargs'-like parameter kwargs_param = param continue + if param.kind == _VAR_POSITIONAL: + # Named arguments don't refer to '*args'-like parameters. + # We only arrive here if the positional arguments ended + # before reaching the last parameter before *args. + continue + param_name = param.name try: arg_val = kwargs.pop(param_name) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -2516,6 +2516,15 @@ self.assertEqual(self.call(test, 1, 2, 4, 5, bar=6), (1, 2, 4, 5, 6, {})) + self.assertEqual(self.call(test, 1, 2), + (1, 2, 3, 42, 50, {})) + + self.assertEqual(self.call(test, 1, 2, foo=4, bar=5), + (1, 2, 3, 4, 5, {})) + + with self.assertRaisesRegex(TypeError, "but was passed as a keyword"): + self.call(test, 1, 2, foo=4, bar=5, c_po=10) + with self.assertRaisesRegex(TypeError, "parameter is positional only"): self.call(test, 1, 2, c_po=4) @@ -2532,6 +2541,22 @@ ba = sig.bind(1, self=2, b=3) self.assertEqual(ba.args, (1, 2, 3)) + def test_signature_bind_vararg_name(self): + def test(a, *args): + return a, args + sig = inspect.signature(test) + + with self.assertRaisesRegex(TypeError, "too many keyword arguments"): + sig.bind(a=0, args=1) + + def test(*args, **kwargs): + return args, kwargs + self.assertEqual(self.call(test, args=1), ((), {'args': 1})) + + sig = inspect.signature(test) + ba = sig.bind(args=1) + self.assertEqual(ba.arguments, {'kwargs': {'args': 1}}) + class TestBoundArguments(unittest.TestCase): def test_signature_bound_arguments_unhashable(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue Jan 28 23:33:12 2014 From: python-checkins at python.org (victor.stinner) Date: Tue, 28 Jan 2014 23:33:12 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio_doc=3A_close_the_l?= =?utf-8?q?oop_at_exit?= Message-ID: <3fDMzX0Hywz7Ljp@mail.python.org> http://hg.python.org/cpython/rev/824ba744b999 changeset: 88799:824ba744b999 user: Victor Stinner date: Tue Jan 28 23:32:40 2014 +0100 summary: asyncio doc: close the loop at exit files: Doc/library/asyncio-dev.rst | 1 + Doc/library/asyncio-stream.rst | 1 + Doc/library/asyncio-task.rst | 3 +++ 3 files changed, 5 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 @@ -169,6 +169,7 @@ asyncio.async(test()) loop.run_forever() print("Pending tasks at exit: %s" % asyncio.Task.all_tasks(loop)) + loop.close() Expected output:: 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 @@ -256,6 +256,7 @@ loop = asyncio.get_event_loop() task = asyncio.async(print_http_headers(url)) loop.run_until_complete(task) + loop.close() Usage:: 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 @@ -107,6 +107,7 @@ loop = asyncio.get_event_loop() loop.run_until_complete(print_sum(1, 2)) + loop.close() ``compute()`` is chained to ``print_sum()``: ``print_sum()`` coroutine waits until ``compute()`` is completed before returing its result. @@ -234,6 +235,7 @@ asyncio.Task(slow_operation(future)) loop.run_until_complete(future) print(future.result()) + loop.close() The coroutine function is responsible of the computation (which takes 1 second) and it stores the result into the future. The @@ -354,6 +356,7 @@ loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks)) + loop.close() Output:: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 02:54:42 2014 From: python-checkins at python.org (yury.selivanov) Date: Wed, 29 Jan 2014 02:54:42 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2ESignature=2Ebind?= =?utf-8?q?=3A_Add_**kwargs/positional-only_check_back?= Message-ID: <3fDSS250G7zNQP@mail.python.org> http://hg.python.org/cpython/rev/ec6bd526b70a changeset: 88800:ec6bd526b70a user: Yury Selivanov date: Tue Jan 28 20:54:28 2014 -0500 summary: inspect.Signature.bind: Add **kwargs/positional-only check back files: Lib/inspect.py | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -2323,6 +2323,14 @@ format(arg=param_name)) from None else: + if param.kind == _POSITIONAL_ONLY: + # This should never happen in case of a properly built + # Signature object (but let's have this check here + # to ensure correct behaviour just in case) + raise TypeError('{arg!r} parameter is positional only, ' + 'but was passed as a keyword'. \ + format(arg=param.name)) + arguments[param_name] = arg_val if kwargs: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 05:14:37 2014 From: python-checkins at python.org (terry.reedy) Date: Wed, 29 Jan 2014 05:14:37 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSWRsZWxpYjogc2ls?= =?utf-8?q?ence_two_buildbot_Deprecation_Warnings_with_better_code=2E?= Message-ID: <3fDWYT1LJGz7Ljh@mail.python.org> http://hg.python.org/cpython/rev/d45436cb8870 changeset: 88801:d45436cb8870 branch: 2.7 parent: 88791:ca5431a434d6 user: Terry Jan Reedy date: Tue Jan 28 23:13:35 2014 -0500 summary: Idlelib: silence two buildbot Deprecation Warnings with better code. files: Lib/idlelib/Debugger.py | 4 ++-- Lib/idlelib/SearchEngine.py | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Lib/idlelib/Debugger.py b/Lib/idlelib/Debugger.py --- a/Lib/idlelib/Debugger.py +++ b/Lib/idlelib/Debugger.py @@ -253,8 +253,8 @@ if self.vsource.get(): self.sync_source_line() - def show_frame(self, (frame, lineno)): - self.frame = frame + def show_frame(self, stackitem): + self.frame = stackitem[0] # lineno is stackitem[1] self.show_variables() localsviewer = None diff --git a/Lib/idlelib/SearchEngine.py b/Lib/idlelib/SearchEngine.py --- a/Lib/idlelib/SearchEngine.py +++ b/Lib/idlelib/SearchEngine.py @@ -83,11 +83,9 @@ try: prog = re.compile(pat, flags) except re.error as what: - try: - msg, col = what - except: - msg = str(what) - col = -1 + args = what.args + msg = args[0] + col = arg[1] if len(args) >= 2 else -1 self.report_error(pat, msg, col) return None return prog @@ -231,6 +229,6 @@ return line, col if __name__ == "__main__": - from test import support; support.use_resources = ['gui'] + from test import test_support; test_support.use_resources = ['gui'] import unittest unittest.main('idlelib.idle_test.test_searchengine', verbosity=2, exit=False) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 05:14:38 2014 From: python-checkins at python.org (terry.reedy) Date: Wed, 29 Jan 2014 05:14:38 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSWRsZWxpYjogZm9y?= =?utf-8?q?ward_port_changes_that_silenced_2=2E7_-3_deprecation_warnings_a?= =?utf-8?q?nd?= Message-ID: <3fDWYV2ktvz7Ljh@mail.python.org> http://hg.python.org/cpython/rev/14782875030c changeset: 88802:14782875030c branch: 3.3 parent: 88780:f4377699fd47 user: Terry Jan Reedy date: Tue Jan 28 23:13:45 2014 -0500 summary: Idlelib: forward port changes that silenced 2.7 -3 deprecation warnings and which are at least as efficient. On Py3, unpacking exceptions never works. files: Lib/idlelib/Debugger.py | 3 +-- Lib/idlelib/SearchEngine.py | 8 +++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Lib/idlelib/Debugger.py b/Lib/idlelib/Debugger.py --- a/Lib/idlelib/Debugger.py +++ b/Lib/idlelib/Debugger.py @@ -254,8 +254,7 @@ self.sync_source_line() def show_frame(self, stackitem): - frame, lineno = stackitem - self.frame = frame + self.frame = stackitem[0] # lineno is stackitem[1] self.show_variables() localsviewer = None diff --git a/Lib/idlelib/SearchEngine.py b/Lib/idlelib/SearchEngine.py --- a/Lib/idlelib/SearchEngine.py +++ b/Lib/idlelib/SearchEngine.py @@ -83,11 +83,9 @@ try: prog = re.compile(pat, flags) except re.error as what: - try: - msg, col = what - except: - msg = str(what) - col = -1 + args = what.args + msg = args[0] + col = arg[1] if len(args) >= 2 else -1 self.report_error(pat, msg, col) return None return prog -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 05:14:39 2014 From: python-checkins at python.org (terry.reedy) Date: Wed, 29 Jan 2014 05:14:39 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E3?= Message-ID: <3fDWYW4TQ8z7LlW@mail.python.org> http://hg.python.org/cpython/rev/664d83a17710 changeset: 88803:664d83a17710 parent: 88800:ec6bd526b70a parent: 88802:14782875030c user: Terry Jan Reedy date: Tue Jan 28 23:14:12 2014 -0500 summary: Merge with 3.3 files: Lib/idlelib/Debugger.py | 3 +-- Lib/idlelib/SearchEngine.py | 8 +++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Lib/idlelib/Debugger.py b/Lib/idlelib/Debugger.py --- a/Lib/idlelib/Debugger.py +++ b/Lib/idlelib/Debugger.py @@ -254,8 +254,7 @@ self.sync_source_line() def show_frame(self, stackitem): - frame, lineno = stackitem - self.frame = frame + self.frame = stackitem[0] # lineno is stackitem[1] self.show_variables() localsviewer = None diff --git a/Lib/idlelib/SearchEngine.py b/Lib/idlelib/SearchEngine.py --- a/Lib/idlelib/SearchEngine.py +++ b/Lib/idlelib/SearchEngine.py @@ -83,11 +83,9 @@ try: prog = re.compile(pat, flags) except re.error as what: - try: - msg, col = what - except: - msg = str(what) - col = -1 + args = what.args + msg = args[0] + col = arg[1] if len(args) >= 2 else -1 self.report_error(pat, msg, col) return None return prog -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 06:16:19 2014 From: python-checkins at python.org (terry.reedy) Date: Wed, 29 Jan 2014 06:16:19 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Silence_deprec?= =?utf-8?q?ation_warning_in_sunau=2Epy?= Message-ID: <3fDXwg5sMkz7Ljb@mail.python.org> http://hg.python.org/cpython/rev/cbf5d415212a changeset: 88804:cbf5d415212a branch: 2.7 parent: 88801:d45436cb8870 user: Terry Jan Reedy date: Wed Jan 29 00:15:59 2014 -0500 summary: Silence deprecation warning in sunau.py files: Lib/sunau.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/sunau.py b/Lib/sunau.py --- a/Lib/sunau.py +++ b/Lib/sunau.py @@ -224,7 +224,7 @@ if self._data_size == AUDIO_UNKNOWN_SIZE: return AUDIO_UNKNOWN_SIZE if self._encoding in _simple_encodings: - return self._data_size / self._framesize + return self._data_size // self._framesize return 0 # XXX--must do some arithmetic here def getcomptype(self): -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed Jan 29 09:41:23 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 29 Jan 2014 09:41:23 +0100 Subject: [Python-checkins] Daily reference leaks (ec6bd526b70a): sum=60 Message-ID: results for ec6bd526b70a on branch "default" -------------------------------------------- test_multiprocessing_fork leaked [38, 0, 0] references, sum=38 test_multiprocessing_fork leaked [17, 1, 0] memory blocks, sum=18 test_site leaked [2, -2, 2] references, sum=2 test_site leaked [2, -2, 2] memory blocks, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog3iJ1VO', '-x'] From python-checkins at python.org Wed Jan 29 10:49:32 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 29 Jan 2014 10:49:32 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwNDI0?= =?utf-8?q?=3A_Python_implementation_of_io=2EStringIO_now_supports_lone_su?= =?utf-8?q?rrogates=2E?= Message-ID: <3fDfzw0TwYz7LjZ@mail.python.org> http://hg.python.org/cpython/rev/6ca9ba9eb76b changeset: 88805:6ca9ba9eb76b branch: 3.3 parent: 88802:14782875030c user: Serhiy Storchaka date: Wed Jan 29 11:33:26 2014 +0200 summary: Issue #20424: Python implementation of io.StringIO now supports lone surrogates. files: Lib/_pyio.py | 2 +- Lib/test/test_memoryio.py | 9 +++++++++ Misc/NEWS | 2 ++ 3 files changed, 12 insertions(+), 1 deletions(-) diff --git a/Lib/_pyio.py b/Lib/_pyio.py --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -2044,7 +2044,7 @@ def __init__(self, initial_value="", newline="\n"): super(StringIO, self).__init__(BytesIO(), encoding="utf-8", - errors="strict", + errors="surrogatepass", newline=newline) # Issue #5645: make universal newlines semantics the same as in the # C version, even under Windows. 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 @@ -609,6 +609,15 @@ UnsupportedOperation = pyio.UnsupportedOperation EOF = "" + def test_lone_surrogates(self): + # Issue #20424 + memio = self.ioclass('\ud800') + self.assertEqual(memio.read(), '\ud800') + + memio = self.ioclass() + memio.write('\ud800') + self.assertEqual(memio.getvalue(), '\ud800') + class PyStringIOPickleTest(TextIOTestMixin, unittest.TestCase): """Test if pickle restores properly the internal state of StringIO. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -50,6 +50,8 @@ Library ------- +- Issue #20424: Python implementation of io.StringIO now supports lone surrogates. + - Issue #19456: ntpath.join() now joins relative paths correctly when a drive is present. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 10:49:33 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 29 Jan 2014 10:49:33 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Move_Misc/NEWS_entries_com?= =?utf-8?q?mitted_after_releasing_3=2E4=2E0b3_to_correct_places=2E?= Message-ID: <3fDfzx3Sb0z7Lmp@mail.python.org> http://hg.python.org/cpython/rev/0cd7be67f225 changeset: 88806:0cd7be67f225 parent: 88803:664d83a17710 user: Serhiy Storchaka date: Wed Jan 29 11:44:25 2014 +0200 summary: Move Misc/NEWS entries committed after releasing 3.4.0b3 to correct places. files: Misc/NEWS | 77 ++++++++++++++++++++++++------------------ 1 files changed, 43 insertions(+), 34 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -26,6 +26,49 @@ - Issue #20223: inspect.signature now supports methods defined with functools.partialmethods. +- Issue #19456: ntpath.join() now joins relative paths correctly when a drive + is present. + +- Issue #19077: tempfile.TemporaryDirectory cleanup no longer fails when + called during shutdown. Emitting resource warning in __del__ no longer fails. + Original patch by Antoine Pitrou. + +- Issue #20394: Silence Coverity warning in audioop module. + +- Issue #20367: Fix behavior of concurrent.futures.as_completed() for + duplicate arguments. Patch by Glenn Langford. + +- Issue #8260: The read(), readline() and readlines() methods of + codecs.StreamReader returned incomplete data when were called after + readline() or read(size). Based on patch by Amaury Forgeot d'Arc. + +- Issue #20105: the codec exception chaining now correctly sets the + traceback of the original exception as its __traceback__ attribute. + +IDLE +---- + +- Issue #17721: Remove non-functional configuration dialog help button until we + make it actually gives some help when clicked. Patch by Guilherme Sim?es. + +Tests +----- + +- Issue #19990: Added tests for the imghdr module. Based on patch by + Claudiu Popa. + +Tools/Demos +----------- + +- Issue #20326: Argument Clinic now uses a simple, unique signature to + annotate text signatures in docstrings, resulting in fewer false + positives. "self" parameters are also explicitly marked, allowing + inspect.Signature() to authoritatively detect (and skip) said parameters. + +- Issue #20326: Argument Clinic now generates separate checksums for the + input and output sections of the block, allowing external tools to verify + that the input has not changed (and thus the output is not out-of-date). + What's New in Python 3.4.0 Beta 3? ================================== @@ -61,25 +104,6 @@ Library ------- -- Issue #19456: ntpath.join() now joins relative paths correctly when a drive - is present. - -- Issue #19077: tempfile.TemporaryDirectory cleanup no longer fails when - called during shutdown. Emitting resource warning in __del__ no longer fails. - Original patch by Antoine Pitrou. - -- Issue #20394: Silence Coverity warning in audioop module. - -- Issue #20367: Fix behavior of concurrent.futures.as_completed() for - duplicate arguments. Patch by Glenn Langford. - -- Issue #8260: The read(), readline() and readlines() methods of - codecs.StreamReader returned incomplete data when were called after - readline() or read(size). Based on patch by Amaury Forgeot d'Arc. - -- Issue #20105: the codec exception chaining now correctly sets the - traceback of the original exception as its __traceback__ attribute. - - asyncio: Various improvements and small changes not all covered by issues listed below. E.g. wait_for() now cancels the inner task if the timeout occcurs; tweaked the set of exported symbols; renamed @@ -177,9 +201,6 @@ IDLE ---- -- Issue #17721: Remove non-functional configuration dialog help button until we - make it actually gives some help when clicked. Patch by Guilherme Sim?es. - - Issue #17390: Add Python version to Idle editor window title bar. Original patches by Edmond Burnett and Kent Johnson. @@ -189,9 +210,6 @@ Tests ----- -- Issue #19990: Added tests for the imghdr module. Based on patch by - Claudiu Popa. - - Issue #20358: Tests for curses.window.overlay and curses.window.overwrite no longer specify min{row,col} > max{row,col}. @@ -203,15 +221,6 @@ Tools/Demos ----------- -- Issue #20326: Argument Clinic now uses a simple, unique signature to - annotate text signatures in docstrings, resulting in fewer false - positives. "self" parameters are also explicitly marked, allowing - inspect.Signature() to authoritatively detect (and skip) said parameters. - -- Issue #20326: Argument Clinic now generates separate checksums for the - input and output sections of the block, allowing external tools to verify - that the input has not changed (and thus the output is not out-of-date). - - Issue #20390: Argument Clinic's "file" output preset now defaults to "{dirname}/clinic/{basename}.h". -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 10:49:34 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 29 Jan 2014 10:49:34 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320424=3A_Python_implementation_of_io=2EStringIO?= =?utf-8?q?_now_supports_lone_surrogates=2E?= Message-ID: <3fDfzy4tKhz7Lmp@mail.python.org> http://hg.python.org/cpython/rev/483096ef1cf6 changeset: 88807:483096ef1cf6 parent: 88806:0cd7be67f225 parent: 88805:6ca9ba9eb76b user: Serhiy Storchaka date: Wed Jan 29 11:45:31 2014 +0200 summary: Issue #20424: Python implementation of io.StringIO now supports lone surrogates. files: Lib/_pyio.py | 2 +- Lib/test/test_memoryio.py | 9 +++++++++ Misc/NEWS | 2 ++ 3 files changed, 12 insertions(+), 1 deletions(-) diff --git a/Lib/_pyio.py b/Lib/_pyio.py --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -2052,7 +2052,7 @@ def __init__(self, initial_value="", newline="\n"): super(StringIO, self).__init__(BytesIO(), encoding="utf-8", - errors="strict", + errors="surrogatepass", newline=newline) # Issue #5645: make universal newlines semantics the same as in the # C version, even under Windows. 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 @@ -609,6 +609,15 @@ UnsupportedOperation = pyio.UnsupportedOperation EOF = "" + def test_lone_surrogates(self): + # Issue #20424 + memio = self.ioclass('\ud800') + self.assertEqual(memio.read(), '\ud800') + + memio = self.ioclass() + memio.write('\ud800') + self.assertEqual(memio.getvalue(), '\ud800') + class PyStringIOPickleTest(TextIOTestMixin, unittest.TestCase): """Test if pickle restores properly the internal state of StringIO. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,8 @@ Library ------- +- Issue #20424: Python implementation of io.StringIO now supports lone surrogates. + - Issue #20308: inspect.signature now works on classes without user-defined __init__ or __new__ methods. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 10:49:35 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 29 Jan 2014 10:49:35 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Backported_a_t?= =?utf-8?q?est_for_lone_surrogates_support_in_io=2EStringIO=2E?= Message-ID: <3fDfzz6CSCz7LnM@mail.python.org> http://hg.python.org/cpython/rev/3971e1b07af4 changeset: 88808:3971e1b07af4 branch: 2.7 parent: 88804:cbf5d415212a user: Serhiy Storchaka date: Wed Jan 29 11:49:13 2014 +0200 summary: Backported a test for lone surrogates support in io.StringIO. files: Lib/test/test_memoryio.py | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) 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 @@ -588,6 +588,16 @@ UnsupportedOperation = pyio.UnsupportedOperation EOF = "" + def test_lone_surrogates(self): + # Issue #20424 + surrogate = unichr(0xd800) + memio = self.ioclass(surrogate) + self.assertEqual(memio.read(), surrogate) + + memio = self.ioclass() + memio.write(surrogate) + self.assertEqual(memio.getvalue(), surrogate) + class PyStringIOPickleTest(TextIOTestMixin, unittest.TestCase): """Test if pickle restores properly the internal state of StringIO. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 14:06:54 2014 From: python-checkins at python.org (nick.coghlan) Date: Wed, 29 Jan 2014 14:06:54 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_427=3A_Make_it_clear_that?= =?utf-8?q?_supported_!=3D_recommended?= Message-ID: <3fDlMf0N17z7Ljh@mail.python.org> http://hg.python.org/peps/rev/301db11cbb48 changeset: 5365:301db11cbb48 user: Nick Coghlan date: Wed Jan 29 23:06:29 2014 +1000 summary: PEP 427: Make it clear that supported != recommended files: pep-0427.txt | 20 ++++++++++++++++---- 1 files changed, 16 insertions(+), 4 deletions(-) diff --git a/pep-0427.txt b/pep-0427.txt --- a/pep-0427.txt +++ b/pep-0427.txt @@ -383,10 +383,22 @@ Is it possible to import Python code directly from a wheel file? Yes, the wheel format is deliberately designed to be compatible with - Python's support for importing from zip files. While not all wheels - will support being used that way (for example, if they include C - extensions), most pure Python wheels can be used that way just by - placing their name on ``sys.path``. + Python's support for importing from zip files, ensuring that it + provides a superset of the functionality provided by the preceding + egg format. + + However, this is generally not a *recommended* approach to using wheel + files, as importing from a zip file rather than an ordinary filesystem + directory imposes a number of additional constraints that will often + break the assumptions of Python developers (for example, C extensions + cannot be imported directly from a zip archive, and the ``__file__`` + attribute no longer refers to an ordinary filesystem path, but to + a combination path that includes both the location of the zip archive + on the filesystem and the relative path to the module inside the + archive). + + Like metaclasses and metapath importers, if you're not sure if you need + to take advantage of this feature, you almost certainly don't need it. References -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Jan 29 14:50:22 2014 From: python-checkins at python.org (nick.coghlan) Date: Wed, 29 Jan 2014 14:50:22 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Improve_PEP_427_FAQ_formattin?= =?utf-8?q?g?= Message-ID: <3fDmKp2KD8z7LpL@mail.python.org> http://hg.python.org/peps/rev/c1118d37ed3a changeset: 5366:c1118d37ed3a user: Nick Coghlan date: Wed Jan 29 23:50:14 2014 +1000 summary: Improve PEP 427 FAQ formatting files: pep-0427.txt | 18 ++++++++++++++++++ 1 files changed, 18 insertions(+), 0 deletions(-) diff --git a/pep-0427.txt b/pep-0427.txt --- a/pep-0427.txt +++ b/pep-0427.txt @@ -339,7 +339,10 @@ FAQ === + Wheel defines a .data directory. Should I put all my data there? +----------------------------------------------------------------- + This specification does not have an opinion on how you should organize your code. The .data directory is just a place for any files that are not normally installed inside ``site-packages`` or on the PYTHONPATH. @@ -347,26 +350,38 @@ resource)`` even though *those* files will usually not be distributed in *wheel's* ``.data`` directory. + Why does wheel include attached signatures? +------------------------------------------- + Attached signatures are more convenient than detached signatures because they travel with the archive. Since only the individual files are signed, the archive can be recompressed without invalidating the signature or individual files can be verified without having to download the whole archive. + Why does wheel allow JWS signatures? +------------------------------------ + The JOSE specifications of which JWS is a part are designed to be easy to implement, a feature that is also one of wheel's primary design goals. JWS yields a useful, concise pure-Python implementation. + Why does wheel also allow S/MIME signatures? +-------------------------------------------- + S/MIME signatures are allowed for users who need or want to use existing public key infrastructure with wheel. Signed packages are only a basic building block in a secure package update system. Wheel only provides the building block. + What's the deal with "purelib" vs. "platlib"? +--------------------------------------------- + Wheel preserves the "purelib" vs. "platlib" distinction, which is significant on some platforms. For example, Fedora installs pure Python packages to '/usr/lib/pythonX.Y/site-packages' and platform @@ -381,7 +396,10 @@ depending on whether it is pure Python or not and those files should be at the root with the appropriate setting given for "Root-is-purelib". + Is it possible to import Python code directly from a wheel file? +---------------------------------------------------------------- + Yes, the wheel format is deliberately designed to be compatible with Python's support for importing from zip files, ensuring that it provides a superset of the functionality provided by the preceding -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed Jan 29 16:46:28 2014 From: python-checkins at python.org (yury.selivanov) Date: Wed, 29 Jan 2014 16:46:28 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2ESignature=3A_Mak?= =?utf-8?q?e_from=5Fbuiltin_to_raise_an_exception_if_no_signature_can?= Message-ID: <3fDpvm40Bgz7LnW@mail.python.org> http://hg.python.org/cpython/rev/9433b380ad33 changeset: 88809:9433b380ad33 parent: 88807:483096ef1cf6 user: Yury Selivanov date: Wed Jan 29 10:46:14 2014 -0500 summary: inspect.Signature: Make from_builtin to raise an exception if no signature can be provided #20422 files: Lib/inspect.py | 30 ++++++++++++++++++--------- Lib/test/test_inspect.py | 4 +++ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1514,18 +1514,24 @@ return sig.replace(parameters=params) +def _signature_is_builtin(obj): + # Internal helper to test if `obj` is a callable that might + # support Argument Clinic's __text_signature__ protocol. + return (isinstance(obj, _NonUserDefinedCallables) or + ismethoddescriptor(obj) or + # Can't test 'isinstance(type)' here, as it would + # also be True for regular python classes + obj in (type, object)) + + def signature(obj): '''Get a signature object for the passed callable.''' if not callable(obj): raise TypeError('{!r} is not a callable object'.format(obj)) - if (isinstance(obj, _NonUserDefinedCallables) or - ismethoddescriptor(obj) or - isinstance(obj, type)): - sig = Signature.from_builtin(obj) - if sig: - return sig + if _signature_is_builtin(obj): + return Signature.from_builtin(obj) if isinstance(obj, types.MethodType): # In this case we skip the first parameter of the underlying @@ -2017,9 +2023,13 @@ @classmethod def from_builtin(cls, func): + if not _signature_is_builtin(func): + raise TypeError("{!r} is not a Python builtin " + "function".format(func)) + s = getattr(func, "__text_signature__", None) if not s: - return None + raise ValueError("no signature found for builtin {!r}".format(func)) Parameter = cls._parameter_cls @@ -2038,9 +2048,10 @@ try: module = ast.parse(s) except SyntaxError: - return None + module = None + if not isinstance(module, ast.Module): - return None + raise ValueError("{!r} builtin has invalid signature".format(func)) f = module.body[0] @@ -2149,7 +2160,6 @@ return cls(parameters, return_annotation=cls.empty) - @property def parameters(self): return self._parameters diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1667,6 +1667,10 @@ with self.assertRaisesRegex(TypeError, 'is not a Python function'): inspect.Signature.from_function(42) + def test_signature_from_builtin_errors(self): + with self.assertRaisesRegex(TypeError, 'is not a Python builtin'): + inspect.Signature.from_builtin(42) + def test_signature_on_method(self): class Test: def __init__(*args): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 16:53:09 2014 From: python-checkins at python.org (yury.selivanov) Date: Wed, 29 Jan 2014 16:53:09 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2Esignature=3A_Add?= =?utf-8?q?_support_for_decorated_=28wrapped=29_builtins_=2320425?= Message-ID: <3fDq3T1jpQz7Lnx@mail.python.org> http://hg.python.org/cpython/rev/a9fedabb69e5 changeset: 88810:a9fedabb69e5 user: Yury Selivanov date: Wed Jan 29 10:52:57 2014 -0500 summary: inspect.signature: Add support for decorated (wrapped) builtins #20425 files: Lib/inspect.py | 6 +++--- Lib/test/test_inspect.py | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1530,9 +1530,6 @@ if not callable(obj): raise TypeError('{!r} is not a callable object'.format(obj)) - if _signature_is_builtin(obj): - return Signature.from_builtin(obj) - if isinstance(obj, types.MethodType): # In this case we skip the first parameter of the underlying # function (usually `self` or `cls`). @@ -1570,6 +1567,9 @@ return sig.replace(parameters=new_params) + if _signature_is_builtin(obj): + return Signature.from_builtin(obj) + if isinstance(obj, types.FunctionType): return Signature.from_function(obj) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1655,6 +1655,21 @@ __call__ = type test_callable(ThisWorksNow()) + @unittest.skipIf(MISSING_C_DOCSTRINGS, + "Signature information for builtins requires docstrings") + def test_signature_on_decorated_builtins(self): + func = _testcapi.docstring_with_signature_with_defaults + + def decorator(func): + @functools.wraps(func) + def wrapper(*args, **kwargs) -> int: + return func(*args, **kwargs) + return wrapper + + decorated_func = decorator(func) + + self.assertEqual(inspect.signature(func), + inspect.signature(decorated_func)) def test_signature_on_builtins_no_signature(self): with self.assertRaisesRegex(ValueError, 'no signature found for builtin'): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 16:58:50 2014 From: python-checkins at python.org (yury.selivanov) Date: Wed, 29 Jan 2014 16:58:50 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2ESignature=3A_ens?= =?utf-8?q?ure_that_non-default_params_don=27t_follow_default_ones?= Message-ID: <3fDqB26nJvz7Llr@mail.python.org> http://hg.python.org/cpython/rev/ca974997280d changeset: 88811:ca974997280d user: Yury Selivanov date: Wed Jan 29 10:58:16 2014 -0500 summary: inspect.Signature: ensure that non-default params don't follow default ones #20427 files: Lib/inspect.py | 21 ++++++++++++++++++++- Lib/test/test_inspect.py | 13 ++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1924,6 +1924,7 @@ if __validate_parameters__: params = OrderedDict() top_kind = _POSITIONAL_ONLY + kind_defaults = False for idx, param in enumerate(parameters): kind = param.kind @@ -1933,9 +1934,27 @@ msg = 'wrong parameter order: {} before {}' msg = msg.format(top_kind, kind) raise ValueError(msg) - else: + elif kind > top_kind: + kind_defaults = False top_kind = kind + if (kind in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD) and + not param._partial_kwarg): + # If we have a positional-only or positional-or-keyword + # parameter, that does not have its default value set + # by 'functools.partial' or other "partial" signature: + if param.default is _empty: + if kind_defaults: + # No default for this parameter, but the + # previous parameter of the same kind had + # a default + msg = 'non-default argument follows default ' \ + 'argument' + raise ValueError(msg) + else: + # There is a default for this parameter. + kind_defaults = True + if name in params: msg = 'duplicate parameter name: {!r}'.format(name) raise ValueError(msg) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1522,11 +1522,13 @@ self.assertEqual(str(S()), '()') - def test(po, pk, *args, ko, **kwargs): + def test(po, pk, pod=42, pkd=100, *args, ko, **kwargs): pass sig = inspect.signature(test) po = sig.parameters['po'].replace(kind=P.POSITIONAL_ONLY) + pod = sig.parameters['pod'].replace(kind=P.POSITIONAL_ONLY) pk = sig.parameters['pk'] + pkd = sig.parameters['pkd'] args = sig.parameters['args'] ko = sig.parameters['ko'] kwargs = sig.parameters['kwargs'] @@ -1549,6 +1551,15 @@ with self.assertRaisesRegex(ValueError, 'duplicate parameter name'): S((po, pk, args, kwargs2, ko)) + with self.assertRaisesRegex(ValueError, 'follows default argument'): + S((pod, po)) + + with self.assertRaisesRegex(ValueError, 'follows default argument'): + S((po, pkd, pk)) + + with self.assertRaisesRegex(ValueError, 'follows default argument'): + S((pkd, pk)) + def test_signature_immutability(self): def test(a): pass -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 17:45:49 2014 From: python-checkins at python.org (yury.selivanov) Date: Wed, 29 Jan 2014 17:45:49 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2Egetfullargspec?= =?utf-8?q?=3A_Use_inspect=2Esignature_API_behind_the_scenes_=2317481?= Message-ID: <3fDrDF6JD7z7LjN@mail.python.org> http://hg.python.org/cpython/rev/6d1e8162e855 changeset: 88812:6d1e8162e855 user: Yury Selivanov date: Wed Jan 29 11:24:39 2014 -0500 summary: inspect.getfullargspec: Use inspect.signature API behind the scenes #17481 files: Doc/whatsnew/3.4.rst | 7 + Lib/inspect.py | 111 +++++++++++++++++++++++++- Lib/test/test_inspect.py | 42 +++++++++- Misc/NEWS | 2 + 4 files changed, 155 insertions(+), 7 deletions(-) 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 @@ -786,6 +786,13 @@ metaclasses (Contributed by Ethan Furman in :issue:`18929` and :issue:`19030`) +:func:`~inspect.getfullargspec` and :func:`~inspect.getargspec` +now use the :func:`~inspect.signature` API. This allows them to +support much broader range of functions, including some builtins and +callables that follow ``__signature__`` protocol. It is still +recommended to update your code to use :func:`~inspect.signature` +directly. (Contributed by Yury Selivanov in :issue:`17481`) + logging ------- diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -934,7 +934,7 @@ 'args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations') def getfullargspec(func): - """Get the names and default values of a function's arguments. + """Get the names and default values of a callable object's arguments. A tuple of seven things is returned: (args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults annotations). @@ -948,13 +948,90 @@ The first four items in the tuple correspond to getargspec(). """ + builtin_method_param = None + if ismethod(func): + # There is a notable difference in behaviour between getfullargspec + # and Signature: the former always returns 'self' parameter for bound + # methods, whereas the Signature always shows the actual calling + # signature of the passed object. + # + # To simulate this behaviour, we "unbind" bound methods, to trick + # inspect.signature to always return their first parameter ("self", + # usually) func = func.__func__ - if not isfunction(func): - raise TypeError('{!r} is not a Python function'.format(func)) - args, varargs, kwonlyargs, varkw = _getfullargs(func.__code__) - return FullArgSpec(args, varargs, varkw, func.__defaults__, - kwonlyargs, func.__kwdefaults__, func.__annotations__) + + elif isbuiltin(func): + # We have a builtin function or method. For that, we check the + # special '__text_signature__' attribute, provided by the + # Argument Clinic. If it's a method, we'll need to make sure + # that its first parameter (usually "self") is always returned + # (see the previous comment). + text_signature = getattr(func, '__text_signature__', None) + if text_signature and text_signature.startswith('($'): + builtin_method_param = _signature_get_bound_param(text_signature) + + try: + sig = signature(func) + except Exception as ex: + # Most of the times 'signature' will raise ValueError. + # But, it can also raise AttributeError, and, maybe something + # else. So to be fully backwards compatible, we catch all + # possible exceptions here, and reraise a TypeError. + raise TypeError('unsupported callable') from ex + + args = [] + varargs = None + varkw = None + kwonlyargs = [] + defaults = () + annotations = {} + defaults = () + kwdefaults = {} + + if sig.return_annotation is not sig.empty: + annotations['return'] = sig.return_annotation + + for param in sig.parameters.values(): + kind = param.kind + name = param.name + + if kind is _POSITIONAL_ONLY: + args.append(name) + elif kind is _POSITIONAL_OR_KEYWORD: + args.append(name) + if param.default is not param.empty: + defaults += (param.default,) + elif kind is _VAR_POSITIONAL: + varargs = name + elif kind is _KEYWORD_ONLY: + kwonlyargs.append(name) + if param.default is not param.empty: + kwdefaults[name] = param.default + elif kind is _VAR_KEYWORD: + varkw = name + + if param.annotation is not param.empty: + annotations[name] = param.annotation + + if not kwdefaults: + # compatibility with 'func.__kwdefaults__' + kwdefaults = None + + if not defaults: + # compatibility with 'func.__defaults__' + defaults = None + + if builtin_method_param and (not args or args[0] != builtin_method_param): + # `func` is a method, and we always need to return its + # first parameter -- usually "self" (to be backwards + # compatible with the previous implementation of + # getfullargspec) + args.insert(0, builtin_method_param) + + return FullArgSpec(args, varargs, varkw, defaults, + kwonlyargs, kwdefaults, annotations) + ArgInfo = namedtuple('ArgInfo', 'args varargs keywords locals') @@ -1524,6 +1601,28 @@ obj in (type, object)) +def _signature_get_bound_param(spec): + # Internal helper to get first parameter name from a + # __text_signature__ of a builtin method, which should + # be in the following format: '($param1, ...)'. + # Assumptions are that the first argument won't have + # a default value or an annotation. + + assert spec.startswith('($') + + pos = spec.find(',') + if pos == -1: + pos = spec.find(')') + + cpos = spec.find(':') + assert cpos == -1 or cpos > pos + + cpos = spec.find('=') + assert cpos == -1 or cpos > pos + + return spec[2:pos] + + def signature(obj): '''Get a signature object for the passed callable.''' diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -578,6 +578,36 @@ kwonlyargs_e=['arg'], formatted='(*, arg)') + def test_getfullargspec_signature_attr(self): + def test(): + pass + spam_param = inspect.Parameter('spam', inspect.Parameter.POSITIONAL_ONLY) + test.__signature__ = inspect.Signature(parameters=(spam_param,)) + + self.assertFullArgSpecEquals(test, args_e=['spam'], formatted='(spam)') + + @unittest.skipIf(MISSING_C_DOCSTRINGS, + "Signature information for builtins requires docstrings") + def test_getfullargspec_builtin_methods(self): + self.assertFullArgSpecEquals(_pickle.Pickler.dump, + args_e=['self', 'obj'], formatted='(self, obj)') + + self.assertFullArgSpecEquals(_pickle.Pickler(io.BytesIO()).dump, + args_e=['self', 'obj'], formatted='(self, obj)') + + @unittest.skipIf(MISSING_C_DOCSTRINGS, + "Signature information for builtins requires docstrings") + def test_getfullagrspec_builtin_func(self): + builtin = _testcapi.docstring_with_signature_with_defaults + spec = inspect.getfullargspec(builtin) + self.assertEqual(spec.defaults[0], 'avocado') + + @unittest.skipIf(MISSING_C_DOCSTRINGS, + "Signature information for builtins requires docstrings") + def test_getfullagrspec_builtin_func_no_signature(self): + builtin = _testcapi.docstring_no_signature + with self.assertRaises(TypeError): + inspect.getfullargspec(builtin) def test_getargspec_method(self): class A(object): @@ -2614,6 +2644,15 @@ self.assertNotEqual(ba, ba4) +class TestSignaturePrivateHelpers(unittest.TestCase): + def test_signature_get_bound_param(self): + getter = inspect._signature_get_bound_param + + self.assertEqual(getter('($self)'), 'self') + self.assertEqual(getter('($self, obj)'), 'self') + self.assertEqual(getter('($cls, /, obj)'), 'cls') + + class TestUnwrap(unittest.TestCase): def test_unwrap_one(self): @@ -2719,7 +2758,8 @@ TestGetcallargsFunctions, TestGetcallargsMethods, TestGetcallargsUnboundMethods, TestGetattrStatic, TestGetGeneratorState, TestNoEOL, TestSignatureObject, TestSignatureBind, TestParameterObject, - TestBoundArguments, TestGetClosureVars, TestUnwrap, TestMain + TestBoundArguments, TestSignaturePrivateHelpers, TestGetClosureVars, + TestUnwrap, TestMain ) if __name__ == "__main__": diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -47,6 +47,8 @@ - Issue #20105: the codec exception chaining now correctly sets the traceback of the original exception as its __traceback__ attribute. +- Issue #17481: inspect.getfullargspec() now uses inspect.signature() API. + IDLE ---- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 17:54:27 2014 From: python-checkins at python.org (yury.selivanov) Date: Wed, 29 Jan 2014 17:54:27 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2Etest=2Egetfullar?= =?utf-8?q?gspec=3A_Add_a_unittest_to_ensure_correct_annotations?= Message-ID: <3fDrQC3m36z7LkV@mail.python.org> http://hg.python.org/cpython/rev/0fa2750c7241 changeset: 88813:0fa2750c7241 user: Yury Selivanov date: Wed Jan 29 11:54:12 2014 -0500 summary: inspect.test.getfullargspec: Add a unittest to ensure correct annotations handling #17481 files: Lib/test/test_inspect.py | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -586,6 +586,15 @@ self.assertFullArgSpecEquals(test, args_e=['spam'], formatted='(spam)') + def test_getfullargspec_signature_annos(self): + def test(a:'spam') -> 'ham': pass + spec = inspect.getfullargspec(test) + self.assertEqual(test.__annotations__, spec.annotations) + + def test(): pass + spec = inspect.getfullargspec(test) + self.assertEqual(test.__annotations__, spec.annotations) + @unittest.skipIf(MISSING_C_DOCSTRINGS, "Signature information for builtins requires docstrings") def test_getfullargspec_builtin_methods(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 18:05:53 2014 From: python-checkins at python.org (yury.selivanov) Date: Wed, 29 Jan 2014 18:05:53 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=3A_Rename_private_?= =?utf-8?q?helper_function?= Message-ID: <3fDrgP60ybz7Lpx@mail.python.org> http://hg.python.org/cpython/rev/07808c511537 changeset: 88814:07808c511537 user: Yury Selivanov date: Wed Jan 29 12:05:40 2014 -0500 summary: inspect: Rename private helper function files: Lib/inspect.py | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1505,7 +1505,7 @@ types.BuiltinFunctionType) -def _get_user_defined_method(cls, method_name): +def _signature_get_user_defined_method(cls, method_name): try: meth = getattr(cls, method_name) except AttributeError: @@ -1682,17 +1682,17 @@ # First, let's see if it has an overloaded __call__ defined # in its metaclass - call = _get_user_defined_method(type(obj), '__call__') + call = _signature_get_user_defined_method(type(obj), '__call__') if call is not None: sig = signature(call) else: # Now we check if the 'obj' class has a '__new__' method - new = _get_user_defined_method(obj, '__new__') + new = _signature_get_user_defined_method(obj, '__new__') if new is not None: sig = signature(new) else: # Finally, we should have at least __init__ implemented - init = _get_user_defined_method(obj, '__init__') + init = _signature_get_user_defined_method(obj, '__init__') if init is not None: sig = signature(init) @@ -1711,7 +1711,7 @@ # We also check that the 'obj' is not an instance of # _WrapperDescriptor or _MethodWrapper to avoid # infinite recursion (and even potential segfault) - call = _get_user_defined_method(type(obj), '__call__') + call = _signature_get_user_defined_method(type(obj), '__call__') if call is not None: sig = signature(call) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 18:10:42 2014 From: python-checkins at python.org (yury.selivanov) Date: Wed, 29 Jan 2014 18:10:42 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2ESignature=2Ebind?= =?utf-8?q?=3A_Update_method_signature_to_rule_out_possiblity?= Message-ID: <3fDrmy62dmz7Ljt@mail.python.org> http://hg.python.org/cpython/rev/379d9a193539 changeset: 88815:379d9a193539 user: Yury Selivanov date: Wed Jan 29 12:10:27 2014 -0500 summary: inspect.Signature.bind: Update method signature to rule out possiblity of name conflict between '__bind_self' and actual keyword argument to 'bind' or 'bind_partial'. files: Lib/inspect.py | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -2470,19 +2470,19 @@ return self._bound_arguments_cls(self, arguments) - def bind(__bind_self, *args, **kwargs): + def bind(*args, **kwargs): '''Get a BoundArguments object, that maps the passed `args` and `kwargs` to the function's signature. Raises `TypeError` if the passed arguments can not be bound. ''' - return __bind_self._bind(args, kwargs) - - def bind_partial(__bind_self, *args, **kwargs): + return args[0]._bind(args[1:], kwargs) + + def bind_partial(*args, **kwargs): '''Get a BoundArguments object, that partially maps the passed `args` and `kwargs` to the function's signature. Raises `TypeError` if the passed arguments can not be bound. ''' - return __bind_self._bind(args, kwargs, partial=True) + return args[0]._bind(args[1:], kwargs, partial=True) def __str__(self): result = [] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 18:19:15 2014 From: python-checkins at python.org (yury.selivanov) Date: Wed, 29 Jan 2014 18:19:15 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2Esignature=3A_Mak?= =?utf-8?q?e_sure_that_if_a_callable_object_has_=27=5Fpatialmethod=27?= Message-ID: <3fDryq289Bz7LjN@mail.python.org> http://hg.python.org/cpython/rev/e508c2b8fd44 changeset: 88816:e508c2b8fd44 user: Yury Selivanov date: Wed Jan 29 12:18:59 2014 -0500 summary: inspect.signature: Make sure that if a callable object has '_patialmethod' attribute, that attribute is an instance of 'functools.partialmethod'. files: Lib/inspect.py | 29 ++++++++++++++------------- Lib/test/test_inspect.py | 5 ++++ 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1651,20 +1651,21 @@ except AttributeError: pass else: - # Unbound partialmethod (see functools.partialmethod) - # This means, that we need to calculate the signature - # as if it's a regular partial object, but taking into - # account that the first positional argument - # (usually `self`, or `cls`) will not be passed - # automatically (as for boundmethods) - - wrapped_sig = signature(partialmethod.func) - sig = _signature_get_partial(wrapped_sig, partialmethod, (None,)) - - first_wrapped_param = tuple(wrapped_sig.parameters.values())[0] - new_params = (first_wrapped_param,) + tuple(sig.parameters.values()) - - return sig.replace(parameters=new_params) + if isinstance(partialmethod, functools.partialmethod): + # Unbound partialmethod (see functools.partialmethod) + # This means, that we need to calculate the signature + # as if it's a regular partial object, but taking into + # account that the first positional argument + # (usually `self`, or `cls`) will not be passed + # automatically (as for boundmethods) + + wrapped_sig = signature(partialmethod.func) + sig = _signature_get_partial(wrapped_sig, partialmethod, (None,)) + + first_wrapped_param = tuple(wrapped_sig.parameters.values())[0] + new_params = (first_wrapped_param,) + tuple(sig.parameters.values()) + + return sig.replace(parameters=new_params) if _signature_is_builtin(obj): return Signature.from_builtin(obj) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1983,6 +1983,11 @@ ('c', 1, ..., 'keyword_only')), 'spam')) + def test_signature_on_fake_partialmethod(self): + def foo(a): pass + foo._partialmethod = 'spam' + self.assertEqual(str(inspect.signature(foo)), '(a)') + def test_signature_on_decorated(self): import functools -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 20:42:53 2014 From: python-checkins at python.org (terry.reedy) Date: Wed, 29 Jan 2014 20:42:53 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSWRsZWxpYiAmIGJ1?= =?utf-8?q?ildbots=3A_suppress_py3_deprecation_message_even_if_enabled=2E?= Message-ID: <3fDw8Y1xjVz7LjR@mail.python.org> http://hg.python.org/cpython/rev/09716a4d6c52 changeset: 88817:09716a4d6c52 branch: 2.7 parent: 88808:3971e1b07af4 user: Terry Jan Reedy date: Wed Jan 29 14:42:32 2014 -0500 summary: Idlelib & buildbots: suppress py3 deprecation message even if enabled. files: Lib/idlelib/idle_test/test_calltips.py | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -3,6 +3,7 @@ CTi = ct.CallTips() # needed for get_entity test in 2.7 import textwrap import types +import warnings default_tip = '' @@ -162,8 +163,11 @@ class Py2Test(unittest.TestCase): def test_paramtuple_float(self): - # 18539: (a,b) becomes '.0' in code object; change that but not float - def f((a,b), c=0.0): pass + # 18539: (a,b) becomes '.0' in code object; change that but not 0.0 + with warnings.catch_warnings(): + # Suppess message of py3 deprecation of parameter unpacking + warnings.simplefilter("ignore") + def f((a,b), c=0.0): pass self.assertEqual(signature(f), '(, c=0.0)') if __name__ == '__main__': -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 22:50:50 2014 From: python-checkins at python.org (yury.selivanov) Date: Wed, 29 Jan 2014 22:50:50 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2ESignature=2Efrom?= =?utf-8?q?=5Ffunction=3A_Use_CO=5FVARARGS_=26_CO=5FVARKEYWORDS_constants?= Message-ID: <3fDz0B6NWLz7Lmg@mail.python.org> http://hg.python.org/cpython/rev/1435ebd8b88e changeset: 88818:1435ebd8b88e parent: 88816:e508c2b8fd44 user: Yury Selivanov date: Wed Jan 29 16:50:40 2014 -0500 summary: inspect.Signature.from_function: Use CO_VARARGS & CO_VARKEYWORDS constants files: Lib/inspect.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -2109,7 +2109,7 @@ default=defaults[offset])) # *args - if func_code.co_flags & 0x04: + if func_code.co_flags & CO_VARARGS: name = arg_names[pos_count + keyword_only_count] annotation = annotations.get(name, _empty) parameters.append(Parameter(name, annotation=annotation, @@ -2126,9 +2126,9 @@ kind=_KEYWORD_ONLY, default=default)) # **kwargs - if func_code.co_flags & 0x08: + if func_code.co_flags & CO_VARKEYWORDS: index = pos_count + keyword_only_count - if func_code.co_flags & 0x04: + if func_code.co_flags & CO_VARARGS: index += 1 name = arg_names[index] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 23:41:51 2014 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 29 Jan 2014 23:41:51 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_=5Ffatal=5Ferro?= =?utf-8?q?r=28=29_of_=5FUnixWritePipeTransport_and?= Message-ID: <3fF0733gvYz7LjN@mail.python.org> http://hg.python.org/cpython/rev/f21a0ad40734 changeset: 88819:f21a0ad40734 user: Victor Stinner date: Wed Jan 29 13:12:03 2014 -0800 summary: asyncio: _fatal_error() of _UnixWritePipeTransport and _ProactorBasePipeTransport shouldn't log BrokenPipeError nor ConnectionResetError. (Same behaviour as _SelectorTransport._fatal_error().) files: Lib/asyncio/proactor_events.py | 3 ++- Lib/asyncio/unix_events.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -54,7 +54,8 @@ self._read_fut.cancel() def _fatal_error(self, exc): - logger.exception('Fatal error for %s', self) + if not isinstance(exc, (BrokenPipeError, ConnectionResetError)): + logger.exception('Fatal error for %s', self) self._force_close(exc) def _force_close(self, exc): 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 @@ -363,7 +363,8 @@ def _fatal_error(self, exc): # should be called by exception handler only - logger.exception('Fatal error for %s', self) + if not isinstance(exc, (BrokenPipeError, ConnectionResetError)): + logger.exception('Fatal error for %s', self) self._close(exc) def _close(self, exc=None): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 23:41:52 2014 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 29 Jan 2014 23:41:52 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Refactoring=3A_?= =?utf-8?q?move_write_flow_control_to_a_subclass/mixin=2E?= Message-ID: <3fF0746TCtz7Ljn@mail.python.org> http://hg.python.org/cpython/rev/9f0cf41cf593 changeset: 88820:9f0cf41cf593 user: Guido van Rossum date: Wed Jan 29 13:15:59 2014 -0800 summary: asyncio: Refactoring: move write flow control to a subclass/mixin. files: Lib/asyncio/selector_events.py | 98 +++++++++++++-------- 1 files changed, 61 insertions(+), 37 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 @@ -339,7 +339,67 @@ sock.close() -class _SelectorTransport(transports.Transport): +class _FlowControlMixin(transports.Transport): + """All the logic for (write) flow control in a mix-in base class. + + The subclass must implement get_write_buffer_size(). It must call + _maybe_pause_protocol() whenever the write buffer size increases, + and _maybe_resume_protocol() whenever it decreases. It may also + override set_write_buffer_limits() (e.g. to specify different + defaults). + + The subclass constructor must call super().__init__(extra). This + will call set_write_buffer_limits(). + + The user may call set_write_buffer_limits() and + get_write_buffer_size(), and their protocol's pause_writing() and + resume_writing() may be called. + """ + + def __init__(self, extra=None): + super().__init__(extra) + self._protocol_paused = False + self.set_write_buffer_limits() + + def _maybe_pause_protocol(self): + size = self.get_write_buffer_size() + if size <= self._high_water: + return + if not self._protocol_paused: + self._protocol_paused = True + try: + self._protocol.pause_writing() + except Exception: + logger.exception('pause_writing() failed') + + def _maybe_resume_protocol(self): + if (self._protocol_paused and + self.get_write_buffer_size() <= self._low_water): + self._protocol_paused = False + try: + self._protocol.resume_writing() + except Exception: + logger.exception('resume_writing() failed') + + def set_write_buffer_limits(self, high=None, low=None): + if high is None: + if low is None: + high = 64*1024 + else: + high = 4*low + if low is None: + low = high // 4 + if not high >= low >= 0: + raise ValueError('high (%r) must be >= low (%r) must be >= 0' % + (high, low)) + self._high_water = high + self._low_water = low + + def get_write_buffer_size(self): + raise NotImplementedError + + +class _SelectorTransport(_FlowControlMixin, transports.Transport): max_size = 256 * 1024 # Buffer size passed to recv(). @@ -362,8 +422,6 @@ self._buffer = self._buffer_factory() self._conn_lost = 0 # Set when call to connection_lost scheduled. self._closing = False # Set when close() called. - self._protocol_paused = False - self.set_write_buffer_limits() if self._server is not None: self._server.attach(self) @@ -410,40 +468,6 @@ server.detach(self) self._server = None - def _maybe_pause_protocol(self): - size = self.get_write_buffer_size() - if size <= self._high_water: - return - if not self._protocol_paused: - self._protocol_paused = True - try: - self._protocol.pause_writing() - except Exception: - logger.exception('pause_writing() failed') - - def _maybe_resume_protocol(self): - if (self._protocol_paused and - self.get_write_buffer_size() <= self._low_water): - self._protocol_paused = False - try: - self._protocol.resume_writing() - except Exception: - logger.exception('resume_writing() failed') - - def set_write_buffer_limits(self, high=None, low=None): - if high is None: - if low is None: - high = 64*1024 - else: - high = 4*low - if low is None: - low = high // 4 - if not high >= low >= 0: - raise ValueError('high (%r) must be >= low (%r) must be >= 0' % - (high, low)) - self._high_water = high - self._low_water = low - def get_write_buffer_size(self): return len(self._buffer) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 23:41:54 2014 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 29 Jan 2014 23:41:54 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Add_write_flow_?= =?utf-8?q?control_to_unix_pipes=2E?= Message-ID: <3fF0761Dg4z7LkM@mail.python.org> http://hg.python.org/cpython/rev/c71fa690254b changeset: 88821:c71fa690254b user: Guido van Rossum date: Wed Jan 29 13:20:39 2014 -0800 summary: asyncio: Add write flow control to unix pipes. files: Lib/asyncio/unix_events.py | 14 +++++++++++--- 1 files changed, 11 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 @@ -246,7 +246,8 @@ self._loop = None -class _UnixWritePipeTransport(transports.WriteTransport): +class _UnixWritePipeTransport(selector_events._FlowControlMixin, + transports.WriteTransport): def __init__(self, loop, pipe, protocol, waiter=None, extra=None): super().__init__(extra) @@ -277,12 +278,17 @@ if waiter is not None: self._loop.call_soon(waiter.set_result, None) + def get_write_buffer_size(self): + return sum(len(data) for data in self._buffer) + def _read_ready(self): # Pipe was closed by peer. self._close() def write(self, data): - assert isinstance(data, bytes), repr(data) + assert isinstance(data, (bytes, bytearray, memoryview)), repr(data) + if isinstance(data, bytearray): + data = memoryview(data) if not data: return @@ -310,6 +316,7 @@ self._loop.add_writer(self._fileno, self._write_ready) self._buffer.append(data) + self._maybe_pause_protocol() def _write_ready(self): data = b''.join(self._buffer) @@ -329,7 +336,8 @@ else: if n == len(data): self._loop.remove_writer(self._fileno) - if self._closing: + self._maybe_resume_protocol() # May append to buffer. + if not self._buffer and self._closing: self._loop.remove_reader(self._fileno) self._call_connection_lost(None) return -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 23:41:55 2014 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 29 Jan 2014 23:41:55 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Get_rid_of_=5Ft?= =?utf-8?b?cnlfY29ubmVjdGVkKCku?= Message-ID: <3fF0773BXPz7LmW@mail.python.org> http://hg.python.org/cpython/rev/3fe80ecba874 changeset: 88822:3fe80ecba874 user: Victor Stinner date: Wed Jan 29 14:22:56 2014 -0800 summary: asyncio: Get rid of _try_connected(). files: Lib/asyncio/base_subprocess.py | 32 +++++++++------------ 1 files changed, 14 insertions(+), 18 deletions(-) diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -75,19 +75,27 @@ proc = self._proc loop = self._loop if proc.stdin is not None: - transp, proto = yield from loop.connect_write_pipe( + _, pipe = yield from loop.connect_write_pipe( lambda: WriteSubprocessPipeProto(self, STDIN), proc.stdin) + self._pipes[STDIN] = pipe if proc.stdout is not None: - transp, proto = yield from loop.connect_read_pipe( + _, pipe = yield from loop.connect_read_pipe( lambda: ReadSubprocessPipeProto(self, STDOUT), proc.stdout) + self._pipes[STDOUT] = pipe if proc.stderr is not None: - transp, proto = yield from loop.connect_read_pipe( + _, pipe = yield from loop.connect_read_pipe( lambda: ReadSubprocessPipeProto(self, STDERR), proc.stderr) - if not self._pipes: - self._try_connected() + self._pipes[STDERR] = pipe + + assert self._pending_calls is not None + + self._loop.call_soon(self._protocol.connection_made, self) + for callback, data in self._pending_calls: + self._loop.call_soon(callback, *data) + self._pending_calls = None def _call(self, cb, *data): if self._pending_calls is not None: @@ -95,14 +103,6 @@ else: self._loop.call_soon(cb, *data) - def _try_connected(self): - assert self._pending_calls is not None - if all(p is not None and p.connected for p in self._pipes.values()): - self._loop.call_soon(self._protocol.connection_made, self) - for callback, data in self._pending_calls: - self._loop.call_soon(callback, *data) - self._pending_calls = None - def _pipe_connection_lost(self, fd, exc): self._call(self._protocol.pipe_connection_lost, fd, exc) self._try_finish() @@ -136,19 +136,15 @@ class WriteSubprocessPipeProto(protocols.BaseProtocol): - pipe = None def __init__(self, proc, fd): self.proc = proc self.fd = fd - self.connected = False + self.pipe = None self.disconnected = False - proc._pipes[fd] = self def connection_made(self, transport): - self.connected = True self.pipe = transport - self.proc._try_connected() def connection_lost(self, exc): self.disconnected = True -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 23:41:56 2014 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 29 Jan 2014 23:41:56 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Refactor_drain_?= =?utf-8?q?logic_in_streams=2Epy_to_be_reusable=2E?= Message-ID: <3fF07875Z0z7Lln@mail.python.org> http://hg.python.org/cpython/rev/472376125c8f changeset: 88823:472376125c8f user: Guido van Rossum date: Wed Jan 29 14:24:45 2014 -0800 summary: asyncio: Refactor drain logic in streams.py to be reusable. files: Lib/asyncio/streams.py | 97 ++++++++++++++++++----------- 1 files changed, 61 insertions(+), 36 deletions(-) diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -94,8 +94,63 @@ return (yield from loop.create_server(factory, host, port, **kwds)) -class StreamReaderProtocol(protocols.Protocol): - """Trivial helper class to adapt between Protocol and StreamReader. +class FlowControlMixin(protocols.Protocol): + """Reusable flow control logic for StreamWriter.drain(). + + This implements the protocol methods pause_writing(), + resume_reading() and connection_lost(). If the subclass overrides + these it must call the super methods. + + StreamWriter.drain() must check for error conditions and then call + _make_drain_waiter(), which will return either () or a Future + depending on the paused state. + """ + + def __init__(self, loop=None): + self._loop = loop # May be None; we may never need it. + self._paused = False + self._drain_waiter = None + + def pause_writing(self): + assert not self._paused + self._paused = True + + def resume_writing(self): + assert self._paused + self._paused = False + waiter = self._drain_waiter + if waiter is not None: + self._drain_waiter = None + if not waiter.done(): + waiter.set_result(None) + + def connection_lost(self, exc): + # Wake up the writer if currently paused. + if not self._paused: + return + waiter = self._drain_waiter + if waiter is None: + return + self._drain_waiter = None + if waiter.done(): + return + if exc is None: + waiter.set_result(None) + else: + waiter.set_exception(exc) + + def _make_drain_waiter(self): + if not self._paused: + return () + waiter = self._drain_waiter + assert waiter is None or waiter.cancelled() + waiter = futures.Future(loop=self._loop) + self._drain_waiter = waiter + return waiter + + +class StreamReaderProtocol(FlowControlMixin, protocols.Protocol): + """Helper class to adapt between Protocol and StreamReader. (This is a helper class instead of making StreamReader itself a Protocol subclass, because the StreamReader has other potential @@ -104,12 +159,10 @@ """ def __init__(self, stream_reader, client_connected_cb=None, loop=None): + super().__init__(loop=loop) self._stream_reader = stream_reader self._stream_writer = None - self._drain_waiter = None - self._paused = False self._client_connected_cb = client_connected_cb - self._loop = loop # May be None; we may never need it. def connection_made(self, transport): self._stream_reader.set_transport(transport) @@ -127,16 +180,7 @@ self._stream_reader.feed_eof() else: self._stream_reader.set_exception(exc) - # Also wake up the writing side. - if self._paused: - waiter = self._drain_waiter - if waiter is not None: - self._drain_waiter = None - if not waiter.done(): - if exc is None: - waiter.set_result(None) - else: - waiter.set_exception(exc) + super().connection_lost(exc) def data_received(self, data): self._stream_reader.feed_data(data) @@ -144,19 +188,6 @@ def eof_received(self): self._stream_reader.feed_eof() - def pause_writing(self): - assert not self._paused - self._paused = True - - def resume_writing(self): - assert self._paused - self._paused = False - waiter = self._drain_waiter - if waiter is not None: - self._drain_waiter = None - if not waiter.done(): - waiter.set_result(None) - class StreamWriter: """Wraps a Transport. @@ -211,17 +242,11 @@ completed, which will happen when the buffer is (partially) drained and the protocol is resumed. """ - if self._reader._exception is not None: + if self._reader is not None and self._reader._exception is not None: raise self._reader._exception if self._transport._conn_lost: # Uses private variable. raise ConnectionResetError('Connection lost') - if not self._protocol._paused: - return () - waiter = self._protocol._drain_waiter - assert waiter is None or waiter.cancelled() - waiter = futures.Future(loop=self._loop) - self._protocol._drain_waiter = waiter - return waiter + return self._protocol._make_drain_waiter() class StreamReader: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 23:41:58 2014 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 29 Jan 2014 23:41:58 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Pass_through_pa?= =?utf-8?q?use/resume_from_subprocess_pipe_proto_to_subprocess?= Message-ID: <3fF07B1qKFz7Lkw@mail.python.org> http://hg.python.org/cpython/rev/83bec639278c changeset: 88824:83bec639278c user: Guido van Rossum date: Wed Jan 29 14:28:15 2014 -0800 summary: asyncio: Pass through pause/resume from subprocess pipe proto to subprocess proto. Also kill dummy eof_received(). files: Lib/asyncio/base_subprocess.py | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -150,8 +150,11 @@ self.disconnected = True self.proc._pipe_connection_lost(self.fd, exc) - def eof_received(self): - pass + def pause_writing(self): + self.proc._protocol.pause_writing() + + def resume_writing(self): + self.proc._protocol.resume_writing() class ReadSubprocessPipeProto(WriteSubprocessPipeProto, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 23:41:59 2014 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 29 Jan 2014 23:41:59 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_wait=5Ffor=28?= =?utf-8?q?=29_now_accepts_None_as_timeout_=28Victor_Stinner=29=2E?= Message-ID: <3fF07C3BPWz7Lkj@mail.python.org> http://hg.python.org/cpython/rev/999c60a8c01b changeset: 88825:999c60a8c01b user: Guido van Rossum date: Wed Jan 29 14:30:38 2014 -0800 summary: asyncio: wait_for() now accepts None as timeout (Victor Stinner). files: Lib/asyncio/tasks.py | 3 +++ Lib/test/test_asyncio/test_tasks.py | 11 +++++++++++ 2 files changed, 14 insertions(+), 0 deletions(-) diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -394,6 +394,9 @@ if loop is None: loop = events.get_event_loop() + if timeout is None: + return (yield from fut) + waiter = futures.Future(loop=loop) timeout_handle = loop.call_later(timeout, _release_waiter, waiter, False) cb = functools.partial(_release_waiter, waiter, True) 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 @@ -380,6 +380,17 @@ self.assertEqual(foo_running, False) + def test_wait_for_blocking(self): + loop = test_utils.TestLoop() + self.addCleanup(loop.close) + + @asyncio.coroutine + def coro(): + return 'done' + + res = loop.run_until_complete(asyncio.wait_for(coro(), timeout=None, loop=loop)) + self.assertEqual(res, 'done') + def test_wait_for_with_global_loop(self): def gen(): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 23:42:00 2014 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 29 Jan 2014 23:42:00 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Fix_=5Fmake=5Fs?= =?utf-8?q?ubprocess=5Ftransport=28=29=3A_pass_extra_value_to_the_construc?= =?utf-8?q?tor=2E?= Message-ID: <3fF07D4rThz7LjV@mail.python.org> http://hg.python.org/cpython/rev/be3ad5e625f3 changeset: 88826:be3ad5e625f3 user: Victor Stinner date: Wed Jan 29 14:32:20 2014 -0800 summary: asyncio: Fix _make_subprocess_transport(): pass extra value to the constructor. files: Lib/asyncio/unix_events.py | 2 +- Lib/asyncio/windows_events.py | 2 +- 2 files changed, 2 insertions(+), 2 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 @@ -159,7 +159,7 @@ with events.get_child_watcher() as watcher: transp = _UnixSubprocessTransport(self, protocol, args, shell, stdin, stdout, stderr, bufsize, - extra=None, **kwargs) + extra=extra, **kwargs) yield from transp._post_init() watcher.add_child_handler(transp.get_pid(), self._child_watcher_callback, transp) 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 @@ -174,7 +174,7 @@ extra=None, **kwargs): transp = _WindowsSubprocessTransport(self, protocol, args, shell, stdin, stdout, stderr, bufsize, - extra=None, **kwargs) + extra=extra, **kwargs) yield from transp._post_init() return transp -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 23:42:02 2014 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 29 Jan 2014 23:42:02 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_subprocess=5Fsh?= =?utf-8?q?ell=28=29_and_subprocess=5Fexec=28=29_now_raise_ValueError_inst?= =?utf-8?q?ead?= Message-ID: <3fF07G0Zm9z7Lk0@mail.python.org> http://hg.python.org/cpython/rev/8d6112ca083b changeset: 88827:8d6112ca083b user: Victor Stinner date: Wed Jan 29 14:35:15 2014 -0800 summary: asyncio: subprocess_shell() and subprocess_exec() now raise ValueError instead of assert. Moreover, bufsize different than 0 is now considered as an error. files: Lib/asyncio/base_events.py | 19 +++++++-- Lib/test/test_asyncio/test_events.py | 32 ++++++++++++++++ 2 files changed, 46 insertions(+), 5 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 @@ -552,9 +552,14 @@ stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=False, shell=True, bufsize=0, **kwargs): - assert not universal_newlines, "universal_newlines must be False" - assert shell, "shell must be True" - assert isinstance(cmd, str), cmd + if not isinstance(cmd, str): + raise ValueError("cmd must be a string") + if universal_newlines: + raise ValueError("universal_newlines must be False") + if not shell: + raise ValueError("shell must be False") + if bufsize != 0: + raise ValueError("bufsize must be 0") protocol = protocol_factory() transport = yield from self._make_subprocess_transport( protocol, cmd, True, stdin, stdout, stderr, bufsize, **kwargs) @@ -565,8 +570,12 @@ stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=False, shell=False, bufsize=0, **kwargs): - assert not universal_newlines, "universal_newlines must be False" - assert not shell, "shell must be False" + if universal_newlines: + raise ValueError("universal_newlines must be False") + if shell: + raise ValueError("shell must be False") + if bufsize != 0: + raise ValueError("bufsize must be 0") protocol = protocol_factory() transport = yield from self._make_subprocess_transport( protocol, args, False, stdin, stdout, stderr, bufsize, **kwargs) 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 @@ -1491,6 +1491,38 @@ self.loop.run_until_complete(proto.completed) self.assertEqual(7, proto.returncode) + def test_subprocess_exec_invalid_args(self): + @asyncio.coroutine + def connect(**kwds): + yield from self.loop.subprocess_exec( + asyncio.SubprocessProtocol, + 'pwd', **kwds) + + with self.assertRaises(ValueError): + self.loop.run_until_complete(connect(universal_newlines=True)) + with self.assertRaises(ValueError): + self.loop.run_until_complete(connect(bufsize=4096)) + with self.assertRaises(ValueError): + self.loop.run_until_complete(connect(shell=True)) + + def test_subprocess_shell_invalid_args(self): + @asyncio.coroutine + def connect(cmd=None, **kwds): + if not cmd: + cmd = 'pwd' + yield from self.loop.subprocess_shell( + asyncio.SubprocessProtocol, + cmd, **kwds) + + with self.assertRaises(ValueError): + self.loop.run_until_complete(connect(['ls', '-l'])) + with self.assertRaises(ValueError): + self.loop.run_until_complete(connect(universal_newlines=True)) + with self.assertRaises(ValueError): + self.loop.run_until_complete(connect(bufsize=4096)) + with self.assertRaises(ValueError): + self.loop.run_until_complete(connect(shell=False)) + if sys.platform == 'win32': -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 23:42:03 2014 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 29 Jan 2014 23:42:03 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_More_asyncio_news=2E?= Message-ID: <3fF07H26Twz7Llp@mail.python.org> http://hg.python.org/cpython/rev/cb5448352e11 changeset: 88828:cb5448352e11 user: Guido van Rossum date: Wed Jan 29 14:40:56 2014 -0800 summary: More asyncio news. files: Misc/NEWS | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,11 @@ Library ------- +- asyncio: Some refactoring; add write flow control to unix pipes; + support wait_for(f, None); don't log broken/disconnected pipes; use + ValueError instead of assert for forbidden subprocess_{shell,exec} + arguments. (More to follow -- a convenience API for subprocesses.) + - Issue #20424: Python implementation of io.StringIO now supports lone surrogates. - Issue #20308: inspect.signature now works on classes without user-defined -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 23:45:16 2014 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 29 Jan 2014 23:45:16 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwMzcz?= =?utf-8?q?=3A_generalize_use_of_test=2Escript=5Fhelper_in_test=5Fwarnings?= =?utf-8?q?=2E__Patch_by?= Message-ID: <3fF0C025YKz7Llc@mail.python.org> http://hg.python.org/cpython/rev/d844b31471b5 changeset: 88829:d844b31471b5 branch: 3.3 parent: 88805:6ca9ba9eb76b user: Antoine Pitrou date: Wed Jan 29 23:44:05 2014 +0100 summary: Issue #20373: generalize use of test.script_helper in test_warnings. Patch by Arfrever. files: Lib/test/test_warnings.py | 65 +++++++++----------------- 1 files changed, 22 insertions(+), 43 deletions(-) diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py --- a/Lib/test/test_warnings.py +++ b/Lib/test/test_warnings.py @@ -4,7 +4,6 @@ from io import StringIO import sys import unittest -import subprocess from test import support from test.script_helper import assert_python_ok @@ -719,47 +718,34 @@ class EnvironmentVariableTests(BaseTest): def test_single_warning(self): - newenv = os.environ.copy() - newenv["PYTHONWARNINGS"] = "ignore::DeprecationWarning" - p = subprocess.Popen([sys.executable, - "-c", "import sys; sys.stdout.write(str(sys.warnoptions))"], - stdout=subprocess.PIPE, env=newenv) - self.assertEqual(p.communicate()[0], b"['ignore::DeprecationWarning']") - self.assertEqual(p.wait(), 0) + rc, stdout, stderr = assert_python_ok("-c", + "import sys; sys.stdout.write(str(sys.warnoptions))", + PYTHONWARNINGS="ignore::DeprecationWarning") + self.assertEqual(stdout, b"['ignore::DeprecationWarning']") def test_comma_separated_warnings(self): - newenv = os.environ.copy() - newenv["PYTHONWARNINGS"] = ("ignore::DeprecationWarning," - "ignore::UnicodeWarning") - p = subprocess.Popen([sys.executable, - "-c", "import sys; sys.stdout.write(str(sys.warnoptions))"], - stdout=subprocess.PIPE, env=newenv) - self.assertEqual(p.communicate()[0], - b"['ignore::DeprecationWarning', 'ignore::UnicodeWarning']") - self.assertEqual(p.wait(), 0) + rc, stdout, stderr = assert_python_ok("-c", + "import sys; sys.stdout.write(str(sys.warnoptions))", + PYTHONWARNINGS="ignore::DeprecationWarning,ignore::UnicodeWarning") + self.assertEqual(stdout, + b"['ignore::DeprecationWarning', 'ignore::UnicodeWarning']") def test_envvar_and_command_line(self): - newenv = os.environ.copy() - newenv["PYTHONWARNINGS"] = "ignore::DeprecationWarning" - p = subprocess.Popen([sys.executable, "-W" "ignore::UnicodeWarning", - "-c", "import sys; sys.stdout.write(str(sys.warnoptions))"], - stdout=subprocess.PIPE, env=newenv) - self.assertEqual(p.communicate()[0], - b"['ignore::UnicodeWarning', 'ignore::DeprecationWarning']") - self.assertEqual(p.wait(), 0) + rc, stdout, stderr = assert_python_ok("-Wignore::UnicodeWarning", "-c", + "import sys; sys.stdout.write(str(sys.warnoptions))", + PYTHONWARNINGS="ignore::DeprecationWarning") + self.assertEqual(stdout, + b"['ignore::UnicodeWarning', 'ignore::DeprecationWarning']") @unittest.skipUnless(sys.getfilesystemencoding() != 'ascii', 'requires non-ascii filesystemencoding') def test_nonascii(self): - newenv = os.environ.copy() - newenv["PYTHONWARNINGS"] = "ignore:Deprecaci?nWarning" - newenv["PYTHONIOENCODING"] = "utf-8" - p = subprocess.Popen([sys.executable, - "-c", "import sys; sys.stdout.write(str(sys.warnoptions))"], - stdout=subprocess.PIPE, env=newenv) - self.assertEqual(p.communicate()[0], - "['ignore:Deprecaci?nWarning']".encode('utf-8')) - self.assertEqual(p.wait(), 0) + rc, stdout, stderr = assert_python_ok("-c", + "import sys; sys.stdout.write(str(sys.warnoptions))", + PYTHONIOENCODING="utf-8", + PYTHONWARNINGS="ignore:Deprecaci?nWarning") + self.assertEqual(stdout, + "['ignore:Deprecaci?nWarning']".encode('utf-8')) class CEnvironmentVariableTests(EnvironmentVariableTests, unittest.TestCase): module = c_warnings @@ -774,18 +760,11 @@ # or not completely loaded (warnings imports indirectly encodings by # importing linecache) yet with support.temp_cwd() as cwd, support.temp_cwd('encodings'): - env = os.environ.copy() - env['PYTHONPATH'] = cwd - # encodings loaded by initfsencoding() - retcode = subprocess.call([sys.executable, '-c', 'pass'], env=env) - self.assertEqual(retcode, 0) + assert_python_ok('-c', 'pass', PYTHONPATH=cwd) # Use -W to load warnings module at startup - retcode = subprocess.call( - [sys.executable, '-c', 'pass', '-W', 'always'], - env=env) - self.assertEqual(retcode, 0) + assert_python_ok('-c', 'pass', '-W', 'always', PYTHONPATH=cwd) def setUpModule(): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed Jan 29 23:45:17 2014 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 29 Jan 2014 23:45:17 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320373=3A_generalize_use_of_test=2Escript=5Fhelp?= =?utf-8?q?er_in_test=5Fwarnings=2E__Patch_by?= Message-ID: <3fF0C15XR3z7LmL@mail.python.org> http://hg.python.org/cpython/rev/04b658b3fe7c changeset: 88830:04b658b3fe7c parent: 88828:cb5448352e11 parent: 88829:d844b31471b5 user: Antoine Pitrou date: Wed Jan 29 23:45:07 2014 +0100 summary: Issue #20373: generalize use of test.script_helper in test_warnings. Patch by Arfrever. files: Lib/test/test_warnings.py | 65 +++++++++----------------- 1 files changed, 22 insertions(+), 43 deletions(-) diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py --- a/Lib/test/test_warnings.py +++ b/Lib/test/test_warnings.py @@ -4,7 +4,6 @@ from io import StringIO import sys import unittest -import subprocess from test import support from test.script_helper import assert_python_ok @@ -732,47 +731,34 @@ class EnvironmentVariableTests(BaseTest): def test_single_warning(self): - newenv = os.environ.copy() - newenv["PYTHONWARNINGS"] = "ignore::DeprecationWarning" - p = subprocess.Popen([sys.executable, - "-c", "import sys; sys.stdout.write(str(sys.warnoptions))"], - stdout=subprocess.PIPE, env=newenv) - self.assertEqual(p.communicate()[0], b"['ignore::DeprecationWarning']") - self.assertEqual(p.wait(), 0) + rc, stdout, stderr = assert_python_ok("-c", + "import sys; sys.stdout.write(str(sys.warnoptions))", + PYTHONWARNINGS="ignore::DeprecationWarning") + self.assertEqual(stdout, b"['ignore::DeprecationWarning']") def test_comma_separated_warnings(self): - newenv = os.environ.copy() - newenv["PYTHONWARNINGS"] = ("ignore::DeprecationWarning," - "ignore::UnicodeWarning") - p = subprocess.Popen([sys.executable, - "-c", "import sys; sys.stdout.write(str(sys.warnoptions))"], - stdout=subprocess.PIPE, env=newenv) - self.assertEqual(p.communicate()[0], - b"['ignore::DeprecationWarning', 'ignore::UnicodeWarning']") - self.assertEqual(p.wait(), 0) + rc, stdout, stderr = assert_python_ok("-c", + "import sys; sys.stdout.write(str(sys.warnoptions))", + PYTHONWARNINGS="ignore::DeprecationWarning,ignore::UnicodeWarning") + self.assertEqual(stdout, + b"['ignore::DeprecationWarning', 'ignore::UnicodeWarning']") def test_envvar_and_command_line(self): - newenv = os.environ.copy() - newenv["PYTHONWARNINGS"] = "ignore::DeprecationWarning" - p = subprocess.Popen([sys.executable, "-W" "ignore::UnicodeWarning", - "-c", "import sys; sys.stdout.write(str(sys.warnoptions))"], - stdout=subprocess.PIPE, env=newenv) - self.assertEqual(p.communicate()[0], - b"['ignore::UnicodeWarning', 'ignore::DeprecationWarning']") - self.assertEqual(p.wait(), 0) + rc, stdout, stderr = assert_python_ok("-Wignore::UnicodeWarning", "-c", + "import sys; sys.stdout.write(str(sys.warnoptions))", + PYTHONWARNINGS="ignore::DeprecationWarning") + self.assertEqual(stdout, + b"['ignore::UnicodeWarning', 'ignore::DeprecationWarning']") @unittest.skipUnless(sys.getfilesystemencoding() != 'ascii', 'requires non-ascii filesystemencoding') def test_nonascii(self): - newenv = os.environ.copy() - newenv["PYTHONWARNINGS"] = "ignore:Deprecaci?nWarning" - newenv["PYTHONIOENCODING"] = "utf-8" - p = subprocess.Popen([sys.executable, - "-c", "import sys; sys.stdout.write(str(sys.warnoptions))"], - stdout=subprocess.PIPE, env=newenv) - self.assertEqual(p.communicate()[0], - "['ignore:Deprecaci?nWarning']".encode('utf-8')) - self.assertEqual(p.wait(), 0) + rc, stdout, stderr = assert_python_ok("-c", + "import sys; sys.stdout.write(str(sys.warnoptions))", + PYTHONIOENCODING="utf-8", + PYTHONWARNINGS="ignore:Deprecaci?nWarning") + self.assertEqual(stdout, + "['ignore:Deprecaci?nWarning']".encode('utf-8')) class CEnvironmentVariableTests(EnvironmentVariableTests, unittest.TestCase): module = c_warnings @@ -787,18 +773,11 @@ # or not completely loaded (warnings imports indirectly encodings by # importing linecache) yet with support.temp_cwd() as cwd, support.temp_cwd('encodings'): - env = os.environ.copy() - env['PYTHONPATH'] = cwd - # encodings loaded by initfsencoding() - retcode = subprocess.call([sys.executable, '-c', 'pass'], env=env) - self.assertEqual(retcode, 0) + assert_python_ok('-c', 'pass', PYTHONPATH=cwd) # Use -W to load warnings module at startup - retcode = subprocess.call( - [sys.executable, '-c', 'pass', '-W', 'always'], - env=env) - self.assertEqual(retcode, 0) + assert_python_ok('-c', 'pass', '-W', 'always', PYTHONPATH=cwd) class FinalizationTest(unittest.TestCase): def test_finalization(self): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 30 00:19:38 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 30 Jan 2014 00:19:38 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_document_iscoro?= =?utf-8?b?dXRpbmUoKSwgaXNjb3JvdXRpbmVmdW5jdGlvbigpIGFuZCB3YWl0X2Zvcigp?= Message-ID: <3fF0yf4jQjz7Ljn@mail.python.org> http://hg.python.org/cpython/rev/d5ad8bd335f5 changeset: 88831:d5ad8bd335f5 user: Victor Stinner date: Thu Jan 30 00:18:50 2014 +0100 summary: asyncio: document iscoroutine(), iscoroutinefunction() and wait_for() Mention that wait_for() now accepts None for the timeout. files: Doc/library/asyncio-task.rst | 30 ++++++++++++++++++++++- 1 files changed, 28 insertions(+), 2 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 @@ -20,12 +20,13 @@ - The function that defines a coroutine (a function definition decorated with ``@asyncio.coroutine``). If disambiguation is needed - we will call this a *coroutine function*. + we will call this a *coroutine function* (:func:`iscoroutinefunction` + returns ``True``). - The object obtained by calling a coroutine function. This object represents a computation or an I/O operation (usually a combination) that will complete eventually. If disambiguation is needed we will - call it a *coroutine object*. + call it a *coroutine object* (:func:`iscoroutine` returns ``True``). Things a coroutine can do: @@ -425,6 +426,15 @@ outer Future is *not* cancelled in this case. (This is to prevent the cancellation of one child to cause other children to be cancelled.) +.. function:: iscoroutine(obj) + + Return ``True`` if *obj* is a :ref:`coroutine object `. + +.. function:: iscoroutinefunction(obj) + + Return ``True`` if *func* is a decorated :ref:`coroutine function + `. + .. function:: sleep(delay, result=None, \*, loop=None) Create a :ref:`coroutine object ` that completes after a given @@ -501,3 +511,19 @@ the timeout occurs are returned in the second set. +.. function:: wait_for(fut, timeout, \*, loop=None) + + Wait for the single :class:`Future` or :ref:`coroutine object ` + to complete, with timeout. If *timeout* is ``None``, block until the future + completes. + + Coroutine will be wrapped in :class:`Task`. + + Returns result of the Future or coroutine. When a timeout occurs, it + cancels the task and raises :exc:`TimeoutError`. To avoid the task + cancellation, wrap it in :func:`shield`. + + Usage:: + + result = yield from asyncio.wait_for(fut, 60.0) + -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 30 06:12:30 2014 From: python-checkins at python.org (yury.selivanov) Date: Thu, 30 Jan 2014 06:12:30 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2Edocs=3A_Document?= =?utf-8?q?_constructors_for_Signature_=26_Parameter_=2320442?= Message-ID: <3fF8np641Lz7Ljk@mail.python.org> http://hg.python.org/cpython/rev/0a3201aab2b8 changeset: 88832:0a3201aab2b8 user: Yury Selivanov date: Thu Jan 30 00:10:54 2014 -0500 summary: inspect.docs: Document constructors for Signature & Parameter #20442 files: Doc/library/inspect.rst | 13 +++++++++++-- 1 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -444,12 +444,21 @@ no metadata about their arguments. -.. class:: Signature +.. class:: Signature(parameters=None, \*, return_annotation=Signature.empty) A Signature object represents the call signature of a function and its return annotation. For each parameter accepted by the function it stores a :class:`Parameter` object in its :attr:`parameters` collection. + The optional *parameters* argument is a sequence of :class:`Parameter` + objects, which is validated to check that there are no parameters with + duplicate names, and that the parameters are in the right order, i.e. + positional-only first, then positional-or-keyword, and that parameters with + defaults follow parameters without defaults. + + The optional *return_annotation* argument, can be an arbitrary Python object, + is the "return" annotation of the callable. + Signature objects are *immutable*. Use :meth:`Signature.replace` to make a modified copy. @@ -498,7 +507,7 @@ "(a, b) -> 'new return anno'" -.. class:: Parameter +.. class:: Parameter(name, kind, \*, default=Parameter.empty, annotation=Parameter.empty) Parameter objects are *immutable*. Instead of modifying a Parameter object, you can use :meth:`Parameter.replace` to create a modified copy. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 30 06:12:32 2014 From: python-checkins at python.org (yury.selivanov) Date: Thu, 30 Jan 2014 06:12:32 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogaW5zcGVjdC5kb2Nz?= =?utf-8?q?=3A_Document_constructors_for_Signature_=26_Parameter_=2320442?= Message-ID: <3fF8nr0m15z7Ljy@mail.python.org> http://hg.python.org/cpython/rev/885c709d0dde changeset: 88833:885c709d0dde branch: 3.3 parent: 88829:d844b31471b5 user: Yury Selivanov date: Thu Jan 30 00:12:02 2014 -0500 summary: inspect.docs: Document constructors for Signature & Parameter #20442 files: Doc/library/inspect.rst | 13 +++++++++++-- 1 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -435,12 +435,21 @@ no metadata about their arguments. -.. class:: Signature +.. class:: Signature(parameters=None, \*, return_annotation=Signature.empty) A Signature object represents the call signature of a function and its return annotation. For each parameter accepted by the function it stores a :class:`Parameter` object in its :attr:`parameters` collection. + The optional *parameters* argument is a sequence of :class:`Parameter` + objects, which is validated to check that there are no parameters with + duplicate names, and that the parameters are in the right order, i.e. + positional-only first, then positional-or-keyword, and that parameters with + defaults follow parameters without defaults. + + The optional *return_annotation* argument, can be an arbitrary Python object, + is the "return" annotation of the callable. + Signature objects are *immutable*. Use :meth:`Signature.replace` to make a modified copy. @@ -489,7 +498,7 @@ "(a, b) -> 'new return anno'" -.. class:: Parameter +.. class:: Parameter(name, kind, \*, default=Parameter.empty, annotation=Parameter.empty) Parameter objects are *immutable*. Instead of modifying a Parameter object, you can use :meth:`Parameter.replace` to create a modified copy. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 30 06:23:11 2014 From: python-checkins at python.org (yury.selivanov) Date: Thu, 30 Jan 2014 06:23:11 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2Edoc=3A_Soften_th?= =?utf-8?q?e_note_about_inspect=2Esignature_not_supporting?= Message-ID: <3fF9271syhz7LjV@mail.python.org> http://hg.python.org/cpython/rev/3ee3d4449a9f changeset: 88834:3ee3d4449a9f parent: 88832:0a3201aab2b8 user: Yury Selivanov date: Thu Jan 30 00:22:57 2014 -0500 summary: inspect.doc: Soften the note about inspect.signature not supporting all builtin functions. files: Doc/library/inspect.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -440,8 +440,8 @@ .. note:: Some callables may not be introspectable in certain implementations of - Python. For example, in CPython, built-in functions defined in C provide - no metadata about their arguments. + Python. For example, in CPython, some built-in functions defined in + C provide no metadata about their arguments. .. class:: Signature(parameters=None, \*, return_annotation=Signature.empty) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 30 08:03:17 2014 From: python-checkins at python.org (gregory.p.smith) Date: Thu, 30 Jan 2014 08:03:17 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Remove_issue_1?= =?utf-8?q?9081_Misc/NEWS_entry_since_it_isn=27t_entirely_fixed_yet=2E?= Message-ID: <3fFCFd5zXcz7Ljf@mail.python.org> http://hg.python.org/cpython/rev/ecb272bae417 changeset: 88835:ecb272bae417 branch: 3.3 parent: 88833:885c709d0dde user: Gregory P. Smith date: Wed Jan 29 22:59:34 2014 -0800 summary: Remove issue 19081 Misc/NEWS entry since it isn't entirely fixed yet. files: Misc/NEWS | 5 ----- 1 files changed, 0 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,11 +24,6 @@ source encoding declarations, and can be used to make Python batch files on Windows. -- Issue #19081: When a zipimport .zip file in sys.path being imported from - is modified during the lifetime of the Python process after zipimport has - already cached the zip's table of contents we detect this and recover - rather than read bad data from the .zip (causing odd import errors). - - Issue #17432: Drop UCS2 from names of Unicode functions in python3.def. - Issue #19969: PyBytes_FromFormatV() now raises an OverflowError if "%c" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 30 08:03:19 2014 From: python-checkins at python.org (gregory.p.smith) Date: Thu, 30 Jan 2014 08:03:19 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Remove_issue_19081_Misc/NEWS_entry_since_it_isn=27t_enti?= =?utf-8?q?rely_fixed_yet=2E?= Message-ID: <3fFCFg0rDCz7Ljw@mail.python.org> http://hg.python.org/cpython/rev/03fc7449f204 changeset: 88836:03fc7449f204 parent: 88834:3ee3d4449a9f parent: 88835:ecb272bae417 user: Gregory P. Smith date: Wed Jan 29 23:02:49 2014 -0800 summary: Remove issue 19081 Misc/NEWS entry since it isn't entirely fixed yet. files: Misc/NEWS | 5 ----- 1 files changed, 0 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -105,11 +105,6 @@ source encoding declarations, and can be used to make Python batch files on Windows. -- Issue #19081: When a zipimport .zip file in sys.path being imported from - is modified during the lifetime of the Python process after zipimport has - already cached the zip's table of contents we detect this and recover - rather than read bad data from the .zip (causing odd import errors). - Library ------- -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu Jan 30 09:47:13 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 30 Jan 2014 09:47:13 +0100 Subject: [Python-checkins] Daily reference leaks (d5ad8bd335f5): sum=-4 Message-ID: results for d5ad8bd335f5 on branch "default" -------------------------------------------- test_site leaked [-2, 0, 0] references, sum=-2 test_site leaked [-2, 0, 0] memory blocks, sum=-2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogwOQyjv', '-x'] From python-checkins at python.org Thu Jan 30 13:07:59 2014 From: python-checkins at python.org (nick.coghlan) Date: Thu, 30 Jan 2014 13:07:59 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_427=3A_emphasise_the_pref?= =?utf-8?q?erence_for_installation?= Message-ID: <3fFL1C0pT1z7Ljf@mail.python.org> http://hg.python.org/peps/rev/26983acc9c11 changeset: 5367:26983acc9c11 user: Nick Coghlan date: Thu Jan 30 22:07:45 2014 +1000 summary: PEP 427: emphasise the preference for installation The zipimport compatibility isn't an accident, but relying on it is still a great way to create obscure bugs for yourself if you don't already know exactly what you're doing. files: pep-0427.txt | 49 +++++++++++++++++++++++++++------------ 1 files changed, 34 insertions(+), 15 deletions(-) diff --git a/pep-0427.txt b/pep-0427.txt --- a/pep-0427.txt +++ b/pep-0427.txt @@ -400,23 +400,42 @@ Is it possible to import Python code directly from a wheel file? ---------------------------------------------------------------- - Yes, the wheel format is deliberately designed to be compatible with - Python's support for importing from zip files, ensuring that it - provides a superset of the functionality provided by the preceding - egg format. + Technically, a subset of wheel files *do* support being placed directly + on ``sys.path`` (due to the combination of supporting installation + via simple extraction and using an archive format that is compatible + with ``zipimport``), but actually doing so is generally discouraged. - However, this is generally not a *recommended* approach to using wheel - files, as importing from a zip file rather than an ordinary filesystem - directory imposes a number of additional constraints that will often - break the assumptions of Python developers (for example, C extensions - cannot be imported directly from a zip archive, and the ``__file__`` - attribute no longer refers to an ordinary filesystem path, but to - a combination path that includes both the location of the zip archive - on the filesystem and the relative path to the module inside the - archive). + Firstly, wheel *is* designed primarily as an installation format, so + skipping the installation step means deliberately avoiding any reliance + on features that assume full installation (such as being able to use + standard tools like ``pip`` and ``virtualenv`` to capture and manage + dependencies in a way that can be properly tracked for auditing and + security update purposes, or integrating fully with the standard + build machinery for C extensions by publishing header files in the + appropriate place). - Like metaclasses and metapath importers, if you're not sure if you need - to take advantage of this feature, you almost certainly don't need it. + Secondly, while some Python software is written to support running + directly from a zip archive, it is still common for code to be written + assuming it has been fully installed. When that assumption is broken + by trying to run the software from a zip archive, the failures can often + be obscure and hard to diagnose (especially when they occur in third + party libraries). The two most common sources of problems with this + are the fact that importing C extensions from a zip archive is *not* + supported by CPython (since doing so is not supported directly by the + dynamic loading machinery on any platform) and that when running from + a zip archive the ``__file__`` attribute no longer refers to an + ordinary filesystem path, but to a combination path that includes + both the location of the zip archive on the filesystem and the + relative path to the module inside the archive). Even when software + uses the abstract resource APIs correctly internally, interfacing with + external components may still require the available of an actual on-disk + file. + + Like metaclasses, monkeypatching and metapath importers, if you're not + already sure you need to take advantage of this feature, you almost + certainly don't need it. If you *do* decide to use it anyway, be + aware that many projects will require a failure to be reproduced with + a fully installed package before accepting it as a genuine bug. References -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Jan 30 13:18:59 2014 From: python-checkins at python.org (nick.coghlan) Date: Thu, 30 Jan 2014 13:18:59 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?peps=3A_Wording_tweaks?= Message-ID: <3fFLFv189Bz7LjV@mail.python.org> http://hg.python.org/peps/rev/4ad34ebe2a06 changeset: 5368:4ad34ebe2a06 user: Nick Coghlan date: Thu Jan 30 22:18:50 2014 +1000 summary: Wording tweaks files: pep-0427.txt | 29 +++++++++++++++-------------- 1 files changed, 15 insertions(+), 14 deletions(-) diff --git a/pep-0427.txt b/pep-0427.txt --- a/pep-0427.txt +++ b/pep-0427.txt @@ -400,17 +400,18 @@ Is it possible to import Python code directly from a wheel file? ---------------------------------------------------------------- - Technically, a subset of wheel files *do* support being placed directly - on ``sys.path`` (due to the combination of supporting installation - via simple extraction and using an archive format that is compatible - with ``zipimport``), but actually doing so is generally discouraged. + Technically, due to the combination of supporting installation via + simple extraction and using an archive format that is compatible with + ``zipimport``, a subset of wheel files *do* support being placed directly + on ``sys.path``. However, while this behaviour is a natural consequence + of the format design, actually relying on it is generally discouraged. - Firstly, wheel *is* designed primarily as an installation format, so - skipping the installation step means deliberately avoiding any reliance - on features that assume full installation (such as being able to use - standard tools like ``pip`` and ``virtualenv`` to capture and manage - dependencies in a way that can be properly tracked for auditing and - security update purposes, or integrating fully with the standard + Firstly, wheel *is* designed primarily as a distribution format, so + skipping the installation step also means deliberately avoiding any + reliance on features that assume full installation (such as being able + to use standard tools like ``pip`` and ``virtualenv`` to capture and + manage dependencies in a way that can be properly tracked for auditing + and security update purposes, or integrating fully with the standard build machinery for C extensions by publishing header files in the appropriate place). @@ -426,10 +427,10 @@ a zip archive the ``__file__`` attribute no longer refers to an ordinary filesystem path, but to a combination path that includes both the location of the zip archive on the filesystem and the - relative path to the module inside the archive). Even when software - uses the abstract resource APIs correctly internally, interfacing with - external components may still require the available of an actual on-disk - file. + relative path to the module inside the archive. Even when software + correctly uses the abstract resource APIs internally, interfacing with + external components may still require the availability of an actual + on-disk file. Like metaclasses, monkeypatching and metapath importers, if you're not already sure you need to take advantage of this feature, you almost -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu Jan 30 17:23:49 2014 From: python-checkins at python.org (zach.ware) Date: Thu, 30 Jan 2014 17:23:49 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?devguide=3A_Issue_=2320448=3A_Escape_?= =?utf-8?q?backslashes=2E__Caught_by_Saimadhav_Heblikar=2E?= Message-ID: <3fFRhP0DTyz7Ljp@mail.python.org> http://hg.python.org/devguide/rev/7d95a62513ce changeset: 663:7d95a62513ce user: Zachary Ware date: Thu Jan 30 10:23:24 2014 -0600 summary: Issue #20448: Escape backslashes. Caught by Saimadhav Heblikar. files: setup.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.rst b/setup.rst --- a/setup.rst +++ b/setup.rst @@ -221,8 +221,8 @@ to build. If you prefer, you can exclude the offending projects from the build process by unchecking them inside the :menuselection:`Build --> Configuration Manager...` settings. You can -also use the script :file:`Tools\\buildbot\external.bat` or -:file:`Tools\\buildbot\external-amd64.bat` (as applicable) to download and +also use the script :file:`Tools\\buildbot\\external.bat` or +:file:`Tools\\buildbot\\external-amd64.bat` (as applicable) to download and compile missing dependencies. Once built you might want to set Python as a startup project. Pressing F5 in -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Thu Jan 30 19:07:03 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 30 Jan 2014 19:07:03 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_overlapped=2Ec=3A_Fix_usag?= =?utf-8?q?e_of_the_union?= Message-ID: <3fFTzW0ltvzRlj@mail.python.org> http://hg.python.org/cpython/rev/73dbb884eb09 changeset: 88837:73dbb884eb09 user: Victor Stinner date: Thu Jan 30 19:06:44 2014 +0100 summary: overlapped.c: Fix usage of the union * read_buffer can only be used for TYPE_READ and TYPE_ACCEPT types * write_buffer can only be used for TYPE_WRITE type files: Modules/overlapped.c | 20 +++++++++++--------- 1 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Modules/overlapped.c b/Modules/overlapped.c --- a/Modules/overlapped.c +++ b/Modules/overlapped.c @@ -45,9 +45,9 @@ /* Type of operation */ DWORD type; union { - /* Buffer used for reading (optional) */ + /* Buffer used for reading: TYPE_READ and TYPE_ACCEPT */ PyObject *read_buffer; - /* Buffer used for writing (optional) */ + /* Buffer used for writing: TYPE_WRITE */ Py_buffer write_buffer; }; } OverlappedObject; @@ -568,13 +568,15 @@ if (self->overlapped.hEvent != NULL) CloseHandle(self->overlapped.hEvent); - if (self->write_buffer.obj) - PyBuffer_Release(&self->write_buffer); - switch (self->type) { - case TYPE_READ: - case TYPE_ACCEPT: - Py_CLEAR(self->read_buffer); + case TYPE_READ: + case TYPE_ACCEPT: + Py_CLEAR(self->read_buffer); + break; + case TYPE_WRITE: + if (self->write_buffer.obj) + PyBuffer_Release(&self->write_buffer); + break; } PyObject_Del(self); SetLastError(olderr); @@ -648,7 +650,7 @@ case ERROR_MORE_DATA: break; case ERROR_BROKEN_PIPE: - if (self->read_buffer != NULL) + if ((self->type == TYPE_READ || self->type == TYPE_ACCEPT) && self->read_buffer != NULL) break; /* fall through */ default: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu Jan 30 21:22:54 2014 From: python-checkins at python.org (vinay.sajip) Date: Thu, 30 Jan 2014 21:22:54 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIwNDQ0?= =?utf-8?q?=3A_Reduced_code_duplication=2E_Thanks_to_dongwm_for_the_report?= =?utf-8?q?_and?= Message-ID: <3fFY0G58Byz7LjZ@mail.python.org> http://hg.python.org/cpython/rev/03b399c807d6 changeset: 88838:03b399c807d6 branch: 2.7 parent: 88817:09716a4d6c52 user: Vinay Sajip date: Thu Jan 30 20:22:01 2014 +0000 summary: Issue #20444: Reduced code duplication. Thanks to dongwm for the report and patch. files: Lib/logging/config.py | 88 ++++++++++++------------------ 1 files changed, 36 insertions(+), 52 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-2013 by Vinay Sajip. All Rights Reserved. +# Copyright 2001-2014 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-2013 Vinay Sajip. All Rights Reserved. +Copyright (C) 2001-2014 Vinay Sajip. All Rights Reserved. To use, simply 'import logging' and log away! """ @@ -275,6 +275,30 @@ return True +class ConvertingMixin(object): + """For ConvertingXXX's, this mixin class provides common functions""" + + def convert_with_key(self, key, value, replace=True): + result = self.configurator.convert(value) + #If the converted value is different, save for next time + if value is not result: + if replace: + self[key] = result + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + result.key = key + return result + + def convert(self, value): + result = self.configurator.convert(value) + if value is not result: + if type(result) in (ConvertingDict, ConvertingList, + ConvertingTuple): + result.parent = self + return result + + # The ConvertingXXX classes are wrappers around standard Python containers, # and they serve to convert any suitable values in the container. The # conversion converts base dicts, lists and tuples to their wrapped @@ -284,77 +308,37 @@ # Each wrapper should have a configurator attribute holding the actual # configurator to use for conversion. -class ConvertingDict(dict): +class ConvertingDict(dict, ConvertingMixin): """A converting dictionary wrapper.""" def __getitem__(self, key): value = dict.__getitem__(self, key) - result = self.configurator.convert(value) - #If the converted value is different, save for next time - if value is not result: - self[key] = result - if type(result) in (ConvertingDict, ConvertingList, - ConvertingTuple): - result.parent = self - result.key = key - return result + return self.convert_with_key(key, value) def get(self, key, default=None): value = dict.get(self, key, default) - result = self.configurator.convert(value) - #If the converted value is different, save for next time - if value is not result: - self[key] = result - if type(result) in (ConvertingDict, ConvertingList, - ConvertingTuple): - result.parent = self - result.key = key - return result + return self.convert_with_key(key, value) def pop(self, key, default=None): value = dict.pop(self, key, default) - result = self.configurator.convert(value) - if value is not result: - if type(result) in (ConvertingDict, ConvertingList, - ConvertingTuple): - result.parent = self - result.key = key - return result + return self.convert_with_key(key, value, replace=False) -class ConvertingList(list): +class ConvertingList(list, ConvertingMixin): """A converting list wrapper.""" def __getitem__(self, key): value = list.__getitem__(self, key) - result = self.configurator.convert(value) - #If the converted value is different, save for next time - if value is not result: - self[key] = result - if type(result) in (ConvertingDict, ConvertingList, - ConvertingTuple): - result.parent = self - result.key = key - return result + return self.convert_with_key(key, value) def pop(self, idx=-1): value = list.pop(self, idx) - result = self.configurator.convert(value) - if value is not result: - if type(result) in (ConvertingDict, ConvertingList, - ConvertingTuple): - result.parent = self - return result + return self.convert(value) -class ConvertingTuple(tuple): +class ConvertingTuple(tuple, ConvertingMixin): """A converting tuple wrapper.""" def __getitem__(self, key): value = tuple.__getitem__(self, key) - result = self.configurator.convert(value) - if value is not result: - if type(result) in (ConvertingDict, ConvertingList, - ConvertingTuple): - result.parent = self - result.key = key - return result + # Can't replace a tuple entry. + return self.convert_with_key(key, value, replace=False) class BaseConfigurator(object): """ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 01:02:59 2014 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 31 Jan 2014 01:02:59 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Future=2Eset=5F?= =?utf-8?q?exception=28exc=29_should_instantiate_exc_if_it_is_a_class=2E?= Message-ID: <3fFdtC1Prxz7Lkx@mail.python.org> http://hg.python.org/cpython/rev/354ddb56cc81 changeset: 88839:354ddb56cc81 parent: 88837:73dbb884eb09 user: Victor Stinner date: Thu Jan 30 16:01:54 2014 -0800 summary: asyncio: Future.set_exception(exc) should instantiate exc if it is a class. files: Lib/asyncio/futures.py | 2 ++ Lib/test/test_asyncio/test_futures.py | 5 +++++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -301,6 +301,8 @@ """ if self._state != _PENDING: raise InvalidStateError('{}: {!r}'.format(self._state, self)) + if isinstance(exception, type): + exception = exception() self._exception = exception self._state = _FINISHED self._schedule_callbacks() 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 @@ -79,6 +79,11 @@ self.assertRaises(asyncio.InvalidStateError, f.set_exception, None) self.assertFalse(f.cancel()) + def test_exception_class(self): + f = asyncio.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) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 01:08:21 2014 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 31 Jan 2014 01:08:21 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Fix_granularity?= =?utf-8?q?_of_test=5Futils=2ETestLoop=2E?= Message-ID: <3fFf0P6SRkz7LjQ@mail.python.org> http://hg.python.org/cpython/rev/46c1f0e99ff0 changeset: 88840:46c1f0e99ff0 user: Victor Stinner date: Thu Jan 30 16:05:07 2014 -0800 summary: asyncio: Fix granularity of test_utils.TestLoop. files: Lib/asyncio/test_utils.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) 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 @@ -196,6 +196,7 @@ next(self._gen) self._time = 0 self._timers = [] + self._granularity = 1e-9 self._selector = TestSelector() self.readers = {} -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 01:08:23 2014 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 31 Jan 2014 01:08:23 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Fix_misc_whites?= =?utf-8?q?pace_issues=2E?= Message-ID: <3fFf0R28Vpz7LjZ@mail.python.org> http://hg.python.org/cpython/rev/c30a3a6f3b39 changeset: 88841:c30a3a6f3b39 user: Guido van Rossum date: Thu Jan 30 16:05:28 2014 -0800 summary: asyncio: Fix misc whitespace issues. files: Lib/asyncio/streams.py | 1 + Lib/test/test_asyncio/test_streams.py | 4 +- Lib/test/test_asyncio/test_tasks.py | 23 +++++++------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -14,6 +14,7 @@ _DEFAULT_LIMIT = 2**16 + class IncompleteReadError(EOFError): """ Incomplete read error. Attributes: diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py --- a/Lib/test/test_asyncio/test_streams.py +++ b/Lib/test/test_asyncio/test_streams.py @@ -415,7 +415,7 @@ server = MyServer(self.loop) server.start() msg = self.loop.run_until_complete(asyncio.Task(client(), - loop=self.loop)) + loop=self.loop)) server.stop() self.assertEqual(msg, b"hello world!\n") @@ -423,7 +423,7 @@ server = MyServer(self.loop) server.start_callback() msg = self.loop.run_until_complete(asyncio.Task(client(), - loop=self.loop)) + loop=self.loop)) server.stop() self.assertEqual(msg, b"hello world!\n") 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 @@ -379,7 +379,6 @@ self.assertAlmostEqual(0.1, loop.time()) self.assertEqual(foo_running, False) - def test_wait_for_blocking(self): loop = test_utils.TestLoop() self.addCleanup(loop.close) @@ -388,7 +387,9 @@ def coro(): return 'done' - res = loop.run_until_complete(asyncio.wait_for(coro(), timeout=None, loop=loop)) + res = loop.run_until_complete(asyncio.wait_for(coro(), + timeout=None, + loop=loop)) self.assertEqual(res, 'done') def test_wait_for_with_global_loop(self): @@ -490,7 +491,7 @@ self.assertRaises( ValueError, self.loop.run_until_complete, asyncio.wait([asyncio.sleep(10.0, loop=self.loop)], - return_when=-1, loop=self.loop)) + return_when=-1, loop=self.loop)) def test_wait_first_completed(self): @@ -508,7 +509,7 @@ b = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop) task = asyncio.Task( asyncio.wait([b, a], return_when=asyncio.FIRST_COMPLETED, - loop=loop), + loop=loop), loop=loop) done, pending = loop.run_until_complete(task) @@ -540,7 +541,7 @@ b = asyncio.Task(coro2(), loop=self.loop) task = asyncio.Task( 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) @@ -570,7 +571,7 @@ b = asyncio.Task(exc(), loop=loop) task = asyncio.Task( asyncio.wait([b, a], return_when=asyncio.FIRST_EXCEPTION, - loop=loop), + loop=loop), loop=loop) done, pending = loop.run_until_complete(task) @@ -604,7 +605,7 @@ b = asyncio.Task(exc(), loop=loop) task = asyncio.wait([b, a], return_when=asyncio.FIRST_EXCEPTION, - loop=loop) + loop=loop) done, pending = loop.run_until_complete(task) self.assertEqual({b}, done) @@ -670,7 +671,7 @@ @asyncio.coroutine def foo(): done, pending = yield from asyncio.wait([b, a], timeout=0.11, - loop=loop) + loop=loop) self.assertEqual(done, set([a])) self.assertEqual(pending, set([b])) @@ -874,7 +875,7 @@ self.addCleanup(loop.close) t = asyncio.Task(asyncio.sleep(10.0, 'yeah', loop=loop), - loop=loop) + loop=loop) handle = None orig_call_later = loop.call_later @@ -1156,7 +1157,7 @@ task2 = asyncio.Task(coro2(self.loop), loop=self.loop) self.loop.run_until_complete(asyncio.wait((task1, task2), - loop=self.loop)) + loop=self.loop)) self.assertIsNone(asyncio.Task.current_task(loop=self.loop)) # Some thorough tests for cancellation propagation through @@ -1367,7 +1368,7 @@ def test_return_exceptions(self): a, b, c, d = [asyncio.Future(loop=self.one_loop) for i in range(4)] fut = asyncio.gather(*self.wrap_futures(a, b, c, d), - return_exceptions=True) + return_exceptions=True) cb = Mock() fut.add_done_callback(cb) exc = ZeroDivisionError() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 03:37:46 2014 From: python-checkins at python.org (terry.reedy) Date: Fri, 31 Jan 2014 03:37:46 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSWRsZSB0ZXN0OiAy?= =?utf-8?q?nd_try_at_suppressing_compile_time_warning_=28hint_by_Nick_Cogh?= =?utf-8?b?bGFuKS4=?= Message-ID: <3fFjJp1Phbz7Ljs@mail.python.org> http://hg.python.org/cpython/rev/78a721fa9b67 changeset: 88842:78a721fa9b67 branch: 2.7 parent: 88838:03b399c807d6 user: Terry Jan Reedy date: Thu Jan 30 21:37:24 2014 -0500 summary: Idle test: 2nd try at suppressing compile time warning (hint by Nick Coghlan). files: Lib/idlelib/idle_test/test_calltips.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py --- a/Lib/idlelib/idle_test/test_calltips.py +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -167,7 +167,7 @@ with warnings.catch_warnings(): # Suppess message of py3 deprecation of parameter unpacking warnings.simplefilter("ignore") - def f((a,b), c=0.0): pass + exec "def f((a,b), c=0.0): pass" self.assertEqual(signature(f), '(, c=0.0)') if __name__ == '__main__': -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 09:37:37 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 31 Jan 2014 09:37:37 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320452=3A_add_more?= =?utf-8?q?_info_in_case_of_test=5Fasyncio_failure_to_try_to_debug_the?= Message-ID: <3fFsJ155fSz7LjY@mail.python.org> http://hg.python.org/cpython/rev/5545634d98a1 changeset: 88843:5545634d98a1 parent: 88841:c30a3a6f3b39 user: Victor Stinner date: Fri Jan 31 09:29:35 2014 +0100 summary: Issue #20452: add more info in case of test_asyncio failure to try to debug the failure on buildbot "x86 Ubuntu Shared 3.x" files: Lib/asyncio/base_events.py | 10 +++++++++- Lib/test/test_asyncio/test_events.py | 11 ++++++++++- 2 files changed, 19 insertions(+), 2 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 @@ -620,10 +620,18 @@ timeout = min(timeout, deadline) # TODO: Instrumentation only in debug mode? - if logger.isEnabledFor(logging.INFO): + # FIXME: don't force log (issue #20452) + if True: #logger.isEnabledFor(logging.INFO): t0 = self.time() event_list = self._selector.select(timeout) t1 = self.time() + # FIXME: remove these debug info (issue #20452) + dt = t1-t0 + if dt < timeout and not event_list: + print("WARNING: selector.select(timeout=%.20f) took dt=%.20f sec (dt-timeout=%+.20f)" + % (timeout, dt, dt-timeout), file=sys.__stdout__) + print("WARNING: dt+%.20f > timeout? %s" + % (self._granularity, (dt + self._granularity) > timeout), file=sys.__stdout__) if t1-t0 >= 1: level = logging.INFO else: 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 @@ -1157,6 +1157,10 @@ w.close() def test_timeout_rounding(self): + # FIXME: remove this imports, used for debug purpose (issue #20452) + import time + import platform + def _run_once(): self.loop._run_once_counter += 1 orig_run_once() @@ -1177,7 +1181,12 @@ self.loop.run_until_complete(wait()) calls.append(self.loop._run_once_counter) - self.assertEqual(calls, [1, 3, 5, 6]) + self.assertEqual(calls, [1, 3, 5, 6], + # FIXME: remove these info, used for debug purpose (issue #20452) + (self.loop._granularity, + self.loop._selector.resolution, + time.get_clock_info('monotonic'), + platform.platform())) class SubprocessTestsMixin: -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri Jan 31 09:43:04 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 31 Jan 2014 09:43:04 +0100 Subject: [Python-checkins] Daily reference leaks (c30a3a6f3b39): sum=-4 Message-ID: results for c30a3a6f3b39 on branch "default" -------------------------------------------- test_site leaked [-2, 2, -2] references, sum=-2 test_site leaked [-2, 2, -2] memory blocks, sum=-2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog2EW4tT', '-x'] From python-checkins at python.org Fri Jan 31 10:58:50 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 31 Jan 2014 10:58:50 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320452=3A_Oops=2C_?= =?utf-8?q?fix_debug_code_=3A-/?= Message-ID: <3fFv5k1K9Bz7LjW@mail.python.org> http://hg.python.org/cpython/rev/83e110399f3c changeset: 88844:83e110399f3c user: Victor Stinner date: Fri Jan 31 10:55:55 2014 +0100 summary: Issue #20452: Oops, fix debug code :-/ Add also event more debug info files: Lib/asyncio/base_events.py | 15 ++++++++++----- Lib/test/test_asyncio/test_events.py | 6 ++++++ 2 files changed, 16 insertions(+), 5 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 @@ -627,11 +627,16 @@ t1 = self.time() # FIXME: remove these debug info (issue #20452) dt = t1-t0 - if dt < timeout and not event_list: - print("WARNING: selector.select(timeout=%.20f) took dt=%.20f sec (dt-timeout=%+.20f)" - % (timeout, dt, dt-timeout), file=sys.__stdout__) - print("WARNING: dt+%.20f > timeout? %s" - % (self._granularity, (dt + self._granularity) > timeout), file=sys.__stdout__) + if timeout is not None: + if dt < timeout and not event_list: + print("WARNING: selector.select(timeout=%.20f) took dt=%.20f sec (dt-timeout=%+.20f)" + % (timeout, dt, dt-timeout), file=sys.__stdout__) + print("WARNING: dt+%.20f > timeout? %s" + % (self._granularity, (dt + self._granularity) > timeout), file=sys.__stdout__) + else: + if not event_list: + print("WARNING: selector.select(timeout=%r) took dt=%.20f sec" + % (timeout, dt), file=sys.__stdout__) if t1-t0 >= 1: level = logging.INFO else: 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 @@ -1160,6 +1160,7 @@ # FIXME: remove this imports, used for debug purpose (issue #20452) import time import platform + import os def _run_once(): self.loop._run_once_counter += 1 @@ -1181,11 +1182,16 @@ self.loop.run_until_complete(wait()) calls.append(self.loop._run_once_counter) + try: + SC_CLK_TCK = os.sysconf('SC_CLK_TCK') + except Exception: + SC_CLK_TCK = None self.assertEqual(calls, [1, 3, 5, 6], # FIXME: remove these info, used for debug purpose (issue #20452) (self.loop._granularity, self.loop._selector.resolution, time.get_clock_info('monotonic'), + SC_CLK_TCK, platform.platform())) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 12:19:25 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 31 Jan 2014 12:19:25 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320452=3A_select_a?= =?utf-8?q?nd_selectors_round_=28again=29_timeout_away_from_zero_for?= Message-ID: <3fFwtj2DlVzNhG@mail.python.org> http://hg.python.org/cpython/rev/827d948ac6aa changeset: 88845:827d948ac6aa user: Victor Stinner date: Fri Jan 31 12:12:53 2014 +0100 summary: Issue #20452: select and selectors round (again) timeout away from zero for poll and epoll Improve also debug info to analyze the issue files: Lib/asyncio/base_events.py | 15 +++------ Lib/selectors.py | 10 +++++- Lib/test/test_asyncio/test_events.py | 23 ++++++--------- Modules/selectmodule.c | 4 ++- 4 files changed, 26 insertions(+), 26 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 @@ -627,16 +627,11 @@ t1 = self.time() # FIXME: remove these debug info (issue #20452) dt = t1-t0 - if timeout is not None: - if dt < timeout and not event_list: - print("WARNING: selector.select(timeout=%.20f) took dt=%.20f sec (dt-timeout=%+.20f)" - % (timeout, dt, dt-timeout), file=sys.__stdout__) - print("WARNING: dt+%.20f > timeout? %s" - % (self._granularity, (dt + self._granularity) > timeout), file=sys.__stdout__) - else: - if not event_list: - print("WARNING: selector.select(timeout=%r) took dt=%.20f sec" - % (timeout, dt), file=sys.__stdout__) + if timeout is not None and dt < timeout and not event_list: + print("WARNING: selector.select(timeout=%.20f) took dt=%.20f sec (dt-timeout=%+.20f)" + % (timeout, dt, dt-timeout), file=sys.__stdout__) + print("WARNING: dt+%.20f > timeout? %s" + % (self._granularity, (dt + self._granularity) > timeout), file=sys.__stdout__) if t1-t0 >= 1: level = logging.INFO else: diff --git a/Lib/selectors.py b/Lib/selectors.py --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -8,6 +8,7 @@ from abc import ABCMeta, abstractmethod, abstractproperty from collections import namedtuple, Mapping import functools +import math import select import sys @@ -369,8 +370,9 @@ elif timeout <= 0: timeout = 0 else: - # Round towards zero - timeout = int(timeout * 1000) + # poll() has a resolution of 1 millisecond, round away from + # zero to wait *at least* timeout seconds. + timeout = int(math.ceil(timeout * 1e3)) ready = [] try: fd_event_list = self._poll.poll(timeout) @@ -430,6 +432,10 @@ timeout = -1 elif timeout <= 0: timeout = 0 + else: + # epoll_wait() has a resolution of 1 millisecond, round away + # from zero to wait *at least* timeout seconds. + timeout = math.ceil(timeout * 1e3) * 1e-3 max_ev = len(self._fd_to_key) ready = [] try: 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 @@ -28,6 +28,15 @@ from asyncio import selector_events from asyncio import test_utils +# FIXME: remove these info, used for debug purpose (issue #20452) +print("time.monotonic() info: %r" % (time.get_clock_info('monotonic'),)) +try: + SC_CLK_TCK = os.sysconf('SC_CLK_TCK') + print("os.sysconf('SC_CLK_TCK') = %s" % SC_CLK_TCK) +except Exception: + pass +# FIXME: remove these info, used for debug purpose (issue #20452) + def data_file(filename): if hasattr(support, 'TEST_HOME_DIR'): @@ -1157,11 +1166,6 @@ w.close() def test_timeout_rounding(self): - # FIXME: remove this imports, used for debug purpose (issue #20452) - import time - import platform - import os - def _run_once(): self.loop._run_once_counter += 1 orig_run_once() @@ -1182,17 +1186,10 @@ self.loop.run_until_complete(wait()) calls.append(self.loop._run_once_counter) - try: - SC_CLK_TCK = os.sysconf('SC_CLK_TCK') - except Exception: - SC_CLK_TCK = None self.assertEqual(calls, [1, 3, 5, 6], # FIXME: remove these info, used for debug purpose (issue #20452) (self.loop._granularity, - self.loop._selector.resolution, - time.get_clock_info('monotonic'), - SC_CLK_TCK, - platform.platform())) + self.loop._selector.resolution)) class SubprocessTestsMixin: diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -1458,7 +1458,9 @@ return NULL; } else { - timeout = (int)(dtimeout * 1000.0); + /* epoll_wait() has a resolution of 1 millisecond, round away from zero + to wait *at least* dtimeout seconds. */ + timeout = (int)ceil(dtimeout * 1000.0); } if (maxevents == -1) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 12:29:12 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 31 Jan 2014 12:29:12 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Fix_error_messa?= =?utf-8?q?ge_in_BaseEventLoop=2Esubprocess=5Fshell=28=29=2E_Patch_written?= Message-ID: <3fFx6004BzzRlj@mail.python.org> http://hg.python.org/cpython/rev/1b09dcd39f76 changeset: 88846:1b09dcd39f76 user: Victor Stinner date: Fri Jan 31 12:28:30 2014 +0100 summary: asyncio: Fix error message in BaseEventLoop.subprocess_shell(). Patch written by Vajrasky Kok. files: Lib/asyncio/base_events.py | 2 +- 1 files changed, 1 insertions(+), 1 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 @@ -557,7 +557,7 @@ if universal_newlines: raise ValueError("universal_newlines must be False") if not shell: - raise ValueError("shell must be False") + raise ValueError("shell must be True") if bufsize != 0: raise ValueError("bufsize must be 0") protocol = protocol_factory() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 13:05:00 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 31 Jan 2014 13:05:00 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320452=3A_Remove_d?= =?utf-8?q?ebug_code=2C_no_more_needed?= Message-ID: <3fFxvJ2LF1z7LkK@mail.python.org> http://hg.python.org/cpython/rev/21aa1a224049 changeset: 88847:21aa1a224049 user: Victor Stinner date: Fri Jan 31 12:59:43 2014 +0100 summary: Issue #20452: Remove debug code, no more needed files: Lib/asyncio/base_events.py | 10 +--------- Lib/test/test_asyncio/test_events.py | 14 +------------- 2 files changed, 2 insertions(+), 22 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 @@ -620,18 +620,10 @@ timeout = min(timeout, deadline) # TODO: Instrumentation only in debug mode? - # FIXME: don't force log (issue #20452) - if True: #logger.isEnabledFor(logging.INFO): + if logger.isEnabledFor(logging.INFO): t0 = self.time() event_list = self._selector.select(timeout) t1 = self.time() - # FIXME: remove these debug info (issue #20452) - dt = t1-t0 - if timeout is not None and dt < timeout and not event_list: - print("WARNING: selector.select(timeout=%.20f) took dt=%.20f sec (dt-timeout=%+.20f)" - % (timeout, dt, dt-timeout), file=sys.__stdout__) - print("WARNING: dt+%.20f > timeout? %s" - % (self._granularity, (dt + self._granularity) > timeout), file=sys.__stdout__) if t1-t0 >= 1: level = logging.INFO else: 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 @@ -28,15 +28,6 @@ from asyncio import selector_events from asyncio import test_utils -# FIXME: remove these info, used for debug purpose (issue #20452) -print("time.monotonic() info: %r" % (time.get_clock_info('monotonic'),)) -try: - SC_CLK_TCK = os.sysconf('SC_CLK_TCK') - print("os.sysconf('SC_CLK_TCK') = %s" % SC_CLK_TCK) -except Exception: - pass -# FIXME: remove these info, used for debug purpose (issue #20452) - def data_file(filename): if hasattr(support, 'TEST_HOME_DIR'): @@ -1186,10 +1177,7 @@ self.loop.run_until_complete(wait()) calls.append(self.loop._run_once_counter) - self.assertEqual(calls, [1, 3, 5, 6], - # FIXME: remove these info, used for debug purpose (issue #20452) - (self.loop._granularity, - self.loop._selector.resolution)) + self.assertEqual(calls, [1, 3, 5, 6]) class SubprocessTestsMixin: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 13:05:01 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 31 Jan 2014 13:05:01 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320311=2C_=2320452?= =?utf-8?q?=3A_poll_and_epoll_now_round_the_timeout_away_from_zero=2C?= Message-ID: <3fFxvK47gCz7LkK@mail.python.org> http://hg.python.org/cpython/rev/f9a09b40bc17 changeset: 88848:f9a09b40bc17 user: Victor Stinner date: Fri Jan 31 13:02:44 2014 +0100 summary: Issue #20311, #20452: poll and epoll now round the timeout away from zero, instead of rounding towards zero, in select and selectors modules: select.epoll.poll(), selectors.PollSelector.poll() and selectors.EpollSelector.poll(). For example, a timeout of one microsecond (1e-6) is now rounded to one millisecondi (1e-3), instead of being rounded to zero. Mention the change in Misc/NEWS. files: Misc/NEWS | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,13 @@ Library ------- +- Issue #20311, #20452: poll and epoll now round the timeout away from zero, + instead of rounding towards zero, in select and selectors modules: + select.epoll.poll(), selectors.PollSelector.poll() and + selectors.EpollSelector.poll(). For example, a timeout of one microsecond + (1e-6) is now rounded to one millisecondi (1e-3), instead of being rounded to + zero. + - asyncio: Some refactoring; add write flow control to unix pipes; support wait_for(f, None); don't log broken/disconnected pipes; use ValueError instead of assert for forbidden subprocess_{shell,exec} -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 13:05:02 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 31 Jan 2014 13:05:02 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_asyncio=3A_Fix_=5FUnixWrit?= =?utf-8?q?ePipeTransport=2C_raise_BrokenPipeError_when_the_pipe_is?= Message-ID: <3fFxvL5VYTz7LkH@mail.python.org> http://hg.python.org/cpython/rev/b743d709b93b changeset: 88849:b743d709b93b user: Victor Stinner date: Fri Jan 31 13:04:28 2014 +0100 summary: asyncio: Fix _UnixWritePipeTransport, raise BrokenPipeError when the pipe is closed, but only if there was pending write files: Lib/asyncio/unix_events.py | 5 ++++- 1 files changed, 4 insertions(+), 1 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 @@ -283,7 +283,10 @@ def _read_ready(self): # Pipe was closed by peer. - self._close() + if self._buffer: + self._close(BrokenPipeError()) + else: + self._close() def write(self, data): assert isinstance(data, (bytes, bytearray, memoryview)), repr(data) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 14:18:55 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 31 Jan 2014 14:18:55 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320455=3A_asyncio?= =?utf-8?q?=3A_write_a_new_write_pipe_transport_class_for_proactor_=28on?= Message-ID: <3fFzXb3HBkz7Lk2@mail.python.org> http://hg.python.org/cpython/rev/4c496d53b1e1 changeset: 88850:4c496d53b1e1 user: Victor Stinner date: Fri Jan 31 14:18:18 2014 +0100 summary: Issue #20455: asyncio: write a new write pipe transport class for proactor (on Windows) instead of using the "duplex" pipe transport. The new class uses a simpler overlapped read to be notified when the pipe is closed. So the protocol doesn't need to implement eof_received(): connection_lost() is called instead. _UnixWritePipeTransport has the same approach. files: Lib/asyncio/proactor_events.py | 38 +++++++++++++++------ 1 files changed, 26 insertions(+), 12 deletions(-) diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -205,7 +205,7 @@ self.close() -class _ProactorWritePipeTransport(_ProactorBasePipeTransport, +class _ProactorBaseWritePipeTransport(_ProactorBasePipeTransport, transports.WriteTransport): """Transport for write pipes.""" @@ -286,8 +286,27 @@ self._force_close(None) +class _ProactorWritePipeTransport(_ProactorBaseWritePipeTransport): + def __init__(self, *args, **kw): + super().__init__(*args, **kw) + self._read_fut = self._loop._proactor.recv(self._sock, 16) + self._read_fut.add_done_callback(self._pipe_closed) + + def _pipe_closed(self, fut): + if fut.cancelled(): + # the transport has been closed + return + assert fut is self._read_fut, (fut, self._read_fut) + self._read_fut = None + assert fut.result() == b'' + if self._write_fut is not None: + self._force_close(exc) + else: + self.close() + + class _ProactorDuplexPipeTransport(_ProactorReadPipeTransport, - _ProactorWritePipeTransport, + _ProactorBaseWritePipeTransport, transports.Transport): """Transport for duplex pipes.""" @@ -299,7 +318,7 @@ class _ProactorSocketTransport(_ProactorReadPipeTransport, - _ProactorWritePipeTransport, + _ProactorBaseWritePipeTransport, transports.Transport): """Transport for connected sockets.""" @@ -353,15 +372,10 @@ return _ProactorReadPipeTransport(self, sock, protocol, waiter, extra) def _make_write_pipe_transport(self, sock, protocol, waiter=None, - extra=None, check_for_hangup=True): - if check_for_hangup: - # We want connection_lost() to be called when other end closes - return _ProactorDuplexPipeTransport(self, - sock, protocol, waiter, extra) - else: - # If other end closes we may not notice for a long time - return _ProactorWritePipeTransport(self, sock, protocol, waiter, - extra) + extra=None): + # We want connection_lost() to be called when other end closes + return _ProactorWritePipeTransport(self, + sock, protocol, waiter, extra) def close(self): if self._proactor is not None: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 14:59:59 2014 From: python-checkins at python.org (larry.hastings) Date: Fri, 31 Jan 2014 14:59:59 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320390=3A_Removing?= =?utf-8?q?_detritus_from_Argument_Clinic_=22file_preset=22_name_change=2E?= Message-ID: <3fG0Rz39fMz7LjS@mail.python.org> http://hg.python.org/cpython/rev/06b4fbb09c93 changeset: 88851:06b4fbb09c93 user: Larry Hastings date: Fri Jan 31 05:59:48 2014 -0800 summary: Issue #20390: Removing detritus from Argument Clinic "file preset" name change. files: Modules/_lzmamodule.clinic.c | 231 ----------------------- 1 files changed, 0 insertions(+), 231 deletions(-) diff --git a/Modules/_lzmamodule.clinic.c b/Modules/_lzmamodule.clinic.c deleted file mode 100644 --- a/Modules/_lzmamodule.clinic.c +++ /dev/null @@ -1,231 +0,0 @@ -/*[clinic input] -preserve -[clinic start generated code]*/ - -PyDoc_STRVAR(_lzma_LZMACompressor_compress__doc__, -"compress(self, data)\n" -"Provide data to the compressor object.\n" -"\n" -"Returns a chunk of compressed data if possible, or b\'\' otherwise.\n" -"\n" -"When you have finished providing data to the compressor, call the\n" -"flush() method to finish the compression process."); - -#define _LZMA_LZMACOMPRESSOR_COMPRESS_METHODDEF \ - {"compress", (PyCFunction)_lzma_LZMACompressor_compress, METH_VARARGS, _lzma_LZMACompressor_compress__doc__}, - -static PyObject * -_lzma_LZMACompressor_compress_impl(Compressor *self, Py_buffer *data); - -static PyObject * -_lzma_LZMACompressor_compress(Compressor *self, PyObject *args) -{ - PyObject *return_value = NULL; - Py_buffer data = {NULL, NULL}; - - if (!PyArg_ParseTuple(args, - "y*:compress", - &data)) - goto exit; - return_value = _lzma_LZMACompressor_compress_impl(self, &data); - -exit: - /* Cleanup for data */ - if (data.obj) - PyBuffer_Release(&data); - - return return_value; -} - -PyDoc_STRVAR(_lzma_LZMACompressor_flush__doc__, -"flush(self)\n" -"Finish the compression process.\n" -"\n" -"Returns the compressed data left in internal buffers.\n" -"\n" -"The compressor object may not be used after this method is called."); - -#define _LZMA_LZMACOMPRESSOR_FLUSH_METHODDEF \ - {"flush", (PyCFunction)_lzma_LZMACompressor_flush, METH_NOARGS, _lzma_LZMACompressor_flush__doc__}, - -static PyObject * -_lzma_LZMACompressor_flush_impl(Compressor *self); - -static PyObject * -_lzma_LZMACompressor_flush(Compressor *self, PyObject *Py_UNUSED(ignored)) -{ - return _lzma_LZMACompressor_flush_impl(self); -} - -PyDoc_STRVAR(_lzma_LZMADecompressor_decompress__doc__, -"decompress(self, data)\n" -"Provide data to the decompressor object.\n" -"\n" -"Returns a chunk of decompressed data if possible, or b\'\' otherwise.\n" -"\n" -"Attempting to decompress data after the end of stream is reached\n" -"raises an EOFError. Any data found after the end of the stream\n" -"is ignored and saved in the unused_data attribute."); - -#define _LZMA_LZMADECOMPRESSOR_DECOMPRESS_METHODDEF \ - {"decompress", (PyCFunction)_lzma_LZMADecompressor_decompress, METH_VARARGS, _lzma_LZMADecompressor_decompress__doc__}, - -static PyObject * -_lzma_LZMADecompressor_decompress_impl(Decompressor *self, Py_buffer *data); - -static PyObject * -_lzma_LZMADecompressor_decompress(Decompressor *self, PyObject *args) -{ - PyObject *return_value = NULL; - Py_buffer data = {NULL, NULL}; - - if (!PyArg_ParseTuple(args, - "y*:decompress", - &data)) - goto exit; - return_value = _lzma_LZMADecompressor_decompress_impl(self, &data); - -exit: - /* Cleanup for data */ - if (data.obj) - PyBuffer_Release(&data); - - return return_value; -} - -PyDoc_STRVAR(_lzma_LZMADecompressor___init____doc__, -"LZMADecompressor(format=FORMAT_AUTO, memlimit=None, filters=None)\n" -"Create a decompressor object for decompressing data incrementally.\n" -"\n" -" format\n" -" Specifies the container format of the input stream. If this is\n" -" FORMAT_AUTO (the default), the decompressor will automatically detect\n" -" whether the input is FORMAT_XZ or FORMAT_ALONE. Streams created with\n" -" FORMAT_RAW cannot be autodetected.\n" -" memlimit\n" -" Limit the amount of memory used by the decompressor. This will cause\n" -" decompression to fail if the input cannot be decompressed within the\n" -" given limit.\n" -" filters\n" -" A custom filter chain. This argument is required for FORMAT_RAW, and\n" -" not accepted with any other format. When provided, this should be a\n" -" sequence of dicts, each indicating the ID and options for a single\n" -" filter.\n" -"\n" -"For one-shot decompression, use the decompress() function instead."); - -static int -_lzma_LZMADecompressor___init___impl(Decompressor *self, int format, PyObject *memlimit, PyObject *filters); - -static int -_lzma_LZMADecompressor___init__(PyObject *self, PyObject *args, PyObject *kwargs) -{ - int return_value = -1; - static char *_keywords[] = {"format", "memlimit", "filters", NULL}; - int format = FORMAT_AUTO; - PyObject *memlimit = Py_None; - PyObject *filters = Py_None; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "|iOO:LZMADecompressor", _keywords, - &format, &memlimit, &filters)) - goto exit; - return_value = _lzma_LZMADecompressor___init___impl((Decompressor *)self, format, memlimit, filters); - -exit: - return return_value; -} - -PyDoc_STRVAR(_lzma_is_check_supported__doc__, -"is_check_supported(module, check_id)\n" -"Test whether the given integrity check is supported.\n" -"\n" -"Always returns True for CHECK_NONE and CHECK_CRC32."); - -#define _LZMA_IS_CHECK_SUPPORTED_METHODDEF \ - {"is_check_supported", (PyCFunction)_lzma_is_check_supported, METH_VARARGS, _lzma_is_check_supported__doc__}, - -static PyObject * -_lzma_is_check_supported_impl(PyModuleDef *module, int check_id); - -static PyObject * -_lzma_is_check_supported(PyModuleDef *module, PyObject *args) -{ - PyObject *return_value = NULL; - int check_id; - - if (!PyArg_ParseTuple(args, - "i:is_check_supported", - &check_id)) - goto exit; - return_value = _lzma_is_check_supported_impl(module, check_id); - -exit: - return return_value; -} - -PyDoc_STRVAR(_lzma__encode_filter_properties__doc__, -"_encode_filter_properties(module, filter)\n" -"Return a bytes object encoding the options (properties) of the filter specified by *filter* (a dict).\n" -"\n" -"The result does not include the filter ID itself, only the options."); - -#define _LZMA__ENCODE_FILTER_PROPERTIES_METHODDEF \ - {"_encode_filter_properties", (PyCFunction)_lzma__encode_filter_properties, METH_VARARGS, _lzma__encode_filter_properties__doc__}, - -static PyObject * -_lzma__encode_filter_properties_impl(PyModuleDef *module, lzma_filter filter); - -static PyObject * -_lzma__encode_filter_properties(PyModuleDef *module, PyObject *args) -{ - PyObject *return_value = NULL; - lzma_filter filter = {LZMA_VLI_UNKNOWN, NULL}; - - if (!PyArg_ParseTuple(args, - "O&:_encode_filter_properties", - lzma_filter_converter, &filter)) - goto exit; - return_value = _lzma__encode_filter_properties_impl(module, filter); - -exit: - /* Cleanup for filter */ - if (filter.id != LZMA_VLI_UNKNOWN) - PyMem_Free(filter.options); - - return return_value; -} - -PyDoc_STRVAR(_lzma__decode_filter_properties__doc__, -"_decode_filter_properties(module, filter_id, encoded_props)\n" -"Return a bytes object encoding the options (properties) of the filter specified by *filter* (a dict).\n" -"\n" -"The result does not include the filter ID itself, only the options."); - -#define _LZMA__DECODE_FILTER_PROPERTIES_METHODDEF \ - {"_decode_filter_properties", (PyCFunction)_lzma__decode_filter_properties, METH_VARARGS, _lzma__decode_filter_properties__doc__}, - -static PyObject * -_lzma__decode_filter_properties_impl(PyModuleDef *module, lzma_vli filter_id, Py_buffer *encoded_props); - -static PyObject * -_lzma__decode_filter_properties(PyModuleDef *module, PyObject *args) -{ - PyObject *return_value = NULL; - lzma_vli filter_id; - Py_buffer encoded_props = {NULL, NULL}; - - if (!PyArg_ParseTuple(args, - "O&y*:_decode_filter_properties", - lzma_vli_converter, &filter_id, &encoded_props)) - goto exit; - return_value = _lzma__decode_filter_properties_impl(module, filter_id, &encoded_props); - -exit: - /* Cleanup for encoded_props */ - if (encoded_props.obj) - PyBuffer_Release(&encoded_props); - - return return_value; -} -/*[clinic end generated code: output=b4b90dcbd0c9c349 input=a9049054013a1b77]*/ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 16:08:17 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 31 Jan 2014 16:08:17 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Windows_buildbot=3A_use_--?= =?utf-8?q?timeout_feature_in_Tools/buildbot/test=2Ebat?= Message-ID: <3fG1yn69Dnz7Lkb@mail.python.org> http://hg.python.org/cpython/rev/9a3e60b74cc7 changeset: 88852:9a3e60b74cc7 user: Victor Stinner date: Fri Jan 31 16:07:32 2014 +0100 summary: Windows buildbot: use --timeout feature in Tools/buildbot/test.bat Use the same default timeout than Makefile: 1 hour (3600 seconds). files: Tools/buildbot/test.bat | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Tools/buildbot/test.bat b/Tools/buildbot/test.bat --- a/Tools/buildbot/test.bat +++ b/Tools/buildbot/test.bat @@ -1,3 +1,3 @@ @rem Used by the buildbot "test" step. cd PCbuild -call rt.bat -d -q -uall -rwW -n %1 %2 %3 %4 %5 %6 %7 %8 %9 +call rt.bat -d -q -uall -rwW -n --timeout=3600 %1 %2 %3 %4 %5 %6 %7 %8 %9 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 16:28:06 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 31 Jan 2014 16:28:06 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320455=3A_math=2Ec?= =?utf-8?q?eil=28=29_returns_an_int_in_Python_3=2C_no_need_to_cast_the?= Message-ID: <3fG2Pf3yTjz7Lk2@mail.python.org> http://hg.python.org/cpython/rev/8fc69d43bc49 changeset: 88853:8fc69d43bc49 user: Victor Stinner date: Fri Jan 31 16:24:21 2014 +0100 summary: Issue #20455: math.ceil() returns an int in Python 3, no need to cast the result again to int files: Lib/selectors.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/selectors.py b/Lib/selectors.py --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -372,7 +372,7 @@ else: # poll() has a resolution of 1 millisecond, round away from # zero to wait *at least* timeout seconds. - timeout = int(math.ceil(timeout * 1e3)) + timeout = math.ceil(timeout * 1e3) ready = [] try: fd_event_list = self._poll.poll(timeout) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 16:28:07 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 31 Jan 2014 16:28:07 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320455=3A_asyncio?= =?utf-8?q?=3A_use_the_same_code_to_round_a_timeout_than_the_selectors?= Message-ID: <3fG2Pg5wSxz7Lkb@mail.python.org> http://hg.python.org/cpython/rev/3f54bc5392c3 changeset: 88854:3f54bc5392c3 user: Victor Stinner date: Fri Jan 31 16:25:24 2014 +0100 summary: Issue #20455: asyncio: use the same code to round a timeout than the selectors module Sort also imports files: Lib/asyncio/windows_events.py | 13 +++++++++---- 1 files changed, 9 insertions(+), 4 deletions(-) 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 @@ -1,11 +1,12 @@ """Selector and proactor eventloops for Windows.""" +import _winapi import errno +import math import socket +import struct import subprocess import weakref -import struct -import _winapi from . import events from . import base_subprocess @@ -325,7 +326,9 @@ if timeout is None: ms = _winapi.INFINITE else: - ms = int(timeout * 1000 + 0.5) + # RegisterWaitForSingleObject() has a resolution of 1 millisecond, + # round away from zero to wait *at least* timeout seconds. + ms = math.ceil(timeout * 1e3) # We only create ov so we can use ov.address as a key for the cache. ov = _overlapped.Overlapped(NULL) @@ -396,7 +399,9 @@ elif timeout < 0: raise ValueError("negative timeout") else: - ms = int(timeout * 1000 + 0.5) + # GetQueuedCompletionStatus() has a resolution of 1 millisecond, + # round away from zero to wait *at least* timeout seconds. + ms = math.ceil(timeout * 1e3) if ms >= INFINITE: raise ValueError("timeout too big") while True: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 16:28:09 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 31 Jan 2014 16:28:09 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320455=3A_Add_a_re?= =?utf-8?q?solution_attribute_to_IocpProactor_=281_ms=29?= Message-ID: <3fG2Pj15VJz7Lkj@mail.python.org> http://hg.python.org/cpython/rev/55abd847c9f5 changeset: 88855:55abd847c9f5 user: Victor Stinner date: Fri Jan 31 16:26:38 2014 +0100 summary: Issue #20455: Add a resolution attribute to IocpProactor (1 ms) files: Lib/asyncio/proactor_events.py | 1 + Lib/asyncio/windows_events.py | 1 + Lib/test/test_asyncio/test_proactor_events.py | 2 ++ 3 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -354,6 +354,7 @@ self._selector = proactor # convenient alias self._self_reading_future = None self._accept_futures = {} # socket file descriptor => Future + self._granularity = max(proactor.resolution, self._granularity) proactor.set_loop(self) self._make_self_pipe() 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 @@ -191,6 +191,7 @@ self._cache = {} self._registered = weakref.WeakSet() self._stopped_serving = weakref.WeakSet() + self.resolution = 1e-3 def set_loop(self, loop): self._loop = loop diff --git a/Lib/test/test_asyncio/test_proactor_events.py b/Lib/test/test_asyncio/test_proactor_events.py --- a/Lib/test/test_asyncio/test_proactor_events.py +++ b/Lib/test/test_asyncio/test_proactor_events.py @@ -17,6 +17,7 @@ def setUp(self): self.loop = test_utils.TestLoop() self.proactor = unittest.mock.Mock() + self.proactor.resolution = 1e-3 self.loop._proactor = self.proactor self.protocol = test_utils.make_test_protocol(asyncio.Protocol) self.sock = unittest.mock.Mock(socket.socket) @@ -342,6 +343,7 @@ def setUp(self): self.sock = unittest.mock.Mock(socket.socket) self.proactor = unittest.mock.Mock() + self.proactor.resolution = 1e-3 self.ssock, self.csock = unittest.mock.Mock(), unittest.mock.Mock() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 16:50:00 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 31 Jan 2014 16:50:00 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320452=3A_test=5Fa?= =?utf-8?q?syncio=3A_Add_more_info_if_the_test_fails?= Message-ID: <3fG2tw69xgz7LjS@mail.python.org> http://hg.python.org/cpython/rev/7f649ff0756c changeset: 88856:7f649ff0756c user: Victor Stinner date: Fri Jan 31 16:39:10 2014 +0100 summary: Issue #20452: test_asyncio: Add more info if the test fails files: Lib/test/test_asyncio/test_base_events.py | 9 +++++++-- 1 files changed, 7 insertions(+), 2 deletions(-) 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 @@ -120,8 +120,13 @@ self.loop.call_at(when, cb) t0 = self.loop.time() self.loop.run_forever() - t1 = self.loop.time() - self.assertTrue(0.09 <= t1-t0 <= 0.9, t1-t0) + dt = self.loop.time() - t0 + self.assertTrue(0.09 <= dt <= 0.9, + # Issue #20452: add more info in case of failure, + # to try to investigate the bug + (dt, + self.loop._granularity, + time.get_clock_info('monotonic'))) def test_run_once_in_executor_handle(self): def cb(): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 18:04:44 2014 From: python-checkins at python.org (brett.cannon) Date: Fri, 31 Jan 2014 18:04:44 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_The_function_name_for_cmat?= =?utf-8?q?h=2Eisinf_in_PyArg=5FParseTuple=28=29_was_wrong=2E?= Message-ID: <3fG4Y86pgBz7LkH@mail.python.org> http://hg.python.org/cpython/rev/4e30f327164a changeset: 88857:4e30f327164a user: Brett Cannon date: Fri Jan 31 12:04:36 2014 -0500 summary: The function name for cmath.isinf in PyArg_ParseTuple() was wrong. files: Misc/NEWS | 2 ++ Modules/cmathmodule.c | 2 +- 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,8 @@ Library ------- +- Fixed cmath.isinf's name in its argument parsing code. + - Issue #20311, #20452: poll and epoll now round the timeout away from zero, instead of rounding towards zero, in select and selectors modules: select.epoll.poll(), selectors.PollSelector.poll() and diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -1060,7 +1060,7 @@ cmath_isinf(PyObject *self, PyObject *args) { Py_complex z; - if (!PyArg_ParseTuple(args, "D:isnan", &z)) + if (!PyArg_ParseTuple(args, "D:isinf", &z)) return NULL; return PyBool_FromLong(Py_IS_INFINITY(z.real) || Py_IS_INFINITY(z.imag)); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 18:18:09 2014 From: python-checkins at python.org (andrew.kuchling) Date: Fri, 31 Jan 2014 18:18:09 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Typo_fix?= Message-ID: <3fG4rd57zRz7LjM@mail.python.org> http://hg.python.org/cpython/rev/ffe73a516208 changeset: 88858:ffe73a516208 user: Andrew Kuchling date: Fri Jan 31 12:17:53 2014 -0500 summary: Typo fix files: Doc/whatsnew/3.4.rst | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) 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 @@ -678,7 +678,7 @@ functools --------- -The new :func:`~functools.partialmethod` descriptor bring partial argument +The new :func:`~functools.partialmethod` descriptor brings partial argument application to descriptors, just as :func:`~functools.partial` provides for normal callables. The new descriptor also makes it easier to get arbitrary callables (including :func:`~functools.partial` instances) @@ -1624,4 +1624,3 @@ * The ``f_tstate`` (thread state) field of the :c:type:`PyFrameObject` structure has been removed to fix a bug: see :issue:`14432` for the rationale. - -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 18:31:31 2014 From: python-checkins at python.org (zach.ware) Date: Fri, 31 Jan 2014 18:31:31 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fix_unfinished?= =?utf-8?q?_thought_in_xml_overview_page=2E__Suggested_by_Bo_Bayles_on_doc?= =?utf-8?b?c0Au?= Message-ID: <3fG5832ntGz7LlD@mail.python.org> http://hg.python.org/cpython/rev/ea1f2f1f84a7 changeset: 88859:ea1f2f1f84a7 branch: 2.7 parent: 88842:78a721fa9b67 user: Zachary Ware date: Fri Jan 31 11:27:24 2014 -0600 summary: Fix unfinished thought in xml overview page. Suggested by Bo Bayles on docs at . files: Doc/library/xml.rst | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Doc/library/xml.rst b/Doc/library/xml.rst --- a/Doc/library/xml.rst +++ b/Doc/library/xml.rst @@ -28,6 +28,7 @@ The XML handling submodules are: * :mod:`xml.etree.ElementTree`: the ElementTree API, a simple and lightweight + XML processor .. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 18:31:32 2014 From: python-checkins at python.org (zach.ware) Date: Fri, 31 Jan 2014 18:31:32 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Fix_unfinished?= =?utf-8?q?_thought_in_xml_overview_page=2E__Suggested_by_Bo_Bayles_on_doc?= =?utf-8?b?c0Au?= Message-ID: <3fG5845Gzsz7Ll1@mail.python.org> http://hg.python.org/cpython/rev/d080214883aa changeset: 88860:d080214883aa branch: 3.3 parent: 88835:ecb272bae417 user: Zachary Ware date: Fri Jan 31 11:30:36 2014 -0600 summary: Fix unfinished thought in xml overview page. Suggested by Bo Bayles on docs at . files: Doc/library/xml.rst | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Doc/library/xml.rst b/Doc/library/xml.rst --- a/Doc/library/xml.rst +++ b/Doc/library/xml.rst @@ -29,6 +29,7 @@ The XML handling submodules are: * :mod:`xml.etree.ElementTree`: the ElementTree API, a simple and lightweight + XML processor .. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 18:31:34 2014 From: python-checkins at python.org (zach.ware) Date: Fri, 31 Jan 2014 18:31:34 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E3?= Message-ID: <3fG5861CHLz7Ll1@mail.python.org> http://hg.python.org/cpython/rev/681c86da0664 changeset: 88861:681c86da0664 parent: 88858:ffe73a516208 parent: 88860:d080214883aa user: Zachary Ware date: Fri Jan 31 11:31:14 2014 -0600 summary: Merge with 3.3 files: Doc/library/xml.rst | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Doc/library/xml.rst b/Doc/library/xml.rst --- a/Doc/library/xml.rst +++ b/Doc/library/xml.rst @@ -29,6 +29,7 @@ The XML handling submodules are: * :mod:`xml.etree.ElementTree`: the ElementTree API, a simple and lightweight + XML processor .. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 19:07:45 2014 From: python-checkins at python.org (zach.ware) Date: Fri, 31 Jan 2014 19:07:45 +0100 (CET) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzIwNDYw?= =?utf-8?q?=3A_Render_=27bytes=27_as_a_class=2C_not_a_function=2E?= Message-ID: <3fG5xs0j1sz7LkW@mail.python.org> http://hg.python.org/cpython/rev/7a611b7aae38 changeset: 88862:7a611b7aae38 branch: 3.3 parent: 88860:d080214883aa user: Zachary Ware date: Fri Jan 31 12:06:14 2014 -0600 summary: Issue #20460: Render 'bytes' as a class, not a function. Patch by OSAMU NAKAMURA. files: Doc/c-api/arg.rst | 2 +- 1 files changed, 1 insertions(+), 1 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 @@ -513,7 +513,7 @@ ``None`` is returned. ``y`` (:class:`bytes`) [char \*] - This converts a C string to a Python :func:`bytes` object. If the C + This converts a C string to a Python :class:`bytes` object. If the C string pointer is *NULL*, ``None`` is returned. ``y#`` (:class:`bytes`) [char \*, int] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 19:07:46 2014 From: python-checkins at python.org (zach.ware) Date: Fri, 31 Jan 2014 19:07:46 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320460=3A_Merge_with_3=2E3?= Message-ID: <3fG5xt2XpSz7LlH@mail.python.org> http://hg.python.org/cpython/rev/b56ce3410ca6 changeset: 88863:b56ce3410ca6 parent: 88861:681c86da0664 parent: 88862:7a611b7aae38 user: Zachary Ware date: Fri Jan 31 12:06:48 2014 -0600 summary: Issue #20460: Merge with 3.3 files: Doc/c-api/arg.rst | 2 +- 1 files changed, 1 insertions(+), 1 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 @@ -515,7 +515,7 @@ ``None`` is returned. ``y`` (:class:`bytes`) [char \*] - This converts a C string to a Python :func:`bytes` object. If the C + This converts a C string to a Python :class:`bytes` object. If the C string pointer is *NULL*, ``None`` is returned. ``y#`` (:class:`bytes`) [char \*, int] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 20:39:33 2014 From: python-checkins at python.org (yury.selivanov) Date: Fri, 31 Jan 2014 20:39:33 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2Eclassify=5Fclass?= =?utf-8?b?X2F0dHJzOiBDbGFzc2lmeSBvYmplY3QuX19uZXdfXyBhbmQgX19pbml0X18g?= =?utf-8?q?correctly?= Message-ID: <3fG7zn1C8rz7LjQ@mail.python.org> http://hg.python.org/cpython/rev/c38f99554be4 changeset: 88864:c38f99554be4 user: Yury Selivanov date: Fri Jan 31 14:28:44 2014 -0500 summary: inspect.classify_class_attrs: Classify object.__new__ and __init__ correctly #18801 files: Lib/inspect.py | 2 +- Lib/test/test_inspect.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -412,7 +412,7 @@ elif isinstance(dict_obj, property): kind = "property" obj = dict_obj - elif isfunction(obj) or ismethoddescriptor(obj): + elif isroutine(obj): kind = "method" else: kind = "data" diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -646,6 +646,10 @@ md = _BrokenMethodDescriptor() attrs = attrs_wo_objs(A) + + self.assertIn(('__new__', 'method', object), attrs, 'missing __new__') + self.assertIn(('__init__', 'method', object), attrs, 'missing __init__') + self.assertIn(('s', 'static method', A), attrs, 'missing static method') self.assertIn(('c', 'class method', A), attrs, 'missing class method') self.assertIn(('p', 'property', A), attrs, 'missing property') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 20:42:42 2014 From: python-checkins at python.org (yury.selivanov) Date: Fri, 31 Jan 2014 20:42:42 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_NEWS=3A_Add_news_item_for_?= =?utf-8?q?=2318801?= Message-ID: <3fG83Q66m4z7LjS@mail.python.org> http://hg.python.org/cpython/rev/d0f95094033d changeset: 88865:d0f95094033d user: Yury Selivanov date: Fri Jan 31 14:42:34 2014 -0500 summary: NEWS: Add news item for #18801 files: Misc/NEWS | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #18801: Fix inspect.classify_class_attrs to correctly classify + object.__new__ and object.__init__. + - Fixed cmath.isinf's name in its argument parsing code. - Issue #20311, #20452: poll and epoll now round the timeout away from zero, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 20:48:52 2014 From: python-checkins at python.org (yury.selivanov) Date: Fri, 31 Jan 2014 20:48:52 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2Esignature=3A_Sup?= =?utf-8?q?port_duck-types_of_Python_functions_=28Cython=2C_for?= Message-ID: <3fG8BX3gycz7LjQ@mail.python.org> http://hg.python.org/cpython/rev/32a660a52aae changeset: 88866:32a660a52aae user: Yury Selivanov date: Fri Jan 31 14:48:37 2014 -0500 summary: inspect.signature: Support duck-types of Python functions (Cython, for instance) #17159 files: Doc/whatsnew/3.4.rst | 4 + Lib/inspect.py | 32 ++++++++++++++- Lib/test/test_inspect.py | 60 ++++++++++++++++++++++++++++ Misc/NEWS | 3 + 4 files changed, 97 insertions(+), 2 deletions(-) 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 @@ -793,6 +793,10 @@ recommended to update your code to use :func:`~inspect.signature` directly. (Contributed by Yury Selivanov in :issue:`17481`) +:func:`~inspect.signature` now supports duck types of CPython functions, +which adds support for functions compiled with Cython. (Contributed +by Stefan Behnel and Yury Selivanov in :issue:`17159`) + logging ------- diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1601,6 +1601,30 @@ obj in (type, object)) +def _signature_is_functionlike(obj): + # Internal helper to test if `obj` is a duck type of FunctionType. + # A good example of such objects are functions compiled with + # Cython, which have all attributes that a pure Python function + # would have, but have their code statically compiled. + + if not callable(obj) or isclass(obj): + # All function-like objects are obviously callables, + # and not classes. + return False + + name = getattr(obj, '__name__', None) + code = getattr(obj, '__code__', None) + defaults = getattr(obj, '__defaults__', _void) # Important to use _void ... + kwdefaults = getattr(obj, '__kwdefaults__', _void) # ... and not None here + annotations = getattr(obj, '__annotations__', None) + + return (isinstance(code, types.CodeType) and + isinstance(name, str) and + (defaults is None or isinstance(defaults, tuple)) and + (kwdefaults is None or isinstance(kwdefaults, dict)) and + isinstance(annotations, dict)) + + def _signature_get_bound_param(spec): # Internal helper to get first parameter name from a # __text_signature__ of a builtin method, which should @@ -1670,7 +1694,9 @@ if _signature_is_builtin(obj): return Signature.from_builtin(obj) - if isinstance(obj, types.FunctionType): + if isfunction(obj) or _signature_is_functionlike(obj): + # If it's a pure Python function, or an object that is duck type + # of a Python function (Cython functions, for instance), then: return Signature.from_function(obj) if isinstance(obj, functools.partial): @@ -2071,7 +2097,9 @@ def from_function(cls, func): '''Constructs Signature for the given python function''' - if not isinstance(func, types.FunctionType): + if not (isfunction(func) or _signature_is_functionlike(func)): + # If it's not a pure Python function, and not a duck type + # of pure function: raise TypeError('{!r} is not a Python function'.format(func)) Parameter = cls._parameter_cls diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1740,6 +1740,66 @@ with self.assertRaisesRegex(TypeError, 'is not a Python builtin'): inspect.Signature.from_builtin(42) + def test_signature_from_functionlike_object(self): + def func(a,b, *args, kwonly=True, kwonlyreq, **kwargs): + pass + + class funclike: + # Has to be callable, and have correct + # __code__, __annotations__, __defaults__, __name__, + # and __kwdefaults__ attributes + + def __init__(self, func): + self.__name__ = func.__name__ + self.__code__ = func.__code__ + self.__annotations__ = func.__annotations__ + self.__defaults__ = func.__defaults__ + self.__kwdefaults__ = func.__kwdefaults__ + self.func = func + + def __call__(self, *args, **kwargs): + return self.func(*args, **kwargs) + + sig_func = inspect.Signature.from_function(func) + + sig_funclike = inspect.Signature.from_function(funclike(func)) + self.assertEqual(sig_funclike, sig_func) + + sig_funclike = inspect.signature(funclike(func)) + self.assertEqual(sig_funclike, sig_func) + + # If object is not a duck type of function, then + # signature will try to get a signature for its '__call__' + # method + fl = funclike(func) + del fl.__defaults__ + self.assertEqual(self.signature(fl), + ((('args', ..., ..., "var_positional"), + ('kwargs', ..., ..., "var_keyword")), + ...)) + + def test_signature_functionlike_class(self): + # We only want to duck type function-like objects, + # not classes. + + def func(a,b, *args, kwonly=True, kwonlyreq, **kwargs): + pass + + class funclike: + def __init__(self, marker): + pass + + __name__ = func.__name__ + __code__ = func.__code__ + __annotations__ = func.__annotations__ + __defaults__ = func.__defaults__ + __kwdefaults__ = func.__kwdefaults__ + + with self.assertRaisesRegex(TypeError, 'is not a Python function'): + inspect.Signature.from_function(funclike) + + self.assertEqual(str(inspect.signature(funclike)), '(marker)') + def test_signature_on_method(self): class Test: def __init__(*args): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #17159: inspect.signature now accepts duck types of functions, + which adds support for Cython functions. Initial patch by Stefan Behnel. + - Issue #18801: Fix inspect.classify_class_attrs to correctly classify object.__new__ and object.__init__. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 21:22:11 2014 From: python-checkins at python.org (yury.selivanov) Date: Fri, 31 Jan 2014 21:22:11 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=2ESignauture=2Efro?= =?utf-8?q?m=5Ffunction=3A_validate_duck_functions_in_Signature?= Message-ID: <3fG8wz20Rlz7LjW@mail.python.org> http://hg.python.org/cpython/rev/8a91132ed6aa changeset: 88867:8a91132ed6aa user: Yury Selivanov date: Fri Jan 31 15:21:51 2014 -0500 summary: inspect.Signauture.from_function: validate duck functions in Signature constructor #17159 files: Lib/inspect.py | 16 +++++++++++----- 1 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -2097,10 +2097,14 @@ def from_function(cls, func): '''Constructs Signature for the given python function''' - if not (isfunction(func) or _signature_is_functionlike(func)): - # If it's not a pure Python function, and not a duck type - # of pure function: - raise TypeError('{!r} is not a Python function'.format(func)) + is_duck_function = False + if not isfunction(func): + if _signature_is_functionlike(func): + is_duck_function = True + else: + # If it's not a pure Python function, and not a duck type + # of pure function: + raise TypeError('{!r} is not a Python function'.format(func)) Parameter = cls._parameter_cls @@ -2164,9 +2168,11 @@ parameters.append(Parameter(name, annotation=annotation, kind=_VAR_KEYWORD)) + # Is 'func' is a pure Python function - don't validate the + # parameters list (for correct order and defaults), it should be OK. return cls(parameters, return_annotation=annotations.get('return', _empty), - __validate_parameters__=False) + __validate_parameters__=is_duck_function) @classmethod def from_builtin(cls, func): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri Jan 31 21:31:33 2014 From: python-checkins at python.org (yury.selivanov) Date: Fri, 31 Jan 2014 21:31:33 +0100 (CET) Subject: [Python-checkins] =?utf-8?q?cpython=3A_inspect=3A_Add_some_commen?= =?utf-8?q?ts_in_Parameter=2E=5F=5Feq=5F=5F_method?= Message-ID: <3fG97n1ynpz7LjS@mail.python.org> http://hg.python.org/cpython/rev/c7233921b612 changeset: 88868:c7233921b612 user: Yury Selivanov date: Fri Jan 31 15:30:30 2014 -0500 summary: inspect: Add some comments in Parameter.__eq__ method files: Lib/inspect.py | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1905,6 +1905,17 @@ id(self), self.name) def __eq__(self, other): + # NB: We deliberately do not compare '_partial_kwarg' attributes + # here. Imagine we have a following situation: + # + # def foo(a, b=1): pass + # def bar(a, b): pass + # bar2 = functools.partial(bar, b=1) + # + # For the above scenario, signatures for `foo` and `bar2` should + # be equal. '_partial_kwarg' attribute is an internal flag, to + # distinguish between keyword parameters with defaults and + # keyword parameters which got their defaults from functools.partial return (issubclass(other.__class__, Parameter) and self._name == other._name and self._kind == other._kind and -- Repository URL: http://hg.python.org/cpython