From python-checkins at python.org Sat Nov 1 00:49:04 2014 From: python-checkins at python.org (ethan.furman) Date: Fri, 31 Oct 2014 23:49:04 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_issue22780=3A_update_NotIm?= =?utf-8?q?plemented_description?= Message-ID: <20141031234904.120736.58013@psf.io> https://hg.python.org/cpython/rev/26d0a17affb5 changeset: 93327:26d0a17affb5 parent: 93325:c95ce9b0a085 user: Ethan Furman date: Fri Oct 31 16:48:41 2014 -0700 summary: issue22780: update NotImplemented description files: Doc/library/constants.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/constants.rst b/Doc/library/constants.rst --- a/Doc/library/constants.rst +++ b/Doc/library/constants.rst @@ -26,9 +26,9 @@ .. data:: NotImplemented - Special value which can be returned by the "rich comparison" special methods - (:meth:`__eq__`, :meth:`__lt__`, and friends), to indicate that the comparison - is not implemented with respect to the other type. + Special value which should be returned by the special methods + (:meth:`__eq__`, :meth:`__lt__`, :meth:`__add__`, etc.) to indicate + that the operation is not implemented with respect to the other type. .. data:: Ellipsis -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 1 00:54:33 2014 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 31 Oct 2014 23:54:33 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_2=2E7=2E9_concrete_dates?= Message-ID: <20141031235433.109256.52937@psf.io> https://hg.python.org/peps/rev/8df0058f32cc changeset: 5591:8df0058f32cc user: Benjamin Peterson date: Fri Oct 31 19:54:32 2014 -0400 summary: 2.7.9 concrete dates files: pep-0373.txt | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/pep-0373.txt b/pep-0373.txt --- a/pep-0373.txt +++ b/pep-0373.txt @@ -71,7 +71,8 @@ Planned future release dates: -- 2.7.9 December 2014 +- 2.7.9rc1 2014-11-22 +- 2.7.9 2014-12-05 - 2.7.10 June 2015 - beyond this date, releases as needed -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Sat Nov 1 09:46:01 2014 From: python-checkins at python.org (berker.peksag) Date: Sat, 01 Nov 2014 08:46:01 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=236623=3A_Remove_de?= =?utf-8?q?precated_Netrc_class_in_the_ftplib_module=2E?= Message-ID: <20141101084600.101688.80686@psf.io> https://hg.python.org/cpython/rev/ec196a99af8d changeset: 93328:ec196a99af8d user: Berker Peksag date: Sat Nov 01 10:45:57 2014 +0200 summary: Issue #6623: Remove deprecated Netrc class in the ftplib module. Patch by Matt Chaput. files: Doc/whatsnew/3.5.rst | 8 + Lib/ftplib.py | 117 +-------------------------- Lib/test/test_ftplib.py | 23 +---- Misc/ACKS | 1 + Misc/NEWS | 3 + 5 files changed, 23 insertions(+), 129 deletions(-) diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -369,10 +369,18 @@ Removed ======= +API and Feature Removals +------------------------ + +The following obsolete and previously deprecated APIs and features have been +removed: + * The ``__version__`` attribute has been dropped from the email package. The email code hasn't been shipped separately from the stdlib for a long time, and the ``__version__`` string was not updated in the last few releases. +* The internal ``Netrc`` class in the :mod:`ftplib` module was deprecated in + 3.4, and has now been removed. (Contributed by Matt Chaput in :issue:`6623`.) Porting to Python 3.5 ===================== diff --git a/Lib/ftplib.py b/Lib/ftplib.py --- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -42,7 +42,7 @@ import warnings from socket import _GLOBAL_DEFAULT_TIMEOUT -__all__ = ["FTP", "Netrc"] +__all__ = ["FTP"] # Magic number from MSG_OOB = 0x1 # Process data out of band @@ -920,115 +920,6 @@ target.voidresp() -class Netrc: - """Class to parse & provide access to 'netrc' format files. - - See the netrc(4) man page for information on the file format. - - WARNING: This class is obsolete -- use module netrc instead. - - """ - __defuser = None - __defpasswd = None - __defacct = None - - def __init__(self, filename=None): - warnings.warn("This class is deprecated, use the netrc module instead", - DeprecationWarning, 2) - if filename is None: - if "HOME" in os.environ: - filename = os.path.join(os.environ["HOME"], - ".netrc") - else: - raise OSError("specify file to load or set $HOME") - self.__hosts = {} - self.__macros = {} - fp = open(filename, "r") - in_macro = 0 - while 1: - line = fp.readline() - if not line: - break - if in_macro and line.strip(): - macro_lines.append(line) - continue - elif in_macro: - self.__macros[macro_name] = tuple(macro_lines) - in_macro = 0 - words = line.split() - host = user = passwd = acct = None - default = 0 - i = 0 - while i < len(words): - w1 = words[i] - if i+1 < len(words): - w2 = words[i + 1] - else: - w2 = None - if w1 == 'default': - default = 1 - elif w1 == 'machine' and w2: - host = w2.lower() - i = i + 1 - elif w1 == 'login' and w2: - user = w2 - i = i + 1 - elif w1 == 'password' and w2: - passwd = w2 - i = i + 1 - elif w1 == 'account' and w2: - acct = w2 - i = i + 1 - elif w1 == 'macdef' and w2: - macro_name = w2 - macro_lines = [] - in_macro = 1 - break - i = i + 1 - if default: - self.__defuser = user or self.__defuser - self.__defpasswd = passwd or self.__defpasswd - self.__defacct = acct or self.__defacct - if host: - if host in self.__hosts: - ouser, opasswd, oacct = \ - self.__hosts[host] - user = user or ouser - passwd = passwd or opasswd - acct = acct or oacct - self.__hosts[host] = user, passwd, acct - fp.close() - - def get_hosts(self): - """Return a list of hosts mentioned in the .netrc file.""" - return self.__hosts.keys() - - def get_account(self, host): - """Returns login information for the named host. - - The return value is a triple containing userid, - password, and the accounting field. - - """ - host = host.lower() - user = passwd = acct = None - if host in self.__hosts: - user, passwd, acct = self.__hosts[host] - user = user or self.__defuser - passwd = passwd or self.__defpasswd - acct = acct or self.__defacct - return user, passwd, acct - - def get_macros(self): - """Return a list of all defined macro names.""" - return self.__macros.keys() - - def get_macro(self, macro): - """Return a sequence of lines which define a named macro.""" - return self.__macros[macro] - - - def test(): '''Test program. Usage: ftp [-d] [-r[file]] host [-l[dir]] [-d[dir]] [-p] [file] ... @@ -1042,6 +933,8 @@ print(test.__doc__) sys.exit(0) + import netrc + debugging = 0 rcfile = None while sys.argv[1] == '-d': @@ -1056,14 +949,14 @@ ftp.set_debuglevel(debugging) userid = passwd = acct = '' try: - netrc = Netrc(rcfile) + netrcobj = netrc.netrc(rcfile) except OSError: if rcfile is not None: sys.stderr.write("Could not open account file" " -- using anonymous login.") else: try: - userid, passwd, acct = netrc.get_account(host) + userid, acct, passwd = netrcobj.authenticators(host) except KeyError: # no account for host sys.stderr.write( diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -76,7 +76,7 @@ super(DummyDTPHandler, self).push(what.encode('ascii')) def handle_error(self): - raise + raise Exception class DummyFTPHandler(asynchat.async_chat): @@ -121,7 +121,7 @@ self.push('550 command "%s" not understood.' %cmd) def handle_error(self): - raise + raise Exception def push(self, data): asynchat.async_chat.push(self, data.encode('ascii') + b'\r\n') @@ -299,7 +299,7 @@ return 0 def handle_error(self): - raise + raise Exception if ssl is not None: @@ -397,7 +397,7 @@ raise def handle_error(self): - raise + raise Exception def close(self): if (isinstance(self.socket, ssl.SSLSocket) and @@ -673,7 +673,7 @@ self.assertRaises(StopIteration, next, self.client.mlsd()) set_data('') for x in self.client.mlsd(): - self.fail("unexpected data %s" % data) + self.fail("unexpected data %s" % x) def test_makeport(self): with self.client.makeport(): @@ -1053,19 +1053,8 @@ ftp.close() -class TestNetrcDeprecation(TestCase): - - def test_deprecation(self): - with support.temp_cwd(), support.EnvironmentVarGuard() as env: - env['HOME'] = os.getcwd() - open('.netrc', 'w').close() - with self.assertWarns(DeprecationWarning): - ftplib.Netrc() - - - def test_main(): - tests = [TestFTPClass, TestTimeouts, TestNetrcDeprecation, + tests = [TestFTPClass, TestTimeouts, TestIPv6Environment, TestTLS_FTPClassMixin, TestTLS_FTPClass] diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -233,6 +233,7 @@ Brad Chapman Greg Chapman Mitch Chapman +Matt Chaput Yogesh Chaudhari David Chaum Nicolas Chauvat diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -180,6 +180,9 @@ Library ------- +- Issue #6623: Remove deprecated Netrc class in the ftplib module. Patch by + Matt Chaput. + - Issue #17381: Fixed handling of case-insensitive ranges in regular expressions. -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Sat Nov 1 10:05:40 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 01 Nov 2014 10:05:40 +0100 Subject: [Python-checkins] Daily reference leaks (26d0a17affb5): sum=3 Message-ID: results for 26d0a17affb5 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogP2wzaR', '-x'] From python-checkins at python.org Sat Nov 1 10:05:39 2014 From: python-checkins at python.org (berker.peksag) Date: Sat, 01 Nov 2014 09:05:39 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322665=3A_Add_missing_get=5Fterminal=5Fsize_and_?= =?utf-8?q?SameFileError_to_shutil=2E=5F=5Fall=5F=5F=2E?= Message-ID: <20141101090538.120714.80210@psf.io> https://hg.python.org/cpython/rev/193ac288bc7f changeset: 93330:193ac288bc7f parent: 93328:ec196a99af8d parent: 93329:232520144c6c user: Berker Peksag date: Sat Nov 01 11:05:36 2014 +0200 summary: Issue #22665: Add missing get_terminal_size and SameFileError to shutil.__all__. files: Lib/shutil.py | 3 ++- Lib/test/test_shutil.py | 18 ++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 23 insertions(+), 1 deletions(-) diff --git a/Lib/shutil.py b/Lib/shutil.py --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -42,7 +42,8 @@ "register_archive_format", "unregister_archive_format", "get_unpack_formats", "register_unpack_format", "unregister_unpack_format", "unpack_archive", - "ignore_patterns", "chown", "which"] + "ignore_patterns", "chown", "which", "get_terminal_size", + "SameFileError"] # disk_usage is added later, if available on the platform class Error(OSError): 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 @@ -1788,5 +1788,23 @@ self.assertEqual(expected, actual) +class PublicAPITests(unittest.TestCase): + """Ensures that the correct values are exposed in the public API.""" + + def test_module_all_attribute(self): + self.assertTrue(hasattr(shutil, '__all__')) + target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat', + 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error', + 'SpecialFileError', 'ExecError', 'make_archive', + 'get_archive_formats', 'register_archive_format', + 'unregister_archive_format', 'get_unpack_formats', + 'register_unpack_format', 'unregister_unpack_format', + 'unpack_archive', 'ignore_patterns', 'chown', 'which', + 'get_terminal_size', 'SameFileError'] + if hasattr(os, 'statvfs') or os.name == 'nt': + target_api.append('disk_usage') + self.assertEqual(set(shutil.__all__), set(target_api)) + + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -180,6 +180,9 @@ Library ------- +- Issue #22665: Add missing get_terminal_size and SameFileError to + shutil.__all__. + - Issue #6623: Remove deprecated Netrc class in the ftplib module. Patch by Matt Chaput. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 1 10:05:39 2014 From: python-checkins at python.org (berker.peksag) Date: Sat, 01 Nov 2014 09:05:39 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyNjY1?= =?utf-8?q?=3A_Add_missing_get=5Fterminal=5Fsize_and_SameFileError_to_shut?= =?utf-8?b?aWwuX19hbGxfXy4=?= Message-ID: <20141101090538.109280.86646@psf.io> https://hg.python.org/cpython/rev/232520144c6c changeset: 93329:232520144c6c branch: 3.4 parent: 93324:147518a95b60 user: Berker Peksag date: Sat Nov 01 11:04:06 2014 +0200 summary: Issue #22665: Add missing get_terminal_size and SameFileError to shutil.__all__. files: Lib/shutil.py | 3 ++- Lib/test/test_shutil.py | 18 ++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 23 insertions(+), 1 deletions(-) diff --git a/Lib/shutil.py b/Lib/shutil.py --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -36,7 +36,8 @@ "register_archive_format", "unregister_archive_format", "get_unpack_formats", "register_unpack_format", "unregister_unpack_format", "unpack_archive", - "ignore_patterns", "chown", "which"] + "ignore_patterns", "chown", "which", "get_terminal_size", + "SameFileError"] # disk_usage is added later, if available on the platform class Error(OSError): 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 @@ -1762,5 +1762,23 @@ self.assertEqual(expected, actual) +class PublicAPITests(unittest.TestCase): + """Ensures that the correct values are exposed in the public API.""" + + def test_module_all_attribute(self): + self.assertTrue(hasattr(shutil, '__all__')) + target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat', + 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error', + 'SpecialFileError', 'ExecError', 'make_archive', + 'get_archive_formats', 'register_archive_format', + 'unregister_archive_format', 'get_unpack_formats', + 'register_unpack_format', 'unregister_unpack_format', + 'unpack_archive', 'ignore_patterns', 'chown', 'which', + 'get_terminal_size', 'SameFileError'] + if hasattr(os, 'statvfs') or os.name == 'nt': + target_api.append('disk_usage') + self.assertEqual(set(shutil.__all__), set(target_api)) + + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -33,6 +33,9 @@ Library ------- +- Issue #22665: Add missing get_terminal_size and SameFileError to + shutil.__all__. + - Issue #17381: Fixed handling of case-insensitive ranges in regular expressions. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 1 15:40:47 2014 From: python-checkins at python.org (ethan.furman) Date: Sat, 01 Nov 2014 14:40:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_standardize_Enum_docs_by_r?= =?utf-8?q?eferring_to_=27special_methods=27_instead_of_=5F=5Fdunder=5F=5F?= Message-ID: <20141101144044.101698.67174@psf.io> https://hg.python.org/cpython/rev/149490bbd260 changeset: 93331:149490bbd260 user: Ethan Furman date: Sat Nov 01 07:40:22 2014 -0700 summary: standardize Enum docs by referring to 'special methods' instead of __dunder__ methods files: Doc/library/enum.rst | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -314,11 +314,11 @@ >>> str(Mood.funky) 'my custom str! 1' -The rules for what is allowed are as follows: _sunder_ names (starting and -ending with a single underscore) are reserved by enum and cannot be used; -all other attributes defined within an enumeration will become members of this -enumeration, with the exception of *__dunder__* names and descriptors (methods -are also descriptors). +The rules for what is allowed are as follows: names that start and end with a +with a single underscore are reserved by enum and cannot be used; all other +attributes defined within an enumeration will become members of this +enumeration, with the exception of special methods (:meth:`__str__`, +:meth:`__add__`, etc.) and descriptors (methods are also descriptors). Note: if your enumeration defines :meth:`__new__` and/or :meth:`__init__` then whatever value(s) were given to the enum member will be passed into those -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 1 21:01:12 2014 From: python-checkins at python.org (vinay.sajip) Date: Sat, 01 Nov 2014 20:01:12 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Brought_exclud?= =?utf-8?q?ed_code_into_the_scope_of_a_try_block_in_SysLogHandler=2Eemit?= =?utf-8?b?KCku?= Message-ID: <20141101200109.120724.27785@psf.io> https://hg.python.org/cpython/rev/f6a906541476 changeset: 93333:f6a906541476 branch: 3.4 parent: 93329:232520144c6c user: Vinay Sajip date: Sat Nov 01 19:58:47 2014 +0000 summary: Brought excluded code into the scope of a try block in SysLogHandler.emit(). files: Lib/logging/handlers.py | 28 ++++++++++++++-------------- Misc/NEWS | 3 +++ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -879,21 +879,21 @@ The record is formatted, and then sent to the syslog server. If exception information is present, it is NOT sent to the server. """ - msg = self.format(record) - if self.ident: - msg = self.ident + msg - if self.append_nul: - msg += '\000' + try: + msg = self.format(record) + if self.ident: + msg = self.ident + msg + if self.append_nul: + msg += '\000' - # We need to convert record level to lowercase, maybe this will - # change in the future. - prio = '<%d>' % self.encodePriority(self.facility, - self.mapPriority(record.levelname)) - prio = prio.encode('utf-8') - # Message is a string. Convert to bytes as required by RFC 5424 - msg = msg.encode('utf-8') - msg = prio + msg - try: + # We need to convert record level to lowercase, maybe this will + # change in the future. + prio = '<%d>' % self.encodePriority(self.facility, + self.mapPriority(record.levelname)) + prio = prio.encode('utf-8') + # Message is a string. Convert to bytes as required by RFC 5424 + msg = msg.encode('utf-8') + msg = prio + msg if self.unixsocket: try: self.socket.send(msg) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -33,6 +33,9 @@ Library ------- +- Issue #22776: Brought excluded code into the scope of a try block in + SysLogHandler.emit(). + - Issue #22665: Add missing get_terminal_size and SameFileError to shutil.__all__. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 1 21:01:12 2014 From: python-checkins at python.org (vinay.sajip) Date: Sat, 01 Nov 2014 20:01:12 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Closes_=2322776=3A_Merged_fix_from_3=2E4=2E?= Message-ID: <20141101200109.101682.22068@psf.io> https://hg.python.org/cpython/rev/54549f9b2ecc changeset: 93334:54549f9b2ecc parent: 93331:149490bbd260 parent: 93333:f6a906541476 user: Vinay Sajip date: Sat Nov 01 20:00:56 2014 +0000 summary: Closes #22776: Merged fix from 3.4. files: Lib/logging/handlers.py | 28 ++++++++++++++-------------- Misc/NEWS | 3 +++ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -879,21 +879,21 @@ The record is formatted, and then sent to the syslog server. If exception information is present, it is NOT sent to the server. """ - msg = self.format(record) - if self.ident: - msg = self.ident + msg - if self.append_nul: - msg += '\000' + try: + msg = self.format(record) + if self.ident: + msg = self.ident + msg + if self.append_nul: + msg += '\000' - # We need to convert record level to lowercase, maybe this will - # change in the future. - prio = '<%d>' % self.encodePriority(self.facility, - self.mapPriority(record.levelname)) - prio = prio.encode('utf-8') - # Message is a string. Convert to bytes as required by RFC 5424 - msg = msg.encode('utf-8') - msg = prio + msg - try: + # We need to convert record level to lowercase, maybe this will + # change in the future. + prio = '<%d>' % self.encodePriority(self.facility, + self.mapPriority(record.levelname)) + prio = prio.encode('utf-8') + # Message is a string. Convert to bytes as required by RFC 5424 + msg = msg.encode('utf-8') + msg = prio + msg if self.unixsocket: try: self.socket.send(msg) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -180,6 +180,9 @@ Library ------- +- Issue #22776: Brought excluded code into the scope of a try block in + SysLogHandler.emit(). + - Issue #22665: Add missing get_terminal_size and SameFileError to shutil.__all__. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 1 21:01:12 2014 From: python-checkins at python.org (vinay.sajip) Date: Sat, 01 Nov 2014 20:01:12 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Brought_exclud?= =?utf-8?q?ed_code_into_the_scope_of_a_try_block_in_SysLogHandler=2Eemit?= =?utf-8?b?KCku?= Message-ID: <20141101200108.109268.11270@psf.io> https://hg.python.org/cpython/rev/ea7b64406396 changeset: 93332:ea7b64406396 branch: 2.7 parent: 93326:3f13f1620d70 user: Vinay Sajip date: Sat Nov 01 19:56:13 2014 +0000 summary: Brought excluded code into the scope of a try block in SysLogHandler.emit(). files: Lib/logging/handlers.py | 22 +++++++++++----------- Misc/NEWS | 3 +++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -840,18 +840,18 @@ The record is formatted, and then sent to the syslog server. If exception information is present, it is NOT sent to the server. """ - msg = self.format(record) + '\000' - """ - We need to convert record level to lowercase, maybe this will - change in the future. - """ - prio = '<%d>' % self.encodePriority(self.facility, - self.mapPriority(record.levelname)) - # Message is a string. Convert to bytes as required by RFC 5424 - if type(msg) is unicode: - msg = msg.encode('utf-8') - msg = prio + msg try: + msg = self.format(record) + '\000' + """ + We need to convert record level to lowercase, maybe this will + change in the future. + """ + prio = '<%d>' % self.encodePriority(self.facility, + self.mapPriority(record.levelname)) + # Message is a string. Convert to bytes as required by RFC 5424 + if type(msg) is unicode: + msg = msg.encode('utf-8') + msg = prio + msg if self.unixsocket: try: self.socket.send(msg) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,6 +37,9 @@ Library ------- +- Issue #22776: Brought excluded code into the scope of a try block in + SysLogHandler.emit(). + - Issue #17381: Fixed ranges handling in case-insensitive regular expressions. - Issue #19329: Optimized compiling charsets in regular expressions. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 1 23:11:38 2014 From: python-checkins at python.org (steve.dower) Date: Sat, 01 Nov 2014 22:11:38 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_=2322731_test=5Fcapi_test_?= =?utf-8?q?fails_because_of_mismatched_newlines?= Message-ID: <20141101221136.109258.64289@psf.io> https://hg.python.org/cpython/rev/edb270e5c9c3 changeset: 93335:edb270e5c9c3 user: Steve Dower date: Sat Nov 01 15:11:05 2014 -0700 summary: #22731 test_capi test fails because of mismatched newlines files: Lib/test/test_capi.py | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -304,12 +304,13 @@ cmd.extend(args) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + stderr=subprocess.PIPE, + universal_newlines=True) (out, err) = p.communicate() self.assertEqual(p.returncode, 0, "bad returncode %d, stderr is %r" % (p.returncode, err)) - return out.decode("latin1"), err.decode("latin1") + return out, err def test_subinterps(self): # This is just a "don't crash" test @@ -339,7 +340,7 @@ expected_errors = sys.__stdout__.errors expected_stdin_encoding = sys.__stdin__.encoding expected_pipe_encoding = self._get_default_pipe_encoding() - expected_output = os.linesep.join([ + expected_output = '\n'.join([ "--- Use defaults ---", "Expected encoding: default", "Expected errors: default", -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 1 23:16:09 2014 From: python-checkins at python.org (steve.dower) Date: Sat, 01 Nov 2014 22:16:09 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_=2322732_ctypes_tests_don?= =?utf-8?q?=27t_set_correct_restype_for_intptr=5Ft_functions?= Message-ID: <20141101221607.111420.13171@psf.io> https://hg.python.org/cpython/rev/a944fe09fae8 changeset: 93336:a944fe09fae8 user: Steve Dower date: Sat Nov 01 15:14:27 2014 -0700 summary: #22732 ctypes tests don't set correct restype for intptr_t functions files: Lib/ctypes/test/test_pointers.py | 5 ++++- Lib/ctypes/test/test_prototypes.py | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Lib/ctypes/test/test_pointers.py b/Lib/ctypes/test/test_pointers.py --- a/Lib/ctypes/test/test_pointers.py +++ b/Lib/ctypes/test/test_pointers.py @@ -24,7 +24,10 @@ def test_pass_pointers(self): dll = CDLL(_ctypes_test.__file__) func = dll._testfunc_p_p - func.restype = c_long + if sizeof(c_longlong) == sizeof(c_void_p): + func.restype = c_longlong + else: + func.restype = c_long i = c_int(12345678) ## func.argtypes = (POINTER(c_int),) diff --git a/Lib/ctypes/test/test_prototypes.py b/Lib/ctypes/test/test_prototypes.py --- a/Lib/ctypes/test/test_prototypes.py +++ b/Lib/ctypes/test/test_prototypes.py @@ -69,7 +69,10 @@ def test_int_pointer_arg(self): func = testdll._testfunc_p_p - func.restype = c_long + if sizeof(c_longlong) == sizeof(c_void_p): + func.restype = c_longlong + else: + func.restype = c_long self.assertEqual(0, func(0)) ci = c_int(0) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 1 23:16:09 2014 From: python-checkins at python.org (steve.dower) Date: Sat, 01 Nov 2014 22:16:09 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_=2322734_marshal_needs_a_l?= =?utf-8?q?ower_stack_depth_for_debug_builds_on_Windows?= Message-ID: <20141101221608.111404.71617@psf.io> https://hg.python.org/cpython/rev/c2a3865a59f4 changeset: 93337:c2a3865a59f4 user: Steve Dower date: Sat Nov 01 15:15:16 2014 -0700 summary: #22734 marshal needs a lower stack depth for debug builds on Windows files: Lib/test/test_marshal.py | 2 +- Python/marshal.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 @@ -188,7 +188,7 @@ head = last = [] # The max stack depth should match the value in Python/marshal.c. if os.name == 'nt' and hasattr(sys, 'gettotalrefcount'): - MAX_MARSHAL_STACK_DEPTH = 1500 + MAX_MARSHAL_STACK_DEPTH = 1000 else: MAX_MARSHAL_STACK_DEPTH = 2000 for i in range(MAX_MARSHAL_STACK_DEPTH - 2): diff --git a/Python/marshal.c b/Python/marshal.c --- a/Python/marshal.c +++ b/Python/marshal.c @@ -19,7 +19,7 @@ * On Windows debug builds, reduce this value. */ #if defined(MS_WINDOWS) && defined(_DEBUG) -#define MAX_MARSHAL_STACK_DEPTH 1500 +#define MAX_MARSHAL_STACK_DEPTH 1000 #else #define MAX_MARSHAL_STACK_DEPTH 2000 #endif -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 00:43:50 2014 From: python-checkins at python.org (zach.ware) Date: Sat, 01 Nov 2014 23:43:50 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzE3NzE3?= =?utf-8?q?=3A_Pull_NASM_from_svn=2Epython=2Eorg_for_OpenSSL_build=2E?= Message-ID: <20141101234349.35248.64114@psf.io> https://hg.python.org/cpython/rev/f7ed3e058fca changeset: 93339:f7ed3e058fca branch: 3.4 parent: 93333:f6a906541476 user: Zachary Ware date: Sat Nov 01 17:11:08 2014 -0500 summary: Issue #17717: Pull NASM from svn.python.org for OpenSSL build. files: Misc/NEWS | 3 +++ PCbuild/build_ssl.py | 11 +++++++++++ PCbuild/readme.txt | 4 +++- Tools/buildbot/external-common.bat | 4 ++++ 4 files changed, 21 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -126,6 +126,9 @@ Windows ------- +- Issue #17717: The Windows build scripts now use a copy of NASM pulled from + svn.python.org to build OpenSSL. + - Issue #22644: The bundled version of OpenSSL has been updated to 1.0.1j. What's New in Python 3.4.2? diff --git a/PCbuild/build_ssl.py b/PCbuild/build_ssl.py --- a/PCbuild/build_ssl.py +++ b/PCbuild/build_ssl.py @@ -182,6 +182,17 @@ if ssl_dir is None: sys.exit(1) + # add our copy of NASM to PATH. It will be on the same level as openssl + for dir in os.listdir(os.path.join(ssl_dir, os.pardir)): + if dir.startswith('nasm'): + nasm_dir = os.path.join(ssl_dir, os.pardir, dir) + nasm_dir = os.path.abspath(nasm_dir) + os.environ['PATH'] += os.pathsep.join(['', nasm_dir]) + break + else: + print('NASM was not found, make sure it is on PATH') + + old_cd = os.getcwd() try: os.chdir(ssl_dir) diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -182,7 +182,9 @@ to be somewhere on your PATH. More recent versions of OpenSSL may need a later version of NASM. If OpenSSL's self tests don't pass, you should first try to update NASM and do a full rebuild of - OpenSSL. + OpenSSL. If you use the Tools\buildbot\external(-amd64).bat method + for getting sources, it also downloads a version of NASM which the + ssl build script will add to PATH. If you like to use the official sources instead of the files from python.org's subversion repository, Perl is required to build the diff --git a/Tools/buildbot/external-common.bat b/Tools/buildbot/external-common.bat --- a/Tools/buildbot/external-common.bat +++ b/Tools/buildbot/external-common.bat @@ -20,6 +20,10 @@ svn export http://svn.python.org/projects/external/bzip2-1.0.6 ) + at rem NASM, for OpenSSL build + at rem if exist nasm-2.11.06 rd /s/q nasm-2.11.06 +if not exist nasm-2.11.06 svn export http://svn.python.org/projects/external/nasm-2.11.06 + @rem OpenSSL if not exist openssl-1.0.1j ( rd /s/q openssl-1.0.1i -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 00:43:49 2014 From: python-checkins at python.org (zach.ware) Date: Sat, 01 Nov 2014 23:43:49 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3NzE3?= =?utf-8?q?=3A_Pull_NASM_from_svn=2Epython=2Eorg_for_OpenSSL_build=2E?= Message-ID: <20141101234349.35258.89627@psf.io> https://hg.python.org/cpython/rev/28d18fdc52c4 changeset: 93338:28d18fdc52c4 branch: 2.7 parent: 93332:ea7b64406396 user: Zachary Ware date: Sat Nov 01 17:11:08 2014 -0500 summary: Issue #17717: Pull NASM from svn.python.org for OpenSSL build. files: Misc/NEWS | 3 +++ PCbuild/build_ssl.py | 11 +++++++++++ PCbuild/readme.txt | 4 +++- Tools/buildbot/external-common.bat | 4 ++++ 4 files changed, 21 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -305,6 +305,9 @@ Windows ------- +- Issue #17717: The Windows build scripts now use a copy of NASM pulled from + svn.python.org to build OpenSSL. + - Issue #22644: The bundled version of OpenSSL has been updated to 1.0.1j. diff --git a/PCbuild/build_ssl.py b/PCbuild/build_ssl.py --- a/PCbuild/build_ssl.py +++ b/PCbuild/build_ssl.py @@ -170,6 +170,17 @@ if ssl_dir is None: sys.exit(1) + # add our copy of NASM to PATH. It will be on the same level as openssl + for dir in os.listdir(os.path.join(ssl_dir, os.pardir)): + if dir.startswith('nasm'): + nasm_dir = os.path.join(ssl_dir, os.pardir, dir) + nasm_dir = os.path.abspath(nasm_dir) + os.environ['PATH'] += os.pathsep.join(['', nasm_dir]) + break + else: + print('NASM was not found, make sure it is on PATH') + + old_cd = os.getcwd() try: os.chdir(ssl_dir) diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -144,7 +144,9 @@ You must install the NASM assembler from http://nasm.sf.net - for x86 builds. Put nasm.exe anywhere in your PATH. + for x86 builds. Put nasm.exe anywhere in your PATH. If you use the + Tools\buildbot\external(-amd64).bat method for getting sources, it also + downloads a version of NASM, which the ssl build script will add to PATH. You can also install ActivePerl from http://www.activestate.com/activeperl/ diff --git a/Tools/buildbot/external-common.bat b/Tools/buildbot/external-common.bat --- a/Tools/buildbot/external-common.bat +++ b/Tools/buildbot/external-common.bat @@ -37,6 +37,10 @@ if exist db-4.4.20 rd /s/q db-4.4.20 if not exist db-4.7.25.0 svn export http://svn.python.org/projects/external/db-4.7.25.0 + at rem NASM, for OpenSSL build + at rem if exist nasm-2.11.06 rd /s/q nasm-2.11.06 +if not exist nasm-2.11.06 svn export http://svn.python.org/projects/external/nasm-2.11.06 + @rem OpenSSL if exist openssl-1.0.1i rd /s/q openssl-1.0.1i if not exist openssl-1.0.1j svn export http://svn.python.org/projects/external/openssl-1.0.1j -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 00:43:50 2014 From: python-checkins at python.org (zach.ware) Date: Sat, 01 Nov 2014 23:43:50 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Null_merge_with_3=2E4?= Message-ID: <20141101234350.101680.86997@psf.io> https://hg.python.org/cpython/rev/58b1426981c4 changeset: 93340:58b1426981c4 parent: 93337:c2a3865a59f4 parent: 93339:f7ed3e058fca user: Zachary Ware date: Sat Nov 01 18:33:52 2014 -0500 summary: Null merge with 3.4 files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 00:43:53 2014 From: python-checkins at python.org (zach.ware) Date: Sat, 01 Nov 2014 23:43:53 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2317717=3A_Pull_NAS?= =?utf-8?q?M_from_svn=2Epython=2Eorg_for_OpenSSL_build=2E?= Message-ID: <20141101234350.101684.64168@psf.io> https://hg.python.org/cpython/rev/ef15b51d59fb changeset: 93341:ef15b51d59fb user: Zachary Ware date: Sat Nov 01 18:42:46 2014 -0500 summary: Issue #17717: Pull NASM from svn.python.org for OpenSSL build. files: Misc/NEWS | 3 +++ PCbuild/get_externals.bat | 8 +++++--- PCbuild/pyproject.props | 4 ++++ PCbuild/readme.txt | 8 ++++---- PCbuild/ssl.vcxproj | 8 ++++++++ 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1383,6 +1383,9 @@ Windows ------- +- Issue #17717: The Windows build scripts now use a copy of NASM pulled from + svn.python.org to build OpenSSL. + - Issue #21907: Improved the batch scripts provided for building Python. - Issue #22644: The bundled version of OpenSSL has been updated to 1.0.1j. diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -20,6 +20,7 @@ for /D %%d in ( bzip2-* db-* + nasm-* openssl-* tcl-* tcltk* @@ -51,6 +52,7 @@ for %%e in ( bzip2-1.0.6 + nasm-2.11.06 openssl-1.0.1j tcl-8.6.1.0 tk-8.6.1.0 @@ -87,9 +89,9 @@ echo.**WARNING**: the cleaning options unconditionally remove any directory echo.that is a child of echo. %CD% -echo.and matches wildcard patterns beginning with bzip2-, db-, openssl-, tcl-, -echo.tcltk, tk-, tix-, sqlite-, or xz-, and as such has the potential to be -echo.very destructive if you are not aware of what it is doing. Use with +echo.and matches wildcard patterns beginning with bzip2-, db-, nasm-, openssl-, +echo.tcl-, tcltk, tk-, tix-, sqlite-, or xz-, and as such has the potential +echo.to be very destructive if you are not aware of what it is doing. Use with echo.caution! popd exit /b -1 diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -20,6 +20,7 @@ $(externalsDir)\sqlite-3.8.3.1 $(externalsDir)\bzip2-1.0.6 $(externalsDir)\xz-5.0.5 + $(externalsDir)\nasm-2.11.06 $(externalsDir)\openssl-1.0.1j $(externalsDir)\tcl-8.6.1.0 $(externalsDir)\tk-8.6.1.0 @@ -77,6 +78,9 @@ $(lzmaDir) + + $(nasmDir) + $(opensslDir) diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -3,9 +3,8 @@ 1. Install Microsoft Visual C++ 2010 SP1, any edition. 2. Install Subversion, and make sure 'svn.exe' is on your PATH. -3. Install NASM, and make sure 'nasm.exe' is on your PATH. -4. Run "build.bat -e" to build Python in 32-bit Release configuration. -5. (Optional, but recommended) Run the test suite with "rt.bat -q". +3. Run "build.bat -e" to build Python in 32-bit Release configuration. +4. (Optional, but recommended) Run the test suite with "rt.bat -q". Building Python using Microsoft Visual C++ @@ -225,7 +224,8 @@ to be somewhere on your PATH. More recent versions of OpenSSL may need a later version of NASM. If OpenSSL's self tests don't pass, you should first try to update NASM and do a full rebuild of - OpenSSL. + OpenSSL. get_externals.py also downloads a snapshot of NASM, and the + ssl sub-project includes that version of nasm.exe on PATH. The ssl sub-project expects your OpenSSL sources to have already been configured and be ready to build. If you get your sources diff --git a/PCbuild/ssl.vcxproj b/PCbuild/ssl.vcxproj --- a/PCbuild/ssl.vcxproj +++ b/PCbuild/ssl.vcxproj @@ -119,6 +119,7 @@ <_ProjectFileVersion>10.0.30319.1 +path %PATH%;$(SolutionDir)$(nasmDir) cd "$(SolutionDir)$(opensslDir)" copy /Y crypto\buildinf_x86.h crypto\buildinf.h copy /Y crypto\opensslconf_x86.h crypto\opensslconf.h @@ -133,6 +134,7 @@ $(NMakeAssemblySearchPath) $(NMakeForcedUsingAssemblies) +path %PATH%;$(SolutionDir)$(nasmDir) cd "$(SolutionDir)$(opensslDir)" nasm -f win64 -DNEAR -Ox -g ms\\uptable.asm || echo nasm failed! && exit copy /Y crypto\buildinf_amd64.h crypto\buildinf.h @@ -148,6 +150,7 @@ $(NMakeAssemblySearchPath) $(NMakeForcedUsingAssemblies) +path %PATH%;$(SolutionDir)$(nasmDir) cd "$(SolutionDir)$(opensslDir)" copy /Y crypto\buildinf_x86.h crypto\buildinf.h copy /Y crypto\opensslconf_x86.h crypto\opensslconf.h @@ -162,6 +165,7 @@ $(NMakeAssemblySearchPath) $(NMakeForcedUsingAssemblies) +path %PATH%;$(SolutionDir)$(nasmDir) cd "$(SolutionDir)$(opensslDir)" nasm -f win64 -DNEAR -Ox -g ms\\uptable.asm || echo nasm failed! && exit copy /Y crypto\buildinf_amd64.h crypto\buildinf.h @@ -177,6 +181,7 @@ $(NMakeAssemblySearchPath) $(NMakeForcedUsingAssemblies) +path %PATH%;$(SolutionDir)$(nasmDir) cd "$(SolutionDir)$(opensslDir)" copy /Y crypto\buildinf_x86.h crypto\buildinf.h copy /Y crypto\opensslconf_x86.h crypto\opensslconf.h @@ -191,6 +196,7 @@ $(NMakeAssemblySearchPath) $(NMakeForcedUsingAssemblies) +path %PATH%;$(SolutionDir)$(nasmDir) cd "$(SolutionDir)$(opensslDir)" nasm -f win64 -DNEAR -Ox -g ms\\uptable.asm || echo nasm failed! && exit copy /Y crypto\buildinf_amd64.h crypto\buildinf.h @@ -206,6 +212,7 @@ $(NMakeAssemblySearchPath) $(NMakeForcedUsingAssemblies) +path %PATH%;$(SolutionDir)$(nasmDir) cd "$(SolutionDir)$(opensslDir)" copy /Y crypto\buildinf_x86.h crypto\buildinf.h copy /Y crypto\opensslconf_x86.h crypto\opensslconf.h @@ -220,6 +227,7 @@ $(NMakeAssemblySearchPath) $(NMakeForcedUsingAssemblies) +path %PATH%;$(SolutionDir)$(nasmDir) cd "$(SolutionDir)$(opensslDir)" nasm -f win64 -DNEAR -Ox -g ms\\uptable.asm || echo nasm failed! && exit copy /Y crypto\buildinf_amd64.h crypto\buildinf.h -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 03:34:01 2014 From: python-checkins at python.org (ned.deily) Date: Sun, 02 Nov 2014 02:34:01 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIyNzcw?= =?utf-8?q?=3A_Prevent_some_Tk_segfaults_on_OS_X_when_running_gui_tests=2E?= Message-ID: <20141102023400.111410.59186@psf.io> https://hg.python.org/cpython/rev/bd4dc351d670 changeset: 93342:bd4dc351d670 branch: 2.7 parent: 93338:28d18fdc52c4 user: Ned Deily date: Sat Nov 01 19:26:45 2014 -0700 summary: Issue #22770: Prevent some Tk segfaults on OS X when running gui tests. When running tests in subprocesses with the regrtest -j option, a bug in Cocoa Tk can result in a Tcl segfault. Avoid the problem by forcing Tk to fully initialize as an OS X gui process before destroying the Tcl instance and creating another. (Original patch by Serhiy Storchaka) files: Lib/test/test_support.py | 5 ++--- Misc/NEWS | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) 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 @@ -326,12 +326,11 @@ reason = "cannot run without OS X gui process" # check on every platform whether tkinter can actually do anything - # but skip the test on OS X because it can cause segfaults in Cocoa Tk - # when running regrtest with the -j option (multiple threads/subprocesses) - if (not reason) and (sys.platform != 'darwin'): + if not reason: try: from Tkinter import Tk root = Tk() + root.update() root.destroy() except Exception as e: err_string = str(e) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -277,6 +277,8 @@ - Issue #21976: Fix test_ssl to accept LibreSSL version strings. Thanks to William Orr. +- Issue #22770: Prevent some Tk segfaults on OS X when running gui tests. + Build ----- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 03:34:01 2014 From: python-checkins at python.org (ned.deily) Date: Sun, 02 Nov 2014 02:34:01 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322770=3A_merge_from_3=2E4?= Message-ID: <20141102023401.101684.26236@psf.io> https://hg.python.org/cpython/rev/e119343bc3ec changeset: 93344:e119343bc3ec parent: 93341:ef15b51d59fb parent: 93343:121517deb318 user: Ned Deily date: Sat Nov 01 19:33:25 2014 -0700 summary: Issue #22770: merge from 3.4 files: Lib/test/support/__init__.py | 5 ++--- Misc/NEWS | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -461,12 +461,11 @@ reason = "cannot run without OS X gui process" # check on every platform whether tkinter can actually do anything - # but skip the test on OS X because it can cause segfaults in Cocoa Tk - # when running regrtest with the -j option (multiple threads/subprocesses) - if (not reason) and (sys.platform != 'darwin'): + if not reason: try: from tkinter import Tk root = Tk() + root.update() root.destroy() except Exception as e: err_string = str(e) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1342,6 +1342,8 @@ - Issue #21093: Prevent failures of ctypes test_macholib on OS X if a copy of libz exists in $HOME/lib or /usr/local/lib. +- Issue #22770: Prevent some Tk segfaults on OS X when running gui tests. + Tools/Demos ----------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 03:34:01 2014 From: python-checkins at python.org (ned.deily) Date: Sun, 02 Nov 2014 02:34:01 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyNzcw?= =?utf-8?q?=3A_Prevent_some_Tk_segfaults_on_OS_X_when_running_gui_tests=2E?= Message-ID: <20141102023401.109276.44229@psf.io> https://hg.python.org/cpython/rev/121517deb318 changeset: 93343:121517deb318 branch: 3.4 parent: 93339:f7ed3e058fca user: Ned Deily date: Sat Nov 01 19:29:22 2014 -0700 summary: Issue #22770: Prevent some Tk segfaults on OS X when running gui tests. When running tests in subprocesses with the regrtest -j option, a bug in Cocoa Tk can result in a Tcl segfault. Avoid the problem by forcing Tk to fully initialize as an OS X gui process before destroying the Tcl instance and creating another. (Original patch by Serhiy Storchaka) files: Lib/test/support/__init__.py | 5 ++--- Misc/NEWS | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -461,12 +461,11 @@ reason = "cannot run without OS X gui process" # check on every platform whether tkinter can actually do anything - # but skip the test on OS X because it can cause segfaults in Cocoa Tk - # when running regrtest with the -j option (multiple threads/subprocesses) - if (not reason) and (sys.platform != 'darwin'): + if not reason: try: from tkinter import Tk root = Tk() + root.update() root.destroy() except Exception as e: err_string = str(e) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -113,6 +113,8 @@ - Issue #21456: Skip two tests in test_urllib2net.py if _ssl module not present. Patch by Remi Pointel. +- Issue #22770: Prevent some Tk segfaults on OS X when running gui tests. + Build ----- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 04:50:08 2014 From: python-checkins at python.org (zach.ware) Date: Sun, 02 Nov 2014 03:50:08 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzE3ODk2?= =?utf-8?q?=3A_Move_Windows_external_lib_sources_from_=2E=2E_to_externals?= =?utf-8?q?=2E?= Message-ID: <20141102035008.101682.70902@psf.io> https://hg.python.org/cpython/rev/b5e9bc4352e1 changeset: 93346:b5e9bc4352e1 branch: 3.4 parent: 93343:121517deb318 user: Zachary Ware date: Sat Nov 01 22:39:21 2014 -0500 summary: Issue #17896: Move Windows external lib sources from .. to externals. files: .gitignore | 1 + .hgignore | 1 + Lib/tkinter/_fix.py | 4 ++-- Misc/NEWS | 3 +++ PCbuild/build_ssl.py | 2 +- PCbuild/pyproject.props | 2 +- PCbuild/readme.txt | 13 +++++++------ PCbuild/rt.bat | 2 +- Tools/buildbot/external-common.bat | 3 ++- 9 files changed, 19 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore --- a/.gitignore +++ b/.gitignore @@ -70,4 +70,5 @@ TAGS .coverage coverage/ +externals/ htmlcov/ diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -92,6 +92,7 @@ Modules/_testembed .coverage coverage/ +externals/ htmlcov/ *.gcda *.gcno diff --git a/Lib/tkinter/_fix.py b/Lib/tkinter/_fix.py --- a/Lib/tkinter/_fix.py +++ b/Lib/tkinter/_fix.py @@ -48,8 +48,8 @@ prefix = os.path.join(sys.base_prefix,"tcl") if not os.path.exists(prefix): - # devdir/../tcltk/lib - prefix = os.path.join(sys.base_prefix, os.path.pardir, "tcltk", "lib") + # devdir/externals/tcltk/lib + prefix = os.path.join(sys.base_prefix, "externals", "tcltk", "lib") prefix = os.path.abspath(prefix) # if this does not exist, no further search is needed if os.path.exists(prefix): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -128,6 +128,9 @@ Windows ------- +- Issue #17896: The Windows build scripts now expect external library sources + to be in ``PCbuild\..\externals`` rather than ``PCbuild\..\..``. + - Issue #17717: The Windows build scripts now use a copy of NASM pulled from svn.python.org to build OpenSSL. diff --git a/PCbuild/build_ssl.py b/PCbuild/build_ssl.py --- a/PCbuild/build_ssl.py +++ b/PCbuild/build_ssl.py @@ -68,7 +68,7 @@ propfile = (os.path.join(os.path.dirname(__file__), 'pyproject.props')) with open(propfile, encoding='utf-8-sig') as f: m = re.search('openssl-([^<]+)<', f.read()) - return "..\..\openssl-"+m.group(1) + return "..\externals\openssl-"+m.group(1) def create_makefile64(makefile, m32): diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -16,7 +16,7 @@ python34$(PyDebugExt) $(OutDir)python$(PyDebugExt).exe $(OutDir)kill_python$(PyDebugExt).exe - ..\.. + ..\externals $(externalsDir)\sqlite-3.8.3.1 $(externalsDir)\bzip2-1.0.6 $(externalsDir)\xz-5.0.5 diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -224,9 +224,10 @@ Unlike the other external libraries listed above, Tk must be built separately before the _tkinter module can be built. This means that - a pre-built Tcl/Tk installation is expected in ..\..\tcltk (tcltk64 - for 64-bit) relative to this directory. See "Getting External - Sources" below for the easiest method to ensure Tcl/Tk is built. + a pre-built Tcl/Tk installation is expected in ..\externals\tcltk + (tcltk64 for 64-bit) relative to this directory. See "Getting + External Sources" below for the easiest method to ensure Tcl/Tk is + built. Getting External Sources @@ -246,12 +247,12 @@ This extracts all the external sub-projects from http://svn.python.org/projects/external via Subversion (so you'll need an svn.exe on your PATH) and places them -in ..\.. (relative to this directory). +in ..\externals (relative to this directory). It is also possible to download sources from each project's homepage, though you may have to change the names of some folders in order to make things work. For instance, if you were to download a version 5.0.7 of -XZ Utils, you would need to extract the archive into ..\..\xz-5.0.5 +XZ Utils, you would need to extract the archive into ..\externals\xz-5.0.5 anyway, since that is where the solution is set to look for xz. The same is true for all other external projects. @@ -268,7 +269,7 @@ So for a release build, you'd call it as: nmake -f makefile.vc MACHINE=AMD64 INSTALLDIR=..\..\tcltk64 clean all install -Note that the above command is called from within ..\..\tcl-8.6.1.0\win +Note that the above command is called from within ..\externals\tcl-8.6.1.0\win (relative to this directory); don't forget to build Tk as well as Tcl! This will be cleaned up in the future; http://bugs.python.org/issue15968 diff --git a/PCbuild/rt.bat b/PCbuild/rt.bat --- a/PCbuild/rt.bat +++ b/PCbuild/rt.bat @@ -38,7 +38,7 @@ if "%1"=="-d" (set suffix=_d) & shift & goto CheckOpts if "%1"=="-x64" (set prefix=amd64) & (set tcltk=tcltk64) & shift & goto CheckOpts -PATH %PATH%;%~dp0..\..\%tcltk%\bin +PATH %PATH%;%~dp0..\externals\%tcltk%\bin set exe=%prefix%\python%suffix% set cmd=%exe% %dashO% -Wd -E -bb ../lib/test/regrtest.py %1 %2 %3 %4 %5 %6 %7 %8 %9 if defined qmode goto Qmode diff --git a/Tools/buildbot/external-common.bat b/Tools/buildbot/external-common.bat --- a/Tools/buildbot/external-common.bat +++ b/Tools/buildbot/external-common.bat @@ -1,7 +1,8 @@ @rem Common file shared between external.bat and external-amd64.bat. Responsible for @rem fetching external components into the root\.. buildbot directories. -cd .. +if not exist externals mkdir externals +cd externals @rem XXX: If you need to force the buildbots to start from a fresh environment, uncomment @rem the following, check it in, then check it out, comment it out, then check it back in. @rem if exist bzip2-1.0.6 rd /s/q bzip2-1.0.6 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 04:50:08 2014 From: python-checkins at python.org (zach.ware) Date: Sun, 02 Nov 2014 03:50:08 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3ODk2?= =?utf-8?q?=3A_Move_Windows_external_lib_sources_from_=2E=2E_to_externals?= =?utf-8?q?=2E?= Message-ID: <20141102035008.109258.13410@psf.io> https://hg.python.org/cpython/rev/62ce0f623154 changeset: 93345:62ce0f623154 branch: 2.7 parent: 93342:bd4dc351d670 user: Zachary Ware date: Sat Nov 01 22:34:09 2014 -0500 summary: Issue #17896: Move Windows external lib sources from .. to externals. files: .gitignore | 1 + .hgignore | 1 + Lib/lib-tk/FixTk.py | 4 +- Misc/NEWS | 3 + PCbuild/build_ssl.py | 2 +- PCbuild/pyproject.vsprops | 2 +- PCbuild/readme.txt | 40 ++--------------- PCbuild/rt.bat | 2 +- Tools/buildbot/external-common.bat | 5 +- 9 files changed, 18 insertions(+), 42 deletions(-) diff --git a/.gitignore b/.gitignore --- a/.gitignore +++ b/.gitignore @@ -43,4 +43,5 @@ tags .coverage coverage/ +externals/ htmlcov/ diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -61,4 +61,5 @@ PCbuild/Win32-temp-* .coverage coverage/ +externals/ htmlcov/ diff --git a/Lib/lib-tk/FixTk.py b/Lib/lib-tk/FixTk.py --- a/Lib/lib-tk/FixTk.py +++ b/Lib/lib-tk/FixTk.py @@ -48,8 +48,8 @@ prefix = os.path.join(sys.prefix,"tcl") if not os.path.exists(prefix): - # devdir/../tcltk/lib - prefix = os.path.join(sys.prefix, os.path.pardir, "tcltk", "lib") + # devdir/externals/tcltk/lib + prefix = os.path.join(sys.prefix, "externals", "tcltk", "lib") prefix = os.path.abspath(prefix) # if this does not exist, no further search is needed if os.path.exists(prefix): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -307,6 +307,9 @@ Windows ------- +- Issue #17896: The Windows build scripts now expect external library sources + to be in ``PCbuild\..\externals`` rather than ``PCbuild\..\..``. + - Issue #17717: The Windows build scripts now use a copy of NASM pulled from svn.python.org to build OpenSSL. diff --git a/PCbuild/build_ssl.py b/PCbuild/build_ssl.py --- a/PCbuild/build_ssl.py +++ b/PCbuild/build_ssl.py @@ -69,7 +69,7 @@ propfile = (os.path.join(os.path.dirname(__file__), 'pyproject.vsprops')) with open(propfile) as f: m = re.search('openssl-([^"]+)"', f.read()) - return "..\..\openssl-"+m.group(1) + return "..\externals\openssl-"+m.group(1) def create_makefile64(makefile, m32): diff --git a/PCbuild/pyproject.vsprops b/PCbuild/pyproject.vsprops --- a/PCbuild/pyproject.vsprops +++ b/PCbuild/pyproject.vsprops @@ -46,7 +46,7 @@ /> linkd.exe external ..\..\trunk\external - Link created at: external - - Only a slight tweak would be needed to the buildbots such that bots - building trunk and py3k could make use of the same facility. (2.5.x - builds need to be kept separate as they're using Visual Studio 7.1.) -/XXX trent.nelson 02-Apr-08 - Building for Itanium -------------------- diff --git a/PCbuild/rt.bat b/PCbuild/rt.bat --- a/PCbuild/rt.bat +++ b/PCbuild/rt.bat @@ -38,7 +38,7 @@ if "%1"=="-d" (set suffix=_d) & shift & goto CheckOpts if "%1"=="-x64" (set prefix=amd64) & (set tcltk=tcltk64) & shift & goto CheckOpts -PATH %PATH%;%~dp0..\..\%tcltk%\bin +PATH %PATH%;%~dp0..\externals\%tcltk%\bin set exe=%prefix%\python%suffix% set cmd=%exe% %dashO% -Wd -3 -E -tt ../lib/test/regrtest.py %1 %2 %3 %4 %5 %6 %7 %8 %9 if defined qmode goto Qmode diff --git a/Tools/buildbot/external-common.bat b/Tools/buildbot/external-common.bat --- a/Tools/buildbot/external-common.bat +++ b/Tools/buildbot/external-common.bat @@ -1,7 +1,8 @@ @rem Common file shared between external.bat and external-amd64.bat. Responsible for - at rem fetching external components into the root\.. buildbot directories. + at rem fetching external components into the root\externals directory. -cd .. +if not exist externals mkdir externals +cd externals @rem XXX: If you need to force the buildbots to start from a fresh environment, uncomment @rem the following, check it in, then check it out, comment it out, then check it back in. @rem if exist bzip2-1.0.6 rd /s/q bzip2-1.0.6 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 04:50:12 2014 From: python-checkins at python.org (zach.ware) Date: Sun, 02 Nov 2014 03:50:12 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317896=3A_Move_Windows_external_lib_sources_from?= =?utf-8?q?_=2E=2E_to_externals=2E?= Message-ID: <20141102035008.109264.23418@psf.io> https://hg.python.org/cpython/rev/64a54f0c87d7 changeset: 93347:64a54f0c87d7 parent: 93344:e119343bc3ec parent: 93346:b5e9bc4352e1 user: Zachary Ware date: Sat Nov 01 22:48:24 2014 -0500 summary: Issue #17896: Move Windows external lib sources from .. to externals. files: .gitignore | 1 + .hgignore | 1 + Lib/tkinter/_fix.py | 4 ++-- Misc/NEWS | 3 +++ PCbuild/get_externals.bat | 3 ++- PCbuild/pyproject.props | 2 +- PCbuild/readme.txt | 2 +- Tools/buildbot/test-amd64.bat | 2 +- Tools/buildbot/test.bat | 2 +- 9 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore --- a/.gitignore +++ b/.gitignore @@ -80,4 +80,5 @@ TAGS .coverage coverage/ +externals/ htmlcov/ diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -93,6 +93,7 @@ Programs/_testembed .coverage coverage/ +externals/ htmlcov/ *.gcda *.gcno diff --git a/Lib/tkinter/_fix.py b/Lib/tkinter/_fix.py --- a/Lib/tkinter/_fix.py +++ b/Lib/tkinter/_fix.py @@ -48,8 +48,8 @@ prefix = os.path.join(sys.base_prefix,"tcl") if not os.path.exists(prefix): - # devdir/../tcltk/lib - prefix = os.path.join(sys.base_prefix, os.path.pardir, "tcltk", "lib") + # devdir/externals/tcltk/lib + prefix = os.path.join(sys.base_prefix, "externals", "tcltk", "lib") prefix = os.path.abspath(prefix) # if this does not exist, no further search is needed if os.path.exists(prefix): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1385,6 +1385,9 @@ Windows ------- +- Issue #17896: The Windows build scripts now expect external library sources + to be in ``PCbuild\..\externals`` rather than ``PCbuild\..\..``. + - Issue #17717: The Windows build scripts now use a copy of NASM pulled from svn.python.org to build OpenSSL. diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -2,7 +2,8 @@ setlocal rem Simple script to fetch source for external libraries -pushd "%~dp0..\.." +if not exist "%~dp0..\externals" mkdir "%~dp0..\externals" +pushd "%~dp0..\externals" if "%SVNROOT%"=="" set SVNROOT=http://svn.python.org/projects/external/ diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -16,7 +16,7 @@ python35$(PyDebugExt) $(OutDir)python$(PyDebugExt).exe $(OutDir)kill_python$(PyDebugExt).exe - ..\.. + ..\externals $(externalsDir)\sqlite-3.8.3.1 $(externalsDir)\bzip2-1.0.6 $(externalsDir)\xz-5.0.5 diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -278,7 +278,7 @@ directory. This script extracts all the external sub-projects from http://svn.python.org/projects/external via Subversion (so you'll need svn.exe on your PATH) and places them -in ..\.. (relative to this directory). +in ..\externals (relative to this directory). It is also possible to download sources from each project's homepage, though you may have to change folder names or pass the names to MSBuild diff --git a/Tools/buildbot/test-amd64.bat b/Tools/buildbot/test-amd64.bat --- a/Tools/buildbot/test-amd64.bat +++ b/Tools/buildbot/test-amd64.bat @@ -2,6 +2,6 @@ setlocal rem The following line should be removed before #20035 is closed -set TCL_LIBRARY=%~dp0..\..\..\tcltk64\lib\tcl8.6 +set TCL_LIBRARY=%~dp0..\..\externals\tcltk64\lib\tcl8.6 call "%~dp0..\..\PCbuild\rt.bat" -d -q -x64 -uall -rwW -n --timeout=3600 %* diff --git a/Tools/buildbot/test.bat b/Tools/buildbot/test.bat --- a/Tools/buildbot/test.bat +++ b/Tools/buildbot/test.bat @@ -2,6 +2,6 @@ setlocal rem The following line should be removed before #20035 is closed -set TCL_LIBRARY=%~dp0..\..\..\tcltk\lib\tcl8.6 +set TCL_LIBRARY=%~dp0..\..\externals\tcltk\lib\tcl8.6 call "%~dp0..\..\PCbuild\rt.bat" -d -q -uall -rwW -n --timeout=3600 %* -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Sun Nov 2 10:04:17 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 02 Nov 2014 10:04:17 +0100 Subject: [Python-checkins] Daily reference leaks (ef15b51d59fb): sum=3 Message-ID: results for ef15b51d59fb on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogLigs4a', '-x'] From python-checkins at python.org Sun Nov 2 17:13:57 2014 From: python-checkins at python.org (ezio.melotti) Date: Sun, 02 Nov 2014 16:13:57 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Fix_commas_and_whitespace_in_?= =?utf-8?q?PEP_473=2E?= Message-ID: <20141102161355.35250.45664@psf.io> https://hg.python.org/peps/rev/8e9097a145dd changeset: 5592:8e9097a145dd user: Ezio Melotti date: Sun Nov 02 18:13:45 2014 +0200 summary: Fix commas and whitespace in PEP 473. files: pep-0473.txt | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pep-0473.txt b/pep-0473.txt --- a/pep-0473.txt +++ b/pep-0473.txt @@ -14,7 +14,7 @@ ======== Exceptions like ``AttributeError``, ``IndexError``, ``KeyError``, -``LookupError``, ``NameError``, , ``TypeError`` and ``ValueError`` do not +``LookupError``, ``NameError``, ``TypeError``, and ``ValueError`` do not provide all information required by programmers to debug and better understand what caused them. Furthermore, in some cases the messages even have slightly different formats, @@ -47,7 +47,7 @@ A similar proposal [2]_ has been implemented for ``ImportError`` and in the same fashion this idea has received support [3]_. Additionally, almost 10 years ago Guido asked in [11]_ to have a clean API to access the affected objects in -Exceptions like ``KeyError``, ``AttributeError``, ``NameError`` and +Exceptions like ``KeyError``, ``AttributeError``, ``NameError``, and ``IndexError``. Similar issues and proposals ideas have been written in the last year. Some other issues have been created, but despite receiving support they finally get abandoned. References to the created issues are listed below: @@ -157,7 +157,7 @@ ======== Extend the exceptions ``AttributeError``, ``IndexError``, ``KeyError``, -``LookupError``, ``NameError``, , ``TypeError`` and ``ValueError`` with the +``LookupError``, ``NameError``, ``TypeError``, and ``ValueError`` with the following: * ``AttributeError``: target :sup:`w`, attribute -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Sun Nov 2 18:15:42 2014 From: python-checkins at python.org (ezio.melotti) Date: Sun, 02 Nov 2014 17:15:42 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzIyNzUxOiBmaXgg?= =?utf-8?q?test=5F=5F=5Fall=5F=5F_warning_about_modified_environment_in_th?= =?utf-8?q?e_tests=2E?= Message-ID: <20141102171539.109268.76886@psf.io> https://hg.python.org/cpython/rev/16dfefe67c1f changeset: 93349:16dfefe67c1f branch: 2.7 parent: 93345:62ce0f623154 user: Ezio Melotti date: Sun Nov 02 19:08:35 2014 +0200 summary: #22751: fix test___all__ warning about modified environment in the tests. Patch by Michael Cetrulo. files: Lib/test/test___all__.py | 7 ++++--- Misc/ACKS | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Lib/test/test___all__.py b/Lib/test/test___all__.py --- a/Lib/test/test___all__.py +++ b/Lib/test/test___all__.py @@ -75,13 +75,14 @@ # rlcompleter needs special consideration; it imports readline which # initializes GNU readline which calls setlocale(LC_CTYPE, "")... :-( + import locale + locale_tuple = locale.getlocale(locale.LC_CTYPE) try: import rlcompleter - import locale except ImportError: pass - else: - locale.setlocale(locale.LC_CTYPE, 'C') + finally: + locale.setlocale(locale.LC_CTYPE, locale_tuple) ignored = [] failed_imports = [] diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -218,6 +218,7 @@ Matej Cepl Carl Cerecke Octavian Cerna +Michael Cetrulo Dave Chambers Pascal Chambon John Chandler -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 18:15:43 2014 From: python-checkins at python.org (ezio.melotti) Date: Sun, 02 Nov 2014 17:15:43 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogIzIyNzUxOiBtZXJnZSB3aXRoIDMuNC4=?= Message-ID: <20141102171539.120722.54329@psf.io> https://hg.python.org/cpython/rev/3c030e4da7c6 changeset: 93350:3c030e4da7c6 parent: 93347:64a54f0c87d7 parent: 93348:37ed6eed0595 user: Ezio Melotti date: Sun Nov 02 19:14:54 2014 +0200 summary: #22751: merge with 3.4. files: Lib/test/test___all__.py | 7 ++++--- Misc/ACKS | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Lib/test/test___all__.py b/Lib/test/test___all__.py --- a/Lib/test/test___all__.py +++ b/Lib/test/test___all__.py @@ -72,13 +72,14 @@ # rlcompleter needs special consideration; it import readline which # initializes GNU readline which calls setlocale(LC_CTYPE, "")... :-( + import locale + locale_tuple = locale.getlocale(locale.LC_CTYPE) try: import rlcompleter - import locale except ImportError: pass - else: - locale.setlocale(locale.LC_CTYPE, 'C') + finally: + locale.setlocale(locale.LC_CTYPE, locale_tuple) ignored = [] failed_imports = [] diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -224,6 +224,7 @@ Matej Cepl Carl Cerecke Octavian Cerna +Michael Cetrulo Dave Chambers Pascal Chambon John Chandler -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 18:15:43 2014 From: python-checkins at python.org (ezio.melotti) Date: Sun, 02 Nov 2014 17:15:43 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogIzIyNzUxOiBmaXgg?= =?utf-8?q?test=5F=5F=5Fall=5F=5F_warning_about_modified_environment_in_th?= =?utf-8?q?e_tests=2E?= Message-ID: <20141102171539.101688.28249@psf.io> https://hg.python.org/cpython/rev/37ed6eed0595 changeset: 93348:37ed6eed0595 branch: 3.4 parent: 93346:b5e9bc4352e1 user: Ezio Melotti date: Sun Nov 02 19:08:35 2014 +0200 summary: #22751: fix test___all__ warning about modified environment in the tests. Patch by Michael Cetrulo. files: Lib/test/test___all__.py | 7 ++++--- Misc/ACKS | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Lib/test/test___all__.py b/Lib/test/test___all__.py --- a/Lib/test/test___all__.py +++ b/Lib/test/test___all__.py @@ -72,13 +72,14 @@ # rlcompleter needs special consideration; it import readline which # initializes GNU readline which calls setlocale(LC_CTYPE, "")... :-( + import locale + locale_tuple = locale.getlocale(locale.LC_CTYPE) try: import rlcompleter - import locale except ImportError: pass - else: - locale.setlocale(locale.LC_CTYPE, 'C') + finally: + locale.setlocale(locale.LC_CTYPE, locale_tuple) ignored = [] failed_imports = [] diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -222,6 +222,7 @@ Matej Cepl Carl Cerecke Octavian Cerna +Michael Cetrulo Dave Chambers Pascal Chambon John Chandler -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 18:29:27 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Nov 2014 17:29:27 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy40IC0+IDMuNCk6?= =?utf-8?q?_Merge_heads?= Message-ID: <20141102172927.35248.50233@psf.io> https://hg.python.org/cpython/rev/a5dd8e89d4da changeset: 93353:a5dd8e89d4da branch: 3.4 parent: 93351:e3825486da53 parent: 93348:37ed6eed0595 user: Serhiy Storchaka date: Sun Nov 02 19:26:23 2014 +0200 summary: Merge heads files: Lib/test/test___all__.py | 7 ++++--- Misc/ACKS | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Lib/test/test___all__.py b/Lib/test/test___all__.py --- a/Lib/test/test___all__.py +++ b/Lib/test/test___all__.py @@ -72,13 +72,14 @@ # rlcompleter needs special consideration; it import readline which # initializes GNU readline which calls setlocale(LC_CTYPE, "")... :-( + import locale + locale_tuple = locale.getlocale(locale.LC_CTYPE) try: import rlcompleter - import locale except ImportError: pass - else: - locale.setlocale(locale.LC_CTYPE, 'C') + finally: + locale.setlocale(locale.LC_CTYPE, locale_tuple) ignored = [] failed_imports = [] diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -222,6 +222,7 @@ Matej Cepl Carl Cerecke Octavian Cerna +Michael Cetrulo Dave Chambers Pascal Chambon John Chandler -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 18:29:27 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Nov 2014 17:29:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Null_merge?= Message-ID: <20141102172927.120714.44184@psf.io> https://hg.python.org/cpython/rev/769a217764f2 changeset: 93355:769a217764f2 parent: 93354:0ea8a5bdc2f0 parent: 93353:a5dd8e89d4da user: Serhiy Storchaka date: Sun Nov 02 19:26:48 2014 +0200 summary: Null merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 18:29:28 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Nov 2014 17:29:28 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_heads?= Message-ID: <20141102172927.35270.83839@psf.io> https://hg.python.org/cpython/rev/0ea8a5bdc2f0 changeset: 93354:0ea8a5bdc2f0 parent: 93352:5f10a4a1e4df parent: 93350:3c030e4da7c6 user: Serhiy Storchaka date: Sun Nov 02 19:26:28 2014 +0200 summary: Merge heads files: Lib/test/test___all__.py | 7 ++++--- Misc/ACKS | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Lib/test/test___all__.py b/Lib/test/test___all__.py --- a/Lib/test/test___all__.py +++ b/Lib/test/test___all__.py @@ -72,13 +72,14 @@ # rlcompleter needs special consideration; it import readline which # initializes GNU readline which calls setlocale(LC_CTYPE, "")... :-( + import locale + locale_tuple = locale.getlocale(locale.LC_CTYPE) try: import rlcompleter - import locale except ImportError: pass - else: - locale.setlocale(locale.LC_CTYPE, 'C') + finally: + locale.setlocale(locale.LC_CTYPE, locale_tuple) ignored = [] failed_imports = [] diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -224,6 +224,7 @@ Matej Cepl Carl Cerecke Octavian Cerna +Michael Cetrulo Dave Chambers Pascal Chambon John Chandler -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 18:29:27 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Nov 2014 17:29:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322388=3A_Unified_the_style_of_=22Contributed_by?= =?utf-8?q?=22_sentences_in_What=27s_New=2E?= Message-ID: <20141102172926.35260.88422@psf.io> https://hg.python.org/cpython/rev/5f10a4a1e4df changeset: 93352:5f10a4a1e4df parent: 93347:64a54f0c87d7 parent: 93351:e3825486da53 user: Serhiy Storchaka date: Sun Nov 02 19:22:02 2014 +0200 summary: Issue #22388: Unified the style of "Contributed by" sentences in What's New. files: Doc/whatsnew/3.3.rst | 102 ++++++++++++++-------------- Doc/whatsnew/3.4.rst | 112 +++++++++++++++--------------- Doc/whatsnew/3.5.rst | 61 ++++++++-------- 3 files changed, 138 insertions(+), 137 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 @@ -171,7 +171,7 @@ * Multi-dimensional comparisons are supported for any array type. * One-dimensional memoryviews of hashable (read-only) types with formats B, - b or c are now hashable. (Contributed by Antoine Pitrou in :issue:`13411`) + b or c are now hashable. (Contributed by Antoine Pitrou in :issue:`13411`.) * Arbitrary slicing of any 1-D arrays type is supported. For example, it is now possible to reverse a memoryview in O(1) by using a negative step. @@ -196,7 +196,7 @@ * For further changes see `Build and C API Changes`_ and `Porting C code`_. -(Contributed by Stefan Krah in :issue:`10181`) +(Contributed by Stefan Krah in :issue:`10181`.) .. seealso:: @@ -307,8 +307,8 @@ Python version when a more recent version is installed). In addition to the launcher, the Windows installer now includes an -option to add the newly installed Python to the system PATH (contributed -by Brian Curtin in :issue:`3561`). +option to add the newly installed Python to the system PATH. (Contributed +by Brian Curtin in :issue:`3561`.) .. seealso:: @@ -781,7 +781,7 @@ Both :func:`unicodedata.lookup()` and ``'\N{...}'`` now resolve name aliases, and :func:`unicodedata.lookup()` resolves named sequences too. - (Contributed by Ezio Melotti in :issue:`12753`) + (Contributed by Ezio Melotti in :issue:`12753`.) * Unicode database updated to UCD version 6.1.0 @@ -793,7 +793,7 @@ methods of :class:`bytes` and :class:`bytearray` objects now accept an integer between 0 and 255 as their first argument. - (Contributed by Petri Lehtinen in :issue:`12170`) + (Contributed by Petri Lehtinen in :issue:`12170`.) * The ``rjust()``, ``ljust()``, and ``center()`` methods of :class:`bytes` and :class:`bytearray` now accept a :class:`bytearray` for the ``fill`` @@ -854,7 +854,7 @@ * The sequence documentation has been substantially rewritten to better explain the binary/text sequence distinction and to provide specific documentation sections for the individual builtin sequence types - (:issue:`4966`) + (:issue:`4966`). New Modules @@ -891,7 +891,7 @@ objects representing IPv4 and IPv6 addresses, networks and interfaces (i.e. an IP address associated with a specific IP subnet). -(Contributed by Google and Peter Moody in :pep:`3144`) +(Contributed by Google and Peter Moody in :pep:`3144`.) lzma ---- @@ -900,7 +900,7 @@ using the LZMA algorithm, including support for the ``.xz`` and ``.lzma`` file formats. -(Contributed by Nadeem Vawda and Per ?yvind Karlsen in :issue:`6715`) +(Contributed by Nadeem Vawda and Per ?yvind Karlsen in :issue:`6715`.) Improved Modules @@ -921,7 +921,7 @@ * :class:`abc.abstractstaticmethod` has been deprecated, use :class:`staticmethod` with :func:`abc.abstractmethod` instead. -(Contributed by Darren Dale in :issue:`11610`) +(Contributed by Darren Dale in :issue:`11610`.) :meth:`abc.ABCMeta.register` now returns the registered subclass, which means it can now be used as a class decorator (:issue:`10868`). @@ -933,7 +933,7 @@ The :mod:`array` module supports the :c:type:`long long` type using ``q`` and ``Q`` type codes. -(Contributed by Oren Tirosh and Hirokazu Yamamoto in :issue:`1172711`) +(Contributed by Oren Tirosh and Hirokazu Yamamoto in :issue:`1172711`.) base64 @@ -964,14 +964,14 @@ * :class:`bz2.BZ2File` can now read from and write to arbitrary file-like objects, by means of its constructor's *fileobj* argument. - (Contributed by Nadeem Vawda in :issue:`5863`) + (Contributed by Nadeem Vawda in :issue:`5863`.) * :class:`bz2.BZ2File` and :func:`bz2.decompress` can now decompress multi-stream inputs (such as those produced by the :program:`pbzip2` tool). :class:`bz2.BZ2File` can now also be used to create this type of file, using the ``'a'`` (append) mode. - (Contributed by Nir Aides in :issue:`1625`) + (Contributed by Nir Aides in :issue:`1625`.) * :class:`bz2.BZ2File` now implements all of the :class:`io.BufferedIOBase` API, except for the :meth:`detach` and :meth:`truncate` methods. @@ -1018,7 +1018,7 @@ Addition of a new :class:`~collections.ChainMap` class to allow treating a number of mappings as a single unit. (Written by Raymond Hettinger for -:issue:`11089`, made public in :issue:`11297`) +:issue:`11089`, made public in :issue:`11297`.) The abstract base classes have been moved in a new :mod:`collections.abc` module, to better differentiate between the abstract and the concrete @@ -1069,7 +1069,7 @@ push a wide character so the next :meth:`~curses.window.get_wch` will return it -(Contributed by I?igo Serna in :issue:`6755`) +(Contributed by I?igo Serna in :issue:`6755`.) datetime -------- @@ -1376,11 +1376,11 @@ :func:`~ftplib.FTP_TLS.ccc` function to revert control channel back to plaintext. This can be useful to take advantage of firewalls that know how to handle NAT with non-secure FTP without opening fixed ports. (Contributed - by Giampaolo Rodol? in :issue:`12139`) + by Giampaolo Rodol? in :issue:`12139`.) * Added :meth:`ftplib.FTP.mlsd` method which provides a parsable directory listing format and deprecates :meth:`ftplib.FTP.nlst` and - :meth:`ftplib.FTP.dir`. (Contributed by Giampaolo Rodol? in :issue:`11072`) + :meth:`ftplib.FTP.dir`. (Contributed by Giampaolo Rodol? in :issue:`11072`.) functools @@ -1404,7 +1404,7 @@ A new :func:`~hmac.compare_digest` function has been added to prevent side channel attacks on digests through timing analysis. (Contributed by Nick -Coghlan and Christian Heimes in :issue:`15061`) +Coghlan and Christian Heimes in :issue:`15061`.) http @@ -1436,13 +1436,13 @@ (Contributed by Ezio Melotti in :issue:`15114`, and :issue:`14538`, :issue:`13993`, :issue:`13960`, :issue:`13358`, :issue:`1745761`, :issue:`755670`, :issue:`13357`, :issue:`12629`, :issue:`1200313`, -:issue:`670664`, :issue:`13273`, :issue:`12888`, :issue:`7311`) +:issue:`670664`, :issue:`13273`, :issue:`12888`, :issue:`7311`.) A new :data:`~html.entities.html5` dictionary that maps HTML5 named character references to the equivalent Unicode character(s) (e.g. ``html5['gt;'] == '>'``) has been added to the :mod:`html.entities` module. The dictionary is now also used by :class:`~html.parser.HTMLParser`. (Contributed by Ezio -Melotti in :issue:`11113` and :issue:`15156`) +Melotti in :issue:`11113` and :issue:`15156`.) imaplib @@ -1451,7 +1451,7 @@ The :class:`~imaplib.IMAP4_SSL` constructor now accepts an SSLContext parameter to control parameters of the secure channel. -(Contributed by Sijin Joseph in :issue:`8808`) +(Contributed by Sijin Joseph in :issue:`8808`.) inspect @@ -1462,14 +1462,14 @@ where those names were resolved, making it easier to verify correct internal state when testing code that relies on stateful closures. -(Contributed by Meador Inge and Nick Coghlan in :issue:`13062`) +(Contributed by Meador Inge and Nick Coghlan in :issue:`13062`.) A new :func:`~inspect.getgeneratorlocals` function has been added. This function reports the current binding of local variables in the generator's stack frame, making it easier to verify correct internal state when testing generators. -(Contributed by Meador Inge in :issue:`15153`) +(Contributed by Meador Inge in :issue:`15153`.) io -- @@ -1478,7 +1478,7 @@ exclusively create a new file, and raise a :exc:`FileExistsError` if the file already exists. It is based on the C11 'x' mode to fopen(). -(Contributed by David Townshend in :issue:`12760`) +(Contributed by David Townshend in :issue:`12760`.) The constructor of the :class:`~io.TextIOWrapper` class has a new *write_through* optional argument. If *write_through* is ``True``, calls to @@ -1513,7 +1513,7 @@ The :mod:`math` module has a new function, :func:`~math.log2`, which returns the base-2 logarithm of *x*. -(Written by Mark Dickinson in :issue:`11888`). +(Written by Mark Dickinson in :issue:`11888`.) mmap @@ -1567,7 +1567,7 @@ ('211 1755 1 1755 gmane.comp.python.committers', 1755, 1, 1755, 'gmane.comp.python.committers') >>> -(Contributed by Giampaolo Rodol? in :issue:`9795`) +(Contributed by Giampaolo Rodol? in :issue:`9795`.) os @@ -1744,24 +1744,24 @@ set to False makes the method execute the scheduled events due to expire soonest (if any) and then return immediately. This is useful in case you want to use the :class:`~sched.scheduler` in - non-blocking applications. (Contributed by Giampaolo Rodol? in :issue:`13449`) + non-blocking applications. (Contributed by Giampaolo Rodol? in :issue:`13449`.) * :class:`~sched.scheduler` class can now be safely used in multi-threaded environments. (Contributed by Josiah Carlson and Giampaolo Rodol? in - :issue:`8684`) + :issue:`8684`.) * *timefunc* and *delayfunct* parameters of :class:`~sched.scheduler` class constructor are now optional and defaults to :func:`time.time` and :func:`time.sleep` respectively. (Contributed by Chris Clark in - :issue:`13245`) + :issue:`13245`.) * :meth:`~sched.scheduler.enter` and :meth:`~sched.scheduler.enterabs` *argument* parameter is now optional. (Contributed by Chris Clark in - :issue:`13245`) + :issue:`13245`.) * :meth:`~sched.scheduler.enter` and :meth:`~sched.scheduler.enterabs` now accept a *kwargs* parameter. (Contributed by Chris Clark in - :issue:`13245`) + :issue:`13245`.) select @@ -1787,10 +1787,10 @@ * New functions: * :func:`~shutil.disk_usage`: provides total, used and free disk space - statistics. (Contributed by Giampaolo Rodol? in :issue:`12442`) + statistics. (Contributed by Giampaolo Rodol? in :issue:`12442`.) * :func:`~shutil.chown`: allows one to change user and/or group of the given path also specifying the user/group names and not only their numeric - ids. (Contributed by Sandro Tosi in :issue:`12191`) + ids. (Contributed by Sandro Tosi in :issue:`12191`.) * :func:`shutil.get_terminal_size`: returns the size of the terminal window to which the interpreter is attached. (Contributed by Zbigniew J?drzejewski-Szmek in :issue:`13609`.) @@ -1813,7 +1813,7 @@ * :func:`~shutil.rmtree` is now resistant to symlink attacks on platforms which support the new ``dir_fd`` parameter in :func:`os.open` and - :func:`os.unlink`. (Contributed by Martin von L?wis and Hynek Schlawack + :func:`os.unlink`. (Contributed by Martin von L?wis and Hynek Schlawack in :issue:`4489`.) @@ -1867,7 +1867,7 @@ The :class:`~smtplib.SMTP_SSL` constructor and the :meth:`~smtplib.SMTP.starttls` method now accept an SSLContext parameter to control parameters of the secure -channel. (Contributed by Kasun Herath in :issue:`8809`) +channel. (Contributed by Kasun Herath in :issue:`8809`.) socket @@ -1887,7 +1887,7 @@ (http://en.wikipedia.org/wiki/Socketcan), on Linux (http://lwn.net/Articles/253425). - (Contributed by Matthias Fuchs, updated by Tiago Gon?alves in :issue:`10141`) + (Contributed by Matthias Fuchs, updated by Tiago Gon?alves in :issue:`10141`.) * The :class:`~socket.socket` class now supports the PF_RDS protocol family (http://en.wikipedia.org/wiki/Reliable_Datagram_Sockets and @@ -1929,37 +1929,37 @@ pseudo-random bytes. * :func:`~ssl.RAND_pseudo_bytes`: generate pseudo-random bytes. - (Contributed by Victor Stinner in :issue:`12049`) + (Contributed by Victor Stinner in :issue:`12049`.) * The :mod:`ssl` module now exposes a finer-grained exception hierarchy in order to make it easier to inspect the various kinds of errors. - (Contributed by Antoine Pitrou in :issue:`11183`) + (Contributed by Antoine Pitrou in :issue:`11183`.) * :meth:`~ssl.SSLContext.load_cert_chain` now accepts a *password* argument to be used if the private key is encrypted. - (Contributed by Adam Simpkins in :issue:`12803`) + (Contributed by Adam Simpkins in :issue:`12803`.) * Diffie-Hellman key exchange, both regular and Elliptic Curve-based, is now supported through the :meth:`~ssl.SSLContext.load_dh_params` and :meth:`~ssl.SSLContext.set_ecdh_curve` methods. - (Contributed by Antoine Pitrou in :issue:`13626` and :issue:`13627`) + (Contributed by Antoine Pitrou in :issue:`13626` and :issue:`13627`.) * SSL sockets have a new :meth:`~ssl.SSLSocket.get_channel_binding` method allowing the implementation of certain authentication mechanisms such as - SCRAM-SHA-1-PLUS. (Contributed by Jacek Konieczny in :issue:`12551`) + SCRAM-SHA-1-PLUS. (Contributed by Jacek Konieczny in :issue:`12551`.) * You can query the SSL compression algorithm used by an SSL socket, thanks to its new :meth:`~ssl.SSLSocket.compression` method. The new attribute :attr:`~ssl.OP_NO_COMPRESSION` can be used to disable compression. - (Contributed by Antoine Pitrou in :issue:`13634`) + (Contributed by Antoine Pitrou in :issue:`13634`.) * Support has been added for the Next Procotol Negotiation extension using the :meth:`ssl.SSLContext.set_npn_protocols` method. - (Contributed by Colin Marc in :issue:`14204`) + (Contributed by Colin Marc in :issue:`14204`.) * SSL errors can now be introspected more easily thanks to :attr:`~ssl.SSLError.library` and :attr:`~ssl.SSLError.reason` attributes. - (Contributed by Antoine Pitrou in :issue:`14837`) + (Contributed by Antoine Pitrou in :issue:`14837`.) * The :func:`~ssl.get_server_certificate` function now supports IPv6. (Contributed by Charles-Fran?ois Natali in :issue:`11811`.) @@ -1976,7 +1976,7 @@ :func:`stat.filemode`. It can be used to convert a file's mode to a string of the form '-rwxrwxrwx'. -(Contributed by Giampaolo Rodol? in :issue:`14807`) +(Contributed by Giampaolo Rodol? in :issue:`14807`.) struct @@ -2035,8 +2035,8 @@ :class:`threading.Condition`, :class:`threading.Semaphore`, :class:`threading.BoundedSemaphore`, :class:`threading.Event`, and :class:`threading.Timer`, all of which used to be factory functions returning a -class instance, are now classes and may be subclassed. (Contributed by ?ric -Araujo in :issue:`10968`). +class instance, are now classes and may be subclassed. (Contributed by ?ric +Araujo in :issue:`10968`.) The :class:`threading.Thread` constructor now accepts a ``daemon`` keyword argument to override the default behavior of inheriting the ``deamon`` flag @@ -2066,7 +2066,7 @@ * :func:`~time.clock_getres`, :func:`~time.clock_gettime` and :func:`~time.clock_settime` functions with ``CLOCK_xxx`` constants. - (Contributed by Victor Stinner in :issue:`10278`) + (Contributed by Victor Stinner in :issue:`10278`.) To improve cross platform consistency, :func:`~time.sleep` now raises a :exc:`ValueError` when passed a negative sleep value. Previously this was an @@ -2090,7 +2090,7 @@ :meth:`.assertRaises`, :meth:`.assertRaisesRegex`, :meth:`.assertWarns`, and :meth:`.assertWarnsRegex` now accept a keyword argument *msg* when used as context managers. (Contributed by Ezio Melotti and Winston Ewert in -:issue:`10775`) +:issue:`10775`.) :meth:`unittest.TestCase.run` now returns the :class:`~unittest.TestResult` object. @@ -2117,7 +2117,7 @@ and the generic launchers :program:`xdg-open`, from the FreeDesktop.org project, and :program:`gvfs-open`, which is the default URI handler for GNOME 3. (The former contributed by Arnaud Calmettes in :issue:`13620`, the latter -by Matthias Klose in :issue:`14493`) +by Matthias Klose in :issue:`14493`.) xml.etree.ElementTree @@ -2160,7 +2160,7 @@ * UTF-8 is now 2x to 4x faster. UTF-16 encoding is now up to 10x faster. - (contributed by Serhiy Storchaka, :issue:`14624`, :issue:`14738` and + (Contributed by Serhiy Storchaka, :issue:`14624`, :issue:`14738` and :issue:`15026`.) 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 @@ -52,7 +52,7 @@ * It's helpful to add the bug/patch number as a comment: The :ref:`~socket.transmogrify()` function was added to the - :mod:`socket` module. (Contributed by P.Y. Developer in :issue:`12345`.) + :mod:`socket` module. (Contributed by P.Y. Developer in :issue:`12345`.) This saves the maintainer the effort of going through the Mercurial log when researching a change. @@ -372,7 +372,7 @@ in :ref:`binary-transforms` and :ref:`text-transforms`. (Contributed by Nick Coghlan in :issue:`7475`, :issue:`17827`, -:issue:`17828` and :issue:`19619`) +:issue:`17828` and :issue:`19619`.) .. _whatsnew-pep-451: @@ -414,14 +414,14 @@ * Module ``__file__`` attributes (and related values) should now always contain absolute paths by default, with the sole exception of ``__main__.__file__`` when a script has been executed directly using - a relative path (Contributed by Brett Cannon in :issue:`18416`). + a relative path. (Contributed by Brett Cannon in :issue:`18416`.) * All the UTF-\* codecs (except UTF-7) now reject surrogates during both encoding and decoding unless the ``surrogatepass`` error handler is used, with the exception of the UTF-16 decoder (which accepts valid surrogate pairs) and the UTF-16 encoder (which produces them while encoding non-BMP characters). - Contributed by Victor Stinner, Kang-Hao (Kenny) Lu and Serhiy Storchaka in - :issue:`12892`. + (Contributed by Victor Stinner, Kang-Hao (Kenny) Lu and Serhiy Storchaka in + :issue:`12892`.) * New German EBCDIC :ref:`codec ` ``cp273``. (Contributed by Michael Bierenfeld and Andrew Kuchling in :issue:`1097797`.) @@ -633,8 +633,8 @@ in :issue:`12866`.) New :func:`~audioop.byteswap` function converts big-endian samples to -little-endian and vice versa (Contributed by Serhiy Storchaka in -:issue:`19641`). +little-endian and vice versa. (Contributed by Serhiy Storchaka in +:issue:`19641`.) All :mod:`audioop` functions now accept any :term:`bytes-like object`. Strings are not accepted: they didn't work before, now they raise an error right away. @@ -681,8 +681,8 @@ The new :class:`contextlib.suppress` context manager helps to clarify the intent of code that deliberately suppresses exceptions from a single -statement. (Contributed by Raymond Hettinger in :issue:`15806` and -Zero Piraeus in :issue:`19266`) +statement. (Contributed by Raymond Hettinger in :issue:`15806` and +Zero Piraeus in :issue:`19266`.) The new :func:`contextlib.redirect_stdout` context manager makes it easier for utility scripts to handle inflexible APIs that write their output to @@ -693,7 +693,7 @@ from a function that was written to implement a command line interface. It is recommended only for utility scripts because it affects the global state of :data:`sys.stdout`. (Contributed by Raymond Hettinger -in :issue:`15805`) +in :issue:`15805`.) The :mod:`contextlib` documentation has also been updated to include a :ref:`discussion ` of the @@ -765,7 +765,7 @@ to ``distb(tb)``). (Contributed by Nick Coghlan, Ryan Kelly and Thomas Kluyver in :issue:`11816` -and Claudiu Popa in :issue:`17916`) +and Claudiu Popa in :issue:`17916`.) New function :func:`~dis.stack_effect` computes the effect on the Python stack of a given opcode and argument, information that is not otherwise available. @@ -855,7 +855,7 @@ for normal callables. The new descriptor also makes it easier to get arbitrary callables (including :func:`~functools.partial` instances) to behave like normal instance methods when included in a class definition. -(Contributed by Alon Horev and Nick Coghlan in :issue:`4331`) +(Contributed by Alon Horev and Nick Coghlan in :issue:`4331`.) .. _whatsnew-singledispatch: @@ -903,7 +903,7 @@ A new :func:`hashlib.pbkdf2_hmac` function provides the `PKCS#5 password-based key derivation function 2 `_. (Contributed by Christian -Heimes in :issue:`18582`) +Heimes in :issue:`18582`.) The :attr:`~hashlib.hash.name` attribute of :mod:`hashlib` hash objects is now a formally supported interface. It has always existed in CPython's @@ -939,17 +939,17 @@ New function :func:`~html.unescape` function converts HTML5 character references to the corresponding Unicode characters. (Contributed by Ezio Melotti in -:issue:`2927`) +:issue:`2927`.) :class:`~html.parser.HTMLParser` accepts a new keyword argument *convert_charrefs* that, when ``True``, automatically converts all character references. For backward-compatibility, its value defaults to ``False``, but it will change to ``True`` in a future version of Python, so you are invited to set it explicitly and update your code to use this new feature. (Contributed -by Ezio Melotti in :issue:`13633`) +by Ezio Melotti in :issue:`13633`.) The *strict* argument of :class:`~html.parser.HTMLParser` is now deprecated. -(Contributed by Ezio Melotti in :issue:`15114`) +(Contributed by Ezio Melotti in :issue:`15114`.) http @@ -1015,19 +1015,19 @@ The :mod:`inspect` module now offers a basic :ref:`command line interface ` to quickly display source code and other -information for modules, classes and functions. (Contributed by Claudiu Popa -and Nick Coghlan in :issue:`18626`) +information for modules, classes and functions. (Contributed by Claudiu Popa +and Nick Coghlan in :issue:`18626`.) :func:`~inspect.unwrap` makes it easy to unravel wrapper function chains created by :func:`functools.wraps` (and any other API that sets the -``__wrapped__`` attribute on a wrapper function). (Contributed by -Daniel Urban, Aaron Iles and Nick Coghlan in :issue:`13266`) +``__wrapped__`` attribute on a wrapper function). (Contributed by +Daniel Urban, Aaron Iles and Nick Coghlan in :issue:`13266`.) As part of the implementation of the new :mod:`enum` module, the :mod:`inspect` module now has substantially better support for custom ``__dir__`` methods and dynamic class attributes provided through -metaclasses (Contributed by Ethan Furman in :issue:`18929` and -:issue:`19030`) +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 @@ -1038,11 +1038,11 @@ attributes, and report the already bound first argument for bound methods, so it is still necessary to update your code to use :func:`~inspect.signature` directly if those features are desired. -(Contributed by Yury Selivanov in :issue:`17481`) +(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`) +which adds support for functions compiled with Cython. (Contributed +by Stefan Behnel and Yury Selivanov in :issue:`17159`.) ipaddress @@ -1082,7 +1082,7 @@ Logging configuration data received from a socket via the :func:`logging.config.listen` function can now be validated before being processed by supplying a verification function as the argument to the new -*verify* keyword argument. (Contributed by Vinay Sajip in :issue:`15452`.) +*verify* keyword argument. (Contributed by Vinay Sajip in :issue:`15452`.) .. _whatsnew-marshal-3: @@ -1120,7 +1120,7 @@ :func:`~multiprocessing.get_all_start_methods` reports all start methods available on the platform, :func:`~multiprocessing.get_start_method` reports the current start method, and :func:`~multiprocessing.set_start_method` sets -the start method. (Contributed by Richard Oudkerk in :issue:`8713`). +the start method. (Contributed by Richard Oudkerk in :issue:`8713`.) :mod:`multiprocessing` also now has the concept of a ``context``, which determines how child processes are created. New function @@ -1141,7 +1141,7 @@ when using the ``spawn`` or ``forkserver`` start methods. This resolves some edge cases where combining multiprocessing, the ``-m`` command line switch, and explicit relative imports could cause obscure failures in child -processes. (Contributed by Nick Coghlan in :issue:`19946`) +processes. (Contributed by Nick Coghlan in :issue:`19946`.) operator @@ -1176,7 +1176,7 @@ Windows). (Contributed by Brian Curtin in :issue:`11939`.) :func:`os.path.ismount` now recognizes volumes mounted below a drive -root on Windows. (Contributed by Tim Golden in :issue:`9035`.) +root on Windows. (Contributed by Tim Golden in :issue:`9035`.) :func:`os.open` supports two new flags on platforms that provide them, :data:`~os.O_PATH` (un-opened file descriptor), and :data:`~os.O_TMPFILE` @@ -1230,7 +1230,7 @@ functions. (The older API is now deprecated.) In addition to the already supported XML plist format (:data:`~plistlib.FMT_XML`), it also now supports the binary plist format (:data:`~plistlib.FMT_BINARY`). (Contributed by Ronald -Oussoren and others in :issue:`14455`). +Oussoren and others in :issue:`14455`.) poplib @@ -1254,7 +1254,7 @@ (Contributed by Serhiy Storchaka in :issue:`19132`.) Long strings are now wrapped using Python's normal line continuation -syntax. (Contributed by Antoine Pitrou in :issue:`17150`). +syntax. (Contributed by Antoine Pitrou in :issue:`17150`.) pty @@ -1270,13 +1270,13 @@ The :mod:`pydoc` module is now based directly on the :func:`inspect.signature` introspection API, allowing it to provide signature information for a wider variety of callable objects. This change also means that ``__wrapped__`` -attributes are now taken into account when displaying help information -(Contributed by Larry Hastings in :issue:`19674`) +attributes are now taken into account when displaying help information. +(Contributed by Larry Hastings in :issue:`19674`.) The :mod:`pydoc` module no longer displays the ``self`` parameter for already bound methods. Instead, it aims to always display the exact current -signature of the supplied callable (Contributed by Larry Hastings in -:issue:`20710`) +signature of the supplied callable. (Contributed by Larry Hastings in +:issue:`20710`.) In addition to the changes that have been made to :mod:`pydoc` directly, its handling of custom ``__dir__`` methods and various descriptor @@ -1372,7 +1372,7 @@ :exc:`~smtplib.SMTPException` is now a subclass of :exc:`OSError`, which allows both socket level errors and SMTP protocol level errors to be caught in one try/except statement by code that only cares whether or not an error occurred. -(Contributed by Ned Jackson Lovely in :issue:`2118`). +(Contributed by Ned Jackson Lovely in :issue:`2118`.) socket @@ -1412,7 +1412,7 @@ :data:`~ssl.PROTOCOL_TLSv1_1` and :data:`~ssl.PROTOCOL_TLSv1_2` (TLSv1.1 and TLSv1.2 support) have been added; support for these protocols is only available if Python is linked with OpenSSL 1.0.1 or later. (Contributed by Michele Orr? and -Antoine Pitrou in :issue:`16692`) +Antoine Pitrou in :issue:`16692`.) .. _whatsnew34-sslcontext: @@ -1596,7 +1596,7 @@ A new :func:`traceback.clear_frames` function takes a traceback object and clears the local variables in all of the frames it references, reducing the amount of memory consumed. (Contributed by Andrew Kuchling in -:issue:`1565525`). +:issue:`1565525`.) types @@ -1619,7 +1619,7 @@ The http method that will be used by a :class:`~urllib.request.Request` class can now be specified by setting a :class:`~urllib.request.Request.method` -class attribute on the subclass. (Contributed by Jason R Coombs in +class attribute on the subclass. (Contributed by Jason R Coombs in :issue:`18978`.) :class:`~urllib.request.Request` objects are now reusable: if the @@ -1701,14 +1701,14 @@ :issue:`17015`.) :func:`~mock.mock_open` objects now have ``readline`` and ``readlines`` -methods. (Contributed by Toshio Kuratomi in :issue:`17467`.) +methods. (Contributed by Toshio Kuratomi in :issue:`17467`.) venv ---- :mod:`venv` now includes activation scripts for the ``csh`` and ``fish`` -shells (Contributed by Andrew Svetlov in :issue:`15417`.) +shells. (Contributed by Andrew Svetlov in :issue:`15417`.) :class:`~venv.EnvBuilder` and the :func:`~venv.create` convenience function take a new keyword argument *with_pip*, which defaults to ``False``, that @@ -1739,12 +1739,12 @@ ------- New :class:`~weakref.WeakMethod` class simulates weak references to bound -methods. (Contributed by Antoine Pitrou in :issue:`14631`.) +methods. (Contributed by Antoine Pitrou in :issue:`14631`.) New :class:`~weakref.finalize` class makes it possible to register a callback to be invoked when an object is garbage collected, without needing to -carefully manage the lifecycle of the weak reference itself. (Contributed by -Richard Oudkerk in :issue:`15528`) +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 @@ -1879,16 +1879,16 @@ * The new :c:func:`PyType_GetSlot` function has been added to the stable ABI, allowing retrieval of function pointers from named type slots when using - the limited API. (Contributed by Martin von L?wis in :issue:`17162`) + the limited API. (Contributed by Martin von L?wis in :issue:`17162`.) * The new :c:func:`Py_SetStandardStreamEncoding` pre-initialization API allows applications embedding the CPython interpreter to reliably force - a particular encoding and error handler for the standard streams - (Contributed by Bastien Montagne and Nick Coghlan in :issue:`16129`) + a particular encoding and error handler for the standard streams. + (Contributed by Bastien Montagne and Nick Coghlan in :issue:`16129`.) * Most Python C APIs that don't mutate string arguments are now correctly - marked as accepting ``const char *`` rather than ``char *`` (Contributed - by Serhiy Storchaka in :issue:`1772673`). + marked as accepting ``const char *`` rather than ``char *``. (Contributed + by Serhiy Storchaka in :issue:`1772673`.) * A new shell version of ``python-config`` can be used even when a python interpreter is not available (for example, in cross compilation scenarios). @@ -1958,7 +1958,7 @@ * The ``-R`` option to the :ref:`python regression test suite ` now also checks for memory allocation leaks, using :func:`sys.getallocatedblocks()`. (Contributed by Antoine Pitrou in - :issue:`13390`). + :issue:`13390`.) * ``python -m`` now works with namespace packages. @@ -2021,14 +2021,14 @@ 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`) + :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 Serhiy Storchaka and Nadeem Vawda in :issue:`16034`.) * :func:`random.getrandbits` is 20%-40% faster for small integers (the most - common use case). (Contributed by Serhiy Storchaka in :issue:`16674`). + 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 @@ -2048,7 +2048,7 @@ * :func:`os.urandom` now uses a lazily-opened persistent file descriptor so as to avoid using many file descriptors when run in parallel from - multiple threads. (Contributed by Antoine Pitrou in :issue:`18756`.) + multiple threads. (Contributed by Antoine Pitrou in :issue:`18756`.) .. _deprecated-3.4: @@ -2246,7 +2246,7 @@ * The [X refs, Y blocks] output of a debug (``--with-pydebug``) build of the CPython interpreter is now off by default. It can be re-enabled using the - ``-X showrefcount`` option. (Contributed by Ezio Melotti in :issue:`17323`.) + ``-X showrefcount`` option. (Contributed by Ezio Melotti in :issue:`17323`.) * The python command and most stdlib scripts (as well as :mod:`argparse`) now output ``--version`` information to ``stdout`` instead of ``stderr`` (for @@ -2395,8 +2395,8 @@ storage). (:issue:`17094`.) * Parameter names in ``__annotations__`` dicts are now mangled properly, - similarly to ``__kwdefaults__``. (Contributed by Yury Selivanov in - :issue:`20625`). + similarly to ``__kwdefaults__``. (Contributed by Yury Selivanov in + :issue:`20625`.) * :attr:`hashlib.hash.name` now always returns the identifier in lower case. Previously some builtin hashes had uppercase names, but now that it is a diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -138,22 +138,22 @@ ---- * The :func:`code.InteractiveInterpreter.showtraceback` method now prints - the full chained traceback, just like the interactive interpreter - (contributed by Claudiu.Popa in :issue:`17442`). + the full chained traceback, just like the interactive interpreter. + (Contributed by Claudiu.Popa in :issue:`17442`.) compileall ---------- * :func:`compileall.compile_dir` and :mod:`compileall`'s command-line interface can now do parallel bytecode compilation. - (Contributed by Claudiu Popa in :issue:`16104`). + (Contributed by Claudiu Popa in :issue:`16104`.) doctest ------- * :func:`doctest.DocTestSuite` returns an empty :class:`unittest.TestSuite` if - *module* contains no docstrings instead of raising :exc:`ValueError` - (contributed by Glenn Jones in :issue:`15916`). + *module* contains no docstrings instead of raising :exc:`ValueError`. + (Contributed by Glenn Jones in :issue:`15916`.) glob ---- @@ -168,20 +168,20 @@ * :class:`IMAP4` now supports the context management protocol. When used in a :keyword:`with` statement, the IMAP4 ``LOGOUT`` command will be called automatically at the end of the block. (Contributed by Tarek Ziad? and - Serhiy Storchaka in :issue:`4972`). + Serhiy Storchaka in :issue:`4972`.) imghdr ------ * :func:`~imghdr.what` now recognizes the `OpenEXR `_ - format (contributed by Martin vignali and Cladui Popa in :issue:`20295`). + format. (Contributed by Martin vignali and Cladui Popa in :issue:`20295`.) importlib --------- * :class:`importlib.util.LazyLoader` allows for the lazy loading of modules in - applications where startup time is paramount (contributed by Brett Cannon in - :issue:`17621`). + applications where startup time is paramount. + (Contributed by Brett Cannon in :issue:`17621`.) * :func:`importlib.abc.InspectLoader.source_to_code` is now a static method to make it easier to work with source code in a string. @@ -196,26 +196,26 @@ ------- * :class:`inspect.Signature` and :class:`inspect.Parameter` are now - picklable and hashable (contributed by Yury Selivanov in :issue:`20726` - and :issue:`20334`). + picklable and hashable. (Contributed by Yury Selivanov in :issue:`20726` + and :issue:`20334`.) * New class method :meth:`inspect.Signature.from_callable`, which makes - subclassing of :class:`~inspect.Signature` easier (contributed - by Yury Selivanov and Eric Snow in :issue:`17373`). + subclassing of :class:`~inspect.Signature` easier. (Contributed + by Yury Selivanov and Eric Snow in :issue:`17373`.) ipaddress --------- * :class:`ipaddress.IPv4Network` and :class:`ipaddress.IPv6Network` now accept an ``(address, netmask)`` tuple argument, so as to easily construct - network objects from existing addresses (contributed by Peter Moody - and Antoine Pitrou in :issue:`16531`). + network objects from existing addresses. (Contributed by Peter Moody + and Antoine Pitrou in :issue:`16531`.) os -- * :class:`os.stat_result` now has a :attr:`~os.stat_result.st_file_attributes` - attribute on Windows (contributed by Ben Hoyt in :issue:`21719`). + attribute on Windows. (Contributed by Ben Hoyt in :issue:`21719`.) re -- @@ -239,8 +239,8 @@ * Different constants of :mod:`signal` module are now enumeration values using the :mod:`enum` module. This allows meaningful names to be printed during - debugging, instead of integer ?magic numbers?. (contributed by Giampaolo - Rodola' in :issue:`21076`) + debugging, instead of integer ?magic numbers?. (Contributed by Giampaolo + Rodola' in :issue:`21076`.) smtpd ----- @@ -264,15 +264,15 @@ ------- * A new :meth:`~smtplib.SMTP.auth` method provides a convenient way to - implement custom authentication mechanisms (contributed by Milan Oberkirch in - :issue:`15014`). + implement custom authentication mechanisms. + (Contributed by Milan Oberkirch in :issue:`15014`.) sndhdr ------ * :func:`~sndhdr.what` and :func:`~sndhdr.whathdr` now return - :func:`~collections.namedtuple` \s (contributed by Claudiu Popa in - :issue:`18615`). + :func:`~collections.namedtuple`. + (Contributed by Claudiu Popa in :issue:`18615`.) socket ------ @@ -281,7 +281,7 @@ by using high-performance :func:`os.sendfile` function on UNIX resulting in uploads being from 2x to 3x faster than when using plain :meth:`socket.socket.send`. - (contributed by Giampaolo Rodola' in :issue:`17552`) + (Contributed by Giampaolo Rodola' in :issue:`17552`.) time ---- @@ -298,8 +298,8 @@ xmlrpc ------ -* :class:`xmlrpc.client.ServerProxy` is now a :term:`context manager` - (contributed by Claudiu Popa in :issue:`20627`). +* :class:`xmlrpc.client.ServerProxy` is now a :term:`context manager`. + (Contributed by Claudiu Popa in :issue:`20627`.) Optimizations @@ -380,7 +380,8 @@ and the ``__version__`` string was not updated in the last few releases. * The internal ``Netrc`` class in the :mod:`ftplib` module was deprecated in - 3.4, and has now been removed. (Contributed by Matt Chaput in :issue:`6623`.) + 3.4, and has now been removed. + (Contributed by Matt Chaput in :issue:`6623`.) Porting to Python 3.5 ===================== @@ -408,15 +409,15 @@ * The deprecated "strict" mode and argument of :class:`~html.parser.HTMLParser`, :meth:`HTMLParser.error`, and the :exc:`HTMLParserError` exception have been - removed (contributed by Ezio Melotti in :issue:`15114`). + removed. (Contributed by Ezio Melotti in :issue:`15114`.) The *convert_charrefs* argument of :class:`~html.parser.HTMLParser` is - now ``True`` by default (contributed by Berker Peksag in :issue:`21047`). + now ``True`` by default. (Contributed by Berker Peksag in :issue:`21047`.) * Although it is not formally part of the API, it is worth noting for porting purposes (ie: fixing tests) that error messages that were previously of the form "'sometype' does not support the buffer protocol" are now of the form "a - bytes-like object is required, not 'sometype'" (contributed by Ezio Melotti - in :issue:`16518`). + bytes-like object is required, not 'sometype'". (Contributed by Ezio Melotti + in :issue:`16518`.) Changes in the C API -------------------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 18:29:27 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Nov 2014 17:29:27 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyMzg4?= =?utf-8?q?=3A_Unified_the_style_of_=22Contributed_by=22_sentences_in_What?= =?utf-8?q?=27s_New=2E?= Message-ID: <20141102172926.111408.27166@psf.io> https://hg.python.org/cpython/rev/e3825486da53 changeset: 93351:e3825486da53 branch: 3.4 parent: 93346:b5e9bc4352e1 user: Serhiy Storchaka date: Sun Nov 02 19:18:52 2014 +0200 summary: Issue #22388: Unified the style of "Contributed by" sentences in What's New. files: Doc/whatsnew/3.3.rst | 102 ++++++++++++++-------------- Doc/whatsnew/3.4.rst | 112 +++++++++++++++--------------- 2 files changed, 107 insertions(+), 107 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 @@ -171,7 +171,7 @@ * Multi-dimensional comparisons are supported for any array type. * One-dimensional memoryviews of hashable (read-only) types with formats B, - b or c are now hashable. (Contributed by Antoine Pitrou in :issue:`13411`) + b or c are now hashable. (Contributed by Antoine Pitrou in :issue:`13411`.) * Arbitrary slicing of any 1-D arrays type is supported. For example, it is now possible to reverse a memoryview in O(1) by using a negative step. @@ -196,7 +196,7 @@ * For further changes see `Build and C API Changes`_ and `Porting C code`_. -(Contributed by Stefan Krah in :issue:`10181`) +(Contributed by Stefan Krah in :issue:`10181`.) .. seealso:: @@ -307,8 +307,8 @@ Python version when a more recent version is installed). In addition to the launcher, the Windows installer now includes an -option to add the newly installed Python to the system PATH (contributed -by Brian Curtin in :issue:`3561`). +option to add the newly installed Python to the system PATH. (Contributed +by Brian Curtin in :issue:`3561`.) .. seealso:: @@ -781,7 +781,7 @@ Both :func:`unicodedata.lookup()` and ``'\N{...}'`` now resolve name aliases, and :func:`unicodedata.lookup()` resolves named sequences too. - (Contributed by Ezio Melotti in :issue:`12753`) + (Contributed by Ezio Melotti in :issue:`12753`.) * Unicode database updated to UCD version 6.1.0 @@ -793,7 +793,7 @@ methods of :class:`bytes` and :class:`bytearray` objects now accept an integer between 0 and 255 as their first argument. - (Contributed by Petri Lehtinen in :issue:`12170`) + (Contributed by Petri Lehtinen in :issue:`12170`.) * The ``rjust()``, ``ljust()``, and ``center()`` methods of :class:`bytes` and :class:`bytearray` now accept a :class:`bytearray` for the ``fill`` @@ -854,7 +854,7 @@ * The sequence documentation has been substantially rewritten to better explain the binary/text sequence distinction and to provide specific documentation sections for the individual builtin sequence types - (:issue:`4966`) + (:issue:`4966`). New Modules @@ -891,7 +891,7 @@ objects representing IPv4 and IPv6 addresses, networks and interfaces (i.e. an IP address associated with a specific IP subnet). -(Contributed by Google and Peter Moody in :pep:`3144`) +(Contributed by Google and Peter Moody in :pep:`3144`.) lzma ---- @@ -900,7 +900,7 @@ using the LZMA algorithm, including support for the ``.xz`` and ``.lzma`` file formats. -(Contributed by Nadeem Vawda and Per ?yvind Karlsen in :issue:`6715`) +(Contributed by Nadeem Vawda and Per ?yvind Karlsen in :issue:`6715`.) Improved Modules @@ -921,7 +921,7 @@ * :class:`abc.abstractstaticmethod` has been deprecated, use :class:`staticmethod` with :func:`abc.abstractmethod` instead. -(Contributed by Darren Dale in :issue:`11610`) +(Contributed by Darren Dale in :issue:`11610`.) :meth:`abc.ABCMeta.register` now returns the registered subclass, which means it can now be used as a class decorator (:issue:`10868`). @@ -933,7 +933,7 @@ The :mod:`array` module supports the :c:type:`long long` type using ``q`` and ``Q`` type codes. -(Contributed by Oren Tirosh and Hirokazu Yamamoto in :issue:`1172711`) +(Contributed by Oren Tirosh and Hirokazu Yamamoto in :issue:`1172711`.) base64 @@ -964,14 +964,14 @@ * :class:`bz2.BZ2File` can now read from and write to arbitrary file-like objects, by means of its constructor's *fileobj* argument. - (Contributed by Nadeem Vawda in :issue:`5863`) + (Contributed by Nadeem Vawda in :issue:`5863`.) * :class:`bz2.BZ2File` and :func:`bz2.decompress` can now decompress multi-stream inputs (such as those produced by the :program:`pbzip2` tool). :class:`bz2.BZ2File` can now also be used to create this type of file, using the ``'a'`` (append) mode. - (Contributed by Nir Aides in :issue:`1625`) + (Contributed by Nir Aides in :issue:`1625`.) * :class:`bz2.BZ2File` now implements all of the :class:`io.BufferedIOBase` API, except for the :meth:`detach` and :meth:`truncate` methods. @@ -1018,7 +1018,7 @@ Addition of a new :class:`~collections.ChainMap` class to allow treating a number of mappings as a single unit. (Written by Raymond Hettinger for -:issue:`11089`, made public in :issue:`11297`) +:issue:`11089`, made public in :issue:`11297`.) The abstract base classes have been moved in a new :mod:`collections.abc` module, to better differentiate between the abstract and the concrete @@ -1069,7 +1069,7 @@ push a wide character so the next :meth:`~curses.window.get_wch` will return it -(Contributed by I?igo Serna in :issue:`6755`) +(Contributed by I?igo Serna in :issue:`6755`.) datetime -------- @@ -1376,11 +1376,11 @@ :func:`~ftplib.FTP_TLS.ccc` function to revert control channel back to plaintext. This can be useful to take advantage of firewalls that know how to handle NAT with non-secure FTP without opening fixed ports. (Contributed - by Giampaolo Rodol? in :issue:`12139`) + by Giampaolo Rodol? in :issue:`12139`.) * Added :meth:`ftplib.FTP.mlsd` method which provides a parsable directory listing format and deprecates :meth:`ftplib.FTP.nlst` and - :meth:`ftplib.FTP.dir`. (Contributed by Giampaolo Rodol? in :issue:`11072`) + :meth:`ftplib.FTP.dir`. (Contributed by Giampaolo Rodol? in :issue:`11072`.) functools @@ -1404,7 +1404,7 @@ A new :func:`~hmac.compare_digest` function has been added to prevent side channel attacks on digests through timing analysis. (Contributed by Nick -Coghlan and Christian Heimes in :issue:`15061`) +Coghlan and Christian Heimes in :issue:`15061`.) http @@ -1436,13 +1436,13 @@ (Contributed by Ezio Melotti in :issue:`15114`, and :issue:`14538`, :issue:`13993`, :issue:`13960`, :issue:`13358`, :issue:`1745761`, :issue:`755670`, :issue:`13357`, :issue:`12629`, :issue:`1200313`, -:issue:`670664`, :issue:`13273`, :issue:`12888`, :issue:`7311`) +:issue:`670664`, :issue:`13273`, :issue:`12888`, :issue:`7311`.) A new :data:`~html.entities.html5` dictionary that maps HTML5 named character references to the equivalent Unicode character(s) (e.g. ``html5['gt;'] == '>'``) has been added to the :mod:`html.entities` module. The dictionary is now also used by :class:`~html.parser.HTMLParser`. (Contributed by Ezio -Melotti in :issue:`11113` and :issue:`15156`) +Melotti in :issue:`11113` and :issue:`15156`.) imaplib @@ -1451,7 +1451,7 @@ The :class:`~imaplib.IMAP4_SSL` constructor now accepts an SSLContext parameter to control parameters of the secure channel. -(Contributed by Sijin Joseph in :issue:`8808`) +(Contributed by Sijin Joseph in :issue:`8808`.) inspect @@ -1462,14 +1462,14 @@ where those names were resolved, making it easier to verify correct internal state when testing code that relies on stateful closures. -(Contributed by Meador Inge and Nick Coghlan in :issue:`13062`) +(Contributed by Meador Inge and Nick Coghlan in :issue:`13062`.) A new :func:`~inspect.getgeneratorlocals` function has been added. This function reports the current binding of local variables in the generator's stack frame, making it easier to verify correct internal state when testing generators. -(Contributed by Meador Inge in :issue:`15153`) +(Contributed by Meador Inge in :issue:`15153`.) io -- @@ -1478,7 +1478,7 @@ exclusively create a new file, and raise a :exc:`FileExistsError` if the file already exists. It is based on the C11 'x' mode to fopen(). -(Contributed by David Townshend in :issue:`12760`) +(Contributed by David Townshend in :issue:`12760`.) The constructor of the :class:`~io.TextIOWrapper` class has a new *write_through* optional argument. If *write_through* is ``True``, calls to @@ -1513,7 +1513,7 @@ The :mod:`math` module has a new function, :func:`~math.log2`, which returns the base-2 logarithm of *x*. -(Written by Mark Dickinson in :issue:`11888`). +(Written by Mark Dickinson in :issue:`11888`.) mmap @@ -1567,7 +1567,7 @@ ('211 1755 1 1755 gmane.comp.python.committers', 1755, 1, 1755, 'gmane.comp.python.committers') >>> -(Contributed by Giampaolo Rodol? in :issue:`9795`) +(Contributed by Giampaolo Rodol? in :issue:`9795`.) os @@ -1744,24 +1744,24 @@ set to False makes the method execute the scheduled events due to expire soonest (if any) and then return immediately. This is useful in case you want to use the :class:`~sched.scheduler` in - non-blocking applications. (Contributed by Giampaolo Rodol? in :issue:`13449`) + non-blocking applications. (Contributed by Giampaolo Rodol? in :issue:`13449`.) * :class:`~sched.scheduler` class can now be safely used in multi-threaded environments. (Contributed by Josiah Carlson and Giampaolo Rodol? in - :issue:`8684`) + :issue:`8684`.) * *timefunc* and *delayfunct* parameters of :class:`~sched.scheduler` class constructor are now optional and defaults to :func:`time.time` and :func:`time.sleep` respectively. (Contributed by Chris Clark in - :issue:`13245`) + :issue:`13245`.) * :meth:`~sched.scheduler.enter` and :meth:`~sched.scheduler.enterabs` *argument* parameter is now optional. (Contributed by Chris Clark in - :issue:`13245`) + :issue:`13245`.) * :meth:`~sched.scheduler.enter` and :meth:`~sched.scheduler.enterabs` now accept a *kwargs* parameter. (Contributed by Chris Clark in - :issue:`13245`) + :issue:`13245`.) select @@ -1787,10 +1787,10 @@ * New functions: * :func:`~shutil.disk_usage`: provides total, used and free disk space - statistics. (Contributed by Giampaolo Rodol? in :issue:`12442`) + statistics. (Contributed by Giampaolo Rodol? in :issue:`12442`.) * :func:`~shutil.chown`: allows one to change user and/or group of the given path also specifying the user/group names and not only their numeric - ids. (Contributed by Sandro Tosi in :issue:`12191`) + ids. (Contributed by Sandro Tosi in :issue:`12191`.) * :func:`shutil.get_terminal_size`: returns the size of the terminal window to which the interpreter is attached. (Contributed by Zbigniew J?drzejewski-Szmek in :issue:`13609`.) @@ -1813,7 +1813,7 @@ * :func:`~shutil.rmtree` is now resistant to symlink attacks on platforms which support the new ``dir_fd`` parameter in :func:`os.open` and - :func:`os.unlink`. (Contributed by Martin von L?wis and Hynek Schlawack + :func:`os.unlink`. (Contributed by Martin von L?wis and Hynek Schlawack in :issue:`4489`.) @@ -1867,7 +1867,7 @@ The :class:`~smtplib.SMTP_SSL` constructor and the :meth:`~smtplib.SMTP.starttls` method now accept an SSLContext parameter to control parameters of the secure -channel. (Contributed by Kasun Herath in :issue:`8809`) +channel. (Contributed by Kasun Herath in :issue:`8809`.) socket @@ -1887,7 +1887,7 @@ (http://en.wikipedia.org/wiki/Socketcan), on Linux (http://lwn.net/Articles/253425). - (Contributed by Matthias Fuchs, updated by Tiago Gon?alves in :issue:`10141`) + (Contributed by Matthias Fuchs, updated by Tiago Gon?alves in :issue:`10141`.) * The :class:`~socket.socket` class now supports the PF_RDS protocol family (http://en.wikipedia.org/wiki/Reliable_Datagram_Sockets and @@ -1929,37 +1929,37 @@ pseudo-random bytes. * :func:`~ssl.RAND_pseudo_bytes`: generate pseudo-random bytes. - (Contributed by Victor Stinner in :issue:`12049`) + (Contributed by Victor Stinner in :issue:`12049`.) * The :mod:`ssl` module now exposes a finer-grained exception hierarchy in order to make it easier to inspect the various kinds of errors. - (Contributed by Antoine Pitrou in :issue:`11183`) + (Contributed by Antoine Pitrou in :issue:`11183`.) * :meth:`~ssl.SSLContext.load_cert_chain` now accepts a *password* argument to be used if the private key is encrypted. - (Contributed by Adam Simpkins in :issue:`12803`) + (Contributed by Adam Simpkins in :issue:`12803`.) * Diffie-Hellman key exchange, both regular and Elliptic Curve-based, is now supported through the :meth:`~ssl.SSLContext.load_dh_params` and :meth:`~ssl.SSLContext.set_ecdh_curve` methods. - (Contributed by Antoine Pitrou in :issue:`13626` and :issue:`13627`) + (Contributed by Antoine Pitrou in :issue:`13626` and :issue:`13627`.) * SSL sockets have a new :meth:`~ssl.SSLSocket.get_channel_binding` method allowing the implementation of certain authentication mechanisms such as - SCRAM-SHA-1-PLUS. (Contributed by Jacek Konieczny in :issue:`12551`) + SCRAM-SHA-1-PLUS. (Contributed by Jacek Konieczny in :issue:`12551`.) * You can query the SSL compression algorithm used by an SSL socket, thanks to its new :meth:`~ssl.SSLSocket.compression` method. The new attribute :attr:`~ssl.OP_NO_COMPRESSION` can be used to disable compression. - (Contributed by Antoine Pitrou in :issue:`13634`) + (Contributed by Antoine Pitrou in :issue:`13634`.) * Support has been added for the Next Procotol Negotiation extension using the :meth:`ssl.SSLContext.set_npn_protocols` method. - (Contributed by Colin Marc in :issue:`14204`) + (Contributed by Colin Marc in :issue:`14204`.) * SSL errors can now be introspected more easily thanks to :attr:`~ssl.SSLError.library` and :attr:`~ssl.SSLError.reason` attributes. - (Contributed by Antoine Pitrou in :issue:`14837`) + (Contributed by Antoine Pitrou in :issue:`14837`.) * The :func:`~ssl.get_server_certificate` function now supports IPv6. (Contributed by Charles-Fran?ois Natali in :issue:`11811`.) @@ -1976,7 +1976,7 @@ :func:`stat.filemode`. It can be used to convert a file's mode to a string of the form '-rwxrwxrwx'. -(Contributed by Giampaolo Rodol? in :issue:`14807`) +(Contributed by Giampaolo Rodol? in :issue:`14807`.) struct @@ -2035,8 +2035,8 @@ :class:`threading.Condition`, :class:`threading.Semaphore`, :class:`threading.BoundedSemaphore`, :class:`threading.Event`, and :class:`threading.Timer`, all of which used to be factory functions returning a -class instance, are now classes and may be subclassed. (Contributed by ?ric -Araujo in :issue:`10968`). +class instance, are now classes and may be subclassed. (Contributed by ?ric +Araujo in :issue:`10968`.) The :class:`threading.Thread` constructor now accepts a ``daemon`` keyword argument to override the default behavior of inheriting the ``deamon`` flag @@ -2066,7 +2066,7 @@ * :func:`~time.clock_getres`, :func:`~time.clock_gettime` and :func:`~time.clock_settime` functions with ``CLOCK_xxx`` constants. - (Contributed by Victor Stinner in :issue:`10278`) + (Contributed by Victor Stinner in :issue:`10278`.) To improve cross platform consistency, :func:`~time.sleep` now raises a :exc:`ValueError` when passed a negative sleep value. Previously this was an @@ -2090,7 +2090,7 @@ :meth:`.assertRaises`, :meth:`.assertRaisesRegex`, :meth:`.assertWarns`, and :meth:`.assertWarnsRegex` now accept a keyword argument *msg* when used as context managers. (Contributed by Ezio Melotti and Winston Ewert in -:issue:`10775`) +:issue:`10775`.) :meth:`unittest.TestCase.run` now returns the :class:`~unittest.TestResult` object. @@ -2117,7 +2117,7 @@ and the generic launchers :program:`xdg-open`, from the FreeDesktop.org project, and :program:`gvfs-open`, which is the default URI handler for GNOME 3. (The former contributed by Arnaud Calmettes in :issue:`13620`, the latter -by Matthias Klose in :issue:`14493`) +by Matthias Klose in :issue:`14493`.) xml.etree.ElementTree @@ -2160,7 +2160,7 @@ * UTF-8 is now 2x to 4x faster. UTF-16 encoding is now up to 10x faster. - (contributed by Serhiy Storchaka, :issue:`14624`, :issue:`14738` and + (Contributed by Serhiy Storchaka, :issue:`14624`, :issue:`14738` and :issue:`15026`.) 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 @@ -52,7 +52,7 @@ * It's helpful to add the bug/patch number as a comment: The :ref:`~socket.transmogrify()` function was added to the - :mod:`socket` module. (Contributed by P.Y. Developer in :issue:`12345`.) + :mod:`socket` module. (Contributed by P.Y. Developer in :issue:`12345`.) This saves the maintainer the effort of going through the Mercurial log when researching a change. @@ -372,7 +372,7 @@ in :ref:`binary-transforms` and :ref:`text-transforms`. (Contributed by Nick Coghlan in :issue:`7475`, :issue:`17827`, -:issue:`17828` and :issue:`19619`) +:issue:`17828` and :issue:`19619`.) .. _whatsnew-pep-451: @@ -414,14 +414,14 @@ * Module ``__file__`` attributes (and related values) should now always contain absolute paths by default, with the sole exception of ``__main__.__file__`` when a script has been executed directly using - a relative path (Contributed by Brett Cannon in :issue:`18416`). + a relative path. (Contributed by Brett Cannon in :issue:`18416`.) * All the UTF-\* codecs (except UTF-7) now reject surrogates during both encoding and decoding unless the ``surrogatepass`` error handler is used, with the exception of the UTF-16 decoder (which accepts valid surrogate pairs) and the UTF-16 encoder (which produces them while encoding non-BMP characters). - Contributed by Victor Stinner, Kang-Hao (Kenny) Lu and Serhiy Storchaka in - :issue:`12892`. + (Contributed by Victor Stinner, Kang-Hao (Kenny) Lu and Serhiy Storchaka in + :issue:`12892`.) * New German EBCDIC :ref:`codec ` ``cp273``. (Contributed by Michael Bierenfeld and Andrew Kuchling in :issue:`1097797`.) @@ -633,8 +633,8 @@ in :issue:`12866`.) New :func:`~audioop.byteswap` function converts big-endian samples to -little-endian and vice versa (Contributed by Serhiy Storchaka in -:issue:`19641`). +little-endian and vice versa. (Contributed by Serhiy Storchaka in +:issue:`19641`.) All :mod:`audioop` functions now accept any :term:`bytes-like object`. Strings are not accepted: they didn't work before, now they raise an error right away. @@ -681,8 +681,8 @@ The new :class:`contextlib.suppress` context manager helps to clarify the intent of code that deliberately suppresses exceptions from a single -statement. (Contributed by Raymond Hettinger in :issue:`15806` and -Zero Piraeus in :issue:`19266`) +statement. (Contributed by Raymond Hettinger in :issue:`15806` and +Zero Piraeus in :issue:`19266`.) The new :func:`contextlib.redirect_stdout` context manager makes it easier for utility scripts to handle inflexible APIs that write their output to @@ -693,7 +693,7 @@ from a function that was written to implement a command line interface. It is recommended only for utility scripts because it affects the global state of :data:`sys.stdout`. (Contributed by Raymond Hettinger -in :issue:`15805`) +in :issue:`15805`.) The :mod:`contextlib` documentation has also been updated to include a :ref:`discussion ` of the @@ -765,7 +765,7 @@ to ``distb(tb)``). (Contributed by Nick Coghlan, Ryan Kelly and Thomas Kluyver in :issue:`11816` -and Claudiu Popa in :issue:`17916`) +and Claudiu Popa in :issue:`17916`.) New function :func:`~dis.stack_effect` computes the effect on the Python stack of a given opcode and argument, information that is not otherwise available. @@ -855,7 +855,7 @@ for normal callables. The new descriptor also makes it easier to get arbitrary callables (including :func:`~functools.partial` instances) to behave like normal instance methods when included in a class definition. -(Contributed by Alon Horev and Nick Coghlan in :issue:`4331`) +(Contributed by Alon Horev and Nick Coghlan in :issue:`4331`.) .. _whatsnew-singledispatch: @@ -903,7 +903,7 @@ A new :func:`hashlib.pbkdf2_hmac` function provides the `PKCS#5 password-based key derivation function 2 `_. (Contributed by Christian -Heimes in :issue:`18582`) +Heimes in :issue:`18582`.) The :attr:`~hashlib.hash.name` attribute of :mod:`hashlib` hash objects is now a formally supported interface. It has always existed in CPython's @@ -939,17 +939,17 @@ New function :func:`~html.unescape` function converts HTML5 character references to the corresponding Unicode characters. (Contributed by Ezio Melotti in -:issue:`2927`) +:issue:`2927`.) :class:`~html.parser.HTMLParser` accepts a new keyword argument *convert_charrefs* that, when ``True``, automatically converts all character references. For backward-compatibility, its value defaults to ``False``, but it will change to ``True`` in a future version of Python, so you are invited to set it explicitly and update your code to use this new feature. (Contributed -by Ezio Melotti in :issue:`13633`) +by Ezio Melotti in :issue:`13633`.) The *strict* argument of :class:`~html.parser.HTMLParser` is now deprecated. -(Contributed by Ezio Melotti in :issue:`15114`) +(Contributed by Ezio Melotti in :issue:`15114`.) http @@ -1015,19 +1015,19 @@ The :mod:`inspect` module now offers a basic :ref:`command line interface ` to quickly display source code and other -information for modules, classes and functions. (Contributed by Claudiu Popa -and Nick Coghlan in :issue:`18626`) +information for modules, classes and functions. (Contributed by Claudiu Popa +and Nick Coghlan in :issue:`18626`.) :func:`~inspect.unwrap` makes it easy to unravel wrapper function chains created by :func:`functools.wraps` (and any other API that sets the -``__wrapped__`` attribute on a wrapper function). (Contributed by -Daniel Urban, Aaron Iles and Nick Coghlan in :issue:`13266`) +``__wrapped__`` attribute on a wrapper function). (Contributed by +Daniel Urban, Aaron Iles and Nick Coghlan in :issue:`13266`.) As part of the implementation of the new :mod:`enum` module, the :mod:`inspect` module now has substantially better support for custom ``__dir__`` methods and dynamic class attributes provided through -metaclasses (Contributed by Ethan Furman in :issue:`18929` and -:issue:`19030`) +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 @@ -1038,11 +1038,11 @@ attributes, and report the already bound first argument for bound methods, so it is still necessary to update your code to use :func:`~inspect.signature` directly if those features are desired. -(Contributed by Yury Selivanov in :issue:`17481`) +(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`) +which adds support for functions compiled with Cython. (Contributed +by Stefan Behnel and Yury Selivanov in :issue:`17159`.) ipaddress @@ -1082,7 +1082,7 @@ Logging configuration data received from a socket via the :func:`logging.config.listen` function can now be validated before being processed by supplying a verification function as the argument to the new -*verify* keyword argument. (Contributed by Vinay Sajip in :issue:`15452`.) +*verify* keyword argument. (Contributed by Vinay Sajip in :issue:`15452`.) .. _whatsnew-marshal-3: @@ -1120,7 +1120,7 @@ :func:`~multiprocessing.get_all_start_methods` reports all start methods available on the platform, :func:`~multiprocessing.get_start_method` reports the current start method, and :func:`~multiprocessing.set_start_method` sets -the start method. (Contributed by Richard Oudkerk in :issue:`8713`). +the start method. (Contributed by Richard Oudkerk in :issue:`8713`.) :mod:`multiprocessing` also now has the concept of a ``context``, which determines how child processes are created. New function @@ -1141,7 +1141,7 @@ when using the ``spawn`` or ``forkserver`` start methods. This resolves some edge cases where combining multiprocessing, the ``-m`` command line switch, and explicit relative imports could cause obscure failures in child -processes. (Contributed by Nick Coghlan in :issue:`19946`) +processes. (Contributed by Nick Coghlan in :issue:`19946`.) operator @@ -1176,7 +1176,7 @@ Windows). (Contributed by Brian Curtin in :issue:`11939`.) :func:`os.path.ismount` now recognizes volumes mounted below a drive -root on Windows. (Contributed by Tim Golden in :issue:`9035`.) +root on Windows. (Contributed by Tim Golden in :issue:`9035`.) :func:`os.open` supports two new flags on platforms that provide them, :data:`~os.O_PATH` (un-opened file descriptor), and :data:`~os.O_TMPFILE` @@ -1230,7 +1230,7 @@ functions. (The older API is now deprecated.) In addition to the already supported XML plist format (:data:`~plistlib.FMT_XML`), it also now supports the binary plist format (:data:`~plistlib.FMT_BINARY`). (Contributed by Ronald -Oussoren and others in :issue:`14455`). +Oussoren and others in :issue:`14455`.) poplib @@ -1254,7 +1254,7 @@ (Contributed by Serhiy Storchaka in :issue:`19132`.) Long strings are now wrapped using Python's normal line continuation -syntax. (Contributed by Antoine Pitrou in :issue:`17150`). +syntax. (Contributed by Antoine Pitrou in :issue:`17150`.) pty @@ -1270,13 +1270,13 @@ The :mod:`pydoc` module is now based directly on the :func:`inspect.signature` introspection API, allowing it to provide signature information for a wider variety of callable objects. This change also means that ``__wrapped__`` -attributes are now taken into account when displaying help information -(Contributed by Larry Hastings in :issue:`19674`) +attributes are now taken into account when displaying help information. +(Contributed by Larry Hastings in :issue:`19674`.) The :mod:`pydoc` module no longer displays the ``self`` parameter for already bound methods. Instead, it aims to always display the exact current -signature of the supplied callable (Contributed by Larry Hastings in -:issue:`20710`) +signature of the supplied callable. (Contributed by Larry Hastings in +:issue:`20710`.) In addition to the changes that have been made to :mod:`pydoc` directly, its handling of custom ``__dir__`` methods and various descriptor @@ -1372,7 +1372,7 @@ :exc:`~smtplib.SMTPException` is now a subclass of :exc:`OSError`, which allows both socket level errors and SMTP protocol level errors to be caught in one try/except statement by code that only cares whether or not an error occurred. -(Contributed by Ned Jackson Lovely in :issue:`2118`). +(Contributed by Ned Jackson Lovely in :issue:`2118`.) socket @@ -1412,7 +1412,7 @@ :data:`~ssl.PROTOCOL_TLSv1_1` and :data:`~ssl.PROTOCOL_TLSv1_2` (TLSv1.1 and TLSv1.2 support) have been added; support for these protocols is only available if Python is linked with OpenSSL 1.0.1 or later. (Contributed by Michele Orr? and -Antoine Pitrou in :issue:`16692`) +Antoine Pitrou in :issue:`16692`.) .. _whatsnew34-sslcontext: @@ -1596,7 +1596,7 @@ A new :func:`traceback.clear_frames` function takes a traceback object and clears the local variables in all of the frames it references, reducing the amount of memory consumed. (Contributed by Andrew Kuchling in -:issue:`1565525`). +:issue:`1565525`.) types @@ -1619,7 +1619,7 @@ The http method that will be used by a :class:`~urllib.request.Request` class can now be specified by setting a :class:`~urllib.request.Request.method` -class attribute on the subclass. (Contributed by Jason R Coombs in +class attribute on the subclass. (Contributed by Jason R Coombs in :issue:`18978`.) :class:`~urllib.request.Request` objects are now reusable: if the @@ -1701,14 +1701,14 @@ :issue:`17015`.) :func:`~mock.mock_open` objects now have ``readline`` and ``readlines`` -methods. (Contributed by Toshio Kuratomi in :issue:`17467`.) +methods. (Contributed by Toshio Kuratomi in :issue:`17467`.) venv ---- :mod:`venv` now includes activation scripts for the ``csh`` and ``fish`` -shells (Contributed by Andrew Svetlov in :issue:`15417`.) +shells. (Contributed by Andrew Svetlov in :issue:`15417`.) :class:`~venv.EnvBuilder` and the :func:`~venv.create` convenience function take a new keyword argument *with_pip*, which defaults to ``False``, that @@ -1739,12 +1739,12 @@ ------- New :class:`~weakref.WeakMethod` class simulates weak references to bound -methods. (Contributed by Antoine Pitrou in :issue:`14631`.) +methods. (Contributed by Antoine Pitrou in :issue:`14631`.) New :class:`~weakref.finalize` class makes it possible to register a callback to be invoked when an object is garbage collected, without needing to -carefully manage the lifecycle of the weak reference itself. (Contributed by -Richard Oudkerk in :issue:`15528`) +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 @@ -1879,16 +1879,16 @@ * The new :c:func:`PyType_GetSlot` function has been added to the stable ABI, allowing retrieval of function pointers from named type slots when using - the limited API. (Contributed by Martin von L?wis in :issue:`17162`) + the limited API. (Contributed by Martin von L?wis in :issue:`17162`.) * The new :c:func:`Py_SetStandardStreamEncoding` pre-initialization API allows applications embedding the CPython interpreter to reliably force - a particular encoding and error handler for the standard streams - (Contributed by Bastien Montagne and Nick Coghlan in :issue:`16129`) + a particular encoding and error handler for the standard streams. + (Contributed by Bastien Montagne and Nick Coghlan in :issue:`16129`.) * Most Python C APIs that don't mutate string arguments are now correctly - marked as accepting ``const char *`` rather than ``char *`` (Contributed - by Serhiy Storchaka in :issue:`1772673`). + marked as accepting ``const char *`` rather than ``char *``. (Contributed + by Serhiy Storchaka in :issue:`1772673`.) * A new shell version of ``python-config`` can be used even when a python interpreter is not available (for example, in cross compilation scenarios). @@ -1958,7 +1958,7 @@ * The ``-R`` option to the :ref:`python regression test suite ` now also checks for memory allocation leaks, using :func:`sys.getallocatedblocks()`. (Contributed by Antoine Pitrou in - :issue:`13390`). + :issue:`13390`.) * ``python -m`` now works with namespace packages. @@ -2021,14 +2021,14 @@ 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`) + :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 Serhiy Storchaka and Nadeem Vawda in :issue:`16034`.) * :func:`random.getrandbits` is 20%-40% faster for small integers (the most - common use case). (Contributed by Serhiy Storchaka in :issue:`16674`). + 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 @@ -2048,7 +2048,7 @@ * :func:`os.urandom` now uses a lazily-opened persistent file descriptor so as to avoid using many file descriptors when run in parallel from - multiple threads. (Contributed by Antoine Pitrou in :issue:`18756`.) + multiple threads. (Contributed by Antoine Pitrou in :issue:`18756`.) .. _deprecated-3.4: @@ -2246,7 +2246,7 @@ * The [X refs, Y blocks] output of a debug (``--with-pydebug``) build of the CPython interpreter is now off by default. It can be re-enabled using the - ``-X showrefcount`` option. (Contributed by Ezio Melotti in :issue:`17323`.) + ``-X showrefcount`` option. (Contributed by Ezio Melotti in :issue:`17323`.) * The python command and most stdlib scripts (as well as :mod:`argparse`) now output ``--version`` information to ``stdout`` instead of ``stderr`` (for @@ -2395,8 +2395,8 @@ storage). (:issue:`17094`.) * Parameter names in ``__annotations__`` dicts are now mangled properly, - similarly to ``__kwdefaults__``. (Contributed by Yury Selivanov in - :issue:`20625`). + similarly to ``__kwdefaults__``. (Contributed by Yury Selivanov in + :issue:`20625`.) * :attr:`hashlib.hash.name` now always returns the identifier in lower case. Previously some builtin hashes had uppercase names, but now that it is a -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 18:34:14 2014 From: python-checkins at python.org (r.david.murray) Date: Sun, 02 Nov 2014 17:34:14 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Fix_English_ph?= =?utf-8?q?rasing=2E?= Message-ID: <20141102173359.120726.12716@psf.io> https://hg.python.org/cpython/rev/1cafcc11e719 changeset: 93356:1cafcc11e719 branch: 3.4 parent: 93353:a5dd8e89d4da user: R David Murray date: Sun Nov 02 12:31:47 2014 -0500 summary: Fix English phrasing. files: Doc/library/asyncio-protocol.rst | 2 +- 1 files changed, 1 insertions(+), 1 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 @@ -439,7 +439,7 @@ ------------------------ 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 +is no guarantee made about 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 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 18:34:14 2014 From: python-checkins at python.org (r.david.murray) Date: Sun, 02 Nov 2014 17:34:14 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_asyncio_doc_English_phrasing_fix=2E?= Message-ID: <20141102173359.35246.5785@psf.io> https://hg.python.org/cpython/rev/b2a57fe50712 changeset: 93358:b2a57fe50712 parent: 93355:769a217764f2 parent: 93357:4924b0ce72c0 user: R David Murray date: Sun Nov 02 12:33:37 2014 -0500 summary: Merge asyncio doc English phrasing fix. files: Doc/library/asyncio-protocol.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 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 @@ -439,8 +439,8 @@ ------------------------ 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. +is no guarantee made about 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` -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 18:34:14 2014 From: python-checkins at python.org (r.david.murray) Date: Sun, 02 Nov 2014 17:34:14 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Reflow_paragra?= =?utf-8?b?cGgu?= Message-ID: <20141102173359.35274.93079@psf.io> https://hg.python.org/cpython/rev/4924b0ce72c0 changeset: 93357:4924b0ce72c0 branch: 3.4 user: R David Murray date: Sun Nov 02 12:32:26 2014 -0500 summary: Reflow paragraph. files: Doc/library/asyncio-protocol.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 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 @@ -439,8 +439,8 @@ ------------------------ Coroutines can be scheduled in a protocol method using :func:`async`, but there -is no guarantee made about the execution order. Protocols are not aware of coroutines -created in protocol methods and so will not wait for them. +is no guarantee made about 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` -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 18:42:53 2014 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 02 Nov 2014 17:42:53 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_heads?= Message-ID: <20141102174253.120720.70057@psf.io> https://hg.python.org/cpython/rev/7e89c24245ea changeset: 93362:7e89c24245ea parent: 93361:f0b334ae95c9 parent: 93359:016bc54999a2 user: Antoine Pitrou date: Sun Nov 02 18:42:41 2014 +0100 summary: Merge heads files: Lib/test/test_urllib.py | 6 +++++- 1 files changed, 5 insertions(+), 1 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 @@ -10,7 +10,10 @@ from unittest.mock import patch from test import support import os -import ssl +try: + import ssl +except ImportError: + ssl = None import sys import tempfile from nturl2path import url2pathname, pathname2url @@ -380,6 +383,7 @@ with support.check_warnings(('',DeprecationWarning)): urllib.request.URLopener() + @unittest.skipUnless(ssl, "ssl module required") def test_cafile_and_context(self): context = ssl.create_default_context() with self.assertRaises(ValueError): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 18:42:53 2014 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 02 Nov 2014 17:42:53 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_test=5Furllib_without_?= =?utf-8?q?the_ssl_module?= Message-ID: <20141102174252.35262.90121@psf.io> https://hg.python.org/cpython/rev/016bc54999a2 changeset: 93359:016bc54999a2 parent: 93347:64a54f0c87d7 user: Antoine Pitrou date: Sun Nov 02 17:23:14 2014 +0100 summary: Fix test_urllib without the ssl module files: Lib/test/test_urllib.py | 6 +++++- 1 files changed, 5 insertions(+), 1 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 @@ -10,7 +10,10 @@ from unittest.mock import patch from test import support import os -import ssl +try: + import ssl +except ImportError: + ssl = None import sys import tempfile from nturl2path import url2pathname, pathname2url @@ -380,6 +383,7 @@ with support.check_warnings(('',DeprecationWarning)): urllib.request.URLopener() + @unittest.skipUnless(ssl, "ssl module required") def test_cafile_and_context(self): context = ssl.create_default_context() with self.assertRaises(ValueError): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 18:42:53 2014 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 02 Nov 2014 17:42:53 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyMzM1?= =?utf-8?q?=3A_Fix_crash_when_trying_to_enlarge_a_bytearray_to_0x7fffffff_?= =?utf-8?q?bytes?= Message-ID: <20141102174252.35272.29008@psf.io> https://hg.python.org/cpython/rev/1590c594550e changeset: 93360:1590c594550e branch: 3.4 parent: 93357:4924b0ce72c0 user: Antoine Pitrou date: Sun Nov 02 18:40:09 2014 +0100 summary: Issue #22335: Fix crash when trying to enlarge a bytearray to 0x7fffffff bytes on a 32-bit platform. files: Lib/test/test_bytes.py | 13 +++++++++++++ Misc/NEWS | 3 +++ Objects/bytearrayobject.c | 23 +++++++++++++++-------- Objects/obmalloc.c | 8 ++++---- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -13,9 +13,11 @@ import pickle import tempfile import unittest + import test.support import test.string_tests import test.buffer_tests +from test.support import bigaddrspacetest, MAX_Py_ssize_t if sys.flags.bytes_warning: @@ -111,6 +113,17 @@ self.assertRaises(ValueError, self.type2test, [sys.maxsize+1]) self.assertRaises(ValueError, self.type2test, [10**100]) + @bigaddrspacetest + def test_constructor_overflow(self): + size = MAX_Py_ssize_t + self.assertRaises((OverflowError, MemoryError), self.type2test, size) + try: + # Should either pass or raise an error (e.g. on debug builds with + # additional malloc() overhead), but shouldn't crash. + bytearray(size - 4) + except (OverflowError, MemoryError): + pass + def test_compare(self): b1 = self.type2test([1, 2, 3]) b2 = self.type2test([1, 2, 3]) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -11,6 +11,9 @@ Core and Builtins ----------------- +- Issue #22335: Fix crash when trying to enlarge a bytearray to 0x7fffffff + bytes on a 32-bit platform. + - Issue #22653: Fix an assertion failure in debug mode when doing a reentrant dict insertion in debug mode. diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -175,20 +175,22 @@ } int -PyByteArray_Resize(PyObject *self, Py_ssize_t size) +PyByteArray_Resize(PyObject *self, Py_ssize_t requested_size) { void *sval; PyByteArrayObject *obj = ((PyByteArrayObject *)self); - Py_ssize_t alloc = obj->ob_alloc; - Py_ssize_t logical_offset = obj->ob_start - obj->ob_bytes; + /* All computations are done unsigned to avoid integer overflows + (see issue #22335). */ + size_t alloc = (size_t) obj->ob_alloc; + size_t logical_offset = (size_t) (obj->ob_start - obj->ob_bytes); + size_t size = (size_t) requested_size; assert(self != NULL); assert(PyByteArray_Check(self)); - assert(size >= 0); - assert(logical_offset >= 0); assert(logical_offset <= alloc); - - if (size == Py_SIZE(self)) { + assert(requested_size >= 0); + + if (requested_size == Py_SIZE(self)) { return 0; } if (!_canresize(obj)) { @@ -220,6 +222,10 @@ alloc = size + 1; } } + if (alloc > PY_SSIZE_T_MAX) { + PyErr_NoMemory(); + return -1; + } if (logical_offset > 0) { sval = PyObject_Malloc(alloc); @@ -227,7 +233,8 @@ PyErr_NoMemory(); return -1; } - memcpy(sval, PyByteArray_AS_STRING(self), Py_MIN(size, Py_SIZE(self))); + memcpy(sval, PyByteArray_AS_STRING(self), + Py_MIN(requested_size, Py_SIZE(self))); PyObject_Free(obj->ob_bytes); } else { diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -1754,8 +1754,8 @@ bumpserialno(); total = nbytes + 4*SST; - if (total < nbytes) - /* overflow: can't represent total as a size_t */ + if (nbytes > PY_SSIZE_T_MAX - 4*SST) + /* overflow: can't represent total as a Py_ssize_t */ return NULL; p = (uchar *)api->alloc.malloc(api->alloc.ctx, total); @@ -1817,8 +1817,8 @@ bumpserialno(); original_nbytes = read_size_t(q - 2*SST); total = nbytes + 4*SST; - if (total < nbytes) - /* overflow: can't represent total as a size_t */ + if (nbytes > PY_SSIZE_T_MAX - 4*SST) + /* overflow: can't represent total as a Py_ssize_t */ return NULL; /* Resize and add decorations. We may get a new pointer here, in which -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 18:42:53 2014 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 02 Nov 2014 17:42:53 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322335=3A_Fix_crash_when_trying_to_enlarge_a_byt?= =?utf-8?q?earray_to_0x7fffffff_bytes?= Message-ID: <20141102174252.111422.12155@psf.io> https://hg.python.org/cpython/rev/f0b334ae95c9 changeset: 93361:f0b334ae95c9 parent: 93358:b2a57fe50712 parent: 93360:1590c594550e user: Antoine Pitrou date: Sun Nov 02 18:41:56 2014 +0100 summary: Issue #22335: Fix crash when trying to enlarge a bytearray to 0x7fffffff bytes on a 32-bit platform. files: Lib/test/test_bytes.py | 13 +++++++++++++ Misc/NEWS | 3 +++ Objects/bytearrayobject.c | 23 +++++++++++++++-------- Objects/obmalloc.c | 8 ++++---- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -13,9 +13,11 @@ import pickle import tempfile import unittest + import test.support import test.string_tests import test.buffer_tests +from test.support import bigaddrspacetest, MAX_Py_ssize_t if sys.flags.bytes_warning: @@ -111,6 +113,17 @@ self.assertRaises(ValueError, self.type2test, [sys.maxsize+1]) self.assertRaises(ValueError, self.type2test, [10**100]) + @bigaddrspacetest + def test_constructor_overflow(self): + size = MAX_Py_ssize_t + self.assertRaises((OverflowError, MemoryError), self.type2test, size) + try: + # Should either pass or raise an error (e.g. on debug builds with + # additional malloc() overhead), but shouldn't crash. + bytearray(size - 4) + except (OverflowError, MemoryError): + pass + def test_compare(self): b1 = self.type2test([1, 2, 3]) b2 = self.type2test([1, 2, 3]) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #22335: Fix crash when trying to enlarge a bytearray to 0x7fffffff + bytes on a 32-bit platform. + - Issue #22653: Fix an assertion failure in debug mode when doing a reentrant dict insertion in debug mode. diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -180,20 +180,22 @@ } int -PyByteArray_Resize(PyObject *self, Py_ssize_t size) +PyByteArray_Resize(PyObject *self, Py_ssize_t requested_size) { void *sval; PyByteArrayObject *obj = ((PyByteArrayObject *)self); - Py_ssize_t alloc = obj->ob_alloc; - Py_ssize_t logical_offset = obj->ob_start - obj->ob_bytes; + /* All computations are done unsigned to avoid integer overflows + (see issue #22335). */ + size_t alloc = (size_t) obj->ob_alloc; + size_t logical_offset = (size_t) (obj->ob_start - obj->ob_bytes); + size_t size = (size_t) requested_size; assert(self != NULL); assert(PyByteArray_Check(self)); - assert(size >= 0); - assert(logical_offset >= 0); assert(logical_offset <= alloc); - - if (size == Py_SIZE(self)) { + assert(requested_size >= 0); + + if (requested_size == Py_SIZE(self)) { return 0; } if (!_canresize(obj)) { @@ -225,6 +227,10 @@ alloc = size + 1; } } + if (alloc > PY_SSIZE_T_MAX) { + PyErr_NoMemory(); + return -1; + } if (logical_offset > 0) { sval = PyObject_Malloc(alloc); @@ -232,7 +238,8 @@ PyErr_NoMemory(); return -1; } - memcpy(sval, PyByteArray_AS_STRING(self), Py_MIN(size, Py_SIZE(self))); + memcpy(sval, PyByteArray_AS_STRING(self), + Py_MIN(requested_size, Py_SIZE(self))); PyObject_Free(obj->ob_bytes); } else { diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -1828,8 +1828,8 @@ bumpserialno(); total = nbytes + 4*SST; - if (total < nbytes) - /* overflow: can't represent total as a size_t */ + if (nbytes > PY_SSIZE_T_MAX - 4*SST) + /* overflow: can't represent total as a Py_ssize_t */ return NULL; if (use_calloc) @@ -1909,8 +1909,8 @@ bumpserialno(); original_nbytes = read_size_t(q - 2*SST); total = nbytes + 4*SST; - if (total < nbytes) - /* overflow: can't represent total as a size_t */ + if (nbytes > PY_SSIZE_T_MAX - 4*SST) + /* overflow: can't represent total as a Py_ssize_t */ return NULL; /* Resize and add decorations. We may get a new pointer here, in which -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 19:19:24 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 02 Nov 2014 18:19:24 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20141102181920.109262.53974@psf.io> https://hg.python.org/cpython/rev/21b4356ffc06 changeset: 93365:21b4356ffc06 parent: 93362:7e89c24245ea parent: 93364:c51d85cf57f2 user: Benjamin Peterson date: Sun Nov 02 13:19:15 2014 -0500 summary: merge 3.4 files: Doc/library/urllib.request.rst | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -48,8 +48,8 @@ only works for HTTP, HTTPS and FTP connections. If *context* is specified, it must be a :class:`ssl.SSLContext` instance - describing the various SSL options. See - :class:`~http.client.HTTPSConnection` for more details. + describing the various SSL options. See :class:`~http.client.HTTPSConnection` + for more details. The optional *cafile* and *capath* parameters specify a set of trusted CA certificates for HTTPS requests. *cafile* should point to a single @@ -118,6 +118,7 @@ .. versionchanged:: 3.5 *context* was added. + .. function:: install_opener(opener) Install an :class:`OpenerDirector` instance as the default global opener. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 19:19:24 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 02 Nov 2014 18:19:24 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_wrap?= Message-ID: <20141102181920.35270.70983@psf.io> https://hg.python.org/cpython/rev/c51d85cf57f2 changeset: 93364:c51d85cf57f2 branch: 3.4 user: Benjamin Peterson date: Sun Nov 02 13:17:56 2014 -0500 summary: wrap files: Doc/library/urllib.request.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -48,8 +48,8 @@ only works for HTTP, HTTPS and FTP connections. If *context* is specified, it must be a :class:`ssl.SSLContext` instance - describing the various SSL options. See - :class:`~http.client.HTTPSConnection` for more details. + describing the various SSL options. See :class:`~http.client.HTTPSConnection` + for more details. The optional *cafile* and *capath* parameters specify a set of trusted CA certificates for HTTPS requests. *cafile* should point to a single -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 19:19:24 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 02 Nov 2014 18:19:24 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_backport_conte?= =?utf-8?q?xt_argument_of_urlopen_=28=2322366=29_for_pep_476?= Message-ID: <20141102181920.35260.9219@psf.io> https://hg.python.org/cpython/rev/13f46fc1a002 changeset: 93363:13f46fc1a002 branch: 3.4 parent: 93360:1590c594550e user: Senthil Kumaran date: Fri Sep 19 15:23:30 2014 +0800 summary: backport context argument of urlopen (#22366) for pep 476 files: Doc/library/urllib.request.rst | 9 ++++++++- Lib/test/test_urllib.py | 8 ++++++++ Lib/urllib/request.py | 10 +++++++++- Misc/NEWS | 4 ++++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -16,7 +16,7 @@ The :mod:`urllib.request` module defines the following functions: -.. function:: urlopen(url, data=None[, timeout], *, cafile=None, capath=None, cadefault=False) +.. function:: urlopen(url, data=None[, timeout], *, cafile=None, capath=None, cadefault=False, context=None) Open the URL *url*, which can be either a string or a :class:`Request` object. @@ -47,6 +47,10 @@ the global default timeout setting will be used). This actually only works for HTTP, HTTPS and FTP connections. + If *context* is specified, it must be a :class:`ssl.SSLContext` instance + describing the various SSL options. See + :class:`~http.client.HTTPSConnection` for more details. + The optional *cafile* and *capath* parameters specify a set of trusted CA certificates for HTTPS requests. *cafile* should point to a single file containing a bundle of CA certificates, whereas *capath* should @@ -111,6 +115,9 @@ .. versionchanged:: 3.3 *cadefault* was added. + .. versionchanged:: 3.4.3 + *context* was added. + .. function:: install_opener(opener) Install an :class:`OpenerDirector` instance as the default global opener. 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 @@ -10,6 +10,7 @@ from unittest.mock import patch from test import support import os +import ssl import sys import tempfile from nturl2path import url2pathname, pathname2url @@ -379,6 +380,13 @@ with support.check_warnings(('',DeprecationWarning)): urllib.request.URLopener() + def test_cafile_and_context(self): + context = ssl.create_default_context() + with self.assertRaises(ValueError): + urllib.request.urlopen( + "https://localhost", cafile="/nonexistent/path", context=context + ) + class urlopen_DataTests(unittest.TestCase): """Test urlopen() opening a data URL.""" diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -136,9 +136,14 @@ _opener = None def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, - *, cafile=None, capath=None, cadefault=False): + *, cafile=None, capath=None, cadefault=False, context=None): global _opener if cafile or capath or cadefault: + if context is not None: + raise ValueError( + "You can't pass both context and any of cafile, capath, and " + "cadefault" + ) if not _have_ssl: raise ValueError('SSL support not available') context = ssl._create_stdlib_context(cert_reqs=ssl.CERT_REQUIRED, @@ -146,6 +151,9 @@ capath=capath) https_handler = HTTPSHandler(context=context, check_hostname=True) opener = build_opener(https_handler) + elif context: + https_handler = HTTPSHandler(context=context) + opener = build_opener(https_handler) elif _opener is None: _opener = opener = build_opener() else: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,10 @@ Library ------- +- Issue #22366: urllib.request.urlopen will accept a context object + (SSLContext) as an argument which will then used be for HTTPS connection. + Patch by Alex Gaynor. + - Issue #22776: Brought excluded code into the scope of a try block in SysLogHandler.emit(). -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 21:22:45 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Nov 2014 20:22:45 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322775=3A_Fixed_unpickling_of_http=2Ecookies=2ES?= =?utf-8?q?impleCookie_with_protocol_2?= Message-ID: <20141102202244.101668.84743@psf.io> https://hg.python.org/cpython/rev/caa8f9248ab8 changeset: 93367:caa8f9248ab8 parent: 93365:21b4356ffc06 parent: 93366:7be6ef737aaf user: Serhiy Storchaka date: Sun Nov 02 22:19:56 2014 +0200 summary: Issue #22775: Fixed unpickling of http.cookies.SimpleCookie with protocol 2 and above. Patch by Tim Graham. files: Lib/http/cookies.py | 8 ++++++-- Lib/test/pickletester.py | 2 +- Lib/test/test_http_cookies.py | 15 ++++++++++++++- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py --- a/Lib/http/cookies.py +++ b/Lib/http/cookies.py @@ -486,8 +486,12 @@ def __setitem__(self, key, value): """Dictionary style assignment.""" - rval, cval = self.value_encode(value) - self.__set(key, rval, cval) + if isinstance(value, Morsel): + # allow assignment of constructed Morsels (e.g. for pickling) + dict.__setitem__(self, key, value) + else: + rval, cval = self.value_encode(value) + self.__set(key, rval, cval) def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"): """Return a string suitable for HTTP.""" diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -1284,7 +1284,7 @@ loaded = self.loads(DATA5) self.assertEqual(type(loaded), SimpleCookie) self.assertEqual(list(loaded.keys()), ["key"]) - self.assertEqual(loaded["key"].value, "Set-Cookie: key=value") + self.assertEqual(loaded["key"].value, "value") for (exc, data) in DATA7.items(): loaded = self.loads(data) diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py --- a/Lib/test/test_http_cookies.py +++ b/Lib/test/test_http_cookies.py @@ -3,7 +3,7 @@ from test.support import run_unittest, run_doctest, check_warnings import unittest from http import cookies - +import pickle import warnings class CookieTests(unittest.TestCase): @@ -187,6 +187,19 @@ self.assertEqual(dict(C), {}) self.assertEqual(C.output(), '') + def test_pickle(self): + rawdata = 'Customer="WILE_E_COYOTE"; Path=/acme; Version=1' + expected_output = 'Set-Cookie: %s' % rawdata + + C = cookies.SimpleCookie() + C.load(rawdata) + self.assertEqual(C.output(), expected_output) + + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(proto=proto): + C1 = pickle.loads(pickle.dumps(C, protocol=proto)) + self.assertEqual(C1.output(), expected_output) + class MorselTests(unittest.TestCase): """Tests for the Morsel object.""" diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -496,6 +496,7 @@ Shelley Gooch David Goodger Hans de Graaff +Tim Graham Kim Gr?sman Nathaniel Gray Eddy De Greef diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -183,6 +183,9 @@ Library ------- +- Issue #22775: Fixed unpickling of http.cookies.SimpleCookie with protocol 2 + and above. Patch by Tim Graham. + - Issue #22776: Brought excluded code into the scope of a try block in SysLogHandler.emit(). -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 21:22:44 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Nov 2014 20:22:44 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyNzc1?= =?utf-8?q?=3A_Fixed_unpickling_of_http=2Ecookies=2ESimpleCookie_with_prot?= =?utf-8?q?ocol_2?= Message-ID: <20141102202244.111412.63530@psf.io> https://hg.python.org/cpython/rev/7be6ef737aaf changeset: 93366:7be6ef737aaf branch: 3.4 parent: 93364:c51d85cf57f2 user: Serhiy Storchaka date: Sun Nov 02 22:18:25 2014 +0200 summary: Issue #22775: Fixed unpickling of http.cookies.SimpleCookie with protocol 2 and above. Patch by Tim Graham. files: Lib/http/cookies.py | 8 ++++++-- Lib/test/pickletester.py | 2 +- Lib/test/test_http_cookies.py | 15 ++++++++++++++- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py --- a/Lib/http/cookies.py +++ b/Lib/http/cookies.py @@ -486,8 +486,12 @@ def __setitem__(self, key, value): """Dictionary style assignment.""" - rval, cval = self.value_encode(value) - self.__set(key, rval, cval) + if isinstance(value, Morsel): + # allow assignment of constructed Morsels (e.g. for pickling) + dict.__setitem__(self, key, value) + else: + rval, cval = self.value_encode(value) + self.__set(key, rval, cval) def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"): """Return a string suitable for HTTP.""" diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -1284,7 +1284,7 @@ loaded = self.loads(DATA5) self.assertEqual(type(loaded), SimpleCookie) self.assertEqual(list(loaded.keys()), ["key"]) - self.assertEqual(loaded["key"].value, "Set-Cookie: key=value") + self.assertEqual(loaded["key"].value, "value") for (exc, data) in DATA7.items(): loaded = self.loads(data) diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py --- a/Lib/test/test_http_cookies.py +++ b/Lib/test/test_http_cookies.py @@ -3,7 +3,7 @@ from test.support import run_unittest, run_doctest, check_warnings import unittest from http import cookies - +import pickle import warnings class CookieTests(unittest.TestCase): @@ -187,6 +187,19 @@ self.assertEqual(dict(C), {}) self.assertEqual(C.output(), '') + def test_pickle(self): + rawdata = 'Customer="WILE_E_COYOTE"; Path=/acme; Version=1' + expected_output = 'Set-Cookie: %s' % rawdata + + C = cookies.SimpleCookie() + C.load(rawdata) + self.assertEqual(C.output(), expected_output) + + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(proto=proto): + C1 = pickle.loads(pickle.dumps(C, protocol=proto)) + self.assertEqual(C1.output(), expected_output) + class MorselTests(unittest.TestCase): """Tests for the Morsel object.""" diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -492,6 +492,7 @@ Shelley Gooch David Goodger Hans de Graaff +Tim Graham Nathaniel Gray Eddy De Greef Grant Griffin diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,9 @@ Library ------- +- Issue #22775: Fixed unpickling of http.cookies.SimpleCookie with protocol 2 + and above. Patch by Tim Graham. + - Issue #22366: urllib.request.urlopen will accept a context object (SSLContext) as an argument which will then used be for HTTPS connection. Patch by Alex Gaynor. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 2 21:37:48 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 02 Nov 2014 20:37:48 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIyNzc1?= =?utf-8?q?=3A_Fixed_unpickling_of_Cookie=2ESimpleCookie_with_protocol_2?= =?utf-8?q?=2E?= Message-ID: <20141102203747.120710.6007@psf.io> https://hg.python.org/cpython/rev/515331e0ca0c changeset: 93368:515331e0ca0c branch: 2.7 parent: 93349:16dfefe67c1f user: Serhiy Storchaka date: Sun Nov 02 22:35:47 2014 +0200 summary: Issue #22775: Fixed unpickling of Cookie.SimpleCookie with protocol 2. Patch by Tim Graham. files: Lib/Cookie.py | 8 ++++++-- Lib/test/test_cookie.py | 13 +++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Lib/Cookie.py b/Lib/Cookie.py --- a/Lib/Cookie.py +++ b/Lib/Cookie.py @@ -591,8 +591,12 @@ def __setitem__(self, key, value): """Dictionary style assignment.""" - rval, cval = self.value_encode(value) - self.__set(key, rval, cval) + if isinstance(value, Morsel): + # allow assignment of constructed Morsels (e.g. for pickling) + dict.__setitem__(self, key, value) + else: + rval, cval = self.value_encode(value) + self.__set(key, rval, cval) # end __setitem__ def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"): diff --git a/Lib/test/test_cookie.py b/Lib/test/test_cookie.py --- a/Lib/test/test_cookie.py +++ b/Lib/test/test_cookie.py @@ -3,6 +3,7 @@ from test.test_support import run_unittest, run_doctest, check_warnings import unittest import Cookie +import pickle class CookieTests(unittest.TestCase): @@ -141,6 +142,18 @@ self.assertEqual(dict(C), {}) self.assertEqual(C.output(), '') + def test_pickle(self): + rawdata = 'Customer="WILE_E_COYOTE"; Path=/acme; Version=1' + expected_output = 'Set-Cookie: %s' % rawdata + + C = Cookie.SimpleCookie() + C.load(rawdata) + self.assertEqual(C.output(), expected_output) + + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + C1 = pickle.loads(pickle.dumps(C, protocol=proto)) + self.assertEqual(C1.output(), expected_output) + def test_main(): run_unittest(CookieTests) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -484,6 +484,7 @@ Shelley Gooch David Goodger Hans de Graaff +Tim Graham Nathaniel Gray Eddy De Greef Grant Griffin diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,6 +37,9 @@ Library ------- +- Issue #22775: Fixed unpickling of Cookie.SimpleCookie with protocol 2. + Patch by Tim Graham. + - Issue #22776: Brought excluded code into the scope of a try block in SysLogHandler.emit(). -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Mon Nov 3 10:05:19 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 03 Nov 2014 10:05:19 +0100 Subject: [Python-checkins] Daily reference leaks (caa8f9248ab8): sum=3 Message-ID: results for caa8f9248ab8 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogM9fFaa', '-x'] From python-checkins at python.org Mon Nov 3 11:28:26 2014 From: python-checkins at python.org (georg.brandl) Date: Mon, 03 Nov 2014 10:28:26 +0000 Subject: [Python-checkins] =?utf-8?q?devguide=3A_Add_instruction_how_to_ac?= =?utf-8?q?tivate_python-gdb=2Epy?= Message-ID: <20141103102822.101690.49823@psf.io> https://hg.python.org/devguide/rev/4bf21e0cb078 changeset: 723:4bf21e0cb078 user: Georg Brandl date: Mon Nov 03 11:28:19 2014 +0100 summary: Add instruction how to activate python-gdb.py files: gdb.rst | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/gdb.rst b/gdb.rst --- a/gdb.rst +++ b/gdb.rst @@ -23,6 +23,13 @@ root directory of your checkout. Read the module docstring for details on how to use the file to enhance gdb for easier debugging of a CPython process. +To activate support, you must add the directory containing ``python-gdb.py`` +to GDB's "auto-load-safe-path". Put this in your ``~/.gdbinit`` file:: + + add-auto-load-safe-path /path/to/checkout + +You can also add multiple paths, separated by ``:``. + This is what a backtrace looks like (truncated) when this extension is enabled:: -- Repository URL: https://hg.python.org/devguide From python-checkins at python.org Mon Nov 3 20:37:00 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 03 Nov 2014 19:37:00 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjMjI0MTcp?= Message-ID: <20141103193658.120736.55619@psf.io> https://hg.python.org/cpython/rev/731375f83406 changeset: 93370:731375f83406 parent: 93367:caa8f9248ab8 parent: 93369:2afe5413d7af user: Benjamin Peterson date: Mon Nov 03 14:36:48 2014 -0500 summary: merge 3.4 (#22417) files: Doc/library/http.client.rst | 12 ++-- Doc/library/urllib.request.rst | 5 - Doc/library/xmlrpc.client.rst | 7 +- Doc/whatsnew/3.4.rst | 29 ++++++++++ Lib/http/client.py | 2 +- Lib/ssl.py | 10 ++- Lib/test/test_httplib.py | 49 +++++++++++++--- Lib/test/test_logging.py | 55 ++++++------------ Lib/test/test_ssl.py | 7 +- Lib/test/test_urllib2_localnet.py | 6 +- Misc/NEWS | 2 + 11 files changed, 115 insertions(+), 69 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 @@ -71,12 +71,6 @@ :func:`ssl.create_default_context` select the system's trusted CA certificates for you. - The recommended way to connect to HTTPS hosts on the Internet is as - follows:: - - context = ssl.create_default_context() - h = client.HTTPSConnection('www.python.org', 443, context=context) - Please read :ref:`ssl-security` for more information on best practices. .. note:: @@ -97,6 +91,12 @@ The *strict* parameter was removed. HTTP 0.9-style "Simple Responses" are no longer supported. + .. versionchanged:: 3.4.3 + This class now performs all the necessary certificate and hostname checks + by default. To revert to the previous, unverified, behavior + :func:`ssl._create_unverified_context` can be passed to the *context* + parameter. + .. class:: HTTPResponse(sock, debuglevel=0, method=None, url=None) diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -62,11 +62,6 @@ *cafile* and *capath* parameters are omitted. This will only work on some non-Windows platforms. - .. warning:: - If neither *cafile* nor *capath* is specified, and *cadefault* is ``False``, - an HTTPS request will not do any verification of the server's - certificate. - For http and https urls, this function returns a :class:`http.client.HTTPResponse` object which has the following :ref:`httpresponse-objects` methods. diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst --- a/Doc/library/xmlrpc.client.rst +++ b/Doc/library/xmlrpc.client.rst @@ -27,11 +27,10 @@ constructed data. If you need to parse untrusted or unauthenticated data see :ref:`xml-vulnerabilities`. -.. warning:: +.. versionchanged:: 3.4.3 - In the case of https URIs, :mod:`xmlrpc.client` does not do any verification - of the server's certificate. - + For https URIs, :mod:`xmlrpc.client` now performs all the necessary + certificate and hostname checks by default .. class:: ServerProxy(uri, transport=None, encoding=None, verbose=False, \ allow_none=False, use_datetime=False, \ 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 @@ -2504,3 +2504,32 @@ * 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. + +Changed in 3.4.3 +================ + +.. _pep-476: + +PEP 476: Enabling certificate verification by default for stdlib http clients +----------------------------------------------------------------------------- + +:mod:`http.client` and modules which use it, such as :mod:`urllib.request` and +:mod:`xmlrpc.client`, will now verify that the server presents a certificate +which is signed by a CA in the platform trust store and whose hostname matches +the hostname being requested by default, significantly improving security for +many applications. + +For applications which require the old previous behavior, they can pass an +alternate context:: + + import urllib.request + import ssl + + # This disables all verification + context = ssl._create_unverified_context() + + # This allows using a specific certificate for the host, which doesn't need + # to be in the trust store + context = ssl.create_default_context(cafile="/path/to/file.crt") + + urllib.request.urlopen("https://invalid-cert", context=context) diff --git a/Lib/http/client.py b/Lib/http/client.py --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -1267,7 +1267,7 @@ self.key_file = key_file self.cert_file = cert_file if context is None: - context = ssl._create_stdlib_context() + context = ssl._create_default_https_context() will_verify = context.verify_mode != ssl.CERT_NONE if check_hostname is None: check_hostname = will_verify diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -436,8 +436,7 @@ context.load_default_certs(purpose) return context - -def _create_stdlib_context(protocol=PROTOCOL_SSLv23, *, cert_reqs=None, +def _create_unverified_context(protocol=PROTOCOL_SSLv23, *, cert_reqs=None, check_hostname=False, purpose=Purpose.SERVER_AUTH, certfile=None, keyfile=None, cafile=None, capath=None, cadata=None): @@ -478,6 +477,13 @@ return context +# Used by http.client if no context is explicitly passed. +_create_default_https_context = create_default_context + + +# Backwards compatibility alias, even though it's not a public name. +_create_stdlib_context = _create_unverified_context + class SSLObject: """This class implements an interface on top of a low-level SSL object as diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -1012,13 +1012,36 @@ self.assertIn('Apache', server_string) def test_networked(self): - # Default settings: no cert verification is done + # Default settings: requires a valid cert from a trusted CA + import ssl support.requires('network') - with support.transient_internet('svn.python.org'): - h = client.HTTPSConnection('svn.python.org', 443) + with support.transient_internet('self-signed.pythontest.net'): + h = client.HTTPSConnection('self-signed.pythontest.net', 443) + with self.assertRaises(ssl.SSLError) as exc_info: + h.request('GET', '/') + self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') + + def test_networked_noverification(self): + # Switch off cert verification + import ssl + support.requires('network') + with support.transient_internet('self-signed.pythontest.net'): + context = ssl._create_unverified_context() + h = client.HTTPSConnection('self-signed.pythontest.net', 443, + context=context) h.request('GET', '/') resp = h.getresponse() - self._check_svn_python_org(resp) + self.assertIn('nginx', resp.getheader('server')) + + def test_networked_trusted_by_default_cert(self): + # Default settings: requires a valid cert from a trusted CA + support.requires('network') + with support.transient_internet('www.python.org'): + h = client.HTTPSConnection('www.python.org', 443) + h.request('GET', '/') + resp = h.getresponse() + content_type = resp.getheader('content-type') + self.assertIn('text/html', content_type) def test_networked_good_cert(self): # We feed a CA cert that validates the server's cert @@ -1037,13 +1060,23 @@ # We feed a "CA" cert that is unrelated to the server's cert import ssl support.requires('network') - with support.transient_internet('svn.python.org'): + with support.transient_internet('self-signed.pythontest.net'): context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) context.verify_mode = ssl.CERT_REQUIRED context.load_verify_locations(CERT_localhost) - h = client.HTTPSConnection('svn.python.org', 443, context=context) - with self.assertRaises(ssl.SSLError): + h = client.HTTPSConnection('self-signed.pythontest.net', 443, context=context) + with self.assertRaises(ssl.SSLError) as exc_info: h.request('GET', '/') + self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') + + def test_local_unknown_cert(self): + # The custom cert isn't known to the default trust bundle + import ssl + server = self.make_server(CERT_localhost) + h = client.HTTPSConnection('localhost', server.port) + with self.assertRaises(ssl.SSLError) as exc_info: + h.request('GET', '/') + self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') def test_local_good_hostname(self): # The (valid) cert validates the HTTP hostname @@ -1056,7 +1089,6 @@ h.request('GET', '/nonexistent') resp = h.getresponse() self.assertEqual(resp.status, 404) - del server def test_local_bad_hostname(self): # The (valid) cert doesn't validate the HTTP hostname @@ -1079,7 +1111,6 @@ h.request('GET', '/nonexistent') resp = h.getresponse() self.assertEqual(resp.status, 404) - del server @unittest.skipIf(not hasattr(client, 'HTTPSConnection'), 'http.client.HTTPSConnection not available') 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 @@ -1627,36 +1627,6 @@ class HTTPHandlerTest(BaseTest): """Test for HTTPHandler.""" - PEMFILE = """-----BEGIN RSA PRIVATE KEY----- -MIICXQIBAAKBgQDGT4xS5r91rbLJQK2nUDenBhBG6qFk+bVOjuAGC/LSHlAoBnvG -zQG3agOG+e7c5z2XT8m2ktORLqG3E4mYmbxgyhDrzP6ei2Anc+pszmnxPoK3Puh5 -aXV+XKt0bU0C1m2+ACmGGJ0t3P408art82nOxBw8ZHgIg9Dtp6xIUCyOqwIDAQAB -AoGBAJFTnFboaKh5eUrIzjmNrKsG44jEyy+vWvHN/FgSC4l103HxhmWiuL5Lv3f7 -0tMp1tX7D6xvHwIG9VWvyKb/Cq9rJsDibmDVIOslnOWeQhG+XwJyitR0pq/KlJIB -5LjORcBw795oKWOAi6RcOb1ON59tysEFYhAGQO9k6VL621gRAkEA/Gb+YXULLpbs -piXN3q4zcHzeaVANo69tUZ6TjaQqMeTxE4tOYM0G0ZoSeHEdaP59AOZGKXXNGSQy -2z/MddcYGQJBAMkjLSYIpOLJY11ja8OwwswFG2hEzHe0cS9bzo++R/jc1bHA5R0Y -i6vA5iPi+wopPFvpytdBol7UuEBe5xZrxWMCQQCWxELRHiP2yWpEeLJ3gGDzoXMN -PydWjhRju7Bx3AzkTtf+D6lawz1+eGTuEss5i0JKBkMEwvwnN2s1ce+EuF4JAkBb -E96h1lAzkVW5OAfYOPY8RCPA90ZO/hoyg7PpSxR0ECuDrgERR8gXIeYUYfejBkEa -rab4CfRoVJKKM28Yq/xZAkBvuq670JRCwOgfUTdww7WpdOQBYPkzQccsKNCslQW8 -/DyW6y06oQusSENUvynT6dr3LJxt/NgZPhZX2+k1eYDV ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIICGzCCAYSgAwIBAgIJAIq84a2Q/OvlMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV -BAMTCWxvY2FsaG9zdDAeFw0xMTA1MjExMDIzMzNaFw03NTAzMjEwMzU1MTdaMBQx -EjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA -xk+MUua/da2yyUCtp1A3pwYQRuqhZPm1To7gBgvy0h5QKAZ7xs0Bt2oDhvnu3Oc9 -l0/JtpLTkS6htxOJmJm8YMoQ68z+notgJ3PqbM5p8T6Ctz7oeWl1flyrdG1NAtZt -vgAphhidLdz+NPGq7fNpzsQcPGR4CIPQ7aesSFAsjqsCAwEAAaN1MHMwHQYDVR0O -BBYEFLWaUPO6N7efGiuoS9i3DVYcUwn0MEQGA1UdIwQ9MDuAFLWaUPO6N7efGiuo -S9i3DVYcUwn0oRikFjAUMRIwEAYDVQQDEwlsb2NhbGhvc3SCCQCKvOGtkPzr5TAM -BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAMK5whPjLNQK1Ivvk88oqJqq -4f889OwikGP0eUhOBhbFlsZs+jq5YZC2UzHz+evzKBlgAP1u4lP/cB85CnjvWqM+ -1c/lywFHQ6HOdDeQ1L72tSYMrNOG4XNmLn0h7rx6GoTU7dcFRfseahBCq8mv0IDt -IRbTpvlHWPjsSvHz0ZOH ------END CERTIFICATE-----""" - def setUp(self): """Set up an HTTP server to receive log messages, and a HTTPHandler pointing to that server's address and port.""" @@ -1686,15 +1656,26 @@ if secure: try: import ssl - fd, fn = tempfile.mkstemp() - os.close(fd) - with open(fn, 'w') as f: - f.write(self.PEMFILE) - sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - sslctx.load_cert_chain(fn) - os.unlink(fn) except ImportError: sslctx = None + else: + here = os.path.dirname(__file__) + localhost_cert = os.path.join(here, "keycert.pem") + sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + sslctx.load_cert_chain(localhost_cert) + # Unfortunately, HTTPHandler doesn't allow us to change the + # SSLContext used by HTTPSConnection, so we have to + # monkeypatch. This can be cleaned up if issue 22788 is + # fixed. + old = ssl._create_default_https_context + def restore_handler(): + ssl._create_default_https_context = old + self.addCleanup(restore_handler) + def hack_create_ctx(): + ctx = old() + ctx.load_verify_locations(localhost_cert) + return ctx + ssl._create_default_https_context = hack_create_ctx else: sslctx = None self.server = server = TestHTTPServer(addr, self.handle_request, 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 @@ -2582,9 +2582,10 @@ d1 = f.read() d2 = '' # now fetch the same data from the HTTPS server - url = 'https://%s:%d/%s' % ( - HOST, server.port, os.path.split(CERTFILE)[1]) - f = urllib.request.urlopen(url) + url = 'https://localhost:%d/%s' % ( + server.port, os.path.split(CERTFILE)[1]) + context = ssl.create_default_context(cafile=CERTFILE) + f = urllib.request.urlopen(url, context=context) try: dlen = f.info().get("content-length") if dlen and (int(dlen) > 0): 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 @@ -545,7 +545,8 @@ def test_https(self): handler = self.start_https_server() - data = self.urlopen("https://localhost:%s/bizarre" % handler.port) + context = ssl.create_default_context(cafile=CERT_localhost) + data = self.urlopen("https://localhost:%s/bizarre" % handler.port, context=context) self.assertEqual(data, b"we care a bit") def test_https_with_cafile(self): @@ -584,7 +585,8 @@ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) context.set_servername_callback(cb_sni) handler = self.start_https_server(context=context, certfile=CERT_localhost) - self.urlopen("https://localhost:%s" % handler.port) + context = ssl.create_default_context(cafile=CERT_localhost) + self.urlopen("https://localhost:%s" % handler.port, context=context) self.assertEqual(sni_name, "localhost") def test_sending_headers(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -183,6 +183,8 @@ Library ------- +- Issue #22417: Verify certificates by default in httplib (PEP 476). + - Issue #22775: Fixed unpickling of http.cookies.SimpleCookie with protocol 2 and above. Patch by Tim Graham. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 3 20:37:08 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 03 Nov 2014 19:37:08 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogUEVQIDQ3NjogZW5h?= =?utf-8?q?ble_HTTPS_certificate_verification_by_default_=28=2322417=29?= Message-ID: <20141103193654.35246.40303@psf.io> https://hg.python.org/cpython/rev/2afe5413d7af changeset: 93369:2afe5413d7af branch: 3.4 parent: 93366:7be6ef737aaf user: Benjamin Peterson date: Mon Nov 03 14:29:33 2014 -0500 summary: PEP 476: enable HTTPS certificate verification by default (#22417) Patch by Alex Gaynor with some modifications by me. files: Doc/library/http.client.rst | 12 ++-- Doc/library/urllib.request.rst | 5 - Doc/library/xmlrpc.client.rst | 7 +- Doc/whatsnew/3.4.rst | 29 ++++++++++ Lib/http/client.py | 2 +- Lib/ssl.py | 11 +++- Lib/test/test_httplib.py | 49 +++++++++++++--- Lib/test/test_logging.py | 55 ++++++------------ Lib/test/test_ssl.py | 7 +- Lib/test/test_urllib2_localnet.py | 6 +- Misc/NEWS | 2 + 11 files changed, 116 insertions(+), 69 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 @@ -71,12 +71,6 @@ :func:`ssl.create_default_context` select the system's trusted CA certificates for you. - The recommended way to connect to HTTPS hosts on the Internet is as - follows:: - - context = ssl.create_default_context() - h = client.HTTPSConnection('www.python.org', 443, context=context) - Please read :ref:`ssl-security` for more information on best practices. .. note:: @@ -97,6 +91,12 @@ The *strict* parameter was removed. HTTP 0.9-style "Simple Responses" are no longer supported. + .. versionchanged:: 3.4.3 + This class now performs all the necessary certificate and hostname checks + by default. To revert to the previous, unverified, behavior + :func:`ssl._create_unverified_context` can be passed to the *context* + parameter. + .. class:: HTTPResponse(sock, debuglevel=0, method=None, url=None) diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -62,11 +62,6 @@ *cafile* and *capath* parameters are omitted. This will only work on some non-Windows platforms. - .. warning:: - If neither *cafile* nor *capath* is specified, and *cadefault* is ``False``, - an HTTPS request will not do any verification of the server's - certificate. - For http and https urls, this function returns a :class:`http.client.HTTPResponse` object which has the following :ref:`httpresponse-objects` methods. diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst --- a/Doc/library/xmlrpc.client.rst +++ b/Doc/library/xmlrpc.client.rst @@ -27,11 +27,10 @@ constructed data. If you need to parse untrusted or unauthenticated data see :ref:`xml-vulnerabilities`. -.. warning:: +.. versionchanged:: 3.4.3 - In the case of https URIs, :mod:`xmlrpc.client` does not do any verification - of the server's certificate. - + For https URIs, :mod:`xmlrpc.client` now performs all the necessary + certificate and hostname checks by default .. class:: ServerProxy(uri, transport=None, encoding=None, verbose=False, \ allow_none=False, use_datetime=False, \ 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 @@ -2504,3 +2504,32 @@ * 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. + +Changed in 3.4.3 +================ + +.. _pep-476: + +PEP 476: Enabling certificate verification by default for stdlib http clients +----------------------------------------------------------------------------- + +:mod:`http.client` and modules which use it, such as :mod:`urllib.request` and +:mod:`xmlrpc.client`, will now verify that the server presents a certificate +which is signed by a CA in the platform trust store and whose hostname matches +the hostname being requested by default, significantly improving security for +many applications. + +For applications which require the old previous behavior, they can pass an +alternate context:: + + import urllib.request + import ssl + + # This disables all verification + context = ssl._create_unverified_context() + + # This allows using a specific certificate for the host, which doesn't need + # to be in the trust store + context = ssl.create_default_context(cafile="/path/to/file.crt") + + urllib.request.urlopen("https://invalid-cert", context=context) diff --git a/Lib/http/client.py b/Lib/http/client.py --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -1203,7 +1203,7 @@ self.key_file = key_file self.cert_file = cert_file if context is None: - context = ssl._create_stdlib_context() + context = ssl._create_default_https_context() will_verify = context.verify_mode != ssl.CERT_NONE if check_hostname is None: check_hostname = will_verify diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -441,8 +441,7 @@ context.load_default_certs(purpose) return context - -def _create_stdlib_context(protocol=PROTOCOL_SSLv23, *, cert_reqs=None, +def _create_unverified_context(protocol=PROTOCOL_SSLv23, *, cert_reqs=None, check_hostname=False, purpose=Purpose.SERVER_AUTH, certfile=None, keyfile=None, cafile=None, capath=None, cadata=None): @@ -480,6 +479,14 @@ return context +# Used by http.client if no context is explicitly passed. +_create_default_https_context = create_default_context + + +# Backwards compatibility alias, even though it's not a public name. +_create_stdlib_context = _create_unverified_context + + class SSLSocket(socket): """This class implements a subtype of socket.socket that wraps the underlying OS socket in an SSL context when necessary, and diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -778,13 +778,36 @@ self.assertIn('Apache', server_string) def test_networked(self): - # Default settings: no cert verification is done + # Default settings: requires a valid cert from a trusted CA + import ssl support.requires('network') - with support.transient_internet('svn.python.org'): - h = client.HTTPSConnection('svn.python.org', 443) + with support.transient_internet('self-signed.pythontest.net'): + h = client.HTTPSConnection('self-signed.pythontest.net', 443) + with self.assertRaises(ssl.SSLError) as exc_info: + h.request('GET', '/') + self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') + + def test_networked_noverification(self): + # Switch off cert verification + import ssl + support.requires('network') + with support.transient_internet('self-signed.pythontest.net'): + context = ssl._create_unverified_context() + h = client.HTTPSConnection('self-signed.pythontest.net', 443, + context=context) h.request('GET', '/') resp = h.getresponse() - self._check_svn_python_org(resp) + self.assertIn('nginx', resp.getheader('server')) + + def test_networked_trusted_by_default_cert(self): + # Default settings: requires a valid cert from a trusted CA + support.requires('network') + with support.transient_internet('www.python.org'): + h = client.HTTPSConnection('www.python.org', 443) + h.request('GET', '/') + resp = h.getresponse() + content_type = resp.getheader('content-type') + self.assertIn('text/html', content_type) def test_networked_good_cert(self): # We feed a CA cert that validates the server's cert @@ -803,13 +826,23 @@ # We feed a "CA" cert that is unrelated to the server's cert import ssl support.requires('network') - with support.transient_internet('svn.python.org'): + with support.transient_internet('self-signed.pythontest.net'): context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) context.verify_mode = ssl.CERT_REQUIRED context.load_verify_locations(CERT_localhost) - h = client.HTTPSConnection('svn.python.org', 443, context=context) - with self.assertRaises(ssl.SSLError): + h = client.HTTPSConnection('self-signed.pythontest.net', 443, context=context) + with self.assertRaises(ssl.SSLError) as exc_info: h.request('GET', '/') + self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') + + def test_local_unknown_cert(self): + # The custom cert isn't known to the default trust bundle + import ssl + server = self.make_server(CERT_localhost) + h = client.HTTPSConnection('localhost', server.port) + with self.assertRaises(ssl.SSLError) as exc_info: + h.request('GET', '/') + self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') def test_local_good_hostname(self): # The (valid) cert validates the HTTP hostname @@ -822,7 +855,6 @@ h.request('GET', '/nonexistent') resp = h.getresponse() self.assertEqual(resp.status, 404) - del server def test_local_bad_hostname(self): # The (valid) cert doesn't validate the HTTP hostname @@ -845,7 +877,6 @@ h.request('GET', '/nonexistent') resp = h.getresponse() self.assertEqual(resp.status, 404) - del server @unittest.skipIf(not hasattr(client, 'HTTPSConnection'), 'http.client.HTTPSConnection not available') 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 @@ -1631,36 +1631,6 @@ class HTTPHandlerTest(BaseTest): """Test for HTTPHandler.""" - PEMFILE = """-----BEGIN RSA PRIVATE KEY----- -MIICXQIBAAKBgQDGT4xS5r91rbLJQK2nUDenBhBG6qFk+bVOjuAGC/LSHlAoBnvG -zQG3agOG+e7c5z2XT8m2ktORLqG3E4mYmbxgyhDrzP6ei2Anc+pszmnxPoK3Puh5 -aXV+XKt0bU0C1m2+ACmGGJ0t3P408art82nOxBw8ZHgIg9Dtp6xIUCyOqwIDAQAB -AoGBAJFTnFboaKh5eUrIzjmNrKsG44jEyy+vWvHN/FgSC4l103HxhmWiuL5Lv3f7 -0tMp1tX7D6xvHwIG9VWvyKb/Cq9rJsDibmDVIOslnOWeQhG+XwJyitR0pq/KlJIB -5LjORcBw795oKWOAi6RcOb1ON59tysEFYhAGQO9k6VL621gRAkEA/Gb+YXULLpbs -piXN3q4zcHzeaVANo69tUZ6TjaQqMeTxE4tOYM0G0ZoSeHEdaP59AOZGKXXNGSQy -2z/MddcYGQJBAMkjLSYIpOLJY11ja8OwwswFG2hEzHe0cS9bzo++R/jc1bHA5R0Y -i6vA5iPi+wopPFvpytdBol7UuEBe5xZrxWMCQQCWxELRHiP2yWpEeLJ3gGDzoXMN -PydWjhRju7Bx3AzkTtf+D6lawz1+eGTuEss5i0JKBkMEwvwnN2s1ce+EuF4JAkBb -E96h1lAzkVW5OAfYOPY8RCPA90ZO/hoyg7PpSxR0ECuDrgERR8gXIeYUYfejBkEa -rab4CfRoVJKKM28Yq/xZAkBvuq670JRCwOgfUTdww7WpdOQBYPkzQccsKNCslQW8 -/DyW6y06oQusSENUvynT6dr3LJxt/NgZPhZX2+k1eYDV ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIICGzCCAYSgAwIBAgIJAIq84a2Q/OvlMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV -BAMTCWxvY2FsaG9zdDAeFw0xMTA1MjExMDIzMzNaFw03NTAzMjEwMzU1MTdaMBQx -EjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA -xk+MUua/da2yyUCtp1A3pwYQRuqhZPm1To7gBgvy0h5QKAZ7xs0Bt2oDhvnu3Oc9 -l0/JtpLTkS6htxOJmJm8YMoQ68z+notgJ3PqbM5p8T6Ctz7oeWl1flyrdG1NAtZt -vgAphhidLdz+NPGq7fNpzsQcPGR4CIPQ7aesSFAsjqsCAwEAAaN1MHMwHQYDVR0O -BBYEFLWaUPO6N7efGiuoS9i3DVYcUwn0MEQGA1UdIwQ9MDuAFLWaUPO6N7efGiuo -S9i3DVYcUwn0oRikFjAUMRIwEAYDVQQDEwlsb2NhbGhvc3SCCQCKvOGtkPzr5TAM -BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAMK5whPjLNQK1Ivvk88oqJqq -4f889OwikGP0eUhOBhbFlsZs+jq5YZC2UzHz+evzKBlgAP1u4lP/cB85CnjvWqM+ -1c/lywFHQ6HOdDeQ1L72tSYMrNOG4XNmLn0h7rx6GoTU7dcFRfseahBCq8mv0IDt -IRbTpvlHWPjsSvHz0ZOH ------END CERTIFICATE-----""" - def setUp(self): """Set up an HTTP server to receive log messages, and a HTTPHandler pointing to that server's address and port.""" @@ -1690,15 +1660,26 @@ if secure: try: import ssl - fd, fn = tempfile.mkstemp() - os.close(fd) - with open(fn, 'w') as f: - f.write(self.PEMFILE) - sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - sslctx.load_cert_chain(fn) - os.unlink(fn) except ImportError: sslctx = None + else: + here = os.path.dirname(__file__) + localhost_cert = os.path.join(here, "keycert.pem") + sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + sslctx.load_cert_chain(localhost_cert) + # Unfortunately, HTTPHandler doesn't allow us to change the + # SSLContext used by HTTPSConnection, so we have to + # monkeypatch. This can be cleaned up if issue 22788 is + # fixed. + old = ssl._create_default_https_context + def restore_handler(): + ssl._create_default_https_context = old + self.addCleanup(restore_handler) + def hack_create_ctx(): + ctx = old() + ctx.load_verify_locations(localhost_cert) + return ctx + ssl._create_default_https_context = hack_create_ctx else: sslctx = None self.server = server = TestHTTPServer(addr, self.handle_request, 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 @@ -2337,9 +2337,10 @@ d1 = f.read() d2 = '' # now fetch the same data from the HTTPS server - url = 'https://%s:%d/%s' % ( - HOST, server.port, os.path.split(CERTFILE)[1]) - f = urllib.request.urlopen(url) + url = 'https://localhost:%d/%s' % ( + server.port, os.path.split(CERTFILE)[1]) + context = ssl.create_default_context(cafile=CERTFILE) + f = urllib.request.urlopen(url, context=context) try: dlen = f.info().get("content-length") if dlen and (int(dlen) > 0): 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 @@ -545,7 +545,8 @@ def test_https(self): handler = self.start_https_server() - data = self.urlopen("https://localhost:%s/bizarre" % handler.port) + context = ssl.create_default_context(cafile=CERT_localhost) + data = self.urlopen("https://localhost:%s/bizarre" % handler.port, context=context) self.assertEqual(data, b"we care a bit") def test_https_with_cafile(self): @@ -584,7 +585,8 @@ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) context.set_servername_callback(cb_sni) handler = self.start_https_server(context=context, certfile=CERT_localhost) - self.urlopen("https://localhost:%s" % handler.port) + context = ssl.create_default_context(cafile=CERT_localhost) + self.urlopen("https://localhost:%s" % handler.port, context=context) self.assertEqual(sni_name, "localhost") def test_sending_headers(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,8 @@ Library ------- +- Issue #22417: Verify certificates by default in httplib (PEP 476). + - Issue #22775: Fixed unpickling of http.cookies.SimpleCookie with protocol 2 and above. Patch by Tim Graham. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 3 21:13:36 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 03 Nov 2014 20:13:36 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMyk6?= =?utf-8?q?_merge_3=2E2?= Message-ID: <20141103201258.35250.40427@psf.io> https://hg.python.org/cpython/rev/b5d92b52d494 changeset: 93372:b5d92b52d494 branch: 3.3 parent: 93137:a34be8915cf6 parent: 93371:c16e047965a2 user: Benjamin Peterson date: Mon Nov 03 15:11:53 2014 -0500 summary: merge 3.2 files: Lib/test/test_socket.py | 7 ++++--- 1 files changed, 4 insertions(+), 3 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 @@ -1188,9 +1188,10 @@ if e.errno == socket.EAI_NODATA: self.skipTest('internet access required for this test') # these should all be successful - socket.gethostbyname('?????????.python.org') - socket.gethostbyname_ex('?????????.python.org') - socket.getaddrinfo('?????????.python.org',0,socket.AF_UNSPEC,socket.SOCK_STREAM) + domain = '?????????.pythontest.net' + socket.gethostbyname(domain) + socket.gethostbyname_ex(domain) + socket.getaddrinfo(domain,0,socket.AF_UNSPEC,socket.SOCK_STREAM) # this may not work if the forward lookup choses the IPv6 address, as that doesn't # have a reverse entry yet # socket.gethostbyaddr('?????????.python.org') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 3 21:13:36 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 03 Nov 2014 20:13:36 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuNCk6?= =?utf-8?q?_merge_3=2E3?= Message-ID: <20141103201259.120728.39962@psf.io> https://hg.python.org/cpython/rev/a716afa8e23f changeset: 93373:a716afa8e23f branch: 3.4 parent: 93369:2afe5413d7af parent: 93372:b5d92b52d494 user: Benjamin Peterson date: Mon Nov 03 15:12:06 2014 -0500 summary: merge 3.3 files: Lib/test/test_socket.py | 7 ++++--- 1 files changed, 4 insertions(+), 3 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 @@ -1291,9 +1291,10 @@ if e.errno == socket.EAI_NODATA: self.skipTest('internet access required for this test') # these should all be successful - socket.gethostbyname('?????????.python.org') - socket.gethostbyname_ex('?????????.python.org') - socket.getaddrinfo('?????????.python.org',0,socket.AF_UNSPEC,socket.SOCK_STREAM) + domain = '?????????.pythontest.net' + socket.gethostbyname(domain) + socket.gethostbyname_ex(domain) + socket.getaddrinfo(domain,0,socket.AF_UNSPEC,socket.SOCK_STREAM) # this may not work if the forward lookup choses the IPv6 address, as that doesn't # have a reverse entry yet # socket.gethostbyaddr('?????????.python.org') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 3 21:13:36 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 03 Nov 2014 20:13:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20141103201259.35262.1257@psf.io> https://hg.python.org/cpython/rev/bd3e9dcbd9ab changeset: 93374:bd3e9dcbd9ab parent: 93370:731375f83406 parent: 93373:a716afa8e23f user: Benjamin Peterson date: Mon Nov 03 15:12:52 2014 -0500 summary: merge 3.4 files: Lib/test/test_socket.py | 7 ++++--- 1 files changed, 4 insertions(+), 3 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 @@ -1293,9 +1293,10 @@ if e.errno == socket.EAI_NODATA: self.skipTest('internet access required for this test') # these should all be successful - socket.gethostbyname('?????????.python.org') - socket.gethostbyname_ex('?????????.python.org') - socket.getaddrinfo('?????????.python.org',0,socket.AF_UNSPEC,socket.SOCK_STREAM) + domain = '?????????.pythontest.net' + socket.gethostbyname(domain) + socket.gethostbyname_ex(domain) + socket.getaddrinfo(domain,0,socket.AF_UNSPEC,socket.SOCK_STREAM) # this may not work if the forward lookup choses the IPv6 address, as that doesn't # have a reverse entry yet # socket.gethostbyaddr('?????????.python.org') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 3 21:13:36 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 03 Nov 2014 20:13:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_move_idna_test?= =?utf-8?q?_domain_to_pythontest=2Enet?= Message-ID: <20141103201257.101692.78642@psf.io> https://hg.python.org/cpython/rev/c16e047965a2 changeset: 93371:c16e047965a2 branch: 3.2 parent: 92975:eac54f7a8018 user: Benjamin Peterson date: Mon Nov 03 15:10:47 2014 -0500 summary: move idna test domain to pythontest.net files: Lib/test/test_socket.py | 7 ++++--- 1 files changed, 4 insertions(+), 3 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 @@ -775,9 +775,10 @@ def test_idna(self): support.requires('network') # these should all be successful - socket.gethostbyname('?????????.python.org') - socket.gethostbyname_ex('?????????.python.org') - socket.getaddrinfo('?????????.python.org',0,socket.AF_UNSPEC,socket.SOCK_STREAM) + domain = '?????????.pythontest.net' + socket.gethostbyname(domain) + socket.gethostbyname_ex(domain) + socket.getaddrinfo(domain,0,socket.AF_UNSPEC,socket.SOCK_STREAM) # this may not work if the forward lookup choses the IPv6 address, as that doesn't # have a reverse entry yet # socket.gethostbyaddr('?????????.python.org') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 3 23:04:09 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 03 Nov 2014 22:04:09 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_context_has_been_backporte?= =?utf-8?q?d_so_fix_versionchanged?= Message-ID: <20141103220404.120724.36937@psf.io> https://hg.python.org/cpython/rev/aeb1f941663f changeset: 93375:aeb1f941663f user: Benjamin Peterson date: Mon Nov 03 17:04:01 2014 -0500 summary: context has been backported so fix versionchanged files: Doc/library/urllib.request.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -110,7 +110,7 @@ .. versionchanged:: 3.3 *cadefault* was added. - .. versionchanged:: 3.5 + .. versionchanged:: 3.4.3 *context* was added. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 4 03:12:17 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 04 Nov 2014 02:12:17 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_test_that_keyf?= =?utf-8?q?ile_can_be_None?= Message-ID: <20141104021216.108377.16235@psf.io> https://hg.python.org/cpython/rev/f9a72b3eca7c changeset: 93378:f9a72b3eca7c branch: 2.7 parent: 93368:515331e0ca0c user: Benjamin Peterson date: Mon Nov 03 21:05:01 2014 -0500 summary: test that keyfile can be None files: Lib/test/test_ssl.py | 2 +- 1 files changed, 1 insertions(+), 1 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 @@ -766,7 +766,7 @@ def test_load_cert_chain(self): ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) # Combined key and cert in a single file - ctx.load_cert_chain(CERTFILE) + ctx.load_cert_chain(CERTFILE, keyfile=None) ctx.load_cert_chain(CERTFILE, keyfile=CERTFILE) self.assertRaises(TypeError, ctx.load_cert_chain, keyfile=CERTFILE) with self.assertRaises(IOError) as cm: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 4 03:12:17 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 04 Nov 2014 02:12:17 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_test_that_keyf?= =?utf-8?q?ile_can_be_None?= Message-ID: <20141104021216.108085.58940@psf.io> https://hg.python.org/cpython/rev/b9d9e7762783 changeset: 93376:b9d9e7762783 branch: 3.4 parent: 93373:a716afa8e23f user: Benjamin Peterson date: Mon Nov 03 21:05:01 2014 -0500 summary: test that keyfile can be None files: Lib/test/test_ssl.py | 2 +- 1 files changed, 1 insertions(+), 1 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 @@ -727,7 +727,7 @@ def test_load_cert_chain(self): ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) # Combined key and cert in a single file - ctx.load_cert_chain(CERTFILE) + ctx.load_cert_chain(CERTFILE, keyfile=None) ctx.load_cert_chain(CERTFILE, keyfile=CERTFILE) self.assertRaises(TypeError, ctx.load_cert_chain, keyfile=CERTFILE) with self.assertRaises(OSError) as cm: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 4 03:12:17 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 04 Nov 2014 02:12:17 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20141104021216.85190.90487@psf.io> https://hg.python.org/cpython/rev/205810ca5069 changeset: 93377:205810ca5069 parent: 93375:aeb1f941663f parent: 93376:b9d9e7762783 user: Benjamin Peterson date: Mon Nov 03 21:06:07 2014 -0500 summary: merge 3.4 files: Lib/test/test_ssl.py | 2 +- 1 files changed, 1 insertions(+), 1 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 @@ -811,7 +811,7 @@ def test_load_cert_chain(self): ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) # Combined key and cert in a single file - ctx.load_cert_chain(CERTFILE) + ctx.load_cert_chain(CERTFILE, keyfile=None) ctx.load_cert_chain(CERTFILE, keyfile=CERTFILE) self.assertRaises(TypeError, ctx.load_cert_chain, keyfile=CERTFILE) with self.assertRaises(OSError) as cm: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 4 03:12:17 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 04 Nov 2014 02:12:17 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_allow_keyfile_?= =?utf-8?q?argument_to_be_None_=28closes_=2322787=29?= Message-ID: <20141104021217.108365.12999@psf.io> https://hg.python.org/cpython/rev/e54d0b197c82 changeset: 93379:e54d0b197c82 branch: 2.7 user: Benjamin Peterson date: Mon Nov 03 21:12:05 2014 -0500 summary: allow keyfile argument to be None (closes #22787) files: Misc/NEWS | 3 +++ Modules/_ssl.c | 30 +++++++++++++++++++++++------- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,6 +37,9 @@ Library ------- +- Issue #22787: Allow the keyfile argument of SSLContext.load_cert_chain to be + None. + - Issue #22775: Fixed unpickling of Cookie.SimpleCookie with protocol 2. Patch by Tim Graham. diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2447,8 +2447,8 @@ load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds) { char *kwlist[] = {"certfile", "keyfile", "password", NULL}; - PyObject *password = NULL; - char *certfile_bytes = NULL, *keyfile_bytes = NULL; + PyObject *keyfile = NULL, *keyfile_bytes = NULL, *password = NULL; + char *certfile_bytes = NULL; pem_password_cb *orig_passwd_cb = self->ctx->default_passwd_callback; void *orig_passwd_userdata = self->ctx->default_passwd_callback_userdata; _PySSLPasswordInfo pw_info = { NULL, NULL, NULL, 0, 0 }; @@ -2457,11 +2457,27 @@ errno = 0; ERR_clear_error(); if (!PyArg_ParseTupleAndKeywords(args, kwds, - "et|etO:load_cert_chain", kwlist, + "et|OO:load_cert_chain", kwlist, Py_FileSystemDefaultEncoding, &certfile_bytes, - Py_FileSystemDefaultEncoding, &keyfile_bytes, - &password)) + &keyfile, &password)) return NULL; + + if (keyfile && keyfile != Py_None) { + if (PyString_Check(keyfile)) { + Py_INCREF(keyfile); + keyfile_bytes = keyfile; + } else { + PyObject *u = PyUnicode_FromObject(keyfile); + if (!u) + goto error; + keyfile_bytes = PyUnicode_AsEncodedString( + u, Py_FileSystemDefaultEncoding, NULL); + Py_DECREF(u); + if (!keyfile_bytes) + goto error; + } + } + if (password && password != Py_None) { if (PyCallable_Check(password)) { pw_info.callable = password; @@ -2491,7 +2507,7 @@ } PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state); r = SSL_CTX_use_PrivateKey_file(self->ctx, - keyfile_bytes ? keyfile_bytes : certfile_bytes, + keyfile_bytes ? PyBytes_AS_STRING(keyfile_bytes) : certfile_bytes, SSL_FILETYPE_PEM); PySSL_END_ALLOW_THREADS_S(pw_info.thread_state); if (r != 1) { @@ -2523,8 +2539,8 @@ error: SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb); SSL_CTX_set_default_passwd_cb_userdata(self->ctx, orig_passwd_userdata); + Py_XDECREF(keyfile_bytes); PyMem_Free(pw_info.password); - PyMem_Free(keyfile_bytes); PyMem_Free(certfile_bytes); return NULL; } -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Tue Nov 4 09:37:53 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 04 Nov 2014 09:37:53 +0100 Subject: [Python-checkins] Daily reference leaks (205810ca5069): sum=3 Message-ID: results for 205810ca5069 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog0pEFkg', '-x'] From python-checkins at python.org Tue Nov 4 14:53:32 2014 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 04 Nov 2014 13:53:32 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322773=3A_fix_failing_test_with_old_readline_ver?= =?utf-8?q?sions_due_to_issue_=2319884=2E?= Message-ID: <20141104135308.703.68639@psf.io> https://hg.python.org/cpython/rev/be374b8c40c8 changeset: 93381:be374b8c40c8 parent: 93377:205810ca5069 parent: 93380:c4b5a5d44254 user: Antoine Pitrou date: Tue Nov 04 14:53:01 2014 +0100 summary: Issue #22773: fix failing test with old readline versions due to issue #19884. files: Lib/test/test_readline.py | 4 ++++ Modules/readline.c | 4 ++++ 2 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py --- a/Lib/test/test_readline.py +++ b/Lib/test/test_readline.py @@ -44,6 +44,10 @@ class TestReadline(unittest.TestCase): + + @unittest.skipIf(readline._READLINE_VERSION < 0x0600 + and "libedit" not in readline.__doc__, + "not supported in this library version") def test_init(self): # Issue #19884: Ensure that the ANSI sequence "\033[1034h" is not # written into stdout when the readline module is imported and stdout diff --git a/Modules/readline.c b/Modules/readline.c --- a/Modules/readline.c +++ b/Modules/readline.c @@ -1285,5 +1285,9 @@ mod_state = (readlinestate *) PyModule_GetState(m); PyOS_ReadlineFunctionPointer = call_readline; setup_readline(mod_state); + + PyModule_AddIntConstant(m, "_READLINE_VERSION", RL_READLINE_VERSION); + PyModule_AddIntConstant(m, "_READLINE_RUNTIME_VERSION", rl_readline_version); + return m; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 4 14:53:32 2014 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 04 Nov 2014 13:53:32 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyNzcz?= =?utf-8?q?=3A_fix_failing_test_with_old_readline_versions_due_to_issue_?= =?utf-8?q?=2319884=2E?= Message-ID: <20141104135308.85190.63752@psf.io> https://hg.python.org/cpython/rev/c4b5a5d44254 changeset: 93380:c4b5a5d44254 branch: 3.4 parent: 93376:b9d9e7762783 user: Antoine Pitrou date: Tue Nov 04 14:52:10 2014 +0100 summary: Issue #22773: fix failing test with old readline versions due to issue #19884. files: Lib/test/test_readline.py | 4 ++++ Modules/readline.c | 4 ++++ 2 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py --- a/Lib/test/test_readline.py +++ b/Lib/test/test_readline.py @@ -44,6 +44,10 @@ class TestReadline(unittest.TestCase): + + @unittest.skipIf(readline._READLINE_VERSION < 0x0600 + and "libedit" not in readline.__doc__, + "not supported in this library version") def test_init(self): # Issue #19884: Ensure that the ANSI sequence "\033[1034h" is not # written into stdout when the readline module is imported and stdout diff --git a/Modules/readline.c b/Modules/readline.c --- a/Modules/readline.c +++ b/Modules/readline.c @@ -1285,5 +1285,9 @@ mod_state = (readlinestate *) PyModule_GetState(m); PyOS_ReadlineFunctionPointer = call_readline; setup_readline(mod_state); + + PyModule_AddIntConstant(m, "_READLINE_VERSION", RL_READLINE_VERSION); + PyModule_AddIntConstant(m, "_READLINE_RUNTIME_VERSION", rl_readline_version); + return m; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 4 14:55:00 2014 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 04 Nov 2014 13:55:00 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIyNzcz?= =?utf-8?q?=3A_fix_failing_test_with_old_readline_versions_due_to_issue_?= =?utf-8?q?=2319884=2E?= Message-ID: <20141104135456.108393.94114@psf.io> https://hg.python.org/cpython/rev/eba6e68e818c changeset: 93382:eba6e68e818c branch: 2.7 parent: 93379:e54d0b197c82 user: Antoine Pitrou date: Tue Nov 04 14:52:10 2014 +0100 summary: Issue #22773: fix failing test with old readline versions due to issue #19884. files: Lib/test/test_readline.py | 4 ++++ Modules/readline.c | 3 +++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py --- a/Lib/test/test_readline.py +++ b/Lib/test/test_readline.py @@ -43,6 +43,10 @@ class TestReadline(unittest.TestCase): + + @unittest.skipIf(readline._READLINE_VERSION < 0x0600 + and "libedit" not in readline.__doc__, + "not supported in this library version") def test_init(self): # Issue #19884: Ensure that the ANSI sequence "\033[1034h" is not # written into stdout when the readline module is imported and stdout diff --git a/Modules/readline.c b/Modules/readline.c --- a/Modules/readline.c +++ b/Modules/readline.c @@ -1184,4 +1184,7 @@ PyOS_ReadlineFunctionPointer = call_readline; setup_readline(); + + PyModule_AddIntConstant(m, "_READLINE_VERSION", RL_READLINE_VERSION); + PyModule_AddIntConstant(m, "_READLINE_RUNTIME_VERSION", rl_readline_version); } -- Repository URL: https://hg.python.org/cpython From benjamin at python.org Tue Nov 4 14:58:29 2014 From: benjamin at python.org (Benjamin Peterson) Date: Tue, 04 Nov 2014 09:58:29 -0400 Subject: [Python-checkins] cpython (2.7): Issue #22773: fix failing test with old readline versions due to issue #19884. In-Reply-To: <20141104135456.108393.94114@psf.io> References: <20141104135456.108393.94114@psf.io> Message-ID: <1415109509.2950700.186901193.57C2BE56@webmail.messagingengine.com> On Tue, Nov 4, 2014, at 09:55, antoine.pitrou wrote: > https://hg.python.org/cpython/rev/eba6e68e818c > changeset: 93382:eba6e68e818c > branch: 2.7 > parent: 93379:e54d0b197c82 > user: Antoine Pitrou > date: Tue Nov 04 14:52:10 2014 +0100 > summary: > Issue #22773: fix failing test with old readline versions due to issue > #19884. > > files: > Lib/test/test_readline.py | 4 ++++ > Modules/readline.c | 3 +++ > 2 files changed, 7 insertions(+), 0 deletions(-) > > > diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py > --- a/Lib/test/test_readline.py > +++ b/Lib/test/test_readline.py > @@ -43,6 +43,10 @@ > > > class TestReadline(unittest.TestCase): > + > + @unittest.skipIf(readline._READLINE_VERSION < 0x0600 Shouldn't this use the runtime version? From python-checkins at python.org Tue Nov 4 15:09:42 2014 From: python-checkins at python.org (robert.collins) Date: Tue, 04 Nov 2014 14:09:42 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Close_=2322457=3A_Honour_l?= =?utf-8?q?oad=5Ftests_in_the_start=5Fdir_of_discovery=2E?= Message-ID: <20141104140917.719.34141@psf.io> https://hg.python.org/cpython/rev/ce0dd5e4b801 changeset: 93383:ce0dd5e4b801 parent: 93381:be374b8c40c8 user: Robert Collins date: Wed Nov 05 03:09:01 2014 +1300 summary: Close #22457: Honour load_tests in the start_dir of discovery. We were not honouring load_tests in a package/__init__.py when that was the start_dir parameter, though we do when it is a child package. The fix required a little care since it introduces the possibility of infinite recursion. files: Doc/library/unittest.rst | 6 +- Lib/unittest/__init__.py | 9 + Lib/unittest/loader.py | 160 ++++++++++----- Lib/unittest/test/test_discovery.py | 45 ++++ Lib/unittest/test/test_loader.py | 2 +- Misc/NEWS | 2 + 6 files changed, 166 insertions(+), 58 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1668,7 +1668,11 @@ If a package (a directory containing a file named :file:`__init__.py`) is found, the package will be checked for a ``load_tests`` function. If this - exists then it will be called with *loader*, *tests*, *pattern*. + exists then it will be called + ``package.load_tests(loader, tests, pattern)``. Test discovery takes care + to ensure that a package is only checked for tests once during an + invocation, even if the load_tests function itself calls + ``loader.discover``. If ``load_tests`` exists then discovery does *not* recurse into the package, ``load_tests`` is responsible for loading all tests in the diff --git a/Lib/unittest/__init__.py b/Lib/unittest/__init__.py --- a/Lib/unittest/__init__.py +++ b/Lib/unittest/__init__.py @@ -67,3 +67,12 @@ # deprecated _TextTestResult = TextTestResult + +# There are no tests here, so don't try to run anything discovered from +# introspecting the symbols (e.g. FunctionTestCase). Instead, all our +# tests come from within unittest.test. +def load_tests(loader, tests, pattern): + import os.path + # top level directory cached on loader instance + this_dir = os.path.dirname(__file__) + return loader.discover(start_dir=this_dir, pattern=pattern) diff --git a/Lib/unittest/loader.py b/Lib/unittest/loader.py --- a/Lib/unittest/loader.py +++ b/Lib/unittest/loader.py @@ -65,6 +65,9 @@ def __init__(self): super(TestLoader, self).__init__() self.errors = [] + # Tracks packages which we have called into via load_tests, to + # avoid infinite re-entrancy. + self._loading_packages = set() def loadTestsFromTestCase(self, testCaseClass): """Return a suite of all tests cases contained in testCaseClass""" @@ -229,9 +232,13 @@ If a test package name (directory with '__init__.py') matches the pattern then the package will be checked for a 'load_tests' function. If - this exists then it will be called with loader, tests, pattern. + this exists then it will be called with (loader, tests, pattern) unless + the package has already had load_tests called from the same discovery + invocation, in which case the package module object is not scanned for + tests - this ensures that when a package uses discover to further + discover child tests that infinite recursion does not happen. - If load_tests exists then discovery does *not* recurse into the package, + If load_tests exists then discovery does *not* recurse into the package, load_tests is responsible for loading all tests in the package. The pattern is deliberately not stored as a loader attribute so that @@ -355,69 +362,110 @@ def _find_tests(self, start_dir, pattern, namespace=False): """Used by discovery. Yields test suites it loads.""" + # Handle the __init__ in this package + name = self._get_name_from_path(start_dir) + # name is '.' when start_dir == top_level_dir (and top_level_dir is by + # definition not a package). + if name != '.' and name not in self._loading_packages: + # name is in self._loading_packages while we have called into + # loadTestsFromModule with name. + tests, should_recurse = self._find_test_path( + start_dir, pattern, namespace) + if tests is not None: + yield tests + if not should_recurse: + # Either an error occured, or load_tests was used by the + # package. + return + # Handle the contents. paths = sorted(os.listdir(start_dir)) - for path in paths: full_path = os.path.join(start_dir, path) - if os.path.isfile(full_path): - if not VALID_MODULE_NAME.match(path): - # valid Python identifiers only - continue - if not self._match_path(path, full_path, pattern): - continue - # if the test file matches, load it + tests, should_recurse = self._find_test_path( + full_path, pattern, namespace) + if tests is not None: + yield tests + if should_recurse: + # we found a package that didn't use load_tests. name = self._get_name_from_path(full_path) + self._loading_packages.add(name) try: - module = self._get_module_from_name(name) - except case.SkipTest as e: - yield _make_skipped_test(name, e, self.suiteClass) - except: - error_case, error_message = \ - _make_failed_import_test(name, self.suiteClass) - self.errors.append(error_message) - yield error_case - else: - mod_file = os.path.abspath(getattr(module, '__file__', full_path)) - realpath = _jython_aware_splitext(os.path.realpath(mod_file)) - fullpath_noext = _jython_aware_splitext(os.path.realpath(full_path)) - if realpath.lower() != fullpath_noext.lower(): - module_dir = os.path.dirname(realpath) - mod_name = _jython_aware_splitext(os.path.basename(full_path)) - expected_dir = os.path.dirname(full_path) - msg = ("%r module incorrectly imported from %r. Expected %r. " - "Is this module globally installed?") - raise ImportError(msg % (mod_name, module_dir, expected_dir)) - yield self.loadTestsFromModule(module, pattern=pattern) - elif os.path.isdir(full_path): - if (not namespace and - not os.path.isfile(os.path.join(full_path, '__init__.py'))): - continue + yield from self._find_tests(full_path, pattern, namespace) + finally: + self._loading_packages.discard(name) - load_tests = None - tests = None - name = self._get_name_from_path(full_path) + def _find_test_path(self, full_path, pattern, namespace=False): + """Used by discovery. + + Loads tests from a single file, or a directories' __init__.py when + passed the directory. + + Returns a tuple (None_or_tests_from_file, should_recurse). + """ + basename = os.path.basename(full_path) + if os.path.isfile(full_path): + if not VALID_MODULE_NAME.match(basename): + # valid Python identifiers only + return None, False + if not self._match_path(basename, full_path, pattern): + return None, False + # if the test file matches, load it + name = self._get_name_from_path(full_path) + try: + module = self._get_module_from_name(name) + except case.SkipTest as e: + return _make_skipped_test(name, e, self.suiteClass), False + except: + error_case, error_message = \ + _make_failed_import_test(name, self.suiteClass) + self.errors.append(error_message) + return error_case, False + else: + mod_file = os.path.abspath( + getattr(module, '__file__', full_path)) + realpath = _jython_aware_splitext( + os.path.realpath(mod_file)) + fullpath_noext = _jython_aware_splitext( + os.path.realpath(full_path)) + if realpath.lower() != fullpath_noext.lower(): + module_dir = os.path.dirname(realpath) + mod_name = _jython_aware_splitext( + os.path.basename(full_path)) + expected_dir = os.path.dirname(full_path) + msg = ("%r module incorrectly imported from %r. Expected " + "%r. Is this module globally installed?") + raise ImportError( + msg % (mod_name, module_dir, expected_dir)) + return self.loadTestsFromModule(module, pattern=pattern), False + elif os.path.isdir(full_path): + if (not namespace and + not os.path.isfile(os.path.join(full_path, '__init__.py'))): + return None, False + + load_tests = None + tests = None + name = self._get_name_from_path(full_path) + try: + package = self._get_module_from_name(name) + except case.SkipTest as e: + return _make_skipped_test(name, e, self.suiteClass), False + except: + error_case, error_message = \ + _make_failed_import_test(name, self.suiteClass) + self.errors.append(error_message) + return error_case, False + else: + load_tests = getattr(package, 'load_tests', None) + # Mark this package as being in load_tests (possibly ;)) + self._loading_packages.add(name) try: - package = self._get_module_from_name(name) - except case.SkipTest as e: - yield _make_skipped_test(name, e, self.suiteClass) - except: - error_case, error_message = \ - _make_failed_import_test(name, self.suiteClass) - self.errors.append(error_message) - yield error_case - else: - load_tests = getattr(package, 'load_tests', None) tests = self.loadTestsFromModule(package, pattern=pattern) - if tests is not None: - # tests loaded from package file - yield tests - if load_tests is not None: - # loadTestsFromModule(package) has load_tests for us. - continue - # recurse into the package - yield from self._find_tests(full_path, pattern, - namespace=namespace) + # loadTestsFromModule(package) has loaded tests for us. + return tests, False + return tests, True + finally: + self._loading_packages.discard(name) defaultTestLoader = TestLoader() diff --git a/Lib/unittest/test/test_discovery.py b/Lib/unittest/test/test_discovery.py --- a/Lib/unittest/test/test_discovery.py +++ b/Lib/unittest/test/test_discovery.py @@ -368,6 +368,51 @@ self.assertEqual(_find_tests_args, [(start_dir, 'pattern')]) self.assertIn(top_level_dir, sys.path) + def test_discover_start_dir_is_package_calls_package_load_tests(self): + # This test verifies that the package load_tests in a package is indeed + # invoked when the start_dir is a package (and not the top level). + # http://bugs.python.org/issue22457 + + # Test data: we expect the following: + # an isfile to verify the package, then importing and scanning + # as per _find_tests' normal behaviour. + # We expect to see our load_tests hook called once. + vfs = {abspath('/toplevel'): ['startdir'], + abspath('/toplevel/startdir'): ['__init__.py']} + def list_dir(path): + return list(vfs[path]) + self.addCleanup(setattr, os, 'listdir', os.listdir) + os.listdir = list_dir + self.addCleanup(setattr, os.path, 'isfile', os.path.isfile) + os.path.isfile = lambda path: path.endswith('.py') + self.addCleanup(setattr, os.path, 'isdir', os.path.isdir) + os.path.isdir = lambda path: not path.endswith('.py') + self.addCleanup(sys.path.remove, abspath('/toplevel')) + + class Module(object): + paths = [] + load_tests_args = [] + + def __init__(self, path): + self.path = path + + def load_tests(self, loader, tests, pattern): + return ['load_tests called ' + self.path] + + def __eq__(self, other): + return self.path == other.path + + loader = unittest.TestLoader() + loader._get_module_from_name = lambda name: Module(name) + loader.suiteClass = lambda thing: thing + + suite = loader.discover('/toplevel/startdir', top_level_dir='/toplevel') + + # We should have loaded tests from the package __init__. + # (normally this would be nested TestSuites.) + self.assertEqual(suite, + [['load_tests called startdir']]) + def setup_import_issue_tests(self, fakefile): listdir = os.listdir os.listdir = lambda _: [fakefile] diff --git a/Lib/unittest/test/test_loader.py b/Lib/unittest/test/test_loader.py --- a/Lib/unittest/test/test_loader.py +++ b/Lib/unittest/test/test_loader.py @@ -841,7 +841,7 @@ loader = unittest.TestLoader() suite = loader.loadTestsFromNames( - ['unittest.loader.sdasfasfasdf', 'unittest']) + ['unittest.loader.sdasfasfasdf', 'unittest.test.dummy']) error, test = self.check_deferred_error(loader, list(suite)[0]) expected = "module 'unittest.loader' has no attribute 'sdasfasfasdf'" self.assertIn( diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -212,6 +212,8 @@ - Issue #22217: Implemented reprs of classes in the zipfile module. +- Issue #22457: Honour load_tests in the start_dir of discovery. + - Issue #18216: gettext now raises an error when a .mo file has an unsupported major version number. Patch by Aaron Hill. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 4 15:44:12 2014 From: python-checkins at python.org (robert.collins) Date: Tue, 04 Nov 2014 14:44:12 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_regression_in_issue_22?= =?utf-8?q?457_fix=2E?= Message-ID: <20141104144402.727.47162@psf.io> https://hg.python.org/cpython/rev/2aac2d76035e changeset: 93384:2aac2d76035e user: Robert Collins date: Wed Nov 05 03:43:36 2014 +1300 summary: Fix regression in issue 22457 fix. When used in the real world it can under some situations trigger " assert not _relpath.startswith('..'), "Path must be within the project" AssertionError: Path must be within the project " Because _get_name_from_path was not expecting to be called with the top level directory. files: Lib/unittest/loader.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Lib/unittest/loader.py b/Lib/unittest/loader.py --- a/Lib/unittest/loader.py +++ b/Lib/unittest/loader.py @@ -343,6 +343,8 @@ return os.path.dirname(full_path) def _get_name_from_path(self, path): + if path == self._top_level_dir: + return '.' path = _jython_aware_splitext(os.path.normpath(path)) _relpath = os.path.relpath(path, self._top_level_dir) -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Wed Nov 5 09:37:34 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 05 Nov 2014 09:37:34 +0100 Subject: [Python-checkins] Daily reference leaks (2aac2d76035e): sum=58 Message-ID: results for 2aac2d76035e on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 test_multiprocessing_fork leaked [38, 0, 0] references, sum=38 test_multiprocessing_fork leaked [17, 0, 0] memory blocks, sum=17 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogP2dcoq', '-x'] From python-checkins at python.org Wed Nov 5 15:12:13 2014 From: python-checkins at python.org (victor.stinner) Date: Wed, 05 Nov 2014 14:12:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320597=3A_Remove_u?= =?utf-8?q?nused_definition_of_PATH=5FMAX_on_Windows=2C_MAXPATHLEN_is?= Message-ID: <20141105141204.108095.73110@psf.io> https://hg.python.org/cpython/rev/6aaa0aab1e93 changeset: 93386:6aaa0aab1e93 parent: 93384:2aac2d76035e user: Victor Stinner date: Wed Nov 05 15:11:34 2014 +0100 summary: Issue #20597: Remove unused definition of PATH_MAX on Windows, MAXPATHLEN is now preferred. Patch written by Jeffrey Armstrong. files: Modules/main.c | 1 - Python/pythonrun.c | 1 - 2 files changed, 0 insertions(+), 2 deletions(-) diff --git a/Modules/main.c b/Modules/main.c --- a/Modules/main.c +++ b/Modules/main.c @@ -9,7 +9,6 @@ #include #ifdef HAVE_FCNTL_H #include -#define PATH_MAX MAXPATHLEN #endif #endif diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -32,7 +32,6 @@ #ifdef MS_WINDOWS #undef BYTE #include "windows.h" -#define PATH_MAX MAXPATHLEN #endif #ifdef __gnu_hurd__ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 15:12:13 2014 From: python-checkins at python.org (victor.stinner) Date: Wed, 05 Nov 2014 14:12:13 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE5NzUz?= =?utf-8?q?=3A_Fix_test=5Fgdb_on_SystemZ_buildbot=2C_ignore_warnings?= Message-ID: <20141105140725.108073.96591@psf.io> https://hg.python.org/cpython/rev/4c260cf1ba39 changeset: 93385:4c260cf1ba39 branch: 2.7 parent: 93382:eba6e68e818c user: Victor Stinner date: Wed Nov 05 15:07:18 2014 +0100 summary: Issue #19753: Fix test_gdb on SystemZ buildbot, ignore warnings files: Lib/test/test_gdb.py | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -163,6 +163,10 @@ 'linux-gate.so', 'Do you need "set solib-search-path" or ' '"set sysroot"?', + 'warning: Source file is more recent than executable.', + # Issue #19753: missing symbols on System Z + 'Missing separate debuginfo for ', + 'Try: zypper install -C ', ) for line in errlines: if not line.startswith(ignore_patterns): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 15:15:35 2014 From: python-checkins at python.org (victor.stinner) Date: Wed, 05 Nov 2014 14:15:35 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320597=2C_=2321274?= =?utf-8?q?=3A_Remove_unused_definition_of_PATH=5FMAX_on_GNU/Hurd=2C?= Message-ID: <20141105141451.108395.76675@psf.io> https://hg.python.org/cpython/rev/d6fb87972dee changeset: 93387:d6fb87972dee user: Victor Stinner date: Wed Nov 05 15:13:51 2014 +0100 summary: Issue #20597, #21274: Remove unused definition of PATH_MAX on GNU/Hurd, MAXPATHLEN is now preferred. files: Python/pythonrun.c | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -34,10 +34,6 @@ #include "windows.h" #endif -#ifdef __gnu_hurd__ -#define PATH_MAX MAXPATHLEN -#endif - _Py_IDENTIFIER(builtins); _Py_IDENTIFIER(excepthook); _Py_IDENTIFIER(flush); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 15:31:30 2014 From: python-checkins at python.org (victor.stinner) Date: Wed, 05 Nov 2014 14:31:30 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbzogTW92?= =?utf-8?q?e_loop_attribute_to_=5FFlowControlMixin?= Message-ID: <20141105143124.113470.80565@psf.io> https://hg.python.org/cpython/rev/d05ba48cfc29 changeset: 93388:d05ba48cfc29 branch: 3.4 parent: 93380:c4b5a5d44254 user: Victor Stinner date: Wed Nov 05 15:27:41 2014 +0100 summary: asyncio: Move loop attribute to _FlowControlMixin Move the _loop attribute from the constructor of _SelectorTransport, _ProactorBasePipeTransport and _UnixWritePipeTransport classes to the constructor of the _FlowControlMixin class. Add also an assertion to explicit that the parent class must ensure that the loop is defined (not None) files: Lib/asyncio/proactor_events.py | 3 +-- Lib/asyncio/selector_events.py | 3 +-- Lib/asyncio/transports.py | 4 +++- Lib/asyncio/unix_events.py | 3 +-- Lib/test/test_asyncio/test_transports.py | 3 ++- 5 files changed, 8 insertions(+), 8 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 @@ -21,9 +21,8 @@ def __init__(self, loop, sock, protocol, waiter=None, extra=None, server=None): - super().__init__(extra) + super().__init__(extra, loop) self._set_extra(sock) - self._loop = loop self._sock = sock self._protocol = protocol self._server = server 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 @@ -447,7 +447,7 @@ _buffer_factory = bytearray # Constructs initial value for self._buffer. def __init__(self, loop, sock, protocol, extra, server=None): - super().__init__(extra) + super().__init__(extra, loop) self._extra['socket'] = sock self._extra['sockname'] = sock.getsockname() if 'peername' not in self._extra: @@ -455,7 +455,6 @@ self._extra['peername'] = sock.getpeername() except socket.error: self._extra['peername'] = None - self._loop = loop self._sock = sock self._sock_fd = sock.fileno() self._protocol = protocol diff --git a/Lib/asyncio/transports.py b/Lib/asyncio/transports.py --- a/Lib/asyncio/transports.py +++ b/Lib/asyncio/transports.py @@ -238,8 +238,10 @@ resume_writing() may be called. """ - def __init__(self, extra=None): + def __init__(self, extra=None, loop=None): super().__init__(extra) + assert loop is not None + self._loop = loop self._protocol_paused = False self._set_write_buffer_limits() 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 @@ -369,9 +369,8 @@ transports.WriteTransport): def __init__(self, loop, pipe, protocol, waiter=None, extra=None): - super().__init__(extra) + super().__init__(extra, loop) self._extra['pipe'] = pipe - self._loop = loop self._pipe = pipe self._fileno = pipe.fileno() mode = os.fstat(self._fileno).st_mode 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 @@ -69,7 +69,8 @@ def get_write_buffer_size(self): return 512 - transport = MyTransport() + loop = mock.Mock() + transport = MyTransport(loop=loop) transport._protocol = mock.Mock() self.assertFalse(transport._protocol_paused) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 15:31:30 2014 From: python-checkins at python.org (victor.stinner) Date: Wed, 05 Nov 2014 14:31:30 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_=28Merge_3=2E4=29_asyncio=3A_Move_loop_attribute_to_=5FF?= =?utf-8?q?lowControlMixin?= Message-ID: <20141105143125.108099.70234@psf.io> https://hg.python.org/cpython/rev/b9ee2082256d changeset: 93389:b9ee2082256d parent: 93387:d6fb87972dee parent: 93388:d05ba48cfc29 user: Victor Stinner date: Wed Nov 05 15:27:54 2014 +0100 summary: (Merge 3.4) asyncio: Move loop attribute to _FlowControlMixin Move the _loop attribute from the constructor of _SelectorTransport, _ProactorBasePipeTransport and _UnixWritePipeTransport classes to the constructor of the _FlowControlMixin class. Add also an assertion to explicit that the parent class must ensure that the loop is defined (not None) files: Lib/asyncio/proactor_events.py | 3 +-- Lib/asyncio/selector_events.py | 3 +-- Lib/asyncio/transports.py | 4 +++- Lib/asyncio/unix_events.py | 3 +-- Lib/test/test_asyncio/test_transports.py | 3 ++- 5 files changed, 8 insertions(+), 8 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 @@ -21,9 +21,8 @@ def __init__(self, loop, sock, protocol, waiter=None, extra=None, server=None): - super().__init__(extra) + super().__init__(extra, loop) self._set_extra(sock) - self._loop = loop self._sock = sock self._protocol = protocol self._server = server 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 @@ -447,7 +447,7 @@ _buffer_factory = bytearray # Constructs initial value for self._buffer. def __init__(self, loop, sock, protocol, extra, server=None): - super().__init__(extra) + super().__init__(extra, loop) self._extra['socket'] = sock self._extra['sockname'] = sock.getsockname() if 'peername' not in self._extra: @@ -455,7 +455,6 @@ self._extra['peername'] = sock.getpeername() except socket.error: self._extra['peername'] = None - self._loop = loop self._sock = sock self._sock_fd = sock.fileno() self._protocol = protocol diff --git a/Lib/asyncio/transports.py b/Lib/asyncio/transports.py --- a/Lib/asyncio/transports.py +++ b/Lib/asyncio/transports.py @@ -238,8 +238,10 @@ resume_writing() may be called. """ - def __init__(self, extra=None): + def __init__(self, extra=None, loop=None): super().__init__(extra) + assert loop is not None + self._loop = loop self._protocol_paused = False self._set_write_buffer_limits() 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 @@ -369,9 +369,8 @@ transports.WriteTransport): def __init__(self, loop, pipe, protocol, waiter=None, extra=None): - super().__init__(extra) + super().__init__(extra, loop) self._extra['pipe'] = pipe - self._loop = loop self._pipe = pipe self._fileno = pipe.fileno() mode = os.fstat(self._fileno).st_mode 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 @@ -69,7 +69,8 @@ def get_write_buffer_size(self): return 512 - transport = MyTransport() + loop = mock.Mock() + transport = MyTransport(loop=loop) transport._protocol = mock.Mock() self.assertFalse(transport._protocol_paused) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 16:19:40 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 05 Nov 2014 15:19:40 +0000 Subject: [Python-checkins] =?utf-8?q?pythontestdotnet=3A_add_self-signed_c?= =?utf-8?q?ert_and_key?= Message-ID: <20141105151933.108373.56056@psf.io> https://hg.python.org/pythontestdotnet/rev/075864c8191e changeset: 0:075864c8191e user: Benjamin Peterson date: Wed Nov 05 10:19:31 2014 -0500 summary: add self-signed cert and key files: tls/self-signed-cert.pem | 16 ++++++++++++++++ tls/self-signed-key.pem | 16 ++++++++++++++++ 2 files changed, 32 insertions(+), 0 deletions(-) diff --git a/tls/self-signed-cert.pem b/tls/self-signed-cert.pem new file mode 100644 --- /dev/null +++ b/tls/self-signed-cert.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIIChzCCAfCgAwIBAgIJAKGU95wKR8pSMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV +BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u +IFNvZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMMGnNlbGYtc2lnbmVkLnB5dGhv +bnRlc3QubmV0MB4XDTE0MTEwMjE4MDkyOVoXDTI0MTAzMDE4MDkyOVowcDELMAkG +A1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRo +b24gU29mdHdhcmUgRm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0 +aG9udGVzdC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANDXQXW9tjyZ +Xt0Iv2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vm +Sv/yIvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALv +EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjKTAnMCUGA1UdEQQeMByCGnNl +bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MA0GCSqGSIb3DQEBBQUAA4GBAIOXmdtM +eG9qzP9TiXW/Gc/zI4cBfdCpC+Y4gOfC9bQUC7hefix4iO3+iZjgy3X/FaRxUUoV +HKiXcXIaWqTSUWp45cSh0MbwZXudp6JIAptzdAhvvCrPKeC9i9GvxsPD4LtDAL97 +vSaxQBezA7hdxZd90/EeyMgVZgAnTCnvAWX9 +-----END CERTIFICATE----- diff --git a/tls/self-signed-key.pem b/tls/self-signed-key.pem new file mode 100644 --- /dev/null +++ b/tls/self-signed-key.pem @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANDXQXW9tjyZXt0I +v2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vmSv/y +IvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALvEHY5 +7lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAECgYEArO8iwJn5FxM1r7j3saRPtVWa +bZwgz+xFVs1RlG9Qy9w/QB6V93ZnPkCB4iBA/5FStcCzKNab4i9wOaNLfQIoysDZ +jOonRG6pbdFSIBnH4lw1UGi8SS34gFhvWuDW6QHya1enMu2eyOz0W756FUIy9uLx +V1//jNjeT7UcsFowgkkCQQD4ZlMnCWwygGKO3KXlHp0X44UL3HjIObBhaoBECkci +kxsbk8Iwarcq5BBKgwKtTaGvcnzlM9N5xTZ7v30nukANAkEA1zsSmB0P9k5pZsAs +xqRQggVdnjZ55zI6q6KrP69f9LJy8bEQ2Xz1MluAUwKsG26gsThzMPBdn2rWmjYf +9NirfwJAXhWr0zJfd/Vm30O11kW1LNIxl5+HZBdttkg3kw3tiav8bYKW3+3buPQv +M3nR7sBjyGdt5QavSAUpsM+D4SNLlQJAJ4flCWVFGkMantGrJ6zkUI01vapZx3n1 +RrLw6xiF8kaYUAXqh1epHV+q+RQjkkJGZ2Zr2dA8Edyon9hTFEB7dwJBAPRRChg8 +9fcihtNMiRwzGGr7rHtS1TpoA5hbIjPCbY8rHMkLdMnoxBa11E9PmXqyyyctrN+z +o54iWWshXKtbx24= +-----END PRIVATE KEY----- -- Repository URL: https://hg.python.org/pythontestdotnet From python-checkins at python.org Wed Nov 5 17:00:42 2014 From: python-checkins at python.org (victor.stinner) Date: Wed, 05 Nov 2014 16:00:42 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322793=2C_=2322637?= =?utf-8?q?=3A_Add_missing_=22import_os=22_in_uuid=2E=5Fifconfig=5Fgetnode?= =?utf-8?b?KCk=?= Message-ID: <20141105160036.108371.72610@psf.io> https://hg.python.org/cpython/rev/16d6c2443131 changeset: 93390:16d6c2443131 user: Victor Stinner date: Wed Nov 05 16:55:36 2014 +0100 summary: Issue #22793, #22637: Add missing "import os" in uuid._ifconfig_getnode() files: Lib/uuid.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/uuid.py b/Lib/uuid.py --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -346,6 +346,7 @@ def _ifconfig_getnode(): """Get the hardware address on Unix by running ifconfig.""" + import os # This works on Linux ('' or '-a'), Tru64 ('-av'), but not all Unixes. for args in ('', '-a', '-av'): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 17:09:19 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 05 Nov 2014 16:09:19 +0000 Subject: [Python-checkins] =?utf-8?q?pythontestdotnet=3A_add_index_page?= Message-ID: <20141105160822.113480.79170@psf.io> https://hg.python.org/pythontestdotnet/rev/607a33b35ad4 changeset: 1:607a33b35ad4 user: Benjamin Peterson date: Wed Nov 05 11:08:16 2014 -0500 summary: add index page files: www/index.html | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/www/index.html b/www/index.html new file mode 100644 --- /dev/null +++ b/www/index.html @@ -0,0 +1,10 @@ + + + + (C)Python test resources + + + This domain is hosted to host various services contacted by + the Python test suite. + + -- Repository URL: https://hg.python.org/pythontestdotnet From python-checkins at python.org Wed Nov 5 17:12:37 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 05 Nov 2014 16:12:37 +0000 Subject: [Python-checkins] =?utf-8?q?pythontestdotnet=3A_fix_wording?= Message-ID: <20141105161220.113462.77297@psf.io> https://hg.python.org/pythontestdotnet/rev/92f2abd2f88b changeset: 2:92f2abd2f88b user: Benjamin Peterson date: Wed Nov 05 11:12:18 2014 -0500 summary: fix wording files: www/index.html | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/www/index.html b/www/index.html --- a/www/index.html +++ b/www/index.html @@ -4,7 +4,7 @@ (C)Python test resources - This domain is hosted to host various services contacted by + This domain is used to host various services contacted by the Python test suite. -- Repository URL: https://hg.python.org/pythontestdotnet From python-checkins at python.org Wed Nov 5 17:31:12 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 05 Nov 2014 16:31:12 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_use_pythontest?= =?utf-8?q?=2Enet_for_url_fragment_test?= Message-ID: <20141105163108.108071.41985@psf.io> https://hg.python.org/cpython/rev/4fbf1a7c1e40 changeset: 93392:4fbf1a7c1e40 branch: 3.2 parent: 93371:c16e047965a2 user: Benjamin Peterson date: Wed Nov 05 11:27:14 2014 -0500 summary: use pythontest.net for url fragment test files: Lib/test/test_urllib2net.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) 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 @@ -156,12 +156,12 @@ ## self._test_urls(urls, self._extra_handlers()+[bauth, dauth]) def test_urlwithfrag(self): - urlwith_frag = "https://docs.python.org/2/glossary.html#glossary" + urlwith_frag = "http://www.pythontest.net/index.html#frag" with support.transient_internet(urlwith_frag): req = urllib.request.Request(urlwith_frag) res = urllib.request.urlopen(req) self.assertEqual(res.geturl(), - "https://docs.python.org/2/glossary.html#glossary") + "http://www.pythontest.net/index.html#frag") def test_custom_headers(self): url = "http://www.example.com" -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 17:31:12 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 05 Nov 2014 16:31:12 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_remove_require?= =?utf-8?q?s=5Fssl_decorator?= Message-ID: <20141105163109.108099.11204@psf.io> https://hg.python.org/cpython/rev/2bad07298c5c changeset: 93395:2bad07298c5c branch: 3.4 user: Benjamin Peterson date: Wed Nov 05 11:30:21 2014 -0500 summary: remove requires_ssl decorator files: Lib/test/test_urllib2net.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py --- a/Lib/test/test_urllib2net.py +++ b/Lib/test/test_urllib2net.py @@ -159,7 +159,6 @@ ## self._test_urls(urls, self._extra_handlers()+[bauth, dauth]) - @requires_ssl def test_urlwithfrag(self): urlwith_frag = "http://www.pythontest.net/index.html#frag" with support.transient_internet(urlwith_frag): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 17:31:12 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 05 Nov 2014 16:31:12 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20141105163109.108369.18083@psf.io> https://hg.python.org/cpython/rev/826566b1b219 changeset: 93396:826566b1b219 parent: 93390:16d6c2443131 parent: 93395:2bad07298c5c user: Benjamin Peterson date: Wed Nov 05 11:31:02 2014 -0500 summary: merge 3.4 files: Lib/test/test_urllib2net.py | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py --- a/Lib/test/test_urllib2net.py +++ b/Lib/test/test_urllib2net.py @@ -159,14 +159,13 @@ ## self._test_urls(urls, self._extra_handlers()+[bauth, dauth]) - @requires_ssl def test_urlwithfrag(self): - urlwith_frag = "https://docs.python.org/2/glossary.html#glossary" + urlwith_frag = "http://www.pythontest.net/index.html#frag" with support.transient_internet(urlwith_frag): req = urllib.request.Request(urlwith_frag) res = urllib.request.urlopen(req) self.assertEqual(res.geturl(), - "https://docs.python.org/2/glossary.html#glossary") + "http://www.pythontest.net/index.html#frag") @requires_ssl def test_redirect_url_withfrag(self): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 17:31:12 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 05 Nov 2014 16:31:12 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuNCk6?= =?utf-8?q?_merge_3=2E3?= Message-ID: <20141105163109.113482.67959@psf.io> https://hg.python.org/cpython/rev/4045f28ccbec changeset: 93394:4045f28ccbec branch: 3.4 parent: 93388:d05ba48cfc29 parent: 93393:6c46859edfd7 user: Benjamin Peterson date: Wed Nov 05 11:30:00 2014 -0500 summary: merge 3.3 files: Lib/test/test_urllib2net.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) 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 @@ -161,12 +161,12 @@ @requires_ssl def test_urlwithfrag(self): - urlwith_frag = "https://docs.python.org/2/glossary.html#glossary" + urlwith_frag = "http://www.pythontest.net/index.html#frag" with support.transient_internet(urlwith_frag): req = urllib.request.Request(urlwith_frag) res = urllib.request.urlopen(req) self.assertEqual(res.geturl(), - "https://docs.python.org/2/glossary.html#glossary") + "http://www.pythontest.net/index.html#frag") @requires_ssl def test_redirect_url_withfrag(self): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 17:31:12 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 05 Nov 2014 16:31:12 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMyk6?= =?utf-8?q?_merge_3=2E2?= Message-ID: <20141105163108.85216.21957@psf.io> https://hg.python.org/cpython/rev/6c46859edfd7 changeset: 93393:6c46859edfd7 branch: 3.3 parent: 93372:b5d92b52d494 parent: 93392:4fbf1a7c1e40 user: Benjamin Peterson date: Wed Nov 05 11:29:39 2014 -0500 summary: merge 3.2 files: Lib/test/test_urllib2net.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) 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 @@ -155,12 +155,12 @@ ## self._test_urls(urls, self._extra_handlers()+[bauth, dauth]) def test_urlwithfrag(self): - urlwith_frag = "https://docs.python.org/2/glossary.html#glossary" + urlwith_frag = "http://www.pythontest.net/index.html#frag" with support.transient_internet(urlwith_frag): req = urllib.request.Request(urlwith_frag) res = urllib.request.urlopen(req) self.assertEqual(res.geturl(), - "https://docs.python.org/2/glossary.html#glossary") + "http://www.pythontest.net/index.html#frag") def test_custom_headers(self): url = "http://www.example.com" -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 17:31:12 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 05 Nov 2014 16:31:12 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_use_pythontest?= =?utf-8?q?=2Enet_for_url_fragment_test?= Message-ID: <20141105163108.108087.44767@psf.io> https://hg.python.org/cpython/rev/603bd221527c changeset: 93391:603bd221527c branch: 2.7 parent: 93385:4c260cf1ba39 user: Benjamin Peterson date: Wed Nov 05 11:27:14 2014 -0500 summary: use pythontest.net for url fragment test files: Lib/test/test_urllib2net.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) 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 @@ -155,12 +155,12 @@ ## self._test_urls(urls, self._extra_handlers()+[bauth, dauth]) def test_urlwithfrag(self): - urlwith_frag = "https://docs.python.org/2/glossary.html#glossary" + urlwith_frag = "http://www.pythontest.net/index.html#frag" with test_support.transient_internet(urlwith_frag): req = urllib2.Request(urlwith_frag) res = urllib2.urlopen(req) self.assertEqual(res.geturl(), - "https://docs.python.org/2/glossary.html#glossary") + "http://www.pythontest.net/index.html#frag") def test_fileno(self): req = urllib2.Request("http://www.example.com") -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 18:59:57 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 05 Nov 2014 17:59:57 +0000 Subject: [Python-checkins] =?utf-8?q?pythontestdotnet=3A_add_redirect_targ?= =?utf-8?q?et?= Message-ID: <20141105175950.108073.64464@psf.io> https://hg.python.org/pythontestdotnet/rev/5fdf30f78cf1 changeset: 3:5fdf30f78cf1 user: Benjamin Peterson date: Wed Nov 05 12:59:48 2014 -0500 summary: add redirect target files: www/elsewhere/index.html | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/www/elsewhere/index.html b/www/elsewhere/index.html new file mode 100644 --- /dev/null +++ b/www/elsewhere/index.html @@ -0,0 +1,10 @@ + + + +Redirect target + + +This is a redirect target. + + + -- Repository URL: https://hg.python.org/pythontestdotnet From python-checkins at python.org Wed Nov 5 19:10:35 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 05 Nov 2014 18:10:35 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20141105181020.108081.93656@psf.io> https://hg.python.org/cpython/rev/98ee59f61940 changeset: 93398:98ee59f61940 parent: 93396:826566b1b219 parent: 93397:ffa326335c4d user: Benjamin Peterson date: Wed Nov 05 13:10:16 2014 -0500 summary: merge 3.4 files: Lib/test/test_urllib2net.py | 12 ++---------- 1 files changed, 2 insertions(+), 10 deletions(-) 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 @@ -8,13 +8,6 @@ import urllib.request import sys -try: - import ssl -except ImportError: - ssl = None - -requires_ssl = unittest.skipIf(ssl is None, "SSL not supported") - support.requires("network") TIMEOUT = 60 # seconds @@ -167,14 +160,13 @@ self.assertEqual(res.geturl(), "http://www.pythontest.net/index.html#frag") - @requires_ssl def test_redirect_url_withfrag(self): - redirect_url_with_frag = "http://bit.ly/1iSHToT" + redirect_url_with_frag = "http://www.pythontest.net/redir/with_frag/" with support.transient_internet(redirect_url_with_frag): req = urllib.request.Request(redirect_url_with_frag) res = urllib.request.urlopen(req) self.assertEqual(res.geturl(), - "https://docs.python.org/3.4/glossary.html#term-global-interpreter-lock") + "http://www.pythontest.net/elsewhere/#frag") def test_custom_headers(self): url = "http://www.example.com" -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 19:10:36 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 05 Nov 2014 18:10:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_use_pythontest?= =?utf-8?q?=2Enet_for_fragment_redirection_test?= Message-ID: <20141105181019.703.92636@psf.io> https://hg.python.org/cpython/rev/ffa326335c4d changeset: 93397:ffa326335c4d branch: 3.4 parent: 93395:2bad07298c5c user: Benjamin Peterson date: Wed Nov 05 13:10:08 2014 -0500 summary: use pythontest.net for fragment redirection test files: Lib/test/test_urllib2net.py | 12 ++---------- 1 files changed, 2 insertions(+), 10 deletions(-) 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 @@ -8,13 +8,6 @@ import urllib.request import sys -try: - import ssl -except ImportError: - ssl = None - -requires_ssl = unittest.skipIf(ssl is None, "SSL not supported") - support.requires("network") TIMEOUT = 60 # seconds @@ -167,14 +160,13 @@ self.assertEqual(res.geturl(), "http://www.pythontest.net/index.html#frag") - @requires_ssl def test_redirect_url_withfrag(self): - redirect_url_with_frag = "http://bit.ly/1iSHToT" + redirect_url_with_frag = "http://www.pythontest.net/redir/with_frag/" with support.transient_internet(redirect_url_with_frag): req = urllib.request.Request(redirect_url_with_frag) res = urllib.request.urlopen(req) self.assertEqual(res.geturl(), - "https://docs.python.org/3.4/glossary.html#term-global-interpreter-lock") + "http://www.pythontest.net/elsewhere/#frag") def test_custom_headers(self): url = "http://www.example.com" -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 20:22:45 2014 From: python-checkins at python.org (georg.brandl) Date: Wed, 05 Nov 2014 19:22:45 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogQ2xvc2VzICMyMjUy?= =?utf-8?q?5=3A_clarify_documentation_for_ast=2Eliteral=5Feval=28=29=2E?= Message-ID: <20141105192105.719.63871@psf.io> https://hg.python.org/cpython/rev/5c5909740026 changeset: 93399:5c5909740026 branch: 3.4 parent: 93397:ffa326335c4d user: Georg Brandl date: Wed Nov 05 20:20:28 2014 +0100 summary: Closes #22525: clarify documentation for ast.literal_eval(). files: Doc/library/ast.rst | 14 ++++++++------ 1 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -115,13 +115,15 @@ .. function:: literal_eval(node_or_string) - Safely evaluate an expression node or a string containing a Python - expression. The string or node provided may only consist of the following - Python literal structures: strings, bytes, numbers, tuples, lists, dicts, - sets, booleans, and ``None``. + Safely evaluate an expression node or a string containing a Python literal or + container display. The string or node provided may only consist of the + following Python literal structures: strings, bytes, numbers, tuples, lists, + dicts, sets, booleans, and ``None``. - This can be used for safely evaluating strings containing Python expressions - from untrusted sources without the need to parse the values oneself. + This can be used for safely evaluating strings containing Python values from + untrusted sources without the need to parse the values oneself. It is not + capable of evaluating arbitrarily complex expressions, for example involving + operators or indexing. .. versionchanged:: 3.2 Now allows bytes and set literals. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 20:22:45 2014 From: python-checkins at python.org (georg.brandl) Date: Wed, 05 Nov 2014 19:22:45 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_merge_with_3=2E4?= Message-ID: <20141105192105.85200.29777@psf.io> https://hg.python.org/cpython/rev/ce07253e384f changeset: 93400:ce07253e384f parent: 93398:98ee59f61940 parent: 93399:5c5909740026 user: Georg Brandl date: Wed Nov 05 20:20:45 2014 +0100 summary: merge with 3.4 files: Doc/library/ast.rst | 14 ++++++++------ 1 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -115,13 +115,15 @@ .. function:: literal_eval(node_or_string) - Safely evaluate an expression node or a string containing a Python - expression. The string or node provided may only consist of the following - Python literal structures: strings, bytes, numbers, tuples, lists, dicts, - sets, booleans, and ``None``. + Safely evaluate an expression node or a string containing a Python literal or + container display. The string or node provided may only consist of the + following Python literal structures: strings, bytes, numbers, tuples, lists, + dicts, sets, booleans, and ``None``. - This can be used for safely evaluating strings containing Python expressions - from untrusted sources without the need to parse the values oneself. + This can be used for safely evaluating strings containing Python values from + untrusted sources without the need to parse the values oneself. It is not + capable of evaluating arbitrarily complex expressions, for example involving + operators or indexing. .. versionchanged:: 3.2 Now allows bytes and set literals. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 20:24:15 2014 From: python-checkins at python.org (georg.brandl) Date: Wed, 05 Nov 2014 19:24:15 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogQ2xvc2VzICMyMjUy?= =?utf-8?q?5=3A_clarify_documentation_for_ast=2Eliteral=5Feval=28=29=2E?= Message-ID: <20141105192409.108379.34047@psf.io> https://hg.python.org/cpython/rev/3e8d3c4bc17e changeset: 93401:3e8d3c4bc17e branch: 2.7 parent: 93391:603bd221527c user: Georg Brandl date: Wed Nov 05 20:20:28 2014 +0100 summary: Closes #22525: clarify documentation for ast.literal_eval(). files: Doc/library/ast.rst | 12 +++++++----- 1 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -132,12 +132,14 @@ .. function:: literal_eval(node_or_string) Safely evaluate an expression node or a Unicode or *Latin-1* encoded string - containing a Python expression. The string or node provided may only consist - of the following Python literal structures: strings, numbers, tuples, lists, - dicts, booleans, and ``None``. + containing a Python literal or container display. The string or node + provided may only consist of the following Python literal structures: + strings, numbers, tuples, lists, dicts, booleans, and ``None``. - This can be used for safely evaluating strings containing Python expressions - from untrusted sources without the need to parse the values oneself. + This can be used for safely evaluating strings containing Python values from + untrusted sources without the need to parse the values oneself. It is not + capable of evaluating arbitrarily complex expressions, for example involving + operators or indexing. .. function:: get_docstring(node, clean=True) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 20:49:36 2014 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 05 Nov 2014 19:49:36 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogQ2xvc2VzICMyMjc4?= =?utf-8?q?4=3A_fix_test=5Fasyncio_when_the_ssl_module_isn=27t_available?= Message-ID: <20141105194914.113480.30880@psf.io> https://hg.python.org/cpython/rev/7e9e2b17ac6f changeset: 93402:7e9e2b17ac6f branch: 3.4 parent: 93399:5c5909740026 user: Antoine Pitrou date: Wed Nov 05 20:48:16 2014 +0100 summary: Closes #22784: fix test_asyncio when the ssl module isn't available files: Lib/test/test_asyncio/test_events.py | 17 ++++++++------- 1 files changed, 9 insertions(+), 8 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 @@ -606,14 +606,15 @@ self.assertGreater(pr.nbytes, 0) tr.close() - def _dummy_ssl_create_context(self, purpose=ssl.Purpose.SERVER_AUTH, *, - cafile=None, capath=None, cadata=None): - """ - A ssl.create_default_context() replacement that doesn't enable - cert validation. - """ - self.assertEqual(purpose, ssl.Purpose.SERVER_AUTH) - return test_utils.dummy_ssl_context() + if ssl: + def _dummy_ssl_create_context(self, purpose=ssl.Purpose.SERVER_AUTH, *, + cafile=None, capath=None, cadata=None): + """ + A ssl.create_default_context() replacement that doesn't enable + cert validation. + """ + self.assertEqual(purpose, ssl.Purpose.SERVER_AUTH) + return test_utils.dummy_ssl_context() def _test_create_ssl_connection(self, httpd, create_connection, check_sockname=True): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 20:49:36 2014 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 05 Nov 2014 19:49:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Closes_=2322784=3A_fix_test=5Fasyncio_when_the_ssl_modul?= =?utf-8?q?e_isn=27t_available?= Message-ID: <20141105194914.108393.60951@psf.io> https://hg.python.org/cpython/rev/028c729714af changeset: 93403:028c729714af parent: 93400:ce07253e384f parent: 93402:7e9e2b17ac6f user: Antoine Pitrou date: Wed Nov 05 20:48:40 2014 +0100 summary: Closes #22784: fix test_asyncio when the ssl module isn't available files: Lib/test/test_asyncio/test_events.py | 17 ++++++++------- 1 files changed, 9 insertions(+), 8 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 @@ -606,14 +606,15 @@ self.assertGreater(pr.nbytes, 0) tr.close() - def _dummy_ssl_create_context(self, purpose=ssl.Purpose.SERVER_AUTH, *, - cafile=None, capath=None, cadata=None): - """ - A ssl.create_default_context() replacement that doesn't enable - cert validation. - """ - self.assertEqual(purpose, ssl.Purpose.SERVER_AUTH) - return test_utils.dummy_ssl_context() + if ssl: + def _dummy_ssl_create_context(self, purpose=ssl.Purpose.SERVER_AUTH, *, + cafile=None, capath=None, cadata=None): + """ + A ssl.create_default_context() replacement that doesn't enable + cert validation. + """ + self.assertEqual(purpose, ssl.Purpose.SERVER_AUTH) + return test_utils.dummy_ssl_context() def _test_create_ssl_connection(self, httpd, create_connection, check_sockname=True): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 22:18:37 2014 From: python-checkins at python.org (georg.brandl) Date: Wed, 05 Nov 2014 21:18:37 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogdGVzdF9odHRwbGli?= =?utf-8?q?=3A_use_self-signed=2Epythontest=2Enet_for_verification_test_wi?= =?utf-8?q?th?= Message-ID: <20141105211833.108387.70219@psf.io> https://hg.python.org/cpython/rev/4985375db40f changeset: 93404:4985375db40f branch: 3.4 parent: 93402:7e9e2b17ac6f user: Georg Brandl date: Wed Nov 05 20:37:40 2014 +0100 summary: test_httplib: use self-signed.pythontest.net for verification test with non-root-CA cert files: Lib/test/selfsigned_pythontestdotnet.pem | 16 +++++++++ Lib/test/test_httplib.py | 20 ++++------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/Lib/test/selfsigned_pythontestdotnet.pem b/Lib/test/selfsigned_pythontestdotnet.pem new file mode 100644 --- /dev/null +++ b/Lib/test/selfsigned_pythontestdotnet.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIIChzCCAfCgAwIBAgIJAKGU95wKR8pSMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV +BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u +IFNvZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMMGnNlbGYtc2lnbmVkLnB5dGhv +bnRlc3QubmV0MB4XDTE0MTEwMjE4MDkyOVoXDTI0MTAzMDE4MDkyOVowcDELMAkG +A1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRo +b24gU29mdHdhcmUgRm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0 +aG9udGVzdC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANDXQXW9tjyZ +Xt0Iv2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vm +Sv/yIvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALv +EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjKTAnMCUGA1UdEQQeMByCGnNl +bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MA0GCSqGSIb3DQEBBQUAA4GBAIOXmdtM +eG9qzP9TiXW/Gc/zI4cBfdCpC+Y4gOfC9bQUC7hefix4iO3+iZjgy3X/FaRxUUoV +HKiXcXIaWqTSUWp45cSh0MbwZXudp6JIAptzdAhvvCrPKeC9i9GvxsPD4LtDAL97 +vSaxQBezA7hdxZd90/EeyMgVZgAnTCnvAWX9 +-----END CERTIFICATE----- diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -15,8 +15,8 @@ CERT_localhost = os.path.join(here, 'keycert.pem') # Self-signed cert file for 'fakehostname' CERT_fakehostname = os.path.join(here, 'keycert2.pem') -# Root cert file (CA) for svn.python.org's cert -CACERT_svn_python_org = os.path.join(here, 'https_svn_python_org_root.pem') +# Self-signed cert file for self-signed.pythontest.net +CERT_selfsigned_pythontestdotnet = os.path.join(here, 'selfsigned_pythontestdotnet.pem') HOST = support.HOST @@ -772,11 +772,6 @@ h = client.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30) self.assertEqual(h.timeout, 30) - def _check_svn_python_org(self, resp): - # Just a simple check that everything went fine - server_string = resp.getheader('server') - self.assertIn('Apache', server_string) - def test_networked(self): # Default settings: requires a valid cert from a trusted CA import ssl @@ -810,17 +805,18 @@ self.assertIn('text/html', content_type) def test_networked_good_cert(self): - # We feed a CA cert that validates the server's cert + # We feed the server's cert as a validating cert import ssl support.requires('network') - with support.transient_internet('svn.python.org'): + with support.transient_internet('self-signed.pythontest.net'): context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) context.verify_mode = ssl.CERT_REQUIRED - context.load_verify_locations(CACERT_svn_python_org) - h = client.HTTPSConnection('svn.python.org', 443, context=context) + context.load_verify_locations(CERT_selfsigned_pythontestdotnet) + h = client.HTTPSConnection('self-signed.pythontest.net', 443, context=context) h.request('GET', '/') resp = h.getresponse() - self._check_svn_python_org(resp) + server_string = resp.getheader('server') + self.assertIn('nginx', server_string) def test_networked_bad_cert(self): # We feed a "CA" cert that is unrelated to the server's cert -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 5 22:18:39 2014 From: python-checkins at python.org (georg.brandl) Date: Wed, 05 Nov 2014 21:18:39 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_merge_with_3=2E4?= Message-ID: <20141105211834.113474.4902@psf.io> https://hg.python.org/cpython/rev/089573725c77 changeset: 93405:089573725c77 parent: 93403:028c729714af parent: 93404:4985375db40f user: Georg Brandl date: Wed Nov 05 22:17:29 2014 +0100 summary: merge with 3.4 files: Lib/test/selfsigned_pythontestdotnet.pem | 16 +++++++++ Lib/test/test_httplib.py | 20 ++++------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/Lib/test/selfsigned_pythontestdotnet.pem b/Lib/test/selfsigned_pythontestdotnet.pem new file mode 100644 --- /dev/null +++ b/Lib/test/selfsigned_pythontestdotnet.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIIChzCCAfCgAwIBAgIJAKGU95wKR8pSMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV +BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u +IFNvZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMMGnNlbGYtc2lnbmVkLnB5dGhv +bnRlc3QubmV0MB4XDTE0MTEwMjE4MDkyOVoXDTI0MTAzMDE4MDkyOVowcDELMAkG +A1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRo +b24gU29mdHdhcmUgRm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0 +aG9udGVzdC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANDXQXW9tjyZ +Xt0Iv2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vm +Sv/yIvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALv +EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjKTAnMCUGA1UdEQQeMByCGnNl +bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MA0GCSqGSIb3DQEBBQUAA4GBAIOXmdtM +eG9qzP9TiXW/Gc/zI4cBfdCpC+Y4gOfC9bQUC7hefix4iO3+iZjgy3X/FaRxUUoV +HKiXcXIaWqTSUWp45cSh0MbwZXudp6JIAptzdAhvvCrPKeC9i9GvxsPD4LtDAL97 +vSaxQBezA7hdxZd90/EeyMgVZgAnTCnvAWX9 +-----END CERTIFICATE----- diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -15,8 +15,8 @@ CERT_localhost = os.path.join(here, 'keycert.pem') # Self-signed cert file for 'fakehostname' CERT_fakehostname = os.path.join(here, 'keycert2.pem') -# Root cert file (CA) for svn.python.org's cert -CACERT_svn_python_org = os.path.join(here, 'https_svn_python_org_root.pem') +# Self-signed cert file for self-signed.pythontest.net +CERT_selfsigned_pythontestdotnet = os.path.join(here, 'selfsigned_pythontestdotnet.pem') # constants for testing chunked encoding chunked_start = ( @@ -1006,11 +1006,6 @@ h = client.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30) self.assertEqual(h.timeout, 30) - def _check_svn_python_org(self, resp): - # Just a simple check that everything went fine - server_string = resp.getheader('server') - self.assertIn('Apache', server_string) - def test_networked(self): # Default settings: requires a valid cert from a trusted CA import ssl @@ -1044,17 +1039,18 @@ self.assertIn('text/html', content_type) def test_networked_good_cert(self): - # We feed a CA cert that validates the server's cert + # We feed the server's cert as a validating cert import ssl support.requires('network') - with support.transient_internet('svn.python.org'): + with support.transient_internet('self-signed.pythontest.net'): context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) context.verify_mode = ssl.CERT_REQUIRED - context.load_verify_locations(CACERT_svn_python_org) - h = client.HTTPSConnection('svn.python.org', 443, context=context) + context.load_verify_locations(CERT_selfsigned_pythontestdotnet) + h = client.HTTPSConnection('self-signed.pythontest.net', 443, context=context) h.request('GET', '/') resp = h.getresponse() - self._check_svn_python_org(resp) + server_string = resp.getheader('server') + self.assertIn('nginx', server_string) def test_networked_bad_cert(self): # We feed a "CA" cert that is unrelated to the server's cert -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 6 04:31:08 2014 From: python-checkins at python.org (steve.dower) Date: Thu, 06 Nov 2014 03:31:08 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIwMTYw?= =?utf-8?q?=3A_broken_ctypes_calling_convention_on_MSVC_/_64-bit_Windows_?= =?utf-8?q?=28large?= Message-ID: <20141106033103.85196.11331@psf.io> https://hg.python.org/cpython/rev/f75b0470168b changeset: 93406:f75b0470168b branch: 2.7 parent: 93401:3e8d3c4bc17e user: Steve Dower date: Wed Nov 05 19:16:05 2014 -0800 summary: Issue #20160: broken ctypes calling convention on MSVC / 64-bit Windows (large structs). Patch by mattip files: Lib/ctypes/test/test_win32.py | 26 +++++++- Modules/_ctypes/_ctypes_test.c | 43 ++++++++++++++ Modules/_ctypes/callproc.c | 6 +- Modules/_ctypes/libffi_msvc/ffi.c | 29 +++++++- Modules/_ctypes/libffi_msvc/prep_cif.c | 18 ++++- Modules/_ctypes/libffi_msvc/types.c | 2 +- 6 files changed, 106 insertions(+), 18 deletions(-) diff --git a/Lib/ctypes/test/test_win32.py b/Lib/ctypes/test/test_win32.py --- a/Lib/ctypes/test/test_win32.py +++ b/Lib/ctypes/test/test_win32.py @@ -90,9 +90,29 @@ dll = CDLL(_ctypes_test.__file__) - pt = POINT(10, 10) - rect = RECT(0, 0, 20, 20) - self.assertEqual(1, dll.PointInRect(byref(rect), pt)) + pt = POINT(15, 25) + left = c_long.in_dll(dll, 'left') + top = c_long.in_dll(dll, 'top') + right = c_long.in_dll(dll, 'right') + bottom = c_long.in_dll(dll, 'bottom') + rect = RECT(left, top, right, bottom) + PointInRect = dll.PointInRect + PointInRect.argtypes = [POINTER(RECT), POINT] + self.assertEqual(1, PointInRect(byref(rect), pt)) + + ReturnRect = dll.ReturnRect + ReturnRect.argtypes = [c_int, RECT, POINTER(RECT), POINT, RECT, + POINTER(RECT), POINT, RECT] + ReturnRect.restype = RECT + for i in range(4): + ret = ReturnRect(i, rect, pointer(rect), pt, rect, + byref(rect), pt, rect) + # the c function will check and modify ret if something is + # passed in improperly + self.assertEqual(ret.left, left.value) + self.assertEqual(ret.right, right.value) + self.assertEqual(ret.top, top.value) + self.assertEqual(ret.bottom, bottom.value) if __name__ == '__main__': unittest.main() diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -540,6 +540,49 @@ return 1; } +EXPORT(int left = 10); +EXPORT(int top = 20); +EXPORT(int right = 30); +EXPORT(int bottom = 40); + +EXPORT(RECT) ReturnRect(int i, RECT ar, RECT* br, POINT cp, RECT dr, + RECT *er, POINT fp, RECT gr) +{ + /*Check input */ + if (ar.left + br->left + dr.left + er->left + gr.left != left * 5) + { + ar.left = 100; + return ar; + } + if (ar.right + br->right + dr.right + er->right + gr.right != right * 5) + { + ar.right = 100; + return ar; + } + if (cp.x != fp.x) + { + ar.left = -100; + } + if (cp.y != fp.y) + { + ar.left = -200; + } + switch(i) + { + case 0: + return ar; + break; + case 1: + return dr; + break; + case 2: + return gr; + break; + + } + return ar; +} + typedef struct { short x; short y; diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -1170,11 +1170,7 @@ } for (i = 0; i < argcount; ++i) { atypes[i] = args[i].ffi_type; - if (atypes[i]->type == FFI_TYPE_STRUCT -#ifdef _WIN64 - && atypes[i]->size <= sizeof(void *) -#endif - ) + if (atypes[i]->type == FFI_TYPE_STRUCT) avalues[i] = (void *)args[i].value.p; else avalues[i] = (void *)&args[i].value; diff --git a/Modules/_ctypes/libffi_msvc/ffi.c b/Modules/_ctypes/libffi_msvc/ffi.c --- a/Modules/_ctypes/libffi_msvc/ffi.c +++ b/Modules/_ctypes/libffi_msvc/ffi.c @@ -102,6 +102,15 @@ FFI_ASSERT(0); } } +#ifdef _WIN64 + else if (z > 8) + { + /* On Win64, if a single argument takes more than 8 bytes, + then it is always passed by reference. */ + *(void **)argp = *p_argv; + z = 8; + } +#endif else { memcpy(argp, *p_argv, z); @@ -124,7 +133,6 @@ switch (cif->rtype->type) { case FFI_TYPE_VOID: - case FFI_TYPE_STRUCT: case FFI_TYPE_SINT64: case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: @@ -132,6 +140,18 @@ cif->flags = (unsigned) cif->rtype->type; break; + case FFI_TYPE_STRUCT: + /* MSVC returns small structures in registers. Put in cif->flags + the value FFI_TYPE_STRUCT only if the structure is big enough; + otherwise, put the 4- or 8-bytes integer type. */ + if (cif->rtype->size <= 4) + cif->flags = FFI_TYPE_INT; + else if (cif->rtype->size <= 8) + cif->flags = FFI_TYPE_SINT64; + else + cif->flags = FFI_TYPE_STRUCT; + break; + case FFI_TYPE_UINT64: #ifdef _WIN64 case FFI_TYPE_POINTER: @@ -201,8 +221,7 @@ #else case FFI_SYSV: /*@-usedef@*/ - /* Function call needs at least 40 bytes stack size, on win64 AMD64 */ - return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes ? cif->bytes : 40, + return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; @@ -227,7 +246,7 @@ #else static void __fastcall #endif -ffi_closure_SYSV (ffi_closure *closure, int *argp) +ffi_closure_SYSV (ffi_closure *closure, char *argp) { // this is our return value storage long double res; @@ -237,7 +256,7 @@ void **arg_area; unsigned short rtype; void *resp = (void*)&res; - void *args = &argp[1]; + void *args = argp + sizeof(void*); cif = closure->cif; arg_area = (void**) alloca (cif->nargs * sizeof (void*)); diff --git a/Modules/_ctypes/libffi_msvc/prep_cif.c b/Modules/_ctypes/libffi_msvc/prep_cif.c --- a/Modules/_ctypes/libffi_msvc/prep_cif.c +++ b/Modules/_ctypes/libffi_msvc/prep_cif.c @@ -116,9 +116,9 @@ #if !defined M68K && !defined __x86_64__ && !defined S390 /* Make space for the return structure pointer */ if (cif->rtype->type == FFI_TYPE_STRUCT - /* MSVC returns small structures in registers. But we have a different - workaround: pretend int32 or int64 return type, and converting to - structure afterwards. */ +#ifdef _WIN32 + && (cif->rtype->size > 8) /* MSVC returns small structs in registers */ +#endif #ifdef SPARC && (cif->abi != FFI_V9 || cif->rtype->size > 32) #endif @@ -143,7 +143,11 @@ && ((*ptr)->size > 16 || cif->abi != FFI_V9)) || ((*ptr)->type == FFI_TYPE_LONGDOUBLE && cif->abi != FFI_V9)) - bytes += sizeof(void*); + bytes += sizeof(void*); + else +#elif defined (_WIN64) + if ((*ptr)->type == FFI_TYPE_STRUCT && ((*ptr)->size > 8)) + bytes += sizeof(void*); else #endif { @@ -168,6 +172,12 @@ #endif } +#ifdef _WIN64 + /* Function call needs at least 40 bytes stack size, on win64 AMD64 */ + if (bytes < 40) + bytes = 40; +#endif + cif->bytes = bytes; /* Perform machine dependent cif processing */ diff --git a/Modules/_ctypes/libffi_msvc/types.c b/Modules/_ctypes/libffi_msvc/types.c --- a/Modules/_ctypes/libffi_msvc/types.c +++ b/Modules/_ctypes/libffi_msvc/types.c @@ -43,7 +43,7 @@ FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT); #if defined ALPHA || defined SPARC64 || defined X86_64 || defined S390X \ - || defined IA64 + || defined IA64 || defined _WIN64 FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 6 04:31:26 2014 From: python-checkins at python.org (steve.dower) Date: Thu, 06 Nov 2014 03:31:26 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIwMTYw?= =?utf-8?q?=3A_broken_ctypes_calling_convention_on_MSVC_/_64-bit_Windows_?= =?utf-8?q?=28large?= Message-ID: <20141106033126.108373.87640@psf.io> https://hg.python.org/cpython/rev/cd36ba22602d changeset: 93407:cd36ba22602d branch: 3.4 parent: 93404:4985375db40f user: Steve Dower date: Tue Nov 04 21:21:22 2014 -0800 summary: Issue #20160: broken ctypes calling convention on MSVC / 64-bit Windows (large structs) Patch by mattip files: Lib/ctypes/test/test_win32.py | 26 +++++++- Modules/_ctypes/_ctypes_test.c | 43 ++++++++++++++ Modules/_ctypes/callproc.c | 3 - Modules/_ctypes/libffi_msvc/ffi.c | 29 +++++++- Modules/_ctypes/libffi_msvc/prep_cif.c | 16 ++++- Modules/_ctypes/libffi_msvc/types.c | 2 +- 6 files changed, 104 insertions(+), 15 deletions(-) diff --git a/Lib/ctypes/test/test_win32.py b/Lib/ctypes/test/test_win32.py --- a/Lib/ctypes/test/test_win32.py +++ b/Lib/ctypes/test/test_win32.py @@ -111,9 +111,29 @@ dll = CDLL(_ctypes_test.__file__) - pt = POINT(10, 10) - rect = RECT(0, 0, 20, 20) - self.assertEqual(1, dll.PointInRect(byref(rect), pt)) + pt = POINT(15, 25) + left = c_long.in_dll(dll, 'left') + top = c_long.in_dll(dll, 'top') + right = c_long.in_dll(dll, 'right') + bottom = c_long.in_dll(dll, 'bottom') + rect = RECT(left, top, right, bottom) + PointInRect = dll.PointInRect + PointInRect.argtypes = [POINTER(RECT), POINT] + self.assertEqual(1, PointInRect(byref(rect), pt)) + + ReturnRect = dll.ReturnRect + ReturnRect.argtypes = [c_int, RECT, POINTER(RECT), POINT, RECT, + POINTER(RECT), POINT, RECT] + ReturnRect.restype = RECT + for i in range(4): + ret = ReturnRect(i, rect, pointer(rect), pt, rect, + byref(rect), pt, rect) + # the c function will check and modify ret if something is + # passed in improperly + self.assertEqual(ret.left, left.value) + self.assertEqual(ret.right, right.value) + self.assertEqual(ret.top, top.value) + self.assertEqual(ret.bottom, bottom.value) if __name__ == '__main__': unittest.main() diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -527,6 +527,49 @@ return 1; } +EXPORT(int left = 10); +EXPORT(int top = 20); +EXPORT(int right = 30); +EXPORT(int bottom = 40); + +EXPORT(RECT) ReturnRect(int i, RECT ar, RECT* br, POINT cp, RECT dr, + RECT *er, POINT fp, RECT gr) +{ + /*Check input */ + if (ar.left + br->left + dr.left + er->left + gr.left != left * 5) + { + ar.left = 100; + return ar; + } + if (ar.right + br->right + dr.right + er->right + gr.right != right * 5) + { + ar.right = 100; + return ar; + } + if (cp.x != fp.x) + { + ar.left = -100; + } + if (cp.y != fp.y) + { + ar.left = -200; + } + switch(i) + { + case 0: + return ar; + break; + case 1: + return dr; + break; + case 2: + return gr; + break; + + } + return ar; +} + typedef struct { short x; short y; diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -1140,9 +1140,6 @@ for (i = 0; i < argcount; ++i) { atypes[i] = args[i].ffi_type; if (atypes[i]->type == FFI_TYPE_STRUCT -#ifdef _WIN64 - && atypes[i]->size <= sizeof(void *) -#endif ) avalues[i] = (void *)args[i].value.p; else diff --git a/Modules/_ctypes/libffi_msvc/ffi.c b/Modules/_ctypes/libffi_msvc/ffi.c --- a/Modules/_ctypes/libffi_msvc/ffi.c +++ b/Modules/_ctypes/libffi_msvc/ffi.c @@ -102,6 +102,15 @@ FFI_ASSERT(0); } } +#ifdef _WIN64 + else if (z > 8) + { + /* On Win64, if a single argument takes more than 8 bytes, + then it is always passed by reference. */ + *(void **)argp = *p_argv; + z = 8; + } +#endif else { memcpy(argp, *p_argv, z); @@ -124,7 +133,6 @@ switch (cif->rtype->type) { case FFI_TYPE_VOID: - case FFI_TYPE_STRUCT: case FFI_TYPE_SINT64: case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: @@ -132,6 +140,18 @@ cif->flags = (unsigned) cif->rtype->type; break; + case FFI_TYPE_STRUCT: + /* MSVC returns small structures in registers. Put in cif->flags + the value FFI_TYPE_STRUCT only if the structure is big enough; + otherwise, put the 4- or 8-bytes integer type. */ + if (cif->rtype->size <= 4) + cif->flags = FFI_TYPE_INT; + else if (cif->rtype->size <= 8) + cif->flags = FFI_TYPE_SINT64; + else + cif->flags = FFI_TYPE_STRUCT; + break; + case FFI_TYPE_UINT64: #ifdef _WIN64 case FFI_TYPE_POINTER: @@ -201,8 +221,7 @@ #else case FFI_SYSV: /*@-usedef@*/ - /* Function call needs at least 40 bytes stack size, on win64 AMD64 */ - return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes ? cif->bytes : 40, + return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; @@ -227,7 +246,7 @@ #else static void __fastcall #endif -ffi_closure_SYSV (ffi_closure *closure, int *argp) +ffi_closure_SYSV (ffi_closure *closure, char *argp) { // this is our return value storage long double res; @@ -237,7 +256,7 @@ void **arg_area; unsigned short rtype; void *resp = (void*)&res; - void *args = &argp[1]; + void *args = argp + sizeof(void*); cif = closure->cif; arg_area = (void**) alloca (cif->nargs * sizeof (void*)); diff --git a/Modules/_ctypes/libffi_msvc/prep_cif.c b/Modules/_ctypes/libffi_msvc/prep_cif.c --- a/Modules/_ctypes/libffi_msvc/prep_cif.c +++ b/Modules/_ctypes/libffi_msvc/prep_cif.c @@ -116,9 +116,9 @@ #if !defined M68K && !defined __x86_64__ && !defined S390 /* Make space for the return structure pointer */ if (cif->rtype->type == FFI_TYPE_STRUCT - /* MSVC returns small structures in registers. But we have a different - workaround: pretend int32 or int64 return type, and converting to - structure afterwards. */ +#ifdef _WIN32 + && (cif->rtype->size > 8) /* MSVC returns small structs in registers */ +#endif #ifdef SPARC && (cif->abi != FFI_V9 || cif->rtype->size > 32) #endif @@ -145,6 +145,10 @@ && cif->abi != FFI_V9)) bytes += sizeof(void*); else +#elif defined (_WIN64) + if ((*ptr)->type == FFI_TYPE_STRUCT && ((*ptr)->size > 8)) + bytes += sizeof(void*); + else #endif { #if !defined(_MSC_VER) && !defined(__MINGW32__) @@ -168,6 +172,12 @@ #endif } +#ifdef _WIN64 + /* Function call needs at least 40 bytes stack size, on win64 AMD64 */ + if (bytes < 40) + bytes = 40; +#endif + cif->bytes = bytes; /* Perform machine dependent cif processing */ diff --git a/Modules/_ctypes/libffi_msvc/types.c b/Modules/_ctypes/libffi_msvc/types.c --- a/Modules/_ctypes/libffi_msvc/types.c +++ b/Modules/_ctypes/libffi_msvc/types.c @@ -43,7 +43,7 @@ FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT); #if defined ALPHA || defined SPARC64 || defined X86_64 || defined S390X \ - || defined IA64 + || defined IA64 || defined _WIN64 FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 6 04:31:27 2014 From: python-checkins at python.org (steve.dower) Date: Thu, 06 Nov 2014 03:31:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320160=3A_broken_ctypes_calling_convention_on_MS?= =?utf-8?q?VC_/_64-bit_Windows_=28large?= Message-ID: <20141106033126.113470.87820@psf.io> https://hg.python.org/cpython/rev/b701eb69260d changeset: 93408:b701eb69260d parent: 93405:089573725c77 parent: 93407:cd36ba22602d user: Steve Dower date: Wed Nov 05 19:30:30 2014 -0800 summary: Issue #20160: broken ctypes calling convention on MSVC / 64-bit Windows (large structs) Patch by mattip files: Lib/ctypes/test/test_win32.py | 26 +++++++- Modules/_ctypes/_ctypes_test.c | 43 ++++++++++++++ Modules/_ctypes/callproc.c | 3 - Modules/_ctypes/libffi_msvc/ffi.c | 29 +++++++- Modules/_ctypes/libffi_msvc/prep_cif.c | 16 ++++- Modules/_ctypes/libffi_msvc/types.c | 2 +- 6 files changed, 104 insertions(+), 15 deletions(-) diff --git a/Lib/ctypes/test/test_win32.py b/Lib/ctypes/test/test_win32.py --- a/Lib/ctypes/test/test_win32.py +++ b/Lib/ctypes/test/test_win32.py @@ -111,9 +111,29 @@ dll = CDLL(_ctypes_test.__file__) - pt = POINT(10, 10) - rect = RECT(0, 0, 20, 20) - self.assertEqual(1, dll.PointInRect(byref(rect), pt)) + pt = POINT(15, 25) + left = c_long.in_dll(dll, 'left') + top = c_long.in_dll(dll, 'top') + right = c_long.in_dll(dll, 'right') + bottom = c_long.in_dll(dll, 'bottom') + rect = RECT(left, top, right, bottom) + PointInRect = dll.PointInRect + PointInRect.argtypes = [POINTER(RECT), POINT] + self.assertEqual(1, PointInRect(byref(rect), pt)) + + ReturnRect = dll.ReturnRect + ReturnRect.argtypes = [c_int, RECT, POINTER(RECT), POINT, RECT, + POINTER(RECT), POINT, RECT] + ReturnRect.restype = RECT + for i in range(4): + ret = ReturnRect(i, rect, pointer(rect), pt, rect, + byref(rect), pt, rect) + # the c function will check and modify ret if something is + # passed in improperly + self.assertEqual(ret.left, left.value) + self.assertEqual(ret.right, right.value) + self.assertEqual(ret.top, top.value) + self.assertEqual(ret.bottom, bottom.value) if __name__ == '__main__': unittest.main() diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -527,6 +527,49 @@ return 1; } +EXPORT(int left = 10); +EXPORT(int top = 20); +EXPORT(int right = 30); +EXPORT(int bottom = 40); + +EXPORT(RECT) ReturnRect(int i, RECT ar, RECT* br, POINT cp, RECT dr, + RECT *er, POINT fp, RECT gr) +{ + /*Check input */ + if (ar.left + br->left + dr.left + er->left + gr.left != left * 5) + { + ar.left = 100; + return ar; + } + if (ar.right + br->right + dr.right + er->right + gr.right != right * 5) + { + ar.right = 100; + return ar; + } + if (cp.x != fp.x) + { + ar.left = -100; + } + if (cp.y != fp.y) + { + ar.left = -200; + } + switch(i) + { + case 0: + return ar; + break; + case 1: + return dr; + break; + case 2: + return gr; + break; + + } + return ar; +} + typedef struct { short x; short y; diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -1140,9 +1140,6 @@ for (i = 0; i < argcount; ++i) { atypes[i] = args[i].ffi_type; if (atypes[i]->type == FFI_TYPE_STRUCT -#ifdef _WIN64 - && atypes[i]->size <= sizeof(void *) -#endif ) avalues[i] = (void *)args[i].value.p; else diff --git a/Modules/_ctypes/libffi_msvc/ffi.c b/Modules/_ctypes/libffi_msvc/ffi.c --- a/Modules/_ctypes/libffi_msvc/ffi.c +++ b/Modules/_ctypes/libffi_msvc/ffi.c @@ -102,6 +102,15 @@ FFI_ASSERT(0); } } +#ifdef _WIN64 + else if (z > 8) + { + /* On Win64, if a single argument takes more than 8 bytes, + then it is always passed by reference. */ + *(void **)argp = *p_argv; + z = 8; + } +#endif else { memcpy(argp, *p_argv, z); @@ -124,7 +133,6 @@ switch (cif->rtype->type) { case FFI_TYPE_VOID: - case FFI_TYPE_STRUCT: case FFI_TYPE_SINT64: case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: @@ -132,6 +140,18 @@ cif->flags = (unsigned) cif->rtype->type; break; + case FFI_TYPE_STRUCT: + /* MSVC returns small structures in registers. Put in cif->flags + the value FFI_TYPE_STRUCT only if the structure is big enough; + otherwise, put the 4- or 8-bytes integer type. */ + if (cif->rtype->size <= 4) + cif->flags = FFI_TYPE_INT; + else if (cif->rtype->size <= 8) + cif->flags = FFI_TYPE_SINT64; + else + cif->flags = FFI_TYPE_STRUCT; + break; + case FFI_TYPE_UINT64: #ifdef _WIN64 case FFI_TYPE_POINTER: @@ -201,8 +221,7 @@ #else case FFI_SYSV: /*@-usedef@*/ - /* Function call needs at least 40 bytes stack size, on win64 AMD64 */ - return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes ? cif->bytes : 40, + return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; @@ -227,7 +246,7 @@ #else static void __fastcall #endif -ffi_closure_SYSV (ffi_closure *closure, int *argp) +ffi_closure_SYSV (ffi_closure *closure, char *argp) { // this is our return value storage long double res; @@ -237,7 +256,7 @@ void **arg_area; unsigned short rtype; void *resp = (void*)&res; - void *args = &argp[1]; + void *args = argp + sizeof(void*); cif = closure->cif; arg_area = (void**) alloca (cif->nargs * sizeof (void*)); diff --git a/Modules/_ctypes/libffi_msvc/prep_cif.c b/Modules/_ctypes/libffi_msvc/prep_cif.c --- a/Modules/_ctypes/libffi_msvc/prep_cif.c +++ b/Modules/_ctypes/libffi_msvc/prep_cif.c @@ -116,9 +116,9 @@ #if !defined M68K && !defined __x86_64__ && !defined S390 /* Make space for the return structure pointer */ if (cif->rtype->type == FFI_TYPE_STRUCT - /* MSVC returns small structures in registers. But we have a different - workaround: pretend int32 or int64 return type, and converting to - structure afterwards. */ +#ifdef _WIN32 + && (cif->rtype->size > 8) /* MSVC returns small structs in registers */ +#endif #ifdef SPARC && (cif->abi != FFI_V9 || cif->rtype->size > 32) #endif @@ -145,6 +145,10 @@ && cif->abi != FFI_V9)) bytes += sizeof(void*); else +#elif defined (_WIN64) + if ((*ptr)->type == FFI_TYPE_STRUCT && ((*ptr)->size > 8)) + bytes += sizeof(void*); + else #endif { #if !defined(_MSC_VER) && !defined(__MINGW32__) @@ -168,6 +172,12 @@ #endif } +#ifdef _WIN64 + /* Function call needs at least 40 bytes stack size, on win64 AMD64 */ + if (bytes < 40) + bytes = 40; +#endif + cif->bytes = bytes; /* Perform machine dependent cif processing */ diff --git a/Modules/_ctypes/libffi_msvc/types.c b/Modules/_ctypes/libffi_msvc/types.c --- a/Modules/_ctypes/libffi_msvc/types.c +++ b/Modules/_ctypes/libffi_msvc/types.c @@ -43,7 +43,7 @@ FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT); #if defined ALPHA || defined SPARC64 || defined X86_64 || defined S390X \ - || defined IA64 + || defined IA64 || defined _WIN64 FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 6 05:14:08 2014 From: python-checkins at python.org (steve.dower) Date: Thu, 06 Nov 2014 04:14:08 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fixes_path_to_?= =?utf-8?q?patchlevel=2Epy_in_doc/make=2Ebat?= Message-ID: <20141106041405.715.78789@psf.io> https://hg.python.org/cpython/rev/71d5a69e122b changeset: 93409:71d5a69e122b branch: 2.7 parent: 93406:f75b0470168b user: Steve Dower date: Wed Nov 05 20:13:46 2014 -0800 summary: Fixes path to patchlevel.py in doc/make.bat files: Doc/make.bat | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/make.bat b/Doc/make.bat --- a/Doc/make.bat +++ b/Doc/make.bat @@ -12,7 +12,7 @@ if NOT DEFINED ProgramFiles(x86) set _PRGMFLS=%ProgramFiles% if "%HTMLHELP%" EQU "" set HTMLHELP=%_PRGMFLS%\HTML Help Workshop\hhc.exe -if "%DISTVERSION%" EQU "" for /f "usebackq" %%v in (`%PYTHON% tools/patchlevel.py`) do set DISTVERSION=%%v +if "%DISTVERSION%" EQU "" for /f "usebackq" %%v in (`%PYTHON% tools/extensions/patchlevel.py`) do set DISTVERSION=%%v if "%BUILDDIR%" EQU "" set BUILDDIR=build -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 6 06:28:49 2014 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 06 Nov 2014 05:28:49 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <20141106052827.85220.56425@psf.io> https://hg.python.org/cpython/rev/9ed44777331d changeset: 93411:9ed44777331d parent: 93408:b701eb69260d parent: 93410:501edbbb74ff user: Raymond Hettinger date: Wed Nov 05 21:28:19 2014 -0800 summary: merge files: Doc/library/textwrap.rst | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Doc/library/textwrap.rst b/Doc/library/textwrap.rst --- a/Doc/library/textwrap.rst +++ b/Doc/library/textwrap.rst @@ -113,6 +113,8 @@ + + world + .. versionadded:: 3.3 + :func:`wrap`, :func:`fill` and :func:`shorten` work by creating a :class:`TextWrapper` instance and calling a single method on it. That -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 6 06:28:49 2014 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 06 Nov 2014 05:28:49 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgMjI4MDM6?= =?utf-8?q?__Add_missing_versionadded_directive=2E?= Message-ID: <20141106052826.113470.15360@psf.io> https://hg.python.org/cpython/rev/501edbbb74ff changeset: 93410:501edbbb74ff branch: 3.4 parent: 93407:cd36ba22602d user: Raymond Hettinger date: Wed Nov 05 21:27:56 2014 -0800 summary: Issue 22803: Add missing versionadded directive. files: Doc/library/textwrap.rst | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Doc/library/textwrap.rst b/Doc/library/textwrap.rst --- a/Doc/library/textwrap.rst +++ b/Doc/library/textwrap.rst @@ -113,6 +113,8 @@ + + world + .. versionadded:: 3.3 + :func:`wrap`, :func:`fill` and :func:`shorten` work by creating a :class:`TextWrapper` instance and calling a single method on it. That -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 6 06:53:28 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Nov 2014 05:53:28 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_fix_test_where?= =?utf-8?q?_sizeof=28long=29_!=3D_sizeof=28int=29?= Message-ID: <20141106055322.108101.16413@psf.io> https://hg.python.org/cpython/rev/d9fbe4fb2afc changeset: 93412:d9fbe4fb2afc branch: 3.4 parent: 93410:501edbbb74ff user: Benjamin Peterson date: Thu Nov 06 00:52:58 2014 -0500 summary: fix test where sizeof(long) != sizeof(int) files: Modules/_ctypes/_ctypes_test.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -527,10 +527,10 @@ return 1; } -EXPORT(int left = 10); -EXPORT(int top = 20); -EXPORT(int right = 30); -EXPORT(int bottom = 40); +EXPORT(long left = 10); +EXPORT(long top = 20); +EXPORT(long right = 30); +EXPORT(long bottom = 40); EXPORT(RECT) ReturnRect(int i, RECT ar, RECT* br, POINT cp, RECT dr, RECT *er, POINT fp, RECT gr) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 6 06:53:27 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Nov 2014 05:53:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_fix_test_where?= =?utf-8?q?_sizeof=28long=29_!=3D_sizeof=28int=29?= Message-ID: <20141106055322.113482.2215@psf.io> https://hg.python.org/cpython/rev/5a2d40435dfe changeset: 93413:5a2d40435dfe branch: 2.7 parent: 93409:71d5a69e122b user: Benjamin Peterson date: Thu Nov 06 00:52:58 2014 -0500 summary: fix test where sizeof(long) != sizeof(int) files: Modules/_ctypes/_ctypes_test.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -540,10 +540,10 @@ return 1; } -EXPORT(int left = 10); -EXPORT(int top = 20); -EXPORT(int right = 30); -EXPORT(int bottom = 40); +EXPORT(long left = 10); +EXPORT(long top = 20); +EXPORT(long right = 30); +EXPORT(long bottom = 40); EXPORT(RECT) ReturnRect(int i, RECT ar, RECT* br, POINT cp, RECT dr, RECT *er, POINT fp, RECT gr) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 6 06:53:27 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 06 Nov 2014 05:53:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20141106055322.85204.98811@psf.io> https://hg.python.org/cpython/rev/123369631063 changeset: 93414:123369631063 parent: 93411:9ed44777331d parent: 93412:d9fbe4fb2afc user: Benjamin Peterson date: Thu Nov 06 00:53:18 2014 -0500 summary: merge 3.4 files: Modules/_ctypes/_ctypes_test.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -527,10 +527,10 @@ return 1; } -EXPORT(int left = 10); -EXPORT(int top = 20); -EXPORT(int right = 30); -EXPORT(int bottom = 40); +EXPORT(long left = 10); +EXPORT(long top = 20); +EXPORT(long right = 30); +EXPORT(long bottom = 40); EXPORT(RECT) ReturnRect(int i, RECT ar, RECT* br, POINT cp, RECT dr, RECT *er, POINT fp, RECT gr) -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Thu Nov 6 10:33:02 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 06 Nov 2014 10:33:02 +0100 Subject: [Python-checkins] Daily reference leaks (089573725c77): sum=3 Message-ID: results for 089573725c77 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogc_f6Zi', '-x'] From python-checkins at python.org Thu Nov 6 14:38:37 2014 From: python-checkins at python.org (georg.brandl) Date: Thu, 06 Nov 2014 13:38:37 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_merge_with_3=2E4?= Message-ID: <20141106133833.707.24395@psf.io> https://hg.python.org/cpython/rev/124e9547cb36 changeset: 93416:124e9547cb36 parent: 93414:123369631063 parent: 93415:39536b377241 user: Georg Brandl date: Thu Nov 06 14:38:23 2014 +0100 summary: merge with 3.4 files: Lib/test/test_codecmaps_cn.py | 8 +++----- Lib/test/test_codecmaps_hk.py | 2 +- Lib/test/test_codecmaps_jp.py | 12 +++++------- Lib/test/test_codecmaps_kr.py | 8 +++----- Lib/test/test_codecmaps_tw.py | 6 ++---- Lib/test/test_normalization.py | 2 +- Lib/test/test_ucn.py | 2 +- 7 files changed, 16 insertions(+), 24 deletions(-) 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 @@ -10,19 +10,17 @@ class TestGB2312Map(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'gb2312' - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-CN.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/EUC-CN.TXT' class TestGBKMap(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'gbk' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/' \ - 'MICSFT/WINDOWS/CP936.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/CP936.TXT' class TestGB18030Map(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'gb18030' - mapfileurl = 'http://source.icu-project.org/repos/icu/data/' \ - 'trunk/charset/data/xml/gb-18030-2000.xml' + mapfileurl = 'http://www.pythontest.net/unicode/gb-18030-2000.xml' if __name__ == "__main__": 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 @@ -10,7 +10,7 @@ class TestBig5HKSCSMap(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'big5hkscs' - mapfileurl = 'http://people.freebsd.org/~perky/i18n/BIG5HKSCS-2004.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/BIG5HKSCS-2004.TXT' if __name__ == "__main__": unittest.main() 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 @@ -10,8 +10,7 @@ class TestCP932Map(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'cp932' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/' \ - 'WINDOWS/CP932.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/CP932.TXT' supmaps = [ (b'\x80', '\u0080'), (b'\xa0', '\uf8f0'), @@ -27,15 +26,14 @@ unittest.TestCase): encoding = 'euc_jp' mapfilename = 'EUC-JP.TXT' - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-JP.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/EUC-JP.TXT' class TestSJISCOMPATMap(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'shift_jis' mapfilename = 'SHIFTJIS.TXT' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/OBSOLETE' \ - '/EASTASIA/JIS/SHIFTJIS.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/SHIFTJIS.TXT' pass_enctest = [ (b'\x81_', '\\'), ] @@ -49,14 +47,14 @@ unittest.TestCase): encoding = 'euc_jisx0213' mapfilename = 'EUC-JISX0213.TXT' - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-JISX0213.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/EUC-JISX0213.TXT' class TestSJISX0213Map(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'shift_jisx0213' mapfilename = 'SHIFT_JISX0213.TXT' - mapfileurl = 'http://people.freebsd.org/~perky/i18n/SHIFT_JISX0213.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/SHIFT_JISX0213.TXT' if __name__ == "__main__": 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 @@ -10,14 +10,13 @@ class TestCP949Map(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'cp949' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT' \ - '/WINDOWS/CP949.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/CP949.TXT' class TestEUCKRMap(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'euc_kr' - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-KR.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/EUC-KR.TXT' # A4D4 HANGUL FILLER indicates the begin of 8-bytes make-up sequence. pass_enctest = [(b'\xa4\xd4', '\u3164')] @@ -27,8 +26,7 @@ class TestJOHABMap(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'johab' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/' \ - 'KSC/JOHAB.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/JOHAB.TXT' # KS X 1001 standard assigned 0x5c as WON SIGN. # but, in early 90s that is the only era used johab widely, # the most softwares implements it as REVERSE SOLIDUS. 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 @@ -10,14 +10,12 @@ class TestBIG5Map(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'big5' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/OBSOLETE/' \ - 'EASTASIA/OTHER/BIG5.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/BIG5.TXT' class TestCP950Map(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'cp950' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/' \ - 'WINDOWS/CP950.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/CP950.TXT' pass_enctest = [ (b'\xa2\xcc', '\u5341'), (b'\xa2\xce', '\u5345'), diff --git a/Lib/test/test_normalization.py b/Lib/test/test_normalization.py --- a/Lib/test/test_normalization.py +++ b/Lib/test/test_normalization.py @@ -7,7 +7,7 @@ from unicodedata import normalize, unidata_version TESTDATAFILE = "NormalizationTest.txt" -TESTDATAURL = "http://www.unicode.org/Public/" + unidata_version + "/ucd/" + TESTDATAFILE +TESTDATAURL = "http://www.pythontest.net/unicode/" + unidata_version + "/" + TESTDATAFILE def check_version(testfile): hdr = testfile.readline() diff --git a/Lib/test/test_ucn.py b/Lib/test/test_ucn.py --- a/Lib/test/test_ucn.py +++ b/Lib/test/test_ucn.py @@ -172,7 +172,7 @@ def test_named_sequences_full(self): # Check all the named sequences - url = ("http://www.unicode.org/Public/%s/ucd/NamedSequences.txt" % + url = ("http://www.pythontest.net/unicode/%s/NamedSequences.txt" % unicodedata.unidata_version) try: testdata = support.open_urlresource(url, encoding="utf-8", -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 6 14:38:37 2014 From: python-checkins at python.org (georg.brandl) Date: Thu, 06 Nov 2014 13:38:37 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogIzIyNjUwOiB0ZXN0?= =?utf-8?q?_suite=3A_load_Unicode_test_data_files_from_www=2Epythontest=2E?= =?utf-8?q?net?= Message-ID: <20141106133833.113470.37898@psf.io> https://hg.python.org/cpython/rev/39536b377241 changeset: 93415:39536b377241 branch: 3.4 parent: 93412:d9fbe4fb2afc user: Georg Brandl date: Thu Nov 06 14:37:49 2014 +0100 summary: #22650: test suite: load Unicode test data files from www.pythontest.net files: Lib/test/test_codecmaps_cn.py | 8 +++----- Lib/test/test_codecmaps_hk.py | 2 +- Lib/test/test_codecmaps_jp.py | 12 +++++------- Lib/test/test_codecmaps_kr.py | 8 +++----- Lib/test/test_codecmaps_tw.py | 6 ++---- Lib/test/test_normalization.py | 2 +- Lib/test/test_ucn.py | 2 +- 7 files changed, 16 insertions(+), 24 deletions(-) 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 @@ -10,19 +10,17 @@ class TestGB2312Map(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'gb2312' - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-CN.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/EUC-CN.TXT' class TestGBKMap(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'gbk' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/' \ - 'MICSFT/WINDOWS/CP936.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/CP936.TXT' class TestGB18030Map(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'gb18030' - mapfileurl = 'http://source.icu-project.org/repos/icu/data/' \ - 'trunk/charset/data/xml/gb-18030-2000.xml' + mapfileurl = 'http://www.pythontest.net/unicode/gb-18030-2000.xml' if __name__ == "__main__": 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 @@ -10,7 +10,7 @@ class TestBig5HKSCSMap(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'big5hkscs' - mapfileurl = 'http://people.freebsd.org/~perky/i18n/BIG5HKSCS-2004.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/BIG5HKSCS-2004.TXT' if __name__ == "__main__": unittest.main() 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 @@ -10,8 +10,7 @@ class TestCP932Map(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'cp932' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/' \ - 'WINDOWS/CP932.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/CP932.TXT' supmaps = [ (b'\x80', '\u0080'), (b'\xa0', '\uf8f0'), @@ -27,15 +26,14 @@ unittest.TestCase): encoding = 'euc_jp' mapfilename = 'EUC-JP.TXT' - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-JP.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/EUC-JP.TXT' class TestSJISCOMPATMap(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'shift_jis' mapfilename = 'SHIFTJIS.TXT' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/OBSOLETE' \ - '/EASTASIA/JIS/SHIFTJIS.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/SHIFTJIS.TXT' pass_enctest = [ (b'\x81_', '\\'), ] @@ -49,14 +47,14 @@ unittest.TestCase): encoding = 'euc_jisx0213' mapfilename = 'EUC-JISX0213.TXT' - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-JISX0213.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/EUC-JISX0213.TXT' class TestSJISX0213Map(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'shift_jisx0213' mapfilename = 'SHIFT_JISX0213.TXT' - mapfileurl = 'http://people.freebsd.org/~perky/i18n/SHIFT_JISX0213.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/SHIFT_JISX0213.TXT' if __name__ == "__main__": 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 @@ -10,14 +10,13 @@ class TestCP949Map(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'cp949' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT' \ - '/WINDOWS/CP949.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/CP949.TXT' class TestEUCKRMap(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'euc_kr' - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-KR.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/EUC-KR.TXT' # A4D4 HANGUL FILLER indicates the begin of 8-bytes make-up sequence. pass_enctest = [(b'\xa4\xd4', '\u3164')] @@ -27,8 +26,7 @@ class TestJOHABMap(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'johab' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/' \ - 'KSC/JOHAB.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/JOHAB.TXT' # KS X 1001 standard assigned 0x5c as WON SIGN. # but, in early 90s that is the only era used johab widely, # the most softwares implements it as REVERSE SOLIDUS. 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 @@ -10,14 +10,12 @@ class TestBIG5Map(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'big5' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/OBSOLETE/' \ - 'EASTASIA/OTHER/BIG5.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/BIG5.TXT' class TestCP950Map(multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'cp950' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/' \ - 'WINDOWS/CP950.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/CP950.TXT' pass_enctest = [ (b'\xa2\xcc', '\u5341'), (b'\xa2\xce', '\u5345'), diff --git a/Lib/test/test_normalization.py b/Lib/test/test_normalization.py --- a/Lib/test/test_normalization.py +++ b/Lib/test/test_normalization.py @@ -7,7 +7,7 @@ from unicodedata import normalize, unidata_version TESTDATAFILE = "NormalizationTest.txt" -TESTDATAURL = "http://www.unicode.org/Public/" + unidata_version + "/ucd/" + TESTDATAFILE +TESTDATAURL = "http://www.pythontest.net/unicode/" + unidata_version + "/" + TESTDATAFILE def check_version(testfile): hdr = testfile.readline() diff --git a/Lib/test/test_ucn.py b/Lib/test/test_ucn.py --- a/Lib/test/test_ucn.py +++ b/Lib/test/test_ucn.py @@ -172,7 +172,7 @@ def test_named_sequences_full(self): # Check all the named sequences - url = ("http://www.unicode.org/Public/%s/ucd/NamedSequences.txt" % + url = ("http://www.pythontest.net/unicode/%s/NamedSequences.txt" % unicodedata.unidata_version) try: testdata = support.open_urlresource(url, encoding="utf-8", -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 6 14:57:08 2014 From: python-checkins at python.org (georg.brandl) Date: Thu, 06 Nov 2014 13:57:08 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf-8?q?_merge_heads?= Message-ID: <20141106135653.85206.51901@psf.io> https://hg.python.org/cpython/rev/14a69e40dbb0 changeset: 93418:14a69e40dbb0 branch: 2.7 parent: 93417:0af36ea1d010 parent: 93413:5a2d40435dfe user: Georg Brandl date: Thu Nov 06 14:56:47 2014 +0100 summary: merge heads files: Doc/make.bat | 2 +- Lib/ctypes/test/test_win32.py | 26 +++++++- Modules/_ctypes/_ctypes_test.c | 43 ++++++++++++++ Modules/_ctypes/callproc.c | 6 +- Modules/_ctypes/libffi_msvc/ffi.c | 29 +++++++- Modules/_ctypes/libffi_msvc/prep_cif.c | 18 ++++- Modules/_ctypes/libffi_msvc/types.c | 2 +- 7 files changed, 107 insertions(+), 19 deletions(-) diff --git a/Doc/make.bat b/Doc/make.bat --- a/Doc/make.bat +++ b/Doc/make.bat @@ -12,7 +12,7 @@ if NOT DEFINED ProgramFiles(x86) set _PRGMFLS=%ProgramFiles% if "%HTMLHELP%" EQU "" set HTMLHELP=%_PRGMFLS%\HTML Help Workshop\hhc.exe -if "%DISTVERSION%" EQU "" for /f "usebackq" %%v in (`%PYTHON% tools/patchlevel.py`) do set DISTVERSION=%%v +if "%DISTVERSION%" EQU "" for /f "usebackq" %%v in (`%PYTHON% tools/extensions/patchlevel.py`) do set DISTVERSION=%%v if "%BUILDDIR%" EQU "" set BUILDDIR=build diff --git a/Lib/ctypes/test/test_win32.py b/Lib/ctypes/test/test_win32.py --- a/Lib/ctypes/test/test_win32.py +++ b/Lib/ctypes/test/test_win32.py @@ -90,9 +90,29 @@ dll = CDLL(_ctypes_test.__file__) - pt = POINT(10, 10) - rect = RECT(0, 0, 20, 20) - self.assertEqual(1, dll.PointInRect(byref(rect), pt)) + pt = POINT(15, 25) + left = c_long.in_dll(dll, 'left') + top = c_long.in_dll(dll, 'top') + right = c_long.in_dll(dll, 'right') + bottom = c_long.in_dll(dll, 'bottom') + rect = RECT(left, top, right, bottom) + PointInRect = dll.PointInRect + PointInRect.argtypes = [POINTER(RECT), POINT] + self.assertEqual(1, PointInRect(byref(rect), pt)) + + ReturnRect = dll.ReturnRect + ReturnRect.argtypes = [c_int, RECT, POINTER(RECT), POINT, RECT, + POINTER(RECT), POINT, RECT] + ReturnRect.restype = RECT + for i in range(4): + ret = ReturnRect(i, rect, pointer(rect), pt, rect, + byref(rect), pt, rect) + # the c function will check and modify ret if something is + # passed in improperly + self.assertEqual(ret.left, left.value) + self.assertEqual(ret.right, right.value) + self.assertEqual(ret.top, top.value) + self.assertEqual(ret.bottom, bottom.value) if __name__ == '__main__': unittest.main() diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -540,6 +540,49 @@ return 1; } +EXPORT(long left = 10); +EXPORT(long top = 20); +EXPORT(long right = 30); +EXPORT(long bottom = 40); + +EXPORT(RECT) ReturnRect(int i, RECT ar, RECT* br, POINT cp, RECT dr, + RECT *er, POINT fp, RECT gr) +{ + /*Check input */ + if (ar.left + br->left + dr.left + er->left + gr.left != left * 5) + { + ar.left = 100; + return ar; + } + if (ar.right + br->right + dr.right + er->right + gr.right != right * 5) + { + ar.right = 100; + return ar; + } + if (cp.x != fp.x) + { + ar.left = -100; + } + if (cp.y != fp.y) + { + ar.left = -200; + } + switch(i) + { + case 0: + return ar; + break; + case 1: + return dr; + break; + case 2: + return gr; + break; + + } + return ar; +} + typedef struct { short x; short y; diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -1170,11 +1170,7 @@ } for (i = 0; i < argcount; ++i) { atypes[i] = args[i].ffi_type; - if (atypes[i]->type == FFI_TYPE_STRUCT -#ifdef _WIN64 - && atypes[i]->size <= sizeof(void *) -#endif - ) + if (atypes[i]->type == FFI_TYPE_STRUCT) avalues[i] = (void *)args[i].value.p; else avalues[i] = (void *)&args[i].value; diff --git a/Modules/_ctypes/libffi_msvc/ffi.c b/Modules/_ctypes/libffi_msvc/ffi.c --- a/Modules/_ctypes/libffi_msvc/ffi.c +++ b/Modules/_ctypes/libffi_msvc/ffi.c @@ -102,6 +102,15 @@ FFI_ASSERT(0); } } +#ifdef _WIN64 + else if (z > 8) + { + /* On Win64, if a single argument takes more than 8 bytes, + then it is always passed by reference. */ + *(void **)argp = *p_argv; + z = 8; + } +#endif else { memcpy(argp, *p_argv, z); @@ -124,7 +133,6 @@ switch (cif->rtype->type) { case FFI_TYPE_VOID: - case FFI_TYPE_STRUCT: case FFI_TYPE_SINT64: case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: @@ -132,6 +140,18 @@ cif->flags = (unsigned) cif->rtype->type; break; + case FFI_TYPE_STRUCT: + /* MSVC returns small structures in registers. Put in cif->flags + the value FFI_TYPE_STRUCT only if the structure is big enough; + otherwise, put the 4- or 8-bytes integer type. */ + if (cif->rtype->size <= 4) + cif->flags = FFI_TYPE_INT; + else if (cif->rtype->size <= 8) + cif->flags = FFI_TYPE_SINT64; + else + cif->flags = FFI_TYPE_STRUCT; + break; + case FFI_TYPE_UINT64: #ifdef _WIN64 case FFI_TYPE_POINTER: @@ -201,8 +221,7 @@ #else case FFI_SYSV: /*@-usedef@*/ - /* Function call needs at least 40 bytes stack size, on win64 AMD64 */ - return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes ? cif->bytes : 40, + return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; @@ -227,7 +246,7 @@ #else static void __fastcall #endif -ffi_closure_SYSV (ffi_closure *closure, int *argp) +ffi_closure_SYSV (ffi_closure *closure, char *argp) { // this is our return value storage long double res; @@ -237,7 +256,7 @@ void **arg_area; unsigned short rtype; void *resp = (void*)&res; - void *args = &argp[1]; + void *args = argp + sizeof(void*); cif = closure->cif; arg_area = (void**) alloca (cif->nargs * sizeof (void*)); diff --git a/Modules/_ctypes/libffi_msvc/prep_cif.c b/Modules/_ctypes/libffi_msvc/prep_cif.c --- a/Modules/_ctypes/libffi_msvc/prep_cif.c +++ b/Modules/_ctypes/libffi_msvc/prep_cif.c @@ -116,9 +116,9 @@ #if !defined M68K && !defined __x86_64__ && !defined S390 /* Make space for the return structure pointer */ if (cif->rtype->type == FFI_TYPE_STRUCT - /* MSVC returns small structures in registers. But we have a different - workaround: pretend int32 or int64 return type, and converting to - structure afterwards. */ +#ifdef _WIN32 + && (cif->rtype->size > 8) /* MSVC returns small structs in registers */ +#endif #ifdef SPARC && (cif->abi != FFI_V9 || cif->rtype->size > 32) #endif @@ -143,7 +143,11 @@ && ((*ptr)->size > 16 || cif->abi != FFI_V9)) || ((*ptr)->type == FFI_TYPE_LONGDOUBLE && cif->abi != FFI_V9)) - bytes += sizeof(void*); + bytes += sizeof(void*); + else +#elif defined (_WIN64) + if ((*ptr)->type == FFI_TYPE_STRUCT && ((*ptr)->size > 8)) + bytes += sizeof(void*); else #endif { @@ -168,6 +172,12 @@ #endif } +#ifdef _WIN64 + /* Function call needs at least 40 bytes stack size, on win64 AMD64 */ + if (bytes < 40) + bytes = 40; +#endif + cif->bytes = bytes; /* Perform machine dependent cif processing */ diff --git a/Modules/_ctypes/libffi_msvc/types.c b/Modules/_ctypes/libffi_msvc/types.c --- a/Modules/_ctypes/libffi_msvc/types.c +++ b/Modules/_ctypes/libffi_msvc/types.c @@ -43,7 +43,7 @@ FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT); #if defined ALPHA || defined SPARC64 || defined X86_64 || defined S390X \ - || defined IA64 + || defined IA64 || defined _WIN64 FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 6 14:57:08 2014 From: python-checkins at python.org (georg.brandl) Date: Thu, 06 Nov 2014 13:57:08 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzIyNjUwOiB0ZXN0?= =?utf-8?q?_suite=3A_load_Unicode_test_data_files_from_www=2Epythontest=2E?= =?utf-8?q?net?= Message-ID: <20141106135652.108375.20457@psf.io> https://hg.python.org/cpython/rev/0af36ea1d010 changeset: 93417:0af36ea1d010 branch: 2.7 parent: 93401:3e8d3c4bc17e user: Georg Brandl date: Thu Nov 06 14:37:49 2014 +0100 summary: #22650: test suite: load Unicode test data files from www.pythontest.net files: Lib/test/test_codecmaps_cn.py | 8 +++----- Lib/test/test_codecmaps_hk.py | 2 +- Lib/test/test_codecmaps_jp.py | 12 +++++------- Lib/test/test_codecmaps_kr.py | 8 +++----- Lib/test/test_codecmaps_tw.py | 6 ++---- Lib/test/test_normalization.py | 2 +- 6 files changed, 15 insertions(+), 23 deletions(-) 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 @@ -10,19 +10,17 @@ class TestGB2312Map(test_multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'gb2312' - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-CN.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/EUC-CN.TXT' class TestGBKMap(test_multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'gbk' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/' \ - 'MICSFT/WINDOWS/CP936.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/CP936.TXT' class TestGB18030Map(test_multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'gb18030' - mapfileurl = 'http://source.icu-project.org/repos/icu/data/' \ - 'trunk/charset/data/xml/gb-18030-2000.xml' + mapfileurl = 'http://www.pythontest.net/unicode/gb-18030-2000.xml' def test_main(): 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 @@ -10,7 +10,7 @@ class TestBig5HKSCSMap(test_multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'big5hkscs' - mapfileurl = 'http://people.freebsd.org/~perky/i18n/BIG5HKSCS-2004.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/BIG5HKSCS-2004.TXT' def test_main(): test_support.run_unittest(__name__) 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 @@ -10,8 +10,7 @@ class TestCP932Map(test_multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'cp932' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/' \ - 'WINDOWS/CP932.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/CP932.TXT' supmaps = [ ('\x80', u'\u0080'), ('\xa0', u'\uf8f0'), @@ -27,15 +26,14 @@ unittest.TestCase): encoding = 'euc_jp' mapfilename = 'EUC-JP.TXT' - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-JP.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/EUC-JP.TXT' class TestSJISCOMPATMap(test_multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'shift_jis' mapfilename = 'SHIFTJIS.TXT' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/OBSOLETE' \ - '/EASTASIA/JIS/SHIFTJIS.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/SHIFTJIS.TXT' pass_enctest = [ ('\x81_', u'\\'), ] @@ -49,14 +47,14 @@ unittest.TestCase): encoding = 'euc_jisx0213' mapfilename = 'EUC-JISX0213.TXT' - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-JISX0213.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/EUC-JISX0213.TXT' class TestSJISX0213Map(test_multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'shift_jisx0213' mapfilename = 'SHIFT_JISX0213.TXT' - mapfileurl = 'http://people.freebsd.org/~perky/i18n/SHIFT_JISX0213.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/SHIFT_JISX0213.TXT' def test_main(): 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 @@ -10,14 +10,13 @@ class TestCP949Map(test_multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'cp949' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT' \ - '/WINDOWS/CP949.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/CP949.TXT' class TestEUCKRMap(test_multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'euc_kr' - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-KR.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/EUC-KR.TXT' # A4D4 HANGUL FILLER indicates the begin of 8-bytes make-up sequence. pass_enctest = [('\xa4\xd4', u'\u3164')] @@ -27,8 +26,7 @@ class TestJOHABMap(test_multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'johab' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/' \ - 'KSC/JOHAB.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/JOHAB.TXT' # KS X 1001 standard assigned 0x5c as WON SIGN. # but, in early 90s that is the only era used johab widely, # the most softwares implements it as REVERSE SOLIDUS. 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 @@ -10,14 +10,12 @@ class TestBIG5Map(test_multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'big5' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/OBSOLETE/' \ - 'EASTASIA/OTHER/BIG5.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/BIG5.TXT' class TestCP950Map(test_multibytecodec_support.TestBase_Mapping, unittest.TestCase): encoding = 'cp950' - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/' \ - 'WINDOWS/CP950.TXT' + mapfileurl = 'http://www.pythontest.net/unicode/CP950.TXT' pass_enctest = [ ('\xa2\xcc', u'\u5341'), ('\xa2\xce', u'\u5345'), diff --git a/Lib/test/test_normalization.py b/Lib/test/test_normalization.py --- a/Lib/test/test_normalization.py +++ b/Lib/test/test_normalization.py @@ -7,7 +7,7 @@ from unicodedata import normalize, unidata_version TESTDATAFILE = "NormalizationTest.txt" -TESTDATAURL = "http://www.unicode.org/Public/" + unidata_version + "/ucd/" + TESTDATAFILE +TESTDATAURL = "http://www.pythontest.net/unicode/" + unidata_version + "/" + TESTDATAFILE def check_version(testfile): hdr = testfile.readline() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 6 15:33:48 2014 From: python-checkins at python.org (georg.brandl) Date: Thu, 06 Nov 2014 14:33:48 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Try_to_transfe?= =?utf-8?q?r_the_Unicode_test_data_files_gzipped=2E?= Message-ID: <20141106143341.108091.47188@psf.io> https://hg.python.org/cpython/rev/540b022ae7a9 changeset: 93419:540b022ae7a9 branch: 3.4 parent: 93415:39536b377241 user: Georg Brandl date: Thu Nov 06 15:33:30 2014 +0100 summary: Try to transfer the Unicode test data files gzipped. files: Lib/test/support/__init__.py | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -1029,7 +1029,12 @@ requires('urlfetch') print('\tfetching %s ...' % url, file=get_original_stdout()) - f = urllib.request.urlopen(url, timeout=15) + opener = urllib.request.build_opener() + if gzip: + opener.addheaders.append(('Accept-Encoding', 'gzip')) + f = opener.open(url, timeout=15) + if gzip and f.headers.get('Content-Encoding') == 'gzip': + f = gzip.GzipFile(fileobj=f) try: with open(fn, "wb") as out: s = f.read() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 6 15:33:48 2014 From: python-checkins at python.org (georg.brandl) Date: Thu, 06 Nov 2014 14:33:48 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_merge_with_3=2E4?= Message-ID: <20141106143342.108073.34910@psf.io> https://hg.python.org/cpython/rev/a688d3206646 changeset: 93420:a688d3206646 parent: 93416:124e9547cb36 parent: 93419:540b022ae7a9 user: Georg Brandl date: Thu Nov 06 15:33:35 2014 +0100 summary: merge with 3.4 files: Lib/test/support/__init__.py | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -1029,7 +1029,12 @@ requires('urlfetch') print('\tfetching %s ...' % url, file=get_original_stdout()) - f = urllib.request.urlopen(url, timeout=15) + opener = urllib.request.build_opener() + if gzip: + opener.addheaders.append(('Accept-Encoding', 'gzip')) + f = opener.open(url, timeout=15) + if gzip and f.headers.get('Content-Encoding') == 'gzip': + f = gzip.GzipFile(fileobj=f) try: with open(fn, "wb") as out: s = f.read() -- Repository URL: https://hg.python.org/cpython From bcannon at gmail.com Thu Nov 6 15:39:03 2014 From: bcannon at gmail.com (Brett Cannon) Date: Thu, 06 Nov 2014 14:39:03 +0000 Subject: [Python-checkins] cpython (2.7): #22650: test suite: load Unicode test data files from www.pythontest.net References: <20141106135652.108375.20457@psf.io> Message-ID: What is pythontest.net? Is it something we control, and if so how do we add things to it for tests? Did I miss an email on python-dev or python-committers about this? On Thu Nov 06 2014 at 8:57:22 AM georg.brandl wrote: > https://hg.python.org/cpython/rev/0af36ea1d010 > changeset: 93417:0af36ea1d010 > branch: 2.7 > parent: 93401:3e8d3c4bc17e > user: Georg Brandl > date: Thu Nov 06 14:37:49 2014 +0100 > summary: > #22650: test suite: load Unicode test data files from www.pythontest.net > > files: > Lib/test/test_codecmaps_cn.py | 8 +++----- > Lib/test/test_codecmaps_hk.py | 2 +- > Lib/test/test_codecmaps_jp.py | 12 +++++------- > Lib/test/test_codecmaps_kr.py | 8 +++----- > Lib/test/test_codecmaps_tw.py | 6 ++---- > Lib/test/test_normalization.py | 2 +- > 6 files changed, 15 insertions(+), 23 deletions(-) > > > 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 > @@ -10,19 +10,17 @@ > class TestGB2312Map(test_multibytecodec_support.TestBase_Mapping, > unittest.TestCase): > encoding = 'gb2312' > - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-CN.TXT' > + mapfileurl = 'http://www.pythontest.net/unicode/EUC-CN.TXT' > > class TestGBKMap(test_multibytecodec_support.TestBase_Mapping, > unittest.TestCase): > encoding = 'gbk' > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/' \ > - 'MICSFT/WINDOWS/CP936.TXT' > + mapfileurl = 'http://www.pythontest.net/unicode/CP936.TXT' > > class TestGB18030Map(test_multibytecodec_support.TestBase_Mapping, > unittest.TestCase): > encoding = 'gb18030' > - mapfileurl = 'http://source.icu-project.org/repos/icu/data/' \ > - 'trunk/charset/data/xml/gb-18030-2000.xml' > + mapfileurl = 'http://www.pythontest.net/unicode/gb-18030-2000.xml' > > > def test_main(): > 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 > @@ -10,7 +10,7 @@ > class TestBig5HKSCSMap(test_multibytecodec_support.TestBase_Mapping, > unittest.TestCase): > encoding = 'big5hkscs' > - mapfileurl = 'http://people.freebsd.org/~ > perky/i18n/BIG5HKSCS-2004.TXT' > + mapfileurl = 'http://www.pythontest.net/unicode/BIG5HKSCS-2004.TXT' > > def test_main(): > test_support.run_unittest(__name__) > 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 > @@ -10,8 +10,7 @@ > class TestCP932Map(test_multibytecodec_support.TestBase_Mapping, > unittest.TestCase): > encoding = 'cp932' > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/' > \ > - 'WINDOWS/CP932.TXT' > + mapfileurl = 'http://www.pythontest.net/unicode/CP932.TXT' > supmaps = [ > ('\x80', u'\u0080'), > ('\xa0', u'\uf8f0'), > @@ -27,15 +26,14 @@ > unittest.TestCase): > encoding = 'euc_jp' > mapfilename = 'EUC-JP.TXT' > - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-JP.TXT' > + mapfileurl = 'http://www.pythontest.net/unicode/EUC-JP.TXT' > > > class TestSJISCOMPATMap(test_multibytecodec_support.TestBase_Mapping, > unittest.TestCase): > encoding = 'shift_jis' > mapfilename = 'SHIFTJIS.TXT' > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/OBSOLETE' \ > - '/EASTASIA/JIS/SHIFTJIS.TXT' > + mapfileurl = 'http://www.pythontest.net/unicode/SHIFTJIS.TXT' > pass_enctest = [ > ('\x81_', u'\\'), > ] > @@ -49,14 +47,14 @@ > unittest.TestCase): > encoding = 'euc_jisx0213' > mapfilename = 'EUC-JISX0213.TXT' > - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-JISX0213.TXT' > + mapfileurl = 'http://www.pythontest.net/unicode/EUC-JISX0213.TXT' > > > class TestSJISX0213Map(test_multibytecodec_support.TestBase_Mapping, > unittest.TestCase): > encoding = 'shift_jisx0213' > mapfilename = 'SHIFT_JISX0213.TXT' > - mapfileurl = 'http://people.freebsd.org/~ > perky/i18n/SHIFT_JISX0213.TXT' > + mapfileurl = 'http://www.pythontest.net/unicode/SHIFT_JISX0213.TXT' > > > def test_main(): > 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 > @@ -10,14 +10,13 @@ > class TestCP949Map(test_multibytecodec_support.TestBase_Mapping, > unittest.TestCase): > encoding = 'cp949' > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT' > \ > - '/WINDOWS/CP949.TXT' > + mapfileurl = 'http://www.pythontest.net/unicode/CP949.TXT' > > > class TestEUCKRMap(test_multibytecodec_support.TestBase_Mapping, > unittest.TestCase): > encoding = 'euc_kr' > - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-KR.TXT' > + mapfileurl = 'http://www.pythontest.net/unicode/EUC-KR.TXT' > > # A4D4 HANGUL FILLER indicates the begin of 8-bytes make-up sequence. > pass_enctest = [('\xa4\xd4', u'\u3164')] > @@ -27,8 +26,7 @@ > class TestJOHABMap(test_multibytecodec_support.TestBase_Mapping, > unittest.TestCase): > encoding = 'johab' > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/OBSOLETE/ > EASTASIA/' \ > - 'KSC/JOHAB.TXT' > + mapfileurl = 'http://www.pythontest.net/unicode/JOHAB.TXT' > # KS X 1001 standard assigned 0x5c as WON SIGN. > # but, in early 90s that is the only era used johab widely, > # the most softwares implements it as REVERSE SOLIDUS. > 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 > @@ -10,14 +10,12 @@ > class TestBIG5Map(test_multibytecodec_support.TestBase_Mapping, > unittest.TestCase): > encoding = 'big5' > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/OBSOLETE/' \ > - 'EASTASIA/OTHER/BIG5.TXT' > + mapfileurl = 'http://www.pythontest.net/unicode/BIG5.TXT' > > class TestCP950Map(test_multibytecodec_support.TestBase_Mapping, > unittest.TestCase): > encoding = 'cp950' > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/' > \ > - 'WINDOWS/CP950.TXT' > + mapfileurl = 'http://www.pythontest.net/unicode/CP950.TXT' > pass_enctest = [ > ('\xa2\xcc', u'\u5341'), > ('\xa2\xce', u'\u5345'), > diff --git a/Lib/test/test_normalization.py b/Lib/test/test_normalization. > py > --- a/Lib/test/test_normalization.py > +++ b/Lib/test/test_normalization.py > @@ -7,7 +7,7 @@ > from unicodedata import normalize, unidata_version > > TESTDATAFILE = "NormalizationTest.txt" > -TESTDATAURL = "http://www.unicode.org/Public/" + unidata_version + > "/ucd/" + TESTDATAFILE > +TESTDATAURL = "http://www.pythontest.net/unicode/" + unidata_version + > "/" + TESTDATAFILE > > def check_version(testfile): > hdr = testfile.readline() > > -- > Repository URL: https://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 benjamin at python.org Thu Nov 6 15:41:50 2014 From: benjamin at python.org (Benjamin Peterson) Date: Thu, 06 Nov 2014 09:41:50 -0500 Subject: [Python-checkins] cpython (2.7): #22650: test suite: load Unicode test data files from www.pythontest.net In-Reply-To: References: <20141106135652.108375.20457@psf.io> Message-ID: <1415284910.3978287.187837097.131F9A4E@webmail.messagingengine.com> On Thu, Nov 6, 2014, at 09:39, Brett Cannon wrote: > What is pythontest.net? Is it something we control, and if so how do we > add > things to it for tests? Did I miss an email on python-dev or > python-committers about this? See https://bugs.python.org/issue22650 > > On Thu Nov 06 2014 at 8:57:22 AM georg.brandl > > wrote: > > > https://hg.python.org/cpython/rev/0af36ea1d010 > > changeset: 93417:0af36ea1d010 > > branch: 2.7 > > parent: 93401:3e8d3c4bc17e > > user: Georg Brandl > > date: Thu Nov 06 14:37:49 2014 +0100 > > summary: > > #22650: test suite: load Unicode test data files from www.pythontest.net > > > > files: > > Lib/test/test_codecmaps_cn.py | 8 +++----- > > Lib/test/test_codecmaps_hk.py | 2 +- > > Lib/test/test_codecmaps_jp.py | 12 +++++------- > > Lib/test/test_codecmaps_kr.py | 8 +++----- > > Lib/test/test_codecmaps_tw.py | 6 ++---- > > Lib/test/test_normalization.py | 2 +- > > 6 files changed, 15 insertions(+), 23 deletions(-) > > > > > > 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 > > @@ -10,19 +10,17 @@ > > class TestGB2312Map(test_multibytecodec_support.TestBase_Mapping, > > unittest.TestCase): > > encoding = 'gb2312' > > - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-CN.TXT' > > + mapfileurl = 'http://www.pythontest.net/unicode/EUC-CN.TXT' > > > > class TestGBKMap(test_multibytecodec_support.TestBase_Mapping, > > unittest.TestCase): > > encoding = 'gbk' > > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/' \ > > - 'MICSFT/WINDOWS/CP936.TXT' > > + mapfileurl = 'http://www.pythontest.net/unicode/CP936.TXT' > > > > class TestGB18030Map(test_multibytecodec_support.TestBase_Mapping, > > unittest.TestCase): > > encoding = 'gb18030' > > - mapfileurl = 'http://source.icu-project.org/repos/icu/data/' \ > > - 'trunk/charset/data/xml/gb-18030-2000.xml' > > + mapfileurl = 'http://www.pythontest.net/unicode/gb-18030-2000.xml' > > > > > > def test_main(): > > 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 > > @@ -10,7 +10,7 @@ > > class TestBig5HKSCSMap(test_multibytecodec_support.TestBase_Mapping, > > unittest.TestCase): > > encoding = 'big5hkscs' > > - mapfileurl = 'http://people.freebsd.org/~ > > perky/i18n/BIG5HKSCS-2004.TXT' > > + mapfileurl = 'http://www.pythontest.net/unicode/BIG5HKSCS-2004.TXT' > > > > def test_main(): > > test_support.run_unittest(__name__) > > 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 > > @@ -10,8 +10,7 @@ > > class TestCP932Map(test_multibytecodec_support.TestBase_Mapping, > > unittest.TestCase): > > encoding = 'cp932' > > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/' > > \ > > - 'WINDOWS/CP932.TXT' > > + mapfileurl = 'http://www.pythontest.net/unicode/CP932.TXT' > > supmaps = [ > > ('\x80', u'\u0080'), > > ('\xa0', u'\uf8f0'), > > @@ -27,15 +26,14 @@ > > unittest.TestCase): > > encoding = 'euc_jp' > > mapfilename = 'EUC-JP.TXT' > > - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-JP.TXT' > > + mapfileurl = 'http://www.pythontest.net/unicode/EUC-JP.TXT' > > > > > > class TestSJISCOMPATMap(test_multibytecodec_support.TestBase_Mapping, > > unittest.TestCase): > > encoding = 'shift_jis' > > mapfilename = 'SHIFTJIS.TXT' > > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/OBSOLETE' \ > > - '/EASTASIA/JIS/SHIFTJIS.TXT' > > + mapfileurl = 'http://www.pythontest.net/unicode/SHIFTJIS.TXT' > > pass_enctest = [ > > ('\x81_', u'\\'), > > ] > > @@ -49,14 +47,14 @@ > > unittest.TestCase): > > encoding = 'euc_jisx0213' > > mapfilename = 'EUC-JISX0213.TXT' > > - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-JISX0213.TXT' > > + mapfileurl = 'http://www.pythontest.net/unicode/EUC-JISX0213.TXT' > > > > > > class TestSJISX0213Map(test_multibytecodec_support.TestBase_Mapping, > > unittest.TestCase): > > encoding = 'shift_jisx0213' > > mapfilename = 'SHIFT_JISX0213.TXT' > > - mapfileurl = 'http://people.freebsd.org/~ > > perky/i18n/SHIFT_JISX0213.TXT' > > + mapfileurl = 'http://www.pythontest.net/unicode/SHIFT_JISX0213.TXT' > > > > > > def test_main(): > > 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 > > @@ -10,14 +10,13 @@ > > class TestCP949Map(test_multibytecodec_support.TestBase_Mapping, > > unittest.TestCase): > > encoding = 'cp949' > > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT' > > \ > > - '/WINDOWS/CP949.TXT' > > + mapfileurl = 'http://www.pythontest.net/unicode/CP949.TXT' > > > > > > class TestEUCKRMap(test_multibytecodec_support.TestBase_Mapping, > > unittest.TestCase): > > encoding = 'euc_kr' > > - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-KR.TXT' > > + mapfileurl = 'http://www.pythontest.net/unicode/EUC-KR.TXT' > > > > # A4D4 HANGUL FILLER indicates the begin of 8-bytes make-up sequence. > > pass_enctest = [('\xa4\xd4', u'\u3164')] > > @@ -27,8 +26,7 @@ > > class TestJOHABMap(test_multibytecodec_support.TestBase_Mapping, > > unittest.TestCase): > > encoding = 'johab' > > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/OBSOLETE/ > > EASTASIA/' \ > > - 'KSC/JOHAB.TXT' > > + mapfileurl = 'http://www.pythontest.net/unicode/JOHAB.TXT' > > # KS X 1001 standard assigned 0x5c as WON SIGN. > > # but, in early 90s that is the only era used johab widely, > > # the most softwares implements it as REVERSE SOLIDUS. > > 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 > > @@ -10,14 +10,12 @@ > > class TestBIG5Map(test_multibytecodec_support.TestBase_Mapping, > > unittest.TestCase): > > encoding = 'big5' > > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/OBSOLETE/' \ > > - 'EASTASIA/OTHER/BIG5.TXT' > > + mapfileurl = 'http://www.pythontest.net/unicode/BIG5.TXT' > > > > class TestCP950Map(test_multibytecodec_support.TestBase_Mapping, > > unittest.TestCase): > > encoding = 'cp950' > > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/' > > \ > > - 'WINDOWS/CP950.TXT' > > + mapfileurl = 'http://www.pythontest.net/unicode/CP950.TXT' > > pass_enctest = [ > > ('\xa2\xcc', u'\u5341'), > > ('\xa2\xce', u'\u5345'), > > diff --git a/Lib/test/test_normalization.py b/Lib/test/test_normalization. > > py > > --- a/Lib/test/test_normalization.py > > +++ b/Lib/test/test_normalization.py > > @@ -7,7 +7,7 @@ > > from unicodedata import normalize, unidata_version > > > > TESTDATAFILE = "NormalizationTest.txt" > > -TESTDATAURL = "http://www.unicode.org/Public/" + unidata_version + > > "/ucd/" + TESTDATAFILE > > +TESTDATAURL = "http://www.pythontest.net/unicode/" + unidata_version + > > "/" + TESTDATAFILE > > > > def check_version(testfile): > > hdr = testfile.readline() > > > > -- > > Repository URL: https://hg.python.org/cpython > > _______________________________________________ > > Python-checkins mailing list > > Python-checkins at python.org > > https://mail.python.org/mailman/listinfo/python-checkins > > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > https://mail.python.org/mailman/listinfo/python-checkins From mal at egenix.com Thu Nov 6 16:09:54 2014 From: mal at egenix.com (M.-A. Lemburg) Date: Thu, 06 Nov 2014 16:09:54 +0100 Subject: [Python-checkins] [Python-Dev] cpython (2.7): #22650: test suite: load Unicode test data files from www.pythontest.net In-Reply-To: References: <20141106135652.108375.20457@psf.io> Message-ID: <545B8F42.10000@egenix.com> On 06.11.2014 15:39, Brett Cannon wrote: > What is pythontest.net? Is it something we control, and if so how do we add > things to it for tests? Did I miss an email on python-dev or > python-committers about this? pythontest.net is a domain owned by the PSF and run by Donald Stufft and Benjamin (I believe). https://bugs.python.org/issue22650 has the details. > On Thu Nov 06 2014 at 8:57:22 AM georg.brandl > wrote: > >> https://hg.python.org/cpython/rev/0af36ea1d010 >> changeset: 93417:0af36ea1d010 >> branch: 2.7 >> parent: 93401:3e8d3c4bc17e >> user: Georg Brandl >> date: Thu Nov 06 14:37:49 2014 +0100 >> summary: >> #22650: test suite: load Unicode test data files from www.pythontest.net -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Source (#1, Nov 06 2014) >>> Python Projects, Consulting and Support ... http://www.egenix.com/ >>> mxODBC.Zope/Plone.Database.Adapter ... http://zope.egenix.com/ >>> mxODBC, mxDateTime, mxTextTools ... http://python.egenix.com/ ________________________________________________________________________ 2014-10-24: Released eGenix pyOpenSSL 0.13.5 ... http://egenix.com/go63 ::::: Try our mxODBC.Connect Python Database Interface for free ! :::::: eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 http://www.egenix.com/company/contact/ From g.brandl at gmx.net Thu Nov 6 17:43:48 2014 From: g.brandl at gmx.net (Georg Brandl) Date: Thu, 06 Nov 2014 17:43:48 +0100 Subject: [Python-checkins] cpython (2.7): #22650: test suite: load Unicode test data files from www.pythontest.net In-Reply-To: References: <20141106135652.108375.20457@psf.io> Message-ID: On 11/06/2014 03:39 PM, Brett Cannon wrote: > What is pythontest.net ? Is it something we control, and > if so how do we add things to it for tests? Did I miss an email on python-dev or > python-committers about this? Benjamin already gave the link to the related issue. The idea is to make the networking tests depend on as few external hosts as possible, so that we can reduce spurious skips or failures when one of them is not reachable or changes its configuration. The pythontest.net domain was chosen to be able to test things like cookies or certificates without a potential of compromising python.org related services. There is a repository at hg.python.org/pythontestdotnet which can be used by developers; server configuration is maintained together with other Python services on https://github.com/python/psf-salt. cheers, Georg From bcannon at gmail.com Thu Nov 6 16:41:09 2014 From: bcannon at gmail.com (Brett Cannon) Date: Thu, 06 Nov 2014 15:41:09 +0000 Subject: [Python-checkins] cpython (2.7): #22650: test suite: load Unicode test data files from www.pythontest.net References: <20141106135652.108375.20457@psf.io> <1415284910.3978287.187837097.131F9A4E@webmail.messagingengine.com> Message-ID: Ah, cool! Just an FYI, the index.html file is not being served for me. -Brett On Thu Nov 06 2014 at 9:41:59 AM Benjamin Peterson wrote: > > > On Thu, Nov 6, 2014, at 09:39, Brett Cannon wrote: > > What is pythontest.net? Is it something we control, and if so how do we > > add > > things to it for tests? Did I miss an email on python-dev or > > python-committers about this? > > See https://bugs.python.org/issue22650 > > > > > On Thu Nov 06 2014 at 8:57:22 AM georg.brandl > > > > wrote: > > > > > https://hg.python.org/cpython/rev/0af36ea1d010 > > > changeset: 93417:0af36ea1d010 > > > branch: 2.7 > > > parent: 93401:3e8d3c4bc17e > > > user: Georg Brandl > > > date: Thu Nov 06 14:37:49 2014 +0100 > > > summary: > > > #22650: test suite: load Unicode test data files from > www.pythontest.net > > > > > > files: > > > Lib/test/test_codecmaps_cn.py | 8 +++----- > > > Lib/test/test_codecmaps_hk.py | 2 +- > > > Lib/test/test_codecmaps_jp.py | 12 +++++------- > > > Lib/test/test_codecmaps_kr.py | 8 +++----- > > > Lib/test/test_codecmaps_tw.py | 6 ++---- > > > Lib/test/test_normalization.py | 2 +- > > > 6 files changed, 15 insertions(+), 23 deletions(-) > > > > > > > > > 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 > > > @@ -10,19 +10,17 @@ > > > class TestGB2312Map(test_multibytecodec_support.TestBase_Mapping, > > > unittest.TestCase): > > > encoding = 'gb2312' > > > - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-CN.TXT' > > > + mapfileurl = 'http://www.pythontest.net/unicode/EUC-CN.TXT' > > > > > > class TestGBKMap(test_multibytecodec_support.TestBase_Mapping, > > > unittest.TestCase): > > > encoding = 'gbk' > > > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/' \ > > > - 'MICSFT/WINDOWS/CP936.TXT' > > > + mapfileurl = 'http://www.pythontest.net/unicode/CP936.TXT' > > > > > > class TestGB18030Map(test_multibytecodec_support.TestBase_Mapping, > > > unittest.TestCase): > > > encoding = 'gb18030' > > > - mapfileurl = 'http://source.icu-project.org/repos/icu/data/' \ > > > - 'trunk/charset/data/xml/gb-18030-2000.xml' > > > + mapfileurl = 'http://www.pythontest.net/unicode/gb-18030-2000.xml > ' > > > > > > > > > def test_main(): > > > 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 > > > @@ -10,7 +10,7 @@ > > > class TestBig5HKSCSMap(test_multibytecodec_support.TestBase_Mapping, > > > unittest.TestCase): > > > encoding = 'big5hkscs' > > > - mapfileurl = 'http://people.freebsd.org/~ > > > perky/i18n/BIG5HKSCS-2004.TXT' > > > + mapfileurl = 'http://www.pythontest.net/uni > code/BIG5HKSCS-2004.TXT' > > > > > > def test_main(): > > > test_support.run_unittest(__name__) > > > 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 > > > @@ -10,8 +10,7 @@ > > > class TestCP932Map(test_multibytecodec_support.TestBase_Mapping, > > > unittest.TestCase): > > > encoding = 'cp932' > > > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/ > MICSFT/' > > > \ > > > - 'WINDOWS/CP932.TXT' > > > + mapfileurl = 'http://www.pythontest.net/unicode/CP932.TXT' > > > supmaps = [ > > > ('\x80', u'\u0080'), > > > ('\xa0', u'\uf8f0'), > > > @@ -27,15 +26,14 @@ > > > unittest.TestCase): > > > encoding = 'euc_jp' > > > mapfilename = 'EUC-JP.TXT' > > > - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-JP.TXT' > > > + mapfileurl = 'http://www.pythontest.net/unicode/EUC-JP.TXT' > > > > > > > > > class TestSJISCOMPATMap(test_multibytecodec_support.TestBase_Mapping, > > > unittest.TestCase): > > > encoding = 'shift_jis' > > > mapfilename = 'SHIFTJIS.TXT' > > > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/OBSOLETE' \ > > > - '/EASTASIA/JIS/SHIFTJIS.TXT' > > > + mapfileurl = 'http://www.pythontest.net/unicode/SHIFTJIS.TXT' > > > pass_enctest = [ > > > ('\x81_', u'\\'), > > > ] > > > @@ -49,14 +47,14 @@ > > > unittest.TestCase): > > > encoding = 'euc_jisx0213' > > > mapfilename = 'EUC-JISX0213.TXT' > > > - mapfileurl = 'http://people.freebsd.org/~pe > rky/i18n/EUC-JISX0213.TXT' > > > + mapfileurl = 'http://www.pythontest.net/unicode/EUC-JISX0213.TXT' > > > > > > > > > class TestSJISX0213Map(test_multibytecodec_support.TestBase_Mapping, > > > unittest.TestCase): > > > encoding = 'shift_jisx0213' > > > mapfilename = 'SHIFT_JISX0213.TXT' > > > - mapfileurl = 'http://people.freebsd.org/~ > > > perky/i18n/SHIFT_JISX0213.TXT' > > > + mapfileurl = 'http://www.pythontest.net/uni > code/SHIFT_JISX0213.TXT' > > > > > > > > > def test_main(): > > > 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 > > > @@ -10,14 +10,13 @@ > > > class TestCP949Map(test_multibytecodec_support.TestBase_Mapping, > > > unittest.TestCase): > > > encoding = 'cp949' > > > - mapfileurl = 'http://www.unicode.org/Public > /MAPPINGS/VENDORS/MICSFT' > > > \ > > > - '/WINDOWS/CP949.TXT' > > > + mapfileurl = 'http://www.pythontest.net/unicode/CP949.TXT' > > > > > > > > > class TestEUCKRMap(test_multibytecodec_support.TestBase_Mapping, > > > unittest.TestCase): > > > encoding = 'euc_kr' > > > - mapfileurl = 'http://people.freebsd.org/~perky/i18n/EUC-KR.TXT' > > > + mapfileurl = 'http://www.pythontest.net/unicode/EUC-KR.TXT' > > > > > > # A4D4 HANGUL FILLER indicates the begin of 8-bytes make-up > sequence. > > > pass_enctest = [('\xa4\xd4', u'\u3164')] > > > @@ -27,8 +26,7 @@ > > > class TestJOHABMap(test_multibytecodec_support.TestBase_Mapping, > > > unittest.TestCase): > > > encoding = 'johab' > > > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/OBSOLETE/ > > > EASTASIA/' \ > > > - 'KSC/JOHAB.TXT' > > > + mapfileurl = 'http://www.pythontest.net/unicode/JOHAB.TXT' > > > # KS X 1001 standard assigned 0x5c as WON SIGN. > > > # but, in early 90s that is the only era used johab widely, > > > # the most softwares implements it as REVERSE SOLIDUS. > > > 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 > > > @@ -10,14 +10,12 @@ > > > class TestBIG5Map(test_multibytecodec_support.TestBase_Mapping, > > > unittest.TestCase): > > > encoding = 'big5' > > > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/OBSOLETE/' \ > > > - 'EASTASIA/OTHER/BIG5.TXT' > > > + mapfileurl = 'http://www.pythontest.net/unicode/BIG5.TXT' > > > > > > class TestCP950Map(test_multibytecodec_support.TestBase_Mapping, > > > unittest.TestCase): > > > encoding = 'cp950' > > > - mapfileurl = 'http://www.unicode.org/Public/MAPPINGS/VENDORS/ > MICSFT/' > > > \ > > > - 'WINDOWS/CP950.TXT' > > > + mapfileurl = 'http://www.pythontest.net/unicode/CP950.TXT' > > > pass_enctest = [ > > > ('\xa2\xcc', u'\u5341'), > > > ('\xa2\xce', u'\u5345'), > > > diff --git a/Lib/test/test_normalization.py > b/Lib/test/test_normalization. > > > py > > > --- a/Lib/test/test_normalization.py > > > +++ b/Lib/test/test_normalization.py > > > @@ -7,7 +7,7 @@ > > > from unicodedata import normalize, unidata_version > > > > > > TESTDATAFILE = "NormalizationTest.txt" > > > -TESTDATAURL = "http://www.unicode.org/Public/" + unidata_version + > > > "/ucd/" + TESTDATAFILE > > > +TESTDATAURL = "http://www.pythontest.net/unicode/" + unidata_version > + > > > "/" + TESTDATAFILE > > > > > > def check_version(testfile): > > > hdr = testfile.readline() > > > > > > -- > > > Repository URL: https://hg.python.org/cpython > > > _______________________________________________ > > > Python-checkins mailing list > > > Python-checkins at python.org > > > https://mail.python.org/mailman/listinfo/python-checkins > > > > > _______________________________________________ > > Python-checkins mailing list > > Python-checkins at python.org > > https://mail.python.org/mailman/listinfo/python-checkins > _______________________________________________ > 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 benjamin at python.org Thu Nov 6 17:56:31 2014 From: benjamin at python.org (Benjamin Peterson) Date: Thu, 06 Nov 2014 11:56:31 -0500 Subject: [Python-checkins] [Python-Dev] cpython (2.7): #22650: test suite: load Unicode test data files from www.pythontest.net In-Reply-To: References: <20141106135652.108375.20457@psf.io> <1415284910.3978287.187837097.131F9A4E@webmail.messagingengine.com> Message-ID: <1415292991.4007266.187895233.3A8B1517@webmail.messagingengine.com> On Thu, Nov 6, 2014, at 10:41, Brett Cannon wrote: > Ah, cool! Just an FYI, the index.html file is not being served for me. At the moment it's only served on www. From solipsis at pitrou.net Fri Nov 7 10:22:52 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 07 Nov 2014 10:22:52 +0100 Subject: [Python-checkins] Daily reference leaks (a688d3206646): sum=3 Message-ID: results for a688d3206646 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogbqyikb', '-x'] From python-checkins at python.org Fri Nov 7 11:12:38 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Nov 2014 10:12:38 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogSXNzdWUgIzIyNzY5OiBGaXhlZCB0dGsuVHJlZXZpZXcudGFnX2hhcygp?= =?utf-8?q?_when_called_without_arguments=2E?= Message-ID: <20141107101238.85210.46022@psf.io> https://hg.python.org/cpython/rev/0b56adcb737d changeset: 93423:0b56adcb737d parent: 93420:a688d3206646 parent: 93422:cd17aa63492e user: Serhiy Storchaka date: Fri Nov 07 12:03:09 2014 +0200 summary: Issue #22769: Fixed ttk.Treeview.tag_has() when called without arguments. files: Lib/tkinter/test/test_ttk/test_widgets.py | 17 ++++++++++- Lib/tkinter/ttk.py | 6 +++- Misc/NEWS | 2 + 3 files changed, 23 insertions(+), 2 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 @@ -1,6 +1,6 @@ import unittest import tkinter -from tkinter import ttk +from tkinter import ttk, TclError from test.support import requires import sys @@ -1563,6 +1563,21 @@ 'blue') self.assertIsInstance(self.tv.tag_configure('test'), dict) + def test_tag_has(self): + item1 = self.tv.insert('', 'end', text='Item 1', tags=['tag1']) + item2 = self.tv.insert('', 'end', text='Item 2', tags=['tag2']) + self.assertRaises(TypeError, self.tv.tag_has) + self.assertRaises(TclError, self.tv.tag_has, 'tag1', 'non-existing') + self.assertTrue(self.tv.tag_has('tag1', item1)) + self.assertFalse(self.tv.tag_has('tag1', item2)) + self.assertFalse(self.tv.tag_has('tag2', item1)) + self.assertTrue(self.tv.tag_has('tag2', item2)) + self.assertFalse(self.tv.tag_has('tag3', item1)) + self.assertFalse(self.tv.tag_has('tag3', item2)) + self.assertEqual(self.tv.tag_has('tag1'), (item1,)) + self.assertEqual(self.tv.tag_has('tag2'), (item2,)) + self.assertEqual(self.tv.tag_has('tag3'), ()) + @add_standard_options(StandardTtkOptionsTests) class SeparatorTest(AbstractWidgetTest, unittest.TestCase): diff --git a/Lib/tkinter/ttk.py b/Lib/tkinter/ttk.py --- a/Lib/tkinter/ttk.py +++ b/Lib/tkinter/ttk.py @@ -1456,7 +1456,11 @@ all items which have the specified tag. * Availability: Tk 8.6""" - return self.tk.getboolean( + if item is None: + return self.tk.splitlist( + self.tk.call(self._w, "tag", "has", tagname)) + else: + return self.tk.getboolean( self.tk.call(self._w, "tag", "has", tagname, item)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -183,6 +183,8 @@ Library ------- +- Issue #22769: Fixed ttk.Treeview.tag_has() when called without arguments. + - Issue #22417: Verify certificates by default in httplib (PEP 476). - Issue #22775: Fixed unpickling of http.cookies.SimpleCookie with protocol 2 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 7 11:12:37 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Nov 2014 10:12:37 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIyNzY5?= =?utf-8?q?=3A_Fixed_ttk=2ETreeview=2Etag=5Fhas=28=29_when_called_without_?= =?utf-8?q?arguments=2E?= Message-ID: <20141107101237.113474.24233@psf.io> https://hg.python.org/cpython/rev/b3a5b53173c0 changeset: 93421:b3a5b53173c0 branch: 2.7 parent: 93418:14a69e40dbb0 user: Serhiy Storchaka date: Fri Nov 07 12:02:11 2014 +0200 summary: Issue #22769: Fixed ttk.Treeview.tag_has() when called without arguments. files: Lib/lib-tk/test/test_ttk/test_widgets.py | 16 ++++++++++++ Lib/lib-tk/ttk.py | 6 +++- Misc/NEWS | 2 + 3 files changed, 23 insertions(+), 1 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 @@ -1,5 +1,6 @@ import unittest import Tkinter as tkinter +from Tkinter import TclError import ttk from test.test_support import requires, run_unittest import sys @@ -1564,6 +1565,21 @@ 'blue') self.assertIsInstance(self.tv.tag_configure('test'), dict) + def test_tag_has(self): + item1 = self.tv.insert('', 'end', text='Item 1', tags=['tag1']) + item2 = self.tv.insert('', 'end', text='Item 2', tags=['tag2']) + self.assertRaises(TypeError, self.tv.tag_has) + self.assertRaises(TclError, self.tv.tag_has, 'tag1', 'non-existing') + self.assertTrue(self.tv.tag_has('tag1', item1)) + self.assertFalse(self.tv.tag_has('tag1', item2)) + self.assertFalse(self.tv.tag_has('tag2', item1)) + self.assertTrue(self.tv.tag_has('tag2', item2)) + self.assertFalse(self.tv.tag_has('tag3', item1)) + self.assertFalse(self.tv.tag_has('tag3', item2)) + self.assertEqual(self.tv.tag_has('tag1'), (item1,)) + self.assertEqual(self.tv.tag_has('tag2'), (item2,)) + self.assertEqual(self.tv.tag_has('tag3'), ()) + @add_standard_options(StandardTtkOptionsTests) class SeparatorTest(AbstractWidgetTest, unittest.TestCase): 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 @@ -1458,7 +1458,11 @@ all items which have the specified tag. * Availability: Tk 8.6""" - return self.tk.getboolean( + if item is None: + return self.tk.splitlist( + self.tk.call(self._w, "tag", "has", tagname)) + else: + return self.tk.getboolean( self.tk.call(self._w, "tag", "has", tagname, item)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,6 +37,8 @@ Library ------- +- Issue #22769: Fixed ttk.Treeview.tag_has() when called without arguments. + - Issue #22787: Allow the keyfile argument of SSLContext.load_cert_chain to be None. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 7 11:12:38 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Nov 2014 10:12:38 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyNzY5?= =?utf-8?q?=3A_Fixed_ttk=2ETreeview=2Etag=5Fhas=28=29_when_called_without_?= =?utf-8?q?arguments=2E?= Message-ID: <20141107101237.713.97497@psf.io> https://hg.python.org/cpython/rev/cd17aa63492e changeset: 93422:cd17aa63492e branch: 3.4 parent: 93419:540b022ae7a9 user: Serhiy Storchaka date: Fri Nov 07 12:02:31 2014 +0200 summary: Issue #22769: Fixed ttk.Treeview.tag_has() when called without arguments. files: Lib/tkinter/test/test_ttk/test_widgets.py | 17 ++++++++++- Lib/tkinter/ttk.py | 6 +++- Misc/NEWS | 2 + 3 files changed, 23 insertions(+), 2 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 @@ -1,6 +1,6 @@ import unittest import tkinter -from tkinter import ttk +from tkinter import ttk, TclError from test.support import requires import sys @@ -1563,6 +1563,21 @@ 'blue') self.assertIsInstance(self.tv.tag_configure('test'), dict) + def test_tag_has(self): + item1 = self.tv.insert('', 'end', text='Item 1', tags=['tag1']) + item2 = self.tv.insert('', 'end', text='Item 2', tags=['tag2']) + self.assertRaises(TypeError, self.tv.tag_has) + self.assertRaises(TclError, self.tv.tag_has, 'tag1', 'non-existing') + self.assertTrue(self.tv.tag_has('tag1', item1)) + self.assertFalse(self.tv.tag_has('tag1', item2)) + self.assertFalse(self.tv.tag_has('tag2', item1)) + self.assertTrue(self.tv.tag_has('tag2', item2)) + self.assertFalse(self.tv.tag_has('tag3', item1)) + self.assertFalse(self.tv.tag_has('tag3', item2)) + self.assertEqual(self.tv.tag_has('tag1'), (item1,)) + self.assertEqual(self.tv.tag_has('tag2'), (item2,)) + self.assertEqual(self.tv.tag_has('tag3'), ()) + @add_standard_options(StandardTtkOptionsTests) class SeparatorTest(AbstractWidgetTest, unittest.TestCase): diff --git a/Lib/tkinter/ttk.py b/Lib/tkinter/ttk.py --- a/Lib/tkinter/ttk.py +++ b/Lib/tkinter/ttk.py @@ -1456,7 +1456,11 @@ all items which have the specified tag. * Availability: Tk 8.6""" - return self.tk.getboolean( + if item is None: + return self.tk.splitlist( + self.tk.call(self._w, "tag", "has", tagname)) + else: + return self.tk.getboolean( self.tk.call(self._w, "tag", "has", tagname, item)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,8 @@ Library ------- +- Issue #22769: Fixed ttk.Treeview.tag_has() when called without arguments. + - Issue #22417: Verify certificates by default in httplib (PEP 476). - Issue #22775: Fixed unpickling of http.cookies.SimpleCookie with protocol 2 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 7 11:27:22 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Nov 2014 10:27:22 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3Mjkz?= =?utf-8?q?=3A_uuid=2Egetnode=28=29_now_determines_MAC_address_on_AIX_usin?= =?utf-8?q?g_netstat=2E?= Message-ID: <20141107102720.85196.62034@psf.io> https://hg.python.org/cpython/rev/e80cb046e764 changeset: 93424:e80cb046e764 branch: 2.7 parent: 93421:b3a5b53173c0 user: Serhiy Storchaka date: Fri Nov 07 12:19:23 2014 +0200 summary: Issue #17293: uuid.getnode() now determines MAC address on AIX using netstat. Based on patch by Aivars Kalv?ns. files: Lib/test/test_uuid.py | 18 ++++++++ Lib/uuid.py | 68 ++++++++++++++++++++++-------- Misc/NEWS | 3 + 3 files changed, 71 insertions(+), 18 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 @@ -307,6 +307,24 @@ if node is not None: self.check_node(node, 'ifconfig') + @unittest.skipUnless(os.name == 'posix', 'requires Posix') + def test_arp_getnode(self): + node = uuid._arp_getnode() + if node is not None: + self.check_node(node, 'arp') + + @unittest.skipUnless(os.name == 'posix', 'requires Posix') + def test_lanscan_getnode(self): + node = uuid._lanscan_getnode() + if node is not None: + self.check_node(node, 'lanscan') + + @unittest.skipUnless(os.name == 'posix', 'requires Posix') + def test_netstat_getnode(self): + node = uuid._netstat_getnode() + if node is not None: + self.check_node(node, 'netstat') + @unittest.skipUnless(os.name == 'nt', 'requires Windows') def test_ipconfig_getnode(self): node = uuid._ipconfig_getnode() diff --git a/Lib/uuid.py b/Lib/uuid.py --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -291,7 +291,7 @@ version = property(get_version) -def _find_mac(command, args, hw_identifiers, get_index): +def _popen(command, args): import os path = os.environ.get("PATH", os.defpath).split(os.pathsep) path.extend(('/sbin', '/usr/sbin')) @@ -303,19 +303,27 @@ break else: return None + # 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) + return os.popen(cmd) +def _find_mac(command, args, hw_identifiers, get_index): try: - # LC_ALL to ensure English output, 2>/dev/null to - # prevent output on stderr - cmd = 'LC_ALL=C %s %s 2>/dev/null' % (executable, args) - with os.popen(cmd) as pipe: + pipe = _popen(command, args) + if not pipe: + return + with pipe: for line in pipe: - words = line.lower().split() + words = line.lower().rstrip().split() for i in range(len(words)): if words[i] in hw_identifiers: try: - return int( - words[get_index(i)].replace(':', ''), 16) + word = words[get_index(i)] + mac = int(word.replace(':', ''), 16) + if mac: + return mac except (ValueError, IndexError): # Virtual interfaces, such as those provided by # VPNs, do not have a colon-delimited MAC address @@ -328,27 +336,50 @@ def _ifconfig_getnode(): """Get the hardware address on Unix by running ifconfig.""" - # This works on Linux ('' or '-a'), Tru64 ('-av'), but not all Unixes. for args in ('', '-a', '-av'): mac = _find_mac('ifconfig', args, ['hwaddr', 'ether'], lambda i: i+1) if mac: return mac - import socket +def _arp_getnode(): + """Get the hardware address on Unix by running arp.""" + import os, socket ip_addr = socket.gethostbyname(socket.gethostname()) # Try getting the MAC addr from arp based on our IP address (Solaris). - mac = _find_mac('arp', '-an', [ip_addr], lambda i: -1) - if mac: - return mac + return _find_mac('arp', '-an', [ip_addr], lambda i: -1) +def _lanscan_getnode(): + """Get the hardware address on Unix by running lanscan.""" # This might work on HP-UX. - mac = _find_mac('lanscan', '-ai', ['lan0'], lambda i: 0) - if mac: - return mac + return _find_mac('lanscan', '-ai', ['lan0'], lambda i: 0) - return None +def _netstat_getnode(): + """Get the hardware address on Unix by running netstat.""" + # This might work on AIX, Tru64 UNIX and presumably on IRIX. + try: + pipe = _popen('netstat', '-ia') + if not pipe: + return + with pipe: + words = pipe.readline().rstrip().split() + try: + i = words.index('Address') + except ValueError: + return + for line in pipe: + try: + words = line.rstrip().split() + word = words[i] + if len(word) == 17 and word.count(':') == 5: + mac = int(word.replace(':', ''), 16) + if mac: + return mac + except (ValueError, IndexError): + pass + except OSError: + pass def _ipconfig_getnode(): """Get the hardware address on Windows by running ipconfig.exe.""" @@ -488,7 +519,8 @@ if sys.platform == 'win32': getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode] else: - getters = [_unixdll_getnode, _ifconfig_getnode] + getters = [_unixdll_getnode, _ifconfig_getnode, _arp_getnode, + _lanscan_getnode, _netstat_getnode] for getter in getters + [_random_getnode]: try: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,6 +37,9 @@ Library ------- +- Issue #17293: uuid.getnode() now determines MAC address on AIX using netstat. + Based on patch by Aivars Kalv?ns. + - Issue #22769: Fixed ttk.Treeview.tag_has() when called without arguments. - Issue #22787: Allow the keyfile argument of SSLContext.load_cert_chain to be -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 7 11:27:22 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Nov 2014 10:27:22 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzE3Mjkz?= =?utf-8?q?=3A_uuid=2Egetnode=28=29_now_determines_MAC_address_on_AIX_usin?= =?utf-8?q?g_netstat=2E?= Message-ID: <20141107102720.108381.11741@psf.io> https://hg.python.org/cpython/rev/ba4b31ed2952 changeset: 93425:ba4b31ed2952 branch: 3.4 parent: 93422:cd17aa63492e user: Serhiy Storchaka date: Fri Nov 07 12:19:40 2014 +0200 summary: Issue #17293: uuid.getnode() now determines MAC address on AIX using netstat. Based on patch by Aivars Kalv?ns. files: Lib/test/test_uuid.py | 18 ++++++++ Lib/uuid.py | 69 ++++++++++++++++++++++-------- Misc/NEWS | 3 + 3 files changed, 71 insertions(+), 19 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 @@ -319,6 +319,24 @@ if node is not None: self.check_node(node, 'ifconfig') + @unittest.skipUnless(os.name == 'posix', 'requires Posix') + def test_arp_getnode(self): + node = uuid._arp_getnode() + if node is not None: + self.check_node(node, 'arp') + + @unittest.skipUnless(os.name == 'posix', 'requires Posix') + def test_lanscan_getnode(self): + node = uuid._lanscan_getnode() + if node is not None: + self.check_node(node, 'lanscan') + + @unittest.skipUnless(os.name == 'posix', 'requires Posix') + def test_netstat_getnode(self): + node = uuid._netstat_getnode() + if node is not None: + self.check_node(node, 'netstat') + @unittest.skipUnless(os.name == 'nt', 'requires Windows') def test_ipconfig_getnode(self): node = uuid._ipconfig_getnode() diff --git a/Lib/uuid.py b/Lib/uuid.py --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -311,7 +311,7 @@ if self.variant == RFC_4122: return int((self.int >> 76) & 0xf) -def _find_mac(command, args, hw_identifiers, get_index): +def _popen(command, args): import os, shutil executable = shutil.which(command) if executable is None: @@ -319,20 +319,27 @@ executable = shutil.which(command, path=path) if executable is None: return None + # 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) + return os.popen(cmd) +def _find_mac(command, args, hw_identifiers, get_index): try: - # 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: + pipe = _popen(command, args) + if not pipe: + return + with pipe: for line in pipe: - words = line.lower().split() + words = line.lower().rstrip().split() for i in range(len(words)): if words[i] in hw_identifiers: try: - return int( - words[get_index(i)].replace(':', ''), 16) + word = words[get_index(i)] + mac = int(word.replace(':', ''), 16) + if mac: + return mac except (ValueError, IndexError): # Virtual interfaces, such as those provided by # VPNs, do not have a colon-delimited MAC address @@ -345,27 +352,50 @@ def _ifconfig_getnode(): """Get the hardware address on Unix by running ifconfig.""" - # This works on Linux ('' or '-a'), Tru64 ('-av'), but not all Unixes. for args in ('', '-a', '-av'): mac = _find_mac('ifconfig', args, ['hwaddr', 'ether'], lambda i: i+1) if mac: return mac - import socket +def _arp_getnode(): + """Get the hardware address on Unix by running arp.""" + import os, socket ip_addr = socket.gethostbyname(socket.gethostname()) # Try getting the MAC addr from arp based on our IP address (Solaris). - mac = _find_mac('arp', '-an', [ip_addr], lambda i: -1) - if mac: - return mac + return _find_mac('arp', '-an', [ip_addr], lambda i: -1) +def _lanscan_getnode(): + """Get the hardware address on Unix by running lanscan.""" # This might work on HP-UX. - mac = _find_mac('lanscan', '-ai', ['lan0'], lambda i: 0) - if mac: - return mac + return _find_mac('lanscan', '-ai', ['lan0'], lambda i: 0) - return None +def _netstat_getnode(): + """Get the hardware address on Unix by running netstat.""" + # This might work on AIX, Tru64 UNIX and presumably on IRIX. + try: + pipe = _popen('netstat', '-ia') + if not pipe: + return + with pipe: + words = pipe.readline().rstrip().split() + try: + i = words.index('Address') + except ValueError: + return + for line in pipe: + try: + words = line.rstrip().split() + word = words[i] + if len(word) == 17 and word.count(':') == 5: + mac = int(word.replace(':', ''), 16) + if mac: + return mac + except (ValueError, IndexError): + pass + except OSError: + pass def _ipconfig_getnode(): """Get the hardware address on Windows by running ipconfig.exe.""" @@ -506,7 +536,8 @@ if sys.platform == 'win32': getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode] else: - getters = [_unixdll_getnode, _ifconfig_getnode] + getters = [_unixdll_getnode, _ifconfig_getnode, _arp_getnode, + _lanscan_getnode, _netstat_getnode] for getter in getters + [_random_getnode]: try: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,9 @@ Library ------- +- Issue #17293: uuid.getnode() now determines MAC address on AIX using netstat. + Based on patch by Aivars Kalv?ns. + - Issue #22769: Fixed ttk.Treeview.tag_has() when called without arguments. - Issue #22417: Verify certificates by default in httplib (PEP 476). -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 7 11:27:22 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Nov 2014 10:27:22 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317293=3A_uuid=2Egetnode=28=29_now_determines_MA?= =?utf-8?q?C_address_on_AIX_using_netstat=2E?= Message-ID: <20141107102720.731.88914@psf.io> https://hg.python.org/cpython/rev/3e4f3cc4f1f9 changeset: 93426:3e4f3cc4f1f9 parent: 93423:0b56adcb737d parent: 93425:ba4b31ed2952 user: Serhiy Storchaka date: Fri Nov 07 12:23:30 2014 +0200 summary: Issue #17293: uuid.getnode() now determines MAC address on AIX using netstat. Based on patch by Aivars Kalv?ns. files: Lib/test/test_uuid.py | 20 +++++++- Lib/uuid.py | 81 ++++++++++++++++++++---------- Misc/NEWS | 3 + 3 files changed, 76 insertions(+), 28 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 @@ -320,6 +320,24 @@ if node is not None: self.check_node(node, 'ifconfig') + @unittest.skipUnless(os.name == 'posix', 'requires Posix') + def test_arp_getnode(self): + node = uuid._arp_getnode() + if node is not None: + self.check_node(node, 'arp') + + @unittest.skipUnless(os.name == 'posix', 'requires Posix') + def test_lanscan_getnode(self): + node = uuid._lanscan_getnode() + if node is not None: + self.check_node(node, 'lanscan') + + @unittest.skipUnless(os.name == 'posix', 'requires Posix') + def test_netstat_getnode(self): + node = uuid._netstat_getnode() + if node is not None: + self.check_node(node, 'netstat') + @unittest.skipUnless(os.name == 'nt', 'requires Windows') def test_ipconfig_getnode(self): node = uuid._ipconfig_getnode() @@ -377,7 +395,7 @@ return_value=popen): mac = uuid._find_mac( command='ifconfig', - arg='', + args='', hw_identifiers=[b'hwaddr'], get_index=lambda x: x + 1, ) diff --git a/Lib/uuid.py b/Lib/uuid.py --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -304,7 +304,7 @@ if self.variant == RFC_4122: return int((self.int >> 76) & 0xf) -def _find_mac(command, arg, hw_identifiers, get_index): +def _popen(command, *args): import os, shutil, subprocess executable = shutil.which(command) if executable is None: @@ -312,28 +312,32 @@ executable = shutil.which(command, path=path) if executable is None: return None + # LC_ALL=C to ensure English output, stderr=DEVNULL 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.) + env = dict(os.environ) + env['LC_ALL'] = 'C' + proc = subprocess.Popen((executable,) + args, + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + env=env) + return proc +def _find_mac(command, args, hw_identifiers, get_index): try: - # LC_ALL=C to ensure English output, stderr=DEVNULL 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.) - env = dict(os.environ) - env['LC_ALL'] = 'C' - cmd = [executable] - if arg: - cmd.append(arg) - proc = subprocess.Popen(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.DEVNULL, - env=env) + proc = _popen(command, *args.split()) + if not proc: + return with proc: for line in proc.stdout: - words = line.lower().split() + words = line.lower().rstrip().split() for i in range(len(words)): if words[i] in hw_identifiers: try: - return int( - words[get_index(i)].replace(b':', b''), 16) + word = words[get_index(i)] + mac = int(word.replace(b':', b''), 16) + if mac: + return mac except (ValueError, IndexError): # Virtual interfaces, such as those provided by # VPNs, do not have a colon-delimited MAC address @@ -346,28 +350,50 @@ def _ifconfig_getnode(): """Get the hardware address on Unix by running ifconfig.""" - import os - # This works on Linux ('' or '-a'), Tru64 ('-av'), but not all Unixes. for args in ('', '-a', '-av'): mac = _find_mac('ifconfig', args, [b'hwaddr', b'ether'], lambda i: i+1) if mac: return mac - import socket +def _arp_getnode(): + """Get the hardware address on Unix by running arp.""" + import os, socket ip_addr = socket.gethostbyname(socket.gethostname()) # Try getting the MAC addr from arp based on our IP address (Solaris). - mac = _find_mac('arp', '-an', [os.fsencode(ip_addr)], lambda i: -1) - if mac: - return mac + return _find_mac('arp', '-an', [os.fsencode(ip_addr)], lambda i: -1) +def _lanscan_getnode(): + """Get the hardware address on Unix by running lanscan.""" # This might work on HP-UX. - mac = _find_mac('lanscan', '-ai', [b'lan0'], lambda i: 0) - if mac: - return mac + return _find_mac('lanscan', '-ai', [b'lan0'], lambda i: 0) - return None +def _netstat_getnode(): + """Get the hardware address on Unix by running netstat.""" + # This might work on AIX, Tru64 UNIX and presumably on IRIX. + try: + proc = _popen('netstat', '-ia') + if not proc: + return + with proc: + words = proc.stdout.readline().rstrip().split() + try: + i = words.index(b'Address') + except ValueError: + return + for line in proc.stdout: + try: + words = line.rstrip().split() + word = words[i] + if len(word) == 17 and word.count(b':') == 5: + mac = int(word.replace(b':', b''), 16) + if mac: + return mac + except (ValueError, IndexError): + pass + except OSError: + pass def _ipconfig_getnode(): """Get the hardware address on Windows by running ipconfig.exe.""" @@ -509,7 +535,8 @@ if sys.platform == 'win32': getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode] else: - getters = [_unixdll_getnode, _ifconfig_getnode] + getters = [_unixdll_getnode, _ifconfig_getnode, _arp_getnode, + _lanscan_getnode, _netstat_getnode] for getter in getters + [_random_getnode]: try: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -183,6 +183,9 @@ Library ------- +- Issue #17293: uuid.getnode() now determines MAC address on AIX using netstat. + Based on patch by Aivars Kalv?ns. + - Issue #22769: Fixed ttk.Treeview.tag_has() when called without arguments. - Issue #22417: Verify certificates by default in httplib (PEP 476). -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 7 13:12:47 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Nov 2014 12:12:47 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyNDA2?= =?utf-8?q?=3A_Fixed_the_uu=5Fcodec_codec_incorrectly_ported_to_3=2Ex=2E?= Message-ID: <20141107121243.85202.47710@psf.io> https://hg.python.org/cpython/rev/ad89a652b4ed changeset: 93427:ad89a652b4ed branch: 3.4 parent: 93425:ba4b31ed2952 user: Serhiy Storchaka date: Fri Nov 07 14:04:37 2014 +0200 summary: Issue #22406: Fixed the uu_codec codec incorrectly ported to 3.x. Based on patch by Martin Panter. files: Lib/encodings/uu_codec.py | 2 +- Lib/test/test_codecs.py | 4 ++++ Lib/test/test_uu.py | 22 ++++++++++++++++++++++ Misc/NEWS | 3 +++ 4 files changed, 30 insertions(+), 1 deletions(-) diff --git a/Lib/encodings/uu_codec.py b/Lib/encodings/uu_codec.py --- a/Lib/encodings/uu_codec.py +++ b/Lib/encodings/uu_codec.py @@ -54,7 +54,7 @@ data = binascii.a2b_uu(s) except binascii.Error as v: # Workaround for broken uuencoders by /Fredrik Lundh - nbytes = (((ord(s[0])-32) & 63) * 4 + 5) / 3 + nbytes = (((s[0]-32) & 63) * 4 + 5) // 3 data = binascii.a2b_uu(s[:nbytes]) #sys.stderr.write("Warning: %s\n" % str(v)) write(data) 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 @@ -2563,6 +2563,10 @@ info = codecs.lookup(alias) self.assertEqual(info.name, expected_name) + def test_uu_invalid(self): + # Missing "begin" line + self.assertRaises(ValueError, codecs.decode, b"", "uu-codec") + # The codec system tries to wrap exceptions in order to ensure the error # mentions the operation being performed and the codec involved. We diff --git a/Lib/test/test_uu.py b/Lib/test/test_uu.py --- a/Lib/test/test_uu.py +++ b/Lib/test/test_uu.py @@ -93,6 +93,28 @@ except uu.Error as e: self.assertEqual(str(e), "No valid begin line found in input file") + def test_garbage_padding(self): + # Issue #22406 + encodedtext = ( + b"begin 644 file\n" + # length 1; bits 001100 111111 111111 111111 + b"\x21\x2C\x5F\x5F\x5F\n" + b"\x20\n" + b"end\n" + ) + plaintext = b"\x33" # 00110011 + + with self.subTest("uu.decode()"): + inp = io.BytesIO(encodedtext) + out = io.BytesIO() + uu.decode(inp, out, quiet=True) + self.assertEqual(out.getvalue(), plaintext) + + with self.subTest("uu_codec"): + import codecs + decoded = codecs.decode(encodedtext, "uu_codec") + self.assertEqual(decoded, plaintext) + class UUStdIOTest(unittest.TestCase): def setUp(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,9 @@ Library ------- +- Issue #22406: Fixed the uu_codec codec incorrectly ported to 3.x. + Based on patch by Martin Panter. + - Issue #17293: uuid.getnode() now determines MAC address on AIX using netstat. Based on patch by Aivars Kalv?ns. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 7 13:12:47 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Nov 2014 12:12:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Backported_tes?= =?utf-8?q?ts_for_issue_=2322406=2E?= Message-ID: <20141107121244.113468.37884@psf.io> https://hg.python.org/cpython/rev/7b82b58b8329 changeset: 93429:7b82b58b8329 branch: 2.7 parent: 93424:e80cb046e764 user: Serhiy Storchaka date: Fri Nov 07 14:07:43 2014 +0200 summary: Backported tests for issue #22406. files: Lib/test/test_codecs.py | 4 ++++ Lib/test/test_uu.py | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 0 deletions(-) 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 @@ -2109,6 +2109,10 @@ BomTest, ) + def test_uu_invalid(self): + # Missing "begin" line + self.assertRaises(ValueError, codecs.decode, "", "uu-codec") + if __name__ == "__main__": test_main() diff --git a/Lib/test/test_uu.py b/Lib/test/test_uu.py --- a/Lib/test/test_uu.py +++ b/Lib/test/test_uu.py @@ -61,6 +61,26 @@ except uu.Error, e: self.assertEqual(str(e), "No valid begin line found in input file") + def test_garbage_padding(self): + # Issue #22406 + encodedtext = ( + "begin 644 file\n" + # length 1; bits 001100 111111 111111 111111 + "\x21\x2C\x5F\x5F\x5F\n" + "\x20\n" + "end\n" + ) + plaintext = "\x33" # 00110011 + + inp = cStringIO.StringIO(encodedtext) + out = cStringIO.StringIO() + uu.decode(inp, out, quiet=True) + self.assertEqual(out.getvalue(), plaintext) + + import codecs + decoded = codecs.decode(encodedtext, "uu_codec") + self.assertEqual(decoded, plaintext) + class UUStdIOTest(unittest.TestCase): def setUp(self): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 7 13:12:47 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Nov 2014 12:12:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322406=3A_Fixed_the_uu=5Fcodec_codec_incorrectly?= =?utf-8?q?_ported_to_3=2Ex=2E?= Message-ID: <20141107121244.108375.25405@psf.io> https://hg.python.org/cpython/rev/b18ef4a3e7c1 changeset: 93428:b18ef4a3e7c1 parent: 93426:3e4f3cc4f1f9 parent: 93427:ad89a652b4ed user: Serhiy Storchaka date: Fri Nov 07 14:06:19 2014 +0200 summary: Issue #22406: Fixed the uu_codec codec incorrectly ported to 3.x. Based on patch by Martin Panter. files: Lib/encodings/uu_codec.py | 2 +- Lib/test/test_codecs.py | 4 ++++ Lib/test/test_uu.py | 22 ++++++++++++++++++++++ Misc/NEWS | 3 +++ 4 files changed, 30 insertions(+), 1 deletions(-) diff --git a/Lib/encodings/uu_codec.py b/Lib/encodings/uu_codec.py --- a/Lib/encodings/uu_codec.py +++ b/Lib/encodings/uu_codec.py @@ -54,7 +54,7 @@ data = binascii.a2b_uu(s) except binascii.Error as v: # Workaround for broken uuencoders by /Fredrik Lundh - nbytes = (((ord(s[0])-32) & 63) * 4 + 5) / 3 + nbytes = (((s[0]-32) & 63) * 4 + 5) // 3 data = binascii.a2b_uu(s[:nbytes]) #sys.stderr.write("Warning: %s\n" % str(v)) write(data) 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 @@ -2571,6 +2571,10 @@ info = codecs.lookup(alias) self.assertEqual(info.name, expected_name) + def test_uu_invalid(self): + # Missing "begin" line + self.assertRaises(ValueError, codecs.decode, b"", "uu-codec") + # The codec system tries to wrap exceptions in order to ensure the error # mentions the operation being performed and the codec involved. We diff --git a/Lib/test/test_uu.py b/Lib/test/test_uu.py --- a/Lib/test/test_uu.py +++ b/Lib/test/test_uu.py @@ -93,6 +93,28 @@ except uu.Error as e: self.assertEqual(str(e), "No valid begin line found in input file") + def test_garbage_padding(self): + # Issue #22406 + encodedtext = ( + b"begin 644 file\n" + # length 1; bits 001100 111111 111111 111111 + b"\x21\x2C\x5F\x5F\x5F\n" + b"\x20\n" + b"end\n" + ) + plaintext = b"\x33" # 00110011 + + with self.subTest("uu.decode()"): + inp = io.BytesIO(encodedtext) + out = io.BytesIO() + uu.decode(inp, out, quiet=True) + self.assertEqual(out.getvalue(), plaintext) + + with self.subTest("uu_codec"): + import codecs + decoded = codecs.decode(encodedtext, "uu_codec") + self.assertEqual(decoded, plaintext) + class UUStdIOTest(unittest.TestCase): def setUp(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -183,6 +183,9 @@ Library ------- +- Issue #22406: Fixed the uu_codec codec incorrectly ported to 3.x. + Based on patch by Martin Panter. + - Issue #17293: uuid.getnode() now determines MAC address on AIX using netstat. Based on patch by Aivars Kalv?ns. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 7 15:56:22 2014 From: python-checkins at python.org (brett.cannon) Date: Fri, 07 Nov 2014 14:56:22 +0000 Subject: [Python-checkins] =?utf-8?q?pythontestdotnet=3A_Link_to_the_hg_re?= =?utf-8?q?po_and_Salt_config?= Message-ID: <20141107145614.108375.81360@psf.io> https://hg.python.org/pythontestdotnet/rev/b51c46800184 changeset: 5:b51c46800184 user: Brett Cannon date: Fri Nov 07 09:56:11 2014 -0500 summary: Link to the hg repo and Salt config files: www/index.html | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/www/index.html b/www/index.html --- a/www/index.html +++ b/www/index.html @@ -6,5 +6,10 @@ This domain is used to host various services contacted by the Python test suite. + All content is managed through + + a Mercurial repository and its configuration is + + managed through Salt. -- Repository URL: https://hg.python.org/pythontestdotnet From python-checkins at python.org Fri Nov 7 17:29:44 2014 From: python-checkins at python.org (brett.cannon) Date: Fri, 07 Nov 2014 16:29:44 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322242=3A_Try_to_m?= =?utf-8?q?ake_some_import-related_loader_details_clearer=2E?= Message-ID: <20141107162942.731.21157@psf.io> https://hg.python.org/cpython/rev/f473063318c3 changeset: 93430:f473063318c3 parent: 93428:b18ef4a3e7c1 user: Brett Cannon date: Fri Nov 07 11:29:33 2014 -0500 summary: Issue #22242: Try to make some import-related loader details clearer. Thanks to Jon Poler for pointing this out. files: Doc/reference/import.rst | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -459,7 +459,8 @@ * If loading fails, the loader must remove any modules it has inserted into :data:`sys.modules`, but it must remove **only** the failing - module, and only if the loader itself has loaded it explicitly. + module(s), and only if the loader itself has loaded the module(s) + explicitly. Module spec ----------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 7 18:51:31 2014 From: python-checkins at python.org (berker.peksag) Date: Fri, 07 Nov 2014 17:51:31 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322808=3A_Link_to_the_correct_time_method_in_Bas?= =?utf-8?b?ZUV2ZW50TG9vcC5jYWxsX2F0KCku?= Message-ID: <20141107175130.108071.25688@psf.io> https://hg.python.org/cpython/rev/98f4bc1332c9 changeset: 93432:98f4bc1332c9 parent: 93430:f473063318c3 parent: 93431:8b1d8fcb494b user: Berker Peksag date: Fri Nov 07 19:51:37 2014 +0200 summary: Issue #22808: Link to the correct time method in BaseEventLoop.call_at(). Patch by Mark Grandi. files: Doc/library/asyncio-eventloop.rst | 3 ++- 1 files changed, 2 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 @@ -121,7 +121,8 @@ .. method:: BaseEventLoop.call_at(when, callback, *args) Arrange for the *callback* to be called at the given absolute timestamp - *when* (an int or float), using the same time reference as :meth:`time`. + *when* (an int or float), using the same time reference as + :meth:`BaseEventLoop.time`. This method's behavior is the same as :meth:`call_later`. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 7 18:51:31 2014 From: python-checkins at python.org (berker.peksag) Date: Fri, 07 Nov 2014 17:51:31 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyODA4?= =?utf-8?q?=3A_Link_to_the_correct_time_method_in_BaseEventLoop=2Ecall=5Fa?= =?utf-8?b?dCgpLg==?= Message-ID: <20141107175130.108081.78582@psf.io> https://hg.python.org/cpython/rev/8b1d8fcb494b changeset: 93431:8b1d8fcb494b branch: 3.4 parent: 93427:ad89a652b4ed user: Berker Peksag date: Fri Nov 07 19:51:07 2014 +0200 summary: Issue #22808: Link to the correct time method in BaseEventLoop.call_at(). Patch by Mark Grandi. files: Doc/library/asyncio-eventloop.rst | 3 ++- 1 files changed, 2 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 @@ -121,7 +121,8 @@ .. method:: BaseEventLoop.call_at(when, callback, *args) Arrange for the *callback* to be called at the given absolute timestamp - *when* (an int or float), using the same time reference as :meth:`time`. + *when* (an int or float), using the same time reference as + :meth:`BaseEventLoop.time`. This method's behavior is the same as :meth:`call_later`. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 7 20:49:19 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Nov 2014 19:49:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issues_=23814253=2C_=239179=3A_Group_references_and_cond?= =?utf-8?q?itional_group_references_now?= Message-ID: <20141107194916.85210.99344@psf.io> https://hg.python.org/cpython/rev/60fccf0aad83 changeset: 93435:60fccf0aad83 parent: 93432:98f4bc1332c9 parent: 93434:9fcf4008b626 user: Serhiy Storchaka date: Fri Nov 07 21:45:17 2014 +0200 summary: Issues #814253, #9179: Group references and conditional group references now work in lookbehind assertions in regular expressions. files: Lib/re.py | 5 ++- Lib/sre_parse.py | 33 ++++++++++++++++++++------- Lib/test/test_re.py | 38 ++++++++++++++++++++++++++++++++- Misc/NEWS | 3 ++ 4 files changed, 67 insertions(+), 12 deletions(-) diff --git a/Lib/re.py b/Lib/re.py --- a/Lib/re.py +++ b/Lib/re.py @@ -351,10 +351,11 @@ s = sre_parse.Pattern() s.flags = flags for phrase, action in lexicon: + gid = s.opengroup() p.append(sre_parse.SubPattern(s, [ - (SUBPATTERN, (len(p)+1, sre_parse.parse(phrase, flags))), + (SUBPATTERN, (gid, sre_parse.parse(phrase, flags))), ])) - s.groups = len(p)+1 + s.closegroup(gid, p[-1]) p = sre_parse.SubPattern(s, [(BRANCH, (None, p))]) self.scanner = sre_compile.compile(p) def scan(self, string): diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -69,12 +69,14 @@ # master pattern object. keeps track of global attributes def __init__(self): self.flags = 0 - self.open = [] - self.groups = 1 self.groupdict = {} + self.subpatterns = [None] # group 0 + @property + def groups(self): + return len(self.subpatterns) def opengroup(self, name=None): gid = self.groups - self.groups = gid + 1 + self.subpatterns.append(None) if self.groups > MAXGROUPS: raise error("groups number is too large") if name is not None: @@ -83,12 +85,11 @@ raise error("redefinition of group name %s as group %d; " "was group %d" % (repr(name), gid, ogid)) self.groupdict[name] = gid - self.open.append(gid) return gid - def closegroup(self, gid): - self.open.remove(gid) + def closegroup(self, gid, p): + self.subpatterns[gid] = p def checkgroup(self, gid): - return gid < self.groups and gid not in self.open + return gid < self.groups and self.subpatterns[gid] is not None class SubPattern: # a subpattern, in intermediate form @@ -184,7 +185,21 @@ elif op in _UNITCODES: lo = lo + 1 hi = hi + 1 - elif op == SUCCESS: + elif op is GROUPREF: + i, j = self.pattern.subpatterns[av].getwidth() + lo = lo + i + hi = hi + j + elif op is GROUPREF_EXISTS: + i, j = av[1].getwidth() + if av[2] is not None: + l, h = av[2].getwidth() + i = min(i, l) + j = max(j, h) + else: + i = 0 + lo = lo + i + hi = hi + j + elif op is SUCCESS: break self.width = min(lo, MAXREPEAT - 1), min(hi, MAXREPEAT) return self.width @@ -705,7 +720,7 @@ if not sourcematch(")"): raise error("unbalanced parenthesis") if group is not None: - state.closegroup(group) + state.closegroup(group, p) subpatternappend((SUBPATTERN, (group, p))) else: while True: diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -575,7 +575,7 @@ self.assertEqual(re.match("a.*b", "a\n\nb", re.DOTALL).group(0), "a\n\nb") - def test_non_consuming(self): + def test_lookahead(self): self.assertEqual(re.match("(a(?=\s[^a]))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[^a]*))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[abc]))", "a b").group(1), "a") @@ -589,6 +589,42 @@ self.assertEqual(re.match(r"(a)(?!\s\1)", "a b").group(1), "a") self.assertEqual(re.match(r"(a)(?!\s(abc|a))", "a b").group(1), "a") + # Group reference. + self.assertTrue(re.match(r'(a)b(?=\1)a', 'aba')) + self.assertIsNone(re.match(r'(a)b(?=\1)c', 'abac')) + # Conditional group reference. + self.assertTrue(re.match('(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) + self.assertIsNone(re.match('(?:(a)|(x))b(?=(?(2)c|x))c', 'abc')) + self.assertTrue(re.match('(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) + self.assertIsNone(re.match('(?:(a)|(x))b(?=(?(1)b|x))c', 'abc')) + self.assertTrue(re.match('(?:(a)|(x))b(?=(?(1)c|x))c', 'abc')) + # Group used before defined. + self.assertTrue(re.match('(a)b(?=(?(2)x|c))(c)', 'abc')) + self.assertIsNone(re.match('(a)b(?=(?(2)b|x))(c)', 'abc')) + self.assertTrue(re.match('(a)b(?=(?(1)c|x))(c)', 'abc')) + + def test_lookbehind(self): + self.assertTrue(re.match('ab(?<=b)c', 'abc')) + self.assertIsNone(re.match('ab(?<=c)c', 'abc')) + self.assertIsNone(re.match('ab(? https://hg.python.org/cpython/rev/9fcf4008b626 changeset: 93434:9fcf4008b626 branch: 3.4 parent: 93431:8b1d8fcb494b user: Serhiy Storchaka date: Fri Nov 07 21:43:57 2014 +0200 summary: Issues #814253, #9179: Group references and conditional group references now work in lookbehind assertions in regular expressions. files: Lib/re.py | 5 ++- Lib/sre_parse.py | 33 ++++++++++++++++++++------- Lib/test/test_re.py | 38 ++++++++++++++++++++++++++++++++- Misc/NEWS | 3 ++ 4 files changed, 67 insertions(+), 12 deletions(-) diff --git a/Lib/re.py b/Lib/re.py --- a/Lib/re.py +++ b/Lib/re.py @@ -352,10 +352,11 @@ s = sre_parse.Pattern() s.flags = flags for phrase, action in lexicon: + gid = s.opengroup() p.append(sre_parse.SubPattern(s, [ - (SUBPATTERN, (len(p)+1, sre_parse.parse(phrase, flags))), + (SUBPATTERN, (gid, sre_parse.parse(phrase, flags))), ])) - s.groups = len(p)+1 + s.closegroup(gid, p[-1]) p = sre_parse.SubPattern(s, [(BRANCH, (None, p))]) self.scanner = sre_compile.compile(p) def scan(self, string): diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -66,24 +66,25 @@ # master pattern object. keeps track of global attributes def __init__(self): self.flags = 0 - self.open = [] - self.groups = 1 self.groupdict = {} + self.subpatterns = [None] # group 0 + @property + def groups(self): + return len(self.subpatterns) def opengroup(self, name=None): gid = self.groups - self.groups = gid + 1 + self.subpatterns.append(None) if name is not None: ogid = self.groupdict.get(name, None) if ogid is not None: raise error("redefinition of group name %s as group %d; " "was group %d" % (repr(name), gid, ogid)) self.groupdict[name] = gid - self.open.append(gid) return gid - def closegroup(self, gid): - self.open.remove(gid) + def closegroup(self, gid, p): + self.subpatterns[gid] = p def checkgroup(self, gid): - return gid < self.groups and gid not in self.open + return gid < self.groups and self.subpatterns[gid] is not None class SubPattern: # a subpattern, in intermediate form @@ -181,7 +182,21 @@ elif op in UNITCODES: lo = lo + 1 hi = hi + 1 - elif op == SUCCESS: + elif op is GROUPREF: + i, j = self.pattern.subpatterns[av].getwidth() + lo = lo + i + hi = hi + j + elif op is GROUPREF_EXISTS: + i, j = av[1].getwidth() + if av[2] is not None: + l, h = av[2].getwidth() + i = min(i, l) + j = max(j, h) + else: + i = 0 + lo = lo + i + hi = hi + j + elif op is SUCCESS: break self.width = min(lo, MAXREPEAT - 1), min(hi, MAXREPEAT) return self.width @@ -709,7 +724,7 @@ if not sourcematch(")"): raise error("unbalanced parenthesis") if group is not None: - state.closegroup(group) + state.closegroup(group, p) subpatternappend((SUBPATTERN, (group, p))) else: while 1: diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -557,7 +557,7 @@ self.assertEqual(re.match("a.*b", "a\n\nb", re.DOTALL).group(0), "a\n\nb") - def test_non_consuming(self): + def test_lookahead(self): self.assertEqual(re.match("(a(?=\s[^a]))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[^a]*))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[abc]))", "a b").group(1), "a") @@ -571,6 +571,42 @@ self.assertEqual(re.match(r"(a)(?!\s\1)", "a b").group(1), "a") self.assertEqual(re.match(r"(a)(?!\s(abc|a))", "a b").group(1), "a") + # Group reference. + self.assertTrue(re.match(r'(a)b(?=\1)a', 'aba')) + self.assertIsNone(re.match(r'(a)b(?=\1)c', 'abac')) + # Conditional group reference. + self.assertTrue(re.match('(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) + self.assertIsNone(re.match('(?:(a)|(x))b(?=(?(2)c|x))c', 'abc')) + self.assertTrue(re.match('(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) + self.assertIsNone(re.match('(?:(a)|(x))b(?=(?(1)b|x))c', 'abc')) + self.assertTrue(re.match('(?:(a)|(x))b(?=(?(1)c|x))c', 'abc')) + # Group used before defined. + self.assertTrue(re.match('(a)b(?=(?(2)x|c))(c)', 'abc')) + self.assertIsNone(re.match('(a)b(?=(?(2)b|x))(c)', 'abc')) + self.assertTrue(re.match('(a)b(?=(?(1)c|x))(c)', 'abc')) + + def test_lookbehind(self): + self.assertTrue(re.match('ab(?<=b)c', 'abc')) + self.assertIsNone(re.match('ab(?<=c)c', 'abc')) + self.assertIsNone(re.match('ab(? https://hg.python.org/cpython/rev/fac649bf2d10 changeset: 93433:fac649bf2d10 branch: 2.7 parent: 93429:7b82b58b8329 user: Serhiy Storchaka date: Fri Nov 07 21:43:45 2014 +0200 summary: Issues #814253, #9179: Group references and conditional group references now work in lookbehind assertions in regular expressions. files: Lib/re.py | 5 ++- Lib/sre_parse.py | 33 ++++++++++++++++++++------- Lib/test/test_re.py | 38 ++++++++++++++++++++++++++++++++- Misc/NEWS | 3 ++ 4 files changed, 67 insertions(+), 12 deletions(-) diff --git a/Lib/re.py b/Lib/re.py --- a/Lib/re.py +++ b/Lib/re.py @@ -312,10 +312,11 @@ s = sre_parse.Pattern() s.flags = flags for phrase, action in lexicon: + gid = s.opengroup() p.append(sre_parse.SubPattern(s, [ - (SUBPATTERN, (len(p)+1, sre_parse.parse(phrase, flags))), + (SUBPATTERN, (gid, sre_parse.parse(phrase, flags))), ])) - s.groups = len(p)+1 + s.closegroup(gid, p[-1]) p = sre_parse.SubPattern(s, [(BRANCH, (None, p))]) self.scanner = sre_compile.compile(p) def scan(self, string): diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -66,24 +66,25 @@ # master pattern object. keeps track of global attributes def __init__(self): self.flags = 0 - self.open = [] - self.groups = 1 self.groupdict = {} + self.subpatterns = [None] # group 0 + @property + def groups(self): + return len(self.subpatterns) def opengroup(self, name=None): gid = self.groups - self.groups = gid + 1 + self.subpatterns.append(None) if name is not None: ogid = self.groupdict.get(name, None) if ogid is not None: raise error, ("redefinition of group name %s as group %d; " "was group %d" % (repr(name), gid, ogid)) self.groupdict[name] = gid - self.open.append(gid) return gid - def closegroup(self, gid): - self.open.remove(gid) + def closegroup(self, gid, p): + self.subpatterns[gid] = p def checkgroup(self, gid): - return gid < self.groups and gid not in self.open + return gid < self.groups and self.subpatterns[gid] is not None class SubPattern: # a subpattern, in intermediate form @@ -178,7 +179,21 @@ elif op in UNITCODES: lo = lo + 1 hi = hi + 1 - elif op == SUCCESS: + elif op is GROUPREF: + i, j = self.pattern.subpatterns[av].getwidth() + lo = lo + i + hi = hi + j + elif op is GROUPREF_EXISTS: + i, j = av[1].getwidth() + if av[2] is not None: + l, h = av[2].getwidth() + i = min(i, l) + j = max(j, h) + else: + i = 0 + lo = lo + i + hi = hi + j + elif op is SUCCESS: break self.width = min(lo, MAXREPEAT - 1), min(hi, MAXREPEAT) return self.width @@ -657,7 +672,7 @@ if not sourcematch(")"): raise error, "unbalanced parenthesis" if group is not None: - state.closegroup(group) + state.closegroup(group, p) subpatternappend((SUBPATTERN, (group, p))) else: while 1: diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -448,7 +448,7 @@ self.assertEqual(re.match("a.*b", "a\n\nb", re.DOTALL).group(0), "a\n\nb") - def test_non_consuming(self): + def test_lookahead(self): self.assertEqual(re.match("(a(?=\s[^a]))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[^a]*))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[abc]))", "a b").group(1), "a") @@ -462,6 +462,42 @@ self.assertEqual(re.match(r"(a)(?!\s\1)", "a b").group(1), "a") self.assertEqual(re.match(r"(a)(?!\s(abc|a))", "a b").group(1), "a") + # Group reference. + self.assertTrue(re.match(r'(a)b(?=\1)a', 'aba')) + self.assertIsNone(re.match(r'(a)b(?=\1)c', 'abac')) + # Conditional group reference. + self.assertTrue(re.match('(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) + self.assertIsNone(re.match('(?:(a)|(x))b(?=(?(2)c|x))c', 'abc')) + self.assertTrue(re.match('(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) + self.assertIsNone(re.match('(?:(a)|(x))b(?=(?(1)b|x))c', 'abc')) + self.assertTrue(re.match('(?:(a)|(x))b(?=(?(1)c|x))c', 'abc')) + # Group used before defined. + self.assertTrue(re.match('(a)b(?=(?(2)x|c))(c)', 'abc')) + self.assertIsNone(re.match('(a)b(?=(?(2)b|x))(c)', 'abc')) + self.assertTrue(re.match('(a)b(?=(?(1)c|x))(c)', 'abc')) + + def test_lookbehind(self): + self.assertTrue(re.match('ab(?<=b)c', 'abc')) + self.assertIsNone(re.match('ab(?<=c)c', 'abc')) + self.assertIsNone(re.match('ab(? https://hg.python.org/cpython/rev/0e2c7d774df3 changeset: 93436:0e2c7d774df3 branch: 2.7 parent: 93433:fac649bf2d10 user: Serhiy Storchaka date: Fri Nov 07 22:31:54 2014 +0200 summary: Silence the failure of test_pyclbr after adding a property in sre_parse (issue #814253). files: Lib/test/test_pyclbr.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py --- a/Lib/test/test_pyclbr.py +++ b/Lib/test/test_pyclbr.py @@ -180,7 +180,7 @@ cm('pickle') cm('aifc', ignore=('openfp',)) # set with = in module cm('Cookie') - cm('sre_parse', ignore=('dump',)) # from sre_constants import * + cm('sre_parse', ignore=('dump', 'groups')) # from sre_constants import *; property cm('pdb') cm('pydoc') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 7 21:37:07 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Nov 2014 20:37:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Silence_the_fa?= =?utf-8?q?ilure_of_test=5Fpyclbr_after_adding_a_property_in_sre=5Fparse?= Message-ID: <20141107203701.113478.34289@psf.io> https://hg.python.org/cpython/rev/246c9570a757 changeset: 93437:246c9570a757 branch: 3.4 parent: 93434:9fcf4008b626 user: Serhiy Storchaka date: Fri Nov 07 22:32:37 2014 +0200 summary: Silence the failure of test_pyclbr after adding a property in sre_parse (issue #814253). files: Lib/test/test_pyclbr.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py --- a/Lib/test/test_pyclbr.py +++ b/Lib/test/test_pyclbr.py @@ -159,7 +159,7 @@ cm('cgi', ignore=('log',)) # set with = in module cm('pickle') cm('aifc', ignore=('openfp', '_aifc_params')) # set with = in module - cm('sre_parse', ignore=('dump',)) # from sre_constants import * + cm('sre_parse', ignore=('dump', 'groups')) # from sre_constants import *; property cm('pdb') cm('pydoc') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 7 21:37:07 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 07 Nov 2014 20:37:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Silence_the_failure_of_test=5Fpyclbr_after_adding_a_prop?= =?utf-8?q?erty_in_sre=5Fparse?= Message-ID: <20141107203701.108085.59089@psf.io> https://hg.python.org/cpython/rev/b2c17681404f changeset: 93438:b2c17681404f parent: 93435:60fccf0aad83 parent: 93437:246c9570a757 user: Serhiy Storchaka date: Fri Nov 07 22:33:19 2014 +0200 summary: Silence the failure of test_pyclbr after adding a property in sre_parse (issue #814253). files: Lib/test/test_pyclbr.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py --- a/Lib/test/test_pyclbr.py +++ b/Lib/test/test_pyclbr.py @@ -159,7 +159,7 @@ cm('cgi', ignore=('log',)) # set with = in module cm('pickle') cm('aifc', ignore=('openfp', '_aifc_params')) # set with = in module - cm('sre_parse', ignore=('dump',)) # from sre_constants import * + cm('sre_parse', ignore=('dump', 'groups')) # from sre_constants import *; property cm('pdb') cm('pydoc') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 8 07:47:38 2014 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 08 Nov 2014 06:47:38 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Remove_unused_?= =?utf-8?q?import?= Message-ID: <20141108064736.713.24362@psf.io> https://hg.python.org/cpython/rev/1cde2bbe841a changeset: 93439:1cde2bbe841a branch: 2.7 parent: 93436:0e2c7d774df3 user: Raymond Hettinger date: Fri Nov 07 22:47:30 2014 -0800 summary: Remove unused import files: Lib/decimal.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Lib/decimal.py b/Lib/decimal.py --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -136,7 +136,6 @@ __version__ = '1.70' # Highest version of the spec this complies with -import copy as _copy import math as _math import numbers as _numbers -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Sat Nov 8 10:33:05 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 08 Nov 2014 10:33:05 +0100 Subject: [Python-checkins] Daily reference leaks (b2c17681404f): sum=3 Message-ID: results for b2c17681404f on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog8Jo34A', '-x'] From python-checkins at python.org Sat Nov 8 21:40:49 2014 From: python-checkins at python.org (berker.peksag) Date: Sat, 08 Nov 2014 20:40:49 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyNjk1?= =?utf-8?q?=3A_Fix_rendering_of_the_deprecated-removed_role_in_HTML=2E?= Message-ID: <20141108204048.108095.70866@psf.io> https://hg.python.org/cpython/rev/9001298e3094 changeset: 93440:9001298e3094 branch: 3.4 parent: 93437:246c9570a757 user: Berker Peksag date: Sat Nov 08 22:40:22 2014 +0200 summary: Issue #22695: Fix rendering of the deprecated-removed role in HTML. files: Doc/tools/extensions/pyspecific.py | 10 ++++------ 1 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -172,22 +172,20 @@ 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'])) + node[0].insert(0, nodes.inline('', '%s: ' % text, + classes=['versionmodified'])) else: para = nodes.paragraph('', '', nodes.inline('', '%s.' % text, classes=['versionmodified'])) - if len(node): - node.insert(0, para) - else: - node.append(para) + node.append(para) env = self.state.document.settings.env env.note_versionchange('deprecated', version[0], node, self.lineno) return [node] + messages -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 8 21:40:51 2014 From: python-checkins at python.org (berker.peksag) Date: Sat, 08 Nov 2014 20:40:51 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322695=3A_Fix_rendering_of_the_deprecated-remove?= =?utf-8?q?d_role_in_HTML=2E?= Message-ID: <20141108204048.108087.12693@psf.io> https://hg.python.org/cpython/rev/ec81edc30221 changeset: 93441:ec81edc30221 parent: 93438:b2c17681404f parent: 93440:9001298e3094 user: Berker Peksag date: Sat Nov 08 22:41:00 2014 +0200 summary: Issue #22695: Fix rendering of the deprecated-removed role in HTML. files: Doc/tools/extensions/pyspecific.py | 10 ++++------ 1 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -172,22 +172,20 @@ 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'])) + node[0].insert(0, nodes.inline('', '%s: ' % text, + classes=['versionmodified'])) else: para = nodes.paragraph('', '', nodes.inline('', '%s.' % text, classes=['versionmodified'])) - if len(node): - node.insert(0, para) - else: - node.append(para) + node.append(para) env = self.state.document.settings.env env.note_versionchange('deprecated', version[0], node, self.lineno) return [node] + messages -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Sun Nov 9 10:32:20 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 09 Nov 2014 10:32:20 +0100 Subject: [Python-checkins] Daily reference leaks (ec81edc30221): sum=3 Message-ID: results for ec81edc30221 on branch "default" -------------------------------------------- test_collections leaked [-2, 0, 2] references, sum=0 test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogXcGGjL', '-x'] From ncoghlan at gmail.com Sun Nov 9 13:44:27 2014 From: ncoghlan at gmail.com (Nick Coghlan) Date: Sun, 9 Nov 2014 22:44:27 +1000 Subject: [Python-checkins] cpython (2.7): #22650: test suite: load Unicode test data files from www.pythontest.net In-Reply-To: References: <20141106135652.108375.20457@psf.io> Message-ID: On 7 Nov 2014 02:44, "Georg Brandl" wrote: > > On 11/06/2014 03:39 PM, Brett Cannon wrote: > > What is pythontest.net ? Is it something we control, and > > if so how do we add things to it for tests? Did I miss an email on python-dev or > > python-committers about this? > > Benjamin already gave the link to the related issue. The idea is to make the > networking tests depend on as few external hosts as possible, so that we can > reduce spurious skips or failures when one of them is not reachable or changes > its configuration. > > The pythontest.net domain was chosen to be able to test things like cookies or > certificates without a potential of compromising python.org related services. > > There is a repository at hg.python.org/pythontestdotnet which can be used by > developers; server configuration is maintained together with other Python > services on https://github.com/python/psf-salt. Thanks for the info! Could we capture that somewhere a bit more permanent? The developer guide would probably be a good place, although it may involve creating a new subsection. Cheers, Nick. > > cheers, > Georg > > _______________________________________________ > 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 Nov 10 00:56:39 2014 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 09 Nov 2014 23:56:39 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322823=3A_Use_set_?= =?utf-8?q?literals_instead_of_creating_a_set_from_a_list?= Message-ID: <20141109235639.108385.96711@psf.io> https://hg.python.org/cpython/rev/4480506137ed changeset: 93442:4480506137ed user: Raymond Hettinger date: Sun Nov 09 15:56:33 2014 -0800 summary: Issue #22823: Use set literals instead of creating a set from a list files: Doc/howto/logging-cookbook.rst | 2 +- Doc/library/pickle.rst | 2 +- Lib/_strptime.py | 4 ++-- Lib/asyncore.py | 6 +++--- Lib/ipaddress.py | 2 +- Lib/mailbox.py | 4 ++-- Lib/sre_compile.py | 8 ++++---- Lib/sre_parse.py | 4 ++-- Lib/statistics.py | 4 ++-- Parser/asdl.py | 3 +-- 10 files changed, 19 insertions(+), 20 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 @@ -1680,7 +1680,7 @@ def main(): logging.basicConfig(level=logging.INFO, format='%(message)s') - logging.info(_('message 1', set_value=set([1, 2, 3]), snowman='\u2603')) + logging.info(_('message 1', set_value={1, 2, 3}, snowman='\u2603')) if __name__ == '__main__': main() diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -859,7 +859,7 @@ data = { 'a': [1, 2.0, 3, 4+6j], 'b': ("character string", b"byte string"), - 'c': set([None, True, False]) + 'c': {None, True, False} } with open('data.pickle', 'wb') as f: diff --git a/Lib/_strptime.py b/Lib/_strptime.py --- a/Lib/_strptime.py +++ b/Lib/_strptime.py @@ -167,9 +167,9 @@ time.tzset() except AttributeError: pass - no_saving = frozenset(["utc", "gmt", time.tzname[0].lower()]) + no_saving = frozenset({"utc", "gmt", time.tzname[0].lower()}) if time.daylight: - has_saving = frozenset([time.tzname[1].lower()]) + has_saving = frozenset({time.tzname[1].lower()}) else: has_saving = frozenset() self.timezone = (no_saving, has_saving) diff --git a/Lib/asyncore.py b/Lib/asyncore.py --- a/Lib/asyncore.py +++ b/Lib/asyncore.py @@ -57,8 +57,8 @@ ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \ errorcode -_DISCONNECTED = frozenset((ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, - EBADF)) +_DISCONNECTED = frozenset({ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, + EBADF}) try: socket_map @@ -220,7 +220,7 @@ connecting = False closing = False addr = None - ignore_log_types = frozenset(['warning']) + ignore_log_types = frozenset({'warning'}) def __init__(self, sock=None, map=None): if map is None: diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1088,7 +1088,7 @@ _DECIMAL_DIGITS = frozenset('0123456789') # the valid octets for host and netmasks. only useful for IPv4. - _valid_mask_octets = frozenset((255, 254, 252, 248, 240, 224, 192, 128, 0)) + _valid_mask_octets = frozenset({255, 254, 252, 248, 240, 224, 192, 128, 0}) _max_prefixlen = IPV4LENGTH # There are only a handful of valid v4 netmasks, so we cache them all diff --git a/Lib/mailbox.py b/Lib/mailbox.py --- a/Lib/mailbox.py +++ b/Lib/mailbox.py @@ -1230,8 +1230,8 @@ class Babyl(_singlefileMailbox): """An Rmail-style Babyl mailbox.""" - _special_labels = frozenset(('unseen', 'deleted', 'filed', 'answered', - 'forwarded', 'edited', 'resent')) + _special_labels = frozenset({'unseen', 'deleted', 'filed', 'answered', + 'forwarded', 'edited', 'resent'}) def __init__(self, path, factory=None, create=True): """Initialize a Babyl mailbox.""" diff --git a/Lib/sre_compile.py b/Lib/sre_compile.py --- a/Lib/sre_compile.py +++ b/Lib/sre_compile.py @@ -22,10 +22,10 @@ else: MAXCODE = 0xFFFFFFFF -_LITERAL_CODES = set([LITERAL, NOT_LITERAL]) -_REPEATING_CODES = set([REPEAT, MIN_REPEAT, MAX_REPEAT]) -_SUCCESS_CODES = set([SUCCESS, FAILURE]) -_ASSERT_CODES = set([ASSERT, ASSERT_NOT]) +_LITERAL_CODES = {LITERAL, NOT_LITERAL} +_REPEATING_CODES = {REPEAT, MIN_REPEAT, MAX_REPEAT} +_SUCCESS_CODES = {SUCCESS, FAILURE} +_ASSERT_CODES = {ASSERT, ASSERT_NOT} def _compile(code, pattern, flags): # internal: compile a (sub)pattern diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -25,8 +25,8 @@ WHITESPACE = frozenset(" \t\n\r\v\f") -_REPEATCODES = frozenset((MIN_REPEAT, MAX_REPEAT)) -_UNITCODES = frozenset((ANY, RANGE, IN, LITERAL, NOT_LITERAL, CATEGORY)) +_REPEATCODES = frozenset({MIN_REPEAT, MAX_REPEAT}) +_UNITCODES = frozenset({ANY, RANGE, IN, LITERAL, NOT_LITERAL, CATEGORY}) ESCAPES = { r"\a": (LITERAL, ord("\a")), diff --git a/Lib/statistics.py b/Lib/statistics.py --- a/Lib/statistics.py +++ b/Lib/statistics.py @@ -150,7 +150,7 @@ # We fail as soon as we reach a value that is not an int or the type of # the first value which is not an int. E.g. _sum([int, int, float, int]) # is okay, but sum([int, int, float, Fraction]) is not. - allowed_types = set([int, type(start)]) + allowed_types = {int, type(start)} n, d = _exact_ratio(start) partials = {d: n} # map {denominator: sum of numerators} # Micro-optimizations. @@ -168,7 +168,7 @@ assert allowed_types.pop() is int T = int else: - T = (allowed_types - set([int])).pop() + T = (allowed_types - {int}).pop() if None in partials: assert issubclass(T, (float, Decimal)) assert not math.isfinite(partials[None]) diff --git a/Parser/asdl.py b/Parser/asdl.py --- a/Parser/asdl.py +++ b/Parser/asdl.py @@ -33,8 +33,7 @@ # See the EBNF at the top of the file to understand the logical connection # between the various node types. -builtin_types = set( - ['identifier', 'string', 'bytes', 'int', 'object', 'singleton']) +builtin_types = {'identifier', 'string', 'bytes', 'int', 'object', 'singleton'} class AST: def __repr__(self): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 02:10:32 2014 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 10 Nov 2014 01:10:32 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgMjI4MzA6?= =?utf-8?q?__Clarify_docs_for_functools=2Ecmp=5Fto=5Fkey=28=29=2E?= Message-ID: <20141110011027.108377.83502@psf.io> https://hg.python.org/cpython/rev/dbe1744ec62e changeset: 93443:dbe1744ec62e branch: 2.7 parent: 93439:1cde2bbe841a user: Raymond Hettinger date: Sun Nov 09 17:10:17 2014 -0800 summary: Issue 22830: Clarify docs for functools.cmp_to_key(). files: Doc/library/functools.rst | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -22,8 +22,8 @@ .. function:: cmp_to_key(func) - Transform an old-style comparison function to a key function. Used with - tools that accept key functions (such as :func:`sorted`, :func:`min`, + Transform an old-style comparison function to a :term:`key function`. Used + with tools that accept key functions (such as :func:`sorted`, :func:`min`, :func:`max`, :func:`heapq.nlargest`, :func:`heapq.nsmallest`, :func:`itertools.groupby`). This function is primarily used as a transition tool for programs being converted to Python 3 where comparison functions are @@ -32,13 +32,16 @@ A comparison function is any callable that accept two arguments, compares them, and returns a negative number for less-than, zero for equality, or a positive number for greater-than. A key function is a callable that accepts one - argument and returns another value that indicates the position in the desired - collation sequence. + argument and returns another value to be used as the sort key. Example:: sorted(iterable, key=cmp_to_key(locale.strcoll)) # locale-aware sort order + For sorting examples and a brief sorting tutorial, see `Sorting HowTo + `_\. + + .. versionadded:: 2.7 .. function:: total_ordering(cls) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 02:21:33 2014 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 10 Nov 2014 01:21:33 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgMjI4MzA6?= =?utf-8?q?__Clarify_docs_for_functools=2Ecmp=5Fto=5Fkey=28=29=2E?= Message-ID: <20141110012129.108101.79727@psf.io> https://hg.python.org/cpython/rev/63274cf1b40d changeset: 93444:63274cf1b40d branch: 3.4 parent: 93440:9001298e3094 user: Raymond Hettinger date: Sun Nov 09 17:20:56 2014 -0800 summary: Issue 22830: Clarify docs for functools.cmp_to_key(). files: Doc/library/functools.rst | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -21,8 +21,8 @@ .. function:: cmp_to_key(func) - Transform an old-style comparison function to a key function. Used with - tools that accept key functions (such as :func:`sorted`, :func:`min`, + Transform an old-style comparison function to a :term:`key function`. Used + with tools that accept key functions (such as :func:`sorted`, :func:`min`, :func:`max`, :func:`heapq.nlargest`, :func:`heapq.nsmallest`, :func:`itertools.groupby`). This function is primarily used as a transition tool for programs being converted from Python 2 which supported the use of @@ -31,13 +31,14 @@ A comparison function is any callable that accept two arguments, compares them, and returns a negative number for less-than, zero for equality, or a positive number for greater-than. A key function is a callable that accepts one - argument and returns another value indicating the position in the desired - collation sequence. + argument and returns another value to be used as the sort key. Example:: sorted(iterable, key=cmp_to_key(locale.strcoll)) # locale-aware sort order + For sorting examples and a brief sorting tutorial, see :ref:`sortinghowto`. + .. versionadded:: 3.2 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 02:21:33 2014 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 10 Nov 2014 01:21:33 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <20141110012129.113464.72926@psf.io> https://hg.python.org/cpython/rev/0c34a2532e31 changeset: 93445:0c34a2532e31 parent: 93442:4480506137ed parent: 93444:63274cf1b40d user: Raymond Hettinger date: Sun Nov 09 17:21:20 2014 -0800 summary: merge files: Doc/library/functools.rst | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -21,8 +21,8 @@ .. function:: cmp_to_key(func) - Transform an old-style comparison function to a key function. Used with - tools that accept key functions (such as :func:`sorted`, :func:`min`, + Transform an old-style comparison function to a :term:`key function`. Used + with tools that accept key functions (such as :func:`sorted`, :func:`min`, :func:`max`, :func:`heapq.nlargest`, :func:`heapq.nsmallest`, :func:`itertools.groupby`). This function is primarily used as a transition tool for programs being converted from Python 2 which supported the use of @@ -31,13 +31,14 @@ A comparison function is any callable that accept two arguments, compares them, and returns a negative number for less-than, zero for equality, or a positive number for greater-than. A key function is a callable that accepts one - argument and returns another value indicating the position in the desired - collation sequence. + argument and returns another value to be used as the sort key. Example:: sorted(iterable, key=cmp_to_key(locale.strcoll)) # locale-aware sort order + For sorting examples and a brief sorting tutorial, see :ref:`sortinghowto`. + .. versionadded:: 3.2 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 02:23:00 2014 From: python-checkins at python.org (brett.cannon) Date: Mon, 10 Nov 2014 01:23:00 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_default?= Message-ID: <20141110012300.108395.24581@psf.io> https://hg.python.org/cpython/rev/55b89e5f9c37 changeset: 93447:55b89e5f9c37 parent: 93446:6e6532d313a1 parent: 93445:0c34a2532e31 user: Brett Cannon date: Sun Nov 09 20:22:53 2014 -0500 summary: Merge with default files: Doc/library/functools.rst | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -21,8 +21,8 @@ .. function:: cmp_to_key(func) - Transform an old-style comparison function to a key function. Used with - tools that accept key functions (such as :func:`sorted`, :func:`min`, + Transform an old-style comparison function to a :term:`key function`. Used + with tools that accept key functions (such as :func:`sorted`, :func:`min`, :func:`max`, :func:`heapq.nlargest`, :func:`heapq.nsmallest`, :func:`itertools.groupby`). This function is primarily used as a transition tool for programs being converted from Python 2 which supported the use of @@ -31,13 +31,14 @@ A comparison function is any callable that accept two arguments, compares them, and returns a negative number for less-than, zero for equality, or a positive number for greater-than. A key function is a callable that accepts one - argument and returns another value indicating the position in the desired - collation sequence. + argument and returns another value to be used as the sort key. Example:: sorted(iterable, key=cmp_to_key(locale.strcoll)) # locale-aware sort order + For sorting examples and a brief sorting tutorial, see :ref:`sortinghowto`. + .. versionadded:: 3.2 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 02:23:00 2014 From: python-checkins at python.org (brett.cannon) Date: Mon, 10 Nov 2014 01:23:00 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_20152=2C_22821=3A_Po?= =?utf-8?q?rt_the_fcntl_module_to_Argument_Clinic=2E?= Message-ID: <20141110012300.108381.39051@psf.io> https://hg.python.org/cpython/rev/6e6532d313a1 changeset: 93446:6e6532d313a1 parent: 93442:4480506137ed user: Brett Cannon date: Sun Nov 09 20:22:01 2014 -0500 summary: Issue 20152, 22821: Port the fcntl module to Argument Clinic. Along the way, fix an argumrnt to fcntl.fcntl to be an int instead of a long. Thanks to Serhiy Storchaka for reviewing my Clinic patch and for writing the patch to fix the long/int issue. files: Modules/clinic/fcntlmodule.c.h | 188 +++++++++ Modules/fcntlmodule.c | 432 ++++++++++---------- 2 files changed, 413 insertions(+), 207 deletions(-) diff --git a/Modules/clinic/fcntlmodule.c.h b/Modules/clinic/fcntlmodule.c.h new file mode 100644 --- /dev/null +++ b/Modules/clinic/fcntlmodule.c.h @@ -0,0 +1,188 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(fcntl_fcntl__doc__, +"fcntl($module, fd, code, arg=None, /)\n" +"--\n" +"\n" +"Perform the operation `code` on file descriptor fd.\n" +"\n" +"The values used for `code` are operating system dependent, and are available\n" +"as constants in the fcntl module, using the same names as used in\n" +"the relevant C header files. The argument arg is optional, and\n" +"defaults to 0; it may be an int or a string. If arg is given as a string,\n" +"the return value of fcntl is a string of that length, containing the\n" +"resulting value put in the arg buffer by the operating system. The length\n" +"of the arg string is not allowed to exceed 1024 bytes. If the arg given\n" +"is an integer or if none is specified, the result value is an integer\n" +"corresponding to the return value of the fcntl call in the C code."); + +#define FCNTL_FCNTL_METHODDEF \ + {"fcntl", (PyCFunction)fcntl_fcntl, METH_VARARGS, fcntl_fcntl__doc__}, + +static PyObject * +fcntl_fcntl_impl(PyModuleDef *module, int fd, int code, PyObject *arg); + +static PyObject * +fcntl_fcntl(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + int fd; + int code; + PyObject *arg = NULL; + + if (!PyArg_ParseTuple(args, + "O&i|O:fcntl", + conv_descriptor, &fd, &code, &arg)) + goto exit; + return_value = fcntl_fcntl_impl(module, fd, code, arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(fcntl_ioctl__doc__, +"ioctl($module, fd, op, arg=None, mutate_flag=True, /)\n" +"--\n" +"\n" +"Perform the operation op on file descriptor fd.\n" +"\n" +"The values used for op are operating system dependent, and are available as\n" +"constants in the fcntl or termios library modules, using the same names as\n" +"used in the relevant C header files.\n" +"\n" +"The argument `arg` is optional, and defaults to 0; it may be an int or a\n" +"buffer containing character data (most likely a string or an array).\n" +"\n" +"If the argument is a mutable buffer (such as an array) and if the\n" +"mutate_flag argument (which is only allowed in this case) is true then the\n" +"buffer is (in effect) passed to the operating system and changes made by\n" +"the OS will be reflected in the contents of the buffer after the call has\n" +"returned. The return value is the integer returned by the ioctl system\n" +"call.\n" +"\n" +"If the argument is a mutable buffer and the mutable_flag argument is not\n" +"passed or is false, the behavior is as if a string had been passed. This\n" +"behavior will change in future releases of Python.\n" +"\n" +"If the argument is an immutable buffer (most likely a string) then a copy\n" +"of the buffer is passed to the operating system and the return value is a\n" +"string of the same length containing whatever the operating system put in\n" +"the buffer. The length of the arg buffer in this case is not allowed to\n" +"exceed 1024 bytes.\n" +"\n" +"If the arg given is an integer or if none is specified, the result value is\n" +"an integer corresponding to the return value of the ioctl call in the C\n" +"code."); + +#define FCNTL_IOCTL_METHODDEF \ + {"ioctl", (PyCFunction)fcntl_ioctl, METH_VARARGS, fcntl_ioctl__doc__}, + +static PyObject * +fcntl_ioctl_impl(PyModuleDef *module, int fd, unsigned int code, PyObject *ob_arg, int mutate_arg); + +static PyObject * +fcntl_ioctl(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + int fd; + unsigned int code; + PyObject *ob_arg = NULL; + int mutate_arg = 1; + + if (!PyArg_ParseTuple(args, + "O&I|Op:ioctl", + conv_descriptor, &fd, &code, &ob_arg, &mutate_arg)) + goto exit; + return_value = fcntl_ioctl_impl(module, fd, code, ob_arg, mutate_arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(fcntl_flock__doc__, +"flock($module, fd, code, /)\n" +"--\n" +"\n" +"Perform the lock operation op on file descriptor fd.\n" +"\n" +"See the Unix manual page for flock(2) for details (On some systems, this\n" +"function is emulated using fcntl())."); + +#define FCNTL_FLOCK_METHODDEF \ + {"flock", (PyCFunction)fcntl_flock, METH_VARARGS, fcntl_flock__doc__}, + +static PyObject * +fcntl_flock_impl(PyModuleDef *module, int fd, int code); + +static PyObject * +fcntl_flock(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + int fd; + int code; + + if (!PyArg_ParseTuple(args, + "O&i:flock", + conv_descriptor, &fd, &code)) + goto exit; + return_value = fcntl_flock_impl(module, fd, code); + +exit: + return return_value; +} + +PyDoc_STRVAR(fcntl_lockf__doc__, +"lockf($module, fd, code, lenobj=None, startobj=None, whence=0, /)\n" +"--\n" +"\n" +"A wrapper around the fcntl() locking calls.\n" +"\n" +"fd is the file descriptor of the file to lock or unlock, and operation is one\n" +"of the following values:\n" +"\n" +" LOCK_UN - unlock\n" +" LOCK_SH - acquire a shared lock\n" +" LOCK_EX - acquire an exclusive lock\n" +"\n" +"When operation is LOCK_SH or LOCK_EX, it can also be bitwise ORed with\n" +"LOCK_NB to avoid blocking on lock acquisition. If LOCK_NB is used and the\n" +"lock cannot be acquired, an IOError will be raised and the exception will\n" +"have an errno attribute set to EACCES or EAGAIN (depending on the operating\n" +"system -- for portability, check for either value).\n" +"\n" +"length is the number of bytes to lock, with the default meaning to lock to\n" +"EOF. start is the byte offset, relative to whence, to that the lock\n" +"starts. whence is as with fileobj.seek(), specifically:\n" +"\n" +" 0 - relative to the start of the file (SEEK_SET)\n" +" 1 - relative to the current buffer position (SEEK_CUR)\n" +" 2 - relative to the end of the file (SEEK_END)"); + +#define FCNTL_LOCKF_METHODDEF \ + {"lockf", (PyCFunction)fcntl_lockf, METH_VARARGS, fcntl_lockf__doc__}, + +static PyObject * +fcntl_lockf_impl(PyModuleDef *module, int fd, int code, PyObject *lenobj, PyObject *startobj, int whence); + +static PyObject * +fcntl_lockf(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + int fd; + int code; + PyObject *lenobj = NULL; + PyObject *startobj = NULL; + int whence = 0; + + if (!PyArg_ParseTuple(args, + "O&i|OOi:lockf", + conv_descriptor, &fd, &code, &lenobj, &startobj, &whence)) + goto exit; + return_value = fcntl_lockf_impl(module, fd, code, lenobj, startobj, whence); + +exit: + return return_value; +} +/*[clinic end generated code: output=84bdde73a92f7c61 input=a9049054013a1b77]*/ diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c --- a/Modules/fcntlmodule.c +++ b/Modules/fcntlmodule.c @@ -15,6 +15,12 @@ #include #endif +/*[clinic input] +output preset file +module fcntl +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c7356fdb126a904a]*/ + static int conv_descriptor(PyObject *object, int *target) { @@ -26,48 +32,72 @@ return 1; } +/* Must come after conv_descriptor definition. */ +#include "clinic/fcntlmodule.c.h" -/* fcntl(fd, op, [arg]) */ +/*[clinic input] +fcntl.fcntl + + fd: object(type='int', converter='conv_descriptor') + code: int + arg: object = NULL + / + +Perform the operation `code` on file descriptor fd. + +The values used for `code` are operating system dependent, and are available +as constants in the fcntl module, using the same names as used in +the relevant C header files. The argument arg is optional, and +defaults to 0; it may be an int or a string. If arg is given as a string, +the return value of fcntl is a string of that length, containing the +resulting value put in the arg buffer by the operating system. The length +of the arg string is not allowed to exceed 1024 bytes. If the arg given +is an integer or if none is specified, the result value is an integer +corresponding to the return value of the fcntl call in the C code. +[clinic start generated code]*/ static PyObject * -fcntl_fcntl(PyObject *self, PyObject *args) +fcntl_fcntl_impl(PyModuleDef *module, int fd, int code, PyObject *arg) +/*[clinic end generated code: output=afc5bfa74a03ef0d input=4850c13a41e86930]*/ { - int fd; - int code; - long arg; + int int_arg = 0; int ret; char *str; Py_ssize_t len; char buf[1024]; - if (PyArg_ParseTuple(args, "O&is#:fcntl", - conv_descriptor, &fd, &code, &str, &len)) { - if ((size_t)len > sizeof buf) { - PyErr_SetString(PyExc_ValueError, - "fcntl string arg too long"); - return NULL; + if (arg != NULL) { + int parse_result; + + if (PyArg_Parse(arg, "s#", &str, &len)) { + if ((size_t)len > sizeof buf) { + PyErr_SetString(PyExc_ValueError, + "fcntl string arg too long"); + return NULL; + } + memcpy(buf, str, len); + Py_BEGIN_ALLOW_THREADS + ret = fcntl(fd, code, buf); + Py_END_ALLOW_THREADS + if (ret < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + return PyBytes_FromStringAndSize(buf, len); } - memcpy(buf, str, len); - Py_BEGIN_ALLOW_THREADS - ret = fcntl(fd, code, buf); - Py_END_ALLOW_THREADS - if (ret < 0) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; + + PyErr_Clear(); + parse_result = PyArg_Parse(arg, + "l;fcntl requires a file or file descriptor," + " an integer and optionally a third integer or a string", + &int_arg); + if (!parse_result) { + return NULL; } - return PyBytes_FromStringAndSize(buf, len); } - PyErr_Clear(); - arg = 0; - if (!PyArg_ParseTuple(args, - "O&i|l;fcntl requires a file or file descriptor," - " an integer and optionally a third integer or a string", - conv_descriptor, &fd, &code, &arg)) { - return NULL; - } Py_BEGIN_ALLOW_THREADS - ret = fcntl(fd, code, arg); + ret = fcntl(fd, code, int_arg); Py_END_ALLOW_THREADS if (ret < 0) { PyErr_SetFromErrno(PyExc_IOError); @@ -76,29 +106,53 @@ return PyLong_FromLong((long)ret); } -PyDoc_STRVAR(fcntl_doc, -"fcntl(fd, op, [arg])\n\ -\n\ -Perform the operation op on file descriptor fd. The values used\n\ -for op are operating system dependent, and are available\n\ -as constants in the fcntl module, using the same names as used in\n\ -the relevant C header files. The argument arg is optional, and\n\ -defaults to 0; it may be an int or a string. If arg is given as a string,\n\ -the return value of fcntl is a string of that length, containing the\n\ -resulting value put in the arg buffer by the operating system. The length\n\ -of the arg string is not allowed to exceed 1024 bytes. If the arg given\n\ -is an integer or if none is specified, the result value is an integer\n\ -corresponding to the return value of the fcntl call in the C code."); +/*[clinic input] +fcntl.ioctl -/* ioctl(fd, op, [arg]) */ + fd: object(type='int', converter='conv_descriptor') + op as code: unsigned_int(bitwise=True) + arg as ob_arg: object = NULL + mutate_flag as mutate_arg: bool = True + / + +Perform the operation op on file descriptor fd. + +The values used for op are operating system dependent, and are available as +constants in the fcntl or termios library modules, using the same names as +used in the relevant C header files. + +The argument `arg` is optional, and defaults to 0; it may be an int or a +buffer containing character data (most likely a string or an array). + +If the argument is a mutable buffer (such as an array) and if the +mutate_flag argument (which is only allowed in this case) is true then the +buffer is (in effect) passed to the operating system and changes made by +the OS will be reflected in the contents of the buffer after the call has +returned. The return value is the integer returned by the ioctl system +call. + +If the argument is a mutable buffer and the mutable_flag argument is not +passed or is false, the behavior is as if a string had been passed. This +behavior will change in future releases of Python. + +If the argument is an immutable buffer (most likely a string) then a copy +of the buffer is passed to the operating system and the return value is a +string of the same length containing whatever the operating system put in +the buffer. The length of the arg buffer in this case is not allowed to +exceed 1024 bytes. + +If the arg given is an integer or if none is specified, the result value is +an integer corresponding to the return value of the ioctl call in the C +code. +[clinic start generated code]*/ static PyObject * -fcntl_ioctl(PyObject *self, PyObject *args) +fcntl_ioctl_impl(PyModuleDef *module, int fd, unsigned int code, PyObject *ob_arg, int mutate_arg) +/*[clinic end generated code: output=ad47738c118622bf input=a55a6ee8e494c449]*/ { #define IOCTL_BUFSZ 1024 - int fd; - /* In PyArg_ParseTuple below, we use the unsigned non-checked 'I' + /* We use the unsigned non-checked 'I' format for the 'code' parameter because Python turns 0x8000000 into either a large positive number (PyLong or PyInt on 64-bit platforms) or a negative number on others (32-bit PyInt) @@ -111,101 +165,98 @@ in their unsigned long ioctl codes this will break and need special casing based on the platform being built on. */ - unsigned int code; - int arg; + int arg = 0; int ret; Py_buffer pstr; char *str; Py_ssize_t len; - int mutate_arg = 1; char buf[IOCTL_BUFSZ+1]; /* argument plus NUL byte */ - if (PyArg_ParseTuple(args, "O&Iw*|i:ioctl", - conv_descriptor, &fd, &code, - &pstr, &mutate_arg)) { - char *arg; - str = pstr.buf; - len = pstr.len; + if (ob_arg != NULL) { + if (PyArg_Parse(ob_arg, "w*:ioctl", &pstr)) { + char *arg; + str = pstr.buf; + len = pstr.len; - if (mutate_arg) { - if (len <= IOCTL_BUFSZ) { - memcpy(buf, str, len); - buf[len] = '\0'; - arg = buf; + if (mutate_arg) { + if (len <= IOCTL_BUFSZ) { + memcpy(buf, str, len); + buf[len] = '\0'; + arg = buf; + } + else { + arg = str; + } } else { - arg = str; + if (len > IOCTL_BUFSZ) { + PyBuffer_Release(&pstr); + PyErr_SetString(PyExc_ValueError, + "ioctl string arg too long"); + return NULL; + } + else { + memcpy(buf, str, len); + buf[len] = '\0'; + arg = buf; + } + } + if (buf == arg) { + Py_BEGIN_ALLOW_THREADS /* think array.resize() */ + ret = ioctl(fd, code, arg); + Py_END_ALLOW_THREADS + } + else { + ret = ioctl(fd, code, arg); + } + if (mutate_arg && (len <= IOCTL_BUFSZ)) { + memcpy(str, buf, len); + } + PyBuffer_Release(&pstr); /* No further access to str below this point */ + if (ret < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + if (mutate_arg) { + return PyLong_FromLong(ret); + } + else { + return PyBytes_FromStringAndSize(buf, len); } } - else { + + PyErr_Clear(); + if (PyArg_Parse(ob_arg, "s*:ioctl", &pstr)) { + str = pstr.buf; + len = pstr.len; if (len > IOCTL_BUFSZ) { PyBuffer_Release(&pstr); PyErr_SetString(PyExc_ValueError, - "ioctl string arg too long"); + "ioctl string arg too long"); return NULL; } - else { - memcpy(buf, str, len); - buf[len] = '\0'; - arg = buf; + memcpy(buf, str, len); + buf[len] = '\0'; + Py_BEGIN_ALLOW_THREADS + ret = ioctl(fd, code, buf); + Py_END_ALLOW_THREADS + if (ret < 0) { + PyBuffer_Release(&pstr); + PyErr_SetFromErrno(PyExc_IOError); + return NULL; } - } - if (buf == arg) { - Py_BEGIN_ALLOW_THREADS /* think array.resize() */ - ret = ioctl(fd, code, arg); - Py_END_ALLOW_THREADS - } - else { - ret = ioctl(fd, code, arg); - } - if (mutate_arg && (len <= IOCTL_BUFSZ)) { - memcpy(str, buf, len); - } - PyBuffer_Release(&pstr); /* No further access to str below this point */ - if (ret < 0) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - if (mutate_arg) { - return PyLong_FromLong(ret); - } - else { + PyBuffer_Release(&pstr); return PyBytes_FromStringAndSize(buf, len); } - } - PyErr_Clear(); - if (PyArg_ParseTuple(args, "O&Is*:ioctl", - conv_descriptor, &fd, &code, &pstr)) { - str = pstr.buf; - len = pstr.len; - if (len > IOCTL_BUFSZ) { - PyBuffer_Release(&pstr); - PyErr_SetString(PyExc_ValueError, - "ioctl string arg too long"); - return NULL; + PyErr_Clear(); + if (!PyArg_Parse(ob_arg, + "i;ioctl requires a file or file descriptor," + " an integer and optionally an integer or buffer argument", + &arg)) { + return NULL; } - memcpy(buf, str, len); - buf[len] = '\0'; - Py_BEGIN_ALLOW_THREADS - ret = ioctl(fd, code, buf); - Py_END_ALLOW_THREADS - if (ret < 0) { - PyBuffer_Release(&pstr); - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - PyBuffer_Release(&pstr); - return PyBytes_FromStringAndSize(buf, len); - } - - PyErr_Clear(); - arg = 0; - if (!PyArg_ParseTuple(args, - "O&I|i;ioctl requires a file or file descriptor," - " an integer and optionally an integer or buffer argument", - conv_descriptor, &fd, &code, &arg)) { - return NULL; + // Fall-through to outside the 'if' statement. } Py_BEGIN_ALLOW_THREADS ret = ioctl(fd, code, arg); @@ -218,52 +269,25 @@ #undef IOCTL_BUFSZ } -PyDoc_STRVAR(ioctl_doc, -"ioctl(fd, op[, arg[, mutate_flag]])\n\ -\n\ -Perform the operation op on file descriptor fd. The values used for op\n\ -are operating system dependent, and are available as constants in the\n\ -fcntl or termios library modules, using the same names as used in the\n\ -relevant C header files.\n\ -\n\ -The argument arg is optional, and defaults to 0; it may be an int or a\n\ -buffer containing character data (most likely a string or an array). \n\ -\n\ -If the argument is a mutable buffer (such as an array) and if the\n\ -mutate_flag argument (which is only allowed in this case) is true then the\n\ -buffer is (in effect) passed to the operating system and changes made by\n\ -the OS will be reflected in the contents of the buffer after the call has\n\ -returned. The return value is the integer returned by the ioctl system\n\ -call.\n\ -\n\ -If the argument is a mutable buffer and the mutable_flag argument is not\n\ -passed or is false, the behavior is as if a string had been passed. This\n\ -behavior will change in future releases of Python.\n\ -\n\ -If the argument is an immutable buffer (most likely a string) then a copy\n\ -of the buffer is passed to the operating system and the return value is a\n\ -string of the same length containing whatever the operating system put in\n\ -the buffer. The length of the arg buffer in this case is not allowed to\n\ -exceed 1024 bytes.\n\ -\n\ -If the arg given is an integer or if none is specified, the result value is\n\ -an integer corresponding to the return value of the ioctl call in the C\n\ -code."); +/*[clinic input] +fcntl.flock + fd: object(type='int', converter='conv_descriptor') + code: int + / -/* flock(fd, operation) */ +Perform the lock operation op on file descriptor fd. + +See the Unix manual page for flock(2) for details (On some systems, this +function is emulated using fcntl()). +[clinic start generated code]*/ static PyObject * -fcntl_flock(PyObject *self, PyObject *args) +fcntl_flock_impl(PyModuleDef *module, int fd, int code) +/*[clinic end generated code: output=c9035133a7dbfc96 input=b762aa9448d05e43]*/ { - int fd; - int code; int ret; - if (!PyArg_ParseTuple(args, "O&i:flock", - conv_descriptor, &fd, &code)) - return NULL; - #ifdef HAVE_FLOCK Py_BEGIN_ALLOW_THREADS ret = flock(fd, code); @@ -299,29 +323,49 @@ PyErr_SetFromErrno(PyExc_IOError); return NULL; } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } -PyDoc_STRVAR(flock_doc, -"flock(fd, operation)\n\ -\n\ -Perform the lock operation op on file descriptor fd. See the Unix \n\ -manual page for flock(2) for details. (On some systems, this function is\n\ -emulated using fcntl().)"); +/*[clinic input] +fcntl.lockf -/* lockf(fd, operation) */ + fd: object(type='int', converter='conv_descriptor') + code: int + lenobj: object = NULL + startobj: object = NULL + whence: int = 0 + / + +A wrapper around the fcntl() locking calls. + +fd is the file descriptor of the file to lock or unlock, and operation is one +of the following values: + + LOCK_UN - unlock + LOCK_SH - acquire a shared lock + LOCK_EX - acquire an exclusive lock + +When operation is LOCK_SH or LOCK_EX, it can also be bitwise ORed with +LOCK_NB to avoid blocking on lock acquisition. If LOCK_NB is used and the +lock cannot be acquired, an IOError will be raised and the exception will +have an errno attribute set to EACCES or EAGAIN (depending on the operating +system -- for portability, check for either value). + +length is the number of bytes to lock, with the default meaning to lock to +EOF. start is the byte offset, relative to whence, to that the lock +starts. whence is as with fileobj.seek(), specifically: + + 0 - relative to the start of the file (SEEK_SET) + 1 - relative to the current buffer position (SEEK_CUR) + 2 - relative to the end of the file (SEEK_END) +[clinic start generated code]*/ + static PyObject * -fcntl_lockf(PyObject *self, PyObject *args) +fcntl_lockf_impl(PyModuleDef *module, int fd, int code, PyObject *lenobj, PyObject *startobj, int whence) +/*[clinic end generated code: output=5536df2892bf3ce9 input=44856fa06db36184]*/ { - int fd, code, ret, whence = 0; - PyObject *lenobj = NULL, *startobj = NULL; - - if (!PyArg_ParseTuple(args, "O&i|OOi:lockf", - conv_descriptor, &fd, &code, - &lenobj, &startobj, &whence)) - return NULL; + int ret; #ifndef LOCK_SH #define LOCK_SH 1 /* shared lock */ @@ -374,43 +418,17 @@ PyErr_SetFromErrno(PyExc_IOError); return NULL; } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } -PyDoc_STRVAR(lockf_doc, -"lockf (fd, operation, length=0, start=0, whence=0)\n\ -\n\ -This is essentially a wrapper around the fcntl() locking calls. fd is the\n\ -file descriptor of the file to lock or unlock, and operation is one of the\n\ -following values:\n\ -\n\ - LOCK_UN - unlock\n\ - LOCK_SH - acquire a shared lock\n\ - LOCK_EX - acquire an exclusive lock\n\ -\n\ -When operation is LOCK_SH or LOCK_EX, it can also be bitwise ORed with\n\ -LOCK_NB to avoid blocking on lock acquisition. If LOCK_NB is used and the\n\ -lock cannot be acquired, an IOError will be raised and the exception will\n\ -have an errno attribute set to EACCES or EAGAIN (depending on the operating\n\ -system -- for portability, check for either value).\n\ -\n\ -length is the number of bytes to lock, with the default meaning to lock to\n\ -EOF. start is the byte offset, relative to whence, to that the lock\n\ -starts. whence is as with fileobj.seek(), specifically:\n\ -\n\ - 0 - relative to the start of the file (SEEK_SET)\n\ - 1 - relative to the current buffer position (SEEK_CUR)\n\ - 2 - relative to the end of the file (SEEK_END)"); - /* List of functions */ static PyMethodDef fcntl_methods[] = { - {"fcntl", fcntl_fcntl, METH_VARARGS, fcntl_doc}, - {"ioctl", fcntl_ioctl, METH_VARARGS, ioctl_doc}, - {"flock", fcntl_flock, METH_VARARGS, flock_doc}, - {"lockf", fcntl_lockf, METH_VARARGS, lockf_doc}, - {NULL, NULL} /* sentinel */ + FCNTL_FCNTL_METHODDEF + FCNTL_IOCTL_METHODDEF + FCNTL_FLOCK_METHODDEF + FCNTL_LOCKF_METHODDEF + {NULL, NULL} /* sentinel */ }; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 02:25:52 2014 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 10 Nov 2014 01:25:52 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Use_internal_l?= =?utf-8?q?inks_where_possible?= Message-ID: <20141110012551.85212.96118@psf.io> https://hg.python.org/cpython/rev/3a8e0a5359cf changeset: 93448:3a8e0a5359cf branch: 2.7 parent: 93443:dbe1744ec62e user: Raymond Hettinger date: Sun Nov 09 17:25:42 2014 -0800 summary: Use internal links where possible files: Doc/library/functions.rst | 3 +-- Doc/library/functools.rst | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1326,8 +1326,7 @@ compare equal --- this is helpful for sorting in multiple passes (for example, sort by department, then by salary grade). - For sorting examples and a brief sorting tutorial, see `Sorting HowTo - `_\. + For sorting examples and a brief sorting tutorial, see :ref:`sortinghowto`. .. versionadded:: 2.4 diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -38,8 +38,7 @@ sorted(iterable, key=cmp_to_key(locale.strcoll)) # locale-aware sort order - For sorting examples and a brief sorting tutorial, see `Sorting HowTo - `_\. + For sorting examples and a brief sorting tutorial, see :ref:`sortinghowto`. .. versionadded:: 2.7 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 07:30:42 2014 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 10 Nov 2014 06:30:42 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322824=3A__Updated?= =?utf-8?q?_reprlib_output_format_for_sets_to_use_set_literals=2E?= Message-ID: <20141110063042.108083.25450@psf.io> https://hg.python.org/cpython/rev/147fda13bec8 changeset: 93449:147fda13bec8 parent: 93447:55b89e5f9c37 user: Raymond Hettinger date: Sun Nov 09 22:30:36 2014 -0800 summary: Issue #22824: Updated reprlib output format for sets to use set literals. files: Doc/tutorial/stdlib2.rst | 2 +- Lib/reprlib.py | 8 +++- Lib/test/test_reprlib.py | 44 ++++++++++++++++----------- Misc/NEWS | 3 + 4 files changed, 36 insertions(+), 21 deletions(-) diff --git a/Doc/tutorial/stdlib2.rst b/Doc/tutorial/stdlib2.rst --- a/Doc/tutorial/stdlib2.rst +++ b/Doc/tutorial/stdlib2.rst @@ -18,7 +18,7 @@ >>> import reprlib >>> reprlib.repr(set('supercalifragilisticexpialidocious')) - "set(['a', 'c', 'd', 'e', 'f', 'g', ...])" + "{'a', 'c', 'd', 'e', 'f', 'g', ...}" The :mod:`pprint` module offers more sophisticated control over printing both built-in and user defined objects in a way that is readable by the interpreter. diff --git a/Lib/reprlib.py b/Lib/reprlib.py --- a/Lib/reprlib.py +++ b/Lib/reprlib.py @@ -87,12 +87,16 @@ return self._repr_iterable(x, level, header, '])', self.maxarray) def repr_set(self, x, level): + if not x: + return 'set()' x = _possibly_sorted(x) - return self._repr_iterable(x, level, 'set([', '])', self.maxset) + return self._repr_iterable(x, level, '{', '}', self.maxset) def repr_frozenset(self, x, level): + if not x: + return 'frozenset()' x = _possibly_sorted(x) - return self._repr_iterable(x, level, 'frozenset([', '])', + return self._repr_iterable(x, level, 'frozenset({', '})', self.maxfrozenset) def repr_deque(self, x, level): diff --git a/Lib/test/test_reprlib.py b/Lib/test/test_reprlib.py --- a/Lib/test/test_reprlib.py +++ b/Lib/test/test_reprlib.py @@ -10,7 +10,7 @@ import importlib.util import unittest -from test.support import run_unittest, create_empty_file, verbose +from test.support import create_empty_file, verbose from reprlib import repr as r # Don't shadow builtin repr from reprlib import Repr from reprlib import recursive_repr @@ -70,18 +70,18 @@ eq(r([1, 2, 3, 4, 5, 6, 7]), "[1, 2, 3, 4, 5, 6, ...]") # Sets give up after 6 as well - eq(r(set([])), "set([])") - eq(r(set([1])), "set([1])") - eq(r(set([1, 2, 3])), "set([1, 2, 3])") - eq(r(set([1, 2, 3, 4, 5, 6])), "set([1, 2, 3, 4, 5, 6])") - eq(r(set([1, 2, 3, 4, 5, 6, 7])), "set([1, 2, 3, 4, 5, 6, ...])") + eq(r(set([])), "set()") + eq(r(set([1])), "{1}") + eq(r(set([1, 2, 3])), "{1, 2, 3}") + eq(r(set([1, 2, 3, 4, 5, 6])), "{1, 2, 3, 4, 5, 6}") + eq(r(set([1, 2, 3, 4, 5, 6, 7])), "{1, 2, 3, 4, 5, 6, ...}") # Frozensets give up after 6 as well - eq(r(frozenset([])), "frozenset([])") - eq(r(frozenset([1])), "frozenset([1])") - eq(r(frozenset([1, 2, 3])), "frozenset([1, 2, 3])") - eq(r(frozenset([1, 2, 3, 4, 5, 6])), "frozenset([1, 2, 3, 4, 5, 6])") - eq(r(frozenset([1, 2, 3, 4, 5, 6, 7])), "frozenset([1, 2, 3, 4, 5, 6, ...])") + eq(r(frozenset([])), "frozenset()") + eq(r(frozenset([1])), "frozenset({1})") + eq(r(frozenset([1, 2, 3])), "frozenset({1, 2, 3})") + eq(r(frozenset([1, 2, 3, 4, 5, 6])), "frozenset({1, 2, 3, 4, 5, 6})") + eq(r(frozenset([1, 2, 3, 4, 5, 6, 7])), "frozenset({1, 2, 3, 4, 5, 6, ...})") # collections.deque after 6 eq(r(deque([1, 2, 3, 4, 5, 6, 7])), "deque([1, 2, 3, 4, 5, 6, ...])") @@ -103,6 +103,20 @@ eq(r(array('i', [1, 2, 3, 4, 5, 6])), "array('i', [1, 2, 3, 4, 5, ...])") + def test_set_literal(self): + eq = self.assertEqual + eq(r({1}), "{1}") + eq(r({1, 2, 3}), "{1, 2, 3}") + eq(r({1, 2, 3, 4, 5, 6}), "{1, 2, 3, 4, 5, 6}") + eq(r({1, 2, 3, 4, 5, 6, 7}), "{1, 2, 3, 4, 5, 6, ...}") + + def test_frozenset(self): + eq = self.assertEqual + eq(r(frozenset({1})), "frozenset({1})") + eq(r(frozenset({1, 2, 3})), "frozenset({1, 2, 3})") + eq(r(frozenset({1, 2, 3, 4, 5, 6})), "frozenset({1, 2, 3, 4, 5, 6})") + eq(r(frozenset({1, 2, 3, 4, 5, 6, 7})), "frozenset({1, 2, 3, 4, 5, 6, ...})") + def test_numbers(self): eq = self.assertEqual eq(r(123), repr(123)) @@ -373,11 +387,5 @@ m.append(m) self.assertEqual(repr(m), '') -def test_main(): - run_unittest(ReprTests) - run_unittest(LongReprTest) - run_unittest(TestRecursiveRepr) - - if __name__ == "__main__": - test_main() + unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -186,6 +186,9 @@ - Issues #814253, #9179: Group references and conditional group references now work in lookbehind assertions in regular expressions. +- Issue #22824: Updated reprlib output format for sets to use set literals. + Patch contributed by Berker Peksag. + - Issue #22406: Fixed the uu_codec codec incorrectly ported to 3.x. Based on patch by Martin Panter. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 08:56:36 2014 From: python-checkins at python.org (berker.peksag) Date: Mon, 10 Nov 2014 07:56:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2321650=3A_Add_an_?= =?utf-8?q?=60--sort-keys=60_option_to_json=2Etool_CLI=2E?= Message-ID: <20141110075635.731.11536@psf.io> https://hg.python.org/cpython/rev/58a871227e5b changeset: 93450:58a871227e5b user: Berker Peksag date: Mon Nov 10 09:56:54 2014 +0200 summary: Issue #21650: Add an `--sort-keys` option to json.tool CLI. files: Doc/library/json.rst | 11 ++++++ Doc/whatsnew/3.5.rst | 8 ++++ Lib/json/tool.py | 12 ++++++- Lib/test/test_json/test_tool.py | 35 +++++++++++++++++++- Misc/NEWS | 2 + 5 files changed, 64 insertions(+), 4 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -567,6 +567,7 @@ The *object_pairs_hook* parameter can be used to alter this behavior. .. highlight:: bash +.. module:: json.tool .. _json-commandline: @@ -586,6 +587,10 @@ $ echo '{1.2:3.4}' | python -m json.tool Expecting property name enclosed in double quotes: line 1 column 2 (char 1) +.. versionchanged:: 3.5 + The output is now in the same order as the input. Use the + :option:`--sort-keys` option to sort the output of dictionaries + alphabetically by key. Command line options ^^^^^^^^^^^^^^^^^^^^ @@ -613,6 +618,12 @@ Write the output of the *infile* to the given *outfile*. Otherwise, write it to :attr:`sys.stdout`. +.. cmdoption:: --sort-keys + + Sort the output of dictionaries alphabetically by key. + + .. versionadded:: 3.5 + .. cmdoption:: -h, --help Show the help message. diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -211,6 +211,14 @@ network objects from existing addresses. (Contributed by Peter Moody and Antoine Pitrou in :issue:`16531`.) +json +---- + +* The output of :mod:`json.tool` command line interface is now in the same + order as the input. Use the :option:`--sort-keys` option to sort the output + of dictionaries alphabetically by key. (Contributed by Berker Peksag in + :issue:`21650`.) + os -- diff --git a/Lib/json/tool.py b/Lib/json/tool.py --- a/Lib/json/tool.py +++ b/Lib/json/tool.py @@ -11,6 +11,7 @@ """ import argparse +import collections import json import sys @@ -24,17 +25,24 @@ help='a JSON file to be validated or pretty-printed') parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'), help='write the output of infile to outfile') + parser.add_argument('--sort-keys', action='store_true', default=False, + help='sort the output of dictionaries alphabetically by key') options = parser.parse_args() infile = options.infile or sys.stdin outfile = options.outfile or sys.stdout + sort_keys = options.sort_keys with infile: try: - obj = json.load(infile) + if sort_keys: + obj = json.load(infile) + else: + obj = json.load(infile, + object_pairs_hook=collections.OrderedDict) except ValueError as e: raise SystemExit(e) with outfile: - json.dump(obj, outfile, sort_keys=True, indent=4) + json.dump(obj, outfile, sort_keys=sort_keys, indent=4) outfile.write('\n') diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py --- a/Lib/test/test_json/test_tool.py +++ b/Lib/test/test_json/test_tool.py @@ -6,6 +6,7 @@ from test import support from test.script_helper import assert_python_ok + class TestTool(unittest.TestCase): data = """ @@ -15,6 +16,28 @@ :"yes"} ] """ + expect_without_sort_keys = textwrap.dedent("""\ + [ + [ + "blorpie" + ], + [ + "whoops" + ], + [], + "d-shtaeou", + "d-nthiouh", + "i-vhbjkhnth", + { + "nifty": 87 + }, + { + "field": "yes", + "morefield": false + } + ] + """) + expect = textwrap.dedent("""\ [ [ @@ -31,8 +54,8 @@ "nifty": 87 }, { - "field": "yes", - "morefield": false + "morefield": false, + "field": "yes" } ] """) @@ -75,3 +98,11 @@ self.assertEqual(rc, 0) self.assertTrue(out.startswith(b'usage: ')) self.assertEqual(err, b'') + + def test_sort_keys_flag(self): + infile = self._create_infile() + rc, out, err = assert_python_ok('-m', 'json.tool', '--sort-keys', infile) + self.assertEqual(rc, 0) + self.assertEqual(out.splitlines(), + self.expect_without_sort_keys.encode().splitlines()) + self.assertEqual(err, b'') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -183,6 +183,8 @@ Library ------- +- Issue #21650: Add an `--sort-keys` option to json.tool CLI. + - Issues #814253, #9179: Group references and conditional group references now work in lookbehind assertions in regular expressions. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 09:23:18 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 10 Nov 2014 08:23:18 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322434=3A_Constant?= =?utf-8?q?s_in_sre=5Fconstants_are_now_named_constants_=28enum-like=29=2E?= Message-ID: <20141110082318.113474.69580@psf.io> https://hg.python.org/cpython/rev/fc7dbba57869 changeset: 93451:fc7dbba57869 parent: 93441:ec81edc30221 user: Serhiy Storchaka date: Sun Nov 09 20:48:36 2014 +0200 summary: Issue #22434: Constants in sre_constants are now named constants (enum-like). files: Lib/sre_compile.py | 75 +++++----- Lib/sre_constants.py | 197 +++++++++++------------------- Lib/sre_parse.py | 9 +- Lib/test/test_re.py | 32 ++-- 4 files changed, 127 insertions(+), 186 deletions(-) diff --git a/Lib/sre_compile.py b/Lib/sre_compile.py --- a/Lib/sre_compile.py +++ b/Lib/sre_compile.py @@ -13,7 +13,6 @@ import _sre import sre_parse from sre_constants import * -from _sre import MAXREPEAT assert _sre.MAGIC == MAGIC, "SRE module mismatch" @@ -38,65 +37,65 @@ for op, av in pattern: if op in LITERAL_CODES: if flags & SRE_FLAG_IGNORECASE: - emit(OPCODES[OP_IGNORE[op]]) + emit(OP_IGNORE[op]) emit(_sre.getlower(av, flags)) else: - emit(OPCODES[op]) + emit(op) emit(av) elif op is IN: if flags & SRE_FLAG_IGNORECASE: - emit(OPCODES[OP_IGNORE[op]]) + emit(OP_IGNORE[op]) def fixup(literal, flags=flags): return _sre.getlower(literal, flags) else: - emit(OPCODES[op]) + emit(op) fixup = None skip = _len(code); emit(0) _compile_charset(av, flags, code, fixup) code[skip] = _len(code) - skip elif op is ANY: if flags & SRE_FLAG_DOTALL: - emit(OPCODES[ANY_ALL]) + emit(ANY_ALL) else: - emit(OPCODES[ANY]) + emit(ANY) elif op in REPEATING_CODES: if flags & SRE_FLAG_TEMPLATE: raise error("internal: unsupported template operator") elif _simple(av) and op is not REPEAT: if op is MAX_REPEAT: - emit(OPCODES[REPEAT_ONE]) + emit(REPEAT_ONE) else: - emit(OPCODES[MIN_REPEAT_ONE]) + emit(MIN_REPEAT_ONE) skip = _len(code); emit(0) emit(av[0]) emit(av[1]) _compile(code, av[2], flags) - emit(OPCODES[SUCCESS]) + emit(SUCCESS) code[skip] = _len(code) - skip else: - emit(OPCODES[REPEAT]) + emit(REPEAT) skip = _len(code); emit(0) emit(av[0]) emit(av[1]) _compile(code, av[2], flags) code[skip] = _len(code) - skip if op is MAX_REPEAT: - emit(OPCODES[MAX_UNTIL]) + emit(MAX_UNTIL) else: - emit(OPCODES[MIN_UNTIL]) + emit(MIN_UNTIL) elif op is SUBPATTERN: if av[0]: - emit(OPCODES[MARK]) + emit(MARK) emit((av[0]-1)*2) # _compile_info(code, av[1], flags) _compile(code, av[1], flags) if av[0]: - emit(OPCODES[MARK]) + emit(MARK) emit((av[0]-1)*2+1) elif op in SUCCESS_CODES: - emit(OPCODES[op]) + emit(op) elif op in ASSERT_CODES: - emit(OPCODES[op]) + emit(op) skip = _len(code); emit(0) if av[0] >= 0: emit(0) # look ahead @@ -106,57 +105,57 @@ raise error("look-behind requires fixed-width pattern") emit(lo) # look behind _compile(code, av[1], flags) - emit(OPCODES[SUCCESS]) + emit(SUCCESS) code[skip] = _len(code) - skip elif op is CALL: - emit(OPCODES[op]) + emit(op) skip = _len(code); emit(0) _compile(code, av, flags) - emit(OPCODES[SUCCESS]) + emit(SUCCESS) code[skip] = _len(code) - skip elif op is AT: - emit(OPCODES[op]) + emit(op) if flags & SRE_FLAG_MULTILINE: av = AT_MULTILINE.get(av, av) if flags & SRE_FLAG_LOCALE: av = AT_LOCALE.get(av, av) elif flags & SRE_FLAG_UNICODE: av = AT_UNICODE.get(av, av) - emit(ATCODES[av]) + emit(av) elif op is BRANCH: - emit(OPCODES[op]) + emit(op) tail = [] tailappend = tail.append for av in av[1]: skip = _len(code); emit(0) # _compile_info(code, av, flags) _compile(code, av, flags) - emit(OPCODES[JUMP]) + emit(JUMP) tailappend(_len(code)); emit(0) code[skip] = _len(code) - skip emit(0) # end of branch for tail in tail: code[tail] = _len(code) - tail elif op is CATEGORY: - emit(OPCODES[op]) + emit(op) if flags & SRE_FLAG_LOCALE: av = CH_LOCALE[av] elif flags & SRE_FLAG_UNICODE: av = CH_UNICODE[av] - emit(CHCODES[av]) + emit(av) elif op is GROUPREF: if flags & SRE_FLAG_IGNORECASE: - emit(OPCODES[OP_IGNORE[op]]) + emit(OP_IGNORE[op]) else: - emit(OPCODES[op]) + emit(op) emit(av-1) elif op is GROUPREF_EXISTS: - emit(OPCODES[op]) + emit(op) emit(av[0]-1) skipyes = _len(code); emit(0) _compile(code, av[1], flags) if av[2]: - emit(OPCODES[JUMP]) + emit(JUMP) skipno = _len(code); emit(0) code[skipyes] = _len(code) - skipyes + 1 _compile(code, av[2], flags) @@ -170,7 +169,7 @@ # compile charset subprogram emit = code.append for op, av in _optimize_charset(charset, fixup): - emit(OPCODES[op]) + emit(op) if op is NEGATE: pass elif op is LITERAL: @@ -184,14 +183,14 @@ code.extend(av) elif op is CATEGORY: if flags & SRE_FLAG_LOCALE: - emit(CHCODES[CH_LOCALE[av]]) + emit(CH_LOCALE[av]) elif flags & SRE_FLAG_UNICODE: - emit(CHCODES[CH_UNICODE[av]]) + emit(CH_UNICODE[av]) else: - emit(CHCODES[av]) + emit(av) else: raise error("internal: unsupported set operator") - emit(OPCODES[FAILURE]) + emit(FAILURE) def _optimize_charset(charset, fixup): # internal: optimize character set @@ -414,7 +413,7 @@ ## print "*** CHARSET", charset # add an info block emit = code.append - emit(OPCODES[INFO]) + emit(INFO) skip = len(code); emit(0) # literal flag mask = 0 @@ -460,7 +459,7 @@ # compile the pattern _compile(code, p.data, flags) - code.append(OPCODES[SUCCESS]) + code.append(SUCCESS) return code @@ -475,7 +474,7 @@ code = _code(p, flags) - # print code + # print(code) # map in either direction groupindex = p.pattern.groupdict diff --git a/Lib/sre_constants.py b/Lib/sre_constants.py --- a/Lib/sre_constants.py +++ b/Lib/sre_constants.py @@ -23,138 +23,81 @@ class error(Exception): pass + +class _NamedIntConstant(int): + def __new__(cls, value, name): + self = super(_NamedIntConstant, cls).__new__(cls, value) + self.name = name + return self + + def __str__(self): + return self.name + + __repr__ = __str__ + +MAXREPEAT = _NamedIntConstant(MAXREPEAT, 'MAXREPEAT') + +def _makecodes(names): + names = names.strip().split() + items = [_NamedIntConstant(i, name) for i, name in enumerate(names)] + globals().update({item.name: item for item in items}) + return items + # operators +# failure=0 success=1 (just because it looks better that way :-) +OPCODES = _makecodes(""" + FAILURE SUCCESS -FAILURE = "failure" -SUCCESS = "success" + ANY ANY_ALL + ASSERT ASSERT_NOT + AT + BRANCH + CALL + CATEGORY + CHARSET BIGCHARSET + GROUPREF GROUPREF_EXISTS GROUPREF_IGNORE + IN IN_IGNORE + INFO + JUMP + LITERAL LITERAL_IGNORE + MARK + MAX_UNTIL + MIN_UNTIL + NOT_LITERAL NOT_LITERAL_IGNORE + NEGATE + RANGE + REPEAT + REPEAT_ONE + SUBPATTERN + MIN_REPEAT_ONE + RANGE_IGNORE -ANY = "any" -ANY_ALL = "any_all" -ASSERT = "assert" -ASSERT_NOT = "assert_not" -AT = "at" -BIGCHARSET = "bigcharset" -BRANCH = "branch" -CALL = "call" -CATEGORY = "category" -CHARSET = "charset" -GROUPREF = "groupref" -GROUPREF_IGNORE = "groupref_ignore" -GROUPREF_EXISTS = "groupref_exists" -IN = "in" -IN_IGNORE = "in_ignore" -INFO = "info" -JUMP = "jump" -LITERAL = "literal" -LITERAL_IGNORE = "literal_ignore" -MARK = "mark" -MAX_REPEAT = "max_repeat" -MAX_UNTIL = "max_until" -MIN_REPEAT = "min_repeat" -MIN_UNTIL = "min_until" -NEGATE = "negate" -NOT_LITERAL = "not_literal" -NOT_LITERAL_IGNORE = "not_literal_ignore" -RANGE = "range" -RANGE_IGNORE = "range_ignore" -REPEAT = "repeat" -REPEAT_ONE = "repeat_one" -SUBPATTERN = "subpattern" -MIN_REPEAT_ONE = "min_repeat_one" + MIN_REPEAT MAX_REPEAT +""") +del OPCODES[-2:] # remove MIN_REPEAT and MAX_REPEAT # positions -AT_BEGINNING = "at_beginning" -AT_BEGINNING_LINE = "at_beginning_line" -AT_BEGINNING_STRING = "at_beginning_string" -AT_BOUNDARY = "at_boundary" -AT_NON_BOUNDARY = "at_non_boundary" -AT_END = "at_end" -AT_END_LINE = "at_end_line" -AT_END_STRING = "at_end_string" -AT_LOC_BOUNDARY = "at_loc_boundary" -AT_LOC_NON_BOUNDARY = "at_loc_non_boundary" -AT_UNI_BOUNDARY = "at_uni_boundary" -AT_UNI_NON_BOUNDARY = "at_uni_non_boundary" +ATCODES = _makecodes(""" + AT_BEGINNING AT_BEGINNING_LINE AT_BEGINNING_STRING + AT_BOUNDARY AT_NON_BOUNDARY + AT_END AT_END_LINE AT_END_STRING + AT_LOC_BOUNDARY AT_LOC_NON_BOUNDARY + AT_UNI_BOUNDARY AT_UNI_NON_BOUNDARY +""") # categories -CATEGORY_DIGIT = "category_digit" -CATEGORY_NOT_DIGIT = "category_not_digit" -CATEGORY_SPACE = "category_space" -CATEGORY_NOT_SPACE = "category_not_space" -CATEGORY_WORD = "category_word" -CATEGORY_NOT_WORD = "category_not_word" -CATEGORY_LINEBREAK = "category_linebreak" -CATEGORY_NOT_LINEBREAK = "category_not_linebreak" -CATEGORY_LOC_WORD = "category_loc_word" -CATEGORY_LOC_NOT_WORD = "category_loc_not_word" -CATEGORY_UNI_DIGIT = "category_uni_digit" -CATEGORY_UNI_NOT_DIGIT = "category_uni_not_digit" -CATEGORY_UNI_SPACE = "category_uni_space" -CATEGORY_UNI_NOT_SPACE = "category_uni_not_space" -CATEGORY_UNI_WORD = "category_uni_word" -CATEGORY_UNI_NOT_WORD = "category_uni_not_word" -CATEGORY_UNI_LINEBREAK = "category_uni_linebreak" -CATEGORY_UNI_NOT_LINEBREAK = "category_uni_not_linebreak" +CHCODES = _makecodes(""" + CATEGORY_DIGIT CATEGORY_NOT_DIGIT + CATEGORY_SPACE CATEGORY_NOT_SPACE + CATEGORY_WORD CATEGORY_NOT_WORD + CATEGORY_LINEBREAK CATEGORY_NOT_LINEBREAK + CATEGORY_LOC_WORD CATEGORY_LOC_NOT_WORD + CATEGORY_UNI_DIGIT CATEGORY_UNI_NOT_DIGIT + CATEGORY_UNI_SPACE CATEGORY_UNI_NOT_SPACE + CATEGORY_UNI_WORD CATEGORY_UNI_NOT_WORD + CATEGORY_UNI_LINEBREAK CATEGORY_UNI_NOT_LINEBREAK +""") -OPCODES = [ - - # failure=0 success=1 (just because it looks better that way :-) - FAILURE, SUCCESS, - - ANY, ANY_ALL, - ASSERT, ASSERT_NOT, - AT, - BRANCH, - CALL, - CATEGORY, - CHARSET, BIGCHARSET, - GROUPREF, GROUPREF_EXISTS, GROUPREF_IGNORE, - IN, IN_IGNORE, - INFO, - JUMP, - LITERAL, LITERAL_IGNORE, - MARK, - MAX_UNTIL, - MIN_UNTIL, - NOT_LITERAL, NOT_LITERAL_IGNORE, - NEGATE, - RANGE, - REPEAT, - REPEAT_ONE, - SUBPATTERN, - MIN_REPEAT_ONE, - RANGE_IGNORE, - -] - -ATCODES = [ - AT_BEGINNING, AT_BEGINNING_LINE, AT_BEGINNING_STRING, AT_BOUNDARY, - AT_NON_BOUNDARY, AT_END, AT_END_LINE, AT_END_STRING, - AT_LOC_BOUNDARY, AT_LOC_NON_BOUNDARY, AT_UNI_BOUNDARY, - AT_UNI_NON_BOUNDARY -] - -CHCODES = [ - CATEGORY_DIGIT, CATEGORY_NOT_DIGIT, CATEGORY_SPACE, - CATEGORY_NOT_SPACE, CATEGORY_WORD, CATEGORY_NOT_WORD, - CATEGORY_LINEBREAK, CATEGORY_NOT_LINEBREAK, CATEGORY_LOC_WORD, - CATEGORY_LOC_NOT_WORD, CATEGORY_UNI_DIGIT, CATEGORY_UNI_NOT_DIGIT, - CATEGORY_UNI_SPACE, CATEGORY_UNI_NOT_SPACE, CATEGORY_UNI_WORD, - CATEGORY_UNI_NOT_WORD, CATEGORY_UNI_LINEBREAK, - CATEGORY_UNI_NOT_LINEBREAK -] - -def makedict(list): - d = {} - i = 0 - for item in list: - d[item] = i - i = i + 1 - return d - -OPCODES = makedict(OPCODES) -ATCODES = makedict(ATCODES) -CHCODES = makedict(CHCODES) # replacement operations for "ignore case" mode OP_IGNORE = { @@ -220,9 +163,9 @@ if __name__ == "__main__": def dump(f, d, prefix): - items = sorted(d.items(), key=lambda a: a[1]) - for k, v in items: - f.write("#define %s_%s %s\n" % (prefix, k.upper(), v)) + items = sorted(d) + for item in items: + f.write("#define %s_%s %d\n" % (prefix, item, item)) f = open("sre_constants.h", "w") f.write("""\ /* diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -13,7 +13,6 @@ # XXX: show string offset and offending character for all errors from sre_constants import * -from _sre import MAXREPEAT SPECIAL_CHARS = ".\\[{()*+?^$|" REPEAT_CHARS = "*+?{" @@ -103,24 +102,24 @@ nl = True seqtypes = (tuple, list) for op, av in self.data: - print(level*" " + op, end='') + print(level*" " + str(op), end='') if op == IN: # member sublanguage print() for op, a in av: - print((level+1)*" " + op, a) + print((level+1)*" " + str(op), a) elif op == BRANCH: print() for i, a in enumerate(av[1]): if i: - print(level*" " + "or") + print(level*" " + "OR") a.dump(level+1) elif op == GROUPREF_EXISTS: condgroup, item_yes, item_no = av print('', condgroup) item_yes.dump(level+1) if item_no: - print(level*" " + "else") + print(level*" " + "ELSE") item_no.dump(level+1) elif isinstance(av, seqtypes): nl = False diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -1285,22 +1285,22 @@ with captured_stdout() as out: re.compile(pat, re.DEBUG) dump = '''\ -subpattern 1 - literal 46 -subpattern None - branch - in - literal 99 - literal 104 - or - literal 112 - literal 121 -subpattern None - groupref_exists 1 - at at_end - else - literal 58 - literal 32 +SUBPATTERN 1 + LITERAL 46 +SUBPATTERN None + BRANCH + IN + LITERAL 99 + LITERAL 104 + OR + LITERAL 112 + LITERAL 121 +SUBPATTERN None + GROUPREF_EXISTS 1 + AT AT_END + ELSE + LITERAL 58 + LITERAL 32 ''' self.assertEqual(out.getvalue(), dump) # Debug output is output again even a second time (bypassing -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 09:23:18 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 10 Nov 2014 08:23:18 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_heads?= Message-ID: <20141110082318.85194.34355@psf.io> https://hg.python.org/cpython/rev/8111ee79d27c changeset: 93452:8111ee79d27c parent: 93451:fc7dbba57869 parent: 93450:58a871227e5b user: Serhiy Storchaka date: Mon Nov 10 10:21:03 2014 +0200 summary: Merge heads files: Doc/howto/logging-cookbook.rst | 2 +- Doc/library/functools.rst | 9 +- Doc/library/json.rst | 11 + Doc/library/pickle.rst | 2 +- Doc/tutorial/stdlib2.rst | 2 +- Doc/whatsnew/3.5.rst | 8 + Lib/_strptime.py | 4 +- Lib/asyncore.py | 6 +- Lib/ipaddress.py | 2 +- Lib/json/tool.py | 12 +- Lib/mailbox.py | 4 +- Lib/reprlib.py | 8 +- Lib/sre_compile.py | 8 +- Lib/sre_parse.py | 4 +- Lib/statistics.py | 4 +- Lib/test/test_json/test_tool.py | 35 +- Lib/test/test_reprlib.py | 44 +- Misc/NEWS | 5 + Modules/clinic/fcntlmodule.c.h | 188 ++++++++ Modules/fcntlmodule.c | 432 ++++++++++--------- Parser/asdl.py | 3 +- 21 files changed, 537 insertions(+), 256 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 @@ -1680,7 +1680,7 @@ def main(): logging.basicConfig(level=logging.INFO, format='%(message)s') - logging.info(_('message 1', set_value=set([1, 2, 3]), snowman='\u2603')) + logging.info(_('message 1', set_value={1, 2, 3}, snowman='\u2603')) if __name__ == '__main__': main() diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -21,8 +21,8 @@ .. function:: cmp_to_key(func) - Transform an old-style comparison function to a key function. Used with - tools that accept key functions (such as :func:`sorted`, :func:`min`, + Transform an old-style comparison function to a :term:`key function`. Used + with tools that accept key functions (such as :func:`sorted`, :func:`min`, :func:`max`, :func:`heapq.nlargest`, :func:`heapq.nsmallest`, :func:`itertools.groupby`). This function is primarily used as a transition tool for programs being converted from Python 2 which supported the use of @@ -31,13 +31,14 @@ A comparison function is any callable that accept two arguments, compares them, and returns a negative number for less-than, zero for equality, or a positive number for greater-than. A key function is a callable that accepts one - argument and returns another value indicating the position in the desired - collation sequence. + argument and returns another value to be used as the sort key. Example:: sorted(iterable, key=cmp_to_key(locale.strcoll)) # locale-aware sort order + For sorting examples and a brief sorting tutorial, see :ref:`sortinghowto`. + .. versionadded:: 3.2 diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -567,6 +567,7 @@ The *object_pairs_hook* parameter can be used to alter this behavior. .. highlight:: bash +.. module:: json.tool .. _json-commandline: @@ -586,6 +587,10 @@ $ echo '{1.2:3.4}' | python -m json.tool Expecting property name enclosed in double quotes: line 1 column 2 (char 1) +.. versionchanged:: 3.5 + The output is now in the same order as the input. Use the + :option:`--sort-keys` option to sort the output of dictionaries + alphabetically by key. Command line options ^^^^^^^^^^^^^^^^^^^^ @@ -613,6 +618,12 @@ Write the output of the *infile* to the given *outfile*. Otherwise, write it to :attr:`sys.stdout`. +.. cmdoption:: --sort-keys + + Sort the output of dictionaries alphabetically by key. + + .. versionadded:: 3.5 + .. cmdoption:: -h, --help Show the help message. diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -859,7 +859,7 @@ data = { 'a': [1, 2.0, 3, 4+6j], 'b': ("character string", b"byte string"), - 'c': set([None, True, False]) + 'c': {None, True, False} } with open('data.pickle', 'wb') as f: diff --git a/Doc/tutorial/stdlib2.rst b/Doc/tutorial/stdlib2.rst --- a/Doc/tutorial/stdlib2.rst +++ b/Doc/tutorial/stdlib2.rst @@ -18,7 +18,7 @@ >>> import reprlib >>> reprlib.repr(set('supercalifragilisticexpialidocious')) - "set(['a', 'c', 'd', 'e', 'f', 'g', ...])" + "{'a', 'c', 'd', 'e', 'f', 'g', ...}" The :mod:`pprint` module offers more sophisticated control over printing both built-in and user defined objects in a way that is readable by the interpreter. diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -211,6 +211,14 @@ network objects from existing addresses. (Contributed by Peter Moody and Antoine Pitrou in :issue:`16531`.) +json +---- + +* The output of :mod:`json.tool` command line interface is now in the same + order as the input. Use the :option:`--sort-keys` option to sort the output + of dictionaries alphabetically by key. (Contributed by Berker Peksag in + :issue:`21650`.) + os -- diff --git a/Lib/_strptime.py b/Lib/_strptime.py --- a/Lib/_strptime.py +++ b/Lib/_strptime.py @@ -167,9 +167,9 @@ time.tzset() except AttributeError: pass - no_saving = frozenset(["utc", "gmt", time.tzname[0].lower()]) + no_saving = frozenset({"utc", "gmt", time.tzname[0].lower()}) if time.daylight: - has_saving = frozenset([time.tzname[1].lower()]) + has_saving = frozenset({time.tzname[1].lower()}) else: has_saving = frozenset() self.timezone = (no_saving, has_saving) diff --git a/Lib/asyncore.py b/Lib/asyncore.py --- a/Lib/asyncore.py +++ b/Lib/asyncore.py @@ -57,8 +57,8 @@ ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \ errorcode -_DISCONNECTED = frozenset((ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, - EBADF)) +_DISCONNECTED = frozenset({ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, + EBADF}) try: socket_map @@ -220,7 +220,7 @@ connecting = False closing = False addr = None - ignore_log_types = frozenset(['warning']) + ignore_log_types = frozenset({'warning'}) def __init__(self, sock=None, map=None): if map is None: diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -1088,7 +1088,7 @@ _DECIMAL_DIGITS = frozenset('0123456789') # the valid octets for host and netmasks. only useful for IPv4. - _valid_mask_octets = frozenset((255, 254, 252, 248, 240, 224, 192, 128, 0)) + _valid_mask_octets = frozenset({255, 254, 252, 248, 240, 224, 192, 128, 0}) _max_prefixlen = IPV4LENGTH # There are only a handful of valid v4 netmasks, so we cache them all diff --git a/Lib/json/tool.py b/Lib/json/tool.py --- a/Lib/json/tool.py +++ b/Lib/json/tool.py @@ -11,6 +11,7 @@ """ import argparse +import collections import json import sys @@ -24,17 +25,24 @@ help='a JSON file to be validated or pretty-printed') parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'), help='write the output of infile to outfile') + parser.add_argument('--sort-keys', action='store_true', default=False, + help='sort the output of dictionaries alphabetically by key') options = parser.parse_args() infile = options.infile or sys.stdin outfile = options.outfile or sys.stdout + sort_keys = options.sort_keys with infile: try: - obj = json.load(infile) + if sort_keys: + obj = json.load(infile) + else: + obj = json.load(infile, + object_pairs_hook=collections.OrderedDict) except ValueError as e: raise SystemExit(e) with outfile: - json.dump(obj, outfile, sort_keys=True, indent=4) + json.dump(obj, outfile, sort_keys=sort_keys, indent=4) outfile.write('\n') diff --git a/Lib/mailbox.py b/Lib/mailbox.py --- a/Lib/mailbox.py +++ b/Lib/mailbox.py @@ -1230,8 +1230,8 @@ class Babyl(_singlefileMailbox): """An Rmail-style Babyl mailbox.""" - _special_labels = frozenset(('unseen', 'deleted', 'filed', 'answered', - 'forwarded', 'edited', 'resent')) + _special_labels = frozenset({'unseen', 'deleted', 'filed', 'answered', + 'forwarded', 'edited', 'resent'}) def __init__(self, path, factory=None, create=True): """Initialize a Babyl mailbox.""" diff --git a/Lib/reprlib.py b/Lib/reprlib.py --- a/Lib/reprlib.py +++ b/Lib/reprlib.py @@ -87,12 +87,16 @@ return self._repr_iterable(x, level, header, '])', self.maxarray) def repr_set(self, x, level): + if not x: + return 'set()' x = _possibly_sorted(x) - return self._repr_iterable(x, level, 'set([', '])', self.maxset) + return self._repr_iterable(x, level, '{', '}', self.maxset) def repr_frozenset(self, x, level): + if not x: + return 'frozenset()' x = _possibly_sorted(x) - return self._repr_iterable(x, level, 'frozenset([', '])', + return self._repr_iterable(x, level, 'frozenset({', '})', self.maxfrozenset) def repr_deque(self, x, level): diff --git a/Lib/sre_compile.py b/Lib/sre_compile.py --- a/Lib/sre_compile.py +++ b/Lib/sre_compile.py @@ -21,10 +21,10 @@ else: MAXCODE = 0xFFFFFFFF -_LITERAL_CODES = set([LITERAL, NOT_LITERAL]) -_REPEATING_CODES = set([REPEAT, MIN_REPEAT, MAX_REPEAT]) -_SUCCESS_CODES = set([SUCCESS, FAILURE]) -_ASSERT_CODES = set([ASSERT, ASSERT_NOT]) +_LITERAL_CODES = {LITERAL, NOT_LITERAL} +_REPEATING_CODES = {REPEAT, MIN_REPEAT, MAX_REPEAT} +_SUCCESS_CODES = {SUCCESS, FAILURE} +_ASSERT_CODES = {ASSERT, ASSERT_NOT} def _compile(code, pattern, flags): # internal: compile a (sub)pattern diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -24,8 +24,8 @@ WHITESPACE = frozenset(" \t\n\r\v\f") -_REPEATCODES = frozenset((MIN_REPEAT, MAX_REPEAT)) -_UNITCODES = frozenset((ANY, RANGE, IN, LITERAL, NOT_LITERAL, CATEGORY)) +_REPEATCODES = frozenset({MIN_REPEAT, MAX_REPEAT}) +_UNITCODES = frozenset({ANY, RANGE, IN, LITERAL, NOT_LITERAL, CATEGORY}) ESCAPES = { r"\a": (LITERAL, ord("\a")), diff --git a/Lib/statistics.py b/Lib/statistics.py --- a/Lib/statistics.py +++ b/Lib/statistics.py @@ -150,7 +150,7 @@ # We fail as soon as we reach a value that is not an int or the type of # the first value which is not an int. E.g. _sum([int, int, float, int]) # is okay, but sum([int, int, float, Fraction]) is not. - allowed_types = set([int, type(start)]) + allowed_types = {int, type(start)} n, d = _exact_ratio(start) partials = {d: n} # map {denominator: sum of numerators} # Micro-optimizations. @@ -168,7 +168,7 @@ assert allowed_types.pop() is int T = int else: - T = (allowed_types - set([int])).pop() + T = (allowed_types - {int}).pop() if None in partials: assert issubclass(T, (float, Decimal)) assert not math.isfinite(partials[None]) diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py --- a/Lib/test/test_json/test_tool.py +++ b/Lib/test/test_json/test_tool.py @@ -6,6 +6,7 @@ from test import support from test.script_helper import assert_python_ok + class TestTool(unittest.TestCase): data = """ @@ -15,6 +16,28 @@ :"yes"} ] """ + expect_without_sort_keys = textwrap.dedent("""\ + [ + [ + "blorpie" + ], + [ + "whoops" + ], + [], + "d-shtaeou", + "d-nthiouh", + "i-vhbjkhnth", + { + "nifty": 87 + }, + { + "field": "yes", + "morefield": false + } + ] + """) + expect = textwrap.dedent("""\ [ [ @@ -31,8 +54,8 @@ "nifty": 87 }, { - "field": "yes", - "morefield": false + "morefield": false, + "field": "yes" } ] """) @@ -75,3 +98,11 @@ self.assertEqual(rc, 0) self.assertTrue(out.startswith(b'usage: ')) self.assertEqual(err, b'') + + def test_sort_keys_flag(self): + infile = self._create_infile() + rc, out, err = assert_python_ok('-m', 'json.tool', '--sort-keys', infile) + self.assertEqual(rc, 0) + self.assertEqual(out.splitlines(), + self.expect_without_sort_keys.encode().splitlines()) + self.assertEqual(err, b'') diff --git a/Lib/test/test_reprlib.py b/Lib/test/test_reprlib.py --- a/Lib/test/test_reprlib.py +++ b/Lib/test/test_reprlib.py @@ -10,7 +10,7 @@ import importlib.util import unittest -from test.support import run_unittest, create_empty_file, verbose +from test.support import create_empty_file, verbose from reprlib import repr as r # Don't shadow builtin repr from reprlib import Repr from reprlib import recursive_repr @@ -70,18 +70,18 @@ eq(r([1, 2, 3, 4, 5, 6, 7]), "[1, 2, 3, 4, 5, 6, ...]") # Sets give up after 6 as well - eq(r(set([])), "set([])") - eq(r(set([1])), "set([1])") - eq(r(set([1, 2, 3])), "set([1, 2, 3])") - eq(r(set([1, 2, 3, 4, 5, 6])), "set([1, 2, 3, 4, 5, 6])") - eq(r(set([1, 2, 3, 4, 5, 6, 7])), "set([1, 2, 3, 4, 5, 6, ...])") + eq(r(set([])), "set()") + eq(r(set([1])), "{1}") + eq(r(set([1, 2, 3])), "{1, 2, 3}") + eq(r(set([1, 2, 3, 4, 5, 6])), "{1, 2, 3, 4, 5, 6}") + eq(r(set([1, 2, 3, 4, 5, 6, 7])), "{1, 2, 3, 4, 5, 6, ...}") # Frozensets give up after 6 as well - eq(r(frozenset([])), "frozenset([])") - eq(r(frozenset([1])), "frozenset([1])") - eq(r(frozenset([1, 2, 3])), "frozenset([1, 2, 3])") - eq(r(frozenset([1, 2, 3, 4, 5, 6])), "frozenset([1, 2, 3, 4, 5, 6])") - eq(r(frozenset([1, 2, 3, 4, 5, 6, 7])), "frozenset([1, 2, 3, 4, 5, 6, ...])") + eq(r(frozenset([])), "frozenset()") + eq(r(frozenset([1])), "frozenset({1})") + eq(r(frozenset([1, 2, 3])), "frozenset({1, 2, 3})") + eq(r(frozenset([1, 2, 3, 4, 5, 6])), "frozenset({1, 2, 3, 4, 5, 6})") + eq(r(frozenset([1, 2, 3, 4, 5, 6, 7])), "frozenset({1, 2, 3, 4, 5, 6, ...})") # collections.deque after 6 eq(r(deque([1, 2, 3, 4, 5, 6, 7])), "deque([1, 2, 3, 4, 5, 6, ...])") @@ -103,6 +103,20 @@ eq(r(array('i', [1, 2, 3, 4, 5, 6])), "array('i', [1, 2, 3, 4, 5, ...])") + def test_set_literal(self): + eq = self.assertEqual + eq(r({1}), "{1}") + eq(r({1, 2, 3}), "{1, 2, 3}") + eq(r({1, 2, 3, 4, 5, 6}), "{1, 2, 3, 4, 5, 6}") + eq(r({1, 2, 3, 4, 5, 6, 7}), "{1, 2, 3, 4, 5, 6, ...}") + + def test_frozenset(self): + eq = self.assertEqual + eq(r(frozenset({1})), "frozenset({1})") + eq(r(frozenset({1, 2, 3})), "frozenset({1, 2, 3})") + eq(r(frozenset({1, 2, 3, 4, 5, 6})), "frozenset({1, 2, 3, 4, 5, 6})") + eq(r(frozenset({1, 2, 3, 4, 5, 6, 7})), "frozenset({1, 2, 3, 4, 5, 6, ...})") + def test_numbers(self): eq = self.assertEqual eq(r(123), repr(123)) @@ -373,11 +387,5 @@ m.append(m) self.assertEqual(repr(m), '') -def test_main(): - run_unittest(ReprTests) - run_unittest(LongReprTest) - run_unittest(TestRecursiveRepr) - - if __name__ == "__main__": - test_main() + unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -183,9 +183,14 @@ Library ------- +- Issue #21650: Add an `--sort-keys` option to json.tool CLI. + - Issues #814253, #9179: Group references and conditional group references now work in lookbehind assertions in regular expressions. +- Issue #22824: Updated reprlib output format for sets to use set literals. + Patch contributed by Berker Peksag. + - Issue #22406: Fixed the uu_codec codec incorrectly ported to 3.x. Based on patch by Martin Panter. diff --git a/Modules/clinic/fcntlmodule.c.h b/Modules/clinic/fcntlmodule.c.h new file mode 100644 --- /dev/null +++ b/Modules/clinic/fcntlmodule.c.h @@ -0,0 +1,188 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(fcntl_fcntl__doc__, +"fcntl($module, fd, code, arg=None, /)\n" +"--\n" +"\n" +"Perform the operation `code` on file descriptor fd.\n" +"\n" +"The values used for `code` are operating system dependent, and are available\n" +"as constants in the fcntl module, using the same names as used in\n" +"the relevant C header files. The argument arg is optional, and\n" +"defaults to 0; it may be an int or a string. If arg is given as a string,\n" +"the return value of fcntl is a string of that length, containing the\n" +"resulting value put in the arg buffer by the operating system. The length\n" +"of the arg string is not allowed to exceed 1024 bytes. If the arg given\n" +"is an integer or if none is specified, the result value is an integer\n" +"corresponding to the return value of the fcntl call in the C code."); + +#define FCNTL_FCNTL_METHODDEF \ + {"fcntl", (PyCFunction)fcntl_fcntl, METH_VARARGS, fcntl_fcntl__doc__}, + +static PyObject * +fcntl_fcntl_impl(PyModuleDef *module, int fd, int code, PyObject *arg); + +static PyObject * +fcntl_fcntl(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + int fd; + int code; + PyObject *arg = NULL; + + if (!PyArg_ParseTuple(args, + "O&i|O:fcntl", + conv_descriptor, &fd, &code, &arg)) + goto exit; + return_value = fcntl_fcntl_impl(module, fd, code, arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(fcntl_ioctl__doc__, +"ioctl($module, fd, op, arg=None, mutate_flag=True, /)\n" +"--\n" +"\n" +"Perform the operation op on file descriptor fd.\n" +"\n" +"The values used for op are operating system dependent, and are available as\n" +"constants in the fcntl or termios library modules, using the same names as\n" +"used in the relevant C header files.\n" +"\n" +"The argument `arg` is optional, and defaults to 0; it may be an int or a\n" +"buffer containing character data (most likely a string or an array).\n" +"\n" +"If the argument is a mutable buffer (such as an array) and if the\n" +"mutate_flag argument (which is only allowed in this case) is true then the\n" +"buffer is (in effect) passed to the operating system and changes made by\n" +"the OS will be reflected in the contents of the buffer after the call has\n" +"returned. The return value is the integer returned by the ioctl system\n" +"call.\n" +"\n" +"If the argument is a mutable buffer and the mutable_flag argument is not\n" +"passed or is false, the behavior is as if a string had been passed. This\n" +"behavior will change in future releases of Python.\n" +"\n" +"If the argument is an immutable buffer (most likely a string) then a copy\n" +"of the buffer is passed to the operating system and the return value is a\n" +"string of the same length containing whatever the operating system put in\n" +"the buffer. The length of the arg buffer in this case is not allowed to\n" +"exceed 1024 bytes.\n" +"\n" +"If the arg given is an integer or if none is specified, the result value is\n" +"an integer corresponding to the return value of the ioctl call in the C\n" +"code."); + +#define FCNTL_IOCTL_METHODDEF \ + {"ioctl", (PyCFunction)fcntl_ioctl, METH_VARARGS, fcntl_ioctl__doc__}, + +static PyObject * +fcntl_ioctl_impl(PyModuleDef *module, int fd, unsigned int code, PyObject *ob_arg, int mutate_arg); + +static PyObject * +fcntl_ioctl(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + int fd; + unsigned int code; + PyObject *ob_arg = NULL; + int mutate_arg = 1; + + if (!PyArg_ParseTuple(args, + "O&I|Op:ioctl", + conv_descriptor, &fd, &code, &ob_arg, &mutate_arg)) + goto exit; + return_value = fcntl_ioctl_impl(module, fd, code, ob_arg, mutate_arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(fcntl_flock__doc__, +"flock($module, fd, code, /)\n" +"--\n" +"\n" +"Perform the lock operation op on file descriptor fd.\n" +"\n" +"See the Unix manual page for flock(2) for details (On some systems, this\n" +"function is emulated using fcntl())."); + +#define FCNTL_FLOCK_METHODDEF \ + {"flock", (PyCFunction)fcntl_flock, METH_VARARGS, fcntl_flock__doc__}, + +static PyObject * +fcntl_flock_impl(PyModuleDef *module, int fd, int code); + +static PyObject * +fcntl_flock(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + int fd; + int code; + + if (!PyArg_ParseTuple(args, + "O&i:flock", + conv_descriptor, &fd, &code)) + goto exit; + return_value = fcntl_flock_impl(module, fd, code); + +exit: + return return_value; +} + +PyDoc_STRVAR(fcntl_lockf__doc__, +"lockf($module, fd, code, lenobj=None, startobj=None, whence=0, /)\n" +"--\n" +"\n" +"A wrapper around the fcntl() locking calls.\n" +"\n" +"fd is the file descriptor of the file to lock or unlock, and operation is one\n" +"of the following values:\n" +"\n" +" LOCK_UN - unlock\n" +" LOCK_SH - acquire a shared lock\n" +" LOCK_EX - acquire an exclusive lock\n" +"\n" +"When operation is LOCK_SH or LOCK_EX, it can also be bitwise ORed with\n" +"LOCK_NB to avoid blocking on lock acquisition. If LOCK_NB is used and the\n" +"lock cannot be acquired, an IOError will be raised and the exception will\n" +"have an errno attribute set to EACCES or EAGAIN (depending on the operating\n" +"system -- for portability, check for either value).\n" +"\n" +"length is the number of bytes to lock, with the default meaning to lock to\n" +"EOF. start is the byte offset, relative to whence, to that the lock\n" +"starts. whence is as with fileobj.seek(), specifically:\n" +"\n" +" 0 - relative to the start of the file (SEEK_SET)\n" +" 1 - relative to the current buffer position (SEEK_CUR)\n" +" 2 - relative to the end of the file (SEEK_END)"); + +#define FCNTL_LOCKF_METHODDEF \ + {"lockf", (PyCFunction)fcntl_lockf, METH_VARARGS, fcntl_lockf__doc__}, + +static PyObject * +fcntl_lockf_impl(PyModuleDef *module, int fd, int code, PyObject *lenobj, PyObject *startobj, int whence); + +static PyObject * +fcntl_lockf(PyModuleDef *module, PyObject *args) +{ + PyObject *return_value = NULL; + int fd; + int code; + PyObject *lenobj = NULL; + PyObject *startobj = NULL; + int whence = 0; + + if (!PyArg_ParseTuple(args, + "O&i|OOi:lockf", + conv_descriptor, &fd, &code, &lenobj, &startobj, &whence)) + goto exit; + return_value = fcntl_lockf_impl(module, fd, code, lenobj, startobj, whence); + +exit: + return return_value; +} +/*[clinic end generated code: output=84bdde73a92f7c61 input=a9049054013a1b77]*/ diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c --- a/Modules/fcntlmodule.c +++ b/Modules/fcntlmodule.c @@ -15,6 +15,12 @@ #include #endif +/*[clinic input] +output preset file +module fcntl +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c7356fdb126a904a]*/ + static int conv_descriptor(PyObject *object, int *target) { @@ -26,48 +32,72 @@ return 1; } +/* Must come after conv_descriptor definition. */ +#include "clinic/fcntlmodule.c.h" -/* fcntl(fd, op, [arg]) */ +/*[clinic input] +fcntl.fcntl + + fd: object(type='int', converter='conv_descriptor') + code: int + arg: object = NULL + / + +Perform the operation `code` on file descriptor fd. + +The values used for `code` are operating system dependent, and are available +as constants in the fcntl module, using the same names as used in +the relevant C header files. The argument arg is optional, and +defaults to 0; it may be an int or a string. If arg is given as a string, +the return value of fcntl is a string of that length, containing the +resulting value put in the arg buffer by the operating system. The length +of the arg string is not allowed to exceed 1024 bytes. If the arg given +is an integer or if none is specified, the result value is an integer +corresponding to the return value of the fcntl call in the C code. +[clinic start generated code]*/ static PyObject * -fcntl_fcntl(PyObject *self, PyObject *args) +fcntl_fcntl_impl(PyModuleDef *module, int fd, int code, PyObject *arg) +/*[clinic end generated code: output=afc5bfa74a03ef0d input=4850c13a41e86930]*/ { - int fd; - int code; - long arg; + int int_arg = 0; int ret; char *str; Py_ssize_t len; char buf[1024]; - if (PyArg_ParseTuple(args, "O&is#:fcntl", - conv_descriptor, &fd, &code, &str, &len)) { - if ((size_t)len > sizeof buf) { - PyErr_SetString(PyExc_ValueError, - "fcntl string arg too long"); - return NULL; + if (arg != NULL) { + int parse_result; + + if (PyArg_Parse(arg, "s#", &str, &len)) { + if ((size_t)len > sizeof buf) { + PyErr_SetString(PyExc_ValueError, + "fcntl string arg too long"); + return NULL; + } + memcpy(buf, str, len); + Py_BEGIN_ALLOW_THREADS + ret = fcntl(fd, code, buf); + Py_END_ALLOW_THREADS + if (ret < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + return PyBytes_FromStringAndSize(buf, len); } - memcpy(buf, str, len); - Py_BEGIN_ALLOW_THREADS - ret = fcntl(fd, code, buf); - Py_END_ALLOW_THREADS - if (ret < 0) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; + + PyErr_Clear(); + parse_result = PyArg_Parse(arg, + "l;fcntl requires a file or file descriptor," + " an integer and optionally a third integer or a string", + &int_arg); + if (!parse_result) { + return NULL; } - return PyBytes_FromStringAndSize(buf, len); } - PyErr_Clear(); - arg = 0; - if (!PyArg_ParseTuple(args, - "O&i|l;fcntl requires a file or file descriptor," - " an integer and optionally a third integer or a string", - conv_descriptor, &fd, &code, &arg)) { - return NULL; - } Py_BEGIN_ALLOW_THREADS - ret = fcntl(fd, code, arg); + ret = fcntl(fd, code, int_arg); Py_END_ALLOW_THREADS if (ret < 0) { PyErr_SetFromErrno(PyExc_IOError); @@ -76,29 +106,53 @@ return PyLong_FromLong((long)ret); } -PyDoc_STRVAR(fcntl_doc, -"fcntl(fd, op, [arg])\n\ -\n\ -Perform the operation op on file descriptor fd. The values used\n\ -for op are operating system dependent, and are available\n\ -as constants in the fcntl module, using the same names as used in\n\ -the relevant C header files. The argument arg is optional, and\n\ -defaults to 0; it may be an int or a string. If arg is given as a string,\n\ -the return value of fcntl is a string of that length, containing the\n\ -resulting value put in the arg buffer by the operating system. The length\n\ -of the arg string is not allowed to exceed 1024 bytes. If the arg given\n\ -is an integer or if none is specified, the result value is an integer\n\ -corresponding to the return value of the fcntl call in the C code."); +/*[clinic input] +fcntl.ioctl -/* ioctl(fd, op, [arg]) */ + fd: object(type='int', converter='conv_descriptor') + op as code: unsigned_int(bitwise=True) + arg as ob_arg: object = NULL + mutate_flag as mutate_arg: bool = True + / + +Perform the operation op on file descriptor fd. + +The values used for op are operating system dependent, and are available as +constants in the fcntl or termios library modules, using the same names as +used in the relevant C header files. + +The argument `arg` is optional, and defaults to 0; it may be an int or a +buffer containing character data (most likely a string or an array). + +If the argument is a mutable buffer (such as an array) and if the +mutate_flag argument (which is only allowed in this case) is true then the +buffer is (in effect) passed to the operating system and changes made by +the OS will be reflected in the contents of the buffer after the call has +returned. The return value is the integer returned by the ioctl system +call. + +If the argument is a mutable buffer and the mutable_flag argument is not +passed or is false, the behavior is as if a string had been passed. This +behavior will change in future releases of Python. + +If the argument is an immutable buffer (most likely a string) then a copy +of the buffer is passed to the operating system and the return value is a +string of the same length containing whatever the operating system put in +the buffer. The length of the arg buffer in this case is not allowed to +exceed 1024 bytes. + +If the arg given is an integer or if none is specified, the result value is +an integer corresponding to the return value of the ioctl call in the C +code. +[clinic start generated code]*/ static PyObject * -fcntl_ioctl(PyObject *self, PyObject *args) +fcntl_ioctl_impl(PyModuleDef *module, int fd, unsigned int code, PyObject *ob_arg, int mutate_arg) +/*[clinic end generated code: output=ad47738c118622bf input=a55a6ee8e494c449]*/ { #define IOCTL_BUFSZ 1024 - int fd; - /* In PyArg_ParseTuple below, we use the unsigned non-checked 'I' + /* We use the unsigned non-checked 'I' format for the 'code' parameter because Python turns 0x8000000 into either a large positive number (PyLong or PyInt on 64-bit platforms) or a negative number on others (32-bit PyInt) @@ -111,101 +165,98 @@ in their unsigned long ioctl codes this will break and need special casing based on the platform being built on. */ - unsigned int code; - int arg; + int arg = 0; int ret; Py_buffer pstr; char *str; Py_ssize_t len; - int mutate_arg = 1; char buf[IOCTL_BUFSZ+1]; /* argument plus NUL byte */ - if (PyArg_ParseTuple(args, "O&Iw*|i:ioctl", - conv_descriptor, &fd, &code, - &pstr, &mutate_arg)) { - char *arg; - str = pstr.buf; - len = pstr.len; + if (ob_arg != NULL) { + if (PyArg_Parse(ob_arg, "w*:ioctl", &pstr)) { + char *arg; + str = pstr.buf; + len = pstr.len; - if (mutate_arg) { - if (len <= IOCTL_BUFSZ) { - memcpy(buf, str, len); - buf[len] = '\0'; - arg = buf; + if (mutate_arg) { + if (len <= IOCTL_BUFSZ) { + memcpy(buf, str, len); + buf[len] = '\0'; + arg = buf; + } + else { + arg = str; + } } else { - arg = str; + if (len > IOCTL_BUFSZ) { + PyBuffer_Release(&pstr); + PyErr_SetString(PyExc_ValueError, + "ioctl string arg too long"); + return NULL; + } + else { + memcpy(buf, str, len); + buf[len] = '\0'; + arg = buf; + } + } + if (buf == arg) { + Py_BEGIN_ALLOW_THREADS /* think array.resize() */ + ret = ioctl(fd, code, arg); + Py_END_ALLOW_THREADS + } + else { + ret = ioctl(fd, code, arg); + } + if (mutate_arg && (len <= IOCTL_BUFSZ)) { + memcpy(str, buf, len); + } + PyBuffer_Release(&pstr); /* No further access to str below this point */ + if (ret < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + if (mutate_arg) { + return PyLong_FromLong(ret); + } + else { + return PyBytes_FromStringAndSize(buf, len); } } - else { + + PyErr_Clear(); + if (PyArg_Parse(ob_arg, "s*:ioctl", &pstr)) { + str = pstr.buf; + len = pstr.len; if (len > IOCTL_BUFSZ) { PyBuffer_Release(&pstr); PyErr_SetString(PyExc_ValueError, - "ioctl string arg too long"); + "ioctl string arg too long"); return NULL; } - else { - memcpy(buf, str, len); - buf[len] = '\0'; - arg = buf; + memcpy(buf, str, len); + buf[len] = '\0'; + Py_BEGIN_ALLOW_THREADS + ret = ioctl(fd, code, buf); + Py_END_ALLOW_THREADS + if (ret < 0) { + PyBuffer_Release(&pstr); + PyErr_SetFromErrno(PyExc_IOError); + return NULL; } - } - if (buf == arg) { - Py_BEGIN_ALLOW_THREADS /* think array.resize() */ - ret = ioctl(fd, code, arg); - Py_END_ALLOW_THREADS - } - else { - ret = ioctl(fd, code, arg); - } - if (mutate_arg && (len <= IOCTL_BUFSZ)) { - memcpy(str, buf, len); - } - PyBuffer_Release(&pstr); /* No further access to str below this point */ - if (ret < 0) { - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - if (mutate_arg) { - return PyLong_FromLong(ret); - } - else { + PyBuffer_Release(&pstr); return PyBytes_FromStringAndSize(buf, len); } - } - PyErr_Clear(); - if (PyArg_ParseTuple(args, "O&Is*:ioctl", - conv_descriptor, &fd, &code, &pstr)) { - str = pstr.buf; - len = pstr.len; - if (len > IOCTL_BUFSZ) { - PyBuffer_Release(&pstr); - PyErr_SetString(PyExc_ValueError, - "ioctl string arg too long"); - return NULL; + PyErr_Clear(); + if (!PyArg_Parse(ob_arg, + "i;ioctl requires a file or file descriptor," + " an integer and optionally an integer or buffer argument", + &arg)) { + return NULL; } - memcpy(buf, str, len); - buf[len] = '\0'; - Py_BEGIN_ALLOW_THREADS - ret = ioctl(fd, code, buf); - Py_END_ALLOW_THREADS - if (ret < 0) { - PyBuffer_Release(&pstr); - PyErr_SetFromErrno(PyExc_IOError); - return NULL; - } - PyBuffer_Release(&pstr); - return PyBytes_FromStringAndSize(buf, len); - } - - PyErr_Clear(); - arg = 0; - if (!PyArg_ParseTuple(args, - "O&I|i;ioctl requires a file or file descriptor," - " an integer and optionally an integer or buffer argument", - conv_descriptor, &fd, &code, &arg)) { - return NULL; + // Fall-through to outside the 'if' statement. } Py_BEGIN_ALLOW_THREADS ret = ioctl(fd, code, arg); @@ -218,52 +269,25 @@ #undef IOCTL_BUFSZ } -PyDoc_STRVAR(ioctl_doc, -"ioctl(fd, op[, arg[, mutate_flag]])\n\ -\n\ -Perform the operation op on file descriptor fd. The values used for op\n\ -are operating system dependent, and are available as constants in the\n\ -fcntl or termios library modules, using the same names as used in the\n\ -relevant C header files.\n\ -\n\ -The argument arg is optional, and defaults to 0; it may be an int or a\n\ -buffer containing character data (most likely a string or an array). \n\ -\n\ -If the argument is a mutable buffer (such as an array) and if the\n\ -mutate_flag argument (which is only allowed in this case) is true then the\n\ -buffer is (in effect) passed to the operating system and changes made by\n\ -the OS will be reflected in the contents of the buffer after the call has\n\ -returned. The return value is the integer returned by the ioctl system\n\ -call.\n\ -\n\ -If the argument is a mutable buffer and the mutable_flag argument is not\n\ -passed or is false, the behavior is as if a string had been passed. This\n\ -behavior will change in future releases of Python.\n\ -\n\ -If the argument is an immutable buffer (most likely a string) then a copy\n\ -of the buffer is passed to the operating system and the return value is a\n\ -string of the same length containing whatever the operating system put in\n\ -the buffer. The length of the arg buffer in this case is not allowed to\n\ -exceed 1024 bytes.\n\ -\n\ -If the arg given is an integer or if none is specified, the result value is\n\ -an integer corresponding to the return value of the ioctl call in the C\n\ -code."); +/*[clinic input] +fcntl.flock + fd: object(type='int', converter='conv_descriptor') + code: int + / -/* flock(fd, operation) */ +Perform the lock operation op on file descriptor fd. + +See the Unix manual page for flock(2) for details (On some systems, this +function is emulated using fcntl()). +[clinic start generated code]*/ static PyObject * -fcntl_flock(PyObject *self, PyObject *args) +fcntl_flock_impl(PyModuleDef *module, int fd, int code) +/*[clinic end generated code: output=c9035133a7dbfc96 input=b762aa9448d05e43]*/ { - int fd; - int code; int ret; - if (!PyArg_ParseTuple(args, "O&i:flock", - conv_descriptor, &fd, &code)) - return NULL; - #ifdef HAVE_FLOCK Py_BEGIN_ALLOW_THREADS ret = flock(fd, code); @@ -299,29 +323,49 @@ PyErr_SetFromErrno(PyExc_IOError); return NULL; } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } -PyDoc_STRVAR(flock_doc, -"flock(fd, operation)\n\ -\n\ -Perform the lock operation op on file descriptor fd. See the Unix \n\ -manual page for flock(2) for details. (On some systems, this function is\n\ -emulated using fcntl().)"); +/*[clinic input] +fcntl.lockf -/* lockf(fd, operation) */ + fd: object(type='int', converter='conv_descriptor') + code: int + lenobj: object = NULL + startobj: object = NULL + whence: int = 0 + / + +A wrapper around the fcntl() locking calls. + +fd is the file descriptor of the file to lock or unlock, and operation is one +of the following values: + + LOCK_UN - unlock + LOCK_SH - acquire a shared lock + LOCK_EX - acquire an exclusive lock + +When operation is LOCK_SH or LOCK_EX, it can also be bitwise ORed with +LOCK_NB to avoid blocking on lock acquisition. If LOCK_NB is used and the +lock cannot be acquired, an IOError will be raised and the exception will +have an errno attribute set to EACCES or EAGAIN (depending on the operating +system -- for portability, check for either value). + +length is the number of bytes to lock, with the default meaning to lock to +EOF. start is the byte offset, relative to whence, to that the lock +starts. whence is as with fileobj.seek(), specifically: + + 0 - relative to the start of the file (SEEK_SET) + 1 - relative to the current buffer position (SEEK_CUR) + 2 - relative to the end of the file (SEEK_END) +[clinic start generated code]*/ + static PyObject * -fcntl_lockf(PyObject *self, PyObject *args) +fcntl_lockf_impl(PyModuleDef *module, int fd, int code, PyObject *lenobj, PyObject *startobj, int whence) +/*[clinic end generated code: output=5536df2892bf3ce9 input=44856fa06db36184]*/ { - int fd, code, ret, whence = 0; - PyObject *lenobj = NULL, *startobj = NULL; - - if (!PyArg_ParseTuple(args, "O&i|OOi:lockf", - conv_descriptor, &fd, &code, - &lenobj, &startobj, &whence)) - return NULL; + int ret; #ifndef LOCK_SH #define LOCK_SH 1 /* shared lock */ @@ -374,43 +418,17 @@ PyErr_SetFromErrno(PyExc_IOError); return NULL; } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } -PyDoc_STRVAR(lockf_doc, -"lockf (fd, operation, length=0, start=0, whence=0)\n\ -\n\ -This is essentially a wrapper around the fcntl() locking calls. fd is the\n\ -file descriptor of the file to lock or unlock, and operation is one of the\n\ -following values:\n\ -\n\ - LOCK_UN - unlock\n\ - LOCK_SH - acquire a shared lock\n\ - LOCK_EX - acquire an exclusive lock\n\ -\n\ -When operation is LOCK_SH or LOCK_EX, it can also be bitwise ORed with\n\ -LOCK_NB to avoid blocking on lock acquisition. If LOCK_NB is used and the\n\ -lock cannot be acquired, an IOError will be raised and the exception will\n\ -have an errno attribute set to EACCES or EAGAIN (depending on the operating\n\ -system -- for portability, check for either value).\n\ -\n\ -length is the number of bytes to lock, with the default meaning to lock to\n\ -EOF. start is the byte offset, relative to whence, to that the lock\n\ -starts. whence is as with fileobj.seek(), specifically:\n\ -\n\ - 0 - relative to the start of the file (SEEK_SET)\n\ - 1 - relative to the current buffer position (SEEK_CUR)\n\ - 2 - relative to the end of the file (SEEK_END)"); - /* List of functions */ static PyMethodDef fcntl_methods[] = { - {"fcntl", fcntl_fcntl, METH_VARARGS, fcntl_doc}, - {"ioctl", fcntl_ioctl, METH_VARARGS, ioctl_doc}, - {"flock", fcntl_flock, METH_VARARGS, flock_doc}, - {"lockf", fcntl_lockf, METH_VARARGS, lockf_doc}, - {NULL, NULL} /* sentinel */ + FCNTL_FCNTL_METHODDEF + FCNTL_IOCTL_METHODDEF + FCNTL_FLOCK_METHODDEF + FCNTL_LOCKF_METHODDEF + {NULL, NULL} /* sentinel */ }; diff --git a/Parser/asdl.py b/Parser/asdl.py --- a/Parser/asdl.py +++ b/Parser/asdl.py @@ -33,8 +33,7 @@ # See the EBNF at the top of the file to understand the logical connection # between the various node types. -builtin_types = set( - ['identifier', 'string', 'bytes', 'int', 'object', 'singleton']) +builtin_types = {'identifier', 'string', 'bytes', 'int', 'object', 'singleton'} class AST: def __repr__(self): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 10:29:55 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 10 Nov 2014 09:29:55 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyODIx?= =?utf-8?q?=3A_Fixed_fcntl=28=29_with_integer_argument_on_64-bit_big-endia?= =?utf-8?q?n?= Message-ID: <20141110092952.699.35208@psf.io> https://hg.python.org/cpython/rev/45e8aed69767 changeset: 93454:45e8aed69767 branch: 3.4 parent: 93444:63274cf1b40d user: Serhiy Storchaka date: Mon Nov 10 10:42:26 2014 +0200 summary: Issue #22821: Fixed fcntl() with integer argument on 64-bit big-endian platforms. files: Misc/NEWS | 3 +++ Modules/fcntlmodule.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,9 @@ Library ------- +- Issue #22821: Fixed fcntl() with integer argument on 64-bit big-endian + platforms. + - Issues #814253, #9179: Group references and conditional group references now work in lookbehind assertions in regular expressions. diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c --- a/Modules/fcntlmodule.c +++ b/Modules/fcntlmodule.c @@ -34,7 +34,7 @@ { int fd; int code; - long arg; + int arg; int ret; char *str; Py_ssize_t len; @@ -61,7 +61,7 @@ PyErr_Clear(); arg = 0; if (!PyArg_ParseTuple(args, - "O&i|l;fcntl requires a file or file descriptor," + "O&i|I;fcntl requires a file or file descriptor," " an integer and optionally a third integer or a string", conv_descriptor, &fd, &code, &arg)) { return NULL; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 10:29:55 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 10 Nov 2014 09:29:55 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322821=3A_Fixed_fcntl=28=29_with_integer_argumen?= =?utf-8?q?t_on_64-bit_big-endian?= Message-ID: <20141110092952.85202.88603@psf.io> https://hg.python.org/cpython/rev/2d203a0b7908 changeset: 93455:2d203a0b7908 parent: 93452:8111ee79d27c parent: 93454:45e8aed69767 user: Serhiy Storchaka date: Mon Nov 10 11:25:50 2014 +0200 summary: Issue #22821: Fixed fcntl() with integer argument on 64-bit big-endian platforms. files: Misc/NEWS | 3 +++ Modules/fcntlmodule.c | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -183,6 +183,9 @@ Library ------- +- Issue #22821: Fixed fcntl() with integer argument on 64-bit big-endian + platforms. + - Issue #21650: Add an `--sort-keys` option to json.tool CLI. - Issues #814253, #9179: Group references and conditional group references now diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c --- a/Modules/fcntlmodule.c +++ b/Modules/fcntlmodule.c @@ -60,7 +60,7 @@ fcntl_fcntl_impl(PyModuleDef *module, int fd, int code, PyObject *arg) /*[clinic end generated code: output=afc5bfa74a03ef0d input=4850c13a41e86930]*/ { - int int_arg = 0; + unsigned int int_arg = 0; int ret; char *str; Py_ssize_t len; @@ -88,7 +88,7 @@ PyErr_Clear(); parse_result = PyArg_Parse(arg, - "l;fcntl requires a file or file descriptor," + "I;fcntl requires a file or file descriptor," " an integer and optionally a third integer or a string", &int_arg); if (!parse_result) { @@ -97,7 +97,7 @@ } Py_BEGIN_ALLOW_THREADS - ret = fcntl(fd, code, int_arg); + ret = fcntl(fd, code, (int)int_arg); Py_END_ALLOW_THREADS if (ret < 0) { PyErr_SetFromErrno(PyExc_IOError); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 10:29:55 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 10 Nov 2014 09:29:55 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIyODIx?= =?utf-8?q?=3A_Fixed_fcntl=28=29_with_integer_argument_on_64-bit_big-endia?= =?utf-8?q?n?= Message-ID: <20141110092952.113476.92406@psf.io> https://hg.python.org/cpython/rev/61e99438c237 changeset: 93453:61e99438c237 branch: 2.7 parent: 93448:3a8e0a5359cf user: Serhiy Storchaka date: Mon Nov 10 10:42:06 2014 +0200 summary: Issue #22821: Fixed fcntl() with integer argument on 64-bit big-endian platforms. files: Misc/NEWS | 3 +++ Modules/fcntlmodule.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,6 +37,9 @@ Library ------- +- Issue #22821: Fixed fcntl() with integer argument on 64-bit big-endian + platforms. + - Issues #814253, #9179: Group references and conditional group references now work in lookbehind assertions in regular expressions. diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c --- a/Modules/fcntlmodule.c +++ b/Modules/fcntlmodule.c @@ -34,7 +34,7 @@ { int fd; int code; - long arg; + int arg; int ret; char *str; Py_ssize_t len; @@ -61,7 +61,7 @@ PyErr_Clear(); arg = 0; if (!PyArg_ParseTuple(args, - "O&i|l;fcntl requires a file or file descriptor," + "O&i|I;fcntl requires a file or file descriptor," " an integer and optionally a third integer or a string", conv_descriptor, &fd, &code, &arg)) { return NULL; -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Mon Nov 10 10:32:00 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 10 Nov 2014 10:32:00 +0100 Subject: [Python-checkins] Daily reference leaks (55b89e5f9c37): sum=3 Message-ID: results for 55b89e5f9c37 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogocLb0X', '-x'] From python-checkins at python.org Mon Nov 10 11:47:06 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 10 Nov 2014 10:47:06 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzEyNzI4?= =?utf-8?q?=3A_Different_Unicode_characters_having_the_same_uppercase_but?= Message-ID: <20141110104704.108389.60853@psf.io> https://hg.python.org/cpython/rev/47b3084dd6aa changeset: 93457:47b3084dd6aa branch: 3.4 parent: 93454:45e8aed69767 user: Serhiy Storchaka date: Mon Nov 10 12:37:16 2014 +0200 summary: Issue #12728: Different Unicode characters having the same uppercase but different lowercase are now matched in case-insensitive regular expressions. files: Lib/sre_compile.py | 92 +++++++++++++++++++++++++++++--- Lib/test/test_re.py | 51 ++++++++++++++++++ Misc/NEWS | 3 + 3 files changed, 135 insertions(+), 11 deletions(-) diff --git a/Lib/sre_compile.py b/Lib/sre_compile.py --- a/Lib/sre_compile.py +++ b/Lib/sre_compile.py @@ -27,6 +27,46 @@ _SUCCESS_CODES = set([SUCCESS, FAILURE]) _ASSERT_CODES = set([ASSERT, ASSERT_NOT]) +# Sets of lowercase characters which have the same uppercase. +_equivalences = ( + # LATIN SMALL LETTER I, LATIN SMALL LETTER DOTLESS I + (0x69, 0x131), # i? + # LATIN SMALL LETTER S, LATIN SMALL LETTER LONG S + (0x73, 0x17f), # s? + # MICRO SIGN, GREEK SMALL LETTER MU + (0xb5, 0x3bc), # ?? + # COMBINING GREEK YPOGEGRAMMENI, GREEK SMALL LETTER IOTA, GREEK PROSGEGRAMMENI + (0x345, 0x3b9, 0x1fbe), # \u0345?? + # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS, GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA + (0x390, 0x1fd3), # ?? + # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS, GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA + (0x3b0, 0x1fe3), # ?? + # GREEK SMALL LETTER BETA, GREEK BETA SYMBOL + (0x3b2, 0x3d0), # ?? + # GREEK SMALL LETTER EPSILON, GREEK LUNATE EPSILON SYMBOL + (0x3b5, 0x3f5), # ?? + # GREEK SMALL LETTER THETA, GREEK THETA SYMBOL + (0x3b8, 0x3d1), # ?? + # GREEK SMALL LETTER KAPPA, GREEK KAPPA SYMBOL + (0x3ba, 0x3f0), # ?? + # GREEK SMALL LETTER PI, GREEK PI SYMBOL + (0x3c0, 0x3d6), # ?? + # GREEK SMALL LETTER RHO, GREEK RHO SYMBOL + (0x3c1, 0x3f1), # ?? + # GREEK SMALL LETTER FINAL SIGMA, GREEK SMALL LETTER SIGMA + (0x3c2, 0x3c3), # ?? + # GREEK SMALL LETTER PHI, GREEK PHI SYMBOL + (0x3c6, 0x3d5), # ?? + # LATIN SMALL LETTER S WITH DOT ABOVE, LATIN SMALL LETTER LONG S WITH DOT ABOVE + (0x1e61, 0x1e9b), # ?? + # LATIN SMALL LIGATURE LONG S T, LATIN SMALL LIGATURE ST + (0xfb05, 0xfb06), # ?? +) + +# Maps the lowercase code to lowercase codes which have the same uppercase. +_ignorecase_fixes = {i: tuple(j for j in t if i != j) + for t in _equivalences for i in t} + def _compile(code, pattern, flags): # internal: compile a (sub)pattern emit = code.append @@ -35,11 +75,29 @@ REPEATING_CODES = _REPEATING_CODES SUCCESS_CODES = _SUCCESS_CODES ASSERT_CODES = _ASSERT_CODES + if (flags & SRE_FLAG_IGNORECASE and + not (flags & SRE_FLAG_LOCALE) and + flags & SRE_FLAG_UNICODE): + fixes = _ignorecase_fixes + else: + fixes = None for op, av in pattern: if op in LITERAL_CODES: if flags & SRE_FLAG_IGNORECASE: - emit(OPCODES[OP_IGNORE[op]]) - emit(_sre.getlower(av, flags)) + lo = _sre.getlower(av, flags) + if fixes and lo in fixes: + emit(OPCODES[IN_IGNORE]) + skip = _len(code); emit(0) + if op is NOT_LITERAL: + emit(OPCODES[NEGATE]) + for k in (lo,) + fixes[lo]: + emit(OPCODES[LITERAL]) + emit(k) + emit(OPCODES[FAILURE]) + code[skip] = _len(code) - skip + else: + emit(OPCODES[OP_IGNORE[op]]) + emit(lo) else: emit(OPCODES[op]) emit(av) @@ -52,7 +110,7 @@ emit(OPCODES[op]) fixup = None skip = _len(code); emit(0) - _compile_charset(av, flags, code, fixup) + _compile_charset(av, flags, code, fixup, fixes) code[skip] = _len(code) - skip elif op is ANY: if flags & SRE_FLAG_DOTALL: @@ -166,10 +224,11 @@ else: raise ValueError("unsupported operand type", op) -def _compile_charset(charset, flags, code, fixup=None): +def _compile_charset(charset, flags, code, fixup=None, fixes=None): # compile charset subprogram emit = code.append - for op, av in _optimize_charset(charset, fixup, flags & SRE_FLAG_UNICODE): + for op, av in _optimize_charset(charset, fixup, fixes, + flags & SRE_FLAG_UNICODE): emit(OPCODES[op]) if op is NEGATE: pass @@ -193,7 +252,7 @@ raise error("internal: unsupported set operator") emit(OPCODES[FAILURE]) -def _optimize_charset(charset, fixup, isunicode): +def _optimize_charset(charset, fixup, fixes, isunicode): # internal: optimize character set out = [] tail = [] @@ -202,16 +261,27 @@ while True: try: if op is LITERAL: - i = av if fixup: - i = fixup(i) - charmap[i] = 1 + i = fixup(av) + charmap[i] = 1 + if fixes and i in fixes: + for k in fixes[i]: + charmap[k] = 1 + else: + charmap[av] = 1 elif op is RANGE: r = range(av[0], av[1]+1) if fixup: r = map(fixup, r) - for i in r: - charmap[i] = 1 + if fixup and fixes: + for i in r: + charmap[i] = 1 + if i in fixes: + for k in fixes[i]: + charmap[k] = 1 + else: + for i in r: + charmap[i] = 1 elif op is NEGATE: out.append((op, av)) else: diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -619,6 +619,43 @@ self.assertEqual(re.match(r"((a)\s(abc|a))", "a a", re.I).group(1), "a a") self.assertEqual(re.match(r"((a)\s(abc|a)*)", "a aa", re.I).group(1), "a aa") + assert '\u212a'.lower() == 'k' # '?' + self.assertTrue(re.match(r'K', '\u212a', re.I)) + self.assertTrue(re.match(r'k', '\u212a', re.I)) + self.assertTrue(re.match(r'\u212a', 'K', re.I)) + self.assertTrue(re.match(r'\u212a', 'k', re.I)) + assert '\u017f'.upper() == 'S' # '?' + self.assertTrue(re.match(r'S', '\u017f', re.I)) + self.assertTrue(re.match(r's', '\u017f', re.I)) + self.assertTrue(re.match(r'\u017f', 'S', re.I)) + self.assertTrue(re.match(r'\u017f', 's', re.I)) + assert '\ufb05'.upper() == '\ufb06'.upper() == 'ST' # '?', '?' + self.assertTrue(re.match(r'\ufb05', '\ufb06', re.I)) + self.assertTrue(re.match(r'\ufb06', '\ufb05', re.I)) + + def test_ignore_case_set(self): + self.assertTrue(re.match(r'[19A]', 'A', re.I)) + self.assertTrue(re.match(r'[19a]', 'a', re.I)) + self.assertTrue(re.match(r'[19a]', 'A', re.I)) + self.assertTrue(re.match(r'[19A]', 'a', re.I)) + self.assertTrue(re.match(br'[19A]', b'A', re.I)) + self.assertTrue(re.match(br'[19a]', b'a', re.I)) + self.assertTrue(re.match(br'[19a]', b'A', re.I)) + self.assertTrue(re.match(br'[19A]', b'a', re.I)) + assert '\u212a'.lower() == 'k' # '?' + self.assertTrue(re.match(r'[19K]', '\u212a', re.I)) + self.assertTrue(re.match(r'[19k]', '\u212a', re.I)) + self.assertTrue(re.match(r'[19\u212a]', 'K', re.I)) + self.assertTrue(re.match(r'[19\u212a]', 'k', re.I)) + assert '\u017f'.upper() == 'S' # '?' + self.assertTrue(re.match(r'[19S]', '\u017f', re.I)) + self.assertTrue(re.match(r'[19s]', '\u017f', re.I)) + self.assertTrue(re.match(r'[19\u017f]', 'S', re.I)) + self.assertTrue(re.match(r'[19\u017f]', 's', re.I)) + assert '\ufb05'.upper() == '\ufb06'.upper() == 'ST' # '?', '?' + self.assertTrue(re.match(r'[19\ufb05]', '\ufb06', re.I)) + self.assertTrue(re.match(r'[19\ufb06]', '\ufb05', re.I)) + def test_ignore_case_range(self): # Issues #3511, #17381. self.assertTrue(re.match(r'[9-a]', '_', re.I)) @@ -638,6 +675,20 @@ self.assertTrue(re.match(r'[\U00010400-\U00010427]', '\U00010428', re.I)) self.assertTrue(re.match(r'[\U00010400-\U00010427]', '\U00010400', re.I)) + assert '\u212a'.lower() == 'k' # '?' + self.assertTrue(re.match(r'[J-M]', '\u212a', re.I)) + self.assertTrue(re.match(r'[j-m]', '\u212a', re.I)) + self.assertTrue(re.match(r'[\u2129-\u212b]', 'K', re.I)) + self.assertTrue(re.match(r'[\u2129-\u212b]', 'k', re.I)) + assert '\u017f'.upper() == 'S' # '?' + self.assertTrue(re.match(r'[R-T]', '\u017f', re.I)) + self.assertTrue(re.match(r'[r-t]', '\u017f', re.I)) + self.assertTrue(re.match(r'[\u017e-\u0180]', 'S', re.I)) + self.assertTrue(re.match(r'[\u017e-\u0180]', 's', re.I)) + assert '\ufb05'.upper() == '\ufb06'.upper() == 'ST' # '?', '?' + self.assertTrue(re.match(r'[\ufb04-\ufb05]', '\ufb06', re.I)) + self.assertTrue(re.match(r'[\ufb06-\ufb07]', '\ufb05', re.I)) + def test_category(self): self.assertEqual(re.match(r"(\s)", " ").group(1), " ") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,9 @@ Library ------- +- Issue #12728: Different Unicode characters having the same uppercase but + different lowercase are now matched in case-insensitive regular expressions. + - Issue #22821: Fixed fcntl() with integer argument on 64-bit big-endian platforms. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 11:47:06 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 10 Nov 2014 10:47:06 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzEyNzI4?= =?utf-8?q?=3A_Different_Unicode_characters_having_the_same_uppercase_but?= Message-ID: <20141110104703.108089.3658@psf.io> https://hg.python.org/cpython/rev/4caa695af94c changeset: 93456:4caa695af94c branch: 2.7 parent: 93453:61e99438c237 user: Serhiy Storchaka date: Mon Nov 10 12:37:02 2014 +0200 summary: Issue #12728: Different Unicode characters having the same uppercase but different lowercase are now matched in case-insensitive regular expressions. files: Lib/sre_compile.py | 87 ++++++++++++++++++++++++++++---- Lib/test/test_re.py | 45 +++++++++++++++++ Misc/NEWS | 3 + 3 files changed, 124 insertions(+), 11 deletions(-) diff --git a/Lib/sre_compile.py b/Lib/sre_compile.py --- a/Lib/sre_compile.py +++ b/Lib/sre_compile.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # # Secret Labs' Regular Expression Engine # @@ -26,6 +27,40 @@ _SUCCESS_CODES = set([SUCCESS, FAILURE]) _ASSERT_CODES = set([ASSERT, ASSERT_NOT]) +# Sets of lowercase characters which have the same uppercase. +_equivalences = ( + # LATIN SMALL LETTER I, LATIN SMALL LETTER DOTLESS I + (0x69, 0x131), # i? + # LATIN SMALL LETTER S, LATIN SMALL LETTER LONG S + (0x73, 0x17f), # s? + # MICRO SIGN, GREEK SMALL LETTER MU + (0xb5, 0x3bc), # ?? + # COMBINING GREEK YPOGEGRAMMENI, GREEK SMALL LETTER IOTA, GREEK PROSGEGRAMMENI + (0x345, 0x3b9, 0x1fbe), # \u0345?? + # GREEK SMALL LETTER BETA, GREEK BETA SYMBOL + (0x3b2, 0x3d0), # ?? + # GREEK SMALL LETTER EPSILON, GREEK LUNATE EPSILON SYMBOL + (0x3b5, 0x3f5), # ?? + # GREEK SMALL LETTER THETA, GREEK THETA SYMBOL + (0x3b8, 0x3d1), # ?? + # GREEK SMALL LETTER KAPPA, GREEK KAPPA SYMBOL + (0x3ba, 0x3f0), # ?? + # GREEK SMALL LETTER PI, GREEK PI SYMBOL + (0x3c0, 0x3d6), # ?? + # GREEK SMALL LETTER RHO, GREEK RHO SYMBOL + (0x3c1, 0x3f1), # ?? + # GREEK SMALL LETTER FINAL SIGMA, GREEK SMALL LETTER SIGMA + (0x3c2, 0x3c3), # ?? + # GREEK SMALL LETTER PHI, GREEK PHI SYMBOL + (0x3c6, 0x3d5), # ?? + # LATIN SMALL LETTER S WITH DOT ABOVE, LATIN SMALL LETTER LONG S WITH DOT ABOVE + (0x1e61, 0x1e9b), # ?? +) + +# Maps the lowercase code to lowercase codes which have the same uppercase. +_ignorecase_fixes = {i: tuple(j for j in t if i != j) + for t in _equivalences for i in t} + def _compile(code, pattern, flags): # internal: compile a (sub)pattern emit = code.append @@ -34,11 +69,29 @@ REPEATING_CODES = _REPEATING_CODES SUCCESS_CODES = _SUCCESS_CODES ASSERT_CODES = _ASSERT_CODES + if (flags & SRE_FLAG_IGNORECASE and + not (flags & SRE_FLAG_LOCALE) and + flags & SRE_FLAG_UNICODE): + fixes = _ignorecase_fixes + else: + fixes = None for op, av in pattern: if op in LITERAL_CODES: if flags & SRE_FLAG_IGNORECASE: - emit(OPCODES[OP_IGNORE[op]]) - emit(_sre.getlower(av, flags)) + lo = _sre.getlower(av, flags) + if fixes and lo in fixes: + emit(OPCODES[IN_IGNORE]) + skip = _len(code); emit(0) + if op is NOT_LITERAL: + emit(OPCODES[NEGATE]) + for k in (lo,) + fixes[lo]: + emit(OPCODES[LITERAL]) + emit(k) + emit(OPCODES[FAILURE]) + code[skip] = _len(code) - skip + else: + emit(OPCODES[OP_IGNORE[op]]) + emit(lo) else: emit(OPCODES[op]) emit(av) @@ -51,7 +104,7 @@ emit(OPCODES[op]) fixup = None skip = _len(code); emit(0) - _compile_charset(av, flags, code, fixup) + _compile_charset(av, flags, code, fixup, fixes) code[skip] = _len(code) - skip elif op is ANY: if flags & SRE_FLAG_DOTALL: @@ -172,10 +225,11 @@ else: raise ValueError, ("unsupported operand type", op) -def _compile_charset(charset, flags, code, fixup=None): +def _compile_charset(charset, flags, code, fixup=None, fixes=None): # compile charset subprogram emit = code.append - for op, av in _optimize_charset(charset, fixup, flags & SRE_FLAG_UNICODE): + for op, av in _optimize_charset(charset, fixup, fixes, + flags & SRE_FLAG_UNICODE): emit(OPCODES[op]) if op is NEGATE: pass @@ -199,7 +253,7 @@ raise error, "internal: unsupported set operator" emit(OPCODES[FAILURE]) -def _optimize_charset(charset, fixup, isunicode): +def _optimize_charset(charset, fixup, fixes, isunicode): # internal: optimize character set out = [] tail = [] @@ -208,16 +262,27 @@ while True: try: if op is LITERAL: - i = av if fixup: - i = fixup(i) - charmap[i] = 1 + i = fixup(av) + charmap[i] = 1 + if fixes and i in fixes: + for k in fixes[i]: + charmap[k] = 1 + else: + charmap[av] = 1 elif op is RANGE: r = range(av[0], av[1]+1) if fixup: r = map(fixup, r) - for i in r: - charmap[i] = 1 + if fixup and fixes: + for i in r: + charmap[i] = 1 + if i in fixes: + for k in fixes[i]: + charmap[k] = 1 + else: + for i in r: + charmap[i] = 1 elif op is NEGATE: out.append((op, av)) else: diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- from test.test_support import verbose, run_unittest, import_module from test.test_support import precisionbigmemtest, _2G, cpython_only from test.test_support import captured_stdout, have_unicode, requires_unicode, u @@ -510,6 +511,39 @@ self.assertEqual(re.match(r"((a)\s(abc|a))", "a a", re.I).group(1), "a a") self.assertEqual(re.match(r"((a)\s(abc|a)*)", "a aa", re.I).group(1), "a aa") + if have_unicode: + assert u(r'\u212a').lower() == u'k' # '?' + self.assertTrue(re.match(ur'K', u(r'\u212a'), re.U | re.I)) + self.assertTrue(re.match(ur'k', u(r'\u212a'), re.U | re.I)) + self.assertTrue(re.match(u(r'\u212a'), u'K', re.U | re.I)) + self.assertTrue(re.match(u(r'\u212a'), u'k', re.U | re.I)) + assert u(r'\u017f').upper() == u'S' # '?' + self.assertTrue(re.match(ur'S', u(r'\u017f'), re.U | re.I)) + self.assertTrue(re.match(ur's', u(r'\u017f'), re.U | re.I)) + self.assertTrue(re.match(u(r'\u017f'), u'S', re.U | re.I)) + self.assertTrue(re.match(u(r'\u017f'), u's', re.U | re.I)) + + def test_ignore_case_set(self): + self.assertTrue(re.match(r'[19A]', 'A', re.I)) + self.assertTrue(re.match(r'[19a]', 'a', re.I)) + self.assertTrue(re.match(r'[19a]', 'A', re.I)) + self.assertTrue(re.match(r'[19A]', 'a', re.I)) + if have_unicode: + self.assertTrue(re.match(ur'[19A]', u'A', re.U | re.I)) + self.assertTrue(re.match(ur'[19a]', u'a', re.U | re.I)) + self.assertTrue(re.match(ur'[19a]', u'A', re.U | re.I)) + self.assertTrue(re.match(ur'[19A]', u'a', re.U | re.I)) + assert u(r'\u212a').lower() == u'k' # '?' + self.assertTrue(re.match(u(r'[19K]'), u(r'\u212a'), re.U | re.I)) + self.assertTrue(re.match(u(r'[19k]'), u(r'\u212a'), re.U | re.I)) + self.assertTrue(re.match(u(r'[19\u212a]'), u'K', re.U | re.I)) + self.assertTrue(re.match(u(r'[19\u212a]'), u'k', re.U | re.I)) + assert u(r'\u017f').upper() == u'S' # '?' + self.assertTrue(re.match(ur'[19S]', u(r'\u017f'), re.U | re.I)) + self.assertTrue(re.match(ur'[19s]', u(r'\u017f'), re.U | re.I)) + self.assertTrue(re.match(u(r'[19\u017f]'), u'S', re.U | re.I)) + self.assertTrue(re.match(u(r'[19\u017f]'), u's', re.U | re.I)) + def test_ignore_case_range(self): # Issues #3511, #17381. self.assertTrue(re.match(r'[9-a]', '_', re.I)) @@ -547,6 +581,17 @@ self.assertTrue(re.match(u(r'[\U00010400-\U00010427]'), u(r'\U00010400'), re.U | re.I)) + assert u(r'\u212a').lower() == u'k' # '?' + self.assertTrue(re.match(ur'[J-M]', u(r'\u212a'), re.U | re.I)) + self.assertTrue(re.match(ur'[j-m]', u(r'\u212a'), re.U | re.I)) + self.assertTrue(re.match(u(r'[\u2129-\u212b]'), u'K', re.U | re.I)) + self.assertTrue(re.match(u(r'[\u2129-\u212b]'), u'k', re.U | re.I)) + assert u(r'\u017f').upper() == u'S' # '?' + self.assertTrue(re.match(ur'[R-T]', u(r'\u017f'), re.U | re.I)) + self.assertTrue(re.match(ur'[r-t]', u(r'\u017f'), re.U | re.I)) + self.assertTrue(re.match(u(r'[\u017e-\u0180]'), u'S', re.U | re.I)) + self.assertTrue(re.match(u(r'[\u017e-\u0180]'), u's', re.U | re.I)) + def test_category(self): self.assertEqual(re.match(r"(\s)", " ").group(1), " ") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,6 +37,9 @@ Library ------- +- Issue #12728: Different Unicode characters having the same uppercase but + different lowercase are now matched in case-insensitive regular expressions. + - Issue #22821: Fixed fcntl() with integer argument on 64-bit big-endian platforms. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 11:47:06 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 10 Nov 2014 10:47:06 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2312728=3A_Different_Unicode_characters_having_th?= =?utf-8?q?e_same_uppercase_but?= Message-ID: <20141110104704.108367.88825@psf.io> https://hg.python.org/cpython/rev/09ec09cfe539 changeset: 93458:09ec09cfe539 parent: 93455:2d203a0b7908 parent: 93457:47b3084dd6aa user: Serhiy Storchaka date: Mon Nov 10 12:43:14 2014 +0200 summary: Issue #12728: Different Unicode characters having the same uppercase but different lowercase are now matched in case-insensitive regular expressions. files: Lib/sre_compile.py | 90 +++++++++++++++++++++++++++++--- Lib/test/test_re.py | 51 ++++++++++++++++++ Misc/NEWS | 3 + 3 files changed, 134 insertions(+), 10 deletions(-) diff --git a/Lib/sre_compile.py b/Lib/sre_compile.py --- a/Lib/sre_compile.py +++ b/Lib/sre_compile.py @@ -26,6 +26,46 @@ _SUCCESS_CODES = {SUCCESS, FAILURE} _ASSERT_CODES = {ASSERT, ASSERT_NOT} +# Sets of lowercase characters which have the same uppercase. +_equivalences = ( + # LATIN SMALL LETTER I, LATIN SMALL LETTER DOTLESS I + (0x69, 0x131), # i? + # LATIN SMALL LETTER S, LATIN SMALL LETTER LONG S + (0x73, 0x17f), # s? + # MICRO SIGN, GREEK SMALL LETTER MU + (0xb5, 0x3bc), # ?? + # COMBINING GREEK YPOGEGRAMMENI, GREEK SMALL LETTER IOTA, GREEK PROSGEGRAMMENI + (0x345, 0x3b9, 0x1fbe), # \u0345?? + # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS, GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA + (0x390, 0x1fd3), # ?? + # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS, GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA + (0x3b0, 0x1fe3), # ?? + # GREEK SMALL LETTER BETA, GREEK BETA SYMBOL + (0x3b2, 0x3d0), # ?? + # GREEK SMALL LETTER EPSILON, GREEK LUNATE EPSILON SYMBOL + (0x3b5, 0x3f5), # ?? + # GREEK SMALL LETTER THETA, GREEK THETA SYMBOL + (0x3b8, 0x3d1), # ?? + # GREEK SMALL LETTER KAPPA, GREEK KAPPA SYMBOL + (0x3ba, 0x3f0), # ?? + # GREEK SMALL LETTER PI, GREEK PI SYMBOL + (0x3c0, 0x3d6), # ?? + # GREEK SMALL LETTER RHO, GREEK RHO SYMBOL + (0x3c1, 0x3f1), # ?? + # GREEK SMALL LETTER FINAL SIGMA, GREEK SMALL LETTER SIGMA + (0x3c2, 0x3c3), # ?? + # GREEK SMALL LETTER PHI, GREEK PHI SYMBOL + (0x3c6, 0x3d5), # ?? + # LATIN SMALL LETTER S WITH DOT ABOVE, LATIN SMALL LETTER LONG S WITH DOT ABOVE + (0x1e61, 0x1e9b), # ?? + # LATIN SMALL LIGATURE LONG S T, LATIN SMALL LIGATURE ST + (0xfb05, 0xfb06), # ?? +) + +# Maps the lowercase code to lowercase codes which have the same uppercase. +_ignorecase_fixes = {i: tuple(j for j in t if i != j) + for t in _equivalences for i in t} + def _compile(code, pattern, flags): # internal: compile a (sub)pattern emit = code.append @@ -34,11 +74,29 @@ REPEATING_CODES = _REPEATING_CODES SUCCESS_CODES = _SUCCESS_CODES ASSERT_CODES = _ASSERT_CODES + if (flags & SRE_FLAG_IGNORECASE and + not (flags & SRE_FLAG_LOCALE) and + flags & SRE_FLAG_UNICODE): + fixes = _ignorecase_fixes + else: + fixes = None for op, av in pattern: if op in LITERAL_CODES: if flags & SRE_FLAG_IGNORECASE: - emit(OP_IGNORE[op]) - emit(_sre.getlower(av, flags)) + lo = _sre.getlower(av, flags) + if fixes and lo in fixes: + emit(IN_IGNORE) + skip = _len(code); emit(0) + if op is NOT_LITERAL: + emit(NEGATE) + for k in (lo,) + fixes[lo]: + emit(LITERAL) + emit(k) + emit(FAILURE) + code[skip] = _len(code) - skip + else: + emit(OP_IGNORE[op]) + emit(lo) else: emit(op) emit(av) @@ -51,7 +109,7 @@ emit(op) fixup = None skip = _len(code); emit(0) - _compile_charset(av, flags, code, fixup) + _compile_charset(av, flags, code, fixup, fixes) code[skip] = _len(code) - skip elif op is ANY: if flags & SRE_FLAG_DOTALL: @@ -165,10 +223,10 @@ else: raise ValueError("unsupported operand type", op) -def _compile_charset(charset, flags, code, fixup=None): +def _compile_charset(charset, flags, code, fixup=None, fixes=None): # compile charset subprogram emit = code.append - for op, av in _optimize_charset(charset, fixup): + for op, av in _optimize_charset(charset, fixup, fixes): emit(op) if op is NEGATE: pass @@ -192,7 +250,7 @@ raise error("internal: unsupported set operator") emit(FAILURE) -def _optimize_charset(charset, fixup): +def _optimize_charset(charset, fixup, fixes): # internal: optimize character set out = [] tail = [] @@ -202,14 +260,26 @@ try: if op is LITERAL: if fixup: - av = fixup(av) - charmap[av] = 1 + lo = fixup(av) + charmap[lo] = 1 + if fixes and lo in fixes: + for k in fixes[lo]: + charmap[k] = 1 + else: + charmap[av] = 1 elif op is RANGE: r = range(av[0], av[1]+1) if fixup: r = map(fixup, r) - for i in r: - charmap[i] = 1 + if fixup and fixes: + for i in r: + charmap[i] = 1 + if i in fixes: + for k in fixes[i]: + charmap[k] = 1 + else: + for i in r: + charmap[i] = 1 elif op is NEGATE: out.append((op, av)) else: diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -637,6 +637,43 @@ self.assertEqual(re.match(r"((a)\s(abc|a))", "a a", re.I).group(1), "a a") self.assertEqual(re.match(r"((a)\s(abc|a)*)", "a aa", re.I).group(1), "a aa") + assert '\u212a'.lower() == 'k' # '?' + self.assertTrue(re.match(r'K', '\u212a', re.I)) + self.assertTrue(re.match(r'k', '\u212a', re.I)) + self.assertTrue(re.match(r'\u212a', 'K', re.I)) + self.assertTrue(re.match(r'\u212a', 'k', re.I)) + assert '\u017f'.upper() == 'S' # '?' + self.assertTrue(re.match(r'S', '\u017f', re.I)) + self.assertTrue(re.match(r's', '\u017f', re.I)) + self.assertTrue(re.match(r'\u017f', 'S', re.I)) + self.assertTrue(re.match(r'\u017f', 's', re.I)) + assert '\ufb05'.upper() == '\ufb06'.upper() == 'ST' # '?', '?' + self.assertTrue(re.match(r'\ufb05', '\ufb06', re.I)) + self.assertTrue(re.match(r'\ufb06', '\ufb05', re.I)) + + def test_ignore_case_set(self): + self.assertTrue(re.match(r'[19A]', 'A', re.I)) + self.assertTrue(re.match(r'[19a]', 'a', re.I)) + self.assertTrue(re.match(r'[19a]', 'A', re.I)) + self.assertTrue(re.match(r'[19A]', 'a', re.I)) + self.assertTrue(re.match(br'[19A]', b'A', re.I)) + self.assertTrue(re.match(br'[19a]', b'a', re.I)) + self.assertTrue(re.match(br'[19a]', b'A', re.I)) + self.assertTrue(re.match(br'[19A]', b'a', re.I)) + assert '\u212a'.lower() == 'k' # '?' + self.assertTrue(re.match(r'[19K]', '\u212a', re.I)) + self.assertTrue(re.match(r'[19k]', '\u212a', re.I)) + self.assertTrue(re.match(r'[19\u212a]', 'K', re.I)) + self.assertTrue(re.match(r'[19\u212a]', 'k', re.I)) + assert '\u017f'.upper() == 'S' # '?' + self.assertTrue(re.match(r'[19S]', '\u017f', re.I)) + self.assertTrue(re.match(r'[19s]', '\u017f', re.I)) + self.assertTrue(re.match(r'[19\u017f]', 'S', re.I)) + self.assertTrue(re.match(r'[19\u017f]', 's', re.I)) + assert '\ufb05'.upper() == '\ufb06'.upper() == 'ST' # '?', '?' + self.assertTrue(re.match(r'[19\ufb05]', '\ufb06', re.I)) + self.assertTrue(re.match(r'[19\ufb06]', '\ufb05', re.I)) + def test_ignore_case_range(self): # Issues #3511, #17381. self.assertTrue(re.match(r'[9-a]', '_', re.I)) @@ -656,6 +693,20 @@ self.assertTrue(re.match(r'[\U00010400-\U00010427]', '\U00010428', re.I)) self.assertTrue(re.match(r'[\U00010400-\U00010427]', '\U00010400', re.I)) + assert '\u212a'.lower() == 'k' # '?' + self.assertTrue(re.match(r'[J-M]', '\u212a', re.I)) + self.assertTrue(re.match(r'[j-m]', '\u212a', re.I)) + self.assertTrue(re.match(r'[\u2129-\u212b]', 'K', re.I)) + self.assertTrue(re.match(r'[\u2129-\u212b]', 'k', re.I)) + assert '\u017f'.upper() == 'S' # '?' + self.assertTrue(re.match(r'[R-T]', '\u017f', re.I)) + self.assertTrue(re.match(r'[r-t]', '\u017f', re.I)) + self.assertTrue(re.match(r'[\u017e-\u0180]', 'S', re.I)) + self.assertTrue(re.match(r'[\u017e-\u0180]', 's', re.I)) + assert '\ufb05'.upper() == '\ufb06'.upper() == 'ST' # '?', '?' + self.assertTrue(re.match(r'[\ufb04-\ufb05]', '\ufb06', re.I)) + self.assertTrue(re.match(r'[\ufb06-\ufb07]', '\ufb05', re.I)) + def test_category(self): self.assertEqual(re.match(r"(\s)", " ").group(1), " ") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -183,6 +183,9 @@ Library ------- +- Issue #12728: Different Unicode characters having the same uppercase but + different lowercase are now matched in case-insensitive regular expressions. + - Issue #22821: Fixed fcntl() with integer argument on 64-bit big-endian platforms. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 12:27:36 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 10 Nov 2014 11:27:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Got_rid_of_the_array_module_dependency_in_the_re_module?= =?utf-8?q?=2E?= Message-ID: <20141110112731.127953.23406@psf.io> https://hg.python.org/cpython/rev/3c3cf26e6f7d changeset: 93460:3c3cf26e6f7d parent: 93458:09ec09cfe539 parent: 93459:03d6661c13a0 user: Serhiy Storchaka date: Mon Nov 10 13:25:14 2014 +0200 summary: Got rid of the array module dependency in the re module. The re module could be used during building before array is built. files: Lib/sre_compile.py | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/Lib/sre_compile.py b/Lib/sre_compile.py --- a/Lib/sre_compile.py +++ b/Lib/sre_compile.py @@ -382,8 +382,7 @@ def _bytes_to_codes(b): # Convert block indices to word array - import array - a = array.array('I', b) + a = memoryview(b).cast('I') assert a.itemsize == _sre.CODESIZE assert len(a) * a.itemsize == len(b) return a.tolist() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 12:27:36 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 10 Nov 2014 11:27:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Got_rid_of_the?= =?utf-8?q?_array_module_dependency_in_the_re_module=2E?= Message-ID: <20141110112731.85200.57061@psf.io> https://hg.python.org/cpython/rev/03d6661c13a0 changeset: 93459:03d6661c13a0 branch: 3.4 parent: 93457:47b3084dd6aa user: Serhiy Storchaka date: Mon Nov 10 13:24:47 2014 +0200 summary: Got rid of the array module dependency in the re module. The re module could be used during building before array is built. files: Lib/sre_compile.py | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/Lib/sre_compile.py b/Lib/sre_compile.py --- a/Lib/sre_compile.py +++ b/Lib/sre_compile.py @@ -410,8 +410,7 @@ def _bytes_to_codes(b): # Convert block indices to word array - import array - a = array.array('I', b) + a = memoryview(b).cast('I') assert a.itemsize == _sre.CODESIZE assert len(a) * a.itemsize == len(b) return a.tolist() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 12:51:31 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 10 Nov 2014 11:51:31 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322578=3A_Added_at?= =?utf-8?q?tributes_to_the_re=2Eerror_class=2E?= Message-ID: <20141110115106.85194.63069@psf.io> https://hg.python.org/cpython/rev/292c4d853662 changeset: 93461:292c4d853662 user: Serhiy Storchaka date: Mon Nov 10 13:49:00 2014 +0200 summary: Issue #22578: Added attributes to the re.error class. files: Doc/library/re.rst | 27 +++++- Lib/sre_constants.py | 30 ++++++- Lib/sre_parse.py | 141 ++++++++++++++++++------------ Lib/test/test_re.py | 36 +++++++ Misc/NEWS | 2 + 5 files changed, 174 insertions(+), 62 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -733,13 +733,36 @@ Clear the regular expression cache. -.. exception:: error +.. exception:: error(msg, pattern=None, pos=None) Exception raised when a string passed to one of the functions here is not a valid regular expression (for example, it might contain unmatched parentheses) or when some other error occurs during compilation or matching. It is never an - error if a string contains no match for a pattern. + error if a string contains no match for a pattern. The error instance has + the following additional attributes: + .. attribute:: msg + + The unformatted error message. + + .. attribute:: pattern + + The regular expression pattern. + + .. attribute:: pos + + The index of *pattern* where compilation failed. + + .. attribute:: lineno + + The line corresponding to *pos*. + + .. attribute:: colno + + The column corresponding to *pos*. + + .. versionchanged:: 3.5 + Added additional attributes. .. _re-objects: diff --git a/Lib/sre_constants.py b/Lib/sre_constants.py --- a/Lib/sre_constants.py +++ b/Lib/sre_constants.py @@ -21,7 +21,35 @@ # should this really be here? class error(Exception): - pass + def __init__(self, msg, pattern=None, pos=None): + self.msg = msg + self.pattern = pattern + self.pos = pos + if pattern is not None and pos is not None: + msg = '%s at position %d' % (msg, pos) + if isinstance(pattern, str): + newline = '\n' + else: + newline = b'\n' + self.lineno = pattern.count(newline, 0, pos) + 1 + self.colno = pos - pattern.rfind(newline, 0, pos) + if newline in pattern: + msg = '%s (line %d, column %d)' % (msg, self.lineno, self.colno) + else: + self.lineno = self.colno = None + super().__init__(msg) + +def linecol(doc, pos): + if isinstance(pattern, str): + newline = '\n' + else: + newline = b'\n' + lineno = pattern.count(newline, 0, pos) + 1 + if lineno == 1: + colno = pos + 1 + else: + colno = pos - doc.rindex(newline, 0, pos) + return lineno, colno class _NamedIntConstant(int): diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -81,8 +81,8 @@ if name is not None: ogid = self.groupdict.get(name, None) if ogid is not None: - raise error("redefinition of group name %s as group %d; " - "was group %d" % (repr(name), gid, ogid)) + raise error("redefinition of group name %r as group %d; " + "was group %d" % (name, gid, ogid)) self.groupdict[name] = gid return gid def closegroup(self, gid, p): @@ -206,24 +206,25 @@ class Tokenizer: def __init__(self, string): self.istext = isinstance(string, str) + self.string = string if not self.istext: string = str(string, 'latin1') - self.string = string + self.decoded_string = string self.index = 0 self.__next() def __next(self): index = self.index try: - char = self.string[index] + char = self.decoded_string[index] except IndexError: self.next = None return if char == "\\": index += 1 try: - char += self.string[index] + char += self.decoded_string[index] except IndexError: - raise error("bogus escape (end of line)") + raise self.error("bogus escape (end of line)") from None self.index = index + 1 self.next = char def match(self, char): @@ -250,15 +251,19 @@ c = self.next self.__next() if c is None: - raise error("unterminated name") + raise self.error("unterminated name") if c == terminator: break result += c return result def tell(self): - return self.index, self.next + return self.index - len(self.next or '') def seek(self, index): - self.index, self.next = index + self.index = index + self.__next() + + def error(self, msg, offset=0): + return error(msg, self.string, self.tell() - offset) # The following three functions are not used in this module anymore, but we keep # them here (with DeprecationWarnings) for backwards compatibility. @@ -322,8 +327,8 @@ escape += source.getwhile(2, OCTDIGITS) c = int(escape[1:], 8) if c > 0o377: - raise error('octal escape value %r outside of ' - 'range 0-0o377' % escape) + raise source.error('octal escape value %r outside of ' + 'range 0-0o377' % escape, len(escape)) return LITERAL, c elif c in DIGITS: raise ValueError @@ -331,7 +336,7 @@ return LITERAL, ord(escape[1]) except ValueError: pass - raise error("bogus escape: %s" % repr(escape)) + raise source.error("bogus escape: %r" % escape, len(escape)) def _escape(source, escape, state): # handle escape code in expression @@ -377,21 +382,23 @@ escape += source.get() c = int(escape[1:], 8) if c > 0o377: - raise error('octal escape value %r outside of ' - 'range 0-0o377' % escape) + raise source.error('octal escape value %r outside of ' + 'range 0-0o377' % escape, + len(escape)) return LITERAL, c # not an octal escape, so this is a group reference group = int(escape[1:]) if group < state.groups: if not state.checkgroup(group): - raise error("cannot refer to open group") + raise source.error("cannot refer to open group", + len(escape)) return GROUPREF, group raise ValueError if len(escape) == 2: return LITERAL, ord(escape[1]) except ValueError: pass - raise error("bogus escape: %s" % repr(escape)) + raise source.error("bogus escape: %r" % escape, len(escape)) def _parse_sub(source, state, nested=True): # parse an alternation: a|b|c @@ -404,7 +411,7 @@ if not sourcematch("|"): break if nested and source.next is not None and source.next != ")": - raise error("pattern not properly closed") + raise source.error("pattern not properly closed") if len(items) == 1: return items[0] @@ -449,11 +456,11 @@ if source.match("|"): item_no = _parse(source, state) if source.next == "|": - raise error("conditional backref with more than two branches") + raise source.error("conditional backref with more than two branches") else: item_no = None if source.next is not None and source.next != ")": - raise error("pattern not properly closed") + raise source.error("pattern not properly closed") subpattern = SubPattern(state) subpattern.append((GROUPREF_EXISTS, (condgroup, item_yes, item_no))) return subpattern @@ -510,7 +517,7 @@ while True: this = sourceget() if this is None: - raise error("unexpected end of regular expression") + raise source.error("unexpected end of regular expression") if this == "]" and set != start: break elif this[0] == "\\": @@ -521,7 +528,7 @@ # potential range this = sourceget() if this is None: - raise error("unexpected end of regular expression") + raise source.error("unexpected end of regular expression") if this == "]": if code1[0] is IN: code1 = code1[1][0] @@ -533,11 +540,11 @@ else: code2 = LITERAL, _ord(this) if code1[0] != LITERAL or code2[0] != LITERAL: - raise error("bad character range") + raise source.error("bad character range", len(this)) lo = code1[1] hi = code2[1] if hi < lo: - raise error("bad character range") + raise source.error("bad character range", len(this)) setappend((RANGE, (lo, hi))) else: if code1[0] is IN: @@ -555,6 +562,7 @@ elif this in REPEAT_CHARS: # repeat previous item + here = source.tell() if this == "?": min, max = 0, 1 elif this == "*": @@ -566,7 +574,6 @@ if source.next == "}": subpatternappend((LITERAL, _ord(this))) continue - here = source.tell() min, max = 0, MAXREPEAT lo = hi = "" while source.next in DIGITS: @@ -589,18 +596,21 @@ if max >= MAXREPEAT: raise OverflowError("the repetition number is too large") if max < min: - raise error("bad repeat interval") + raise source.error("bad repeat interval", + source.tell() - here) else: - raise error("not supported") + raise source.error("not supported", len(this)) # figure out which item to repeat if subpattern: item = subpattern[-1:] else: item = None if not item or (_len(item) == 1 and item[0][0] == AT): - raise error("nothing to repeat") + raise source.error("nothing to repeat", + source.tell() - here + len(this)) if item[0][0] in _REPEATCODES: - raise error("multiple repeat") + raise source.error("multiple repeat", + source.tell() - here + len(this)) if sourcematch("?"): subpattern[-1] = (MIN_REPEAT, (min, max, item)) else: @@ -618,7 +628,7 @@ # options char = sourceget() if char is None: - raise error("unexpected end of pattern") + raise self.error("unexpected end of pattern") if char == "P": # python extensions if sourcematch("<"): @@ -626,28 +636,32 @@ name = source.getuntil(">") group = 1 if not name: - raise error("missing group name") + raise source.error("missing group name", 1) if not name.isidentifier(): - raise error("bad character in group name %r" % name) + raise source.error("bad character in group name " + "%r" % name, + len(name) + 1) elif sourcematch("="): # named backreference name = source.getuntil(")") if not name: - raise error("missing group name") + raise source.error("missing group name", 1) if not name.isidentifier(): - raise error("bad character in backref group name " - "%r" % name) + raise source.error("bad character in backref " + "group name %r" % name, + len(name) + 1) gid = state.groupdict.get(name) if gid is None: msg = "unknown group name: {0!r}".format(name) - raise error(msg) + raise source.error(msg, len(name) + 1) subpatternappend((GROUPREF, gid)) continue else: char = sourceget() if char is None: - raise error("unexpected end of pattern") - raise error("unknown specifier: ?P%s" % char) + raise source.error("unexpected end of pattern") + raise source.error("unknown specifier: ?P%s" % char, + len(char)) elif char == ":": # non-capturing group group = 2 @@ -655,7 +669,7 @@ # comment while True: if source.next is None: - raise error("unbalanced parenthesis") + raise source.error("unbalanced parenthesis") if sourceget() == ")": break continue @@ -665,11 +679,11 @@ if char == "<": char = sourceget() if char is None or char not in "=!": - raise error("syntax error") + raise source.error("syntax error") dir = -1 # lookbehind p = _parse_sub(source, state) if not sourcematch(")"): - raise error("unbalanced parenthesis") + raise source.error("unbalanced parenthesis") if char == "=": subpatternappend((ASSERT, (dir, p))) else: @@ -680,23 +694,26 @@ condname = source.getuntil(")") group = 2 if not condname: - raise error("missing group name") + raise source.error("missing group name", 1) if condname.isidentifier(): condgroup = state.groupdict.get(condname) if condgroup is None: msg = "unknown group name: {0!r}".format(condname) - raise error(msg) + raise source.error(msg, len(condname) + 1) else: try: condgroup = int(condname) if condgroup < 0: raise ValueError except ValueError: - raise error("bad character in group name") + raise source.error("bad character in group name", + len(condname) + 1) if not condgroup: - raise error("bad group number") + raise source.error("bad group number", + len(condname) + 1) if condgroup >= MAXGROUPS: - raise error("the group number is too large") + raise source.error("the group number is too large", + len(condname) + 1) elif char in FLAGS: # flags state.flags |= FLAGS[char] @@ -704,20 +721,23 @@ state.flags |= FLAGS[sourceget()] verbose = state.flags & SRE_FLAG_VERBOSE else: - raise error("unexpected end of pattern " + char) + raise source.error("unexpected end of pattern") if group: # parse group contents if group == 2: # anonymous group group = None else: - group = state.opengroup(name) + try: + group = state.opengroup(name) + except error as err: + raise source.error(err.msg, len(name) + 1) if condgroup: p = _parse_sub_cond(source, state, condgroup) else: p = _parse_sub(source, state) if not sourcematch(")"): - raise error("unbalanced parenthesis") + raise source.error("unbalanced parenthesis") if group is not None: state.closegroup(group, p) subpatternappend((SUBPATTERN, (group, p))) @@ -725,10 +745,10 @@ while True: char = sourceget() if char is None: - raise error("unexpected end of pattern") + raise source.error("unexpected end of pattern") if char == ")": break - raise error("unknown extension") + raise source.error("unknown extension", len(char)) elif this == "^": subpatternappend((AT, AT_BEGINNING)) @@ -737,7 +757,7 @@ subpattern.append((AT, AT_END)) else: - raise error("parser error") + raise source.error("parser error", len(this)) return subpattern @@ -768,9 +788,10 @@ if source.next is not None: if source.next == ")": - raise error("unbalanced parenthesis") + raise source.error("unbalanced parenthesis") else: - raise error("bogus characters at end of regular expression") + raise source.error("bogus characters at end of regular expression", + len(tail)) if flags & SRE_FLAG_DEBUG: p.dump() @@ -809,16 +830,18 @@ if s.match("<"): name = s.getuntil(">") if not name: - raise error("missing group name") + raise s.error("missing group name", 1) try: index = int(name) if index < 0: - raise error("negative group number") + raise s.error("negative group number", len(name) + 1) if index >= MAXGROUPS: - raise error("the group number is too large") + raise s.error("the group number is too large", + len(name) + 1) except ValueError: if not name.isidentifier(): - raise error("bad character in group name") + raise s.error("bad character in group name", + len(name) + 1) try: index = pattern.groupindex[name] except KeyError: @@ -841,8 +864,8 @@ isoctal = True c = int(this[1:], 8) if c > 0o377: - raise error('octal escape value %r outside of ' - 'range 0-0o377' % this) + raise s.error('octal escape value %r outside of ' + 'range 0-0o377' % this, len(this)) lappend(chr(c)) if not isoctal: addgroup(int(this[1:])) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -1419,6 +1419,42 @@ self.assertIsNone(re.match(b'(?Li)\xc5', b'\xe5')) self.assertIsNone(re.match(b'(?Li)\xe5', b'\xc5')) + def test_error(self): + with self.assertRaises(re.error) as cm: + re.compile('(\u20ac))') + err = cm.exception + self.assertIsInstance(err.pattern, str) + self.assertEqual(err.pattern, '(\u20ac))') + self.assertEqual(err.pos, 3) + self.assertEqual(err.lineno, 1) + self.assertEqual(err.colno, 4) + self.assertIn(err.msg, str(err)) + self.assertIn(' at position 3', str(err)) + self.assertNotIn(' at position 3', err.msg) + # Bytes pattern + with self.assertRaises(re.error) as cm: + re.compile(b'(\xa4))') + err = cm.exception + self.assertIsInstance(err.pattern, bytes) + self.assertEqual(err.pattern, b'(\xa4))') + self.assertEqual(err.pos, 3) + # Multiline pattern + with self.assertRaises(re.error) as cm: + re.compile(""" + ( + abc + ) + ) + ( + """, re.VERBOSE) + err = cm.exception + self.assertEqual(err.pos, 77) + self.assertEqual(err.lineno, 5) + self.assertEqual(err.colno, 17) + self.assertIn(err.msg, str(err)) + self.assertIn(' at position 77', str(err)) + self.assertIn('(line 5, column 17)', str(err)) + class PatternReprTests(unittest.TestCase): def check(self, pattern, expected): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -183,6 +183,8 @@ Library ------- +- Issue #22578: Added attributes to the re.error class. + - Issue #12728: Different Unicode characters having the same uppercase but different lowercase are now matched in case-insensitive regular expressions. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 13:36:00 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 10 Nov 2014 12:36:00 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fixed_IDLE_tests_after_cha?= =?utf-8?q?nging_re_error_messages_=28issue_=2322578=29=2E?= Message-ID: <20141110123544.85216.39224@psf.io> https://hg.python.org/cpython/rev/07f082b200a7 changeset: 93462:07f082b200a7 user: Serhiy Storchaka date: Mon Nov 10 14:18:03 2014 +0200 summary: Fixed IDLE tests after changing re error messages (issue #22578). files: Lib/idlelib/idle_test/test_searchengine.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/idle_test/test_searchengine.py b/Lib/idlelib/idle_test/test_searchengine.py --- a/Lib/idlelib/idle_test/test_searchengine.py +++ b/Lib/idlelib/idle_test/test_searchengine.py @@ -178,7 +178,7 @@ engine.revar.set(1) Equal(engine.getprog(), None) self.assertEqual(Mbox.showerror.message, - 'Error: nothing to repeat\nPattern: +') + 'Error: nothing to repeat at position 0\nPattern: +') def test_report_error(self): showerror = Mbox.showerror -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 13:40:35 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 10 Nov 2014 12:40:35 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fixed_AttributeError_when_?= =?utf-8?q?the_regular_expression_starts_from_illegal_escape=2E?= Message-ID: <20141110124022.108371.29124@psf.io> https://hg.python.org/cpython/rev/7972304b9f92 changeset: 93463:7972304b9f92 user: Serhiy Storchaka date: Mon Nov 10 14:38:16 2014 +0200 summary: Fixed AttributeError when the regular expression starts from illegal escape. files: Lib/sre_parse.py | 1 + Lib/test/test_re.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 0 deletions(-) diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -211,6 +211,7 @@ string = str(string, 'latin1') self.decoded_string = string self.index = 0 + self.next = None self.__next() def __next(self): index = self.index diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -531,6 +531,20 @@ self.assertEqual(re.search(br"\d\D\w\W\s\S", b"1aa! a", re.LOCALE).group(0), b"1aa! a") + def test_other_escapes(self): + self.assertRaises(re.error, re.compile, "\\") + self.assertEqual(re.match(r"\(", '(').group(), '(') + self.assertIsNone(re.match(r"\(", ')')) + self.assertEqual(re.match(r"\\", '\\').group(), '\\') + self.assertEqual(re.match(r"\y", 'y').group(), 'y') + self.assertIsNone(re.match(r"\y", 'z')) + self.assertEqual(re.match(r"[\]]", ']').group(), ']') + self.assertIsNone(re.match(r"[\]]", '[')) + self.assertEqual(re.match(r"[a\-c]", '-').group(), '-') + self.assertIsNone(re.match(r"[a\-c]", 'b')) + self.assertEqual(re.match(r"[\^a]+", 'a^').group(), 'a^') + self.assertIsNone(re.match(r"[\^a]+", 'b')) + def test_string_boundaries(self): # See http://bugs.python.org/issue10713 self.assertEqual(re.search(r"\b(abc)\b", "abc").group(1), -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 16:45:22 2014 From: python-checkins at python.org (georg.brandl) Date: Mon, 10 Nov 2014 15:45:22 +0000 Subject: [Python-checkins] =?utf-8?q?devguide=3A_update_my_entries_in_expe?= =?utf-8?q?rts_list?= Message-ID: <20141110154516.85210.35714@psf.io> https://hg.python.org/devguide/rev/ee636682d869 changeset: 724:ee636682d869 user: Georg Brandl date: Mon Nov 10 16:45:12 2014 +0100 summary: update my entries in experts list files: experts.rst | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/experts.rst b/experts.rst --- a/experts.rst +++ b/experts.rst @@ -54,7 +54,7 @@ aifc r.david.murray argparse bethard array -ast benjamin.peterson +ast benjamin.peterson, georg.brandl asynchat josiahcarlson, giampaolo.rodola*, stutzbach asyncio gvanrossum, haypo, pitrou, yselivanov, giampaolo.rodola asyncore josiahcarlson, giampaolo.rodola*, stutzbach @@ -165,7 +165,7 @@ ossaudiodev parser benjamin.peterson pathlib pitrou* -pdb georg.brandl* +pdb georg.brandl pickle alexandre.vassalotti, pitrou pickletools alexandre.vassalotti pipes @@ -210,7 +210,7 @@ ssl janssen, pitrou, giampaolo.rodola, christian.heimes, dstufft, alex stat christian.heimes statistics steven.daprano -string georg.brandl* +string georg.brandl stringprep struct mark.dickinson, meador.inge subprocess astrand (inactive) @@ -229,7 +229,7 @@ textwrap georg.brandl threading pitrou time belopolsky -timeit georg.brandl +timeit tkinter gpolo, serhiy.storchaka token georg.brandl tokenize meador.inge @@ -249,7 +249,7 @@ warnings wave weakref fdrake, pitrou -webbrowser georg.brandl +webbrowser winreg stutzbach winsound effbot (inactive) wsgiref pje -- Repository URL: https://hg.python.org/devguide From python-checkins at python.org Mon Nov 10 22:15:45 2014 From: python-checkins at python.org (berker.peksag) Date: Mon, 10 Nov 2014 21:15:45 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyODM5?= =?utf-8?q?=3A_Fix_Snapshot=2Estatistics=28=29_link=2E?= Message-ID: <20141110211538.71575.8153@psf.io> https://hg.python.org/cpython/rev/387bbada31e8 changeset: 93464:387bbada31e8 branch: 3.4 parent: 93459:03d6661c13a0 user: Berker Peksag date: Mon Nov 10 23:15:32 2014 +0200 summary: Issue #22839: Fix Snapshot.statistics() link. files: Doc/library/tracemalloc.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/tracemalloc.rst b/Doc/library/tracemalloc.rst --- a/Doc/library/tracemalloc.rst +++ b/Doc/library/tracemalloc.rst @@ -435,7 +435,7 @@ Compute the differences with an old snapshot. Get statistics as a sorted list of :class:`StatisticDiff` instances grouped by *group_by*. - See the :meth:`statistics` method for *group_by* and *cumulative* + See the :meth:`Snapshot.statistics` method for *group_by* and *cumulative* parameters. The result is sorted from the biggest to the smallest by: absolute value -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 10 22:15:45 2014 From: python-checkins at python.org (berker.peksag) Date: Mon, 10 Nov 2014 21:15:45 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322839=3A_Fix_Snapshot=2Estatistics=28=29_link?= =?utf-8?q?=2E?= Message-ID: <20141110211538.17280.93046@psf.io> https://hg.python.org/cpython/rev/524a004e93dd changeset: 93465:524a004e93dd parent: 93463:7972304b9f92 parent: 93464:387bbada31e8 user: Berker Peksag date: Mon Nov 10 23:15:56 2014 +0200 summary: Issue #22839: Fix Snapshot.statistics() link. files: Doc/library/tracemalloc.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/tracemalloc.rst b/Doc/library/tracemalloc.rst --- a/Doc/library/tracemalloc.rst +++ b/Doc/library/tracemalloc.rst @@ -435,7 +435,7 @@ Compute the differences with an old snapshot. Get statistics as a sorted list of :class:`StatisticDiff` instances grouped by *group_by*. - See the :meth:`statistics` method for *group_by* and *cumulative* + See the :meth:`Snapshot.statistics` method for *group_by* and *cumulative* parameters. The result is sorted from the biggest to the smallest by: absolute value -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 11 08:48:03 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 11 Nov 2014 07:48:03 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_heads?= Message-ID: <20141111074756.21125.54968@psf.io> https://hg.python.org/cpython/rev/81d1481bc094 changeset: 93467:81d1481bc094 parent: 93466:2b27ffe611f3 parent: 93465:524a004e93dd user: Serhiy Storchaka date: Tue Nov 11 09:45:55 2014 +0200 summary: Merge heads files: Doc/library/tracemalloc.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/tracemalloc.rst b/Doc/library/tracemalloc.rst --- a/Doc/library/tracemalloc.rst +++ b/Doc/library/tracemalloc.rst @@ -435,7 +435,7 @@ Compute the differences with an old snapshot. Get statistics as a sorted list of :class:`StatisticDiff` instances grouped by *group_by*. - See the :meth:`statistics` method for *group_by* and *cumulative* + See the :meth:`Snapshot.statistics` method for *group_by* and *cumulative* parameters. The result is sorted from the biggest to the smallest by: absolute value -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 11 08:48:03 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 11 Nov 2014 07:48:03 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fixed_error_position_for_t?= =?utf-8?q?he_backslash_at_the_end_of_regex_pattern=2E?= Message-ID: <20141111074756.80126.2430@psf.io> https://hg.python.org/cpython/rev/2b27ffe611f3 changeset: 93466:2b27ffe611f3 parent: 93463:7972304b9f92 user: Serhiy Storchaka date: Mon Nov 10 18:28:53 2014 +0200 summary: Fixed error position for the backslash at the end of regex pattern. files: Lib/sre_parse.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -225,7 +225,8 @@ try: char += self.decoded_string[index] except IndexError: - raise self.error("bogus escape (end of line)") from None + raise error("bogus escape (end of line)", + self.string, len(self.string) - 1) from None self.index = index + 1 self.next = char def match(self, char): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 11 09:06:13 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 11 Nov 2014 08:06:13 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIyODQ1?= =?utf-8?q?=3A_Improved_formatting_of_dis_documentation=2E?= Message-ID: <20141111080603.19409.84200@psf.io> https://hg.python.org/cpython/rev/0a32764004ab changeset: 93470:0a32764004ab branch: 2.7 parent: 93456:4caa695af94c user: Serhiy Storchaka date: Tue Nov 11 10:02:57 2014 +0200 summary: Issue #22845: Improved formatting of dis documentation. files: Doc/library/dis.rst | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -446,7 +446,7 @@ Implements the expression statement for the interactive mode. TOS is removed from the stack and printed. In non-interactive mode, an expression statement is - terminated with ``POP_STACK``. + terminated with :opcode:`POP_TOP`. .. opcode:: PRINT_ITEM () @@ -481,7 +481,7 @@ .. opcode:: CONTINUE_LOOP (target) Continues a loop due to a :keyword:`continue` statement. *target* is the - address to jump to (which should be a ``FOR_ITER`` instruction). + address to jump to (which should be a :opcode:`FOR_ITER` instruction). .. opcode:: LIST_APPEND (i) @@ -838,21 +838,21 @@ .. opcode:: CALL_FUNCTION_VAR (argc) - Calls a function. *argc* is interpreted as in ``CALL_FUNCTION``. The top element + Calls a function. *argc* is interpreted as in :opcode:`CALL_FUNCTION`. The top element on the stack contains the variable argument list, followed by keyword and positional arguments. .. opcode:: CALL_FUNCTION_KW (argc) - Calls a function. *argc* is interpreted as in ``CALL_FUNCTION``. The top element + Calls a function. *argc* is interpreted as in :opcode:`CALL_FUNCTION`. The top element on the stack contains the keyword arguments dictionary, followed by explicit keyword and positional arguments. .. opcode:: CALL_FUNCTION_VAR_KW (argc) - Calls a function. *argc* is interpreted as in ``CALL_FUNCTION``. The top + Calls a function. *argc* is interpreted as in :opcode:`CALL_FUNCTION`. The top element on the stack contains the keyword arguments dictionary, followed by the variable-arguments tuple, followed by explicit keyword and positional arguments. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 11 09:06:13 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 11 Nov 2014 08:06:13 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyODQ1?= =?utf-8?q?=3A_Improved_formatting_of_dis_documentation=2E?= Message-ID: <20141111080602.118395.97109@psf.io> https://hg.python.org/cpython/rev/d676f2725699 changeset: 93468:d676f2725699 branch: 3.4 parent: 93464:387bbada31e8 user: Serhiy Storchaka date: Tue Nov 11 10:02:11 2014 +0200 summary: Issue #22845: Improved formatting of dis documentation. files: Doc/library/dis.rst | 47 ++++++++++++++++---------------- 1 files changed, 24 insertions(+), 23 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -133,7 +133,7 @@ .. versionadded:: 3.2 .. versionchanged:: 3.4 - Added ``file`` parameter + Added *file* parameter. .. function:: dis(x=None, *, file=None) @@ -147,11 +147,11 @@ disassembled. If no object is provided, this function disassembles the last traceback. - The disassembly is written as text to the supplied ``file`` argument if + The disassembly is written as text to the supplied *file* argument if provided and to ``sys.stdout`` otherwise. .. versionchanged:: 3.4 - Added ``file`` parameter + Added *file* parameter. .. function:: distb(tb=None, *, file=None) @@ -160,11 +160,11 @@ traceback if none was passed. The instruction causing the exception is indicated. - The disassembly is written as text to the supplied ``file`` argument if + The disassembly is written as text to the supplied *file* argument if provided and to ``sys.stdout`` otherwise. .. versionchanged:: 3.4 - Added ``file`` parameter + Added *file* parameter. .. function:: disassemble(code, lasti=-1, *, file=None) @@ -184,11 +184,11 @@ The parameter interpretation recognizes local and global variable names, constant values, branch targets, and compare operators. - The disassembly is written as text to the supplied ``file`` argument if + The disassembly is written as text to the supplied *file* argument if provided and to ``sys.stdout`` otherwise. .. versionchanged:: 3.4 - Added ``file`` parameter + Added *file* parameter. .. function:: get_instructions(x, *, first_line=None) @@ -502,7 +502,7 @@ Implements the expression statement for the interactive mode. TOS is removed from the stack and printed. In non-interactive mode, an expression statement is - terminated with ``POP_STACK``. + terminated with :opcode:`POP_TOP`. .. opcode:: BREAK_LOOP @@ -513,7 +513,7 @@ .. opcode:: CONTINUE_LOOP (target) Continues a loop due to a :keyword:`continue` statement. *target* is the - address to jump to (which should be a ``FOR_ITER`` instruction). + address to jump to (which should be a :opcode:`FOR_ITER` instruction). .. opcode:: SET_ADD (i) @@ -531,7 +531,8 @@ Calls ``dict.setitem(TOS1[-i], TOS, TOS1)``. Used to implement dict comprehensions. -For all of the SET_ADD, LIST_APPEND and MAP_ADD instructions, while the +For all of the :opcode:`SET_ADD`, :opcode:`LIST_APPEND` and :opcode:`MAP_ADD` +instructions, while the added value or key/value pair is popped off, the container object remains on the stack so that it is available for further iterations of the loop. @@ -584,7 +585,7 @@ .. opcode:: LOAD_BUILD_CLASS Pushes :func:`builtins.__build_class__` onto the stack. It is later called - by ``CALL_FUNCTION`` to construct a class. + by :opcode:`CALL_FUNCTION` to construct a class. .. opcode:: SETUP_WITH (delta) @@ -615,7 +616,7 @@ If the stack represents an exception, *and* the function call returns a 'true' value, this information is "zapped" and replaced with a single - ``WHY_SILENCED`` to prevent ``END_FINALLY`` from re-raising the exception. + ``WHY_SILENCED`` to prevent :opcode:`END_FINALLY` from re-raising the exception. (But non-local gotos will still be resumed.) .. XXX explain the WHY stuff! @@ -627,8 +628,8 @@ .. opcode:: STORE_NAME (namei) Implements ``name = TOS``. *namei* is the index of *name* in the attribute - :attr:`co_names` of the code object. The compiler tries to use ``STORE_FAST`` - or ``STORE_GLOBAL`` if possible. + :attr:`co_names` of the code object. The compiler tries to use :opcode:`STORE_FAST` + or :opcode:`STORE_GLOBAL` if possible. .. opcode:: DELETE_NAME (namei) @@ -668,12 +669,12 @@ .. opcode:: STORE_GLOBAL (namei) - Works as ``STORE_NAME``, but stores the name as a global. + Works as :opcode:`STORE_NAME`, but stores the name as a global. .. opcode:: DELETE_GLOBAL (namei) - Works as ``DELETE_NAME``, but deletes a global name. + Works as :opcode:`DELETE_NAME`, but deletes a global name. .. opcode:: LOAD_CONST (consti) @@ -694,12 +695,12 @@ .. opcode:: BUILD_LIST (count) - Works as ``BUILD_TUPLE``, but creates a list. + Works as :opcode:`BUILD_TUPLE`, but creates a list. .. opcode:: BUILD_SET (count) - Works as ``BUILD_TUPLE``, but creates a set. + Works as :opcode:`BUILD_TUPLE`, but creates a set. .. opcode:: BUILD_MAP (count) @@ -724,7 +725,7 @@ Imports the module ``co_names[namei]``. TOS and TOS1 are popped and provide the *fromlist* and *level* arguments of :func:`__import__`. The module object is pushed onto the stack. The current namespace is not affected: - for a proper import statement, a subsequent ``STORE_FAST`` instruction + for a proper import statement, a subsequent :opcode:`STORE_FAST` instruction modifies the namespace. @@ -732,7 +733,7 @@ Loads the attribute ``co_names[namei]`` from the module found in TOS. The resulting object is pushed onto the stack, to be subsequently stored by a - ``STORE_FAST`` instruction. + :opcode:`STORE_FAST` instruction. .. opcode:: JUMP_FORWARD (delta) @@ -911,21 +912,21 @@ .. opcode:: CALL_FUNCTION_VAR (argc) - Calls a function. *argc* is interpreted as in ``CALL_FUNCTION``. The top element + Calls a function. *argc* is interpreted as in :opcode:`CALL_FUNCTION`. The top element on the stack contains the variable argument list, followed by keyword and positional arguments. .. opcode:: CALL_FUNCTION_KW (argc) - Calls a function. *argc* is interpreted as in ``CALL_FUNCTION``. The top element + Calls a function. *argc* is interpreted as in :opcode:`CALL_FUNCTION`. The top element on the stack contains the keyword arguments dictionary, followed by explicit keyword and positional arguments. .. opcode:: CALL_FUNCTION_VAR_KW (argc) - Calls a function. *argc* is interpreted as in ``CALL_FUNCTION``. The top + Calls a function. *argc* is interpreted as in :opcode:`CALL_FUNCTION`. The top element on the stack contains the keyword arguments dictionary, followed by the variable-arguments tuple, followed by explicit keyword and positional arguments. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 11 09:06:13 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 11 Nov 2014 08:06:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322845=3A_Improved_formatting_of_dis_documentati?= =?utf-8?b?b24u?= Message-ID: <20141111080603.19397.29997@psf.io> https://hg.python.org/cpython/rev/ac0334665459 changeset: 93469:ac0334665459 parent: 93467:81d1481bc094 parent: 93468:d676f2725699 user: Serhiy Storchaka date: Tue Nov 11 10:02:46 2014 +0200 summary: Issue #22845: Improved formatting of dis documentation. files: Doc/library/dis.rst | 47 ++++++++++++++++---------------- 1 files changed, 24 insertions(+), 23 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -133,7 +133,7 @@ .. versionadded:: 3.2 .. versionchanged:: 3.4 - Added ``file`` parameter + Added *file* parameter. .. function:: dis(x=None, *, file=None) @@ -147,11 +147,11 @@ disassembled. If no object is provided, this function disassembles the last traceback. - The disassembly is written as text to the supplied ``file`` argument if + The disassembly is written as text to the supplied *file* argument if provided and to ``sys.stdout`` otherwise. .. versionchanged:: 3.4 - Added ``file`` parameter + Added *file* parameter. .. function:: distb(tb=None, *, file=None) @@ -160,11 +160,11 @@ traceback if none was passed. The instruction causing the exception is indicated. - The disassembly is written as text to the supplied ``file`` argument if + The disassembly is written as text to the supplied *file* argument if provided and to ``sys.stdout`` otherwise. .. versionchanged:: 3.4 - Added ``file`` parameter + Added *file* parameter. .. function:: disassemble(code, lasti=-1, *, file=None) @@ -184,11 +184,11 @@ The parameter interpretation recognizes local and global variable names, constant values, branch targets, and compare operators. - The disassembly is written as text to the supplied ``file`` argument if + The disassembly is written as text to the supplied *file* argument if provided and to ``sys.stdout`` otherwise. .. versionchanged:: 3.4 - Added ``file`` parameter + Added *file* parameter. .. function:: get_instructions(x, *, first_line=None) @@ -512,7 +512,7 @@ Implements the expression statement for the interactive mode. TOS is removed from the stack and printed. In non-interactive mode, an expression statement is - terminated with ``POP_STACK``. + terminated with :opcode:`POP_TOP`. .. opcode:: BREAK_LOOP @@ -523,7 +523,7 @@ .. opcode:: CONTINUE_LOOP (target) Continues a loop due to a :keyword:`continue` statement. *target* is the - address to jump to (which should be a ``FOR_ITER`` instruction). + address to jump to (which should be a :opcode:`FOR_ITER` instruction). .. opcode:: SET_ADD (i) @@ -541,7 +541,8 @@ Calls ``dict.setitem(TOS1[-i], TOS, TOS1)``. Used to implement dict comprehensions. -For all of the SET_ADD, LIST_APPEND and MAP_ADD instructions, while the +For all of the :opcode:`SET_ADD`, :opcode:`LIST_APPEND` and :opcode:`MAP_ADD` +instructions, while the added value or key/value pair is popped off, the container object remains on the stack so that it is available for further iterations of the loop. @@ -594,7 +595,7 @@ .. opcode:: LOAD_BUILD_CLASS Pushes :func:`builtins.__build_class__` onto the stack. It is later called - by ``CALL_FUNCTION`` to construct a class. + by :opcode:`CALL_FUNCTION` to construct a class. .. opcode:: SETUP_WITH (delta) @@ -625,7 +626,7 @@ If the stack represents an exception, *and* the function call returns a 'true' value, this information is "zapped" and replaced with a single - ``WHY_SILENCED`` to prevent ``END_FINALLY`` from re-raising the exception. + ``WHY_SILENCED`` to prevent :opcode:`END_FINALLY` from re-raising the exception. (But non-local gotos will still be resumed.) .. XXX explain the WHY stuff! @@ -637,8 +638,8 @@ .. opcode:: STORE_NAME (namei) Implements ``name = TOS``. *namei* is the index of *name* in the attribute - :attr:`co_names` of the code object. The compiler tries to use ``STORE_FAST`` - or ``STORE_GLOBAL`` if possible. + :attr:`co_names` of the code object. The compiler tries to use :opcode:`STORE_FAST` + or :opcode:`STORE_GLOBAL` if possible. .. opcode:: DELETE_NAME (namei) @@ -678,12 +679,12 @@ .. opcode:: STORE_GLOBAL (namei) - Works as ``STORE_NAME``, but stores the name as a global. + Works as :opcode:`STORE_NAME`, but stores the name as a global. .. opcode:: DELETE_GLOBAL (namei) - Works as ``DELETE_NAME``, but deletes a global name. + Works as :opcode:`DELETE_NAME`, but deletes a global name. .. opcode:: LOAD_CONST (consti) @@ -704,12 +705,12 @@ .. opcode:: BUILD_LIST (count) - Works as ``BUILD_TUPLE``, but creates a list. + Works as :opcode:`BUILD_TUPLE`, but creates a list. .. opcode:: BUILD_SET (count) - Works as ``BUILD_TUPLE``, but creates a set. + Works as :opcode:`BUILD_TUPLE`, but creates a set. .. opcode:: BUILD_MAP (count) @@ -734,7 +735,7 @@ Imports the module ``co_names[namei]``. TOS and TOS1 are popped and provide the *fromlist* and *level* arguments of :func:`__import__`. The module object is pushed onto the stack. The current namespace is not affected: - for a proper import statement, a subsequent ``STORE_FAST`` instruction + for a proper import statement, a subsequent :opcode:`STORE_FAST` instruction modifies the namespace. @@ -742,7 +743,7 @@ Loads the attribute ``co_names[namei]`` from the module found in TOS. The resulting object is pushed onto the stack, to be subsequently stored by a - ``STORE_FAST`` instruction. + :opcode:`STORE_FAST` instruction. .. opcode:: JUMP_FORWARD (delta) @@ -921,21 +922,21 @@ .. opcode:: CALL_FUNCTION_VAR (argc) - Calls a function. *argc* is interpreted as in ``CALL_FUNCTION``. The top element + Calls a function. *argc* is interpreted as in :opcode:`CALL_FUNCTION`. The top element on the stack contains the variable argument list, followed by keyword and positional arguments. .. opcode:: CALL_FUNCTION_KW (argc) - Calls a function. *argc* is interpreted as in ``CALL_FUNCTION``. The top element + Calls a function. *argc* is interpreted as in :opcode:`CALL_FUNCTION`. The top element on the stack contains the keyword arguments dictionary, followed by explicit keyword and positional arguments. .. opcode:: CALL_FUNCTION_VAR_KW (argc) - Calls a function. *argc* is interpreted as in ``CALL_FUNCTION``. The top + Calls a function. *argc* is interpreted as in :opcode:`CALL_FUNCTION`. The top element on the stack contains the keyword arguments dictionary, followed by the variable-arguments tuple, followed by explicit keyword and positional arguments. -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Tue Nov 11 09:08:55 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 11 Nov 2014 09:08:55 +0100 Subject: [Python-checkins] Daily reference leaks (524a004e93dd): sum=3 Message-ID: results for 524a004e93dd on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogVqLPfR', '-x'] From python-checkins at python.org Tue Nov 11 16:24:40 2014 From: python-checkins at python.org (donald.stufft) Date: Tue, 11 Nov 2014 15:24:40 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Implement_PEP_?= =?utf-8?q?477_-_Backport_ensurepip_=28PEP_453=29_to_2=2E7?= Message-ID: <20141111152417.80124.60518@psf.io> https://hg.python.org/cpython/rev/592a5414fabd changeset: 93471:592a5414fabd branch: 2.7 user: Donald Stufft date: Tue Nov 11 10:24:11 2014 -0500 summary: Implement PEP 477 - Backport ensurepip (PEP 453) to 2.7 * Backports ensurepip to the 2.7 branch * Backports some of the improved documentation to the 2.7 branch. * Adds a private backport of the 3.x mock library as test._mock_backport to enable saner testing of ensurepip. Key Differences from 3.x: * Ensurepip does not have any Makefile integration, specifically it is not ran by default in the Makefile. * There is no venv module in 2.7, so downstream distributors can completely disable ensurepip, ideally with a message redirecting to the correct way to install pip. * To match the ``python`` command in 2.7, ensurepip will install the unversioned ``pip`` command as well. * No-op and hide --default-pip and add --no-default-pip to restore the 3.x behavor on 2.7. files: .hgeol | 1 + Doc/library/distribution.rst | 13 + Doc/library/ensurepip.rst | 130 + Doc/library/index.rst | 1 + Doc/library/python.rst | 1 - Doc/whatsnew/2.7.rst | 59 + Lib/ensurepip/__init__.py | 227 + Lib/ensurepip/__main__.py | 4 + Lib/ensurepip/_bundled/pip-1.5.6-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-3.6-py2.py3-none-any.whl | Bin Lib/ensurepip/_uninstall.py | 30 + Lib/test/_mock_backport.py | 2352 ++++++++++ Lib/test/test_ensurepip.py | 352 + Makefile.pre.in | 1 + Tools/scripts/checkpip.py | 31 + 15 files changed, 3201 insertions(+), 1 deletions(-) diff --git a/.hgeol b/.hgeol --- a/.hgeol +++ b/.hgeol @@ -26,6 +26,7 @@ **.psd = BIN **.tar = BIN **.wav = BIN +**.whl = BIN **.xar = BIN **.zip = BIN diff --git a/Doc/library/distribution.rst b/Doc/library/distribution.rst new file mode 100644 --- /dev/null +++ b/Doc/library/distribution.rst @@ -0,0 +1,13 @@ +*********************************** +Software Packaging and Distribution +*********************************** + +These libraries help you with publishing and installing Python software. +While these modules are designed to work in conjunction with the +`Python Package Index `__, they can also be used +with a local index server, or without any index server at all. + +.. toctree:: + + distutils.rst + ensurepip.rst diff --git a/Doc/library/ensurepip.rst b/Doc/library/ensurepip.rst new file mode 100644 --- /dev/null +++ b/Doc/library/ensurepip.rst @@ -0,0 +1,130 @@ +:mod:`ensurepip` --- Bootstrapping the ``pip`` installer +======================================================== + +.. module:: ensurepip + :synopsis: Bootstrapping the ``pip`` installer into an existing Python + installation or virtual environment. + +.. versionadded:: 2.7.9 + +The :mod:`ensurepip` package provides support for bootstrapping the ``pip`` +installer into an existing Python installation or virtual environment. This +bootstrapping approach reflects the fact that ``pip`` is an independent +project with its own release cycle, and the latest available stable version +is bundled with maintenance and feature releases of the CPython reference +interpreter. + +In most cases, end users of Python shouldn't need to invoke this module +directly (as ``pip`` should be bootstrapped by default), but it may be +needed if installing ``pip`` was skipped when installing Python (or +when creating a virtual environment) or after explicitly uninstalling ``pip``. + +.. note:: + + This module *does not* access the internet. All of the components + needed to bootstrap ``pip`` are included as internal parts of the + package. + +.. seealso:: + + :ref:`installing-index` + The end user guide for installing Python packages + + :pep:`453`: Explicit bootstrapping of pip in Python installations + The original rationale and specification for this module. + + :pep:`477`: Backport ensurepip (PEP 453) to Python 2.7 + The rationale and specification for backporting PEP 453 to Python 2.7. + + +Command line interface +---------------------- + +The command line interface is invoked using the interpreter's ``-m`` switch. + +The simplest possible invocation is:: + + python -m ensurepip + +This invocation will install ``pip`` if it is not already installed, +but otherwise does nothing. To ensure the installed version of ``pip`` +is at least as recent as the one bundled with ``ensurepip``, pass the +``--upgrade`` option:: + + python -m ensurepip --upgrade + +By default, ``pip`` is installed into the current virtual environment +(if one is active) or into the system site packages (if there is no +active virtual environment). The installation location can be controlled +through two additional command line options: + +* ``--root ``: Installs ``pip`` relative to the given root directory + rather than the root of the currently active virtual environment (if any) + or the default root for the current Python installation. +* ``--user``: Installs ``pip`` into the user site packages directory rather + than globally for the current Python installation (this option is not + permitted inside an active virtual environment). + +By default, the scripts ``pip``, ``pipX``, and ``pipX.Y`` will be installed +(where X.Y stands for the version of Python used to invoke ``ensurepip``). The +scripts installed can be controlled through two additional command line +options: + +* ``--altinstall``: if an alternate installation is requested, the ``pip`` and + ``pipX`` script will *not* be installed. + +* ``--no-default-pip``: if a non-default installation is request, the ``pip`` + script will *not* be installed. + + +Module API +---------- + +:mod:`ensurepip` exposes two functions for programmatic use: + +.. function:: version() + + Returns a string specifying the bundled version of pip that will be + installed when bootstrapping an environment. + +.. function:: bootstrap(root=None, upgrade=False, user=False, \ + altinstall=False, default_pip=True, \ + verbosity=0) + + Bootstraps ``pip`` into the current or designated environment. + + *root* specifies an alternative root directory to install relative to. + If *root* is None, then installation uses the default install location + for the current environment. + + *upgrade* indicates whether or not to upgrade an existing installation + of an earlier version of ``pip`` to the bundled version. + + *user* indicates whether to use the user scheme rather than installing + globally. + + By default, the scripts ``pip``, ``pipX``, and ``pipX.Y`` will be installed + (where X.Y stands for the current version of Python). + + If *altinstall* is set, then ``pip`` and ``pipX`` will *not* be installed. + + If *default_pip* is set to ``False``, then ``pip`` will *not* be installed. + + Setting both *altinstall* and *default_pip* will trigger + :exc:`ValueError`. + + *verbosity* controls the level of output to :data:`sys.stdout` from the + bootstrapping operation. + + .. note:: + + The bootstrapping process has side effects on both ``sys.path`` and + ``os.environ``. Invoking the command line interface in a subprocess + instead allows these side effects to be avoided. + + .. note:: + + The bootstrapping process may install additional modules required by + ``pip``, but other software should not assume those dependencies will + always be present by default (as the dependencies may be removed in a + future version of ``pip``). diff --git a/Doc/library/index.rst b/Doc/library/index.rst --- a/Doc/library/index.rst +++ b/Doc/library/index.rst @@ -63,6 +63,7 @@ tk.rst development.rst debug.rst + distribution.rst python.rst custominterp.rst restricted.rst diff --git a/Doc/library/python.rst b/Doc/library/python.rst --- a/Doc/library/python.rst +++ b/Doc/library/python.rst @@ -28,4 +28,3 @@ site.rst user.rst fpectl.rst - distutils.rst diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -2575,6 +2575,65 @@ Gaynor; :issue:`21305`.) +PEP 477: Backport ensurepip (PEP 453) to Python 2.7 +--------------------------------------------------- + +:pep:`477` approves the inclusion of the :pep:`453` ensurepip module and the +improved documentation that was enabled by it in the Python 2.7 maintenance +releases, appearing first in the the Python 2.7.9 release. + + +Bootstrapping pip By Default +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The new :mod:`ensurepip` module (defined in :pep:`453`) provides a standard +cross-platform mechanism to bootstrap the pip installer into Python +installations. The version of ``pip`` included with Python 2.7.9 is ``pip`` +1.5.6, and future 2.7.x maintenance releases will update the bundled version to +the latest version of ``pip`` that is available at the time of creating the +release candidate. + +By default, the commands ``pip``, ``pipX`` and ``pipX.Y`` will be installed on +all platforms (where X.Y stands for the version of the Python installation), +along with the ``pip`` Python package and its dependencies. + +On Windows and Mac OS X, the CPython installers now default to installing +``pip`` along with CPython itself (users may opt out of installing it +during the installation process). Window users will need to opt in to the +automatic ``PATH`` modifications to have ``pip`` available from the command +line by default, otherwise it can still be accessed through the Python +launcher for Windows as ``py -m pip``. + +As `discussed in the PEP`__, platform packagers may choose not to install +these commands by default, as long as, when invoked, they provide clear and +simple directions on how to install them on that platform (usually using +the system package manager). + +__ https://www.python.org/dev/peps/pep-0477/#disabling-ensurepip-by-downstream-distributors + + +Documentation Changes +~~~~~~~~~~~~~~~~~~~~~ + +As part of this change, the :ref:`installing-index` and +:ref:`distributing-index` sections of the documentation have been +completely redesigned as short getting started and FAQ documents. Most +packaging documentation has now been moved out to the Python Packaging +Authority maintained `Python Packaging User Guide +`__ and the documentation of the individual +projects. + +However, as this migration is currently still incomplete, the legacy +versions of those guides remaining available as :ref:`install-index` +and :ref:`distutils-index`. + +.. seealso:: + + :pep:`453` -- Explicit bootstrapping of pip in Python installations + PEP written by Donald Stufft and Nick Coghlan, implemented by + Donald Stufft, Nick Coghlan, Martin von L?wis and Ned Deily. + + .. ====================================================================== .. _acks27: diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py new file mode 100644 --- /dev/null +++ b/Lib/ensurepip/__init__.py @@ -0,0 +1,227 @@ +#!/usr/bin/env python2 +from __future__ import print_function + +import os +import os.path +import pkgutil +import shutil +import sys +import tempfile + + +__all__ = ["version", "bootstrap"] + + +_SETUPTOOLS_VERSION = "3.6" + +_PIP_VERSION = "1.5.6" + +# pip currently requires ssl support, so we try to provide a nicer +# error message when that is missing (http://bugs.python.org/issue19744) +_MISSING_SSL_MESSAGE = ("pip {} requires SSL/TLS".format(_PIP_VERSION)) +try: + import ssl +except ImportError: + ssl = None + + def _require_ssl_for_pip(): + raise RuntimeError(_MISSING_SSL_MESSAGE) +else: + def _require_ssl_for_pip(): + pass + +_PROJECTS = [ + ("setuptools", _SETUPTOOLS_VERSION), + ("pip", _PIP_VERSION), +] + + +def _run_pip(args, additional_paths=None): + # Add our bundled software to the sys.path so we can import it + if additional_paths is not None: + sys.path = additional_paths + sys.path + + # Install the bundled software + import pip + pip.main(args) + + +def version(): + """ + Returns a string specifying the bundled version of pip. + """ + return _PIP_VERSION + + +def _disable_pip_configuration_settings(): + # We deliberately ignore all pip environment variables + # when invoking pip + # See http://bugs.python.org/issue19734 for details + keys_to_remove = [k for k in os.environ if k.startswith("PIP_")] + for k in keys_to_remove: + del os.environ[k] + # We also ignore the settings in the default pip configuration file + # See http://bugs.python.org/issue20053 for details + os.environ['PIP_CONFIG_FILE'] = os.devnull + + +def bootstrap(root=None, upgrade=False, user=False, + altinstall=False, default_pip=True, + verbosity=0): + """ + Bootstrap pip into the current Python installation (or the given root + directory). + + Note that calling this function will alter both sys.path and os.environ. + """ + if altinstall and default_pip: + raise ValueError("Cannot use altinstall and default_pip together") + + _require_ssl_for_pip() + _disable_pip_configuration_settings() + + # By default, installing pip and setuptools installs all of the + # following scripts (X.Y == running Python version): + # + # pip, pipX, pipX.Y, easy_install, easy_install-X.Y + # + # pip 1.5+ allows ensurepip to request that some of those be left out + if altinstall: + # omit pip, pipX and easy_install + os.environ["ENSUREPIP_OPTIONS"] = "altinstall" + elif not default_pip: + # omit pip and easy_install + os.environ["ENSUREPIP_OPTIONS"] = "install" + + tmpdir = tempfile.mkdtemp() + try: + # Put our bundled wheels into a temporary directory and construct the + # additional paths that need added to sys.path + additional_paths = [] + for project, version in _PROJECTS: + wheel_name = "{}-{}-py2.py3-none-any.whl".format(project, version) + whl = pkgutil.get_data( + "ensurepip", + "_bundled/{}".format(wheel_name), + ) + with open(os.path.join(tmpdir, wheel_name), "wb") as fp: + fp.write(whl) + + 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] + if root: + args += ["--root", root] + if upgrade: + args += ["--upgrade"] + if user: + args += ["--user"] + if verbosity: + args += ["-" + "v" * verbosity] + + _run_pip(args + [p[0] for p in _PROJECTS], additional_paths) + finally: + shutil.rmtree(tmpdir, ignore_errors=True) + + +def _uninstall_helper(verbosity=0): + """Helper to support a clean default uninstall process on Windows + + Note that calling this function may alter os.environ. + """ + # Nothing to do if pip was never installed, or has been removed + try: + import pip + except ImportError: + return + + # If the pip version doesn't match the bundled one, leave it alone + if pip.__version__ != _PIP_VERSION: + msg = ("ensurepip will only uninstall a matching version " + "({!r} installed, {!r} bundled)") + print(msg.format(pip.__version__, _PIP_VERSION), file=sys.stderr) + return + + _require_ssl_for_pip() + _disable_pip_configuration_settings() + + # Construct the arguments to be passed to the pip command + args = ["uninstall", "-y"] + if verbosity: + args += ["-" + "v" * verbosity] + + _run_pip(args + [p[0] for p in reversed(_PROJECTS)]) + + +def _main(argv=None): + if ssl is None: + print("Ignoring ensurepip failure: {}".format(_MISSING_SSL_MESSAGE), + file=sys.stderr) + return + + import argparse + parser = argparse.ArgumentParser(prog="python -m ensurepip") + parser.add_argument( + "--version", + action="version", + version="pip {}".format(version()), + help="Show the version of pip that is bundled with this Python.", + ) + parser.add_argument( + "-v", "--verbose", + action="count", + default=0, + dest="verbosity", + help=("Give more output. Option is additive, and can be used up to 3 " + "times."), + ) + parser.add_argument( + "-U", "--upgrade", + action="store_true", + default=False, + help="Upgrade pip and dependencies, even if already installed.", + ) + parser.add_argument( + "--user", + action="store_true", + default=False, + help="Install using the user scheme.", + ) + parser.add_argument( + "--root", + default=None, + help="Install everything relative to this alternate root directory.", + ) + parser.add_argument( + "--altinstall", + action="store_true", + default=False, + help=("Make an alternate install, installing only the X.Y versioned" + "scripts (Default: pipX, pipX.Y, easy_install-X.Y)"), + ) + parser.add_argument( + "--default-pip", + action="store_true", + default=True, + dest="default_pip", + help=argparse.SUPPRESS, + ) + parser.add_argument( + "--no-default-pip", + action="store_false", + dest="default_pip", + help=("Make a non default install, installing only the X and X.Y " + "versioned scripts."), + ) + + args = parser.parse_args(argv) + + bootstrap( + root=args.root, + upgrade=args.upgrade, + user=args.user, + verbosity=args.verbosity, + altinstall=args.altinstall, + default_pip=args.default_pip, + ) diff --git a/Lib/ensurepip/__main__.py b/Lib/ensurepip/__main__.py new file mode 100644 --- /dev/null +++ b/Lib/ensurepip/__main__.py @@ -0,0 +1,4 @@ +import ensurepip + +if __name__ == "__main__": + ensurepip._main() diff --git a/Lib/ensurepip/_bundled/pip-1.5.6-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-1.5.6-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..097ab43430d4c1302b0be353a8c16407c370693b GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-3.6-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-3.6-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f0ffcfce5bb385e393a8385413f7a6092c51b33e GIT binary patch [stripped] diff --git a/Lib/ensurepip/_uninstall.py b/Lib/ensurepip/_uninstall.py new file mode 100644 --- /dev/null +++ b/Lib/ensurepip/_uninstall.py @@ -0,0 +1,30 @@ +"""Basic pip uninstallation support, helper for the Windows uninstaller""" + +import argparse +import ensurepip + + +def _main(argv=None): + parser = argparse.ArgumentParser(prog="python -m ensurepip._uninstall") + parser.add_argument( + "--version", + action="version", + version="pip {}".format(ensurepip.version()), + help="Show the version of pip this will attempt to uninstall.", + ) + parser.add_argument( + "-v", "--verbose", + action="count", + default=0, + dest="verbosity", + help=("Give more output. Option is additive, and can be used up to 3 " + "times."), + ) + + args = parser.parse_args(argv) + + ensurepip._uninstall_helper(verbosity=args.verbosity) + + +if __name__ == "__main__": + _main() diff --git a/Lib/test/_mock_backport.py b/Lib/test/_mock_backport.py new file mode 100644 --- /dev/null +++ b/Lib/test/_mock_backport.py @@ -0,0 +1,2352 @@ +# mock.py +# Test tools for mocking and patching. +# Maintained by Michael Foord +# Backport for other versions of Python available from +# http://pypi.python.org/pypi/mock + +__all__ = ( + 'Mock', + 'MagicMock', + 'patch', + 'sentinel', + 'DEFAULT', + 'ANY', + 'call', + 'create_autospec', + 'FILTER_DIR', + 'NonCallableMock', + 'NonCallableMagicMock', + 'mock_open', + 'PropertyMock', +) + + +__version__ = '1.0' + + +import inspect +import pprint +import sys + +from types import ModuleType +from functools import wraps, partial + + +_builtins = {name for name in __builtins__ if not name.startswith('_')} + +BaseExceptions = (BaseException,) +if 'java' in sys.platform: + # jython + import java + BaseExceptions = (BaseException, java.lang.Throwable) + + +FILTER_DIR = True + +# Workaround for issue #12370 +# Without this, the __class__ properties wouldn't be set correctly +_safe_super = super + +def _is_instance_mock(obj): + # can't use isinstance on Mock objects because they override __class__ + # The base class for all mocks is NonCallableMock + return issubclass(type(obj), NonCallableMock) + + +def _is_exception(obj): + return ( + isinstance(obj, BaseExceptions) or + isinstance(obj, type) and issubclass(obj, BaseExceptions) + ) + + +class _slotted(object): + __slots__ = ['a'] + + +DescriptorTypes = ( + type(_slotted.a), + property, +) + + +def _get_signature_object(func, as_instance, eat_self): + """ + Given an arbitrary, possibly callable object, try to create a suitable + signature object. + Return a (reduced func, signature) tuple, or None. + """ + if isinstance(func, type) and not as_instance: + # If it's a type and should be modelled as a type, use __init__. + try: + func = func.__init__ + except AttributeError: + return None + # Skip the `self` argument in __init__ + eat_self = True + elif not isinstance(func, FunctionTypes): + # If we really want to model an instance of the passed type, + # __call__ should be looked up, not __init__. + try: + func = func.__call__ + except AttributeError: + return None + if eat_self: + sig_func = partial(func, None) + else: + sig_func = func + try: + return func, inspect.signature(sig_func) + except ValueError: + # Certain callable types are not supported by inspect.signature() + return None + + +def _check_signature(func, mock, skipfirst, instance=False): + sig = _get_signature_object(func, instance, skipfirst) + if sig is None: + return + func, sig = sig + def checksig(_mock_self, *args, **kwargs): + sig.bind(*args, **kwargs) + _copy_func_details(func, checksig) + type(mock)._mock_check_sig = checksig + + +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 + 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): + if isinstance(obj, type): + return True + if getattr(obj, '__call__', None) is not None: + return True + return False + + +def _is_list(obj): + # checks for list or tuples + # XXXX badly named! + return type(obj) in (list, tuple) + + +def _instance_callable(obj): + """Given an object, return True if the object is callable. + For classes, return True if instances would be callable.""" + if not isinstance(obj, type): + # already an instance + return getattr(obj, '__call__', None) is not None + + # *could* be broken by a class overriding __mro__ or __dict__ via + # a metaclass + for base in (obj,) + obj.__mro__: + if base.__dict__.get('__call__') is not None: + return True + return False + + +def _set_signature(mock, original, instance=False): + # creates a function with signature (*args, **kwargs) that delegates to a + # mock. It still does signature checking by calling a lambda with the same + # signature as the original. + if not _callable(original): + return + + skipfirst = isinstance(original, type) + result = _get_signature_object(original, instance, skipfirst) + if result is None: + return + func, sig = result + def checksig(*args, **kwargs): + sig.bind(*args, **kwargs) + _copy_func_details(func, checksig) + + name = original.__name__ + if not name.isidentifier(): + name = 'funcopy' + context = {'_checksig_': checksig, 'mock': mock} + src = """def %s(*args, **kwargs): + _checksig_(*args, **kwargs) + return mock(*args, **kwargs)""" % name + exec (src, context) + funcopy = context[name] + _setup_func(funcopy, mock) + return funcopy + + +def _setup_func(funcopy, mock): + funcopy.mock = mock + + # can't use isinstance with mocks + if not _is_instance_mock(mock): + return + + def assert_called_with(*args, **kwargs): + return mock.assert_called_with(*args, **kwargs) + def assert_called_once_with(*args, **kwargs): + return mock.assert_called_once_with(*args, **kwargs) + def assert_has_calls(*args, **kwargs): + return mock.assert_has_calls(*args, **kwargs) + def assert_any_call(*args, **kwargs): + return mock.assert_any_call(*args, **kwargs) + def reset_mock(): + funcopy.method_calls = _CallList() + funcopy.mock_calls = _CallList() + mock.reset_mock() + ret = funcopy.return_value + if _is_instance_mock(ret) and not ret is mock: + ret.reset_mock() + + funcopy.called = False + funcopy.call_count = 0 + funcopy.call_args = None + funcopy.call_args_list = _CallList() + funcopy.method_calls = _CallList() + funcopy.mock_calls = _CallList() + + funcopy.return_value = mock.return_value + funcopy.side_effect = mock.side_effect + funcopy._mock_children = mock._mock_children + + funcopy.assert_called_with = assert_called_with + funcopy.assert_called_once_with = assert_called_once_with + funcopy.assert_has_calls = assert_has_calls + funcopy.assert_any_call = assert_any_call + funcopy.reset_mock = reset_mock + + mock._mock_delegate = funcopy + + +def _is_magic(name): + return '__%s__' % name[2:-2] == name + + +class _SentinelObject(object): + "A unique, named, sentinel object." + def __init__(self, name): + self.name = name + + def __repr__(self): + return 'sentinel.%s' % self.name + + +class _Sentinel(object): + """Access attributes to return a named object, usable as a sentinel.""" + def __init__(self): + self._sentinels = {} + + def __getattr__(self, name): + if name == '__bases__': + # Without this help(unittest.mock) raises an exception + raise AttributeError + return self._sentinels.setdefault(name, _SentinelObject(name)) + + +sentinel = _Sentinel() + +DEFAULT = sentinel.DEFAULT +_missing = sentinel.MISSING +_deleted = sentinel.DELETED + + +def _copy(value): + if type(value) in (dict, list, tuple, set): + return type(value)(value) + return value + + +_allowed_names = set( + [ + 'return_value', '_mock_return_value', 'side_effect', + '_mock_side_effect', '_mock_parent', '_mock_new_parent', + '_mock_name', '_mock_new_name' + ] +) + + +def _delegating_property(name): + _allowed_names.add(name) + _the_name = '_mock_' + name + def _get(self, name=name, _the_name=_the_name): + sig = self._mock_delegate + if sig is None: + return getattr(self, _the_name) + return getattr(sig, name) + def _set(self, value, name=name, _the_name=_the_name): + sig = self._mock_delegate + if sig is None: + self.__dict__[_the_name] = value + else: + setattr(sig, name, value) + + return property(_get, _set) + + + +class _CallList(list): + + def __contains__(self, value): + if not isinstance(value, list): + return list.__contains__(self, value) + len_value = len(value) + len_self = len(self) + if len_value > len_self: + return False + + for i in range(0, len_self - len_value + 1): + sub_list = self[i:i+len_value] + if sub_list == value: + return True + return False + + def __repr__(self): + return pprint.pformat(list(self)) + + +def _check_and_set_parent(parent, value, name, new_name): + if not _is_instance_mock(value): + return False + if ((value._mock_name or value._mock_new_name) or + (value._mock_parent is not None) or + (value._mock_new_parent is not None)): + return False + + _parent = parent + while _parent is not None: + # setting a mock (value) as a child or return value of itself + # should not modify the mock + if _parent is value: + return False + _parent = _parent._mock_new_parent + + if new_name: + value._mock_new_parent = parent + value._mock_new_name = new_name + if name: + value._mock_parent = parent + value._mock_name = name + return True + +# Internal class to identify if we wrapped an iterator object or not. +class _MockIter(object): + def __init__(self, obj): + self.obj = iter(obj) + def __iter__(self): + return self + def __next__(self): + return next(self.obj) + +class Base(object): + _mock_return_value = DEFAULT + _mock_side_effect = None + def __init__(self, *args, **kwargs): + pass + + + +class NonCallableMock(Base): + """A non-callable version of `Mock`""" + + def __new__(cls, *args, **kw): + # every instance has its own class + # so we can create magic methods on the + # class without stomping on other mocks + new = type(cls.__name__, (cls,), {'__doc__': cls.__doc__}) + instance = object.__new__(new) + return instance + + + def __init__( + self, spec=None, wraps=None, name=None, spec_set=None, + parent=None, _spec_state=None, _new_name='', _new_parent=None, + _spec_as_instance=False, _eat_self=None, unsafe=False, **kwargs + ): + if _new_parent is None: + _new_parent = parent + + __dict__ = self.__dict__ + __dict__['_mock_parent'] = parent + __dict__['_mock_name'] = name + __dict__['_mock_new_name'] = _new_name + __dict__['_mock_new_parent'] = _new_parent + + if spec_set is not None: + spec = spec_set + spec_set = True + if _eat_self is None: + _eat_self = parent is not None + + self._mock_add_spec(spec, spec_set, _spec_as_instance, _eat_self) + + __dict__['_mock_children'] = {} + __dict__['_mock_wraps'] = wraps + __dict__['_mock_delegate'] = None + + __dict__['_mock_called'] = False + __dict__['_mock_call_args'] = None + __dict__['_mock_call_count'] = 0 + __dict__['_mock_call_args_list'] = _CallList() + __dict__['_mock_mock_calls'] = _CallList() + + __dict__['method_calls'] = _CallList() + __dict__['_mock_unsafe'] = unsafe + + if kwargs: + self.configure_mock(**kwargs) + + _safe_super(NonCallableMock, self).__init__( + spec, wraps, name, spec_set, parent, + _spec_state + ) + + + def attach_mock(self, mock, attribute): + """ + Attach a mock as an attribute of this one, replacing its name and + parent. Calls to the attached mock will be recorded in the + `method_calls` and `mock_calls` attributes of this one.""" + mock._mock_parent = None + mock._mock_new_parent = None + mock._mock_name = '' + mock._mock_new_name = None + + setattr(self, attribute, mock) + + + def mock_add_spec(self, spec, spec_set=False): + """Add a spec to a mock. `spec` can either be an object or a + list of strings. Only attributes on the `spec` can be fetched as + attributes from the mock. + + If `spec_set` is True then only attributes on the spec can be set.""" + self._mock_add_spec(spec, spec_set) + + + def _mock_add_spec(self, spec, spec_set, _spec_as_instance=False, + _eat_self=False): + _spec_class = None + _spec_signature = None + + if spec is not None and not _is_list(spec): + if isinstance(spec, type): + _spec_class = spec + else: + _spec_class = _get_class(spec) + res = _get_signature_object(spec, + _spec_as_instance, _eat_self) + _spec_signature = res and res[1] + + spec = dir(spec) + + __dict__ = self.__dict__ + __dict__['_spec_class'] = _spec_class + __dict__['_spec_set'] = spec_set + __dict__['_spec_signature'] = _spec_signature + __dict__['_mock_methods'] = spec + + + def __get_return_value(self): + ret = self._mock_return_value + if self._mock_delegate is not None: + ret = self._mock_delegate.return_value + + if ret is DEFAULT: + ret = self._get_child_mock( + _new_parent=self, _new_name='()' + ) + self.return_value = ret + return ret + + + def __set_return_value(self, value): + if self._mock_delegate is not None: + self._mock_delegate.return_value = value + else: + self._mock_return_value = value + _check_and_set_parent(self, value, None, '()') + + __return_value_doc = "The value to be returned when the mock is called." + return_value = property(__get_return_value, __set_return_value, + __return_value_doc) + + + @property + def __class__(self): + if self._spec_class is None: + return type(self) + return self._spec_class + + called = _delegating_property('called') + call_count = _delegating_property('call_count') + call_args = _delegating_property('call_args') + call_args_list = _delegating_property('call_args_list') + mock_calls = _delegating_property('mock_calls') + + + def __get_side_effect(self): + delegated = self._mock_delegate + if delegated is None: + return self._mock_side_effect + sf = delegated.side_effect + if sf is not None and not callable(sf) and not isinstance(sf, _MockIter): + sf = _MockIter(sf) + delegated.side_effect = sf + return sf + + def __set_side_effect(self, value): + value = _try_iter(value) + delegated = self._mock_delegate + if delegated is None: + self._mock_side_effect = value + else: + delegated.side_effect = value + + side_effect = property(__get_side_effect, __set_side_effect) + + + def reset_mock(self): + "Restore the mock object to its initial state." + self.called = False + self.call_args = None + self.call_count = 0 + self.mock_calls = _CallList() + self.call_args_list = _CallList() + self.method_calls = _CallList() + + for child in self._mock_children.values(): + if isinstance(child, _SpecState): + continue + child.reset_mock() + + ret = self._mock_return_value + if _is_instance_mock(ret) and ret is not self: + ret.reset_mock() + + + def configure_mock(self, **kwargs): + """Set attributes on the mock through keyword arguments. + + Attributes plus return values and side effects can be set on child + mocks using standard dot notation and unpacking a dictionary in the + method call: + + >>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError} + >>> mock.configure_mock(**attrs)""" + for arg, val in sorted(kwargs.items(), + # we sort on the number of dots so that + # attributes are set before we set attributes on + # attributes + key=lambda entry: entry[0].count('.')): + args = arg.split('.') + final = args.pop() + obj = self + for entry in args: + obj = getattr(obj, entry) + setattr(obj, final, val) + + + def __getattr__(self, name): + if name in {'_mock_methods', '_mock_unsafe'}: + raise AttributeError(name) + elif self._mock_methods is not None: + if name not in self._mock_methods or name in _all_magics: + raise AttributeError("Mock object has no attribute %r" % name) + elif _is_magic(name): + raise AttributeError(name) + if not self._mock_unsafe: + if name.startswith(('assert', 'assret')): + raise AttributeError(name) + + result = self._mock_children.get(name) + if result is _deleted: + raise AttributeError(name) + elif result is None: + wraps = None + if self._mock_wraps is not None: + # XXXX should we get the attribute without triggering code + # execution? + wraps = getattr(self._mock_wraps, name) + + result = self._get_child_mock( + parent=self, name=name, wraps=wraps, _new_name=name, + _new_parent=self + ) + self._mock_children[name] = result + + elif isinstance(result, _SpecState): + result = create_autospec( + result.spec, result.spec_set, result.instance, + result.parent, result.name + ) + self._mock_children[name] = result + + return result + + + def __repr__(self): + _name_list = [self._mock_new_name] + _parent = self._mock_new_parent + last = self + + dot = '.' + if _name_list == ['()']: + dot = '' + seen = set() + while _parent is not None: + last = _parent + + _name_list.append(_parent._mock_new_name + dot) + dot = '.' + if _parent._mock_new_name == '()': + dot = '' + + _parent = _parent._mock_new_parent + + # use ids here so as not to call __hash__ on the mocks + if id(_parent) in seen: + break + seen.add(id(_parent)) + + _name_list = list(reversed(_name_list)) + _first = last._mock_name or 'mock' + if len(_name_list) > 1: + if _name_list[1] not in ('()', '().'): + _first += '.' + _name_list[0] = _first + name = ''.join(_name_list) + + name_string = '' + if name not in ('mock', 'mock.'): + name_string = ' name=%r' % name + + spec_string = '' + if self._spec_class is not None: + spec_string = ' spec=%r' + if self._spec_set: + spec_string = ' spec_set=%r' + spec_string = spec_string % self._spec_class.__name__ + return "<%s%s%s id='%s'>" % ( + type(self).__name__, + name_string, + spec_string, + id(self) + ) + + + def __dir__(self): + """Filter the output of `dir(mock)` to only useful members.""" + if not FILTER_DIR: + return object.__dir__(self) + + extras = self._mock_methods or [] + from_type = dir(type(self)) + from_dict = list(self.__dict__) + + from_type = [e for e in from_type if not e.startswith('_')] + from_dict = [e for e in from_dict if not e.startswith('_') or + _is_magic(e)] + return sorted(set(extras + from_type + from_dict + + list(self._mock_children))) + + + def __setattr__(self, name, value): + if name in _allowed_names: + # property setters go through here + return object.__setattr__(self, name, value) + elif (self._spec_set and self._mock_methods is not None and + name not in self._mock_methods and + name not in self.__dict__): + raise AttributeError("Mock object has no attribute '%s'" % name) + elif name in _unsupported_magics: + msg = 'Attempting to set unsupported magic method %r.' % name + raise AttributeError(msg) + elif name in _all_magics: + if self._mock_methods is not None and name not in self._mock_methods: + raise AttributeError("Mock object has no attribute '%s'" % name) + + if not _is_instance_mock(value): + setattr(type(self), name, _get_method(name, value)) + original = value + value = lambda *args, **kw: original(self, *args, **kw) + else: + # only set _new_name and not name so that mock_calls is tracked + # but not method calls + _check_and_set_parent(self, value, None, name) + setattr(type(self), name, value) + self._mock_children[name] = value + elif name == '__class__': + self._spec_class = value + return + else: + if _check_and_set_parent(self, value, name, name): + self._mock_children[name] = value + return object.__setattr__(self, name, value) + + + def __delattr__(self, name): + if name in _all_magics and name in type(self).__dict__: + delattr(type(self), name) + if name not in self.__dict__: + # for magic methods that are still MagicProxy objects and + # not set on the instance itself + return + + if name in self.__dict__: + object.__delattr__(self, name) + + obj = self._mock_children.get(name, _missing) + if obj is _deleted: + raise AttributeError(name) + if obj is not _missing: + del self._mock_children[name] + self._mock_children[name] = _deleted + + + def _format_mock_call_signature(self, args, kwargs): + name = self._mock_name or 'mock' + return _format_call_signature(name, args, kwargs) + + + def _format_mock_failure_message(self, args, kwargs): + message = 'Expected call: %s\nActual call: %s' + expected_string = self._format_mock_call_signature(args, kwargs) + call_args = self.call_args + if len(call_args) == 3: + call_args = call_args[1:] + actual_string = self._format_mock_call_signature(*call_args) + return message % (expected_string, actual_string) + + + def _call_matcher(self, _call): + """ + Given a call (or simply a (args, kwargs) tuple), return a + comparison key suitable for matching with other calls. + This is a best effort method which relies on the spec's signature, + if available, or falls back on the arguments themselves. + """ + sig = self._spec_signature + if sig is not None: + if len(_call) == 2: + name = '' + args, kwargs = _call + else: + name, args, kwargs = _call + try: + return name, sig.bind(*args, **kwargs) + except TypeError as e: + return e.with_traceback(None) + else: + return _call + + def assert_not_called(_mock_self): + """assert that the mock was never called. + """ + self = _mock_self + if self.call_count != 0: + msg = ("Expected '%s' to not have been called. Called %s times." % + (self._mock_name or 'mock', self.call_count)) + raise AssertionError(msg) + + def assert_called_with(_mock_self, *args, **kwargs): + """assert that the mock was called with the specified arguments. + + Raises an AssertionError if the args and keyword args passed in are + different to the last call to the mock.""" + self = _mock_self + if self.call_args is None: + expected = self._format_mock_call_signature(args, kwargs) + raise AssertionError('Expected call: %s\nNot called' % (expected,)) + + def _error_message(): + msg = self._format_mock_failure_message(args, kwargs) + return msg + expected = self._call_matcher((args, kwargs)) + actual = self._call_matcher(self.call_args) + if expected != actual: + raise AssertionError(_error_message()) + + + def assert_called_once_with(_mock_self, *args, **kwargs): + """assert that the mock was called exactly once and with the specified + arguments.""" + self = _mock_self + if not self.call_count == 1: + msg = ("Expected '%s' to be called once. Called %s times." % + (self._mock_name or 'mock', self.call_count)) + raise AssertionError(msg) + return self.assert_called_with(*args, **kwargs) + + + def assert_has_calls(self, calls, any_order=False): + """assert the mock has been called with the specified calls. + The `mock_calls` list is checked for the calls. + + If `any_order` is False (the default) then the calls must be + sequential. There can be extra calls before or after the + specified calls. + + If `any_order` is True then the calls can be in any order, but + they must all appear in `mock_calls`.""" + expected = [self._call_matcher(c) for c in calls] + all_calls = _CallList(self._call_matcher(c) for c in self.mock_calls) + if not any_order: + if expected not in all_calls: + raise AssertionError( + 'Calls not found.\nExpected: %r\n' + 'Actual: %r' % (calls, self.mock_calls) + ) + return + + all_calls = list(all_calls) + + not_found = [] + for kall in expected: + try: + all_calls.remove(kall) + except ValueError: + not_found.append(kall) + if not_found: + raise AssertionError( + '%r not all found in call list' % (tuple(not_found),) + ) + + + def assert_any_call(self, *args, **kwargs): + """assert the mock has been called with the specified arguments. + + The assert passes if the mock has *ever* been called, unlike + `assert_called_with` and `assert_called_once_with` that only pass if + the call is the most recent one.""" + expected = self._call_matcher((args, kwargs)) + actual = [self._call_matcher(c) for c in self.call_args_list] + if expected not in actual: + expected_string = self._format_mock_call_signature(args, kwargs) + raise AssertionError( + '%s call not found' % expected_string + ) + + + def _get_child_mock(self, **kw): + """Create the child mocks for attributes and return value. + By default child mocks will be the same type as the parent. + Subclasses of Mock may want to override this to customize the way + child mocks are made. + + For non-callable mocks the callable variant will be used (rather than + any custom subclass).""" + _type = type(self) + if not issubclass(_type, CallableMixin): + if issubclass(_type, NonCallableMagicMock): + klass = MagicMock + elif issubclass(_type, NonCallableMock) : + klass = Mock + else: + klass = _type.__mro__[1] + return klass(**kw) + + + +def _try_iter(obj): + if obj is None: + return obj + if _is_exception(obj): + return obj + if _callable(obj): + return obj + try: + return iter(obj) + except TypeError: + # XXXX backwards compatibility + # but this will blow up on first call - so maybe we should fail early? + return obj + + + +class CallableMixin(Base): + + def __init__(self, spec=None, side_effect=None, return_value=DEFAULT, + wraps=None, name=None, spec_set=None, parent=None, + _spec_state=None, _new_name='', _new_parent=None, **kwargs): + self.__dict__['_mock_return_value'] = return_value + + _safe_super(CallableMixin, self).__init__( + spec, wraps, name, spec_set, parent, + _spec_state, _new_name, _new_parent, **kwargs + ) + + self.side_effect = side_effect + + + def _mock_check_sig(self, *args, **kwargs): + # stub method that can be replaced with one with a specific signature + pass + + + def __call__(_mock_self, *args, **kwargs): + # can't use self in-case a function / method we are mocking uses self + # in the signature + _mock_self._mock_check_sig(*args, **kwargs) + return _mock_self._mock_call(*args, **kwargs) + + + def _mock_call(_mock_self, *args, **kwargs): + self = _mock_self + self.called = True + self.call_count += 1 + _new_name = self._mock_new_name + _new_parent = self._mock_new_parent + + _call = _Call((args, kwargs), two=True) + self.call_args = _call + self.call_args_list.append(_call) + self.mock_calls.append(_Call(('', args, kwargs))) + + seen = set() + skip_next_dot = _new_name == '()' + do_method_calls = self._mock_parent is not None + name = self._mock_name + while _new_parent is not None: + this_mock_call = _Call((_new_name, args, kwargs)) + if _new_parent._mock_new_name: + dot = '.' + if skip_next_dot: + dot = '' + + skip_next_dot = False + if _new_parent._mock_new_name == '()': + skip_next_dot = True + + _new_name = _new_parent._mock_new_name + dot + _new_name + + if do_method_calls: + if _new_name == name: + this_method_call = this_mock_call + else: + this_method_call = _Call((name, args, kwargs)) + _new_parent.method_calls.append(this_method_call) + + do_method_calls = _new_parent._mock_parent is not None + if do_method_calls: + name = _new_parent._mock_name + '.' + name + + _new_parent.mock_calls.append(this_mock_call) + _new_parent = _new_parent._mock_new_parent + + # use ids here so as not to call __hash__ on the mocks + _new_parent_id = id(_new_parent) + if _new_parent_id in seen: + break + seen.add(_new_parent_id) + + ret_val = DEFAULT + effect = self.side_effect + if effect is not None: + if _is_exception(effect): + raise effect + + if not _callable(effect): + result = next(effect) + if _is_exception(result): + raise result + if result is DEFAULT: + result = self.return_value + return result + + ret_val = effect(*args, **kwargs) + + if (self._mock_wraps is not None and + self._mock_return_value is DEFAULT): + return self._mock_wraps(*args, **kwargs) + if ret_val is DEFAULT: + ret_val = self.return_value + return ret_val + + + +class Mock(CallableMixin, NonCallableMock): + """ + Create a new `Mock` object. `Mock` takes several optional arguments + that specify the behaviour of the Mock object: + + * `spec`: This can be either a list of strings or an existing object (a + class or instance) that acts as the specification for the mock object. If + you pass in an object then a list of strings is formed by calling dir on + the object (excluding unsupported magic attributes and methods). Accessing + any attribute not in this list will raise an `AttributeError`. + + If `spec` is an object (rather than a list of strings) then + `mock.__class__` returns the class of the spec object. This allows mocks + to pass `isinstance` tests. + + * `spec_set`: A stricter variant of `spec`. If used, attempting to *set* + or get an attribute on the mock that isn't on the object passed as + `spec_set` will raise an `AttributeError`. + + * `side_effect`: A function to be called whenever the Mock is called. See + the `side_effect` attribute. Useful for raising exceptions or + dynamically changing return values. The function is called with the same + arguments as the mock, and unless it returns `DEFAULT`, the return + value of this function is used as the return value. + + If `side_effect` is an iterable then each call to the mock will return + the next value from the iterable. If any of the members of the iterable + are exceptions they will be raised instead of returned. + + * `return_value`: The value returned when the mock is called. By default + this is a new Mock (created on first access). See the + `return_value` attribute. + + * `wraps`: Item for the mock object to wrap. If `wraps` is not None then + calling the Mock will pass the call through to the wrapped object + (returning the real result). Attribute access on the mock will return a + Mock object that wraps the corresponding attribute of the wrapped object + (so attempting to access an attribute that doesn't exist will raise an + `AttributeError`). + + If the mock has an explicit `return_value` set then calls are not passed + to the wrapped object and the `return_value` is returned instead. + + * `name`: If the mock has a name then it will be used in the repr of the + mock. This can be useful for debugging. The name is propagated to child + mocks. + + Mocks can also be called with arbitrary keyword arguments. These will be + used to set attributes on the mock after it is created. + """ + + + +def _dot_lookup(thing, comp, import_path): + try: + return getattr(thing, comp) + except AttributeError: + __import__(import_path) + return getattr(thing, comp) + + +def _importer(target): + components = target.split('.') + import_path = components.pop(0) + thing = __import__(import_path) + + for comp in components: + import_path += ".%s" % comp + thing = _dot_lookup(thing, comp, import_path) + return thing + + +def _is_started(patcher): + # XXXX horrible + return hasattr(patcher, 'is_local') + + +class _patch(object): + + attribute_name = None + _active_patches = [] + + def __init__( + self, getter, attribute, new, spec, create, + spec_set, autospec, new_callable, kwargs + ): + if new_callable is not None: + if new is not DEFAULT: + raise ValueError( + "Cannot use 'new' and 'new_callable' together" + ) + if autospec is not None: + raise ValueError( + "Cannot use 'autospec' and 'new_callable' together" + ) + + self.getter = getter + self.attribute = attribute + self.new = new + self.new_callable = new_callable + self.spec = spec + self.create = create + self.has_local = False + self.spec_set = spec_set + self.autospec = autospec + self.kwargs = kwargs + self.additional_patchers = [] + + + def copy(self): + patcher = _patch( + self.getter, self.attribute, self.new, self.spec, + self.create, self.spec_set, + self.autospec, self.new_callable, self.kwargs + ) + patcher.attribute_name = self.attribute_name + patcher.additional_patchers = [ + p.copy() for p in self.additional_patchers + ] + return patcher + + + def __call__(self, func): + if isinstance(func, type): + return self.decorate_class(func) + return self.decorate_callable(func) + + + def decorate_class(self, klass): + for attr in dir(klass): + if not attr.startswith(patch.TEST_PREFIX): + continue + + attr_value = getattr(klass, attr) + if not hasattr(attr_value, "__call__"): + continue + + patcher = self.copy() + setattr(klass, attr, patcher(attr_value)) + return klass + + + def decorate_callable(self, func): + if hasattr(func, 'patchings'): + func.patchings.append(self) + return func + + @wraps(func) + def patched(*args, **keywargs): + extra_args = [] + entered_patchers = [] + + exc_info = tuple() + try: + for patching in patched.patchings: + arg = patching.__enter__() + entered_patchers.append(patching) + if patching.attribute_name is not None: + keywargs.update(arg) + elif patching.new is DEFAULT: + extra_args.append(arg) + + args += tuple(extra_args) + return func(*args, **keywargs) + except: + if (patching not in entered_patchers and + _is_started(patching)): + # the patcher may have been started, but an exception + # raised whilst entering one of its additional_patchers + entered_patchers.append(patching) + # Pass the exception to __exit__ + exc_info = sys.exc_info() + # re-raise the exception + raise + finally: + for patching in reversed(entered_patchers): + patching.__exit__(*exc_info) + + patched.patchings = [self] + return patched + + + def get_original(self): + target = self.getter() + name = self.attribute + + original = DEFAULT + local = False + + try: + original = target.__dict__[name] + except (AttributeError, KeyError): + original = getattr(target, name, DEFAULT) + else: + local = True + + if name in _builtins and isinstance(target, ModuleType): + self.create = True + + if not self.create and original is DEFAULT: + raise AttributeError( + "%s does not have the attribute %r" % (target, name) + ) + return original, local + + + def __enter__(self): + """Perform the patch.""" + new, spec, spec_set = self.new, self.spec, self.spec_set + autospec, kwargs = self.autospec, self.kwargs + new_callable = self.new_callable + self.target = self.getter() + + # normalise False to None + if spec is False: + spec = None + if spec_set is False: + spec_set = None + if autospec is False: + autospec = None + + if spec is not None and autospec is not None: + raise TypeError("Can't specify spec and autospec") + if ((spec is not None or autospec is not None) and + spec_set not in (True, None)): + raise TypeError("Can't provide explicit spec_set *and* spec or autospec") + + original, local = self.get_original() + + if new is DEFAULT and autospec is None: + inherit = False + if spec is True: + # set spec to the object we are replacing + spec = original + if spec_set is True: + spec_set = original + spec = None + elif spec is not None: + if spec_set is True: + spec_set = spec + spec = None + elif spec_set is True: + spec_set = original + + if spec is not None or spec_set is not None: + if original is DEFAULT: + raise TypeError("Can't use 'spec' with create=True") + if isinstance(original, type): + # If we're patching out a class and there is a spec + inherit = True + + Klass = MagicMock + _kwargs = {} + if new_callable is not None: + Klass = new_callable + elif spec is not None or spec_set is not None: + this_spec = spec + if spec_set is not None: + this_spec = spec_set + if _is_list(this_spec): + not_callable = '__call__' not in this_spec + else: + not_callable = not callable(this_spec) + if not_callable: + Klass = NonCallableMagicMock + + if spec is not None: + _kwargs['spec'] = spec + if spec_set is not None: + _kwargs['spec_set'] = spec_set + + # add a name to mocks + if (isinstance(Klass, type) and + issubclass(Klass, NonCallableMock) and self.attribute): + _kwargs['name'] = self.attribute + + _kwargs.update(kwargs) + new = Klass(**_kwargs) + + if inherit and _is_instance_mock(new): + # we can only tell if the instance should be callable if the + # spec is not a list + this_spec = spec + if spec_set is not None: + this_spec = spec_set + if (not _is_list(this_spec) and not + _instance_callable(this_spec)): + Klass = NonCallableMagicMock + + _kwargs.pop('name') + new.return_value = Klass(_new_parent=new, _new_name='()', + **_kwargs) + elif autospec is not None: + # spec is ignored, new *must* be default, spec_set is treated + # as a boolean. Should we check spec is not None and that spec_set + # is a bool? + if new is not DEFAULT: + raise TypeError( + "autospec creates the mock for you. Can't specify " + "autospec and new." + ) + if original is DEFAULT: + raise TypeError("Can't use 'autospec' with create=True") + spec_set = bool(spec_set) + if autospec is True: + autospec = original + + new = create_autospec(autospec, spec_set=spec_set, + _name=self.attribute, **kwargs) + elif kwargs: + # can't set keyword args when we aren't creating the mock + # XXXX If new is a Mock we could call new.configure_mock(**kwargs) + raise TypeError("Can't pass kwargs to a mock we aren't creating") + + new_attr = new + + self.temp_original = original + self.is_local = local + setattr(self.target, self.attribute, new_attr) + if self.attribute_name is not None: + extra_args = {} + if self.new is DEFAULT: + extra_args[self.attribute_name] = new + for patching in self.additional_patchers: + arg = patching.__enter__() + if patching.new is DEFAULT: + extra_args.update(arg) + return extra_args + + return new + + + def __exit__(self, *exc_info): + """Undo the patch.""" + if not _is_started(self): + raise RuntimeError('stop called on unstarted patcher') + + if self.is_local and self.temp_original is not DEFAULT: + setattr(self.target, self.attribute, self.temp_original) + else: + delattr(self.target, self.attribute) + if not self.create and not hasattr(self.target, self.attribute): + # needed for proxy objects like django settings + setattr(self.target, self.attribute, self.temp_original) + + del self.temp_original + del self.is_local + del self.target + for patcher in reversed(self.additional_patchers): + if _is_started(patcher): + patcher.__exit__(*exc_info) + + + def start(self): + """Activate a patch, returning any created mock.""" + result = self.__enter__() + self._active_patches.append(self) + return result + + + def stop(self): + """Stop an active patch.""" + try: + self._active_patches.remove(self) + except ValueError: + # If the patch hasn't been started this will fail + pass + + return self.__exit__() + + + +def _get_target(target): + try: + target, attribute = target.rsplit('.', 1) + except (TypeError, ValueError): + raise TypeError("Need a valid target to patch. You supplied: %r" % + (target,)) + getter = lambda: _importer(target) + return getter, attribute + + +def _patch_object( + target, attribute, new=DEFAULT, spec=None, + create=False, spec_set=None, autospec=None, + new_callable=None, **kwargs + ): + """ + patch the named member (`attribute`) on an object (`target`) with a mock + object. + + `patch.object` can be used as a decorator, class decorator or a context + manager. Arguments `new`, `spec`, `create`, `spec_set`, + `autospec` and `new_callable` have the same meaning as for `patch`. Like + `patch`, `patch.object` takes arbitrary keyword arguments for configuring + the mock object it creates. + + When used as a class decorator `patch.object` honours `patch.TEST_PREFIX` + for choosing which methods to wrap. + """ + getter = lambda: target + return _patch( + getter, attribute, new, spec, create, + spec_set, autospec, new_callable, kwargs + ) + + +def _patch_multiple(target, spec=None, create=False, spec_set=None, + autospec=None, new_callable=None, **kwargs): + """Perform multiple patches in a single call. It takes the object to be + patched (either as an object or a string to fetch the object by importing) + and keyword arguments for the patches:: + + with patch.multiple(settings, FIRST_PATCH='one', SECOND_PATCH='two'): + ... + + Use `DEFAULT` as the value if you want `patch.multiple` to create + mocks for you. In this case the created mocks are passed into a decorated + function by keyword, and a dictionary is returned when `patch.multiple` is + used as a context manager. + + `patch.multiple` can be used as a decorator, class decorator or a context + manager. The arguments `spec`, `spec_set`, `create`, + `autospec` and `new_callable` have the same meaning as for `patch`. These + arguments will be applied to *all* patches done by `patch.multiple`. + + When used as a class decorator `patch.multiple` honours `patch.TEST_PREFIX` + for choosing which methods to wrap. + """ + if type(target) is str: + getter = lambda: _importer(target) + else: + getter = lambda: target + + if not kwargs: + raise ValueError( + 'Must supply at least one keyword argument with patch.multiple' + ) + # need to wrap in a list for python 3, where items is a view + items = list(kwargs.items()) + attribute, new = items[0] + patcher = _patch( + getter, attribute, new, spec, create, spec_set, + autospec, new_callable, {} + ) + patcher.attribute_name = attribute + for attribute, new in items[1:]: + this_patcher = _patch( + getter, attribute, new, spec, create, spec_set, + autospec, new_callable, {} + ) + this_patcher.attribute_name = attribute + patcher.additional_patchers.append(this_patcher) + return patcher + + +def patch( + target, new=DEFAULT, spec=None, create=False, + spec_set=None, autospec=None, new_callable=None, **kwargs + ): + """ + `patch` acts as a function decorator, class decorator or a context + manager. Inside the body of the function or with statement, the `target` + is patched with a `new` object. When the function/with statement exits + the patch is undone. + + If `new` is omitted, then the target is replaced with a + `MagicMock`. If `patch` is used as a decorator and `new` is + omitted, the created mock is passed in as an extra argument to the + decorated function. If `patch` is used as a context manager the created + mock is returned by the context manager. + + `target` should be a string in the form `'package.module.ClassName'`. The + `target` is imported and the specified object replaced with the `new` + object, so the `target` must be importable from the environment you are + calling `patch` from. The target is imported when the decorated function + is executed, not at decoration time. + + The `spec` and `spec_set` keyword arguments are passed to the `MagicMock` + if patch is creating one for you. + + In addition you can pass `spec=True` or `spec_set=True`, which causes + patch to pass in the object being mocked as the spec/spec_set object. + + `new_callable` allows you to specify a different class, or callable object, + that will be called to create the `new` object. By default `MagicMock` is + used. + + A more powerful form of `spec` is `autospec`. If you set `autospec=True` + then the mock with be created with a spec from the object being replaced. + All attributes of the mock will also have the spec of the corresponding + attribute of the object being replaced. Methods and functions being + mocked will have their arguments checked and will raise a `TypeError` if + they are called with the wrong signature. For mocks replacing a class, + their return value (the 'instance') will have the same spec as the class. + + Instead of `autospec=True` you can pass `autospec=some_object` to use an + arbitrary object as the spec instead of the one being replaced. + + By default `patch` will fail to replace attributes that don't exist. If + you pass in `create=True`, and the attribute doesn't exist, patch will + create the attribute for you when the patched function is called, and + delete it again afterwards. This is useful for writing tests against + attributes that your production code creates at runtime. It is off by + default because it can be dangerous. With it switched on you can write + passing tests against APIs that don't actually exist! + + Patch can be used as a `TestCase` class decorator. It works by + decorating each test method in the class. This reduces the boilerplate + code when your test methods share a common patchings set. `patch` finds + tests by looking for method names that start with `patch.TEST_PREFIX`. + By default this is `test`, which matches the way `unittest` finds tests. + You can specify an alternative prefix by setting `patch.TEST_PREFIX`. + + Patch can be used as a context manager, with the with statement. Here the + patching applies to the indented block after the with statement. If you + use "as" then the patched object will be bound to the name after the + "as"; very useful if `patch` is creating a mock object for you. + + `patch` takes arbitrary keyword arguments. These will be passed to + the `Mock` (or `new_callable`) on construction. + + `patch.dict(...)`, `patch.multiple(...)` and `patch.object(...)` are + available for alternate use-cases. + """ + getter, attribute = _get_target(target) + return _patch( + getter, attribute, new, spec, create, + spec_set, autospec, new_callable, kwargs + ) + + +class _patch_dict(object): + """ + Patch a dictionary, or dictionary like object, and restore the dictionary + to its original state after the test. + + `in_dict` can be a dictionary or a mapping like container. If it is a + mapping then it must at least support getting, setting and deleting items + plus iterating over keys. + + `in_dict` can also be a string specifying the name of the dictionary, which + will then be fetched by importing it. + + `values` can be a dictionary of values to set in the dictionary. `values` + can also be an iterable of `(key, value)` pairs. + + If `clear` is True then the dictionary will be cleared before the new + values are set. + + `patch.dict` can also be called with arbitrary keyword arguments to set + values in the dictionary:: + + with patch.dict('sys.modules', mymodule=Mock(), other_module=Mock()): + ... + + `patch.dict` can be used as a context manager, decorator or class + decorator. When used as a class decorator `patch.dict` honours + `patch.TEST_PREFIX` for choosing which methods to wrap. + """ + + def __init__(self, in_dict, values=(), clear=False, **kwargs): + if isinstance(in_dict, str): + in_dict = _importer(in_dict) + self.in_dict = in_dict + # support any argument supported by dict(...) constructor + self.values = dict(values) + self.values.update(kwargs) + self.clear = clear + self._original = None + + + def __call__(self, f): + if isinstance(f, type): + return self.decorate_class(f) + @wraps(f) + def _inner(*args, **kw): + self._patch_dict() + try: + return f(*args, **kw) + finally: + self._unpatch_dict() + + return _inner + + + def decorate_class(self, klass): + for attr in dir(klass): + attr_value = getattr(klass, attr) + if (attr.startswith(patch.TEST_PREFIX) and + hasattr(attr_value, "__call__")): + decorator = _patch_dict(self.in_dict, self.values, self.clear) + decorated = decorator(attr_value) + setattr(klass, attr, decorated) + return klass + + + def __enter__(self): + """Patch the dict.""" + self._patch_dict() + + + def _patch_dict(self): + values = self.values + in_dict = self.in_dict + clear = self.clear + + try: + original = in_dict.copy() + except AttributeError: + # dict like object with no copy method + # must support iteration over keys + original = {} + for key in in_dict: + original[key] = in_dict[key] + self._original = original + + if clear: + _clear_dict(in_dict) + + try: + in_dict.update(values) + except AttributeError: + # dict like object with no update method + for key in values: + in_dict[key] = values[key] + + + def _unpatch_dict(self): + in_dict = self.in_dict + original = self._original + + _clear_dict(in_dict) + + try: + in_dict.update(original) + except AttributeError: + for key in original: + in_dict[key] = original[key] + + + def __exit__(self, *args): + """Unpatch the dict.""" + self._unpatch_dict() + return False + + start = __enter__ + stop = __exit__ + + +def _clear_dict(in_dict): + try: + in_dict.clear() + except AttributeError: + keys = list(in_dict) + for key in keys: + del in_dict[key] + + +def _patch_stopall(): + """Stop all active patches. LIFO to unroll nested patches.""" + for patch in reversed(_patch._active_patches): + patch.stop() + + +patch.object = _patch_object +patch.dict = _patch_dict +patch.multiple = _patch_multiple +patch.stopall = _patch_stopall +patch.TEST_PREFIX = 'test' + +magic_methods = ( + "lt le gt ge eq ne " + "getitem setitem delitem " + "len contains iter " + "hash str sizeof " + "enter exit " + "divmod neg pos abs invert " + "complex int float index " + "trunc floor ceil " + "bool next " +) + +numerics = ( + "add sub mul div floordiv mod lshift rshift and xor or pow truediv" +) +inplace = ' '.join('i%s' % n for n in numerics.split()) +right = ' '.join('r%s' % n for n in numerics.split()) + +# not including __prepare__, __instancecheck__, __subclasscheck__ +# (as they are metaclass methods) +# __del__ is not supported at all as it causes problems if it exists + +_non_defaults = set('__%s__' % method for method in [ + 'get', 'set', 'delete', 'reversed', 'missing', 'reduce', 'reduce_ex', + 'getinitargs', 'getnewargs', 'getstate', 'setstate', 'getformat', + 'setformat', 'repr', 'dir', 'subclasses', 'format', +]) + + +def _get_method(name, func): + "Turns a callable object (like a mock) into a real function" + def method(self, *args, **kw): + return func(self, *args, **kw) + method.__name__ = name + return method + + +_magics = set( + '__%s__' % method for method in + ' '.join([magic_methods, numerics, inplace, right]).split() +) + +_all_magics = _magics | _non_defaults + +_unsupported_magics = set([ + '__getattr__', '__setattr__', + '__init__', '__new__', '__prepare__' + '__instancecheck__', '__subclasscheck__', + '__del__' +]) + +_calculate_return_value = { + '__hash__': lambda self: object.__hash__(self), + '__str__': lambda self: object.__str__(self), + '__sizeof__': lambda self: object.__sizeof__(self), +} + +_return_values = { + '__lt__': NotImplemented, + '__gt__': NotImplemented, + '__le__': NotImplemented, + '__ge__': NotImplemented, + '__int__': 1, + '__contains__': False, + '__len__': 0, + '__exit__': False, + '__complex__': 1j, + '__float__': 1.0, + '__bool__': True, + '__index__': 1, +} + + +def _get_eq(self): + def __eq__(other): + ret_val = self.__eq__._mock_return_value + if ret_val is not DEFAULT: + return ret_val + return self is other + return __eq__ + +def _get_ne(self): + def __ne__(other): + if self.__ne__._mock_return_value is not DEFAULT: + return DEFAULT + return self is not other + return __ne__ + +def _get_iter(self): + def __iter__(): + ret_val = self.__iter__._mock_return_value + if ret_val is DEFAULT: + return iter([]) + # if ret_val was already an iterator, then calling iter on it should + # return the iterator unchanged + return iter(ret_val) + return __iter__ + +_side_effect_methods = { + '__eq__': _get_eq, + '__ne__': _get_ne, + '__iter__': _get_iter, +} + + + +def _set_return_value(mock, method, name): + fixed = _return_values.get(name, DEFAULT) + if fixed is not DEFAULT: + method.return_value = fixed + return + + return_calulator = _calculate_return_value.get(name) + if return_calulator is not None: + try: + return_value = return_calulator(mock) + except AttributeError: + # XXXX why do we return AttributeError here? + # set it as a side_effect instead? + return_value = AttributeError(name) + method.return_value = return_value + return + + side_effector = _side_effect_methods.get(name) + if side_effector is not None: + method.side_effect = side_effector(mock) + + + +class MagicMixin(object): + def __init__(self, *args, **kw): + _safe_super(MagicMixin, self).__init__(*args, **kw) + self._mock_set_magics() + + + def _mock_set_magics(self): + these_magics = _magics + + if self._mock_methods is not None: + these_magics = _magics.intersection(self._mock_methods) + + remove_magics = set() + remove_magics = _magics - these_magics + + for entry in remove_magics: + if entry in type(self).__dict__: + # remove unneeded magic methods + delattr(self, entry) + + # don't overwrite existing attributes if called a second time + these_magics = these_magics - set(type(self).__dict__) + + _type = type(self) + for entry in these_magics: + setattr(_type, entry, MagicProxy(entry, self)) + + + +class NonCallableMagicMock(MagicMixin, NonCallableMock): + """A version of `MagicMock` that isn't callable.""" + def mock_add_spec(self, spec, spec_set=False): + """Add a spec to a mock. `spec` can either be an object or a + list of strings. Only attributes on the `spec` can be fetched as + attributes from the mock. + + If `spec_set` is True then only attributes on the spec can be set.""" + self._mock_add_spec(spec, spec_set) + self._mock_set_magics() + + + +class MagicMock(MagicMixin, Mock): + """ + MagicMock is a subclass of Mock with default implementations + of most of the magic methods. You can use MagicMock without having to + configure the magic methods yourself. + + If you use the `spec` or `spec_set` arguments then *only* magic + methods that exist in the spec will be created. + + Attributes and the return value of a `MagicMock` will also be `MagicMocks`. + """ + def mock_add_spec(self, spec, spec_set=False): + """Add a spec to a mock. `spec` can either be an object or a + list of strings. Only attributes on the `spec` can be fetched as + attributes from the mock. + + If `spec_set` is True then only attributes on the spec can be set.""" + self._mock_add_spec(spec, spec_set) + self._mock_set_magics() + + + +class MagicProxy(object): + def __init__(self, name, parent): + self.name = name + self.parent = parent + + def __call__(self, *args, **kwargs): + m = self.create_mock() + return m(*args, **kwargs) + + def create_mock(self): + entry = self.name + parent = self.parent + m = parent._get_child_mock(name=entry, _new_name=entry, + _new_parent=parent) + setattr(parent, entry, m) + _set_return_value(parent, m, entry) + return m + + def __get__(self, obj, _type=None): + return self.create_mock() + + + +class _ANY(object): + "A helper object that compares equal to everything." + + def __eq__(self, other): + return True + + def __ne__(self, other): + return False + + def __repr__(self): + return '' + +ANY = _ANY() + + + +def _format_call_signature(name, args, kwargs): + message = '%s(%%s)' % name + formatted_args = '' + args_string = ', '.join([repr(arg) for arg in args]) + kwargs_string = ', '.join([ + '%s=%r' % (key, value) for key, value in sorted(kwargs.items()) + ]) + if args_string: + formatted_args = args_string + if kwargs_string: + if formatted_args: + formatted_args += ', ' + formatted_args += kwargs_string + + return message % formatted_args + + + +class _Call(tuple): + """ + A tuple for holding the results of a call to a mock, either in the form + `(args, kwargs)` or `(name, args, kwargs)`. + + If args or kwargs are empty then a call tuple will compare equal to + a tuple without those values. This makes comparisons less verbose:: + + _Call(('name', (), {})) == ('name',) + _Call(('name', (1,), {})) == ('name', (1,)) + _Call(((), {'a': 'b'})) == ({'a': 'b'},) + + The `_Call` object provides a useful shortcut for comparing with call:: + + _Call(((1, 2), {'a': 3})) == call(1, 2, a=3) + _Call(('foo', (1, 2), {'a': 3})) == call.foo(1, 2, a=3) + + If the _Call has no name then it will match any name. + """ + def __new__(cls, value=(), name=None, parent=None, two=False, + from_kall=True): + name = '' + args = () + kwargs = {} + _len = len(value) + if _len == 3: + name, args, kwargs = value + elif _len == 2: + first, second = value + if isinstance(first, str): + name = first + if isinstance(second, tuple): + args = second + else: + kwargs = second + else: + args, kwargs = first, second + elif _len == 1: + value, = value + if isinstance(value, str): + name = value + elif isinstance(value, tuple): + args = value + else: + kwargs = value + + if two: + return tuple.__new__(cls, (args, kwargs)) + + return tuple.__new__(cls, (name, args, kwargs)) + + + def __init__(self, value=(), name=None, parent=None, two=False, + from_kall=True): + self.name = name + self.parent = parent + self.from_kall = from_kall + + + def __eq__(self, other): + if other is ANY: + return True + try: + len_other = len(other) + except TypeError: + return False + + self_name = '' + if len(self) == 2: + self_args, self_kwargs = self + else: + self_name, self_args, self_kwargs = self + + other_name = '' + if len_other == 0: + other_args, other_kwargs = (), {} + elif len_other == 3: + other_name, other_args, other_kwargs = other + elif len_other == 1: + value, = other + if isinstance(value, tuple): + other_args = value + other_kwargs = {} + elif isinstance(value, str): + other_name = value + other_args, other_kwargs = (), {} + else: + other_args = () + other_kwargs = value + else: + # len 2 + # could be (name, args) or (name, kwargs) or (args, kwargs) + first, second = other + if isinstance(first, str): + other_name = first + if isinstance(second, tuple): + other_args, other_kwargs = second, {} + else: + other_args, other_kwargs = (), second + else: + other_args, other_kwargs = first, second + + if self_name and other_name != self_name: + return False + + # this order is important for ANY to work! + return (other_args, other_kwargs) == (self_args, self_kwargs) + + + def __ne__(self, other): + return not self.__eq__(other) + + + def __call__(self, *args, **kwargs): + if self.name is None: + return _Call(('', args, kwargs), name='()') + + name = self.name + '()' + return _Call((self.name, args, kwargs), name=name, parent=self) + + + def __getattr__(self, attr): + if self.name is None: + return _Call(name=attr, from_kall=False) + name = '%s.%s' % (self.name, attr) + return _Call(name=name, parent=self, from_kall=False) + + + def count(self, *args, **kwargs): + return self.__getattr__('count')(*args, **kwargs) + + def index(self, *args, **kwargs): + return self.__getattr__('index')(*args, **kwargs) + + def __repr__(self): + if not self.from_kall: + name = self.name or 'call' + if name.startswith('()'): + name = 'call%s' % name + return name + + if len(self) == 2: + name = 'call' + args, kwargs = self + else: + name, args, kwargs = self + if not name: + name = 'call' + elif not name.startswith('()'): + name = 'call.%s' % name + else: + name = 'call%s' % name + return _format_call_signature(name, args, kwargs) + + + def call_list(self): + """For a call object that represents multiple calls, `call_list` + returns a list of all the intermediate calls as well as the + final call.""" + vals = [] + thing = self + while thing is not None: + if thing.from_kall: + vals.append(thing) + thing = thing.parent + return _CallList(reversed(vals)) + + +call = _Call(from_kall=False) + + + +def create_autospec(spec, spec_set=False, instance=False, _parent=None, + _name=None, **kwargs): + """Create a mock object using another object as a spec. Attributes on the + mock will use the corresponding attribute on the `spec` object as their + spec. + + Functions or methods being mocked will have their arguments checked + to check that they are called with the correct signature. + + If `spec_set` is True then attempting to set attributes that don't exist + on the spec object will raise an `AttributeError`. + + If a class is used as a spec then the return value of the mock (the + instance of the class) will have the same spec. You can use a class as the + spec for an instance object by passing `instance=True`. The returned mock + will only be callable if instances of the mock are callable. + + `create_autospec` also takes arbitrary keyword arguments that are passed to + the constructor of the created mock.""" + if _is_list(spec): + # can't pass a list instance to the mock constructor as it will be + # interpreted as a list of strings + spec = type(spec) + + is_type = isinstance(spec, type) + + _kwargs = {'spec': spec} + if spec_set: + _kwargs = {'spec_set': spec} + elif spec is None: + # None we mock with a normal mock without a spec + _kwargs = {} + if _kwargs and instance: + _kwargs['_spec_as_instance'] = True + + _kwargs.update(kwargs) + + Klass = MagicMock + if type(spec) in DescriptorTypes: + # descriptors don't have a spec + # because we don't know what type they return + _kwargs = {} + elif not _callable(spec): + Klass = NonCallableMagicMock + elif is_type and instance and not _instance_callable(spec): + Klass = NonCallableMagicMock + + _name = _kwargs.pop('name', _name) + + _new_name = _name + if _parent is None: + # for a top level object no _new_name should be set + _new_name = '' + + mock = Klass(parent=_parent, _new_parent=_parent, _new_name=_new_name, + name=_name, **_kwargs) + + if isinstance(spec, FunctionTypes): + # should only happen at the top level because we don't + # recurse for functions + mock = _set_signature(mock, spec) + else: + _check_signature(spec, mock, is_type, instance) + + if _parent is not None and not instance: + _parent._mock_children[_name] = mock + + if is_type and not instance and 'return_value' not in kwargs: + mock.return_value = create_autospec(spec, spec_set, instance=True, + _name='()', _parent=mock) + + for entry in dir(spec): + if _is_magic(entry): + # MagicMock already does the useful magic methods for us + continue + + # XXXX do we need a better way of getting attributes without + # triggering code execution (?) Probably not - we need the actual + # object to mock it so we would rather trigger a property than mock + # the property descriptor. Likewise we want to mock out dynamically + # provided attributes. + # XXXX what about attributes that raise exceptions other than + # AttributeError on being fetched? + # we could be resilient against it, or catch and propagate the + # exception when the attribute is fetched from the mock + try: + original = getattr(spec, entry) + except AttributeError: + continue + + kwargs = {'spec': original} + if spec_set: + kwargs = {'spec_set': original} + + if not isinstance(original, FunctionTypes): + new = _SpecState(original, spec_set, mock, entry, instance) + mock._mock_children[entry] = new + else: + parent = mock + if isinstance(spec, FunctionTypes): + parent = mock.mock + + skipfirst = _must_skip(spec, entry, is_type) + kwargs['_eat_self'] = skipfirst + new = MagicMock(parent=parent, name=entry, _new_name=entry, + _new_parent=parent, + **kwargs) + mock._mock_children[entry] = new + _check_signature(original, new, skipfirst=skipfirst) + + # so functions created with _set_signature become instance attributes, + # *plus* their underlying mock exists in _mock_children of the parent + # mock. Adding to _mock_children may be unnecessary where we are also + # setting as an instance attribute? + if isinstance(new, FunctionTypes): + setattr(mock, entry, new) + + return mock + + +def _must_skip(spec, entry, is_type): + """ + Return whether we should skip the first argument on spec's `entry` + attribute. + """ + if not isinstance(spec, type): + if entry in getattr(spec, '__dict__', {}): + # instance attribute - shouldn't skip + return False + spec = spec.__class__ + + for klass in spec.__mro__: + result = klass.__dict__.get(entry, DEFAULT) + if result is DEFAULT: + continue + if isinstance(result, (staticmethod, classmethod)): + return False + elif isinstance(getattr(result, '__get__', None), MethodWrapperTypes): + # Normal method => skip if looked up on type + # (if looked up on instance, self is already skipped) + return is_type + else: + return False + + # shouldn't get here unless function is a dynamically provided attribute + # XXXX untested behaviour + return is_type + + +def _get_class(obj): + try: + return obj.__class__ + except AttributeError: + # it is possible for objects to have no __class__ + return type(obj) + + +class _SpecState(object): + + def __init__(self, spec, spec_set=False, parent=None, + name=None, ids=None, instance=False): + self.spec = spec + self.ids = ids + self.spec_set = spec_set + self.parent = parent + self.instance = instance + self.name = name + + +FunctionTypes = ( + # python function + type(create_autospec), + # instance method + type(ANY.__eq__), +) + +MethodWrapperTypes = ( + type(ANY.__eq__.__get__), +) + + +file_spec = None + +def _iterate_read_data(read_data): + # Helper for mock_open: + # Retrieve lines from read_data via a generator so that separate calls to + # readline, read, and readlines are properly interleaved + data_as_list = ['{}\n'.format(l) for l in read_data.split('\n')] + + if data_as_list[-1] == '\n': + # If the last line ended in a newline, the list comprehension will have an + # extra entry that's just a newline. Remove this. + data_as_list = data_as_list[:-1] + else: + # If there wasn't an extra newline by itself, then the file being + # emulated doesn't have a newline to end the last line remove the + # newline that our naive format() added + data_as_list[-1] = data_as_list[-1][:-1] + + for line in data_as_list: + yield line + +def mock_open(mock=None, read_data=''): + """ + A helper function to create a mock to replace the use of `open`. It works + for `open` called directly or used as a context manager. + + The `mock` argument is the mock object to configure. If `None` (the + default) then a `MagicMock` will be created for you, with the API limited + to methods or attributes available on standard file handles. + + `read_data` is a string for the `read` methoddline`, and `readlines` of the + file handle to return. This is an empty string by default. + """ + def _readlines_side_effect(*args, **kwargs): + if handle.readlines.return_value is not None: + return handle.readlines.return_value + return list(_data) + + def _read_side_effect(*args, **kwargs): + if handle.read.return_value is not None: + return handle.read.return_value + return ''.join(_data) + + def _readline_side_effect(): + if handle.readline.return_value is not None: + while True: + yield handle.readline.return_value + for line in _data: + yield line + + + global file_spec + if file_spec is None: + import _io + file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO)))) + + if mock is None: + mock = MagicMock(name='open', spec=open) + + handle = MagicMock(spec=file_spec) + handle.__enter__.return_value = handle + + _data = _iterate_read_data(read_data) + + handle.write.return_value = None + handle.read.return_value = None + handle.readline.return_value = None + handle.readlines.return_value = None + + handle.read.side_effect = _read_side_effect + handle.readline.side_effect = _readline_side_effect() + handle.readlines.side_effect = _readlines_side_effect + + mock.return_value = handle + return mock + + +class PropertyMock(Mock): + """ + A mock intended to be used as a property, or other descriptor, on a class. + `PropertyMock` provides `__get__` and `__set__` methods so you can specify + a return value when it is fetched. + + Fetching a `PropertyMock` instance from an object calls the mock, with + no args. Setting it calls the mock with the value being set. + """ + def _get_child_mock(self, **kwargs): + return MagicMock(**kwargs) + + def __get__(self, obj, obj_type): + return self() + def __set__(self, obj, val): + self(val) diff --git a/Lib/test/test_ensurepip.py b/Lib/test/test_ensurepip.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_ensurepip.py @@ -0,0 +1,352 @@ +import unittest +import os +import os.path +import contextlib +import sys +import test._mock_backport as mock +import test.test_support + +import ensurepip +import ensurepip._uninstall + +# pip currently requires ssl support, so we ensure we handle +# it being missing (http://bugs.python.org/issue19744) +ensurepip_no_ssl = test.test_support.import_fresh_module("ensurepip", + blocked=["ssl"]) +try: + import ssl +except ImportError: + ssl = None + + def requires_usable_pip(f): + deco = unittest.skip(ensurepip._MISSING_SSL_MESSAGE) + return deco(f) +else: + def requires_usable_pip(f): + return f + + +class TestEnsurePipVersion(unittest.TestCase): + + def test_returns_version(self): + self.assertEqual(ensurepip._PIP_VERSION, ensurepip.version()) + + +class EnsurepipMixin: + + def setUp(self): + run_pip_patch = mock.patch("ensurepip._run_pip") + self.run_pip = run_pip_patch.start() + self.addCleanup(run_pip_patch.stop) + + # Avoid side effects on the actual os module + real_devnull = os.devnull + os_patch = mock.patch("ensurepip.os") + patched_os = os_patch.start() + self.addCleanup(os_patch.stop) + patched_os.devnull = real_devnull + patched_os.path = os.path + self.os_environ = patched_os.environ = os.environ.copy() + + +class TestBootstrap(EnsurepipMixin, unittest.TestCase): + + @requires_usable_pip + def test_basic_bootstrapping(self): + ensurepip.bootstrap() + + self.run_pip.assert_called_once_with( + [ + "install", "--no-index", "--find-links", + mock.ANY, "setuptools", "pip", + ], + mock.ANY, + ) + + additional_paths = self.run_pip.call_args[0][1] + self.assertEqual(len(additional_paths), 2) + + @requires_usable_pip + def test_bootstrapping_with_root(self): + ensurepip.bootstrap(root="/foo/bar/") + + self.run_pip.assert_called_once_with( + [ + "install", "--no-index", "--find-links", + mock.ANY, "--root", "/foo/bar/", + "setuptools", "pip", + ], + mock.ANY, + ) + + @requires_usable_pip + def test_bootstrapping_with_user(self): + ensurepip.bootstrap(user=True) + + self.run_pip.assert_called_once_with( + [ + "install", "--no-index", "--find-links", + mock.ANY, "--user", "setuptools", "pip", + ], + mock.ANY, + ) + + @requires_usable_pip + def test_bootstrapping_with_upgrade(self): + ensurepip.bootstrap(upgrade=True) + + self.run_pip.assert_called_once_with( + [ + "install", "--no-index", "--find-links", + mock.ANY, "--upgrade", "setuptools", "pip", + ], + mock.ANY, + ) + + @requires_usable_pip + def test_bootstrapping_with_verbosity_1(self): + ensurepip.bootstrap(verbosity=1) + + self.run_pip.assert_called_once_with( + [ + "install", "--no-index", "--find-links", + mock.ANY, "-v", "setuptools", "pip", + ], + mock.ANY, + ) + + @requires_usable_pip + def test_bootstrapping_with_verbosity_2(self): + ensurepip.bootstrap(verbosity=2) + + self.run_pip.assert_called_once_with( + [ + "install", "--no-index", "--find-links", + mock.ANY, "-vv", "setuptools", "pip", + ], + mock.ANY, + ) + + @requires_usable_pip + def test_bootstrapping_with_verbosity_3(self): + ensurepip.bootstrap(verbosity=3) + + self.run_pip.assert_called_once_with( + [ + "install", "--no-index", "--find-links", + mock.ANY, "-vvv", "setuptools", "pip", + ], + mock.ANY, + ) + + @requires_usable_pip + def test_bootstrapping_with_regular_install(self): + ensurepip.bootstrap() + self.assertEqual(self.os_environ["ENSUREPIP_OPTIONS"], "install") + + @requires_usable_pip + def test_bootstrapping_with_alt_install(self): + ensurepip.bootstrap(altinstall=True) + self.assertEqual(self.os_environ["ENSUREPIP_OPTIONS"], "altinstall") + + @requires_usable_pip + def test_bootstrapping_with_default_pip(self): + ensurepip.bootstrap(default_pip=True) + self.assertNotIn("ENSUREPIP_OPTIONS", self.os_environ) + + def test_altinstall_default_pip_conflict(self): + with self.assertRaises(ValueError): + ensurepip.bootstrap(altinstall=True, default_pip=True) + self.assertFalse(self.run_pip.called) + + @requires_usable_pip + def test_pip_environment_variables_removed(self): + # ensurepip deliberately ignores all pip environment variables + # See http://bugs.python.org/issue19734 for details + self.os_environ["PIP_THIS_SHOULD_GO_AWAY"] = "test fodder" + ensurepip.bootstrap() + self.assertNotIn("PIP_THIS_SHOULD_GO_AWAY", self.os_environ) + + @requires_usable_pip + def test_pip_config_file_disabled(self): + # ensurepip deliberately ignores the pip config file + # See http://bugs.python.org/issue20053 for details + ensurepip.bootstrap() + self.assertEqual(self.os_environ["PIP_CONFIG_FILE"], os.devnull) + + + at contextlib.contextmanager +def fake_pip(version=ensurepip._PIP_VERSION): + if version is None: + pip = None + else: + class FakePip(): + __version__ = version + pip = FakePip() + sentinel = object() + orig_pip = sys.modules.get("pip", sentinel) + sys.modules["pip"] = pip + try: + yield pip + finally: + if orig_pip is sentinel: + del sys.modules["pip"] + else: + sys.modules["pip"] = orig_pip + + +class TestUninstall(EnsurepipMixin, unittest.TestCase): + + def test_uninstall_skipped_when_not_installed(self): + with fake_pip(None): + ensurepip._uninstall_helper() + self.assertFalse(self.run_pip.called) + + def test_uninstall_skipped_with_warning_for_wrong_version(self): + with fake_pip("not a valid version"): + with test.test_support.captured_stderr() as stderr: + ensurepip._uninstall_helper() + warning = stderr.getvalue().strip() + self.assertIn("only uninstall a matching version", warning) + self.assertFalse(self.run_pip.called) + + @requires_usable_pip + def test_uninstall(self): + with fake_pip(): + ensurepip._uninstall_helper() + + self.run_pip.assert_called_once_with( + ["uninstall", "-y", "pip", "setuptools"] + ) + + @requires_usable_pip + def test_uninstall_with_verbosity_1(self): + with fake_pip(): + ensurepip._uninstall_helper(verbosity=1) + + self.run_pip.assert_called_once_with( + ["uninstall", "-y", "-v", "pip", "setuptools"] + ) + + @requires_usable_pip + def test_uninstall_with_verbosity_2(self): + with fake_pip(): + ensurepip._uninstall_helper(verbosity=2) + + self.run_pip.assert_called_once_with( + ["uninstall", "-y", "-vv", "pip", "setuptools"] + ) + + @requires_usable_pip + def test_uninstall_with_verbosity_3(self): + with fake_pip(): + ensurepip._uninstall_helper(verbosity=3) + + self.run_pip.assert_called_once_with( + ["uninstall", "-y", "-vvv", "pip", "setuptools"] + ) + + @requires_usable_pip + def test_pip_environment_variables_removed(self): + # ensurepip deliberately ignores all pip environment variables + # See http://bugs.python.org/issue19734 for details + self.os_environ["PIP_THIS_SHOULD_GO_AWAY"] = "test fodder" + with fake_pip(): + ensurepip._uninstall_helper() + self.assertNotIn("PIP_THIS_SHOULD_GO_AWAY", self.os_environ) + + @requires_usable_pip + def test_pip_config_file_disabled(self): + # ensurepip deliberately ignores the pip config file + # See http://bugs.python.org/issue20053 for details + with fake_pip(): + ensurepip._uninstall_helper() + self.assertEqual(self.os_environ["PIP_CONFIG_FILE"], os.devnull) + + +class TestMissingSSL(EnsurepipMixin, unittest.TestCase): + + def setUp(self): + sys.modules["ensurepip"] = ensurepip_no_ssl + + @self.addCleanup + def restore_module(): + sys.modules["ensurepip"] = ensurepip + super(TestMissingSSL, self).setUp() + + def test_bootstrap_requires_ssl(self): + self.os_environ["PIP_THIS_SHOULD_STAY"] = "test fodder" + with self.assertRaisesRegexp(RuntimeError, "requires SSL/TLS"): + ensurepip_no_ssl.bootstrap() + self.assertFalse(self.run_pip.called) + self.assertIn("PIP_THIS_SHOULD_STAY", self.os_environ) + + def test_uninstall_requires_ssl(self): + self.os_environ["PIP_THIS_SHOULD_STAY"] = "test fodder" + with self.assertRaisesRegexp(RuntimeError, "requires SSL/TLS"): + with fake_pip(): + ensurepip_no_ssl._uninstall_helper() + self.assertFalse(self.run_pip.called) + self.assertIn("PIP_THIS_SHOULD_STAY", self.os_environ) + + def test_main_exits_early_with_warning(self): + with test.test_support.captured_stderr() as stderr: + ensurepip_no_ssl._main(["--version"]) + warning = stderr.getvalue().strip() + self.assertTrue(warning.endswith("requires SSL/TLS"), warning) + self.assertFalse(self.run_pip.called) + +# Basic testing of the main functions and their argument parsing + +EXPECTED_VERSION_OUTPUT = "pip " + ensurepip._PIP_VERSION + + +class TestBootstrappingMainFunction(EnsurepipMixin, unittest.TestCase): + + @requires_usable_pip + def test_bootstrap_version(self): + with test.test_support.captured_stderr() as stderr: + with self.assertRaises(SystemExit): + ensurepip._main(["--version"]) + result = stderr.getvalue().strip() + self.assertEqual(result, EXPECTED_VERSION_OUTPUT) + self.assertFalse(self.run_pip.called) + + @requires_usable_pip + def test_basic_bootstrapping(self): + ensurepip._main([]) + + self.run_pip.assert_called_once_with( + [ + "install", "--no-index", "--find-links", + mock.ANY, "setuptools", "pip", + ], + mock.ANY, + ) + + additional_paths = self.run_pip.call_args[0][1] + self.assertEqual(len(additional_paths), 2) + + +class TestUninstallationMainFunction(EnsurepipMixin, unittest.TestCase): + + def test_uninstall_version(self): + with test.test_support.captured_stderr() as stderr: + with self.assertRaises(SystemExit): + ensurepip._uninstall._main(["--version"]) + result = stderr.getvalue().strip() + self.assertEqual(result, EXPECTED_VERSION_OUTPUT) + self.assertFalse(self.run_pip.called) + + @requires_usable_pip + def test_basic_uninstall(self): + with fake_pip(): + ensurepip._uninstall._main([]) + + self.run_pip.assert_called_once_with( + ["uninstall", "-y", "pip", "setuptools"] + ) + + +if __name__ == "__main__": + test.test_support.run_unittest(__name__) diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -947,6 +947,7 @@ test/tracedmodules \ encodings compiler hotshot \ email email/mime email/test email/test/data \ + ensurepip ensurepip/_bundled \ json json/tests \ sqlite3 sqlite3/test \ logging bsddb bsddb/test csv importlib wsgiref \ diff --git a/Tools/scripts/checkpip.py b/Tools/scripts/checkpip.py new file mode 100644 --- /dev/null +++ b/Tools/scripts/checkpip.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python2 +""" +Checks that the version of the projects bundled in ensurepip are the latest +versions available. +""" +import ensurepip +import json +import urllib2 +import sys + + +def main(): + outofdate = False + + for project, version in ensurepip._PROJECTS: + data = json.loads(urllib2.urlopen( + "https://pypi.python.org/pypi/{}/json".format(project), + ).read().decode("utf8")) + upstream_version = data["info"]["version"] + + if version != upstream_version: + outofdate = True + print("The latest version of {} on PyPI is {}, but ensurepip " + "has {}".format(project, upstream_version, version)) + + if outofdate: + sys.exit(1) + + +if __name__ == "__main__": + main() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 11 16:54:16 2014 From: python-checkins at python.org (donald.stufft) Date: Tue, 11 Nov 2014 15:54:16 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Upgrade_setupt?= =?utf-8?q?ools_to_7=2E0?= Message-ID: <20141111155404.118387.9654@psf.io> https://hg.python.org/cpython/rev/ed696903ad48 changeset: 93472:ed696903ad48 branch: 2.7 user: Donald Stufft date: Tue Nov 11 10:53:50 2014 -0500 summary: Upgrade setuptools to 7.0 files: Lib/ensurepip/__init__.py | 2 +- Lib/ensurepip/_bundled/setuptools-3.6-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-7.0-py2.py3-none-any.whl | Bin 3 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -12,7 +12,7 @@ __all__ = ["version", "bootstrap"] -_SETUPTOOLS_VERSION = "3.6" +_SETUPTOOLS_VERSION = "7.0" _PIP_VERSION = "1.5.6" diff --git a/Lib/ensurepip/_bundled/setuptools-3.6-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-3.6-py2.py3-none-any.whl deleted file mode 100644 index f0ffcfce5bb385e393a8385413f7a6092c51b33e..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-7.0-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-7.0-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fa1d1054da1dab98f8906555d31a9fda271b3a85 GIT binary patch [stripped] -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 11 17:02:02 2014 From: python-checkins at python.org (donald.stufft) Date: Tue, 11 Nov 2014 16:02:02 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Upgrade_setupt?= =?utf-8?q?ools_to_7=2E0?= Message-ID: <20141111160115.9575.48252@psf.io> https://hg.python.org/cpython/rev/33908f14c0eb changeset: 93473:33908f14c0eb branch: 3.4 parent: 93468:d676f2725699 user: Donald Stufft date: Tue Nov 11 11:01:09 2014 -0500 summary: Upgrade setuptools to 7.0 files: Lib/ensurepip/__init__.py | 2 +- Lib/ensurepip/_bundled/setuptools-2.1-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-7.0-py2.py3-none-any.whl | Bin 3 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -8,7 +8,7 @@ __all__ = ["version", "bootstrap"] -_SETUPTOOLS_VERSION = "2.1" +_SETUPTOOLS_VERSION = "7.0" _PIP_VERSION = "1.5.6" 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 deleted file mode 100644 index ed77b59e632f32d09a3ae52adaa7f3e6659d8b48..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-7.0-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-7.0-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fa1d1054da1dab98f8906555d31a9fda271b3a85 GIT binary patch [stripped] -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 11 17:08:59 2014 From: python-checkins at python.org (donald.stufft) Date: Tue, 11 Nov 2014 16:08:59 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_-_Upgrade_setuptools_to_7=2E0?= Message-ID: <20141111160701.118383.98440@psf.io> https://hg.python.org/cpython/rev/d25c58a420d6 changeset: 93474:d25c58a420d6 parent: 93469:ac0334665459 parent: 93473:33908f14c0eb user: Donald Stufft date: Tue Nov 11 11:06:49 2014 -0500 summary: Merge - Upgrade setuptools to 7.0 files: Lib/ensurepip/__init__.py | 2 +- Lib/ensurepip/_bundled/setuptools-3.6-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-7.0-py2.py3-none-any.whl | Bin 3 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -8,7 +8,7 @@ __all__ = ["version", "bootstrap"] -_SETUPTOOLS_VERSION = "3.6" +_SETUPTOOLS_VERSION = "7.0" _PIP_VERSION = "1.5.6" diff --git a/Lib/ensurepip/_bundled/setuptools-3.6-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-3.6-py2.py3-none-any.whl deleted file mode 100644 index f0ffcfce5bb385e393a8385413f7a6092c51b33e..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-7.0-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-7.0-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fa1d1054da1dab98f8906555d31a9fda271b3a85 GIT binary patch [stripped] -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 11 18:33:24 2014 From: python-checkins at python.org (donald.stufft) Date: Tue, 11 Nov 2014 17:33:24 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogRGVmaW5lIGEgX19o?= =?utf-8?q?ash=5F=5F_to_quiet_down_a_-3_warning?= Message-ID: <20141111173302.118381.24834@psf.io> https://hg.python.org/cpython/rev/e4c32152b25b changeset: 93475:e4c32152b25b branch: 2.7 parent: 93472:ed696903ad48 user: Donald Stufft date: Tue Nov 11 12:32:57 2014 -0500 summary: Define a __hash__ to quiet down a -3 warning files: Lib/test/_mock_backport.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/test/_mock_backport.py b/Lib/test/_mock_backport.py --- a/Lib/test/_mock_backport.py +++ b/Lib/test/_mock_backport.py @@ -1873,6 +1873,8 @@ class _ANY(object): "A helper object that compares equal to everything." + __hash__ = object.__hash__ + def __eq__(self, other): return True @@ -1923,6 +1925,9 @@ If the _Call has no name then it will match any name. """ + + __hash__ = object.__hash__ + def __new__(cls, value=(), name=None, parent=None, two=False, from_kall=True): name = '' -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 11 20:16:13 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 11 Nov 2014 19:16:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Minor_code_clean_up_and_im?= =?utf-8?q?provements_in_the_re_module=2E?= Message-ID: <20141111191528.21117.82488@psf.io> https://hg.python.org/cpython/rev/30a6c74ad87f changeset: 93476:30a6c74ad87f parent: 93474:d25c58a420d6 user: Serhiy Storchaka date: Tue Nov 11 21:13:28 2014 +0200 summary: Minor code clean up and improvements in the re module. files: Lib/re.py | 2 +- Lib/sre_compile.py | 16 ++++++---------- Lib/sre_parse.py | 8 ++++---- Lib/test/test_re.py | 4 ++-- 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/Lib/re.py b/Lib/re.py --- a/Lib/re.py +++ b/Lib/re.py @@ -363,7 +363,7 @@ append = result.append match = self.scanner.scanner(string).match i = 0 - while 1: + while True: m = match() if not m: break diff --git a/Lib/sre_compile.py b/Lib/sre_compile.py --- a/Lib/sre_compile.py +++ b/Lib/sre_compile.py @@ -16,11 +16,6 @@ assert _sre.MAGIC == MAGIC, "SRE module mismatch" -if _sre.CODESIZE == 2: - MAXCODE = 65535 -else: - MAXCODE = 0xFFFFFFFF - _LITERAL_CODES = {LITERAL, NOT_LITERAL} _REPEATING_CODES = {REPEAT, MIN_REPEAT, MAX_REPEAT} _SUCCESS_CODES = {SUCCESS, FAILURE} @@ -191,7 +186,7 @@ emit(JUMP) tailappend(_len(code)); emit(0) code[skip] = _len(code) - skip - emit(0) # end of branch + emit(FAILURE) # end of branch for tail in tail: code[tail] = _len(code) - tail elif op is CATEGORY: @@ -374,6 +369,7 @@ return out _CODEBITS = _sre.CODESIZE * 8 +MAXCODE = (1 << _CODEBITS) - 1 _BITS_TRANS = b'0' + b'1' * 255 def _mk_bitmap(bits, _CODEBITS=_CODEBITS, _int=int): s = bits.translate(_BITS_TRANS)[::-1] @@ -477,9 +473,9 @@ elif op is IN: charset = av ## if prefix: -## print "*** PREFIX", prefix, prefix_skip +## print("*** PREFIX", prefix, prefix_skip) ## if charset: -## print "*** CHARSET", charset +## print("*** CHARSET", charset) # add an info block emit = code.append emit(INFO) @@ -489,9 +485,9 @@ if prefix: mask = SRE_INFO_PREFIX if len(prefix) == prefix_skip == len(pattern.data): - mask = mask + SRE_INFO_LITERAL + mask = mask | SRE_INFO_LITERAL elif charset: - mask = mask + SRE_INFO_CHARSET + mask = mask | SRE_INFO_CHARSET emit(mask) # pattern length if lo < MAXCODE: diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -103,18 +103,18 @@ seqtypes = (tuple, list) for op, av in self.data: print(level*" " + str(op), end='') - if op == IN: + if op is IN: # member sublanguage print() for op, a in av: print((level+1)*" " + str(op), a) - elif op == BRANCH: + elif op is BRANCH: print() for i, a in enumerate(av[1]): if i: print(level*" " + "OR") a.dump(level+1) - elif op == GROUPREF_EXISTS: + elif op is GROUPREF_EXISTS: condgroup, item_yes, item_no = av print('', condgroup) item_yes.dump(level+1) @@ -607,7 +607,7 @@ item = subpattern[-1:] else: item = None - if not item or (_len(item) == 1 and item[0][0] == AT): + if not item or (_len(item) == 1 and item[0][0] is AT): raise source.error("nothing to repeat", source.tell() - here + len(this)) if item[0][0] in _REPEATCODES: diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -1101,8 +1101,8 @@ def test_inline_flags(self): # Bug #1700 - upper_char = chr(0x1ea0) # Latin Capital Letter A with Dot Bellow - lower_char = chr(0x1ea1) # Latin Small Letter A with Dot Bellow + upper_char = '\u1ea0' # Latin Capital Letter A with Dot Below + lower_char = '\u1ea1' # Latin Small Letter A with Dot Below p = re.compile(upper_char, re.I | re.U) q = p.match(lower_char) -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Wed Nov 12 10:32:12 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 12 Nov 2014 10:32:12 +0100 Subject: [Python-checkins] Daily reference leaks (30a6c74ad87f): sum=0 Message-ID: results for 30a6c74ad87f on branch "default" -------------------------------------------- test_collections leaked [4, 0, -6] references, sum=-2 test_collections leaked [2, 0, -3] memory blocks, sum=-1 test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog6b1Mhr', '-x'] From python-checkins at python.org Wed Nov 12 14:34:16 2014 From: python-checkins at python.org (nick.coghlan) Date: Wed, 12 Nov 2014 13:34:16 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Close_=2319494=3A_add_urrl?= =?utf-8?q?ib=2Erequest=2EHTTPBasicPriorAuthHandler?= Message-ID: <20141112133402.47808.62976@psf.io> https://hg.python.org/cpython/rev/fb3061ba6fd2 changeset: 93477:fb3061ba6fd2 user: Nick Coghlan date: Wed Nov 12 23:33:50 2014 +1000 summary: Close #19494: add urrlib.request.HTTPBasicPriorAuthHandler This auth handler adds the Authorization header to the first HTTP request rather than waiting for a HTTP 401 Unauthorized response from the server as the default HTTPBasicAuthHandler does. This allows working with websites like https://api.github.com which do not follow the strict interpretation of RFC, but more the dicta in the end of section 2 of RFC 2617: > A client MAY preemptively send the corresponding Authorization > header with requests for resources in that space without receipt > of another challenge from the server. Similarly, when a client > sends a request to a proxy, it may reuse a userid and password in > the Proxy-Authorization header field without receiving another > challenge from the proxy server. See section 4 for security > considerations associated with Basic authentication. Patch by Matej Cepl. files: Doc/library/urllib.request.rst | 11 +++++++++++ Doc/whatsnew/3.5.rst | 9 +++++++++ Lib/test/test_urllib2.py | 15 +++++++++++++++ Lib/urllib/request.py | 15 +++++++++++++++ Misc/NEWS | 3 +++ 5 files changed, 53 insertions(+), 0 deletions(-) diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -304,6 +304,17 @@ presented with a wrong Authentication scheme. +.. class:: HTTPBasicPriorAuthHandler(password_mgr=None) + + A variant of :class:`HTTPBasicAuthHandler` which automatically sends + authorization credentials with the first request, rather than waiting to + first receive a HTTP 401 "Unauthorised" error response. This allows + authentication to sites that don't provide a 401 response when receiving + a request without an Authorization header. Aside from this difference, + this behaves exactly as :class:`HTTPBasicAuthHandler`. + + .. versionadded:: 3.5 + .. class:: ProxyBasicAuthHandler(password_mgr=None) Handle authentication with the proxy. *password_mgr*, if given, should be diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -297,6 +297,15 @@ * The :func:`time.monotonic` function is now always available. (Contributed by Victor Stinner in :issue:`22043`.) +time +---- + +* A new :class:`urllib.request.HTTPBasicPriorAuthHandler` allows HTTP Basic + Authentication credentials to be sent unconditionally with the first HTTP + request, rather than waiting for a HTTP 401 Unauthorized response from the + server. + (Contributed by Matej Cepl in :issue:`19494`.) + wsgiref ------- diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -1422,6 +1422,21 @@ handler.do_open(conn, req) self.assertTrue(conn.fakesock.closed, "Connection not closed") + def test_auth_prior_handler(self): + pwd_manager = MockPasswordManager() + pwd_manager.add_password(None, 'https://example.com', + 'somebody', 'verysecret') + auth_prior_handler = urllib.request.HTTPBasicPriorAuthHandler( + pwd_manager) + http_hand = MockHTTPSHandler() + + opener = OpenerDirector() + opener.add_handler(http_hand) + opener.add_handler(auth_prior_handler) + + req = Request("https://example.com") + opener.open(req) + self.assertNotIn('Authorization', http_hand.httpconn.req_headers) class MiscTests(unittest.TestCase): diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -916,6 +916,21 @@ return response +class HTTPBasicPriorAuthHandler(HTTPBasicAuthHandler): + handler_order = 400 + + def http_request(self, req): + if not req.has_header('Authorization'): + user, passwd = self.passwd.find_user_password(None, req.host) + credentials = '{0}:{1}'.format(user, passwd).encode() + auth_str = base64.standard_b64encode(credentials).decode() + req.add_unredirected_header('Authorization', + 'Basic {}'.format(auth_str.strip())) + return req + + https_request = http_request + + # Return n random bytes. _randombytes = os.urandom diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -183,6 +183,9 @@ Library ------- +- Issue #19494: Added urllib.request.HTTPBasicPriorAuthHandler. Patch by + Matej Cepl. + - Issue #22578: Added attributes to the re.error class. - Issue #12728: Different Unicode characters having the same uppercase but -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 12 16:24:31 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 12 Nov 2014 15:24:31 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_add_space?= Message-ID: <20141112152406.67922.8051@psf.io> https://hg.python.org/cpython/rev/19b2c54e5f09 changeset: 93480:19b2c54e5f09 user: Benjamin Peterson date: Wed Nov 12 10:23:44 2014 -0500 summary: add space files: Lib/test/test_io.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -2890,6 +2890,7 @@ arr.frombytes(buf[:idx]) return memoryview(arr) + class CTextIOWrapperTest(TextIOWrapperTest): io = io shutdown_error = "RuntimeError: could not find io module state" -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 12 16:24:31 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 12 Nov 2014 15:24:31 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_fix_possible_d?= =?utf-8?q?ouble_free_in_TextIOWrapper=2E=5F=5Finit=5F=5F_=28closes_=23228?= =?utf-8?b?NDkp?= Message-ID: <20141112152405.47788.48154@psf.io> https://hg.python.org/cpython/rev/ec1948191461 changeset: 93478:ec1948191461 branch: 3.4 parent: 93473:33908f14c0eb user: Benjamin Peterson date: Wed Nov 12 10:19:46 2014 -0500 summary: fix possible double free in TextIOWrapper.__init__ (closes #22849) files: Lib/test/test_io.py | 15 +++++++++++++++ Misc/NEWS | 2 ++ Modules/_io/textio.c | 2 +- 3 files changed, 18 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -2784,6 +2784,21 @@ self.assertFalse(err) self.assertEqual("ok", out.decode().strip()) + def test_issue22849(self): + class F(object): + def readable(self): return True + def writable(self): return True + def seekable(self): return True + + for i in range(10): + try: + self.TextIOWrapper(F(), encoding='utf-8') + except Exception: + pass + + F.tell = lambda x: 0 + t = self.TextIOWrapper(F(), encoding='utf-8') + class CTextIOWrapperTest(TextIOWrapperTest): io = io diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,8 @@ Library ------- +- Issue #22849: Fix possible double free in the io.TextIOWrapper constructor. + - Issue #12728: Different Unicode characters having the same uppercase but different lowercase are now matched in case-insensitive regular expressions. diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1061,7 +1061,7 @@ } /* Finished sorting out the codec details */ - Py_DECREF(codec_info); + Py_CLEAR(codec_info); self->buffer = buffer; Py_INCREF(buffer); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 12 16:24:31 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 12 Nov 2014 15:24:31 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjMjI4NDkp?= Message-ID: <20141112152405.118103.78819@psf.io> https://hg.python.org/cpython/rev/a664b150b6c2 changeset: 93479:a664b150b6c2 parent: 93477:fb3061ba6fd2 parent: 93478:ec1948191461 user: Benjamin Peterson date: Wed Nov 12 10:23:35 2014 -0500 summary: merge 3.4 (#22849) files: Lib/test/test_io.py | 16 ++++++++++++++++ Misc/NEWS | 2 ++ Modules/_io/textio.c | 2 +- 3 files changed, 19 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -2856,6 +2856,22 @@ self.assertEqual(t.read(200), bytes_val.decode('utf-8')) + def test_issue22849(self): + class F(object): + def readable(self): return True + def writable(self): return True + def seekable(self): return True + + for i in range(10): + try: + self.TextIOWrapper(F(), encoding='utf-8') + except Exception: + pass + + F.tell = lambda x: 0 + t = self.TextIOWrapper(F(), encoding='utf-8') + + class MemviewBytesIO(io.BytesIO): '''A BytesIO object whose read method returns memoryviews rather than bytes''' diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -188,6 +188,8 @@ - Issue #22578: Added attributes to the re.error class. +- Issue #22849: Fix possible double free in the io.TextIOWrapper constructor. + - Issue #12728: Different Unicode characters having the same uppercase but different lowercase are now matched in case-insensitive regular expressions. diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1061,7 +1061,7 @@ } /* Finished sorting out the codec details */ - Py_DECREF(codec_info); + Py_CLEAR(codec_info); self->buffer = buffer; Py_INCREF(buffer); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 13 04:03:06 2014 From: python-checkins at python.org (steve.dower) Date: Thu, 13 Nov 2014 03:03:06 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIyODUw?= =?utf-8?q?=3A_Backport_ensurepip_Windows_installer_changes_to_2=2E7?= Message-ID: <20141113030255.118111.30981@psf.io> https://hg.python.org/cpython/rev/c248a6bdc1d7 changeset: 93481:c248a6bdc1d7 branch: 2.7 parent: 93475:e4c32152b25b user: Steve Dower date: Wed Nov 12 19:02:20 2014 -0800 summary: Issue #22850: Backport ensurepip Windows installer changes to 2.7 files: Tools/msi/msi.py | 47 +++++++++++++++++++++++++---------- 1 files changed, 33 insertions(+), 14 deletions(-) diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py --- a/Tools/msi/msi.py +++ b/Tools/msi/msi.py @@ -410,6 +410,8 @@ compileargs = r'-Wi "[TARGETDIR]Lib\compileall.py" -f -x "bad_coding|badsyntax|site-packages|py3_" "[TARGETDIR]Lib"' lib2to3args = r'-c "import lib2to3.pygram, lib2to3.patcomp;lib2to3.patcomp.PatternCompiler()"' + updatepipargs = r'-m ensurepip -U --default-pip' + removepipargs = r'-B -m ensurepip._uninstall' # See "CustomAction Table" add_data(db, "CustomAction", [ # msidbCustomActionTypeFirstSequence + msidbCustomActionTypeTextData + msidbCustomActionTypeProperty @@ -421,9 +423,13 @@ ("SetDLLDirToSystem32", 307, "DLLDIR", SystemFolderName), # msidbCustomActionTypeExe + msidbCustomActionTypeSourceFile # See "Custom Action Type 18" - ("CompilePyc", 18, "python.exe", compileargs), - ("CompilePyo", 18, "python.exe", "-O "+compileargs), - ("CompileGrammar", 18, "python.exe", lib2to3args), + # msidbCustomActionTypeInScript (1024); run during actual installation + # msidbCustomActionTypeNoImpersonate (2048); run action in system account, not user account + ("CompilePyc", 18+1024+2048, "python.exe", compileargs), + ("CompilePyo", 18+1024+2048, "python.exe", "-O "+compileargs), + ("CompileGrammar", 18+1024+2048, "python.exe", lib2to3args), + ("UpdatePip", 18+1024+2048, "python.exe", updatepipargs), + ("RemovePip", 18+1024+2048, "python.exe", removepipargs), ]) # UI Sequences, see "InstallUISequence Table", "Using a Sequence Table" @@ -447,7 +453,7 @@ # Prepend TARGETDIR to the system path, and remove it on uninstall. add_data(db, "Environment", - [("PathAddition", "=-*Path", "[TARGETDIR];[~]", "REGISTRY.path")]) + [("PathAddition", "=-*Path", "[TARGETDIR];[TARGETDIR]Scripts;[~]", "REGISTRY.path")]) # Execute Sequences add_data(db, "InstallExecuteSequence", @@ -455,16 +461,19 @@ ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751), ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752), ("UpdateEditIDLE", None, 1050), - ("CompilePyc", "COMPILEALL", 6800), - ("CompilePyo", "COMPILEALL", 6801), - ("CompileGrammar", "COMPILEALL", 6802), + # run command if install state of pip changes to INSTALLSTATE_LOCAL + # run after InstallFiles + ("UpdatePip", "&pip_feature=3", 4001), + # remove pip when state changes to INSTALLSTATE_ABSENT + # run before RemoveFiles + ("RemovePip", "&pip_feature=2", 3499), + ("CompilePyc", "COMPILEALL", 4002), + ("CompilePyo", "COMPILEALL", 4003), + ("CompileGrammar", "COMPILEALL", 4004), ]) add_data(db, "AdminExecuteSequence", [("InitialTargetDir", 'TARGETDIR=""', 750), ("SetDLLDirToTarget", 'DLLDIR=""', 751), - ("CompilePyc", "COMPILEALL", 6800), - ("CompilePyo", "COMPILEALL", 6801), - ("CompileGrammar", "COMPILEALL", 6802), ]) ##################################################################### @@ -830,7 +839,8 @@ # (i.e. additional Python libraries) need to follow the parent feature. # Features that have no advertisement trigger (e.g. the test suite) # must not support advertisement - global default_feature, tcltk, htmlfiles, tools, testsuite, ext_feature, private_crt, prepend_path + global default_feature, tcltk, htmlfiles, tools, testsuite + global ext_feature, private_crt, prepend_path, pip_feature default_feature = Feature(db, "DefaultFeature", "Python", "Python Interpreter and Libraries", 1, directory = "TARGETDIR") @@ -852,8 +862,12 @@ tools = Feature(db, "Tools", "Utility Scripts", "Python utility scripts (Tools/", 9, parent = default_feature, attributes=2) + pip_feature = Feature(db, "pip_feature", "pip", + "Install or upgrade pip, a tool for installing and managing " + "Python packages.", 11, + parent = default_feature, attributes=2|8) testsuite = Feature(db, "Testsuite", "Test suite", - "Python test suite (Lib/test/)", 11, + "Python test suite (Lib/test/)", 13, parent = default_feature, attributes=2|8) # prepend_path is an additional feature which is to be off by default. # Since the default level for the above features is 1, this needs to be @@ -861,7 +875,7 @@ prepend_path = Feature(db, "PrependPath", "Add python.exe to Path", "Prepend [TARGETDIR] to the system Path variable. " "This allows you to type 'python' into a command " - "prompt without needing the full path.", 13, + "prompt without needing the full path.", 15, parent = default_feature, attributes=2|8, level=2) @@ -1188,6 +1202,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". @@ -1205,6 +1221,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 ) @@ -1287,7 +1304,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: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 13 08:20:06 2014 From: python-checkins at python.org (larry.hastings) Date: Thu, 13 Nov 2014 07:20:06 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Fixed_reference_to_Argument_C?= =?utf-8?q?linic_PEP_in_3=2E5_schedule=2E?= Message-ID: <20141113071952.67900.67624@psf.io> https://hg.python.org/peps/rev/23c7fb8febda changeset: 5593:23c7fb8febda user: Larry Hastings date: Wed Nov 12 23:19:48 2014 -0800 summary: Fixed reference to Argument Clinic PEP in 3.5 schedule. files: pep-0478.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0478.txt b/pep-0478.txt --- a/pep-0478.txt +++ b/pep-0478.txt @@ -68,11 +68,11 @@ * PEP 431, improved support for time zone databases * PEP 432, simplifying Python's startup sequence +* PEP 436, a build tool generating boilerplate for extension modules * PEP 441, improved Python zip application support * PEP 447, support for __locallookup__ metaclass method * PEP 448, additional unpacking generalizations * PEP 455, key transforming dictionary -* PEP 457, a build tool generating boilerplate for extension modules * PEP 475, retrying system calls that fail with EINTR -- Repository URL: https://hg.python.org/peps From solipsis at pitrou.net Thu Nov 13 10:34:37 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 13 Nov 2014 10:34:37 +0100 Subject: [Python-checkins] Daily reference leaks (19b2c54e5f09): sum=3 Message-ID: results for 19b2c54e5f09 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogiFlHZd', '-x'] From solipsis at pitrou.net Fri Nov 14 10:33:13 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 14 Nov 2014 10:33:13 +0100 Subject: [Python-checkins] Daily reference leaks (19b2c54e5f09): sum=3 Message-ID: results for 19b2c54e5f09 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogDED6tb', '-x'] From python-checkins at python.org Fri Nov 14 11:05:44 2014 From: python-checkins at python.org (nick.coghlan) Date: Fri, 14 Nov 2014 10:05:44 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogQ2xvc2UgIzIyMzAw?= =?utf-8?q?_by_tweaking_2=2E7=2E9_What=27s_New_announcements?= Message-ID: <20141114100525.57230.57@psf.io> https://hg.python.org/cpython/rev/0dacd614839c changeset: 93482:0dacd614839c branch: 2.7 user: Nick Coghlan date: Fri Nov 14 20:05:04 2014 +1000 summary: Close #22300 by tweaking 2.7.9 What's New announcements files: Doc/whatsnew/2.7.rst | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -2570,10 +2570,18 @@ certificate store, the :class:`~ssl.SSLContext` class, and other features. (Contributed by Alex Gaynor and David Reid; :issue:`21308`.) + Refer to the "Version added: 2.7.9" notes in the module documentation for + specific details. + * :func:`os.urandom` was changed to cache a file descriptor to ``/dev/urandom`` instead of reopening ``/dev/urandom`` on every call. (Contributed by Alex Gaynor; :issue:`21305`.) +* :data:`hashlib.algorithms_guaranteed` and + :data:`hashlib.algorithms_available` were backported from Python 3 to make + it easier for Python 2 applications to select the strongest available hash + algorithm. (Contributed by Alex Gaynor in :issue:`21307`) + PEP 477: Backport ensurepip (PEP 453) to Python 2.7 --------------------------------------------------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 14 11:13:16 2014 From: python-checkins at python.org (georg.brandl) Date: Fri, 14 Nov 2014 10:13:16 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogQ2xvc2VzICMyMjg2?= =?utf-8?q?8=3A_make_example_less_ambiguous=2E?= Message-ID: <20141114101307.36978.11606@psf.io> https://hg.python.org/cpython/rev/5dd835edde1e changeset: 93483:5dd835edde1e branch: 2.7 user: Georg Brandl date: Fri Nov 14 11:12:53 2014 +0100 summary: Closes #22868: make example less ambiguous. files: Doc/tutorial/datastructures.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/tutorial/datastructures.rst b/Doc/tutorial/datastructures.rst --- a/Doc/tutorial/datastructures.rst +++ b/Doc/tutorial/datastructures.rst @@ -181,12 +181,12 @@ the sequence for which ``function(item)`` is true. If *sequence* is a :class:`string` or :class:`tuple`, the result will be of the same type; otherwise, it is always a :class:`list`. For example, to compute a sequence of -numbers not divisible by 2 or 3:: +numbers divisible by 2 or 3:: - >>> def f(x): return x % 2 != 0 and x % 3 != 0 + >>> def f(x): return x % 3 == 0 or x % 5 == 0 ... >>> filter(f, range(2, 25)) - [5, 7, 11, 13, 17, 19, 23] + [3, 5, 6, 9, 10, 12, 15, 18, 20, 21, 24] ``map(function, sequence)`` calls ``function(item)`` for each of the sequence's items and returns a list of the return values. For example, to compute some -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 14 11:21:40 2014 From: python-checkins at python.org (georg.brandl) Date: Fri, 14 Nov 2014 10:21:40 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fix_descriptio?= =?utf-8?q?n=2E?= Message-ID: <20141114102013.57214.64608@psf.io> https://hg.python.org/cpython/rev/e106d9368bff changeset: 93484:e106d9368bff branch: 2.7 user: Georg Brandl date: Fri Nov 14 11:20:07 2014 +0100 summary: Fix description. files: Doc/tutorial/datastructures.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/tutorial/datastructures.rst b/Doc/tutorial/datastructures.rst --- a/Doc/tutorial/datastructures.rst +++ b/Doc/tutorial/datastructures.rst @@ -181,7 +181,7 @@ the sequence for which ``function(item)`` is true. If *sequence* is a :class:`string` or :class:`tuple`, the result will be of the same type; otherwise, it is always a :class:`list`. For example, to compute a sequence of -numbers divisible by 2 or 3:: +numbers divisible by 3 or 5:: >>> def f(x): return x % 3 == 0 or x % 5 == 0 ... -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 14 18:18:41 2014 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 14 Nov 2014 17:18:41 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_use_https_url_to_hg=2Epython?= =?utf-8?q?=2Eorg?= Message-ID: <20141114171749.29230.51897@psf.io> https://hg.python.org/peps/rev/90d77400cae4 changeset: 5594:90d77400cae4 user: Benjamin Peterson date: Fri Nov 14 12:17:47 2014 -0500 summary: use https url to hg.python.org files: pep0/constants.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep0/constants.py b/pep0/constants.py --- a/pep0/constants.py +++ b/pep0/constants.py @@ -24,7 +24,7 @@ references = u""" [1] PEP 1: PEP Purpose and Guidelines [2] View PEP history online - http://hg.python.org/peps/ + https://hg.python.org/peps/ """ footer = u""" -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Fri Nov 14 20:46:09 2014 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 14 Nov 2014 19:46:09 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogLSBJc3N1ZSAjMjI4?= =?utf-8?q?41=3A_Reject_coroutines_in_asyncio_add=5Fsignal=5Fhandler=28=29?= =?utf-8?q?=2E?= Message-ID: <20141114194600.57222.28572@psf.io> https://hg.python.org/cpython/rev/d244e1770f1b changeset: 93485:d244e1770f1b branch: 3.4 parent: 93478:ec1948191461 user: Guido van Rossum date: Fri Nov 14 11:45:47 2014 -0800 summary: - Issue #22841: Reject coroutines in asyncio add_signal_handler(). Patch by Ludovic.Gasc. files: Lib/asyncio/unix_events.py | 3 ++ Lib/test/test_asyncio/test_unix_events.py | 12 +++++++++++ Misc/NEWS | 3 ++ 3 files changed, 18 insertions(+), 0 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 @@ -13,6 +13,7 @@ from . import base_events from . import base_subprocess from . import constants +from . import coroutines from . import events from . import selector_events from . import selectors @@ -66,6 +67,8 @@ Raise ValueError if the signal number is invalid or uncatchable. Raise RuntimeError if there is a problem setting up the handler. """ + if coroutines.iscoroutinefunction(callback): + raise TypeError("coroutines cannot be used with call_soon()") self._check_signal(sig) try: # set_wakeup_fd() raises ValueError if this is not the 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 @@ -64,6 +64,18 @@ signal.SIGINT, lambda: True) @mock.patch('asyncio.unix_events.signal') + def test_add_signal_handler_coroutine_error(self, m_signal): + + @asyncio.coroutine + def simple_coroutine(): + yield from [] + + self.assertRaises( + TypeError, + self.loop.add_signal_handler, + signal.SIGINT, simple_coroutine) + + @mock.patch('asyncio.unix_events.signal') def test_add_signal_handler(self, m_signal): m_signal.NSIG = signal.NSIG diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,9 @@ Library ------- +- Issue #22841: Reject coroutines in asyncio add_signal_handler(). + Patch by Ludovic.Gasc. + - Issue #22849: Fix possible double free in the io.TextIOWrapper constructor. - Issue #12728: Different Unicode characters having the same uppercase but -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 14 20:49:05 2014 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 14 Nov 2014 19:49:05 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_-_Issue_=2322841=3A_Reject_coroutines_in_asyncio_add=5Fs?= =?utf-8?q?ignal=5Fhandler=28=29=2E?= Message-ID: <20141114194853.36980.40853@psf.io> https://hg.python.org/cpython/rev/44e77709daa4 changeset: 93486:44e77709daa4 parent: 93480:19b2c54e5f09 parent: 93485:d244e1770f1b user: Guido van Rossum date: Fri Nov 14 11:48:37 2014 -0800 summary: - Issue #22841: Reject coroutines in asyncio add_signal_handler(). Patch by Ludovic.Gasc. files: Lib/asyncio/unix_events.py | 3 ++ Lib/test/test_asyncio/test_unix_events.py | 12 +++++++++++ Misc/NEWS | 3 ++ 3 files changed, 18 insertions(+), 0 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 @@ -13,6 +13,7 @@ from . import base_events from . import base_subprocess from . import constants +from . import coroutines from . import events from . import selector_events from . import selectors @@ -66,6 +67,8 @@ Raise ValueError if the signal number is invalid or uncatchable. Raise RuntimeError if there is a problem setting up the handler. """ + if coroutines.iscoroutinefunction(callback): + raise TypeError("coroutines cannot be used with call_soon()") self._check_signal(sig) try: # set_wakeup_fd() raises ValueError if this is not the 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 @@ -64,6 +64,18 @@ signal.SIGINT, lambda: True) @mock.patch('asyncio.unix_events.signal') + def test_add_signal_handler_coroutine_error(self, m_signal): + + @asyncio.coroutine + def simple_coroutine(): + yield from [] + + self.assertRaises( + TypeError, + self.loop.add_signal_handler, + signal.SIGINT, simple_coroutine) + + @mock.patch('asyncio.unix_events.signal') def test_add_signal_handler(self, m_signal): m_signal.NSIG = signal.NSIG diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -183,6 +183,9 @@ Library ------- +- Issue #22841: Reject coroutines in asyncio add_signal_handler(). + Patch by Ludovic.Gasc. + - Issue #19494: Added urllib.request.HTTPBasicPriorAuthHandler. Patch by Matej Cepl. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 15 01:35:11 2014 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 15 Nov 2014 00:35:11 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322847=3A_Improve_?= =?utf-8?q?method_cache_efficiency=2E?= Message-ID: <20141115003501.36968.88616@psf.io> https://hg.python.org/cpython/rev/97dc64adb6fe changeset: 93487:97dc64adb6fe user: Antoine Pitrou date: Sat Nov 15 00:56:27 2014 +0100 summary: Issue #22847: Improve method cache efficiency. files: Misc/NEWS | 2 + Objects/typeobject.c | 40 ++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #22847: Improve method cache efficiency. + - Issue #22335: Fix crash when trying to enlarge a bytearray to 0x7fffffff bytes on a 32-bit platform. diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -14,10 +14,11 @@ MCACHE_MAX_ATTR_SIZE, since it might be a problem if very large strings are used as attribute names. */ #define MCACHE_MAX_ATTR_SIZE 100 -#define MCACHE_SIZE_EXP 9 +#define MCACHE_SIZE_EXP 12 #define MCACHE_HASH(version, name_hash) \ - (((unsigned int)(version) * (unsigned int)(name_hash)) \ - >> (8*sizeof(unsigned int) - MCACHE_SIZE_EXP)) + (((unsigned int)(version) ^ (unsigned int)(name_hash)) \ + & ((1 << MCACHE_SIZE_EXP) - 1)) + #define MCACHE_HASH_METHOD(type, name) \ MCACHE_HASH((type)->tp_version_tag, \ ((PyASCIIObject *)(name))->hash) @@ -35,6 +36,14 @@ static struct method_cache_entry method_cache[1 << MCACHE_SIZE_EXP]; static unsigned int next_version_tag = 0; +#define MCACHE_STATS 0 + +#if MCACHE_STATS +static size_t method_cache_hits = 0; +static size_t method_cache_misses = 0; +static size_t method_cache_collisions = 0; +#endif + /* alphabetical order */ _Py_IDENTIFIER(__abstractmethods__); _Py_IDENTIFIER(__class__); @@ -165,6 +174,18 @@ Py_ssize_t i; unsigned int cur_version_tag = next_version_tag - 1; +#if MCACHE_STATS + size_t total = method_cache_hits + method_cache_collisions + method_cache_misses; + fprintf(stderr, "-- Method cache hits = %zd (%d%%)\n", + method_cache_hits, (int) (100.0 * method_cache_hits / total)); + fprintf(stderr, "-- Method cache true misses = %zd (%d%%)\n", + method_cache_misses, (int) (100.0 * method_cache_misses / total)); + fprintf(stderr, "-- Method cache collisions = %zd (%d%%)\n", + method_cache_collisions, (int) (100.0 * method_cache_collisions / total)); + fprintf(stderr, "-- Method cache size = %zd KB\n", + sizeof(method_cache) / 1024); +#endif + for (i = 0; i < (1 << MCACHE_SIZE_EXP); i++) { method_cache[i].version = 0; Py_CLEAR(method_cache[i].name); @@ -2708,8 +2729,12 @@ /* fast path */ h = MCACHE_HASH_METHOD(type, name); if (method_cache[h].version == type->tp_version_tag && - method_cache[h].name == name) + method_cache[h].name == name) { +#if MCACHE_STATS + method_cache_hits++; +#endif return method_cache[h].value; + } } /* Look in tp_dict of types in MRO */ @@ -2743,6 +2768,13 @@ method_cache[h].version = type->tp_version_tag; method_cache[h].value = res; /* borrowed */ Py_INCREF(name); + assert(((PyASCIIObject *)(name))->hash != -1); +#if MCACHE_STATS + if (method_cache[h].name != Py_None && method_cache[h].name != name) + method_cache_collisions++; + else + method_cache_misses++; +#endif Py_DECREF(method_cache[h].name); method_cache[h].name = name; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 15 04:00:03 2014 From: python-checkins at python.org (ned.deily) Date: Sat, 15 Nov 2014 03:00:03 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyODc3?= =?utf-8?q?=3A_PEP_477_-_keep_2=2E7_and_3=2Ex_installers_in_sync=2E?= Message-ID: <20141115030001.29220.2059@psf.io> https://hg.python.org/cpython/rev/e8182c6c9ef1 changeset: 93489:e8182c6c9ef1 branch: 3.4 parent: 93485:d244e1770f1b user: Ned Deily date: Fri Nov 14 18:55:05 2014 -0800 summary: Issue #22877: PEP 477 - keep 2.7 and 3.x installers in sync. files: Mac/BuildScript/build-installer.py | 42 +++---- Mac/BuildScript/scripts/postflight.ensurepip | 50 +++++---- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -198,7 +198,7 @@ LT_10_5 = bool(getDeptargetTuple() < (10, 5)) # Disable for now - if False: # if (getDeptargetTuple() > (10, 5)) and (getVersionTuple() >= (3, 5)): + if False: # if getDeptargetTuple() > (10, 5): result.extend([ dict( name="Tcl 8.5.15", @@ -239,7 +239,7 @@ ), ]) - if getVersionTuple() >= (3, 3): + if PYTHON_3: result.extend([ dict( name="XZ 5.0.5", @@ -369,8 +369,6 @@ # Instructions for building packages inside the .mpkg. def pkg_recipes(): unselected_for_python3 = ('selected', 'unselected')[PYTHON_3] - # unselected if 3.0 through 3.3, selected otherwise (2.x or >= 3.4) - unselected_for_lt_python34 = ('selected', 'unselected')[(3, 0) <= getVersionTuple() < (3, 4)] result = [ dict( name="PythonFramework", @@ -439,27 +437,23 @@ topdir="/Library/Frameworks/Python.framework", source="/empty-dir", required=False, - selected=unselected_for_lt_python34, + selected='selected', + ), + dict( + name="PythonInstallPip", + long_name="Install or upgrade pip", + readme="""\ + This package installs (or upgrades from an earlier version) + pip, a tool for installing and managing Python packages. + """, + postflight="scripts/postflight.ensurepip", + topdir="/Library/Frameworks/Python.framework", + source="/empty-dir", + required=False, + selected='selected', ), ] - if getVersionTuple() >= (3, 4): - result.append( - dict( - name="PythonInstallPip", - long_name="Install or upgrade pip", - readme="""\ - This package installs (or upgrades from an earlier version) - pip, a tool for installing and managing Python packages. - """, - postflight="scripts/postflight.ensurepip", - topdir="/Library/Frameworks/Python.framework", - source="/empty-dir", - required=False, - selected='selected', - ) - ) - if getDeptargetTuple() < (10, 4) and not PYTHON_3: result.append( dict( @@ -977,7 +971,7 @@ shellQuote(os.path.join(SRCDIR, 'configure')), shellQuote(SDKPATH), UNIVERSALARCHS, (' ', '--with-computed-gotos ')[PYTHON_3], - (' ', '--without-ensurepip ')[getVersionTuple() >= (3, 4)], + (' ', '--without-ensurepip ')[PYTHON_3], shellQuote(WORKDIR)[1:-1], shellQuote(WORKDIR)[1:-1])) @@ -1159,7 +1153,9 @@ fp.close() def patchScript(inPath, outPath): + major, minor = getVersionMajorMinor() data = fileContents(inPath) + data = data.replace('@PYMAJOR@', str(major)) data = data.replace('@PYVER@', getVersion()) fp = open(outPath, 'w') fp.write(data) diff --git a/Mac/BuildScript/scripts/postflight.ensurepip b/Mac/BuildScript/scripts/postflight.ensurepip --- a/Mac/BuildScript/scripts/postflight.ensurepip +++ b/Mac/BuildScript/scripts/postflight.ensurepip @@ -4,7 +4,7 @@ # PYVER="@PYVER@" -PYMAJOR="3" +PYMAJOR="@PYMAJOR@" FWK="/Library/Frameworks/Python.framework/Versions/${PYVER}" RELFWKBIN="../../..${FWK}/bin" @@ -34,32 +34,36 @@ if [ -d /usr/local/bin ] ; then ( + install_links_if_our_fw() { + if [ "$(readlink -n ./$1)" = "${RELFWKBIN}/$1" ] ; then + shift + for fn ; + do + if [ -e "${RELFWKBIN}/${fn}" ] ; then + rm -f ./${fn} + ln -s "${RELFWKBIN}/${fn}" "./${fn}" + chgrp -h admin "./${fn}" + chmod -h g+w "./${fn}" + fi + done + fi + } + cd /usr/local/bin + # Create pipx.y and easy_install-x.y links if /usr/local/bin/pythonx.y # is linked to this framework version - if [ "$(readlink -n ./python${PYVER})" = "${RELFWKBIN}/python${PYVER}" ] ; then - for fn in "pip${PYVER}" "easy_install-${PYVER}" ; - do - if [ -e "${RELFWKBIN}/${fn}" ] ; then - rm -f ./${fn} - ln -s "${RELFWKBIN}/${fn}" "./${fn}" - chgrp -h admin "./${fn}" - chmod -h g+w "./${fn}" - fi - done - fi + install_links_if_our_fw "python${PYVER}" \ + "pip${PYVER}" "easy_install-${PYVER}" + # Create pipx link if /usr/local/bin/pythonx is linked to this version - if [ "$(readlink -n ./python${PYMAJOR})" = "${RELFWKBIN}/python${PYMAJOR}" ] ; then - for fn in "pip${PYMAJOR}" ; - do - if [ -e "${RELFWKBIN}/${fn}" ] ; then - rm -f ./${fn} - ln -s "${RELFWKBIN}/${fn}" "./${fn}" - chgrp -h admin "./${fn}" - chmod -h g+w "./${fn}" - fi - done - fi + install_links_if_our_fw "python${PYMAJOR}" \ + "pip${PYMAJOR}" + + # Create pip and easy_install link if /usr/local/bin/python + # is linked to this version + install_links_if_our_fw "python" \ + "pip" "easy_install" ) fi exit 0 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 15 04:00:03 2014 From: python-checkins at python.org (ned.deily) Date: Sat, 15 Nov 2014 03:00:03 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322877=3A_PEP_477_-_keep_2=2E7_and_3=2Ex_install?= =?utf-8?q?ers_in_sync=2E?= Message-ID: <20141115030001.36984.57390@psf.io> https://hg.python.org/cpython/rev/6270a2181ed3 changeset: 93490:6270a2181ed3 parent: 93487:97dc64adb6fe parent: 93489:e8182c6c9ef1 user: Ned Deily date: Fri Nov 14 18:56:28 2014 -0800 summary: Issue #22877: PEP 477 - keep 2.7 and 3.x installers in sync. files: Mac/BuildScript/build-installer.py | 42 +++---- Mac/BuildScript/scripts/postflight.ensurepip | 50 +++++---- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -198,7 +198,7 @@ LT_10_5 = bool(getDeptargetTuple() < (10, 5)) # Disable for now - if False: # if (getDeptargetTuple() > (10, 5)) and (getVersionTuple() >= (3, 5)): + if False: # if getDeptargetTuple() > (10, 5): result.extend([ dict( name="Tcl 8.5.15", @@ -239,7 +239,7 @@ ), ]) - if getVersionTuple() >= (3, 3): + if PYTHON_3: result.extend([ dict( name="XZ 5.0.5", @@ -369,8 +369,6 @@ # Instructions for building packages inside the .mpkg. def pkg_recipes(): unselected_for_python3 = ('selected', 'unselected')[PYTHON_3] - # unselected if 3.0 through 3.3, selected otherwise (2.x or >= 3.4) - unselected_for_lt_python34 = ('selected', 'unselected')[(3, 0) <= getVersionTuple() < (3, 4)] result = [ dict( name="PythonFramework", @@ -439,27 +437,23 @@ topdir="/Library/Frameworks/Python.framework", source="/empty-dir", required=False, - selected=unselected_for_lt_python34, + selected='selected', + ), + dict( + name="PythonInstallPip", + long_name="Install or upgrade pip", + readme="""\ + This package installs (or upgrades from an earlier version) + pip, a tool for installing and managing Python packages. + """, + postflight="scripts/postflight.ensurepip", + topdir="/Library/Frameworks/Python.framework", + source="/empty-dir", + required=False, + selected='selected', ), ] - if getVersionTuple() >= (3, 4): - result.append( - dict( - name="PythonInstallPip", - long_name="Install or upgrade pip", - readme="""\ - This package installs (or upgrades from an earlier version) - pip, a tool for installing and managing Python packages. - """, - postflight="scripts/postflight.ensurepip", - topdir="/Library/Frameworks/Python.framework", - source="/empty-dir", - required=False, - selected='selected', - ) - ) - if getDeptargetTuple() < (10, 4) and not PYTHON_3: result.append( dict( @@ -977,7 +971,7 @@ shellQuote(os.path.join(SRCDIR, 'configure')), shellQuote(SDKPATH), UNIVERSALARCHS, (' ', '--with-computed-gotos ')[PYTHON_3], - (' ', '--without-ensurepip ')[getVersionTuple() >= (3, 4)], + (' ', '--without-ensurepip ')[PYTHON_3], shellQuote(WORKDIR)[1:-1], shellQuote(WORKDIR)[1:-1])) @@ -1159,7 +1153,9 @@ fp.close() def patchScript(inPath, outPath): + major, minor = getVersionMajorMinor() data = fileContents(inPath) + data = data.replace('@PYMAJOR@', str(major)) data = data.replace('@PYVER@', getVersion()) fp = open(outPath, 'w') fp.write(data) diff --git a/Mac/BuildScript/scripts/postflight.ensurepip b/Mac/BuildScript/scripts/postflight.ensurepip --- a/Mac/BuildScript/scripts/postflight.ensurepip +++ b/Mac/BuildScript/scripts/postflight.ensurepip @@ -4,7 +4,7 @@ # PYVER="@PYVER@" -PYMAJOR="3" +PYMAJOR="@PYMAJOR@" FWK="/Library/Frameworks/Python.framework/Versions/${PYVER}" RELFWKBIN="../../..${FWK}/bin" @@ -34,32 +34,36 @@ if [ -d /usr/local/bin ] ; then ( + install_links_if_our_fw() { + if [ "$(readlink -n ./$1)" = "${RELFWKBIN}/$1" ] ; then + shift + for fn ; + do + if [ -e "${RELFWKBIN}/${fn}" ] ; then + rm -f ./${fn} + ln -s "${RELFWKBIN}/${fn}" "./${fn}" + chgrp -h admin "./${fn}" + chmod -h g+w "./${fn}" + fi + done + fi + } + cd /usr/local/bin + # Create pipx.y and easy_install-x.y links if /usr/local/bin/pythonx.y # is linked to this framework version - if [ "$(readlink -n ./python${PYVER})" = "${RELFWKBIN}/python${PYVER}" ] ; then - for fn in "pip${PYVER}" "easy_install-${PYVER}" ; - do - if [ -e "${RELFWKBIN}/${fn}" ] ; then - rm -f ./${fn} - ln -s "${RELFWKBIN}/${fn}" "./${fn}" - chgrp -h admin "./${fn}" - chmod -h g+w "./${fn}" - fi - done - fi + install_links_if_our_fw "python${PYVER}" \ + "pip${PYVER}" "easy_install-${PYVER}" + # Create pipx link if /usr/local/bin/pythonx is linked to this version - if [ "$(readlink -n ./python${PYMAJOR})" = "${RELFWKBIN}/python${PYMAJOR}" ] ; then - for fn in "pip${PYMAJOR}" ; - do - if [ -e "${RELFWKBIN}/${fn}" ] ; then - rm -f ./${fn} - ln -s "${RELFWKBIN}/${fn}" "./${fn}" - chgrp -h admin "./${fn}" - chmod -h g+w "./${fn}" - fi - done - fi + install_links_if_our_fw "python${PYMAJOR}" \ + "pip${PYMAJOR}" + + # Create pip and easy_install link if /usr/local/bin/python + # is linked to this version + install_links_if_our_fw "python" \ + "pip" "easy_install" ) fi exit 0 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 15 04:00:03 2014 From: python-checkins at python.org (ned.deily) Date: Sat, 15 Nov 2014 03:00:03 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIyODc3?= =?utf-8?q?=3A_PEP_477_-_OS_X_installer_for_2=2E7=2E9_now_installs_pip=2E?= Message-ID: <20141115030001.29226.12344@psf.io> https://hg.python.org/cpython/rev/6b8e107622b3 changeset: 93488:6b8e107622b3 branch: 2.7 parent: 93484:e106d9368bff user: Ned Deily date: Fri Nov 14 18:53:59 2014 -0800 summary: Issue #22877: PEP 477 - OS X installer for 2.7.9 now installs pip. files: Mac/BuildScript/build-installer.py | 42 ++--- Mac/BuildScript/scripts/postflight.ensurepip | 69 ++++++++++ Misc/NEWS | 2 + 3 files changed, 90 insertions(+), 23 deletions(-) diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -198,7 +198,7 @@ LT_10_5 = bool(getDeptargetTuple() < (10, 5)) # Disable for now - if False: # if (getDeptargetTuple() > (10, 5)) and (getVersionTuple() >= (3, 5)): + if False: # if getDeptargetTuple() > (10, 5): result.extend([ dict( name="Tcl 8.5.15", @@ -239,7 +239,7 @@ ), ]) - if getVersionTuple() >= (3, 3): + if PYTHON_3: result.extend([ dict( name="XZ 5.0.5", @@ -369,8 +369,6 @@ # Instructions for building packages inside the .mpkg. def pkg_recipes(): unselected_for_python3 = ('selected', 'unselected')[PYTHON_3] - # unselected if 3.0 through 3.3, selected otherwise (2.x or >= 3.4) - unselected_for_lt_python34 = ('selected', 'unselected')[(3, 0) <= getVersionTuple() < (3, 4)] result = [ dict( name="PythonFramework", @@ -439,27 +437,23 @@ topdir="/Library/Frameworks/Python.framework", source="/empty-dir", required=False, - selected=unselected_for_lt_python34, + selected='selected', + ), + dict( + name="PythonInstallPip", + long_name="Install or upgrade pip", + readme="""\ + This package installs (or upgrades from an earlier version) + pip, a tool for installing and managing Python packages. + """, + postflight="scripts/postflight.ensurepip", + topdir="/Library/Frameworks/Python.framework", + source="/empty-dir", + required=False, + selected='selected', ), ] - if getVersionTuple() >= (3, 4): - result.append( - dict( - name="PythonInstallPip", - long_name="Install or upgrade pip", - readme="""\ - This package installs (or upgrades from an earlier version) - pip, a tool for installing and managing Python packages. - """, - postflight="scripts/postflight.ensurepip", - topdir="/Library/Frameworks/Python.framework", - source="/empty-dir", - required=False, - selected='selected', - ) - ) - if getDeptargetTuple() < (10, 4) and not PYTHON_3: result.append( dict( @@ -977,7 +971,7 @@ shellQuote(os.path.join(SRCDIR, 'configure')), shellQuote(SDKPATH), UNIVERSALARCHS, (' ', '--with-computed-gotos ')[PYTHON_3], - (' ', '--without-ensurepip ')[getVersionTuple() >= (3, 4)], + (' ', '--without-ensurepip ')[PYTHON_3], shellQuote(WORKDIR)[1:-1], shellQuote(WORKDIR)[1:-1])) @@ -1159,7 +1153,9 @@ fp.close() def patchScript(inPath, outPath): + major, minor = getVersionMajorMinor() data = fileContents(inPath) + data = data.replace('@PYMAJOR@', str(major)) data = data.replace('@PYVER@', getVersion()) fp = open(outPath, 'w') fp.write(data) diff --git a/Mac/BuildScript/scripts/postflight.ensurepip b/Mac/BuildScript/scripts/postflight.ensurepip new file mode 100755 --- /dev/null +++ b/Mac/BuildScript/scripts/postflight.ensurepip @@ -0,0 +1,69 @@ +#!/bin/sh +# +# Install/upgrade pip. +# + +PYVER="@PYVER@" +PYMAJOR="@PYMAJOR@" +FWK="/Library/Frameworks/Python.framework/Versions/${PYVER}" +RELFWKBIN="../../..${FWK}/bin" + +umask 022 + +"${FWK}/bin/python${PYVER}" -m ensurepip --upgrade + +"${FWK}/bin/python${PYVER}" -Wi \ + "${FWK}/lib/python${PYVER}/compileall.py" \ + -f -x badsyntax \ + "${FWK}/lib/python${PYVER}/site-packages" + +"${FWK}/bin/python${PYVER}" -Wi -O \ + "${FWK}/lib/python${PYVER}/compileall.py" \ + -f -x badsyntax \ + "${FWK}/lib/python${PYVER}/site-packages" + +chgrp -R admin "${FWK}/lib/python${PYVER}/site-packages" "${FWK}/bin" +chmod -R g+w "${FWK}/lib/python${PYVER}/site-packages" "${FWK}/bin" + +# We do not know if the user selected the Python command-line tools +# package that installs symlinks to /usr/local/bin. So we assume +# that the command-line tools package has already completed or was +# not selected and we will only install /usr/local/bin symlinks for +# pip et al if there are /usr/local/bin/python* symlinks to our +# framework bin directory. + +if [ -d /usr/local/bin ] ; then + ( + install_links_if_our_fw() { + if [ "$(readlink -n ./$1)" = "${RELFWKBIN}/$1" ] ; then + shift + for fn ; + do + if [ -e "${RELFWKBIN}/${fn}" ] ; then + rm -f ./${fn} + ln -s "${RELFWKBIN}/${fn}" "./${fn}" + chgrp -h admin "./${fn}" + chmod -h g+w "./${fn}" + fi + done + fi + } + + cd /usr/local/bin + + # Create pipx.y and easy_install-x.y links if /usr/local/bin/pythonx.y + # is linked to this framework version + install_links_if_our_fw "python${PYVER}" \ + "pip${PYVER}" "easy_install-${PYVER}" + + # Create pipx link if /usr/local/bin/pythonx is linked to this version + install_links_if_our_fw "python${PYMAJOR}" \ + "pip${PYMAJOR}" + + # Create pip and easy_install link if /usr/local/bin/python + # is linked to this version + install_links_if_our_fw "python" \ + "pip" "easy_install" + ) +fi +exit 0 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -324,6 +324,8 @@ - Issue #17219: Add library build dir for Python extension cross-builds. +- Issue #22877: PEP 477 - OS X installer now installs pip. + Windows ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 15 04:00:03 2014 From: python-checkins at python.org (ned.deily) Date: Sat, 15 Nov 2014 03:00:03 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Update_OS_X_in?= =?utf-8?q?staller_documentation_files_for_2=2E7=2E9=2E?= Message-ID: <20141115030001.15639.72150@psf.io> https://hg.python.org/cpython/rev/33d68c79d601 changeset: 93491:33d68c79d601 branch: 2.7 parent: 93488:6b8e107622b3 user: Ned Deily date: Fri Nov 14 18:57:13 2014 -0800 summary: Update OS X installer documentation files for 2.7.9. files: Mac/BuildScript/resources/ReadMe.txt | 116 ++++--------- Mac/BuildScript/resources/Welcome.rtf | 20 +- Mac/BuildScript/resources/readme.rtf | 92 +++++++++++ 3 files changed, 147 insertions(+), 81 deletions(-) diff --git a/Mac/BuildScript/resources/ReadMe.txt b/Mac/BuildScript/resources/ReadMe.txt --- a/Mac/BuildScript/resources/ReadMe.txt +++ b/Mac/BuildScript/resources/ReadMe.txt @@ -1,88 +1,52 @@ -This package will install Python $FULL_VERSION for Mac OS X -$MACOSX_DEPLOYMENT_TARGET for the following architecture(s): -$ARCHITECTURES. +This package will install Python $FULL_VERSION for Mac OS X $MACOSX_DEPLOYMENT_TARGET for the following architecture(s): $ARCHITECTURES. - **** IMPORTANT **** +============================= +Update your version of Tcl/Tk to use IDLE or other Tk applications +============================= +To use IDLE or other programs that use the Tkinter graphical user interface toolkit, you need to install a newer third-party version of the Tcl/Tk frameworks. Visit https://www.python.org/download/mac/tcltk/ for current information about supported and recommended versions of Tcl/Tk for this version of Python and of Mac OS X. + +============================= Installing on OS X 10.8 (Mountain Lion) or later systems -======================================================== +[CHANGED for Python 2.7.9] +============================= -If you are attempting to install on an OS X 10.8+ system, you may -see a message that Python can't be installed because it is from an -unidentified developer. This is because this Python installer -package is not yet compatible with the Gatekeeper security feature -introduced in OS X 10.8. To allow Python to be installed, you -can override the Gatekeeper policy for this install. In the Finder, -instead of double-clicking, control-click or right click the "Python" -installer package icon. Then select "Open using ... Installer" from -the contextual menu that appears. +As of Python 2.7.9, installer packages from python.org are now compatible with the Gatekeeper security feature introduced in OS X 10.8. Downloaded packages can now be directly installed by double-clicking with the default system security settings. Python.org installer packages for OS X are signed with the Developer ID of the builder, as identified on the download page for this release (https://www.python.org/downloads/). To inspect the digital signature of the package, click on the lock icon in the upper right corner of the Install Python installer window. Refer to Apple?s support pages for more information on Gatekeeper (http://support.apple.com/kb/ht5290). - **** IMPORTANT **** +============================= +Simplified web-based installs +[NEW for Python 2.7.9] +============================= -Update your version of Tcl/Tk to use IDLE or other Tk applications -================================================================== +With the change to the newer flat format installer package, the download file now has a .pkg extension as it is no longer necessary to embed the installer within a disk image (.dmg) container. If you download the Python installer through a web browser, the OS X installer application may open automatically to allow you to perform the install. If your browser settings do not allow automatic open, double click on the downloaded installer file. -To use IDLE or other programs that use the Tkinter graphical user -interface toolkit, you may need to install a newer third-party version -of the Tcl/Tk frameworks. Visit http://www.python.org/download/mac/tcltk/ -for current information about supported and recommended versions of -Tcl/Tk for this version of Python and of Mac OS X. +============================= +New Installation Options and Defaults +[NEW for Python 2.7.9] +============================= - **** IMPORTANT **** +The Python installer now includes an option to automatically install or upgrade pip, a tool for installing and managing Python packages. This option is enabled by default and no Internet access is required. If you do not want the installer to do this, select the Customize option at the Installation Type step and uncheck the Install or ugprade pip option. -Binary installer support for 10.4 and 10.3.9 to be discontinued -=============================================================== +============================= +Binary installer support for OS X 10.4 and 10.3.9 discontinued +[CHANGED for Python 2.7.9] +============================= -Python 2.7.7 is the last release for which binary installers will be -released on python.org that support OS X 10.3.9 (Panther) and 10.4.x -(Tiger) systems. These systems were last updated by Apple in 2005 -and 2007. As of 2.7.8, the 32-bit-only installer will support PPC -and Intel Macs running OS X 10.5 (Leopard) and later. 10.5 was the -last OS X release for PPC machines (G4 and G5). (The 64-/32-bit -installer configuration will remain unchanged.) This aligns Python -2.7.x installer configurations with those currently provided with -Python 3.x. Some of the reasons for making this change are: -there were significant additions and compatibility improvements to -the OS X POSIX system APIs in OS X 10.5 that Python users can now -take advantage of; it is increasingly difficult to build and test -on obsolete 10.3 and 10.4 systems and with the 10.3 ABI; and it is -assumed that most remaining legacy PPC systems have upgraded to 10.5. -To ease the transition, for Python 2.7.7 only we are providing three -binary installers: (1) the legacy deprecated 32-bit-only 10.3+ -PPC/Intel format, (2) the newer 32-bit-only 10.5+ PPC/Intel format, -and (3) the current 64-bit/32-bit 10.6+ Intel-only format. While -future releases will not provide the deprecated installer, it will -still be possible to build Python from source on 10.3.9 and 10.4 -systems if needed. +As previously announced, binary installers for Python 2.7.9 from python.org +no longer support Mac OS X 10.3.9 (Panther) and 10.4.x (Tiger) systems. +These systems were last updated by Apple in 2005 and 2007. As of 2.7.9, the +32-bit-only installer supports PPC and Intel Macs running OS X 10.5 (Leopard). +10.5 was the last OS X release for PPC machines (G4 and G5). The 64-/32-bit +installer configuration remains unchanged and should normally be used on OS X +10.6 (Snow Leopard) and later systems. This aligns Python 2.7.x installer +configurations with those currently provided with Python 3.x. If needed, +it is still possible to build Python from source for 10.3.9 and 10.4. -Using this version of Python on OS X -==================================== +============================= +Python 3 and Python 2 Co-existence +============================= -Python consists of the Python programming language interpreter, plus -a set of programs to allow easy access to it for Mac users including -an integrated development environment, IDLE, plus a set of pre-built -extension modules that open up specific Macintosh technologies to -Python programs. - -The installer puts applications, an "Update Shell Profile" command, -and a link to the optionally installed Python Documentation into the -"Python $VERSION" subfolder of the system Applications folder, -and puts the underlying machinery into the folder -$PYTHONFRAMEWORKINSTALLDIR. It can -optionally place links to the command-line tools in /usr/local/bin as -well. Double-click on the "Update Shell Profile" command to add the -"bin" directory inside the framework to your shell's search path. - -You must install onto your current boot disk, even though the -installer may not enforce this, otherwise things will not work. - -You can verify the integrity of the disk image file containing the -installer package and this ReadMe file by comparing its md5 checksum -and size with the values published on the release page linked at -http://www.python.org/download/ - -Installation requires approximately $INSTALL_SIZE MB of disk space, -ignore the message that it will take zero bytes. - -More information on Python in general can be found at -http://www.python.org. +Python.org Python 2.7 and 3.x versions can both be installed on your system and +will not conflict. Python 2 command names contain a 2 or no digit: python2 (or +python2.7 or python), idle2 (or idle2.7 or idle), pip2 (or pip2.7 or pip), etc. +Command names for Python 3 contain a 3 in them: python3, idle3, pip3, etc. diff --git a/Mac/BuildScript/resources/Welcome.rtf b/Mac/BuildScript/resources/Welcome.rtf --- a/Mac/BuildScript/resources/Welcome.rtf +++ b/Mac/BuildScript/resources/Welcome.rtf @@ -1,5 +1,5 @@ -{\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf200 -\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\rtf1\ansi\ansicpg1252\cocoartf1343\cocoasubrtf140 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fmodern\fcharset0 CourierNewPSMT;} {\colortbl;\red255\green255\blue255;} \paperw11905\paperh16837\margl1440\margr1440\vieww9640\viewh10620\viewkind0 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640 @@ -14,9 +14,19 @@ \b Python for Mac OS X \b0 consists of the Python programming language interpreter, plus a set of programs to allow easy access to it for Mac OS X users including an integrated development environment \b IDLE -\b0 and a set of pre-built extension modules that open up specific Macintosh technologies to Python programs.\ +\b0 .\ \ -See the ReadMe file and the Python documentation for important information, including the dropping of support for OS X 10.3.9 and 10.4 in future Python 2.7.x binary installers.\ + +\b NEW for Python 2.7.9: +\b0 This package installs a version of +\f1 pip +\f0 , the recommended tool for installing and managing Python packages. Type\ +\ + +\f1 pip2.7 --help +\f0 \ +\ +for an overview. See the ReadMe file and the Python documentation for more information.\ \ \b IMPORTANT: @@ -26,4 +36,4 @@ \b tkinter \b0 graphical user interface toolkit require specific versions of the \b Tcl/Tk -\b0 platform independent windowing toolkit. Visit {\field{\*\fldinst{HYPERLINK "http://www.python.org/download/mac/tcltk/"}}{\fldrslt http://www.python.org/download/mac/tcltk/}} for current information on supported and recommended versions of Tcl/Tk for this version of Python and Mac OS X.} \ No newline at end of file +\b0 platform independent windowing toolkit. Visit {\field{\*\fldinst{HYPERLINK "https://www.python.org/download/mac/tcltk/"}}{\fldrslt https://www.python.org/download/mac/tcltk/}} for current information on supported and recommended versions of Tcl/Tk for this version of Python and Mac OS X.} \ No newline at end of file diff --git a/Mac/BuildScript/resources/readme.rtf b/Mac/BuildScript/resources/readme.rtf new file mode 100644 --- /dev/null +++ b/Mac/BuildScript/resources/readme.rtf @@ -0,0 +1,92 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1343\cocoasubrtf140 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fmodern\fcharset0 CourierNewPSMT;} +{\colortbl;\red255\green255\blue255;} +\margl1440\margr1440\vieww15240\viewh15540\viewkind0 +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural + +\f0\fs24 \cf0 This package will install Python $FULL_VERSION for Mac OS X $MACOSX_DEPLOYMENT_TARGET for the following architecture(s): $ARCHITECTURES.\ +\ + +\b \ul Update your version of Tcl/Tk to use IDLE or other Tk applications +\b0 \ulnone \ +\ +To use IDLE or other programs that use the Tkinter graphical user interface toolkit, you need to install a newer third-party version of the +\i Tcl/Tk +\i0 frameworks. Visit {\field{\*\fldinst{HYPERLINK "https://www.python.org/download/mac/tcltk/"}}{\fldrslt https://www.python.org/download/mac/tcltk/}} for current information about supported and recommended versions of +\i Tcl/Tk +\i0 for this version of Python and of Mac OS X.\ + +\b \ul \ +Installing on OS X 10.8 (Mountain Lion) or later systems\ +\ulnone [CHANGED for Python 2.7.9] +\b0 \ +\ +As of Python 2.7.9, installer packages from python.org are now compatible with the Gatekeeper security feature introduced in OS X 10.8. Downloaded packages can now be directly installed by double-clicking with the default system security settings. Python.org installer packages for OS X are signed with the Developer ID of the builder, as identified on the download page for this release ({\field{\*\fldinst{HYPERLINK "https://www.python.org/downloads/"}}{\fldrslt https://www.python.org/downloads/}}). To inspect the digital signature of the package, click on the lock icon in the upper right corner of the +\i Install Python +\i0 installer window. Refer to Apple\'92s support pages for more information on Gatekeeper ({\field{\*\fldinst{HYPERLINK "http://support.apple.com/kb/ht5290"}}{\fldrslt http://support.apple.com/kb/ht5290}}).\ +\ + +\b \ul Simplified web-based installs\ +\ulnone [NEW for Python 2.7.9] +\b0 \ +\ +With the change to the newer flat format installer package, the download file now has a +\f1 .pkg +\f0 extension as it is no longer necessary to embed the installer within a disk image ( +\f1 .dmg +\f0 ) container. If you download the Python installer through a web browser, the OS X installer application may open automatically to allow you to perform the install. If your browser settings do not allow automatic open, double click on the downloaded installer file.\ +\ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural + +\b \cf0 \ul \ulc0 New Installation Options and Defaults\ +\ulnone [NEW for Python 2.7.9] +\b0 \ +\ +The Python installer now includes an option to automatically install or upgrade +\f1 pip +\f0 , a tool for installing and managing Python packages. This option is enabled by default and no Internet access is required. If you do not want the installer to do this, select the +\i Customize +\i0 option at the +\i Installation Type +\i0 step and uncheck the +\i Install or ugprade pip +\i0 option.\ +\ + +\b \ul Binary installer support for OS X 10.4 and 10.3.9 discontinued\ +\ulnone [CHANGED for Python 2.7.9] +\b0 \ +\ +As previously announced, binary installers for Python 2.7.9 from python.org no longer support Mac OS X 10.3.9 (Panther) and 10.4.x (Tiger) systems. These systems were last updated by Apple in 2005 and 2007. As of 2.7.9, the 32-bit-only installer supports PPC and Intel Macs running OS X 10.5 (Leopard). 10.5 was the last OS X release for PPC machines (G4 and G5). The 64-/32-bit installer configuration remains unchanged and should normally be used on OS X 10.6 (Snow Leopard) and later systems. This aligns Python 2.7.x installer configurations with those currently provided with Python 3.x. If needed, it is still possible to build Python from source for 10.3.9 and 10.4.\ +\ + +\b \ul Python 3 and Python 2 Co-existence\ + +\b0 \ulnone \ +Python.org Python 2.7 and 3.x versions can both be installed on your system and will not conflict. Python 2.7 command names contain a 2 or no digit: +\f1 python2 +\f0 (or +\f1 python2.7 +\f0 or +\f1 python +\f0 ), +\f1 idle2 +\f0 (or +\f1 idle2.7 +\f0 or +\f1 idle +\f0 ), +\f1 pip2 +\f0 (or +\f1 pip2.7 +\f0 or +\f1 pip +\f0 ), etc. Command names for Python 3 contain a 3 in them, +\f1 python3 +\f0 , +\f1 idle3 +\f0 , +\f1 pip3 +\f0 , etc.\ +\ +} \ No newline at end of file -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 15 04:00:08 2014 From: python-checkins at python.org (ned.deily) Date: Sat, 15 Nov 2014 03:00:08 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Update_OS_X_installer_docu?= =?utf-8?q?mentation_files_for_3=2E5=2E0?= Message-ID: <20141115030002.51555.89292@psf.io> https://hg.python.org/cpython/rev/e79c6ea48b83 changeset: 93492:e79c6ea48b83 parent: 93490:6270a2181ed3 user: Ned Deily date: Fri Nov 14 18:41:56 2014 -0800 summary: Update OS X installer documentation files for 3.5.0 files: Mac/BuildScript/resources/ReadMe.txt | 97 +------------- Mac/BuildScript/resources/Welcome.rtf | 22 +-- Mac/BuildScript/resources/readme.rtf | 51 +++++++ 3 files changed, 65 insertions(+), 105 deletions(-) diff --git a/Mac/BuildScript/resources/ReadMe.txt b/Mac/BuildScript/resources/ReadMe.txt --- a/Mac/BuildScript/resources/ReadMe.txt +++ b/Mac/BuildScript/resources/ReadMe.txt @@ -1,92 +1,13 @@ -This package will install Python $FULL_VERSION for Mac OS X -$MACOSX_DEPLOYMENT_TARGET for the following architecture(s): -$ARCHITECTURES. +This package will install Python $FULL_VERSION for Mac OS X $MACOSX_DEPLOYMENT_TARGET for the following architecture(s): $ARCHITECTURES. - **** IMPORTANT **** +============================= +Update your version of Tcl/Tk to use IDLE or other Tk applications +============================= -Installing on OS X 10.8 (Mountain Lion) or later systems -======================================================== +To use IDLE or other programs that use the Tkinter graphical user interface toolkit, you need to install a newer third-party version of the Tcl/Tk frameworks. Visit https://www.python.org/download/mac/tcltk/ for current information about supported and recommended versions of Tcl/Tk for this version of Python and of Mac OS X. -If you are attempting to install on an OS X 10.8+ system, you may -see a message that Python can't be installed because it is from an -unidentified developer. This is because this Python installer -package is not yet compatible with the Gatekeeper security feature -introduced in OS X 10.8. To allow Python to be installed, you -can override the Gatekeeper policy for this install. In the Finder, -instead of double-clicking, control-click or right click the "Python" -installer package icon. Then select "Open using ... Installer" from -the contextual menu that appears. +============================= +Python 3 and Python 2 Co-existence +============================= - **** IMPORTANT **** - -Update your version of Tcl/Tk to use IDLE or other Tk applications -================================================================== - -To use IDLE or other programs that use the Tkinter graphical user -interface toolkit, you may need to install a newer third-party version -of the Tcl/Tk frameworks. Visit http://www.python.org/download/mac/tcltk/ -for current information about supported and recommended versions of -Tcl/Tk for this version of Python and of Mac OS X. - - **NEW* As of Python 3.4.0b1: - -New Installation Options and Defaults -===================================== - -The Python installer now includes an option to automatically install -or upgrade pip, a tool for installing and managing Python packages. -This option is enabled by default and no Internet access is required. -If you do not want the installer to do this, select the "Customize" -option at the "Installation Type" step and uncheck the "Install or -ugprade pip" option. - -To make it easier to use scripts installed by third-party Python -packages, with pip or by other means, the "Shell profile updater" -option is now enabled by default, as has been the case with Python -2.7.x installers. You can also turn this option off by selecting -"Customize" and unchecking the "Shell profile updater" option. You -can also update your shell profile later by launching the "Update -Shell Profile" command found in the /Applications/Python $VERSION -folder. You may need to start a new terminal window for the -changes to take effect. - -Python.org Python $VERSION and 2.7.x versions can both be installed and -will not conflict. Command names for Python 3 contain a 3 in them, -python3 (or python$VERSION), idle3 (or idle$VERSION), pip3 (or pip$VERSION), etc. -Python 2.7 command names contain a 2 or no digit: python2 (or -python2.7 or python), idle2 (or idle2.7 or idle), etc. If you want to -use pip with Python 2.7.x, you will need to download and install a -separate copy of it from the Python Package Index -(https://pypi.python.org/pypi). - -Using this version of Python on OS X -==================================== - -Python consists of the Python programming language interpreter, plus -a set of programs to allow easy access to it for Mac users including -an integrated development environment, IDLE, plus a set of pre-built -extension modules that open up specific Macintosh technologies to -Python programs. - -The installer puts applications, an "Update Shell Profile" command, -and a link to the optionally installed Python Documentation into the -"Python $VERSION" subfolder of the system Applications folder, -and puts the underlying machinery into the folder -$PYTHONFRAMEWORKINSTALLDIR. It can -optionally place links to the command-line tools in /usr/local/bin as -well. Double-click on the "Update Shell Profile" command to add the -"bin" directory inside the framework to your shell's search path. - -You must install onto your current boot disk, even though the -installer may not enforce this, otherwise things will not work. - -You can verify the integrity of the disk image file containing the -installer package and this ReadMe file by comparing its md5 checksum -and size with the values published on the release page linked at -http://www.python.org/download/ - -Installation requires approximately $INSTALL_SIZE MB of disk space, -ignore the message that it will take zero bytes. - -More information on Python in general can be found at -http://www.python.org. +Python.org Python $VERSION and 2.7.x versions can both be installed on your system and will not conflict. Command names for Python 3 contain a 3 in them, python3 (or python$VERSION), idle3 (or idle$VERSION), pip3 (or pip$VERSION), etc. Python 2.7 command names contain a 2 or no digit: python2 (or python2.7 or python), idle2 (or idle2.7 or idle), etc. If you want to use pip with Python 2.7.x, download and install a separate copy of it from the Python Package Index (https://pypi.python.org/pypi/pip/). diff --git a/Mac/BuildScript/resources/Welcome.rtf b/Mac/BuildScript/resources/Welcome.rtf --- a/Mac/BuildScript/resources/Welcome.rtf +++ b/Mac/BuildScript/resources/Welcome.rtf @@ -1,7 +1,7 @@ -{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400 -\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fmodern\fcharset0 CourierNewPSMT;} +{\rtf1\ansi\ansicpg1252\cocoartf1343\cocoasubrtf140 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} -\paperw11905\paperh16837\margl1440\margr1440\vieww9640\viewh10620\viewkind0 +\paperw11905\paperh16837\margl1440\margr1440\vieww12200\viewh10880\viewkind0 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640 \f0\fs24 \cf0 This package will install @@ -14,19 +14,7 @@ \b Python for Mac OS X \b0 consists of the Python programming language interpreter, plus a set of programs to allow easy access to it for Mac OS X users including an integrated development environment \b IDLE -\b0 and a set of pre-built extension modules that open up specific Macintosh technologies to Python programs.\ -\ - -\b NEW for Python 3.4: -\b0 This package now updates your shell profile by default to make $FULL_VERSION the default Python 3 version. This version can co-exist with other installed versions of Python 3 and Python 2. This package also installs a version of -\f1 pip -\f0 , the recommended tool for installing and managing Python packages. Type\ -\ - -\f1 pip3.4 --help -\f0 \ -\ -for an overview. See the ReadMe file and the Python documentation for more information.\ +\b0 .\ \ \b IMPORTANT: @@ -36,4 +24,4 @@ \b tkinter \b0 graphical user interface toolkit require specific versions of the \b Tcl/Tk -\b0 platform independent windowing toolkit. Visit {\field{\*\fldinst{HYPERLINK "http://www.python.org/download/mac/tcltk/"}}{\fldrslt http://www.python.org/download/mac/tcltk/}} for current information on supported and recommended versions of Tcl/Tk for this version of Python and Mac OS X.} \ No newline at end of file +\b0 platform independent windowing toolkit. Visit {\field{\*\fldinst{HYPERLINK "https://www.python.org/download/mac/tcltk/"}}{\fldrslt https://www.python.org/download/mac/tcltk/}} for current information on supported and recommended versions of Tcl/Tk for this version of Python and Mac OS X.} \ No newline at end of file diff --git a/Mac/BuildScript/resources/readme.rtf b/Mac/BuildScript/resources/readme.rtf new file mode 100644 --- /dev/null +++ b/Mac/BuildScript/resources/readme.rtf @@ -0,0 +1,51 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1343\cocoasubrtf140 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fmodern\fcharset0 CourierNewPSMT;} +{\colortbl;\red255\green255\blue255;} +\margl1440\margr1440\vieww13020\viewh15160\viewkind0 +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural + +\f0\fs24 \cf0 This package will install Python $FULL_VERSION for Mac OS X $MACOSX_DEPLOYMENT_TARGET for the following architecture(s): $ARCHITECTURES.\ +\ + +\b \ul Update your version of Tcl/Tk to use IDLE or other Tk applications +\b0 \ulnone \ +\ +To use IDLE or other programs that use the Tkinter graphical user interface toolkit, you need to install a newer third-party version of the +\i Tcl/Tk +\i0 frameworks. Visit {\field{\*\fldinst{HYPERLINK "https://www.python.org/download/mac/tcltk/"}}{\fldrslt https://www.python.org/download/mac/tcltk/}} for current information about supported and recommended versions of +\i Tcl/Tk +\i0 for this version of Python and of Mac OS X.\ + +\b \ul \ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural +\cf0 \ulc0 Python 3 and Python 2 Co-existence\ + +\b0 \ulnone \ +Python.org Python $VERSION and 2.7.x versions can both be installed on your system and will not conflict. Command names for Python 3 contain a 3 in them, +\f1 python3 +\f0 (or +\f1 python$VERSION +\f0 ), +\f1 idle3 +\f0 (or i +\f1 dle$VERSION +\f0 ), +\f1 pip3 +\f0 (or +\f1 pip$VERSION +\f0 ), etc. Python 2.7 command names contain a 2 or no digit: +\f1 python2 +\f0 (or +\f1 python2.7 +\f0 or +\f1 python +\f0 ), +\f1 idle2 +\f0 (or +\f1 idle2.7 +\f0 or +\f1 idle +\f0 ), etc. If you want to use +\f1 pip +\f0 with Python 2.7.x, download and install a separate copy of it from the Python Package Index ({\field{\*\fldinst{HYPERLINK "https://pypi.python.org/pypi/pip/"}}{\fldrslt https://pypi.python.org/pypi/pip/}}).\ +} \ No newline at end of file -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 15 10:19:13 2014 From: python-checkins at python.org (georg.brandl) Date: Sat, 15 Nov 2014 09:19:13 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Add_PEP_479=3A_Change_StopIte?= =?utf-8?q?ration_handling_inside_generators=2C_by_Chris_Angelico=2E?= Message-ID: <20141115091909.51557.18557@psf.io> https://hg.python.org/peps/rev/c8d6596edaed changeset: 5595:c8d6596edaed user: Georg Brandl date: Sat Nov 15 10:13:42 2014 +0100 summary: Add PEP 479: Change StopIteration handling inside generators, by Chris Angelico. files: pep-0479.txt | 123 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 123 insertions(+), 0 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt new file mode 100644 --- /dev/null +++ b/pep-0479.txt @@ -0,0 +1,123 @@ +PEP: 479 +Title: Change StopIteration handling inside generators +Version: $Revision$ +Last-Modified: $Date$ +Author: Chris Angelico +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 15-Nov-2014 +Python-Version: 3.5 +Post-History: + + +Abstract +======== + +This PEP proposes a semantic change to ``StopIteration`` when raised +inside a generator, unifying the behaviour of list comprehensions and +generator expressions somewhat. + + +Rationale +========= + +The interaction of generators and ``StopIteration`` is currently +somewhat surprising, and can conceal obscure bugs. An unexpected +exception should not result in subtly altered behaviour, but should +cause a noisy and easily-debugged traceback. Currently, +``StopIteration`` can be absorbed by the generator construct. + + +Proposal +======== + +If a ``StopIteration`` is about to bubble out of a generator frame, it +is replaced with some other exception (maybe ``RuntimeError``, maybe a +new custom ``Exception`` subclass, but *not* deriving from +``StopIteration``) which causes the ``next()`` call (which invoked the +generator) to fail, passing that exception out. From then on it's +just like any old exception. [3]_ + + +Consequences to existing code +============================= + +This change will affect existing code that depends on +``StopIteration`` bubbling up. The pure Python reference +implementation of ``groupby`` [1]_ currently has comments "Exit on +``StopIteration``" where it is expected that the exception will +propagate and then be handled. This will be unusual, but not unknown, +and such constructs will fail. + +(Nick Coghlan comments: """If you wanted to factor out a helper +function that terminated the generator you'd have to do "return +yield from helper()" rather than just "helper()".""") + +As this can break code, it is proposed to utilize the ``__future__`` +mechanism to introduce this, finally making it standard in Python 3.6 +or 3.7. + + +Alternate proposals +=================== + +Supplying a specific exception to raise on return +------------------------------------------------- + +Nick Coghlan suggested a means of providing a specific +``StopIteration`` instance to the generator; if any other instance of +``StopIteration`` is raised, it is an error, but if that particular +one is raised, the generator has properly completed. + + +Making return-triggered StopIterations obvious +---------------------------------------------- + +For certain situations, a simpler and fully backward-compatible +solution may be sufficient: when a generator returns, instead of +raising ``StopIteration``, it raises a specific subclass of +``StopIteration`` which can then be detected. If it is not that +subclass, it is an escaping exception rather than a return statement. + + +Criticism +========= + +Unofficial and apocryphal statistics suggest that this is seldom, if +ever, a problem. [4]_ Code does exist which relies on the current +behaviour, and there is the concern that this would be unnecessary +code churn to achieve little or no gain. + + +References +========== + +.. [1] Initial mailing list comment + (https://mail.python.org/pipermail/python-ideas/2014-November/029906.html) + +.. [2] Pure Python implementation of groupby + (https://docs.python.org/3/library/itertools.html#itertools.groupby) + +.. [3] Proposal by GvR + (https://mail.python.org/pipermail/python-ideas/2014-November/029953.html) + +.. [4] Response by Steven D'Aprano + (https://mail.python.org/pipermail/python-ideas/2014-November/029994.html) + + +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: https://hg.python.org/peps From solipsis at pitrou.net Sat Nov 15 10:31:30 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 15 Nov 2014 10:31:30 +0100 Subject: [Python-checkins] Daily reference leaks (97dc64adb6fe): sum=3 Message-ID: results for 97dc64adb6fe on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogAxuKtE', '-x'] From python-checkins at python.org Sat Nov 15 10:38:09 2014 From: python-checkins at python.org (georg.brandl) Date: Sat, 15 Nov 2014 09:38:09 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Add_Post-History_to_PEP_479?= =?utf-8?q?=2E?= Message-ID: <20141115093808.29208.23851@psf.io> https://hg.python.org/peps/rev/f956c67f79ab changeset: 5596:f956c67f79ab user: Georg Brandl date: Sat Nov 15 10:38:00 2014 +0100 summary: Add Post-History to PEP 479. files: pep-0479.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -8,7 +8,7 @@ Content-Type: text/x-rst Created: 15-Nov-2014 Python-Version: 3.5 -Post-History: +Post-History: 15-Nov-2014 Abstract -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Sat Nov 15 13:05:31 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 15 Nov 2014 12:05:31 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322823=3A_Use_set_?= =?utf-8?q?literals_instead_of_creating_a_set_from_a_tuple=2E?= Message-ID: <20141115120528.29230.17272@psf.io> https://hg.python.org/cpython/rev/f4e75efdc7f1 changeset: 93496:f4e75efdc7f1 user: Serhiy Storchaka date: Sat Nov 15 13:30:42 2014 +0200 summary: Issue #22823: Use set literals instead of creating a set from a tuple. files: Tools/clinic/clinic.py | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2535,9 +2535,9 @@ length=False, nullable=False, zeroes=False): types = set(types.strip().split()) - bytes_type = set(("bytes",)) - str_type = set(("str",)) - all_3_type = set(("bytearray",)) | bytes_type | str_type + bytes_type = {"bytes"} + str_type = {"str"} + all_3_type = {"bytearray"} | bytes_type | str_type is_bytes = types == bytes_type is_str = types == str_type is_all_3 = types == all_3_type @@ -2633,12 +2633,12 @@ 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',)) - bytearray_type = set(('bytearray',)) - buffer_type = set(('buffer',)) - rwbuffer_type = set(('rwbuffer',)) - robuffer_type = set(('robuffer',)) - str_type = set(('str',)) + bytes_type = {'bytes'} + bytearray_type = {'bytearray'} + buffer_type = {'buffer'} + rwbuffer_type = {'rwbuffer'} + robuffer_type = {'robuffer'} + str_type = {'str'} bytes_bytearray_buffer_type = bytes_type | bytearray_type | buffer_type format_unit = None -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 15 13:05:31 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 15 Nov 2014 12:05:31 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322193=3A_Fixed_integer_overflow_error_in_sys=2E?= =?utf-8?b?Z2V0c2l6ZW9mKCku?= Message-ID: <20141115120528.29210.16719@psf.io> https://hg.python.org/cpython/rev/b7651f9be4a1 changeset: 93495:b7651f9be4a1 parent: 93492:e79c6ea48b83 parent: 93494:df5c6b05238e user: Serhiy Storchaka date: Sat Nov 15 13:22:27 2014 +0200 summary: Issue #22193: Fixed integer overflow error in sys.getsizeof(). Fixed an error in _PySys_GetSizeOf declaration. files: Include/sysmodule.h | 2 +- Lib/test/test_sys.py | 31 +++++++++++++++++++++++++++++++ Python/sysmodule.c | 15 ++++++++++----- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/Include/sysmodule.h b/Include/sysmodule.h --- a/Include/sysmodule.h +++ b/Include/sysmodule.h @@ -34,7 +34,7 @@ PyAPI_FUNC(PyObject *) PySys_GetXOptions(void); #ifndef Py_LIMITED_API -PyAPI_DATA(size_t) _PySys_GetSizeOf(PyObject *); +PyAPI_FUNC(size_t) _PySys_GetSizeOf(PyObject *); #endif #ifdef __cplusplus diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -770,6 +770,37 @@ # but lists are self.assertEqual(sys.getsizeof([]), vsize('Pn') + gc_header_size) + def test_errors(self): + class BadSizeof: + def __sizeof__(self): + raise ValueError + self.assertRaises(ValueError, sys.getsizeof, BadSizeof()) + + class InvalidSizeof: + def __sizeof__(self): + return None + self.assertRaises(TypeError, sys.getsizeof, InvalidSizeof()) + sentinel = ["sentinel"] + self.assertIs(sys.getsizeof(InvalidSizeof(), sentinel), sentinel) + + class FloatSizeof: + def __sizeof__(self): + return 4.5 + self.assertRaises(TypeError, sys.getsizeof, FloatSizeof()) + self.assertIs(sys.getsizeof(FloatSizeof(), sentinel), sentinel) + + class OverflowSizeof(int): + def __sizeof__(self): + return int(self) + self.assertEqual(sys.getsizeof(OverflowSizeof(sys.maxsize)), + sys.maxsize + self.gc_headsize) + with self.assertRaises(OverflowError): + sys.getsizeof(OverflowSizeof(sys.maxsize + 1)) + with self.assertRaises(ValueError): + sys.getsizeof(OverflowSizeof(-1)) + with self.assertRaises((ValueError, OverflowError)): + sys.getsizeof(OverflowSizeof(-sys.maxsize - 1)) + def test_default(self): size = test.support.calcvobjsize self.assertEqual(sys.getsizeof(True), size('') + self.longdigit) diff --git a/Python/sysmodule.c b/Python/sysmodule.c --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -868,7 +868,7 @@ { PyObject *res = NULL; PyObject *method; - size_t size; + Py_ssize_t size; /* Make sure the type is initialized. float gets initialized late */ if (PyType_Ready(Py_TYPE(o)) < 0) @@ -889,15 +889,20 @@ if (res == NULL) return (size_t)-1; - size = PyLong_AsSize_t(res); + size = PyLong_AsSsize_t(res); Py_DECREF(res); - if (size == (size_t)-1 && PyErr_Occurred()) + if (size == -1 && PyErr_Occurred()) return (size_t)-1; + if (size < 0) { + PyErr_SetString(PyExc_ValueError, "__sizeof__() should return >= 0"); + return (size_t)-1; + } + /* add gc_head size */ if (PyObject_IS_GC(o)) - size += sizeof(PyGC_Head); - return size; + return ((size_t)size) + sizeof(PyGC_Head); + return (size_t)size; } static PyObject * -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 15 13:05:31 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 15 Nov 2014 12:05:31 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIyMTkz?= =?utf-8?q?=3A_Fixed_integer_overflow_error_in_sys=2Egetsizeof=28=29=2E?= Message-ID: <20141115120527.57228.93720@psf.io> https://hg.python.org/cpython/rev/3537994fa43b changeset: 93493:3537994fa43b branch: 2.7 parent: 93491:33d68c79d601 user: Serhiy Storchaka date: Sat Nov 15 13:21:01 2014 +0200 summary: Issue #22193: Fixed integer overflow error in sys.getsizeof(). Fixed an error in _PySys_GetSizeOf declaration. files: Include/sysmodule.h | 2 +- Lib/test/test_sys.py | 25 +++++++++++++++++++++++++ Python/sysmodule.c | 13 +++++++++---- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/Include/sysmodule.h b/Include/sysmodule.h --- a/Include/sysmodule.h +++ b/Include/sysmodule.h @@ -23,7 +23,7 @@ PyAPI_FUNC(void) PySys_AddWarnOption(char *); PyAPI_FUNC(int) PySys_HasWarnOptions(void); -PyAPI_DATA(size_t) _PySys_GetSizeOf(PyObject *); +PyAPI_FUNC(size_t) _PySys_GetSizeOf(PyObject *); #ifdef __cplusplus } diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -494,6 +494,31 @@ # but lists are self.assertEqual(sys.getsizeof([]), size('P PP') + gc_header_size) + def test_errors(self): + class BadSizeof(object): + def __sizeof__(self): + raise ValueError + self.assertRaises(ValueError, sys.getsizeof, BadSizeof()) + + class InvalidSizeof(object): + def __sizeof__(self): + return None + self.assertRaises(TypeError, sys.getsizeof, InvalidSizeof()) + sentinel = ["sentinel"] + self.assertIs(sys.getsizeof(InvalidSizeof(), sentinel), sentinel) + + class OverflowSizeof(int): + def __sizeof__(self): + return int(self) + self.assertEqual(sys.getsizeof(OverflowSizeof(sys.maxsize)), + sys.maxsize + self.gc_headsize) + with self.assertRaises(OverflowError): + sys.getsizeof(OverflowSizeof(sys.maxsize + 1)) + with self.assertRaises(ValueError): + sys.getsizeof(OverflowSizeof(-1)) + with self.assertRaises((ValueError, OverflowError)): + sys.getsizeof(OverflowSizeof(-sys.maxsize - 1)) + def test_default(self): size = test.test_support.calcobjsize self.assertEqual(sys.getsizeof(True, -1), size('l')) diff --git a/Python/sysmodule.c b/Python/sysmodule.c --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -689,7 +689,7 @@ { static PyObject *str__sizeof__ = NULL; PyObject *res = NULL; - size_t size; + Py_ssize_t size; /* Make sure the type is initialized. float gets initialized late */ if (PyType_Ready(Py_TYPE(o)) < 0) @@ -718,14 +718,19 @@ size = (size_t)PyInt_AsSsize_t(res); Py_DECREF(res); - if (size == (size_t)-1 && PyErr_Occurred()) + if (size == -1 && PyErr_Occurred()) return (size_t)-1; } + if (size < 0) { + PyErr_SetString(PyExc_ValueError, "__sizeof__() should return >= 0"); + return (size_t)-1; + } + /* add gc_head size */ if (PyObject_IS_GC(o)) - size += sizeof(PyGC_Head); - return size; + return ((size_t)size) + sizeof(PyGC_Head); + return (size_t)size; } static PyObject * -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 15 13:05:31 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 15 Nov 2014 12:05:31 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyMTkz?= =?utf-8?q?=3A_Fixed_integer_overflow_error_in_sys=2Egetsizeof=28=29=2E?= Message-ID: <20141115120528.51555.90020@psf.io> https://hg.python.org/cpython/rev/df5c6b05238e changeset: 93494:df5c6b05238e branch: 3.4 parent: 93489:e8182c6c9ef1 user: Serhiy Storchaka date: Sat Nov 15 13:21:37 2014 +0200 summary: Issue #22193: Fixed integer overflow error in sys.getsizeof(). Fixed an error in _PySys_GetSizeOf declaration. files: Include/sysmodule.h | 2 +- Lib/test/test_sys.py | 31 +++++++++++++++++++++++++++++++ Python/sysmodule.c | 15 ++++++++++----- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/Include/sysmodule.h b/Include/sysmodule.h --- a/Include/sysmodule.h +++ b/Include/sysmodule.h @@ -34,7 +34,7 @@ PyAPI_FUNC(PyObject *) PySys_GetXOptions(void); #ifndef Py_LIMITED_API -PyAPI_DATA(size_t) _PySys_GetSizeOf(PyObject *); +PyAPI_FUNC(size_t) _PySys_GetSizeOf(PyObject *); #endif #ifdef __cplusplus diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -723,6 +723,37 @@ # but lists are self.assertEqual(sys.getsizeof([]), vsize('Pn') + gc_header_size) + def test_errors(self): + class BadSizeof: + def __sizeof__(self): + raise ValueError + self.assertRaises(ValueError, sys.getsizeof, BadSizeof()) + + class InvalidSizeof: + def __sizeof__(self): + return None + self.assertRaises(TypeError, sys.getsizeof, InvalidSizeof()) + sentinel = ["sentinel"] + self.assertIs(sys.getsizeof(InvalidSizeof(), sentinel), sentinel) + + class FloatSizeof: + def __sizeof__(self): + return 4.5 + self.assertRaises(TypeError, sys.getsizeof, FloatSizeof()) + self.assertIs(sys.getsizeof(FloatSizeof(), sentinel), sentinel) + + class OverflowSizeof(int): + def __sizeof__(self): + return int(self) + self.assertEqual(sys.getsizeof(OverflowSizeof(sys.maxsize)), + sys.maxsize + self.gc_headsize) + with self.assertRaises(OverflowError): + sys.getsizeof(OverflowSizeof(sys.maxsize + 1)) + with self.assertRaises(ValueError): + sys.getsizeof(OverflowSizeof(-1)) + with self.assertRaises((ValueError, OverflowError)): + sys.getsizeof(OverflowSizeof(-sys.maxsize - 1)) + def test_default(self): size = test.support.calcvobjsize self.assertEqual(sys.getsizeof(True), size('') + self.longdigit) diff --git a/Python/sysmodule.c b/Python/sysmodule.c --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -868,7 +868,7 @@ { PyObject *res = NULL; PyObject *method; - size_t size; + Py_ssize_t size; /* Make sure the type is initialized. float gets initialized late */ if (PyType_Ready(Py_TYPE(o)) < 0) @@ -889,15 +889,20 @@ if (res == NULL) return (size_t)-1; - size = PyLong_AsSize_t(res); + size = PyLong_AsSsize_t(res); Py_DECREF(res); - if (size == (size_t)-1 && PyErr_Occurred()) + if (size == -1 && PyErr_Occurred()) return (size_t)-1; + if (size < 0) { + PyErr_SetString(PyExc_ValueError, "__sizeof__() should return >= 0"); + return (size_t)-1; + } + /* add gc_head size */ if (PyObject_IS_GC(o)) - size += sizeof(PyGC_Head); - return size; + return ((size_t)size) + sizeof(PyGC_Head); + return (size_t)size; } static PyObject * -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 15 19:59:07 2014 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 15 Nov 2014 18:59:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322824=3A__Simplif?= =?utf-8?q?y_reprlib_output_format_for_empty_arrays?= Message-ID: <20141115185907.51553.8157@psf.io> https://hg.python.org/cpython/rev/cf5b910ac4c8 changeset: 93497:cf5b910ac4c8 user: Raymond Hettinger date: Sat Nov 15 10:58:58 2014 -0800 summary: Issue #22824: Simplify reprlib output format for empty arrays files: Lib/reprlib.py | 2 ++ Lib/test/test_reprlib.py | 2 +- Misc/NEWS | 3 +++ 3 files changed, 6 insertions(+), 1 deletions(-) diff --git a/Lib/reprlib.py b/Lib/reprlib.py --- a/Lib/reprlib.py +++ b/Lib/reprlib.py @@ -83,6 +83,8 @@ return self._repr_iterable(x, level, '[', ']', self.maxlist) def repr_array(self, x, level): + if not x: + return "array('%s')" % x.typecode header = "array('%s', [" % x.typecode return self._repr_iterable(x, level, header, '])', self.maxarray) diff --git a/Lib/test/test_reprlib.py b/Lib/test/test_reprlib.py --- a/Lib/test/test_reprlib.py +++ b/Lib/test/test_reprlib.py @@ -94,7 +94,7 @@ eq(r(d), "{'alice': 1, 'arthur': 1, 'bob': 2, 'charles': 3, ...}") # array.array after 5. - eq(r(array('i')), "array('i', [])") + eq(r(array('i')), "array('i')") eq(r(array('i', [1])), "array('i', [1])") eq(r(array('i', [1, 2])), "array('i', [1, 2])") eq(r(array('i', [1, 2, 3])), "array('i', [1, 2, 3])") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -209,6 +209,9 @@ - Issue #22824: Updated reprlib output format for sets to use set literals. Patch contributed by Berker Peksag. +- Issue #22824: Updated reprlib output format for arrays to display empty + arrays without an unnecessary empty list. Suggested by Serhiy Storchaka. + - Issue #22406: Fixed the uu_codec codec incorrectly ported to 3.x. Based on patch by Martin Panter. -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Sun Nov 16 10:32:11 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 16 Nov 2014 10:32:11 +0100 Subject: [Python-checkins] Daily reference leaks (cf5b910ac4c8): sum=3 Message-ID: results for cf5b910ac4c8 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogTOSWib', '-x'] From python-checkins at python.org Mon Nov 17 10:26:15 2014 From: python-checkins at python.org (georg.brandl) Date: Mon, 17 Nov 2014 09:26:15 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Update_PEP_479_from_author=2E?= Message-ID: <20141117092613.36970.60096@psf.io> https://hg.python.org/peps/rev/75a785922e8c changeset: 5597:75a785922e8c user: Georg Brandl date: Mon Nov 17 10:26:09 2014 +0100 summary: Update PEP 479 from author. files: pep-0479.txt | 62 +++++++++++++++++++++++++++++++++++---- 1 files changed, 55 insertions(+), 7 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -29,15 +29,27 @@ ``StopIteration`` can be absorbed by the generator construct. +Background information +====================== + +When a generator frame is (re)started as a result of a ``__next__()`` +(or ``send()`` or ``throw()``) call, one of three outcomes can occur: + +* A yield point is reached, and the yielded value is returned. +* The frame is returned from; ``StopIteration`` is raised. +* An exception is thrown, which bubbles out. + + Proposal ======== If a ``StopIteration`` is about to bubble out of a generator frame, it -is replaced with some other exception (maybe ``RuntimeError``, maybe a -new custom ``Exception`` subclass, but *not* deriving from -``StopIteration``) which causes the ``next()`` call (which invoked the -generator) to fail, passing that exception out. From then on it's -just like any old exception. [3]_ +is replaced with ``RuntimeError``, which causes the ``next()`` call +(which invoked the generator) to fail, passing that exception out. +From then on it's just like any old exception. [3]_ + +This affects the third outcome listed above, without altering any +other effects. Consequences to existing code @@ -56,19 +68,38 @@ As this can break code, it is proposed to utilize the ``__future__`` mechanism to introduce this, finally making it standard in Python 3.6 -or 3.7. +or 3.7. Any generator function constructed in the presence of this +directive will have a flag set on its code object, and generators with +the flag set will behave according to this proposal. Once the feature +becomes standard, the flag may be dropped; code should not inspect +generators for it. (GvR: """And the flag should somehow be +transferred to the stack frame when the function is executed, so the +right action can be taken when an exception is about to bubble out of +that frame.""") Alternate proposals =================== +Raising something other than RuntimeError +----------------------------------------- + +Rather than the generic ``RuntimeError``, it might make sense to raise +a new exception type ``UnexpectedStopIteration``. This has the +downside of implicitly encouraging that it be caught; the correct +action is to catch the original ``StopIteration``, not the chained +exception. + + Supplying a specific exception to raise on return ------------------------------------------------- Nick Coghlan suggested a means of providing a specific ``StopIteration`` instance to the generator; if any other instance of ``StopIteration`` is raised, it is an error, but if that particular -one is raised, the generator has properly completed. +one is raised, the generator has properly completed. This subproposal +has been withdrawn in favour of better options, but is retained for +reference. Making return-triggered StopIterations obvious @@ -80,6 +111,23 @@ ``StopIteration`` which can then be detected. If it is not that subclass, it is an escaping exception rather than a return statement. +Of the three outcomes listed above: + +* A yielded value, obviously, would still be returned. +* If the frame is returned from, ``GeneratorReturn`` is raised. +* If an instance of ``GeneratorReturn`` would be raised, instead an + instance of ``StopIteration`` would be raised. + +In the third case, the ``StopIteration`` would have the ``value`` of +the original ``GeneratorReturn``, and would reference the original +exception in its ``__cause__``. If uncaught, this would clearly show +the chaining of exceptions. + +This does *not* affect the discrepancy between generator expressions +and list comprehensions, but allows generator-aware code (such as the +contextlib and asyncio modules) to reliably differentiate between the +second and third outcomes listed above. + Criticism ========= -- Repository URL: https://hg.python.org/peps From solipsis at pitrou.net Mon Nov 17 10:33:28 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 17 Nov 2014 10:33:28 +0100 Subject: [Python-checkins] Daily reference leaks (cf5b910ac4c8): sum=3 Message-ID: results for cf5b910ac4c8 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogg835Z8', '-x'] From python-checkins at python.org Mon Nov 17 20:32:23 2014 From: python-checkins at python.org (guido.van.rossum) Date: Mon, 17 Nov 2014 19:32:23 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Make_PEP_479_=28Change_StopIt?= =?utf-8?q?eration=29_be_more_specific=2C_improve_some_wording=2C_etc=2E?= Message-ID: <20141117193159.51559.86606@psf.io> https://hg.python.org/peps/rev/8de949863677 changeset: 5598:8de949863677 user: Guido van Rossum date: Mon Nov 17 11:31:54 2014 -0800 summary: Make PEP 479 (Change StopIteration) be more specific, improve some wording, etc. files: pep-0479.txt | 73 +++++++++++++++++++++++++++++---------- 1 files changed, 53 insertions(+), 20 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -15,8 +15,12 @@ ======== This PEP proposes a semantic change to ``StopIteration`` when raised -inside a generator, unifying the behaviour of list comprehensions and -generator expressions somewhat. +inside a generator. This would unify the behaviour of list +comprehensions and generator expressions, reducing surprises such as +the one that started this discussion [1]_. This is also the main +backwards incompatibility of the proposal -- any generator that +depends on an implicitly-raised ``StopIteration`` to terminate it will +have to be rewritten to either catch that exception or use a for-loop. Rationale @@ -37,7 +41,10 @@ * A yield point is reached, and the yielded value is returned. * The frame is returned from; ``StopIteration`` is raised. -* An exception is thrown, which bubbles out. +* An exception is raised, which bubbles out. + +In the latter two cases the frame is abandoned (and the generator +object's ``gi_frame`` attribute is set to None). Proposal @@ -49,33 +56,47 @@ From then on it's just like any old exception. [3]_ This affects the third outcome listed above, without altering any -other effects. +other effects. Furthermore, it only affects this outcome when the +exception raised is StopIteration (or a subclass thereof). +Note that the proposed replacement happens at the point where the +exception is about to bubble out of the frame, i.e. after any +``except`` or ``finally`` blocks that could affect it have been +exited. The ``StopIteration`` raised by returning from the frame is +not affected (the point being that ``StopIteration`` means that the +generator terminated "normally", i.e. it did not raise an exception). -Consequences to existing code -============================= + +Consequences for existing code +============================== This change will affect existing code that depends on ``StopIteration`` bubbling up. The pure Python reference -implementation of ``groupby`` [1]_ currently has comments "Exit on +implementation of ``groupby`` [2]_ currently has comments "Exit on ``StopIteration``" where it is expected that the exception will propagate and then be handled. This will be unusual, but not unknown, -and such constructs will fail. +and such constructs will fail. Other examples abound, e.g. [5]_, [6]_. (Nick Coghlan comments: """If you wanted to factor out a helper function that terminated the generator you'd have to do "return yield from helper()" rather than just "helper()".""") +There are also examples of generator expressions floating around that +rely on a StopIteration raised by the expression, the target or the +predicate (rather than by the __next__() call implied in the ``for`` +loop proper). + As this can break code, it is proposed to utilize the ``__future__`` -mechanism to introduce this, finally making it standard in Python 3.6 -or 3.7. Any generator function constructed in the presence of this -directive will have a flag set on its code object, and generators with -the flag set will behave according to this proposal. Once the feature -becomes standard, the flag may be dropped; code should not inspect -generators for it. (GvR: """And the flag should somehow be -transferred to the stack frame when the function is executed, so the -right action can be taken when an exception is about to bubble out of -that frame.""") +mechanism to introduce this in Python 3.5, finally making it standard +in Python 3.6 or 3.7. The proposed syntax is:: + + from __future__ import replace_stopiteration_in_generators + +Any generator function constructed under the influence of this +directive will have the REPLACE_STOPITERATION flag set on its code +object, and generators with the flag set will behave according to this +proposal. Once the feature becomes standard, the flag may be dropped; +code should not inspect generators for it. Alternate proposals @@ -123,19 +144,25 @@ exception in its ``__cause__``. If uncaught, this would clearly show the chaining of exceptions. -This does *not* affect the discrepancy between generator expressions +This alternative does *not* affect the discrepancy between generator expressions and list comprehensions, but allows generator-aware code (such as the contextlib and asyncio modules) to reliably differentiate between the second and third outcomes listed above. +However, once code exists that depends on this distinction between +``GeneratorReturn`` and ``StopIteration``, a generator that invokes +another generator and relies on the latter's ``StopIteration`` to +bubble out would still be potentially wrong, depending on the use made +of the distinction between the two exception types. + Criticism ========= Unofficial and apocryphal statistics suggest that this is seldom, if ever, a problem. [4]_ Code does exist which relies on the current -behaviour, and there is the concern that this would be unnecessary -code churn to achieve little or no gain. +behaviour (e.g. [2]_, [5]_, [6]_), and there is the concern that this +would be unnecessary code churn to achieve little or no gain. References @@ -153,6 +180,12 @@ .. [4] Response by Steven D'Aprano (https://mail.python.org/pipermail/python-ideas/2014-November/029994.html) +.. [5] Split a sequence or generator using a predicate + (http://code.activestate.com/recipes/578416-split-a-sequence-or-generator-using-a-predicate/) + +.. [6] wrap unbounded generator to restrict its output + (http://code.activestate.com/recipes/66427-wrap-unbounded-generator-to-restrict-its-output/) + Copyright ========= -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Mon Nov 17 21:16:35 2014 From: python-checkins at python.org (guido.van.rossum) Date: Mon, 17 Nov 2014 20:16:35 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Add_more_words_to_GeneratorRe?= =?utf-8?q?turn_alternative=2E?= Message-ID: <20141117201550.57220.78035@psf.io> https://hg.python.org/peps/rev/d71f1c9cd084 changeset: 5599:d71f1c9cd084 user: Guido van Rossum date: Mon Nov 17 12:15:42 2014 -0800 summary: Add more words to GeneratorReturn alternative. files: pep-0479.txt | 27 +++++++++++++++++++++------ 1 files changed, 21 insertions(+), 6 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -129,8 +129,18 @@ For certain situations, a simpler and fully backward-compatible solution may be sufficient: when a generator returns, instead of raising ``StopIteration``, it raises a specific subclass of -``StopIteration`` which can then be detected. If it is not that -subclass, it is an escaping exception rather than a return statement. +``StopIteration`` (``GeneratorReturn``) which can then be detected. +If it is not that subclass, it is an escaping exception rather than a +return statement. + +The inspiration for this alternative proposal was Nick's observation +[7]_ that if an ``asyncio`` coroutine [8]_ accidentally raises +``StopIteration``, it currently terminates silently, which may present +a hard-to-debug mystery to the developer. The main proposal turns +such accidents in clearly distinguishable ``RuntimeError`` exceptions, +but if that is rejected, this alternate proposal would enable +``asyncio`` to distinguish between a ``return`` statement and an +accidentally-raised ``StopIteration`` exception. Of the three outcomes listed above: @@ -144,10 +154,10 @@ exception in its ``__cause__``. If uncaught, this would clearly show the chaining of exceptions. -This alternative does *not* affect the discrepancy between generator expressions -and list comprehensions, but allows generator-aware code (such as the -contextlib and asyncio modules) to reliably differentiate between the -second and third outcomes listed above. +This alternative does *not* affect the discrepancy between generator +expressions and list comprehensions, but allows generator-aware code +(such as the ``contextlib`` and ``asyncio`` modules) to reliably +differentiate between the second and third outcomes listed above. However, once code exists that depends on this distinction between ``GeneratorReturn`` and ``StopIteration``, a generator that invokes @@ -186,6 +196,11 @@ .. [6] wrap unbounded generator to restrict its output (http://code.activestate.com/recipes/66427-wrap-unbounded-generator-to-restrict-its-output/) +.. [7] Post from Nick Coghlan mentioning asyncio + (https://mail.python.org/pipermail/python-ideas/2014-November/029961.html) + +.. [8] Coroutines in asyncio + (https://docs.python.org/3/library/asyncio-task.html#coroutines) Copyright ========= -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Mon Nov 17 22:50:53 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 17 Nov 2014 21:50:53 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320662=3A_Argspec_now_is_escaped_in_html_output_?= =?utf-8?q?of_pydoc=2E?= Message-ID: <20141117215051.51549.3811@psf.io> https://hg.python.org/cpython/rev/1855b5c3da61 changeset: 93499:1855b5c3da61 parent: 93497:cf5b910ac4c8 parent: 93498:cf2e424e0413 user: Serhiy Storchaka date: Mon Nov 17 23:48:35 2014 +0200 summary: Issue #20662: Argspec now is escaped in html output of pydoc. files: Lib/pydoc.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -954,7 +954,7 @@ if not argspec: argspec = '(...)' - decl = title + argspec + (note and self.grey( + decl = title + self.escape(argspec) + (note and self.grey( '%s' % note)) if skipdocs: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 17 22:50:53 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Mon, 17 Nov 2014 21:50:53 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIwNjYy?= =?utf-8?q?=3A_Argspec_now_is_escaped_in_html_output_of_pydoc=2E?= Message-ID: <20141117215051.57218.99105@psf.io> https://hg.python.org/cpython/rev/cf2e424e0413 changeset: 93498:cf2e424e0413 branch: 3.4 parent: 93494:df5c6b05238e user: Serhiy Storchaka date: Mon Nov 17 23:48:02 2014 +0200 summary: Issue #20662: Argspec now is escaped in html output of pydoc. files: Lib/pydoc.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -956,7 +956,7 @@ if not argspec: argspec = '(...)' - decl = title + argspec + (note and self.grey( + decl = title + self.escape(argspec) + (note and self.grey( '%s' % note)) if skipdocs: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 18 01:12:33 2014 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 18 Nov 2014 00:12:33 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Add_link_to_survey_by_Steven_?= =?utf-8?q?D=2C_and_summarize_the_two_responses_so_far=2E?= Message-ID: <20141118001230.62766.45608@psf.io> https://hg.python.org/peps/rev/7f846f74013f changeset: 5600:7f846f74013f user: Guido van Rossum date: Mon Nov 17 16:12:26 2014 -0800 summary: Add link to survey by Steven D, and summarize the two responses so far. files: pep-0479.txt | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -174,6 +174,11 @@ behaviour (e.g. [2]_, [5]_, [6]_), and there is the concern that this would be unnecessary code churn to achieve little or no gain. +Steven D'Aprano started an informal survey on comp.lang.python [9]_; +at the time of writing only two responses have been received: one was +in favor of changing list comprehensions to match generator +expressions (!), the other was in favor of this PEP's main proposal. + References ========== @@ -202,6 +207,9 @@ .. [8] Coroutines in asyncio (https://docs.python.org/3/library/asyncio-task.html#coroutines) +.. [9] Thread on comp.lang.python started by Steven D'Aprano + (https://mail.python.org/pipermail/python-list/2014-November/680757.html) + Copyright ========= -- Repository URL: https://hg.python.org/peps From solipsis at pitrou.net Tue Nov 18 10:33:46 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 18 Nov 2014 10:33:46 +0100 Subject: [Python-checkins] Daily reference leaks (1855b5c3da61): sum=9 Message-ID: results for 1855b5c3da61 on branch "default" -------------------------------------------- test_collections leaked [0, 0, 4] references, sum=4 test_collections leaked [0, 0, 2] memory blocks, sum=2 test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogiR2Ijf', '-x'] From python-checkins at python.org Tue Nov 18 16:48:58 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 18 Nov 2014 15:48:58 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzE4NjM3?= =?utf-8?q?=3A_Fixed_an_error_in_=5FPyNode=5FSizeOf_declaration=2E?= Message-ID: <20141118153731.62762.13581@psf.io> https://hg.python.org/cpython/rev/ab3e8aab7119 changeset: 93501:ab3e8aab7119 branch: 3.4 parent: 93498:cf2e424e0413 user: Serhiy Storchaka date: Tue Nov 18 17:30:15 2014 +0200 summary: Issue #18637: Fixed an error in _PyNode_SizeOf declaration. Patch by Roumen Petrov. files: Include/node.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Include/node.h b/Include/node.h --- a/Include/node.h +++ b/Include/node.h @@ -21,7 +21,7 @@ char *str, int lineno, int col_offset); PyAPI_FUNC(void) PyNode_Free(node *n); #ifndef Py_LIMITED_API -Py_ssize_t _PyNode_SizeOf(node *n); +PyAPI_FUNC(Py_ssize_t) _PyNode_SizeOf(node *n); #endif /* Node access functions */ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 18 16:48:58 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 18 Nov 2014 15:48:58 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4NjM3?= =?utf-8?q?=3A_Fixed_an_error_in_=5FPyNode=5FSizeOf_declaration=2E?= Message-ID: <20141118153731.36065.81873@psf.io> https://hg.python.org/cpython/rev/eb25629d2a46 changeset: 93500:eb25629d2a46 branch: 2.7 parent: 93493:3537994fa43b user: Serhiy Storchaka date: Tue Nov 18 17:29:47 2014 +0200 summary: Issue #18637: Fixed an error in _PyNode_SizeOf declaration. Patch by Roumen Petrov. files: Include/node.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Include/node.h b/Include/node.h --- a/Include/node.h +++ b/Include/node.h @@ -20,7 +20,7 @@ PyAPI_FUNC(int) PyNode_AddChild(node *n, int type, char *str, int lineno, int col_offset); PyAPI_FUNC(void) PyNode_Free(node *n); -Py_ssize_t _PyNode_SizeOf(node *n); +PyAPI_FUNC(Py_ssize_t) _PyNode_SizeOf(node *n); /* Node access functions */ #define NCH(n) ((n)->n_nchildren) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 18 16:48:58 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 18 Nov 2014 15:48:58 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318637=3A_Fixed_an_error_in_=5FPyNode=5FSizeOf_d?= =?utf-8?q?eclaration=2E?= Message-ID: <20141118153731.109150.60900@psf.io> https://hg.python.org/cpython/rev/0f663e0ce1d3 changeset: 93502:0f663e0ce1d3 parent: 93499:1855b5c3da61 parent: 93501:ab3e8aab7119 user: Serhiy Storchaka date: Tue Nov 18 17:30:50 2014 +0200 summary: Issue #18637: Fixed an error in _PyNode_SizeOf declaration. Patch by Roumen Petrov. files: Include/node.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Include/node.h b/Include/node.h --- a/Include/node.h +++ b/Include/node.h @@ -21,7 +21,7 @@ char *str, int lineno, int col_offset); PyAPI_FUNC(void) PyNode_Free(node *n); #ifndef Py_LIMITED_API -Py_ssize_t _PyNode_SizeOf(node *n); +PyAPI_FUNC(Py_ssize_t) _PyNode_SizeOf(node *n); #endif /* Node access functions */ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 18 21:41:01 2014 From: python-checkins at python.org (victor.stinner) Date: Tue, 18 Nov 2014 20:41:01 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2320948=3A_Inline_m?= =?utf-8?q?akefmt=28=29_in_unicode=5Ffromformat=5Farg=28=29?= Message-ID: <20141118204100.13371.66628@psf.io> https://hg.python.org/cpython/rev/d6d2549340cb changeset: 93503:d6d2549340cb user: Victor Stinner date: Tue Nov 18 21:40:51 2014 +0100 summary: Issue #20948: Inline makefmt() in unicode_fromformat_arg() files: Objects/unicodeobject.c | 53 ++++------------------------ 1 files changed, 9 insertions(+), 44 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -2313,35 +2313,6 @@ #endif /* HAVE_WCHAR_H */ -static void -makefmt(char *fmt, int longflag, int longlongflag, int size_tflag, - char c) -{ - *fmt++ = '%'; - if (longflag) - *fmt++ = 'l'; - else if (longlongflag) { - /* longlongflag should only ever be nonzero on machines with - HAVE_LONG_LONG defined */ -#ifdef HAVE_LONG_LONG - char *f = PY_FORMAT_LONG_LONG; - while (*f) - *fmt++ = *f++; -#else - /* we shouldn't ever get here */ - assert(0); - *fmt++ = 'l'; -#endif - } - else if (size_tflag) { - char *f = PY_FORMAT_SIZE_T; - while (*f) - *fmt++ = *f++; - } - *fmt++ = c; - *fmt = '\0'; -} - /* maximum number of characters required for output of %lld or %p. We need at most ceil(log10(256)*SIZEOF_LONG_LONG) digits, plus 1 for the sign. 53/22 is an upper bound for log10(256). */ @@ -2517,48 +2488,42 @@ case 'x': { /* used by sprintf */ - char fmt[10]; /* should be enough for "%0lld\0" */ char buffer[MAX_LONG_LONG_CHARS]; Py_ssize_t arglen; if (*f == 'u') { - makefmt(fmt, longflag, longlongflag, size_tflag, *f); - if (longflag) - len = sprintf(buffer, fmt, + len = sprintf(buffer, "%lu", va_arg(*vargs, unsigned long)); #ifdef HAVE_LONG_LONG else if (longlongflag) - len = sprintf(buffer, fmt, + len = sprintf(buffer, "%" PY_FORMAT_LONG_LONG "u", va_arg(*vargs, unsigned PY_LONG_LONG)); #endif else if (size_tflag) - len = sprintf(buffer, fmt, + len = sprintf(buffer, "%" PY_FORMAT_SIZE_T "u", va_arg(*vargs, size_t)); else - len = sprintf(buffer, fmt, + len = sprintf(buffer, "%u", va_arg(*vargs, unsigned int)); } else if (*f == 'x') { - makefmt(fmt, 0, 0, 0, 'x'); - len = sprintf(buffer, fmt, va_arg(*vargs, int)); + len = sprintf(buffer, "%x", va_arg(*vargs, int)); } else { - makefmt(fmt, longflag, longlongflag, size_tflag, *f); - if (longflag) - len = sprintf(buffer, fmt, + len = sprintf(buffer, "%li", va_arg(*vargs, long)); #ifdef HAVE_LONG_LONG else if (longlongflag) - len = sprintf(buffer, fmt, + len = sprintf(buffer, "%" PY_FORMAT_LONG_LONG "i", va_arg(*vargs, PY_LONG_LONG)); #endif else if (size_tflag) - len = sprintf(buffer, fmt, + len = sprintf(buffer, "%" PY_FORMAT_SIZE_T "i", va_arg(*vargs, Py_ssize_t)); else - len = sprintf(buffer, fmt, + len = sprintf(buffer, "%i", va_arg(*vargs, int)); } assert(len >= 0); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 18 22:36:55 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 18 Nov 2014 21:36:55 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322453=3A_Removed_?= =?utf-8?q?non-documented_macro_PyObject=5FREPR=28=29=2E?= Message-ID: <20141118213642.113284.70690@psf.io> https://hg.python.org/cpython/rev/e339d75a21d5 changeset: 93504:e339d75a21d5 user: Serhiy Storchaka date: Tue Nov 18 23:34:33 2014 +0200 summary: Issue #22453: Removed non-documented macro PyObject_REPR(). files: Doc/whatsnew/3.5.rst | 4 ++++ Include/object.h | 3 --- Misc/NEWS | 2 ++ Python/compile.c | 20 ++++++++++---------- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -441,3 +441,7 @@ * The :c:type:`PyMemAllocator` structure was renamed to :c:type:`PyMemAllocatorEx` and a new ``calloc`` field was added. + +* Removed non-documented macro :c:macro:`PyObject_REPR` which leaked references. + Use format character ``%R`` in :c:func:`PyUnicode_FromFormat`-like functions + to format the :func:`repr` of the object. diff --git a/Include/object.h b/Include/object.h --- a/Include/object.h +++ b/Include/object.h @@ -575,9 +575,6 @@ PyAPI_FUNC(int) Py_ReprEnter(PyObject *); PyAPI_FUNC(void) Py_ReprLeave(PyObject *); -/* Helper for passing objects to printf and the like */ -#define PyObject_REPR(obj) _PyUnicode_AsString(PyObject_Repr(obj)) - /* Flag bits for printing: */ #define Py_PRINT_RAW 1 /* No string quotes etc. */ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1256,6 +1256,8 @@ C API ----- +- Issue #22453: Removed non-documented macro PyObject_REPR(). + - Issue #18395: Rename ``_Py_char2wchar()`` to :c:func:`Py_DecodeLocale`, rename ``_Py_wchar2char()`` to :c:func:`Py_EncodeLocale`, and document these functions. diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -1414,12 +1414,12 @@ PyOS_snprintf(buf, sizeof(buf), "unknown scope for %.100s in %.100s(%s)\n" "symbols: %s\nlocals: %s\nglobals: %s", - PyBytes_AS_STRING(name), - PyBytes_AS_STRING(c->u->u_name), - PyObject_REPR(c->u->u_ste->ste_id), - PyObject_REPR(c->u->u_ste->ste_symbols), - PyObject_REPR(c->u->u_varnames), - PyObject_REPR(c->u->u_names) + PyUnicode_AsUTF8(name), + PyUnicode_AsUTF8(c->u->u_name), + PyUnicode_AsUTF8(PyObject_Repr(c->u->u_ste->ste_id)), + PyUnicode_AsUTF8(PyObject_Repr(c->u->u_ste->ste_symbols)), + PyUnicode_AsUTF8(PyObject_Repr(c->u->u_varnames)), + PyUnicode_AsUTF8(PyObject_Repr(c->u->u_names)) ); Py_FatalError(buf); } @@ -1476,11 +1476,11 @@ fprintf(stderr, "lookup %s in %s %d %d\n" "freevars of %s: %s\n", - PyObject_REPR(name), - PyBytes_AS_STRING(c->u->u_name), + PyUnicode_AsUTF8(PyObject_Repr(name)), + PyUnicode_AsUTF8(c->u->u_name), reftype, arg, - _PyUnicode_AsString(co->co_name), - PyObject_REPR(co->co_freevars)); + PyUnicode_AsUTF8(co->co_name), + PyUnicode_AsUTF8(PyObject_Repr(co->co_freevars))); Py_FatalError("compiler_make_closure()"); } ADDOP_I(c, LOAD_CLOSURE, arg); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 18 23:17:27 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 18 Nov 2014 22:17:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Null_merge?= Message-ID: <20141118221720.113306.9958@psf.io> https://hg.python.org/cpython/rev/902dbf99fc28 changeset: 93507:902dbf99fc28 parent: 93504:e339d75a21d5 parent: 93505:342a619cdafb user: Serhiy Storchaka date: Wed Nov 19 00:13:24 2014 +0200 summary: Null merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 18 23:17:27 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 18 Nov 2014 22:17:27 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyNDUz?= =?utf-8?q?=3A_Warn_against_the_use_of_leaking_macro_PyObject=5FREPR=28=29?= =?utf-8?q?=2E?= Message-ID: <20141118221720.36061.17668@psf.io> https://hg.python.org/cpython/rev/342a619cdafb changeset: 93505:342a619cdafb branch: 3.4 parent: 93501:ab3e8aab7119 user: Serhiy Storchaka date: Wed Nov 19 00:08:38 2014 +0200 summary: Issue #22453: Warn against the use of leaking macro PyObject_REPR(). files: Include/object.h | 8 ++++++-- Python/compile.c | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/Include/object.h b/Include/object.h --- a/Include/object.h +++ b/Include/object.h @@ -572,8 +572,12 @@ PyAPI_FUNC(int) Py_ReprEnter(PyObject *); PyAPI_FUNC(void) Py_ReprLeave(PyObject *); -/* Helper for passing objects to printf and the like */ -#define PyObject_REPR(obj) _PyUnicode_AsString(PyObject_Repr(obj)) +#ifndef Py_LIMITED_API +/* Helper for passing objects to printf and the like. + Leaks refcounts. Don't use it! +*/ +#define PyObject_REPR(obj) PyUnicode_AsUTF8(PyObject_Repr(obj)) +#endif /* Flag bits for printing: */ #define Py_PRINT_RAW 1 /* No string quotes etc. */ diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -1412,12 +1412,12 @@ PyOS_snprintf(buf, sizeof(buf), "unknown scope for %.100s in %.100s(%s)\n" "symbols: %s\nlocals: %s\nglobals: %s", - PyBytes_AS_STRING(name), - PyBytes_AS_STRING(c->u->u_name), - PyObject_REPR(c->u->u_ste->ste_id), - PyObject_REPR(c->u->u_ste->ste_symbols), - PyObject_REPR(c->u->u_varnames), - PyObject_REPR(c->u->u_names) + PyUnicode_AsUTF8(name), + PyUnicode_AsUTF8(c->u->u_name), + PyUnicode_AsUTF8(PyObject_Repr(c->u->u_ste->ste_id)), + PyUnicode_AsUTF8(PyObject_Repr(c->u->u_ste->ste_symbols)), + PyUnicode_AsUTF8(PyObject_Repr(c->u->u_varnames)), + PyUnicode_AsUTF8(PyObject_Repr(c->u->u_names)) ); Py_FatalError(buf); } @@ -1474,11 +1474,11 @@ fprintf(stderr, "lookup %s in %s %d %d\n" "freevars of %s: %s\n", - PyObject_REPR(name), - PyBytes_AS_STRING(c->u->u_name), + PyUnicode_AsUTF8(PyObject_Repr(name)), + PyUnicode_AsUTF8(c->u->u_name), reftype, arg, - _PyUnicode_AsString(co->co_name), - PyObject_REPR(co->co_freevars)); + PyUnicode_AsUTF8(co->co_name), + PyUnicode_AsUTF8(PyObject_Repr(co->co_freevars))); Py_FatalError("compiler_make_closure()"); } ADDOP_I(c, LOAD_CLOSURE, arg); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 18 23:17:27 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 18 Nov 2014 22:17:27 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIyNDUz?= =?utf-8?q?=3A_Fexed_reference_leaks_when_format_error_messages_in_ceval?= =?utf-8?b?LmMu?= Message-ID: <20141118221720.62756.49480@psf.io> https://hg.python.org/cpython/rev/6e26b5291c41 changeset: 93506:6e26b5291c41 branch: 2.7 parent: 93500:eb25629d2a46 user: Serhiy Storchaka date: Wed Nov 19 00:11:05 2014 +0200 summary: Issue #22453: Fexed reference leaks when format error messages in ceval.c. Warn against the use of leaking macro PyObject_REPR(). files: Include/object.h | 4 +++- Python/ceval.c | 20 ++++++++++++++++---- Python/compile.c | 12 ++++++------ 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/Include/object.h b/Include/object.h --- a/Include/object.h +++ b/Include/object.h @@ -527,7 +527,9 @@ PyAPI_DATA(int) _Py_HashSecret_Initialized; #endif -/* Helper for passing objects to printf and the like */ +/* Helper for passing objects to printf and the like. + Leaks refcounts. Don't use it! +*/ #define PyObject_REPR(obj) PyString_AS_STRING(PyObject_Repr(obj)) /* Flag bits for printing: */ diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1957,9 +1957,13 @@ if (err == 0) continue; break; } + t = PyObject_Repr(w); + if (t == NULL) + break; PyErr_Format(PyExc_SystemError, "no locals found when storing %s", - PyObject_REPR(w)); + PyString_AS_STRING(t)); + Py_DECREF(t); break; case DELETE_NAME: @@ -1971,9 +1975,13 @@ w); break; } + t = PyObject_Repr(w); + if (t == NULL) + break; PyErr_Format(PyExc_SystemError, "no locals when deleting %s", - PyObject_REPR(w)); + PyString_AS_STRING(w)); + Py_DECREF(t); break; PREDICTED_WITH_ARG(UNPACK_SEQUENCE); @@ -2046,10 +2054,14 @@ case LOAD_NAME: w = GETITEM(names, oparg); if ((v = f->f_locals) == NULL) { + why = WHY_EXCEPTION; + t = PyObject_Repr(w); + if (t == NULL) + break; PyErr_Format(PyExc_SystemError, "no locals when loading %s", - PyObject_REPR(w)); - why = WHY_EXCEPTION; + PyString_AS_STRING(w)); + Py_DECREF(t); break; } if (PyDict_CheckExact(v)) { diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -1271,11 +1271,11 @@ "symbols: %s\nlocals: %s\nglobals: %s", PyString_AS_STRING(name), PyString_AS_STRING(c->u->u_name), - PyObject_REPR(c->u->u_ste->ste_id), + PyString_AS_STRING(PyObject_Repr(c->u->u_ste->ste_id)), c->c_filename, - PyObject_REPR(c->u->u_ste->ste_symbols), - PyObject_REPR(c->u->u_varnames), - PyObject_REPR(c->u->u_names) + PyString_AS_STRING(PyObject_Repr(c->u->u_ste->ste_symbols)), + PyString_AS_STRING(PyObject_Repr(c->u->u_varnames)), + PyString_AS_STRING(PyObject_Repr(c->u->u_names)) ); Py_FatalError(buf); } @@ -1327,11 +1327,11 @@ if (arg == -1) { printf("lookup %s in %s %d %d\n" "freevars of %s: %s\n", - PyObject_REPR(name), + PyString_AS_STRING(PyObject_Repr(name)), PyString_AS_STRING(c->u->u_name), reftype, arg, PyString_AS_STRING(co->co_name), - PyObject_REPR(co->co_freevars)); + PyString_AS_STRING(PyObject_Repr(co->co_freevars))); Py_FatalError("compiler_make_closure()"); } ADDOP_I(c, LOAD_CLOSURE, arg); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 19 00:33:44 2014 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 18 Nov 2014 23:33:44 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogQ2xvc2UgIzIyMzcw?= =?utf-8?q?=3A_Windows_detection_in_pathlib_is_now_more_robust=2E?= Message-ID: <20141118233314.13357.78035@psf.io> https://hg.python.org/cpython/rev/cb1d7eac601d changeset: 93508:cb1d7eac601d branch: 3.4 parent: 93505:342a619cdafb user: Antoine Pitrou date: Wed Nov 19 00:32:08 2014 +0100 summary: Close #22370: Windows detection in pathlib is now more robust. files: Lib/pathlib.py | 9 ++++----- Misc/NEWS | 2 ++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Lib/pathlib.py b/Lib/pathlib.py --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -15,16 +15,15 @@ supports_symlinks = True -try: +if os.name == 'nt': import nt -except ImportError: - nt = None -else: if sys.getwindowsversion()[:2] >= (6, 0): from nt import _getfinalpathname else: supports_symlinks = False _getfinalpathname = None +else: + nt = None __all__ = [ @@ -110,7 +109,7 @@ has_drv = True pathmod = ntpath - is_supported = (nt is not None) + is_supported = (os.name == 'nt') drive_letters = ( set(chr(x) for x in range(ord('a'), ord('z') + 1)) | diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,8 @@ Library ------- +- Issue #22370: Windows detection in pathlib is now more robust. + - Issue #22841: Reject coroutines in asyncio add_signal_handler(). Patch by Ludovic.Gasc. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 19 00:33:44 2014 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 18 Nov 2014 23:33:44 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Close_=2322370=3A_Windows_detection_in_pathlib_is_now_mo?= =?utf-8?q?re_robust=2E?= Message-ID: <20141118233315.36037.72921@psf.io> https://hg.python.org/cpython/rev/712f246da49b changeset: 93509:712f246da49b parent: 93507:902dbf99fc28 parent: 93508:cb1d7eac601d user: Antoine Pitrou date: Wed Nov 19 00:33:08 2014 +0100 summary: Close #22370: Windows detection in pathlib is now more robust. files: Lib/pathlib.py | 9 ++++----- Misc/NEWS | 2 ++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Lib/pathlib.py b/Lib/pathlib.py --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -15,16 +15,15 @@ supports_symlinks = True -try: +if os.name == 'nt': import nt -except ImportError: - nt = None -else: if sys.getwindowsversion()[:2] >= (6, 0): from nt import _getfinalpathname else: supports_symlinks = False _getfinalpathname = None +else: + nt = None __all__ = [ @@ -110,7 +109,7 @@ has_drv = True pathmod = ntpath - is_supported = (nt is not None) + is_supported = (os.name == 'nt') drive_letters = ( set(chr(x) for x in range(ord('a'), ord('z') + 1)) | diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -185,6 +185,8 @@ Library ------- +- Issue #22370: Windows detection in pathlib is now more robust. + - Issue #22841: Reject coroutines in asyncio add_signal_handler(). Patch by Ludovic.Gasc. -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Wed Nov 19 10:33:28 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 19 Nov 2014 10:33:28 +0100 Subject: [Python-checkins] Daily reference leaks (712f246da49b): sum=5 Message-ID: results for 712f246da49b on branch "default" -------------------------------------------- test_collections leaked [2, 0, 0] references, sum=2 test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogTFWDlr', '-x'] From python-checkins at python.org Wed Nov 19 11:36:39 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Nov 2014 10:36:39 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320604=3A_Added_missed_invalid_mode_in_error_mes?= =?utf-8?q?sage_of_socket=2Emakefile=28=29=2E?= Message-ID: <20141119103628.36045.90635@psf.io> https://hg.python.org/cpython/rev/d5b36edeecdb changeset: 93511:d5b36edeecdb parent: 93509:712f246da49b parent: 93510:34c7be03259b user: Serhiy Storchaka date: Wed Nov 19 12:34:07 2014 +0200 summary: Issue #20604: Added missed invalid mode in error message of socket.makefile(). Based on patch by Franck Michea. files: Lib/socket.py | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/socket.py b/Lib/socket.py --- a/Lib/socket.py +++ b/Lib/socket.py @@ -209,9 +209,8 @@ except the only mode characters supported are 'r', 'w' and 'b'. The semantics are similar too. (XXX refactor to share code?) """ - for c in mode: - if c not in {"r", "w", "b"}: - raise ValueError("invalid mode %r (only r, w, b allowed)") + if not set(mode) <= {"r", "w", "b"}: + raise ValueError("invalid mode %r (only r, w, b allowed)" % (mode,)) writing = "w" in mode reading = "r" in mode or not writing assert reading or writing -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 19 11:36:39 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Nov 2014 10:36:39 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIwNjA0?= =?utf-8?q?=3A_Added_missed_invalid_mode_in_error_message_of_socket=2Emake?= =?utf-8?b?ZmlsZSgpLg==?= Message-ID: <20141119103628.109146.47390@psf.io> https://hg.python.org/cpython/rev/34c7be03259b changeset: 93510:34c7be03259b branch: 3.4 parent: 93508:cb1d7eac601d user: Serhiy Storchaka date: Wed Nov 19 12:33:40 2014 +0200 summary: Issue #20604: Added missed invalid mode in error message of socket.makefile(). Based on patch by Franck Michea. files: Lib/socket.py | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/socket.py b/Lib/socket.py --- a/Lib/socket.py +++ b/Lib/socket.py @@ -201,9 +201,8 @@ except the only mode characters supported are 'r', 'w' and 'b'. The semantics are similar too. (XXX refactor to share code?) """ - for c in mode: - if c not in {"r", "w", "b"}: - raise ValueError("invalid mode %r (only r, w, b allowed)") + if not set(mode) <= {"r", "w", "b"}: + raise ValueError("invalid mode %r (only r, w, b allowed)" % (mode,)) writing = "w" in mode reading = "r" in mode or not writing assert reading or writing -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 19 12:24:41 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Nov 2014 11:24:41 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIwNzM2?= =?utf-8?q?=3A_testSendmsgDontWait_in_test=5Fsocket_no_longer_skipped_on_L?= =?utf-8?q?inux=2E?= Message-ID: <20141119112401.113284.42225@psf.io> https://hg.python.org/cpython/rev/fb06c8ccfd41 changeset: 93512:fb06c8ccfd41 branch: 3.4 parent: 93510:34c7be03259b user: Serhiy Storchaka date: Wed Nov 19 13:21:13 2014 +0200 summary: Issue #20736: testSendmsgDontWait in test_socket no longer skipped on Linux. Patch by David Watson. 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 @@ -2216,7 +2216,7 @@ # Linux supports MSG_DONTWAIT when sending, but in general, it # only works when receiving. Could add other platforms if they # support it too. - @skipWithClientIf(sys.platform not in {"linux2"}, + @skipWithClientIf(sys.platform not in {"linux"}, "MSG_DONTWAIT not known to work on this platform when " "sending") def testSendmsgDontWait(self): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 19 12:24:41 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 19 Nov 2014 11:24:41 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320736=3A_testSendmsgDontWait_in_test=5Fsocket_n?= =?utf-8?q?o_longer_skipped_on_Linux=2E?= Message-ID: <20141119112401.62748.68851@psf.io> https://hg.python.org/cpython/rev/23ab1197df0b changeset: 93513:23ab1197df0b parent: 93511:d5b36edeecdb parent: 93512:fb06c8ccfd41 user: Serhiy Storchaka date: Wed Nov 19 13:21:40 2014 +0200 summary: Issue #20736: testSendmsgDontWait in test_socket no longer skipped on Linux. Patch by David Watson. 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 @@ -2221,7 +2221,7 @@ # Linux supports MSG_DONTWAIT when sending, but in general, it # only works when receiving. Could add other platforms if they # support it too. - @skipWithClientIf(sys.platform not in {"linux2"}, + @skipWithClientIf(sys.platform not in {"linux"}, "MSG_DONTWAIT not known to work on this platform when " "sending") def testSendmsgDontWait(self): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 19 12:35:29 2014 From: python-checkins at python.org (nick.coghlan) Date: Wed, 19 Nov 2014 11:35:29 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_458=3A_remove_Windows_lin?= =?utf-8?q?e_endings?= Message-ID: <20141119113452.109164.4115@psf.io> https://hg.python.org/peps/rev/e467ef442506 changeset: 5601:e467ef442506 user: Nick Coghlan date: Wed Nov 19 21:34:40 2014 +1000 summary: PEP 458: remove Windows line endings files: pep-0458.txt | 2166 +++++++++++++++++++------------------- 1 files changed, 1083 insertions(+), 1083 deletions(-) diff --git a/pep-0458.txt b/pep-0458.txt --- a/pep-0458.txt +++ b/pep-0458.txt @@ -1,1083 +1,1083 @@ -PEP: 458 -Title: Surviving a Compromise of PyPI -Version: $Revision$ -Last-Modified: $Date$ -Author: Trishank Karthik Kuppusamy , - Donald Stufft , - Justin Cappos -Discussions-To: Distutils SIG -Status: Draft -Type: Standards Track -Content-Type: text/x-rst -Created: 27-Sep-2013 - - -Abstract -======== - -This PEP describes how the Python Package Index (PyPI [1]_) may be integrated -with The Update Framework [2]_ (TUF). TUF was designed to be a plug-and-play -security add-on to a software updater or package manager. TUF provides -end-to-end security like SSL, but for software updates instead of HTTP -connections. The framework integrates best security practices such as -separating responsibilities, adopting the many-man rule for signing packages, -keeping signing keys offline, and revocation of expired or compromised signing -keys. - -The proposed integration will render modern package managers such as pip [3]_ -more secure against various types of security attacks on PyPI and protect users -against them. Even in the worst case where an attacker manages to compromise -PyPI itself, the damage is controlled in scope and limited in duration. - -Specifically, this PEP will describe how PyPI processes should be adapted to -incorporate TUF metadata. It will not prescribe how package managers such as -pip should be adapted to install or update with TUF metadata projects from -PyPI. - - -Rationale -========= - -In January 2013, the Python Software Foundation (PSF) announced [4]_ that the -python.org wikis for Python, Jython, and the PSF were subjected to a security -breach which caused all of the wiki data to be destroyed on January 5 2013. -Fortunately, the PyPI infrastructure was not affected by this security breach. -However, the incident is a reminder that PyPI should take defensive steps to -protect users as much as possible in the event of a compromise. Attacks on -software repositories happen all the time [5]_. We must accept the possibility -of security breaches and prepare PyPI accordingly because it is a valuable -target used by thousands, if not millions, of people. - -Before the wiki attack, PyPI used MD5 hashes to tell package managers such as -pip whether or not a package was corrupted in transit. However, the absence of -SSL made it hard for package managers to verify transport integrity to PyPI. -It was easy to launch a man-in-the-middle attack between pip and PyPI to change -package contents arbitrarily. This can be used to trick users into installing -malicious packages. After the wiki attack, several steps were proposed (some -of which were implemented) to deliver a much higher level of security than was -previously the case: requiring SSL to communicate with PyPI [6]_, restricting -project names [7]_, and migrating from MD5 to SHA-2 hashes [8]_. - -These steps, though necessary, are insufficient because attacks are still -possible through other avenues. For example, a public mirror is trusted to -honestly mirror PyPI, but some mirrors may misbehave due to malice or accident. -Package managers such as pip are supposed to use signatures from PyPI to verify -packages downloaded from a public mirror [9]_, but none are known to actually -do so [10]_. Therefore, it is also wise to add more security measures to -detect attacks from public mirrors or content delivery networks [11]_ (CDNs). - -Even though official mirrors are being deprecated on PyPI [12]_, there remain a -wide variety of other attack vectors on package managers [13]_. Among other -things, these attacks can crash client systems, cause obsolete packages to be -installed, or even allow an attacker to execute arbitrary code. In September -2013, we showed how the latest version of pip then was susceptible to these -attacks and how TUF could protect users against them [14]_. - -Finally, PyPI allows for packages to be signed with GPG keys [15]_, although no -package manager is known to verify those signatures, thus negating much of the -benefits of having those signatures at all. Validating integrity through -cryptography is important, but issues such as immediate and secure key -revocation or specifying a required threshold number of signatures still -remain. Furthermore, GPG by itself does not immediately address the attacks -mentioned above. - -In order to protect PyPI against infrastructure compromises, we propose -integrating PyPI with The Update Framework [2]_ (TUF). - - -Definitions -=========== - -The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", -"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be -interpreted as described in RFC 2119__. - -__ http://www.ietf.org/rfc/rfc2119.txt - -In order to keep this PEP focused solely on the application of TUF on PyPI, the -reader is assumed to already be familiar with the design principles of -TUF [2]_. It is also strongly RECOMMENDED that the reader be familiar with the -TUF specification [16]_. - -* Projects: Projects are software components that are made available for - integration. Projects include Python libraries, frameworks, scripts, plugins, - applications, collections of data or other resources, and various - combinations thereof. Public Python projects are typically registered on the - Python Package Index [17]_. - -* Releases: Releases are uniquely identified snapshots of a project [17]_. - -* Distributions: Distributions are the packaged files which are used to publish - and distribute a release [17]_. - -* Simple index: The HTML page which contains internal links to the - distributions of a project [17]_. - -* Consistent snapshot: A set of TUF metadata and PyPI targets that capture the - complete state of all projects on PyPI as they were at some fixed point in - time. - -* The *consistent-snapshot* (*release*) role: In order to prevent confusion due - to the different meanings of the term "release" as employed by PEP 426 [17]_ - and the TUF specification [16]_, we rename the *release* role as the - *consistent-snapshot* role. - -* Continuous delivery: A set of processes with which PyPI produces consistent - snapshots that can safely coexist and deleted independently [18]_. - -* Developer: Either the owner or maintainer of a project who is allowed to - update the TUF metadata as well as distribution metadata and data for the - project. - -* Online key: A key that MUST be stored on the PyPI server infrastructure. - This is usually to allow automated signing with the key. However, this means - that an attacker who compromises PyPI infrastructure will be able to read - these keys. - -* Offline key: A key that MUST be stored off the PyPI infrastructure. This - prevents automated signing with the key. This means that an attacker who - compromises PyPI infrastructure will not be able to immediately read these - keys. - -* Developer key: A private key for which its corresponding public key is - registered with PyPI to say that it is responsible for directly signing for - or delegating the distributions belonging to a project. For the purposes of - this PEP, it is offline in the sense that the private key MUST not be stored - on PyPI. However, the project is free to require certain developer keys to - be online on its own infrastructure. - -* Threshold signature scheme: A role could increase its resilience to key - compromises by requiring that at least t out of n keys are REQUIRED to sign - its metadata. This means that a compromise of t-1 keys is insufficient to - compromise the role itself. We denote this property by saying that the role - requires (t, n) keys. - - -Overview -======== - -.. image:: https://raw.github.com/theupdateframework/pep-on-pypi-with-tuf/master/figure1.png - -Figure 1: A simplified overview of the roles in PyPI with TUF - -Figure 1 shows a simplified overview of the roles that TUF metadata assume on -PyPI. The top-level *root* role signs for the keys of the top-level -*timestamp*, *consistent-snapshot*, *targets* and *root* roles. The -*timestamp* role signs for a new and consistent snapshot. The *consistent- -snapshot* role signs for the *root*, *targets* and all delegated targets -metadata. The *claimed* role signs for all projects that have registered their -own developer keys with PyPI. The *recently-claimed* role signs for all -projects that recently registered their own developer keys with PyPI. Finally, -the *unclaimed* role signs for all projects that have not registered developer -keys with PyPI. The *claimed*, *recently-claimed* and *unclaimed* roles are -numbered 1, 2, 3 respectively because a project will be searched for in each of -those roles in that descending order: first in *claimed*, then in -*recently-claimed* if necessary, and finally in *unclaimed* if necessary. - -Every year, PyPI administrators are going to sign for *root* role keys. After -that, automation will continuously sign for a timestamped, consistent snapshot -of all projects. Every few months, PyPI administrators will move projects with -vetted developer keys from the *recently-claimed* role to the *claimed* role. -As we will soon see, they will sign for *claimed* with projects with offline -keys. - -This PEP does not require project developers to use TUF to secure their -packages from attacks on PyPI. By default, all projects will be signed for by -the *unclaimed* role. If a project wishes stronger security guarantees, then -the project is strongly RECOMMENDED to register developer keys with PyPI so -that it may sign for its own distributions. By doing so, the project must -remain as a *recently-claimed* project until PyPI administrators have had an -opportunity to vet the developer keys of the project, after which the project -will be moved to the *claimed* role. - -This PEP has **not** been designed to be backward-compatible for package -managers that do not use the TUF security protocol to install or update a -project from the PyPI described here. Instead, it is RECOMMENDED that PyPI -maintain a backward-compatible API of itself that does NOT offer TUF so that -older package managers that do not use TUF will be able to install or update -projects from PyPI as usual but without any of the security offered by TUF. -For the rest of this PEP, we will assume that PyPI will simultaneously maintain -a backward-incompatible API of itself for package managers that MUST use TUF to -securely install or update projects. We think that this approach represents a -reasonable trade-off: older package managers that do not TUF will still be able -to install or update projects without any TUF security from PyPI, and newer -package managers that do use TUF will be able to securely install or update -projects. At some point in the future, PyPI administrators MAY choose to -permanently deprecate the backward-compatible version of itself that does not -offer TUF metadata. - -Unless a mirror, CDN or the PyPI repository has been compromised, the end-user -will not be able to discern whether or not a package manager is using TUF to -install or update a project from PyPI. - - -Responsibility Separation -========================= - -Recall that TUF requires four top-level roles: *root*, *timestamp*, -*consistent-snapshot* and *targets*. The *root* role specifies the keys of all -the top-level roles (including itself). The *timestamp* role specifies the -latest consistent snapshot. The *consistent-snapshot* role specifies the -latest versions of all TUF metadata files (other than *timestamp*). The -*targets* role specifies available target files (in our case, it will be all -files on PyPI under the /simple and /packages directories). In this PEP, each -of these roles will serve their responsibilities without exception. - -Our proposal offers two levels of security to developers. If developers opt in -to secure their projects with their own developer keys, then their projects -will be very secure. Otherwise, TUF will still protect them in many cases: - -1. Minimum security (no action by a developer): protects *unclaimed* and - *recently-claimed* projects without developer keys from CDNs [19]_ or public - mirrors, but not from some PyPI compromises. This is because continuous - delivery requires some keys to be online. This level of security protects - projects from being accidentally or deliberately tampered with by a mirror - or a CDN because the mirror or CDN will not have any of the PyPI or - developer keys required to sign for projects. However, it would not protect - projects from attackers who have compromised PyPI because they will be able - to manipulate the TUF metadata for *unclaimed* projects with the appropriate - online keys. - -2. Maximum security (developer signs their project): protects projects with - developer keys not only from CDNs or public mirrors, but also from some PyPI - compromises. This is because many important keys will be offline. This - level of security protects projects from being accidentally or deliberately - tampered with by a mirror or a CDN for reasons identical to the minimum - security level. It will also protect projects (or at least mitigate - damages) from the most likely attacks on PyPI. For example: given access to - online keys after a PyPI compromise, attackers will be able to freeze the - distributions for these projects, but they will not be able to serve - malicious distributions for these projects (not without compromising other - offline keys which would entail more risk, time and energy). Details for - the exact level of security offered is discussed in the section on key - management. - -In order to complete support for continuous delivery, we propose three -delegated targets roles: - -1. *claimed*: Signs for the delegation of PyPI projects to their respective - developer keys. - -2. *recently-claimed*: This role is almost identical to the *claimed* role and - could technically be performed by the *unclaimed* role, but there are two - important reasons why it exists independently: the first reason is to - improve the performance of looking up projects in the *unclaimed* role (by - moving metadata to the *recently-claimed* role instead), and the second - reason is to make it easier for PyPI administrators to move - *recently-claimed* projects to the *claimed* role. - -3. *unclaimed*: Signs for PyPI projects without developer keys. - -The *targets* role MUST delegate all PyPI projects to the three delegated -targets roles in the order of appearance listed above. This means that when -pip downloads with TUF a distribution from a project on PyPI, it will first -consult the *claimed* role about it. If the *claimed* role has delegated the -project, then pip will trust the project developers (in order of delegation) -about the TUF metadata for the project. Otherwise, pip will consult the -*recently-claimed* role about the project. If the *recently-claimed* role has -delegated the project, then pip will trust the project developers (in order of -delegation) about the TUF metadata for the project. Otherwise, pip will -consult the *unclaimed* role about the TUF metadata for the project. If the -*unclaimed* role has not delegated the project, then the project is considered -to be non-existent on PyPI. - -A PyPI project MAY begin without registering a developer key. Therefore, the -project will be signed for by the *unclaimed* role. After registering -developer keys, the project will be removed from the *unclaimed* role and -delegated to the *recently-claimed* role. After a probation period and a -vetting process to verify the developer keys of the project, the project will -be removed from the *recently-claimed* role and delegated to the *claimed* -role. - -The *claimed* role offers maximum security, whereas the *recently-claimed* and -*unclaimed* role offer minimum security. All three roles support continuous -delivery of PyPI projects. - -The *unclaimed* role offers minimum security because PyPI will sign for -projects without developer keys with an online key in order to permit -continuous delivery. - -The *recently-claimed* role offers minimum security because while the project -developers will sign for their own distributions with offline developer keys, -PyPI will sign with an online key the delegation of the project to those -offline developer keys. The signing of the delegation with an online key -allows PyPI administrators to continuously deliver projects without having to -continuously sign the delegation whenever one of those projects registers -developer keys. - -Finally, the *claimed* role offers maximum security because PyPI will sign with -offline keys the delegation of a project to its offline developer keys. This -means that every now and then, PyPI administrators will vet developer keys and -sign the delegation of a project to those developer keys after being reasonably -sure about the ownership of the developer keys. The process for vetting -developer keys is out of the scope of this PEP. - - -Metadata Management -=================== - -In this section, we examine the TUF metadata that PyPI must manage by itself, -and other TUF metadata that must be safely delegated to projects. Examples of -the metadata described here may be seen at our testbed mirror of -`PyPI-with-TUF`__. - -__ http://mirror1.poly.edu/ - -The metadata files that change most frequently will be *timestamp*, -*consistent-snapshot* and delegated targets (*claimed*, *recently-claimed*, -*unclaimed*, project) metadata. The *timestamp* and *consistent-snapshot* -metadata MUST be updated whenever *root*, *targets* or delegated targets -metadata are updated. Observe, though, that *root* and *targets* metadata are -much less likely to be updated as often as delegated targets metadata. -Therefore, *timestamp* and *consistent-snapshot* metadata will most likely be -updated frequently (possibly every minute) due to delegated targets metadata -being updated frequently in order to drive continuous delivery of projects. - -Consequently, the processes with which PyPI updates projects will have to be -updated accordingly, the details of which are explained in the following -subsections. - - -Why Do We Need Consistent Snapshots? ------------------------------------- - -In an ideal world, metadata and data should be immediately updated and -presented whenever a project is updated. In practice, there will be problems -when there are many readers and writers who access the same metadata or data at -the same time. - -An important example at the time of writing is that, mirrors are very likely, -as far as we can tell, to update in an inconsistent manner from PyPI as it is -without TUF. Specifically, a mirror would update itself in such a way that -project A would be from time T, whereas project B would be from time T+5, -project C would be from time T+3, and so on where T is the time that the mirror -first begun updating itself. There is no known way for a mirror to update -itself such that it captures the state of all projects as they were at time T. - -Adding TUF to PyPI will not automatically solve the problem. Consider what we -call the `"inverse replay" or "fast-forward" problem`__. Suppose that PyPI has -timestamped a consistent snapshot at version 1. A mirror is later in the -middle of copying PyPI at this snapshot. While the mirror is copying PyPI at -this snapshot, PyPI timestamps a new snapshot at, say, version 2. Without -accounting for consistency, the mirror would then find itself with a copy of -PyPI in an inconsistent state which is indistinguishable from arbitrary -metadata or target attacks. The problem would also apply when the mirror is -substituted with a pip user. - -__ https://groups.google.com/forum/#!topic/theupdateframework/8mkR9iqivQA - -Therefore, the problem can be summarized as such: there are problems of -consistency on PyPI with or without TUF. TUF requires its metadata to be -consistent with the data, but how would the metadata be kept consistent with -projects that change all the time? - -As a result, we will solve for PyPI the problem of producing a consistent -snapshot that captures the state of all known projects at a given time. Each -consistent snapshot can safely coexist with any other consistent snapshot and -deleted independently without affecting any other consistent snapshot. - -The gist of the solution is that every metadata or data file written to disk -MUST include in its filename the `cryptographic hash`__ of the file. How would -this help clients which use the TUF protocol to securely and consistently -install or update a project from PyPI? - -__ https://en.wikipedia.org/wiki/Cryptographic_hash_function - -Recall that the first step in the TUF protocol requires the client to download -the latest *timestamp* metadata. However, the client would not know in advance -the hash of the *timestamp* metadata file from the latest consistent snapshot. -Therefore, PyPI MUST redirect all HTTP GET requests for *timestamp* metadata to -the *timestamp* metadata file from the latest consistent snapshot. Since the -*timestamp* metadata is the root of a tree of cryptographic hashes pointing to -every other metadata or target file that are meant to exist together for -consistency, the client is then able to retrieve any file from this consistent -snapshot by deterministically including, in the request for the file, the hash -of the file in the filename. Assuming infinite disk space and no `hash -collisions`__, a client may safely read from one consistent snapshot while PyPI -produces another consistent snapshot. - -__ https://en.wikipedia.org/wiki/Collision_(computer_science) - -In this simple but effective manner, we are able to capture a consistent -snapshot of all projects and the associated metadata at a given time. The next -subsection will explicate the implementation details of this idea. - - -Producing Consistent Snapshots ------------------------------- - -Given a project, PyPI is responsible for updating, depending on the project, -either the *claimed*, *recently-claimed* or *unclaimed* metadata as well as -associated delegated targets metadata. Every project MUST upload its set of -metadata and targets in a single transaction. We will call this set of files -the project transaction. We will discuss later how PyPI MAY validate the files -in a project transaction. For now, let us focus on how PyPI will respond to a -project transaction. We will call this response the project transaction -process. There will also be a consistent snapshot process that we will define -momentarily; for now, it suffices to know that project transaction processes -and the consistent snapshot process must coordinate with each other. - -Also, every metadata and target file MUST include in its filename the `hex -digest`__ of its `SHA-256`__ hash. For this PEP, it is RECOMMENDED that PyPI -adopt a simple convention of the form filename.digest.ext, where filename is -the original filename without a copy of the hash, digest is the hex digest of -the hash, and ext is the filename extension. - -__ http://docs.python.org/2/library/hashlib.html#hashlib.hash.hexdigest -__ https://en.wikipedia.org/wiki/SHA-2 - -When an *unclaimed* project uploads a new transaction, a project transaction -process MUST add all new targets and relevant delegated *unclaimed* metadata. -(We will see later in this section why the *unclaimed* role will delegate -targets to a number of delegated *unclaimed* roles.) Finally, the project -transaction process MUST inform the consistent snapshot process about new -delegated *unclaimed* metadata. - -When a *recently-claimed* project uploads a new a transaction, a project -transaction process MUST add all new targets and delegated targets metadata for -the project. If the project is new, then the project transaction process MUST -also add new *recently-claimed* metadata with public keys and threshold number -(which MUST be part of the transaction) for the project. Finally, the project -transaction process MUST inform the consistent snapshot process about new -*recently-claimed* metadata as well as the current set of delegated targets -metadata for the project. - -The process for a *claimed* project is slightly different. The difference is -that PyPI administrators will choose to move the project from the -*recently-claimed* role to the *claimed* role. A project transaction process -MUST then add new *recently-claimed* and *claimed* metadata to reflect this -migration. As is the case for a *recently-claimed* project, the project -transaction process MUST always add all new targets and delegated targets -metadata for the *claimed* project. Finally, the project transaction process -MUST inform the consistent snapshot process about new *recently-claimed* or -*claimed* metadata as well as the current set of delegated targets metadata for -the project. - -Project transaction processes SHOULD be automated, except when PyPI -administrators move a project from the *recently-claimed* role to the *claimed* -role. Project transaction processes MUST also be applied atomically: either -all metadata and targets, or none of them, are added. The project transaction -processes and consistent snapshot process SHOULD work concurrently. Finally, -project transaction processes SHOULD keep in memory the latest *claimed*, -*recently-claimed* and *unclaimed* metadata so that they will be correctly -updated in new consistent snapshots. - -All project transactions MAY be placed in a single queue and processed -serially. Alternatively, the queue MAY be processed concurrently in order of -appearance provided that the following rules are observed: - -1. No pair of project transaction processes must concurrently work on the same - project. - -2. No pair of project transaction processes must concurrently work on - *unclaimed* projects that belong to the same delegated *unclaimed* targets - role. - -3. No pair of project transaction processes must concurrently work on new - *recently-claimed* projects. - -4. No pair of project transaction processes must concurrently work on new - *claimed* projects. - -5. No project transaction process must work on a new *claimed* project while - another project transaction process is working on a new *recently-claimed* - project and vice versa. - -These rules MUST be observed so that metadata is not read from or written to -inconsistently. - -The consistent snapshot process is fairly simple and SHOULD be automated. The -consistent snapshot process MUST keep in memory the latest working set of -*root*, *targets* and delegated targets metadata. Every minute or so, the -consistent snapshot process will sign for this latest working set. (Recall -that project transaction processes continuously inform the consistent snapshot -process about the latest delegated targets metadata in a concurrency-safe -manner. The consistent snapshot process will actually sign for a copy of the -latest working set while the actual latest working set in memory will be -updated with information continuously communicated by project transaction -processes.) Next, the consistent snapshot process MUST generate and sign new -*timestamp* metadata that will vouch for the *consistent-snapshot* metadata -generated in the previous step. Finally, the consistent snapshot process MUST -add new *timestamp* and *consistent-snapshot* metadata representing the latest -consistent snapshot. - -A few implementation notes are now in order. So far, we have seen only that -new metadata and targets are added, but not that old metadata and targets are -removed. Practical constraints are such that eventually PyPI will run out of -disk space to produce a new consistent snapshot. In that case, PyPI MAY then -use something like a "mark-and-sweep" algorithm to delete sufficiently old -consistent snapshots: in order to preserve the latest consistent snapshot, PyPI -would walk objects beginning from the root (*timestamp*) of the latest -consistent snapshot, mark all visited objects, and delete all unmarked -objects. The last few consistent snapshots may be preserved in a similar -fashion. Deleting a consistent snapshot will cause clients to see nothing -thereafter but HTTP 404 responses to any request for a file in that consistent -snapshot. Clients SHOULD then retry their requests with the latest consistent -snapshot. - -We do **not** consider updates to any consistent snapshot because `hash -collisions`__ are out of the scope of this PEP. In case a hash collision is -observed, PyPI MAY wish to check that the file being added is identical to the -file already stored. (Should a hash collision be observed, it is far more -likely the case that the file is identical rather than being a genuine -`collision attack`__.) Otherwise, PyPI MAY either overwrite the existing file -or ignore any write operation to an existing file. - -__ https://en.wikipedia.org/wiki/Collision_(computer_science) -__ https://en.wikipedia.org/wiki/Collision_attack - -All clients, such as pip using the TUF protocol, MUST be modified to download -every metadata and target file (except for *timestamp* metadata) by including, -in the request for the file, the hash of the file in the filename. Following -the filename convention recommended earlier, a request for the file at -filename.ext will be transformed to the equivalent request for the file at -filename.digest.ext. - -Finally, PyPI SHOULD use a `transaction log`__ to record project transaction -processes and queues so that it will be easier to recover from errors after a -server failure. - -__ https://en.wikipedia.org/wiki/Transaction_log - - -Metadata Validation -------------------- - -A *claimed* or *recently-claimed* project will need to upload in its -transaction to PyPI not just targets (a simple index as well as distributions) -but also TUF metadata. The project MAY do so by uploading a ZIP file -containing two directories, /metadata/ (containing delegated targets metadata -files) and /targets/ (containing targets such as the project simple index and -distributions which are signed for by the delegated targets metadata). - -Whenever the project uploads metadata or targets to PyPI, PyPI SHOULD check the -project TUF metadata for at least the following properties: - -* A threshold number of the developers keys registered with PyPI by that - project MUST have signed for the delegated targets metadata file that - represents the "root" of targets for that project (e.g. metadata/targets/ - project.txt). - -* The signatures of delegated targets metadata files MUST be valid. - -* The delegated targets metadata files MUST NOT be expired. - -* The delegated targets metadata MUST be consistent with the targets. - -* A delegator MUST NOT delegate targets that were not delegated to itself by - another delegator. - -* A delegatee MUST NOT sign for targets that were not delegated to itself by a - delegator. - -* Every file MUST contain a unique copy of its hash in its filename following - the filename.digest.ext convention recommended earlier. - -If PyPI chooses to check the project TUF metadata, then PyPI MAY choose to -reject publishing any set of metadata or targets that do not meet these -requirements. - -PyPI MUST enforce access control by ensuring that each project can only write -to the TUF metadata for which it is responsible. It MUST do so by ensuring -that project transaction processes write to the correct metadata as well as -correct locations within those metadata. For example, a project transaction -process for an *unclaimed* project MUST write to the correct target paths in -the correct delegated *unclaimed* metadata for the targets of the project. - -On rare occasions, PyPI MAY wish to extend the TUF metadata format for projects -in a backward-incompatible manner. Note that PyPI will NOT be able to -automatically rewrite existing TUF metadata on behalf of projects in order to -upgrade the metadata to the new backward-incompatible format because this would -invalidate the signatures of the metadata as signed by developer keys. -Instead, package managers SHOULD be written to recognize and handle multiple -incompatible versions of TUF metadata so that *claimed* and *recently-claimed* -projects could be offered a reasonable time to migrate their metadata to newer -but backward-incompatible formats. - -The details of how each project manages its TUF metadata is beyond the scope of -this PEP. - - -Mirroring Protocol ------------------- - -The mirroring protocol as described in PEP 381 [9]_ SHOULD change to mirror -PyPI with TUF. - -A mirror SHOULD have to maintain for its clients only one consistent snapshot -which would represent the latest consistent snapshot from PyPI known to the -mirror. The mirror would then serve all HTTP requests for metadata or targets -by simply reading directly from this consistent snapshot directory. - -The mirroring protocol itself is fairly simple. The mirror would ask PyPI for -*timestamp* metadata from the latest consistent snapshot and proceed to copy -the entire consistent snapshot from the *timestamp* metadata onwards. If the -mirror encounters a failure to copy any metadata or target file while copying -the consistent snapshot, it SHOULD retrying resuming the copy of that -particular consistent snapshot. If PyPI has deleted that consistent snapshot, -then the mirror SHOULD delete the failed consistent snapshot and try -downloading the latest consistent snapshot instead. - -The mirror SHOULD point users to a previous consistent snapshot directory while -it is copying the latest consistent snapshot from PyPI. Only after the latest -consistent snapshot has been completely copied SHOULD the mirror switch clients -to the latest consistent snapshot. The mirror MAY then delete the previous -consistent snapshot once it finds that no client is reading from the previous -consistent snapshot. - -The mirror MAY use extant file transfer software such as rsync__ to mirror -PyPI. In that case, the mirror MUST first obtain the latest known timestamp -metadata from PyPI. The mirror MUST NOT immediately publish the latest known -timestamp metadata from PyPI. Instead, the mirror MUST first iteratively -transfer all new files from PyPI until there are no new files left to transfer. -Finally, the mirror MUST publish the latest known timestamp it fetched from -PyPI so that package managers such as pip may be directed to the latest -consistent snapshot known to the mirror. - -__ https://rsync.samba.org/ - - -Backup Process --------------- - -In order to be able to safely restore from static snapshots later in the event -of a compromise, PyPI SHOULD maintain a small number of its own mirrors to copy -PyPI consistent snapshots according to some schedule. The mirroring protocol -can be used immediately for this purpose. The mirrors must be secured and -isolated such that they are responsible only for mirroring PyPI. The mirrors -can be checked against one another to detect accidental or malicious failures. - - -Metadata Expiry Times ---------------------- - -The *root* and *targets* role metadata SHOULD expire in a year, because these -metadata files are expected to change very rarely. - -The *claimed* role metadata SHOULD expire in three to six months, because this -metadata is expected to be refreshed in that time frame. This time frame was -chosen to induce an easier administration process for PyPI. - -The *timestamp*, *consistent-snapshot*, *recently-claimed* and *unclaimed* role -metadata SHOULD expire in a day because a CDN or mirror SHOULD synchronize -itself with PyPI every day. Furthermore, this generous time frame also takes -into account client clocks that are highly skewed or adrift. - -The expiry times for the delegated targets metadata of a project is beyond the -scope of this PEP. - - -Metadata Scalability --------------------- - -Due to the growing number of projects and distributions, the TUF metadata will -also grow correspondingly. - -For example, consider the *unclaimed* role. In August 2013, we found that the -size of the *unclaimed* role metadata was about 42MB if the *unclaimed* role -itself signed for about 220K PyPI targets (which are simple indices and -distributions). We will not delve into details in this PEP, but TUF features a -so-called "`lazy bin walk`__" scheme which splits a large targets or delegated -targets metadata file into many small ones. This allows a TUF client updater -to intelligently download only a small number of TUF metadata files in order to -update any project signed for by the *unclaimed* role. For example, applying -this scheme to the previous repository resulted in pip downloading between -1.3KB and 111KB to install or upgrade a PyPI project via TUF. - -__ https://github.com/theupdateframework/tuf/issues/39 - -From our findings as of the time of writing, PyPI SHOULD split all targets in -the *unclaimed* role by delegating it to 1024 delegated targets role, each of -which would sign for PyPI targets whose hashes fall into that "bin" or -delegated targets role. We found that 1024 bins would result in the -*unclaimed* role metadata and each of its binned delegated targets role -metadata to be about the same size (40-50KB) for about 220K PyPI targets -(simple indices and distributions). - -It is possible to make the TUF metadata more compact by representing it in a -binary format as opposed to the JSON text format. Nevertheless, we believe -that a sufficiently large number of project and distributions will induce -scalability challenges at some point, and therefore the *unclaimed* role will -then still need delegations in order to address the problem. Furthermore, the -JSON format is an open and well-known standard for data interchange. - -Due to the large number of delegated target metadata files, compressed versions -of *consistent-snapshot* metadata SHOULD also be made available. - - -Key Management -============== - -In this section, we examine the kind of keys required to sign for TUF roles on -PyPI. TUF is agnostic with respect to choices of digital signature algorithms. -For the purpose of discussion, we will assume that most digital signatures will -be produced with the well-tested and tried RSA algorithm [20]_. Nevertheless, -we do NOT recommend any particular digital signature algorithm in this PEP -because there are a few important constraints: firstly, cryptography changes -over time; secondly, package managers such as pip may wish to perform signature -verification in Python, without resorting to a compiled C library, in order to -be able to run on as many systems as Python supports; finally, TUF recommends -diversity of keys for certain applications, and we will soon discuss these -exceptions. - - -Number Of Keys --------------- - -The *timestamp*, *consistent-snapshot*, *recently-claimed* and *unclaimed* -roles will need to support continuous delivery. Even though their respective -keys will then need to be online, we will require that the keys be independent -of each other. This allows for each of the keys to be placed on separate -servers if need be, and prevents side channel attacks that compromise one key -from automatically compromising the rest of the keys. Therefore, each of the -*timestamp*, *consistent-snapshot*, *recently-claimed* and *unclaimed* roles -MUST require (1, 1) keys. - -The *unclaimed* role MAY delegate targets in an automated manner to a number of -roles called "bins", as we discussed in the previous section. Each of the -"bin" roles SHOULD share the same key as the *unclaimed* role, due -simultaneously to space efficiency of metadata and because there is no security -advantage in requiring separate keys. - -The *root* role is critical for security and should very rarely be used. It is -primarily used for key revocation, and it is the root of trust for all of PyPI. -The *root* role signs for the keys that are authorized for each of the -top-level roles (including itself). The keys belonging to the *root* role are -intended to be very well-protected and used with the least frequency of all -keys. We propose that every PSF board member own a (strong) root key. A -majority of them can then constitute the quorum to revoke or endow trust in all -top-level keys. Alternatively, the system administrators of PyPI (instead of -PSF board members) could be responsible for signing for the *root* role. -Therefore, the *root* role SHOULD require (t, n) keys, where n is the number of -either all PyPI administrators or all PSF board members, and t > 1 (so that at -least two members must sign the *root* role). - -The *targets* role will be used only to sign for the static delegation of all -targets to the *claimed*, *recently-claimed* and *unclaimed* roles. Since -these target delegations must be secured against attacks in the event of a -compromise, the keys for the *targets* role MUST be offline and independent -from other keys. For simplicity of key management without sacrificing -security, it is RECOMMENDED that the keys of the *targets* role are permanently -discarded as soon as they have been created and used to sign for the role. -Therefore, the *targets* role SHOULD require (1, 1) keys. Again, this is -because the keys are going to be permanently discarded, and more offline keys -will not help against key recovery attacks [21]_ unless diversity of keys is -maintained. - -Similarly, the *claimed* role will be used only to sign for the dynamic -delegation of projects to their respective developer keys. Since these target -delegations must be secured against attacks in the event of a compromise, the -keys for the *claimed* role MUST be offline and independent from other keys. -Therefore, the *claimed* role SHOULD require (t, n) keys, where n is the number -of all PyPI administrators (in order to keep it manageable), and t ? 1 (so that -at least one member MUST sign the *claimed* role). While a stronger threshold -would indeed render the role more robust against a compromise of the *claimed* -keys (which is highly unlikely assuming that the keys are independent and -securely kept offline), we think that this trade-off is acceptable for the -important purpose of keeping the maintenance overhead for PyPI administrators -as little as possible. At the time of writing, we are keeping this point open -for discussion by the distutils-sig community. - -The number of developer keys is project-specific and thus beyond the scope of -this PEP. - - -Online and Offline Keys ------------------------ - -In order to support continuous delivery, the *timestamp*, -*consistent-snapshot*, *recently-claimed* and *unclaimed* role keys MUST be -online. - -As explained in the previous section, the *root*, *targets* and *claimed* role -keys MUST be offline for maximum security. Developers keys will be offline in -the sense that the private keys MUST NOT be stored on PyPI, though some of them -may be online on the private infrastructure of the project. - - -Key Strength ------------- - -At the time of writing, we recommend that all RSA keys (both offline and -online) SHOULD have a minimum key size of 3072 bits for data-protection -lifetimes beyond 2030 [22]_. - - -Diversity Of Keys ------------------ - -Due to the threats of weak key generation and implementation weaknesses [2]_, -the types of keys as well as the libraries used to generate them should vary -within TUF on PyPI. Our current implementation of TUF supports multiple -digital signature algorithms such as RSA (with OpenSSL [23]_ or PyCrypto [24]_) -and ed25519 [25]_. Furthermore, TUF supports the binding of other -cryptographic libraries that it does not immediately support "out of the box", -and so one MAY generate keys using other cryptographic libraries and use them -for TUF on PyPI. - -As such, the root role keys SHOULD be generated by a variety of digital -signature algorithms as implemented by different cryptographic libraries. - - -Key Compromise Analysis ------------------------ - -.. image:: https://raw.github.com/theupdateframework/pep-on-pypi-with-tuf/master/table1.png - -Table 1: Attacks possible by compromising certain combinations of role keys - - -Table 1 summarizes the kinds of attacks rendered possible by compromising a -threshold number of keys belonging to the TUF roles on PyPI. Except for the -*timestamp* and *consistent-snapshot* roles, the pairwise interaction of role -compromises may be found by taking the union of both rows. - -In September 2013, we showed how the latest version of pip then was susceptible -to these attacks and how TUF could protect users against them [14]_. - -An attacker who compromises developer keys for a project and who is able to -somehow upload malicious metadata and targets to PyPI will be able to serve -malicious updates to users of that project (and that project alone). Note that -compromising *targets* or any delegated targets role (except for project -targets metadata) does not immediately endow the attacker with the ability to -serve malicious updates. The attacker must also compromise the *timestamp* and -*consistent-snapshot* roles (which are both online and therefore more likely to -be compromised). This means that in order to launch any attack, one must be -not only be able to act as a man-in-the-middle but also compromise the -*timestamp* key (or the *root* keys and sign a new *timestamp* key). To launch -any attack other than a freeze attack, one must also compromise the -*consistent-snapshot* key. - -Finally, a compromise of the PyPI infrastructure MAY introduce malicious -updates to *recently-claimed* and *unclaimed* projects because the keys for -those roles are online. However, attackers cannot modify *claimed* projects in -such an event because *targets* and *claimed* metadata have been signed with -offline keys. Therefore, it is RECOMMENDED that high-value projects register -their developer keys with PyPI and sign for their own distributions. - - -In the Event of a Key Compromise --------------------------------- - -By a key compromise, we mean that the key as well as PyPI infrastructure has -been compromised and used to sign new metadata on PyPI. - -If a threshold number of developer keys of a project have been compromised, -then the project MUST take the following steps: - -1. The project metadata and targets MUST be restored to the last known good - consistent snapshot where the project was not known to be compromised. This - can be done by the developers repackaging and resigning all targets with the - new keys. - -2. The project delegated targets metadata MUST have their version numbers - incremented, expiry times suitably extended and signatures renewed. - -Whereas PyPI MUST take the following steps: - -1. Revoke the compromised developer keys from the delegation to the project by - the *recently-claimed* or *claimed* role. This is done by replacing the - compromised developer keys with newly issued developer keys. - -2. A new timestamped consistent snapshot MUST be issued. - -If a threshold number of *timestamp*, *consistent-snapshot*, *recently-claimed* -or *unclaimed* keys have been compromised, then PyPI MUST take the following -steps: - -1. Revoke the *timestamp*, *consistent-snapshot* and *targets* role keys from - the *root* role. This is done by replacing the compromised *timestamp*, - *consistent-snapshot* and *targets* keys with newly issued keys. - -2. Revoke the *recently-claimed* and *unclaimed* keys from the *targets* role - by replacing their keys with newly issued keys. Sign the new *targets* role - metadata and discard the new keys (because, as we explained earlier, this - increases the security of *targets* metadata). - -3. Clear all targets or delegations in the *recently-claimed* role and delete - all associated delegated targets metadata. Recently registered projects - SHOULD register their developer keys again with PyPI. - -4. All targets of the *recently-claimed* and *unclaimed* roles SHOULD be - compared with the last known good consistent snapshot where none of the - *timestamp*, *consistent-snapshot*, *recently-claimed* or *unclaimed* keys - were known to have been compromised. Added, updated or deleted targets in - the compromised consistent snapshot that do not match the last known good - consistent snapshot MAY be restored to their previous versions. After - ensuring the integrity of all *unclaimed* targets, the *unclaimed* metadata - MUST be regenerated. - -5. The *recently-claimed* and *unclaimed* metadata MUST have their version - numbers incremented, expiry times suitably extended and signatures renewed. - -6. A new timestamped consistent snapshot MUST be issued. - -This would preemptively protect all of these roles even though only one of them -may have been compromised. - -If a threshold number of the *targets* or *claimed* keys have been compromised, -then there is little that an attacker could do without the *timestamp* and -*consistent-snapshot* keys. In this case, PyPI MUST simply revoke the -compromised *targets* or *claimed* keys by replacing them with new keys in the -*root* and *targets* roles respectively. - -If a threshold number of the *timestamp*, *consistent-snapshot* and *claimed* -keys have been compromised, then PyPI MUST take the following steps in addition -to the steps taken when either the *timestamp* or *consistent-snapshot* keys -are compromised: - -1. Revoke the *claimed* role keys from the *targets* role and replace them with - newly issued keys. - -2. All project targets of the *claimed* roles SHOULD be compared with the last - known good consistent snapshot where none of the *timestamp*, - *consistent-snapshot* or *claimed* keys were known to have been compromised. - Added, updated or deleted targets in the compromised consistent snapshot - that do not match the last known good consistent snapshot MAY be restored to - their previous versions. After ensuring the integrity of all *claimed* - project targets, the *claimed* metadata MUST be regenerated. - -3. The *claimed* metadata MUST have their version numbers incremented, expiry - times suitably extended and signatures renewed. - -If a threshold number of the *timestamp*, *consistent-snapshot* and *targets* -keys have been compromised, then PyPI MUST take the union of the steps taken -when the *claimed*, *recently-claimed* and *unclaimed* keys have been -compromised. - -If a threshold number of the *root* keys have been compromised, then PyPI MUST -take the steps taken when the *targets* role has been compromised as well as -replace all of the *root* keys. - -It is also RECOMMENDED that PyPI sufficiently document compromises with -security bulletins. These security bulletins will be most informative when -users of pip with TUF are unable to install or update a project because the -keys for the *timestamp*, *consistent-snapshot* or *root* roles are no longer -valid. They could then visit the PyPI web site to consult security bulletins -that would help to explain why they are no longer able to install or update, -and then take action accordingly. When a threshold number of *root* keys have -not been revoked due to a compromise, then new *root* metadata may be safely -updated because a threshold number of existing *root* keys will be used to sign -for the integrity of the new *root* metadata so that TUF clients will be able -to verify the integrity of the new *root* metadata with a threshold number of -previously known *root* keys. This will be the common case. Otherwise, in the -worst case where a threshold number of *root* keys have been revoked due to a -compromise, an end-user may choose to update new *root* metadata with -`out-of-band`__ mechanisms. - -__ https://en.wikipedia.org/wiki/Out-of-band#Authentication - - -Appendix: Rejected Proposals -============================ - - -Alternative Proposals for Producing Consistent Snapshots --------------------------------------------------------- - -The complete file snapshot (CFS) scheme uses file system directories to store -efficient consistent snapshots over time. In this scheme, every consistent -snapshot will be stored in a separate directory, wherein files that are shared -with previous consistent snapshots will be `hard links`__ instead of copies. - -__ https://en.wikipedia.org/wiki/Hard_link - -The `differential file`__ snapshot (DFS) scheme is a variant of the CFS scheme, -wherein the next consistent snapshot directory will contain only the additions -of new files and updates to existing files of the previous consistent snapshot. -(The first consistent snapshot will contain a complete set of files known -then.) Deleted files will be marked as such in the next consistent snapshot -directory. This means that files will be resolved in this manner: First, set -the current consistent snapshot directory to be the latest consistent snapshot -directory. Then, any requested file will be seeked in the current consistent -snapshot directory. If the file exists in the current consistent snapshot -directory, then that file will be returned. If it has been marked as deleted -in the current consistent snapshot directory, then that file will be reported -as missing. Otherwise, the current consistent snapshot directory will be set -to the preceding consistent snapshot directory and the previous few steps will -be iterated until there is no preceding consistent snapshot to be considered, -at which point the file will be reported as missing. - -__ http://dl.acm.org/citation.cfm?id=320484 - -With the CFS scheme, the trade-off is the I/O costs of producing a consistent -snapshot with the file system. As of October 2013, we found that a fairly -modern computer with a 7200RPM hard disk drive required at least three minutes -to produce a consistent snapshot with the "cp -lr" command on the ext3__ file -system. Perhaps the I/O costs of this scheme may be ameliorated with advanced -tools or file systems such as ZFS__ or btrfs__. - -__ https://en.wikipedia.org/wiki/Ext3 -__ https://en.wikipedia.org/wiki/ZFS -__ https://en.wikipedia.org/wiki/Btrfs - -While the DFS scheme improves upon the CFS scheme in terms of producing faster -consistent snapshots, there are at least two trade-offs. The first is that a -web server will need to be modified to perform the "daisy chain" resolution of -a file. The second is that every now and then, the differential snapshots will -need to be "squashed" or merged together with the first consistent snapshot to -produce a new first consistent snapshot with the latest and complete set of -files. Although the merge cost may be amortized over time, this scheme is not -conceptually si - - - - -References -========== - -.. [1] https://pypi.python.org -.. [2] https://isis.poly.edu/~jcappos/papers/samuel_tuf_ccs_2010.pdf -.. [3] http://www.pip-installer.org -.. [4] https://wiki.python.org/moin/WikiAttack2013 -.. [5] https://github.com/theupdateframework/pip/wiki/Attacks-on-software-repositories -.. [6] https://mail.python.org/pipermail/distutils-sig/2013-April/020596.html -.. [7] https://mail.python.org/pipermail/distutils-sig/2013-May/020701.html -.. [8] https://mail.python.org/pipermail/distutils-sig/2013-July/022008.html -.. [9] PEP 381, Mirroring infrastructure for PyPI, Ziad?, L?wis - http://www.python.org/dev/peps/pep-0381/ -.. [10] https://mail.python.org/pipermail/distutils-sig/2013-September/022773.html -.. [11] https://mail.python.org/pipermail/distutils-sig/2013-May/020848.html -.. [12] PEP 449, Removal of the PyPI Mirror Auto Discovery and Naming Scheme, Stufft - http://www.python.org/dev/peps/pep-0449/ -.. [13] https://isis.poly.edu/~jcappos/papers/cappos_mirror_ccs_08.pdf -.. [14] https://mail.python.org/pipermail/distutils-sig/2013-September/022755.html -.. [15] https://pypi.python.org/security -.. [16] https://github.com/theupdateframework/tuf/blob/develop/docs/tuf-spec.txt -.. [17] PEP 426, Metadata for Python Software Packages 2.0, Coghlan, Holth, Stufft - http://www.python.org/dev/peps/pep-0426/ -.. [18] https://en.wikipedia.org/wiki/Continuous_delivery -.. [19] https://mail.python.org/pipermail/distutils-sig/2013-August/022154.html -.. [20] https://en.wikipedia.org/wiki/RSA_%28algorithm%29 -.. [21] https://en.wikipedia.org/wiki/Key-recovery_attack -.. [22] http://csrc.nist.gov/publications/nistpubs/800-57/SP800-57-Part1.pdf -.. [23] https://www.openssl.org/ -.. [24] https://pypi.python.org/pypi/pycrypto -.. [25] http://ed25519.cr.yp.to/ - - -Acknowledgements -================ - -Nick Coghlan, Daniel Holth and the distutils-sig community in general for -helping us to think about how to usably and efficiently integrate TUF with -PyPI. - -Roger Dingledine, Sebastian Hahn, Nick Mathewson, Martin Peck and Justin -Samuel for helping us to design TUF from its predecessor Thandy of the Tor -project. - -Konstantin Andrianov, Geremy Condra, Vladimir Diaz, Zane Fisher, Justin Samuel, -Tian Tian, Santiago Torres, John Ward, and Yuyu Zheng for helping us to develop -TUF. - -Vladimir Diaz, Monzur Muhammad and Sai Teja Peddinti for helping us to review -this PEP. - -Zane Fisher for helping us to review and transcribe this PEP. - - -Copyright -========= - -This document has been placed in the public domain. +PEP: 458 +Title: Surviving a Compromise of PyPI +Version: $Revision$ +Last-Modified: $Date$ +Author: Trishank Karthik Kuppusamy , + Donald Stufft , + Justin Cappos +Discussions-To: Distutils SIG +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 27-Sep-2013 + + +Abstract +======== + +This PEP describes how the Python Package Index (PyPI [1]_) may be integrated +with The Update Framework [2]_ (TUF). TUF was designed to be a plug-and-play +security add-on to a software updater or package manager. TUF provides +end-to-end security like SSL, but for software updates instead of HTTP +connections. The framework integrates best security practices such as +separating responsibilities, adopting the many-man rule for signing packages, +keeping signing keys offline, and revocation of expired or compromised signing +keys. + +The proposed integration will render modern package managers such as pip [3]_ +more secure against various types of security attacks on PyPI and protect users +against them. Even in the worst case where an attacker manages to compromise +PyPI itself, the damage is controlled in scope and limited in duration. + +Specifically, this PEP will describe how PyPI processes should be adapted to +incorporate TUF metadata. It will not prescribe how package managers such as +pip should be adapted to install or update with TUF metadata projects from +PyPI. + + +Rationale +========= + +In January 2013, the Python Software Foundation (PSF) announced [4]_ that the +python.org wikis for Python, Jython, and the PSF were subjected to a security +breach which caused all of the wiki data to be destroyed on January 5 2013. +Fortunately, the PyPI infrastructure was not affected by this security breach. +However, the incident is a reminder that PyPI should take defensive steps to +protect users as much as possible in the event of a compromise. Attacks on +software repositories happen all the time [5]_. We must accept the possibility +of security breaches and prepare PyPI accordingly because it is a valuable +target used by thousands, if not millions, of people. + +Before the wiki attack, PyPI used MD5 hashes to tell package managers such as +pip whether or not a package was corrupted in transit. However, the absence of +SSL made it hard for package managers to verify transport integrity to PyPI. +It was easy to launch a man-in-the-middle attack between pip and PyPI to change +package contents arbitrarily. This can be used to trick users into installing +malicious packages. After the wiki attack, several steps were proposed (some +of which were implemented) to deliver a much higher level of security than was +previously the case: requiring SSL to communicate with PyPI [6]_, restricting +project names [7]_, and migrating from MD5 to SHA-2 hashes [8]_. + +These steps, though necessary, are insufficient because attacks are still +possible through other avenues. For example, a public mirror is trusted to +honestly mirror PyPI, but some mirrors may misbehave due to malice or accident. +Package managers such as pip are supposed to use signatures from PyPI to verify +packages downloaded from a public mirror [9]_, but none are known to actually +do so [10]_. Therefore, it is also wise to add more security measures to +detect attacks from public mirrors or content delivery networks [11]_ (CDNs). + +Even though official mirrors are being deprecated on PyPI [12]_, there remain a +wide variety of other attack vectors on package managers [13]_. Among other +things, these attacks can crash client systems, cause obsolete packages to be +installed, or even allow an attacker to execute arbitrary code. In September +2013, we showed how the latest version of pip then was susceptible to these +attacks and how TUF could protect users against them [14]_. + +Finally, PyPI allows for packages to be signed with GPG keys [15]_, although no +package manager is known to verify those signatures, thus negating much of the +benefits of having those signatures at all. Validating integrity through +cryptography is important, but issues such as immediate and secure key +revocation or specifying a required threshold number of signatures still +remain. Furthermore, GPG by itself does not immediately address the attacks +mentioned above. + +In order to protect PyPI against infrastructure compromises, we propose +integrating PyPI with The Update Framework [2]_ (TUF). + + +Definitions +=========== + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", +"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be +interpreted as described in RFC 2119__. + +__ http://www.ietf.org/rfc/rfc2119.txt + +In order to keep this PEP focused solely on the application of TUF on PyPI, the +reader is assumed to already be familiar with the design principles of +TUF [2]_. It is also strongly RECOMMENDED that the reader be familiar with the +TUF specification [16]_. + +* Projects: Projects are software components that are made available for + integration. Projects include Python libraries, frameworks, scripts, plugins, + applications, collections of data or other resources, and various + combinations thereof. Public Python projects are typically registered on the + Python Package Index [17]_. + +* Releases: Releases are uniquely identified snapshots of a project [17]_. + +* Distributions: Distributions are the packaged files which are used to publish + and distribute a release [17]_. + +* Simple index: The HTML page which contains internal links to the + distributions of a project [17]_. + +* Consistent snapshot: A set of TUF metadata and PyPI targets that capture the + complete state of all projects on PyPI as they were at some fixed point in + time. + +* The *consistent-snapshot* (*release*) role: In order to prevent confusion due + to the different meanings of the term "release" as employed by PEP 426 [17]_ + and the TUF specification [16]_, we rename the *release* role as the + *consistent-snapshot* role. + +* Continuous delivery: A set of processes with which PyPI produces consistent + snapshots that can safely coexist and deleted independently [18]_. + +* Developer: Either the owner or maintainer of a project who is allowed to + update the TUF metadata as well as distribution metadata and data for the + project. + +* Online key: A key that MUST be stored on the PyPI server infrastructure. + This is usually to allow automated signing with the key. However, this means + that an attacker who compromises PyPI infrastructure will be able to read + these keys. + +* Offline key: A key that MUST be stored off the PyPI infrastructure. This + prevents automated signing with the key. This means that an attacker who + compromises PyPI infrastructure will not be able to immediately read these + keys. + +* Developer key: A private key for which its corresponding public key is + registered with PyPI to say that it is responsible for directly signing for + or delegating the distributions belonging to a project. For the purposes of + this PEP, it is offline in the sense that the private key MUST not be stored + on PyPI. However, the project is free to require certain developer keys to + be online on its own infrastructure. + +* Threshold signature scheme: A role could increase its resilience to key + compromises by requiring that at least t out of n keys are REQUIRED to sign + its metadata. This means that a compromise of t-1 keys is insufficient to + compromise the role itself. We denote this property by saying that the role + requires (t, n) keys. + + +Overview +======== + +.. image:: https://raw.github.com/theupdateframework/pep-on-pypi-with-tuf/master/figure1.png + +Figure 1: A simplified overview of the roles in PyPI with TUF + +Figure 1 shows a simplified overview of the roles that TUF metadata assume on +PyPI. The top-level *root* role signs for the keys of the top-level +*timestamp*, *consistent-snapshot*, *targets* and *root* roles. The +*timestamp* role signs for a new and consistent snapshot. The *consistent- +snapshot* role signs for the *root*, *targets* and all delegated targets +metadata. The *claimed* role signs for all projects that have registered their +own developer keys with PyPI. The *recently-claimed* role signs for all +projects that recently registered their own developer keys with PyPI. Finally, +the *unclaimed* role signs for all projects that have not registered developer +keys with PyPI. The *claimed*, *recently-claimed* and *unclaimed* roles are +numbered 1, 2, 3 respectively because a project will be searched for in each of +those roles in that descending order: first in *claimed*, then in +*recently-claimed* if necessary, and finally in *unclaimed* if necessary. + +Every year, PyPI administrators are going to sign for *root* role keys. After +that, automation will continuously sign for a timestamped, consistent snapshot +of all projects. Every few months, PyPI administrators will move projects with +vetted developer keys from the *recently-claimed* role to the *claimed* role. +As we will soon see, they will sign for *claimed* with projects with offline +keys. + +This PEP does not require project developers to use TUF to secure their +packages from attacks on PyPI. By default, all projects will be signed for by +the *unclaimed* role. If a project wishes stronger security guarantees, then +the project is strongly RECOMMENDED to register developer keys with PyPI so +that it may sign for its own distributions. By doing so, the project must +remain as a *recently-claimed* project until PyPI administrators have had an +opportunity to vet the developer keys of the project, after which the project +will be moved to the *claimed* role. + +This PEP has **not** been designed to be backward-compatible for package +managers that do not use the TUF security protocol to install or update a +project from the PyPI described here. Instead, it is RECOMMENDED that PyPI +maintain a backward-compatible API of itself that does NOT offer TUF so that +older package managers that do not use TUF will be able to install or update +projects from PyPI as usual but without any of the security offered by TUF. +For the rest of this PEP, we will assume that PyPI will simultaneously maintain +a backward-incompatible API of itself for package managers that MUST use TUF to +securely install or update projects. We think that this approach represents a +reasonable trade-off: older package managers that do not TUF will still be able +to install or update projects without any TUF security from PyPI, and newer +package managers that do use TUF will be able to securely install or update +projects. At some point in the future, PyPI administrators MAY choose to +permanently deprecate the backward-compatible version of itself that does not +offer TUF metadata. + +Unless a mirror, CDN or the PyPI repository has been compromised, the end-user +will not be able to discern whether or not a package manager is using TUF to +install or update a project from PyPI. + + +Responsibility Separation +========================= + +Recall that TUF requires four top-level roles: *root*, *timestamp*, +*consistent-snapshot* and *targets*. The *root* role specifies the keys of all +the top-level roles (including itself). The *timestamp* role specifies the +latest consistent snapshot. The *consistent-snapshot* role specifies the +latest versions of all TUF metadata files (other than *timestamp*). The +*targets* role specifies available target files (in our case, it will be all +files on PyPI under the /simple and /packages directories). In this PEP, each +of these roles will serve their responsibilities without exception. + +Our proposal offers two levels of security to developers. If developers opt in +to secure their projects with their own developer keys, then their projects +will be very secure. Otherwise, TUF will still protect them in many cases: + +1. Minimum security (no action by a developer): protects *unclaimed* and + *recently-claimed* projects without developer keys from CDNs [19]_ or public + mirrors, but not from some PyPI compromises. This is because continuous + delivery requires some keys to be online. This level of security protects + projects from being accidentally or deliberately tampered with by a mirror + or a CDN because the mirror or CDN will not have any of the PyPI or + developer keys required to sign for projects. However, it would not protect + projects from attackers who have compromised PyPI because they will be able + to manipulate the TUF metadata for *unclaimed* projects with the appropriate + online keys. + +2. Maximum security (developer signs their project): protects projects with + developer keys not only from CDNs or public mirrors, but also from some PyPI + compromises. This is because many important keys will be offline. This + level of security protects projects from being accidentally or deliberately + tampered with by a mirror or a CDN for reasons identical to the minimum + security level. It will also protect projects (or at least mitigate + damages) from the most likely attacks on PyPI. For example: given access to + online keys after a PyPI compromise, attackers will be able to freeze the + distributions for these projects, but they will not be able to serve + malicious distributions for these projects (not without compromising other + offline keys which would entail more risk, time and energy). Details for + the exact level of security offered is discussed in the section on key + management. + +In order to complete support for continuous delivery, we propose three +delegated targets roles: + +1. *claimed*: Signs for the delegation of PyPI projects to their respective + developer keys. + +2. *recently-claimed*: This role is almost identical to the *claimed* role and + could technically be performed by the *unclaimed* role, but there are two + important reasons why it exists independently: the first reason is to + improve the performance of looking up projects in the *unclaimed* role (by + moving metadata to the *recently-claimed* role instead), and the second + reason is to make it easier for PyPI administrators to move + *recently-claimed* projects to the *claimed* role. + +3. *unclaimed*: Signs for PyPI projects without developer keys. + +The *targets* role MUST delegate all PyPI projects to the three delegated +targets roles in the order of appearance listed above. This means that when +pip downloads with TUF a distribution from a project on PyPI, it will first +consult the *claimed* role about it. If the *claimed* role has delegated the +project, then pip will trust the project developers (in order of delegation) +about the TUF metadata for the project. Otherwise, pip will consult the +*recently-claimed* role about the project. If the *recently-claimed* role has +delegated the project, then pip will trust the project developers (in order of +delegation) about the TUF metadata for the project. Otherwise, pip will +consult the *unclaimed* role about the TUF metadata for the project. If the +*unclaimed* role has not delegated the project, then the project is considered +to be non-existent on PyPI. + +A PyPI project MAY begin without registering a developer key. Therefore, the +project will be signed for by the *unclaimed* role. After registering +developer keys, the project will be removed from the *unclaimed* role and +delegated to the *recently-claimed* role. After a probation period and a +vetting process to verify the developer keys of the project, the project will +be removed from the *recently-claimed* role and delegated to the *claimed* +role. + +The *claimed* role offers maximum security, whereas the *recently-claimed* and +*unclaimed* role offer minimum security. All three roles support continuous +delivery of PyPI projects. + +The *unclaimed* role offers minimum security because PyPI will sign for +projects without developer keys with an online key in order to permit +continuous delivery. + +The *recently-claimed* role offers minimum security because while the project +developers will sign for their own distributions with offline developer keys, +PyPI will sign with an online key the delegation of the project to those +offline developer keys. The signing of the delegation with an online key +allows PyPI administrators to continuously deliver projects without having to +continuously sign the delegation whenever one of those projects registers +developer keys. + +Finally, the *claimed* role offers maximum security because PyPI will sign with +offline keys the delegation of a project to its offline developer keys. This +means that every now and then, PyPI administrators will vet developer keys and +sign the delegation of a project to those developer keys after being reasonably +sure about the ownership of the developer keys. The process for vetting +developer keys is out of the scope of this PEP. + + +Metadata Management +=================== + +In this section, we examine the TUF metadata that PyPI must manage by itself, +and other TUF metadata that must be safely delegated to projects. Examples of +the metadata described here may be seen at our testbed mirror of +`PyPI-with-TUF`__. + +__ http://mirror1.poly.edu/ + +The metadata files that change most frequently will be *timestamp*, +*consistent-snapshot* and delegated targets (*claimed*, *recently-claimed*, +*unclaimed*, project) metadata. The *timestamp* and *consistent-snapshot* +metadata MUST be updated whenever *root*, *targets* or delegated targets +metadata are updated. Observe, though, that *root* and *targets* metadata are +much less likely to be updated as often as delegated targets metadata. +Therefore, *timestamp* and *consistent-snapshot* metadata will most likely be +updated frequently (possibly every minute) due to delegated targets metadata +being updated frequently in order to drive continuous delivery of projects. + +Consequently, the processes with which PyPI updates projects will have to be +updated accordingly, the details of which are explained in the following +subsections. + + +Why Do We Need Consistent Snapshots? +------------------------------------ + +In an ideal world, metadata and data should be immediately updated and +presented whenever a project is updated. In practice, there will be problems +when there are many readers and writers who access the same metadata or data at +the same time. + +An important example at the time of writing is that, mirrors are very likely, +as far as we can tell, to update in an inconsistent manner from PyPI as it is +without TUF. Specifically, a mirror would update itself in such a way that +project A would be from time T, whereas project B would be from time T+5, +project C would be from time T+3, and so on where T is the time that the mirror +first begun updating itself. There is no known way for a mirror to update +itself such that it captures the state of all projects as they were at time T. + +Adding TUF to PyPI will not automatically solve the problem. Consider what we +call the `"inverse replay" or "fast-forward" problem`__. Suppose that PyPI has +timestamped a consistent snapshot at version 1. A mirror is later in the +middle of copying PyPI at this snapshot. While the mirror is copying PyPI at +this snapshot, PyPI timestamps a new snapshot at, say, version 2. Without +accounting for consistency, the mirror would then find itself with a copy of +PyPI in an inconsistent state which is indistinguishable from arbitrary +metadata or target attacks. The problem would also apply when the mirror is +substituted with a pip user. + +__ https://groups.google.com/forum/#!topic/theupdateframework/8mkR9iqivQA + +Therefore, the problem can be summarized as such: there are problems of +consistency on PyPI with or without TUF. TUF requires its metadata to be +consistent with the data, but how would the metadata be kept consistent with +projects that change all the time? + +As a result, we will solve for PyPI the problem of producing a consistent +snapshot that captures the state of all known projects at a given time. Each +consistent snapshot can safely coexist with any other consistent snapshot and +deleted independently without affecting any other consistent snapshot. + +The gist of the solution is that every metadata or data file written to disk +MUST include in its filename the `cryptographic hash`__ of the file. How would +this help clients which use the TUF protocol to securely and consistently +install or update a project from PyPI? + +__ https://en.wikipedia.org/wiki/Cryptographic_hash_function + +Recall that the first step in the TUF protocol requires the client to download +the latest *timestamp* metadata. However, the client would not know in advance +the hash of the *timestamp* metadata file from the latest consistent snapshot. +Therefore, PyPI MUST redirect all HTTP GET requests for *timestamp* metadata to +the *timestamp* metadata file from the latest consistent snapshot. Since the +*timestamp* metadata is the root of a tree of cryptographic hashes pointing to +every other metadata or target file that are meant to exist together for +consistency, the client is then able to retrieve any file from this consistent +snapshot by deterministically including, in the request for the file, the hash +of the file in the filename. Assuming infinite disk space and no `hash +collisions`__, a client may safely read from one consistent snapshot while PyPI +produces another consistent snapshot. + +__ https://en.wikipedia.org/wiki/Collision_(computer_science) + +In this simple but effective manner, we are able to capture a consistent +snapshot of all projects and the associated metadata at a given time. The next +subsection will explicate the implementation details of this idea. + + +Producing Consistent Snapshots +------------------------------ + +Given a project, PyPI is responsible for updating, depending on the project, +either the *claimed*, *recently-claimed* or *unclaimed* metadata as well as +associated delegated targets metadata. Every project MUST upload its set of +metadata and targets in a single transaction. We will call this set of files +the project transaction. We will discuss later how PyPI MAY validate the files +in a project transaction. For now, let us focus on how PyPI will respond to a +project transaction. We will call this response the project transaction +process. There will also be a consistent snapshot process that we will define +momentarily; for now, it suffices to know that project transaction processes +and the consistent snapshot process must coordinate with each other. + +Also, every metadata and target file MUST include in its filename the `hex +digest`__ of its `SHA-256`__ hash. For this PEP, it is RECOMMENDED that PyPI +adopt a simple convention of the form filename.digest.ext, where filename is +the original filename without a copy of the hash, digest is the hex digest of +the hash, and ext is the filename extension. + +__ http://docs.python.org/2/library/hashlib.html#hashlib.hash.hexdigest +__ https://en.wikipedia.org/wiki/SHA-2 + +When an *unclaimed* project uploads a new transaction, a project transaction +process MUST add all new targets and relevant delegated *unclaimed* metadata. +(We will see later in this section why the *unclaimed* role will delegate +targets to a number of delegated *unclaimed* roles.) Finally, the project +transaction process MUST inform the consistent snapshot process about new +delegated *unclaimed* metadata. + +When a *recently-claimed* project uploads a new a transaction, a project +transaction process MUST add all new targets and delegated targets metadata for +the project. If the project is new, then the project transaction process MUST +also add new *recently-claimed* metadata with public keys and threshold number +(which MUST be part of the transaction) for the project. Finally, the project +transaction process MUST inform the consistent snapshot process about new +*recently-claimed* metadata as well as the current set of delegated targets +metadata for the project. + +The process for a *claimed* project is slightly different. The difference is +that PyPI administrators will choose to move the project from the +*recently-claimed* role to the *claimed* role. A project transaction process +MUST then add new *recently-claimed* and *claimed* metadata to reflect this +migration. As is the case for a *recently-claimed* project, the project +transaction process MUST always add all new targets and delegated targets +metadata for the *claimed* project. Finally, the project transaction process +MUST inform the consistent snapshot process about new *recently-claimed* or +*claimed* metadata as well as the current set of delegated targets metadata for +the project. + +Project transaction processes SHOULD be automated, except when PyPI +administrators move a project from the *recently-claimed* role to the *claimed* +role. Project transaction processes MUST also be applied atomically: either +all metadata and targets, or none of them, are added. The project transaction +processes and consistent snapshot process SHOULD work concurrently. Finally, +project transaction processes SHOULD keep in memory the latest *claimed*, +*recently-claimed* and *unclaimed* metadata so that they will be correctly +updated in new consistent snapshots. + +All project transactions MAY be placed in a single queue and processed +serially. Alternatively, the queue MAY be processed concurrently in order of +appearance provided that the following rules are observed: + +1. No pair of project transaction processes must concurrently work on the same + project. + +2. No pair of project transaction processes must concurrently work on + *unclaimed* projects that belong to the same delegated *unclaimed* targets + role. + +3. No pair of project transaction processes must concurrently work on new + *recently-claimed* projects. + +4. No pair of project transaction processes must concurrently work on new + *claimed* projects. + +5. No project transaction process must work on a new *claimed* project while + another project transaction process is working on a new *recently-claimed* + project and vice versa. + +These rules MUST be observed so that metadata is not read from or written to +inconsistently. + +The consistent snapshot process is fairly simple and SHOULD be automated. The +consistent snapshot process MUST keep in memory the latest working set of +*root*, *targets* and delegated targets metadata. Every minute or so, the +consistent snapshot process will sign for this latest working set. (Recall +that project transaction processes continuously inform the consistent snapshot +process about the latest delegated targets metadata in a concurrency-safe +manner. The consistent snapshot process will actually sign for a copy of the +latest working set while the actual latest working set in memory will be +updated with information continuously communicated by project transaction +processes.) Next, the consistent snapshot process MUST generate and sign new +*timestamp* metadata that will vouch for the *consistent-snapshot* metadata +generated in the previous step. Finally, the consistent snapshot process MUST +add new *timestamp* and *consistent-snapshot* metadata representing the latest +consistent snapshot. + +A few implementation notes are now in order. So far, we have seen only that +new metadata and targets are added, but not that old metadata and targets are +removed. Practical constraints are such that eventually PyPI will run out of +disk space to produce a new consistent snapshot. In that case, PyPI MAY then +use something like a "mark-and-sweep" algorithm to delete sufficiently old +consistent snapshots: in order to preserve the latest consistent snapshot, PyPI +would walk objects beginning from the root (*timestamp*) of the latest +consistent snapshot, mark all visited objects, and delete all unmarked +objects. The last few consistent snapshots may be preserved in a similar +fashion. Deleting a consistent snapshot will cause clients to see nothing +thereafter but HTTP 404 responses to any request for a file in that consistent +snapshot. Clients SHOULD then retry their requests with the latest consistent +snapshot. + +We do **not** consider updates to any consistent snapshot because `hash +collisions`__ are out of the scope of this PEP. In case a hash collision is +observed, PyPI MAY wish to check that the file being added is identical to the +file already stored. (Should a hash collision be observed, it is far more +likely the case that the file is identical rather than being a genuine +`collision attack`__.) Otherwise, PyPI MAY either overwrite the existing file +or ignore any write operation to an existing file. + +__ https://en.wikipedia.org/wiki/Collision_(computer_science) +__ https://en.wikipedia.org/wiki/Collision_attack + +All clients, such as pip using the TUF protocol, MUST be modified to download +every metadata and target file (except for *timestamp* metadata) by including, +in the request for the file, the hash of the file in the filename. Following +the filename convention recommended earlier, a request for the file at +filename.ext will be transformed to the equivalent request for the file at +filename.digest.ext. + +Finally, PyPI SHOULD use a `transaction log`__ to record project transaction +processes and queues so that it will be easier to recover from errors after a +server failure. + +__ https://en.wikipedia.org/wiki/Transaction_log + + +Metadata Validation +------------------- + +A *claimed* or *recently-claimed* project will need to upload in its +transaction to PyPI not just targets (a simple index as well as distributions) +but also TUF metadata. The project MAY do so by uploading a ZIP file +containing two directories, /metadata/ (containing delegated targets metadata +files) and /targets/ (containing targets such as the project simple index and +distributions which are signed for by the delegated targets metadata). + +Whenever the project uploads metadata or targets to PyPI, PyPI SHOULD check the +project TUF metadata for at least the following properties: + +* A threshold number of the developers keys registered with PyPI by that + project MUST have signed for the delegated targets metadata file that + represents the "root" of targets for that project (e.g. metadata/targets/ + project.txt). + +* The signatures of delegated targets metadata files MUST be valid. + +* The delegated targets metadata files MUST NOT be expired. + +* The delegated targets metadata MUST be consistent with the targets. + +* A delegator MUST NOT delegate targets that were not delegated to itself by + another delegator. + +* A delegatee MUST NOT sign for targets that were not delegated to itself by a + delegator. + +* Every file MUST contain a unique copy of its hash in its filename following + the filename.digest.ext convention recommended earlier. + +If PyPI chooses to check the project TUF metadata, then PyPI MAY choose to +reject publishing any set of metadata or targets that do not meet these +requirements. + +PyPI MUST enforce access control by ensuring that each project can only write +to the TUF metadata for which it is responsible. It MUST do so by ensuring +that project transaction processes write to the correct metadata as well as +correct locations within those metadata. For example, a project transaction +process for an *unclaimed* project MUST write to the correct target paths in +the correct delegated *unclaimed* metadata for the targets of the project. + +On rare occasions, PyPI MAY wish to extend the TUF metadata format for projects +in a backward-incompatible manner. Note that PyPI will NOT be able to +automatically rewrite existing TUF metadata on behalf of projects in order to +upgrade the metadata to the new backward-incompatible format because this would +invalidate the signatures of the metadata as signed by developer keys. +Instead, package managers SHOULD be written to recognize and handle multiple +incompatible versions of TUF metadata so that *claimed* and *recently-claimed* +projects could be offered a reasonable time to migrate their metadata to newer +but backward-incompatible formats. + +The details of how each project manages its TUF metadata is beyond the scope of +this PEP. + + +Mirroring Protocol +------------------ + +The mirroring protocol as described in PEP 381 [9]_ SHOULD change to mirror +PyPI with TUF. + +A mirror SHOULD have to maintain for its clients only one consistent snapshot +which would represent the latest consistent snapshot from PyPI known to the +mirror. The mirror would then serve all HTTP requests for metadata or targets +by simply reading directly from this consistent snapshot directory. + +The mirroring protocol itself is fairly simple. The mirror would ask PyPI for +*timestamp* metadata from the latest consistent snapshot and proceed to copy +the entire consistent snapshot from the *timestamp* metadata onwards. If the +mirror encounters a failure to copy any metadata or target file while copying +the consistent snapshot, it SHOULD retrying resuming the copy of that +particular consistent snapshot. If PyPI has deleted that consistent snapshot, +then the mirror SHOULD delete the failed consistent snapshot and try +downloading the latest consistent snapshot instead. + +The mirror SHOULD point users to a previous consistent snapshot directory while +it is copying the latest consistent snapshot from PyPI. Only after the latest +consistent snapshot has been completely copied SHOULD the mirror switch clients +to the latest consistent snapshot. The mirror MAY then delete the previous +consistent snapshot once it finds that no client is reading from the previous +consistent snapshot. + +The mirror MAY use extant file transfer software such as rsync__ to mirror +PyPI. In that case, the mirror MUST first obtain the latest known timestamp +metadata from PyPI. The mirror MUST NOT immediately publish the latest known +timestamp metadata from PyPI. Instead, the mirror MUST first iteratively +transfer all new files from PyPI until there are no new files left to transfer. +Finally, the mirror MUST publish the latest known timestamp it fetched from +PyPI so that package managers such as pip may be directed to the latest +consistent snapshot known to the mirror. + +__ https://rsync.samba.org/ + + +Backup Process +-------------- + +In order to be able to safely restore from static snapshots later in the event +of a compromise, PyPI SHOULD maintain a small number of its own mirrors to copy +PyPI consistent snapshots according to some schedule. The mirroring protocol +can be used immediately for this purpose. The mirrors must be secured and +isolated such that they are responsible only for mirroring PyPI. The mirrors +can be checked against one another to detect accidental or malicious failures. + + +Metadata Expiry Times +--------------------- + +The *root* and *targets* role metadata SHOULD expire in a year, because these +metadata files are expected to change very rarely. + +The *claimed* role metadata SHOULD expire in three to six months, because this +metadata is expected to be refreshed in that time frame. This time frame was +chosen to induce an easier administration process for PyPI. + +The *timestamp*, *consistent-snapshot*, *recently-claimed* and *unclaimed* role +metadata SHOULD expire in a day because a CDN or mirror SHOULD synchronize +itself with PyPI every day. Furthermore, this generous time frame also takes +into account client clocks that are highly skewed or adrift. + +The expiry times for the delegated targets metadata of a project is beyond the +scope of this PEP. + + +Metadata Scalability +-------------------- + +Due to the growing number of projects and distributions, the TUF metadata will +also grow correspondingly. + +For example, consider the *unclaimed* role. In August 2013, we found that the +size of the *unclaimed* role metadata was about 42MB if the *unclaimed* role +itself signed for about 220K PyPI targets (which are simple indices and +distributions). We will not delve into details in this PEP, but TUF features a +so-called "`lazy bin walk`__" scheme which splits a large targets or delegated +targets metadata file into many small ones. This allows a TUF client updater +to intelligently download only a small number of TUF metadata files in order to +update any project signed for by the *unclaimed* role. For example, applying +this scheme to the previous repository resulted in pip downloading between +1.3KB and 111KB to install or upgrade a PyPI project via TUF. + +__ https://github.com/theupdateframework/tuf/issues/39 + +From our findings as of the time of writing, PyPI SHOULD split all targets in +the *unclaimed* role by delegating it to 1024 delegated targets role, each of +which would sign for PyPI targets whose hashes fall into that "bin" or +delegated targets role. We found that 1024 bins would result in the +*unclaimed* role metadata and each of its binned delegated targets role +metadata to be about the same size (40-50KB) for about 220K PyPI targets +(simple indices and distributions). + +It is possible to make the TUF metadata more compact by representing it in a +binary format as opposed to the JSON text format. Nevertheless, we believe +that a sufficiently large number of project and distributions will induce +scalability challenges at some point, and therefore the *unclaimed* role will +then still need delegations in order to address the problem. Furthermore, the +JSON format is an open and well-known standard for data interchange. + +Due to the large number of delegated target metadata files, compressed versions +of *consistent-snapshot* metadata SHOULD also be made available. + + +Key Management +============== + +In this section, we examine the kind of keys required to sign for TUF roles on +PyPI. TUF is agnostic with respect to choices of digital signature algorithms. +For the purpose of discussion, we will assume that most digital signatures will +be produced with the well-tested and tried RSA algorithm [20]_. Nevertheless, +we do NOT recommend any particular digital signature algorithm in this PEP +because there are a few important constraints: firstly, cryptography changes +over time; secondly, package managers such as pip may wish to perform signature +verification in Python, without resorting to a compiled C library, in order to +be able to run on as many systems as Python supports; finally, TUF recommends +diversity of keys for certain applications, and we will soon discuss these +exceptions. + + +Number Of Keys +-------------- + +The *timestamp*, *consistent-snapshot*, *recently-claimed* and *unclaimed* +roles will need to support continuous delivery. Even though their respective +keys will then need to be online, we will require that the keys be independent +of each other. This allows for each of the keys to be placed on separate +servers if need be, and prevents side channel attacks that compromise one key +from automatically compromising the rest of the keys. Therefore, each of the +*timestamp*, *consistent-snapshot*, *recently-claimed* and *unclaimed* roles +MUST require (1, 1) keys. + +The *unclaimed* role MAY delegate targets in an automated manner to a number of +roles called "bins", as we discussed in the previous section. Each of the +"bin" roles SHOULD share the same key as the *unclaimed* role, due +simultaneously to space efficiency of metadata and because there is no security +advantage in requiring separate keys. + +The *root* role is critical for security and should very rarely be used. It is +primarily used for key revocation, and it is the root of trust for all of PyPI. +The *root* role signs for the keys that are authorized for each of the +top-level roles (including itself). The keys belonging to the *root* role are +intended to be very well-protected and used with the least frequency of all +keys. We propose that every PSF board member own a (strong) root key. A +majority of them can then constitute the quorum to revoke or endow trust in all +top-level keys. Alternatively, the system administrators of PyPI (instead of +PSF board members) could be responsible for signing for the *root* role. +Therefore, the *root* role SHOULD require (t, n) keys, where n is the number of +either all PyPI administrators or all PSF board members, and t > 1 (so that at +least two members must sign the *root* role). + +The *targets* role will be used only to sign for the static delegation of all +targets to the *claimed*, *recently-claimed* and *unclaimed* roles. Since +these target delegations must be secured against attacks in the event of a +compromise, the keys for the *targets* role MUST be offline and independent +from other keys. For simplicity of key management without sacrificing +security, it is RECOMMENDED that the keys of the *targets* role are permanently +discarded as soon as they have been created and used to sign for the role. +Therefore, the *targets* role SHOULD require (1, 1) keys. Again, this is +because the keys are going to be permanently discarded, and more offline keys +will not help against key recovery attacks [21]_ unless diversity of keys is +maintained. + +Similarly, the *claimed* role will be used only to sign for the dynamic +delegation of projects to their respective developer keys. Since these target +delegations must be secured against attacks in the event of a compromise, the +keys for the *claimed* role MUST be offline and independent from other keys. +Therefore, the *claimed* role SHOULD require (t, n) keys, where n is the number +of all PyPI administrators (in order to keep it manageable), and t ? 1 (so that +at least one member MUST sign the *claimed* role). While a stronger threshold +would indeed render the role more robust against a compromise of the *claimed* +keys (which is highly unlikely assuming that the keys are independent and +securely kept offline), we think that this trade-off is acceptable for the +important purpose of keeping the maintenance overhead for PyPI administrators +as little as possible. At the time of writing, we are keeping this point open +for discussion by the distutils-sig community. + +The number of developer keys is project-specific and thus beyond the scope of +this PEP. + + +Online and Offline Keys +----------------------- + +In order to support continuous delivery, the *timestamp*, +*consistent-snapshot*, *recently-claimed* and *unclaimed* role keys MUST be +online. + +As explained in the previous section, the *root*, *targets* and *claimed* role +keys MUST be offline for maximum security. Developers keys will be offline in +the sense that the private keys MUST NOT be stored on PyPI, though some of them +may be online on the private infrastructure of the project. + + +Key Strength +------------ + +At the time of writing, we recommend that all RSA keys (both offline and +online) SHOULD have a minimum key size of 3072 bits for data-protection +lifetimes beyond 2030 [22]_. + + +Diversity Of Keys +----------------- + +Due to the threats of weak key generation and implementation weaknesses [2]_, +the types of keys as well as the libraries used to generate them should vary +within TUF on PyPI. Our current implementation of TUF supports multiple +digital signature algorithms such as RSA (with OpenSSL [23]_ or PyCrypto [24]_) +and ed25519 [25]_. Furthermore, TUF supports the binding of other +cryptographic libraries that it does not immediately support "out of the box", +and so one MAY generate keys using other cryptographic libraries and use them +for TUF on PyPI. + +As such, the root role keys SHOULD be generated by a variety of digital +signature algorithms as implemented by different cryptographic libraries. + + +Key Compromise Analysis +----------------------- + +.. image:: https://raw.github.com/theupdateframework/pep-on-pypi-with-tuf/master/table1.png + +Table 1: Attacks possible by compromising certain combinations of role keys + + +Table 1 summarizes the kinds of attacks rendered possible by compromising a +threshold number of keys belonging to the TUF roles on PyPI. Except for the +*timestamp* and *consistent-snapshot* roles, the pairwise interaction of role +compromises may be found by taking the union of both rows. + +In September 2013, we showed how the latest version of pip then was susceptible +to these attacks and how TUF could protect users against them [14]_. + +An attacker who compromises developer keys for a project and who is able to +somehow upload malicious metadata and targets to PyPI will be able to serve +malicious updates to users of that project (and that project alone). Note that +compromising *targets* or any delegated targets role (except for project +targets metadata) does not immediately endow the attacker with the ability to +serve malicious updates. The attacker must also compromise the *timestamp* and +*consistent-snapshot* roles (which are both online and therefore more likely to +be compromised). This means that in order to launch any attack, one must be +not only be able to act as a man-in-the-middle but also compromise the +*timestamp* key (or the *root* keys and sign a new *timestamp* key). To launch +any attack other than a freeze attack, one must also compromise the +*consistent-snapshot* key. + +Finally, a compromise of the PyPI infrastructure MAY introduce malicious +updates to *recently-claimed* and *unclaimed* projects because the keys for +those roles are online. However, attackers cannot modify *claimed* projects in +such an event because *targets* and *claimed* metadata have been signed with +offline keys. Therefore, it is RECOMMENDED that high-value projects register +their developer keys with PyPI and sign for their own distributions. + + +In the Event of a Key Compromise +-------------------------------- + +By a key compromise, we mean that the key as well as PyPI infrastructure has +been compromised and used to sign new metadata on PyPI. + +If a threshold number of developer keys of a project have been compromised, +then the project MUST take the following steps: + +1. The project metadata and targets MUST be restored to the last known good + consistent snapshot where the project was not known to be compromised. This + can be done by the developers repackaging and resigning all targets with the + new keys. + +2. The project delegated targets metadata MUST have their version numbers + incremented, expiry times suitably extended and signatures renewed. + +Whereas PyPI MUST take the following steps: + +1. Revoke the compromised developer keys from the delegation to the project by + the *recently-claimed* or *claimed* role. This is done by replacing the + compromised developer keys with newly issued developer keys. + +2. A new timestamped consistent snapshot MUST be issued. + +If a threshold number of *timestamp*, *consistent-snapshot*, *recently-claimed* +or *unclaimed* keys have been compromised, then PyPI MUST take the following +steps: + +1. Revoke the *timestamp*, *consistent-snapshot* and *targets* role keys from + the *root* role. This is done by replacing the compromised *timestamp*, + *consistent-snapshot* and *targets* keys with newly issued keys. + +2. Revoke the *recently-claimed* and *unclaimed* keys from the *targets* role + by replacing their keys with newly issued keys. Sign the new *targets* role + metadata and discard the new keys (because, as we explained earlier, this + increases the security of *targets* metadata). + +3. Clear all targets or delegations in the *recently-claimed* role and delete + all associated delegated targets metadata. Recently registered projects + SHOULD register their developer keys again with PyPI. + +4. All targets of the *recently-claimed* and *unclaimed* roles SHOULD be + compared with the last known good consistent snapshot where none of the + *timestamp*, *consistent-snapshot*, *recently-claimed* or *unclaimed* keys + were known to have been compromised. Added, updated or deleted targets in + the compromised consistent snapshot that do not match the last known good + consistent snapshot MAY be restored to their previous versions. After + ensuring the integrity of all *unclaimed* targets, the *unclaimed* metadata + MUST be regenerated. + +5. The *recently-claimed* and *unclaimed* metadata MUST have their version + numbers incremented, expiry times suitably extended and signatures renewed. + +6. A new timestamped consistent snapshot MUST be issued. + +This would preemptively protect all of these roles even though only one of them +may have been compromised. + +If a threshold number of the *targets* or *claimed* keys have been compromised, +then there is little that an attacker could do without the *timestamp* and +*consistent-snapshot* keys. In this case, PyPI MUST simply revoke the +compromised *targets* or *claimed* keys by replacing them with new keys in the +*root* and *targets* roles respectively. + +If a threshold number of the *timestamp*, *consistent-snapshot* and *claimed* +keys have been compromised, then PyPI MUST take the following steps in addition +to the steps taken when either the *timestamp* or *consistent-snapshot* keys +are compromised: + +1. Revoke the *claimed* role keys from the *targets* role and replace them with + newly issued keys. + +2. All project targets of the *claimed* roles SHOULD be compared with the last + known good consistent snapshot where none of the *timestamp*, + *consistent-snapshot* or *claimed* keys were known to have been compromised. + Added, updated or deleted targets in the compromised consistent snapshot + that do not match the last known good consistent snapshot MAY be restored to + their previous versions. After ensuring the integrity of all *claimed* + project targets, the *claimed* metadata MUST be regenerated. + +3. The *claimed* metadata MUST have their version numbers incremented, expiry + times suitably extended and signatures renewed. + +If a threshold number of the *timestamp*, *consistent-snapshot* and *targets* +keys have been compromised, then PyPI MUST take the union of the steps taken +when the *claimed*, *recently-claimed* and *unclaimed* keys have been +compromised. + +If a threshold number of the *root* keys have been compromised, then PyPI MUST +take the steps taken when the *targets* role has been compromised as well as +replace all of the *root* keys. + +It is also RECOMMENDED that PyPI sufficiently document compromises with +security bulletins. These security bulletins will be most informative when +users of pip with TUF are unable to install or update a project because the +keys for the *timestamp*, *consistent-snapshot* or *root* roles are no longer +valid. They could then visit the PyPI web site to consult security bulletins +that would help to explain why they are no longer able to install or update, +and then take action accordingly. When a threshold number of *root* keys have +not been revoked due to a compromise, then new *root* metadata may be safely +updated because a threshold number of existing *root* keys will be used to sign +for the integrity of the new *root* metadata so that TUF clients will be able +to verify the integrity of the new *root* metadata with a threshold number of +previously known *root* keys. This will be the common case. Otherwise, in the +worst case where a threshold number of *root* keys have been revoked due to a +compromise, an end-user may choose to update new *root* metadata with +`out-of-band`__ mechanisms. + +__ https://en.wikipedia.org/wiki/Out-of-band#Authentication + + +Appendix: Rejected Proposals +============================ + + +Alternative Proposals for Producing Consistent Snapshots +-------------------------------------------------------- + +The complete file snapshot (CFS) scheme uses file system directories to store +efficient consistent snapshots over time. In this scheme, every consistent +snapshot will be stored in a separate directory, wherein files that are shared +with previous consistent snapshots will be `hard links`__ instead of copies. + +__ https://en.wikipedia.org/wiki/Hard_link + +The `differential file`__ snapshot (DFS) scheme is a variant of the CFS scheme, +wherein the next consistent snapshot directory will contain only the additions +of new files and updates to existing files of the previous consistent snapshot. +(The first consistent snapshot will contain a complete set of files known +then.) Deleted files will be marked as such in the next consistent snapshot +directory. This means that files will be resolved in this manner: First, set +the current consistent snapshot directory to be the latest consistent snapshot +directory. Then, any requested file will be seeked in the current consistent +snapshot directory. If the file exists in the current consistent snapshot +directory, then that file will be returned. If it has been marked as deleted +in the current consistent snapshot directory, then that file will be reported +as missing. Otherwise, the current consistent snapshot directory will be set +to the preceding consistent snapshot directory and the previous few steps will +be iterated until there is no preceding consistent snapshot to be considered, +at which point the file will be reported as missing. + +__ http://dl.acm.org/citation.cfm?id=320484 + +With the CFS scheme, the trade-off is the I/O costs of producing a consistent +snapshot with the file system. As of October 2013, we found that a fairly +modern computer with a 7200RPM hard disk drive required at least three minutes +to produce a consistent snapshot with the "cp -lr" command on the ext3__ file +system. Perhaps the I/O costs of this scheme may be ameliorated with advanced +tools or file systems such as ZFS__ or btrfs__. + +__ https://en.wikipedia.org/wiki/Ext3 +__ https://en.wikipedia.org/wiki/ZFS +__ https://en.wikipedia.org/wiki/Btrfs + +While the DFS scheme improves upon the CFS scheme in terms of producing faster +consistent snapshots, there are at least two trade-offs. The first is that a +web server will need to be modified to perform the "daisy chain" resolution of +a file. The second is that every now and then, the differential snapshots will +need to be "squashed" or merged together with the first consistent snapshot to +produce a new first consistent snapshot with the latest and complete set of +files. Although the merge cost may be amortized over time, this scheme is not +conceptually si + + + + +References +========== + +.. [1] https://pypi.python.org +.. [2] https://isis.poly.edu/~jcappos/papers/samuel_tuf_ccs_2010.pdf +.. [3] http://www.pip-installer.org +.. [4] https://wiki.python.org/moin/WikiAttack2013 +.. [5] https://github.com/theupdateframework/pip/wiki/Attacks-on-software-repositories +.. [6] https://mail.python.org/pipermail/distutils-sig/2013-April/020596.html +.. [7] https://mail.python.org/pipermail/distutils-sig/2013-May/020701.html +.. [8] https://mail.python.org/pipermail/distutils-sig/2013-July/022008.html +.. [9] PEP 381, Mirroring infrastructure for PyPI, Ziad?, L?wis + http://www.python.org/dev/peps/pep-0381/ +.. [10] https://mail.python.org/pipermail/distutils-sig/2013-September/022773.html +.. [11] https://mail.python.org/pipermail/distutils-sig/2013-May/020848.html +.. [12] PEP 449, Removal of the PyPI Mirror Auto Discovery and Naming Scheme, Stufft + http://www.python.org/dev/peps/pep-0449/ +.. [13] https://isis.poly.edu/~jcappos/papers/cappos_mirror_ccs_08.pdf +.. [14] https://mail.python.org/pipermail/distutils-sig/2013-September/022755.html +.. [15] https://pypi.python.org/security +.. [16] https://github.com/theupdateframework/tuf/blob/develop/docs/tuf-spec.txt +.. [17] PEP 426, Metadata for Python Software Packages 2.0, Coghlan, Holth, Stufft + http://www.python.org/dev/peps/pep-0426/ +.. [18] https://en.wikipedia.org/wiki/Continuous_delivery +.. [19] https://mail.python.org/pipermail/distutils-sig/2013-August/022154.html +.. [20] https://en.wikipedia.org/wiki/RSA_%28algorithm%29 +.. [21] https://en.wikipedia.org/wiki/Key-recovery_attack +.. [22] http://csrc.nist.gov/publications/nistpubs/800-57/SP800-57-Part1.pdf +.. [23] https://www.openssl.org/ +.. [24] https://pypi.python.org/pypi/pycrypto +.. [25] http://ed25519.cr.yp.to/ + + +Acknowledgements +================ + +Nick Coghlan, Daniel Holth and the distutils-sig community in general for +helping us to think about how to usably and efficiently integrate TUF with +PyPI. + +Roger Dingledine, Sebastian Hahn, Nick Mathewson, Martin Peck and Justin +Samuel for helping us to design TUF from its predecessor Thandy of the Tor +project. + +Konstantin Andrianov, Geremy Condra, Vladimir Diaz, Zane Fisher, Justin Samuel, +Tian Tian, Santiago Torres, John Ward, and Yuyu Zheng for helping us to develop +TUF. + +Vladimir Diaz, Monzur Muhammad and Sai Teja Peddinti for helping us to review +this PEP. + +Zane Fisher for helping us to review and transcribe this PEP. + + +Copyright +========= + +This document has been placed in the public domain. -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Wed Nov 19 12:44:54 2014 From: python-checkins at python.org (nick.coghlan) Date: Wed, 19 Nov 2014 11:44:54 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Split_PEP_458_into_two_distin?= =?utf-8?q?ct_PEPs?= Message-ID: <20141119114314.109162.47437@psf.io> https://hg.python.org/peps/rev/58644fa78931 changeset: 5602:58644fa78931 user: Nick Coghlan date: Wed Nov 19 21:43:04 2014 +1000 summary: Split PEP 458 into two distinct PEPs PEP 458 now focuses on content security (rather than the current transport-only security) between PyPI and end users. PEP 480 builds on PEP 458 to also provide end-to-end security that can fully handle a compromise of PyPI. files: pep-0458.txt | 1680 +++++++++++++++++++------------------ pep-0480.txt | 890 ++++++++++++++++++++ 2 files changed, 1737 insertions(+), 833 deletions(-) diff --git a/pep-0458.txt b/pep-0458.txt --- a/pep-0458.txt +++ b/pep-0458.txt @@ -2,10 +2,11 @@ Title: Surviving a Compromise of PyPI Version: $Revision$ Last-Modified: $Date$ -Author: Trishank Karthik Kuppusamy , - Donald Stufft , - Justin Cappos -Discussions-To: Distutils SIG +Author: Trishank Karthik Kuppusamy , + Vladimir Diaz , + Donald Stufft , Justin Cappos +BDFL-Delegate: Richard Jones +Discussions-To: DistUtils mailing list Status: Draft Type: Standards Track Content-Type: text/x-rst @@ -15,491 +16,632 @@ Abstract ======== -This PEP describes how the Python Package Index (PyPI [1]_) may be integrated -with The Update Framework [2]_ (TUF). TUF was designed to be a plug-and-play -security add-on to a software updater or package manager. TUF provides -end-to-end security like SSL, but for software updates instead of HTTP -connections. The framework integrates best security practices such as -separating responsibilities, adopting the many-man rule for signing packages, -keeping signing keys offline, and revocation of expired or compromised signing -keys. +This PEP proposes how the Python Package Index (PyPI [1]_) should be integrated +with The Update Framework [2]_ (TUF). TUF was designed to be a flexible +security add-on to a software updater or package manager. The framework +integrates best security practices such as separating role responsibilities, +adopting the many-man rule for signing packages, keeping signing keys offline, +and revocation of expired or compromised signing keys. For example, attackers +would have to steal multiple signing keys stored independently to compromise +a role responsible for specifying a repository's available files. Another role +responsible for indicating the latest snapshot of the repository may have to be +similarly compromised, and independent of the first compromised role. -The proposed integration will render modern package managers such as pip [3]_ -more secure against various types of security attacks on PyPI and protect users -against them. Even in the worst case where an attacker manages to compromise -PyPI itself, the damage is controlled in scope and limited in duration. +The proposed integration will allow modern package managers such as pip [3]_ to +be more secure against various types of security attacks on PyPI and protect +users from such attacks. Specifically, this PEP describes how PyPI processes +should be adapted to generate and incorporate TUF metadata (i.e., the minimum +security model). The minimum security model supports verification of PyPI +distributions that are signed with keys stored on PyPI: distributions uploaded +by developers are signed by PyPI, require no action from developers (other than +uploading the distribution), and are immediately available for download. The +minimum security model also minimizes PyPI administrative responsibilities by +automating much of the signing process. -Specifically, this PEP will describe how PyPI processes should be adapted to -incorporate TUF metadata. It will not prescribe how package managers such as -pip should be adapted to install or update with TUF metadata projects from -PyPI. +This PEP does not prescribe how package managers such as pip should be adapted +to install or update projects from PyPI with TUF metadata. Package managers +interested in adopting TUF on the client side may consult TUF's `library +documentation`__, which exists for this purpose. Support for project +distributions that are signed by developers (maximum security model) is also +not discussed in this PEP, but is outlined in the appendix as a possible future +extension and covered in detail in PEP X [VD: Link to PEP once it is +completed]. The PEP X extension focuses on the maximum security model, which +requires more PyPI administrative work (none by clients), but it also proposes +an easy-to-use key management solution for developers, how to interface with a +potential future build farm on PyPI infrastructure, and discusses the +feasibility of end-to-end signing. +__ https://github.com/theupdateframework/tuf/tree/develop/tuf/client#updaterpy -Rationale -========= + +Motivation +========== In January 2013, the Python Software Foundation (PSF) announced [4]_ that the python.org wikis for Python, Jython, and the PSF were subjected to a security -breach which caused all of the wiki data to be destroyed on January 5 2013. +breach that caused all of the wiki data to be destroyed on January 5, 2013. Fortunately, the PyPI infrastructure was not affected by this security breach. However, the incident is a reminder that PyPI should take defensive steps to protect users as much as possible in the event of a compromise. Attacks on -software repositories happen all the time [5]_. We must accept the possibility -of security breaches and prepare PyPI accordingly because it is a valuable -target used by thousands, if not millions, of people. +software repositories happen all the time [5]_. The PSF must accept the +possibility of security breaches and prepare PyPI accordingly because it is a +valuable resource used by thousands, if not millions, of people. -Before the wiki attack, PyPI used MD5 hashes to tell package managers such as -pip whether or not a package was corrupted in transit. However, the absence of -SSL made it hard for package managers to verify transport integrity to PyPI. -It was easy to launch a man-in-the-middle attack between pip and PyPI to change -package contents arbitrarily. This can be used to trick users into installing -malicious packages. After the wiki attack, several steps were proposed (some -of which were implemented) to deliver a much higher level of security than was -previously the case: requiring SSL to communicate with PyPI [6]_, restricting -project names [7]_, and migrating from MD5 to SHA-2 hashes [8]_. +Before the wiki attack, PyPI used MD5 hashes to tell package managers, such as +pip, whether or not a package was corrupted in transit. However, the absence +of SSL made it hard for package managers to verify transport integrity to PyPI. +It was therefore easy to launch a man-in-the-middle attack between pip and +PyPI, and change package content arbitrarily. Users could be tricked into +installing malicious packages with man-in-the-middle attacks. After the wiki +attack, several steps were proposed (some of which were implemented) to deliver +a much higher level of security than was previously the case: requiring SSL to +communicate with PyPI [6]_, restricting project names [7]_, and migrating from +MD5 to SHA-2 hashes [8]_. These steps, though necessary, are insufficient because attacks are still possible through other avenues. For example, a public mirror is trusted to honestly mirror PyPI, but some mirrors may misbehave due to malice or accident. Package managers such as pip are supposed to use signatures from PyPI to verify packages downloaded from a public mirror [9]_, but none are known to actually -do so [10]_. Therefore, it is also wise to add more security measures to +do so [10]_. Therefore, it would be wise to add more security measures to detect attacks from public mirrors or content delivery networks [11]_ (CDNs). Even though official mirrors are being deprecated on PyPI [12]_, there remain a -wide variety of other attack vectors on package managers [13]_. Among other -things, these attacks can crash client systems, cause obsolete packages to be -installed, or even allow an attacker to execute arbitrary code. In September -2013, we showed how the latest version of pip then was susceptible to these -attacks and how TUF could protect users against them [14]_. +wide variety of other attack vectors on package managers [13]_. These attacks +can crash client systems, cause obsolete packages to be installed, or even +allow an attacker to execute arbitrary code. In `September 2013`__, a post was +made to the Distutils mailing list showing that the latest version of pip (at +the time) was susceptible to such attacks, and how TUF could protect users +against them [14]_. Specifically, testing was done to see how pip would +respond to these attacks with and without TUF. Attacks tested included replay +and freeze, arbitrary packages, slow retrieval, and endless data. The post +also included a demonstration of how pip would respond if PyPI were +compromised. -Finally, PyPI allows for packages to be signed with GPG keys [15]_, although no -package manager is known to verify those signatures, thus negating much of the -benefits of having those signatures at all. Validating integrity through -cryptography is important, but issues such as immediate and secure key -revocation or specifying a required threshold number of signatures still -remain. Furthermore, GPG by itself does not immediately address the attacks -mentioned above. +__ https://mail.python.org/pipermail/distutils-sig/2013-September/022755.html -In order to protect PyPI against infrastructure compromises, we propose -integrating PyPI with The Update Framework [2]_ (TUF). +With the intent to protect PyPI against infrastructure compromises, this PEP +proposes integrating PyPI with The Update Framework [2]_ (TUF). TUF helps +secure new or existing software update systems. Software update systems are +vulnerable to many known attacks, including those that can result in clients +being compromised or crashed. TUF solves these problems by providing a flexible +security framework that can be added to software updaters. + + +Threat Model +============ + +The threat model assumes the following: + +* Offline keys are safe and securely stored. + +* Attackers can compromise at least one of PyPI's trusted keys stored online, + and may do so at once or over a period of time. + +* Attackers can respond to client requests. + +An attacker is considered successful if they can cause a client to install (or +leave installed) something other than the most up-to-date version of the +software the client is updating. If the attacker is preventing the installation +of updates, they want clients to not realize there is anything wrong. Definitions =========== -The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", +The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119__. __ http://www.ietf.org/rfc/rfc2119.txt -In order to keep this PEP focused solely on the application of TUF on PyPI, the -reader is assumed to already be familiar with the design principles of -TUF [2]_. It is also strongly RECOMMENDED that the reader be familiar with the -TUF specification [16]_. +This PEP focuses on integrating TUF with PyPI; however, the reader is +encouraged to read about TUF's design principles [2]_. It is also RECOMMENDED +that the reader be familiar with the TUF specification [16]_. + +Terms used in this PEP are defined as follows: * Projects: Projects are software components that are made available for - integration. Projects include Python libraries, frameworks, scripts, plugins, - applications, collections of data or other resources, and various + integration. Projects include Python libraries, frameworks, scripts, + plugins, applications, collections of data or other resources, and various combinations thereof. Public Python projects are typically registered on the Python Package Index [17]_. * Releases: Releases are uniquely identified snapshots of a project [17]_. -* Distributions: Distributions are the packaged files which are used to publish +* Distributions: Distributions are the packaged files that are used to publish and distribute a release [17]_. -* Simple index: The HTML page which contains internal links to the +* Simple index: The HTML page that contains internal links to the distributions of a project [17]_. + +* Roles: There is one *root* role in PyPI. There are multiple roles whose + responsibilities are delegated to them directly or indirectly by the *root* + role. The term top-level role refers to the *root* role and any role + delegated by the *root* role. Each role has a single metadata file that it is + trusted to provide. + +* Metadata: Metadata are signed files that describe roles, other metadata, and + target files. + +* Repository: A repository is a resource compromised of named metadata and + target files. Clients request metadata and target files stored on a + repository. * Consistent snapshot: A set of TUF metadata and PyPI targets that capture the - complete state of all projects on PyPI as they were at some fixed point in + complete state of all projects on PyPI as they existed at some fixed point in time. -* The *consistent-snapshot* (*release*) role: In order to prevent confusion due - to the different meanings of the term "release" as employed by PEP 426 [17]_ - and the TUF specification [16]_, we rename the *release* role as the - *consistent-snapshot* role. - -* Continuous delivery: A set of processes with which PyPI produces consistent - snapshots that can safely coexist and deleted independently [18]_. - +* The *snapshot* (*release*) role: In order to prevent confusion due to the + different meanings of the term "release" used in PEP 426 [17]_ and the TUF + specification [16]_, the *release* role is renamed as the *snapshot* role. + * Developer: Either the owner or maintainer of a project who is allowed to - update the TUF metadata as well as distribution metadata and data for the + update the TUF metadata as well as distribution metadata and files for the project. -* Online key: A key that MUST be stored on the PyPI server infrastructure. - This is usually to allow automated signing with the key. However, this means - that an attacker who compromises PyPI infrastructure will be able to read - these keys. +* Online key: A private cryptographic key that MUST be stored on the PyPI + server infrastructure. This is usually to allow automated signing with the + key. However, an attacker who compromises the PyPI infrastructure will be + able to read these keys. -* Offline key: A key that MUST be stored off the PyPI infrastructure. This - prevents automated signing with the key. This means that an attacker who - compromises PyPI infrastructure will not be able to immediately read these - keys. +* Offline key: A private cryptographic key that MUST be stored independent of + the PyPI server infrastructure. This prevents automated signing with the + key. An attacker who compromises the PyPI infrastructure will not be able to + immediately read these keys. -* Developer key: A private key for which its corresponding public key is - registered with PyPI to say that it is responsible for directly signing for - or delegating the distributions belonging to a project. For the purposes of - this PEP, it is offline in the sense that the private key MUST not be stored - on PyPI. However, the project is free to require certain developer keys to - be online on its own infrastructure. +* Threshold signature scheme: A role can increase its resilience to key + compromises by specifying that at least t out of n keys are REQUIRED to sign + its metadata. A compromise of t-1 keys is insufficient to compromise the + role itself. Saying that a role requires (t, n) keys denotes the threshold + signature property. -* Threshold signature scheme: A role could increase its resilience to key - compromises by requiring that at least t out of n keys are REQUIRED to sign - its metadata. This means that a compromise of t-1 keys is insufficient to - compromise the role itself. We denote this property by saying that the role - requires (t, n) keys. +Overview of TUF +=============== -Overview -======== +At its highest level, TUF provides applications with a secure method of +obtaining files and knowing when new versions of files are available. On the +surface, this all sounds simple. The basic steps for updating applications are: -.. image:: https://raw.github.com/theupdateframework/pep-on-pypi-with-tuf/master/figure1.png +* Knowing when an update exists. -Figure 1: A simplified overview of the roles in PyPI with TUF +* Downloading a correct copy of the latest version of an updated file. -Figure 1 shows a simplified overview of the roles that TUF metadata assume on -PyPI. The top-level *root* role signs for the keys of the top-level -*timestamp*, *consistent-snapshot*, *targets* and *root* roles. The -*timestamp* role signs for a new and consistent snapshot. The *consistent- -snapshot* role signs for the *root*, *targets* and all delegated targets -metadata. The *claimed* role signs for all projects that have registered their -own developer keys with PyPI. The *recently-claimed* role signs for all -projects that recently registered their own developer keys with PyPI. Finally, -the *unclaimed* role signs for all projects that have not registered developer -keys with PyPI. The *claimed*, *recently-claimed* and *unclaimed* roles are -numbered 1, 2, 3 respectively because a project will be searched for in each of -those roles in that descending order: first in *claimed*, then in -*recently-claimed* if necessary, and finally in *unclaimed* if necessary. +The problem is that updating applications is only simple when there are no +malicious activities in the picture. If an attacker is trying to interfere with +these seemingly simple steps, there is plenty they can do. -Every year, PyPI administrators are going to sign for *root* role keys. After -that, automation will continuously sign for a timestamped, consistent snapshot -of all projects. Every few months, PyPI administrators will move projects with -vetted developer keys from the *recently-claimed* role to the *claimed* role. -As we will soon see, they will sign for *claimed* with projects with offline -keys. +Assume a software updater takes the approach of most systems (at least the ones +that try to be secure). It downloads both the file it wants and a cryptographic +signature of the file. The software updater already knows which key it trusts +to make the signature. It checks that the signature is correct and was made by +this trusted key. Unfortunately, the software updater is still at risk in many +ways, including: -This PEP does not require project developers to use TUF to secure their -packages from attacks on PyPI. By default, all projects will be signed for by -the *unclaimed* role. If a project wishes stronger security guarantees, then -the project is strongly RECOMMENDED to register developer keys with PyPI so -that it may sign for its own distributions. By doing so, the project must -remain as a *recently-claimed* project until PyPI administrators have had an -opportunity to vet the developer keys of the project, after which the project -will be moved to the *claimed* role. +* An attacker keeps giving the software updater the same update file, so it + never realizes there is an update. -This PEP has **not** been designed to be backward-compatible for package -managers that do not use the TUF security protocol to install or update a -project from the PyPI described here. Instead, it is RECOMMENDED that PyPI -maintain a backward-compatible API of itself that does NOT offer TUF so that -older package managers that do not use TUF will be able to install or update -projects from PyPI as usual but without any of the security offered by TUF. -For the rest of this PEP, we will assume that PyPI will simultaneously maintain -a backward-incompatible API of itself for package managers that MUST use TUF to -securely install or update projects. We think that this approach represents a -reasonable trade-off: older package managers that do not TUF will still be able -to install or update projects without any TUF security from PyPI, and newer -package managers that do use TUF will be able to securely install or update -projects. At some point in the future, PyPI administrators MAY choose to -permanently deprecate the backward-compatible version of itself that does not -offer TUF metadata. +* An attacker gives the software updater an older, insecure version of a file + that it already has, so it downloads that one and blindly uses it thinking it + is newer. -Unless a mirror, CDN or the PyPI repository has been compromised, the end-user -will not be able to discern whether or not a package manager is using TUF to -install or update a project from PyPI. +* An attacker gives the software updater a newer version of a file it has but + it is not the newest one. The file is newer to the software updater, but it + may be insecure and exploitable by the attacker. +* An attacker compromises the key used to sign these files and now the software + updater downloads a malicious file that is properly signed. -Responsibility Separation +TUF is designed to address these attacks, and others, by adding signed metadata +(text files that describe the repository's files) to the repository and +referencing the metadata files during the update procedure. Repository files +are verified against the information included in the metadata before they are +handed off to the software update system. The framework also provides +multi-signature trust, explicit and implicit revocation of cryptograhic keys, +responsibility separation of the metadata, and minimizes key risk. For a full +list and outline of the repository attacks and software updater weaknesses +addressed by TUF, see Appendix A. + + +Integrating TUF with PyPI ========================= -Recall that TUF requires four top-level roles: *root*, *timestamp*, -*consistent-snapshot* and *targets*. The *root* role specifies the keys of all -the top-level roles (including itself). The *timestamp* role specifies the -latest consistent snapshot. The *consistent-snapshot* role specifies the -latest versions of all TUF metadata files (other than *timestamp*). The -*targets* role specifies available target files (in our case, it will be all -files on PyPI under the /simple and /packages directories). In this PEP, each -of these roles will serve their responsibilities without exception. +A software update system must complete two main tasks to integrate with TUF. +First, it must add the framework to the client side of the update system. For +example, TUF MAY be integrated with the pip package manager. Second, the +repository on the server side MUST be modified to provide signed TUF metadata. +This PEP is concerned with the second part of the integration, and the changes +required on PyPI to support software updates with TUF. -Our proposal offers two levels of security to developers. If developers opt in -to secure their projects with their own developer keys, then their projects -will be very secure. Otherwise, TUF will still protect them in many cases: -1. Minimum security (no action by a developer): protects *unclaimed* and - *recently-claimed* projects without developer keys from CDNs [19]_ or public - mirrors, but not from some PyPI compromises. This is because continuous - delivery requires some keys to be online. This level of security protects - projects from being accidentally or deliberately tampered with by a mirror - or a CDN because the mirror or CDN will not have any of the PyPI or - developer keys required to sign for projects. However, it would not protect - projects from attackers who have compromised PyPI because they will be able - to manipulate the TUF metadata for *unclaimed* projects with the appropriate - online keys. +What Additional Repository Files are Required on PyPI? +------------------------------------------------------ -2. Maximum security (developer signs their project): protects projects with - developer keys not only from CDNs or public mirrors, but also from some PyPI - compromises. This is because many important keys will be offline. This - level of security protects projects from being accidentally or deliberately - tampered with by a mirror or a CDN for reasons identical to the minimum - security level. It will also protect projects (or at least mitigate - damages) from the most likely attacks on PyPI. For example: given access to - online keys after a PyPI compromise, attackers will be able to freeze the - distributions for these projects, but they will not be able to serve - malicious distributions for these projects (not without compromising other - offline keys which would entail more risk, time and energy). Details for - the exact level of security offered is discussed in the section on key - management. +In order for package managers like pip to download and verify packages with +TUF, a few extra files MUST exist on PyPI. These extra repository files are +called TUF metadata. TUF metadata contains information such as which keys are +trustable, the cryptographic hashes of files, signatures to the metadata, +metadata version numbers, and the date after which the metadata should be +considered expired. -In order to complete support for continuous delivery, we propose three -delegated targets roles: +When a package manager wants to check for updates, it asks TUF to do the work. +That is, a package manager never has to deal with this additional metadata or +understand what's going on underneath. If TUF reports back that there are +updates available, a package manager can then ask TUF to download these files +from PyPI. TUF downloads them and checks them against the TUF metadata that it +also downloads from the repository. If the downloaded target files are +trustworthy, TUF then hands them over to the package manager. -1. *claimed*: Signs for the delegation of PyPI projects to their respective - developer keys. +The `Metadata`__ document provides information about each of the required +metadata and their expected content. The next section covers the different +kinds of metadata RECOMMENDED for PyPI. -2. *recently-claimed*: This role is almost identical to the *claimed* role and - could technically be performed by the *unclaimed* role, but there are two - important reasons why it exists independently: the first reason is to - improve the performance of looking up projects in the *unclaimed* role (by - moving metadata to the *recently-claimed* role instead), and the second - reason is to make it easier for PyPI administrators to move - *recently-claimed* projects to the *claimed* role. +__ https://github.com/theupdateframework/tuf/blob/develop/METADATA.md -3. *unclaimed*: Signs for PyPI projects without developer keys. -The *targets* role MUST delegate all PyPI projects to the three delegated -targets roles in the order of appearance listed above. This means that when -pip downloads with TUF a distribution from a project on PyPI, it will first -consult the *claimed* role about it. If the *claimed* role has delegated the -project, then pip will trust the project developers (in order of delegation) -about the TUF metadata for the project. Otherwise, pip will consult the -*recently-claimed* role about the project. If the *recently-claimed* role has -delegated the project, then pip will trust the project developers (in order of -delegation) about the TUF metadata for the project. Otherwise, pip will -consult the *unclaimed* role about the TUF metadata for the project. If the -*unclaimed* role has not delegated the project, then the project is considered -to be non-existent on PyPI. +PyPI and TUF Metadata +===================== -A PyPI project MAY begin without registering a developer key. Therefore, the -project will be signed for by the *unclaimed* role. After registering -developer keys, the project will be removed from the *unclaimed* role and -delegated to the *recently-claimed* role. After a probation period and a -vetting process to verify the developer keys of the project, the project will -be removed from the *recently-claimed* role and delegated to the *claimed* -role. +TUF metadata provides information that clients can use to make update +decisions. For example, a *targets* metadata lists the available distributions +on PyPI and includes the distribution's signatures, cryptographic hashes, and +file sizes. Different metadata files provide different information. The +various metadata files are signed by different roles, which are indicated by +the *root* role. The concept of roles allows TUF to delegate responsibilities +to multiple roles and minimizes the impact of a compromised role. -The *claimed* role offers maximum security, whereas the *recently-claimed* and -*unclaimed* role offer minimum security. All three roles support continuous -delivery of PyPI projects. +TUF requires four top-level roles. These are *root*, *timestamp*, *snapshot*, +and *targets*. The *root* role specifies the public cryptographic keys of the +top-level roles (including its own). The *timestamp* role references the +latest *snapshot* and can signify when a new snapshot of the repository is +available. The *snapshot* role indicates the latest version of all the TUF +metadata files (other than *timestamp*). The *targets* role lists the +available target files (in our case, it will be all files on PyPI under the +/simple and /packages directories). Each top-level role will serve its +responsibilities without exception. Figure 1 provides a table of the roles +used in TUF. -The *unclaimed* role offers minimum security because PyPI will sign for -projects without developer keys with an online key in order to permit -continuous delivery. +.. image:: figure1.png -The *recently-claimed* role offers minimum security because while the project -developers will sign for their own distributions with offline developer keys, -PyPI will sign with an online key the delegation of the project to those -offline developer keys. The signing of the delegation with an online key -allows PyPI administrators to continuously deliver projects without having to -continuously sign the delegation whenever one of those projects registers -developer keys. +Figure 1: An overview of the TUF roles. -Finally, the *claimed* role offers maximum security because PyPI will sign with -offline keys the delegation of a project to its offline developer keys. This -means that every now and then, PyPI administrators will vet developer keys and -sign the delegation of a project to those developer keys after being reasonably -sure about the ownership of the developer keys. The process for vetting -developer keys is out of the scope of this PEP. +Signing Metadata and Repository Management +------------------------------------------ -Metadata Management -=================== +The top-level *root* role signs for the keys of the top-level *timestamp*, +*snapshot*, *targets*, and *root* roles. The *timestamp* role signs for every +new snapshot of the repository metadata. The *snapshot* role signs for *root*, +*targets*, and all delegated roles. The *bins* roles (delegated roles) sign +for all distributions belonging to registered PyPI projects. -In this section, we examine the TUF metadata that PyPI must manage by itself, -and other TUF metadata that must be safely delegated to projects. Examples of -the metadata described here may be seen at our testbed mirror of -`PyPI-with-TUF`__. +Figure 2 provides an overview of the roles available within PyPI, which +includes the top-level roles and the roles delegated by *targets*. The figure +also indicates the types of keys used to sign each role and which roles are +trusted to sign for files available on PyPI. The next two sections cover the +details of signing repository files and the types of keys used for each role. -__ http://mirror1.poly.edu/ +.. image:: figure2.png -The metadata files that change most frequently will be *timestamp*, -*consistent-snapshot* and delegated targets (*claimed*, *recently-claimed*, -*unclaimed*, project) metadata. The *timestamp* and *consistent-snapshot* -metadata MUST be updated whenever *root*, *targets* or delegated targets -metadata are updated. Observe, though, that *root* and *targets* metadata are -much less likely to be updated as often as delegated targets metadata. -Therefore, *timestamp* and *consistent-snapshot* metadata will most likely be -updated frequently (possibly every minute) due to delegated targets metadata -being updated frequently in order to drive continuous delivery of projects. +Figure 2: An overview of the role metadata available on PyPI. -Consequently, the processes with which PyPI updates projects will have to be -updated accordingly, the details of which are explained in the following -subsections. +The roles that change most frequently are *timestamp*, *snapshot* and delegated +roles (*bins* and its delegated roles). The *timestamp* and *snapshot* +metadata MUST be updated whenever *root*, *targets* or delegated metadata are +updated. Observe, though, that *root* and *targets* metadata are much less +likely to be updated as often as delegated metadata. Therefore, *timestamp* +and *snapshot* metadata will most likely be updated frequently (possibly every +minute) due to delegated metadata being updated frequently in order to support +continuous delivery of projects. Continuous delivery is a set of processes +that PyPI uses produce snapshots that can safely coexist and be deleted +independent of other snapshots [18]_. +Every year, PyPI administrators SHOULD sign for *root* and *targets* role keys. +Automation will continuously sign for a timestamped, snapshot of all projects. +A `repository management`__ tool is available that can sign metadata files, +generate cryptographic keys, and manage a TUF repository. -Why Do We Need Consistent Snapshots? ------------------------------------- +__ https://github.com/theupdateframework/tuf/tree/develop/tuf#repository-management -In an ideal world, metadata and data should be immediately updated and -presented whenever a project is updated. In practice, there will be problems -when there are many readers and writers who access the same metadata or data at -the same time. -An important example at the time of writing is that, mirrors are very likely, -as far as we can tell, to update in an inconsistent manner from PyPI as it is -without TUF. Specifically, a mirror would update itself in such a way that -project A would be from time T, whereas project B would be from time T+5, -project C would be from time T+3, and so on where T is the time that the mirror -first begun updating itself. There is no known way for a mirror to update -itself such that it captures the state of all projects as they were at time T. +How to Establish Initial Trust in the PyPI Root Keys +---------------------------------------------------- -Adding TUF to PyPI will not automatically solve the problem. Consider what we -call the `"inverse replay" or "fast-forward" problem`__. Suppose that PyPI has -timestamped a consistent snapshot at version 1. A mirror is later in the -middle of copying PyPI at this snapshot. While the mirror is copying PyPI at -this snapshot, PyPI timestamps a new snapshot at, say, version 2. Without -accounting for consistency, the mirror would then find itself with a copy of -PyPI in an inconsistent state which is indistinguishable from arbitrary -metadata or target attacks. The problem would also apply when the mirror is -substituted with a pip user. +Package managers like pip need to ship a file called "root.json" with the +installation files that users initially download. This includes information +about the keys trusted for certain roles, as well as the root keys themselves. +Any new version of "root.json" that clients may download are verified against +the root keys that client's initially trust. If a root key is compromised, but +a threshold of keys are still secured, the PyPI administrator MUST push a new +release that revokes trust in the compromised keys. If a threshold of root keys +are compromised, then "root.json" should be updated out-of-band, however the +threshold should be chosen so that this is extremely unlikely. The TUF client +library does not require manual intervention if root keys are revoked or added: +the update process handles the cases where "root.json" has changed. -__ https://groups.google.com/forum/#!topic/theupdateframework/8mkR9iqivQA +To bundle the software, "root.json" MUST be included in the version of pip +shipped with CPython (via ensurepip). The TUF client library then loads the +root metadata and downloads the rest of the roles, including updating +"root.json" if it has changed. An `outline of the update process`__ is +available. -Therefore, the problem can be summarized as such: there are problems of -consistency on PyPI with or without TUF. TUF requires its metadata to be -consistent with the data, but how would the metadata be kept consistent with -projects that change all the time? +__ https://github.com/theupdateframework/tuf/tree/develop/tuf/client#overview-of-the-update-process. -As a result, we will solve for PyPI the problem of producing a consistent + +Minimum Security Model +---------------------- + +There are two security models to consider when integrating TUF with PyPI. The +one proposed in this PEP is the minimum security model, which supports +verification of PyPI distributions that are signed with private cryptographic +keys stored on PyPI. Distributions uploaded by developers are signed by PyPI +and immediately available for download. A possible future extension to this +PEP, discussed in Appendix B, proposes the maximum security model and allows a +developer to sign for his/her project. Developer keys are not stored online: +therefore, projects are safe from PyPI compromises. + +The minimum security model requires no action from a developer and protects +against malicious CDNs [19]_ and public mirrors. To support continuous +delivery of uploaded packages, PyPI signs for projects with an online key. +This level of security prevents projects from being accidentally or +deliberately tampered with by a mirror or a CDN because the mirror or CDN will +not have any of the keys required to sign for projects. However, it does not +protect projects from attackers who have compromised PyPI, since attackers can +manipulate TUF metadata using the keys stored online. + +This PEP proposes that the *bins* role (and its delegated roles) sign for all +PyPI projects with an online key. The *targets* role, which only signs with an +offline key, MUST delegate all PyPI projects to the *bins* role. This means +that when a package manager such as pip (i.e., using TUF) downloads a +distribution from a project on PyPI, it will consult the *bins* role about the +TUF metadata for the project. If no bin roles delegated by *bins* specify the +project's distribution, then the project is considered to be non-existent on +PyPI. + + +Metadata Expiry Times +--------------------- + +The *root* and *targets* role metadata SHOULD expire in one year, because these +two metadata files are expected to change very rarely. + +The *timestamp*, *snapshot*, and *bins* metadata SHOULD expire in one day +because a CDN or mirror SHOULD synchronize itself with PyPI every day. +Furthermore, this generous time frame also takes into account client clocks +that are highly skewed or adrift. + + +Metadata Scalability +-------------------- + +Due to the growing number of projects and distributions, TUF metadata will also +grow correspondingly. For example, consider the *bins* role. In August 2013, +it was found that the size of the *bins* metadata was about 42MB if the *bins* +role itself signed for about 220K PyPI targets (which are simple indices and +distributions). This PEP does not delve into the details, but TUF features a +so-called "`lazy bin walk`__" scheme that splits a large targets' metadata file +into many small ones. This allows a TUF client updater to intelligently +download only a small number of TUF metadata files in order to update any +project signed for by the *bins* role. For example, applying this scheme to +the previous repository resulted in pip downloading between 1.3KB and 111KB to +install or upgrade a PyPI project via TUF. + +__ https://github.com/theupdateframework/tuf/issues/39 + +Based on our findings as of the time of writing, PyPI SHOULD split all targets +in the *bins* role by delegating them to 1024 delegated roles, each of which +would sign for PyPI targets whose hashes fall into that "bin" or delegated role +(see Figure 2). It was found that 1024 bins would result in the *bins* +metadata, and each of its delegated roles, being about the same size (40-50KB) +for about 220K PyPI targets (simple indices and distributions). + +It is possible to make TUF metadata more compact by representing it in a binary +format as opposed to the JSON text format. Nevertheless, a sufficiently large +number of projects and distributions will introduce scalability challenges at +some point, and therefore the *bins* role will still need delegations (as +outlined in figure 2) in order to address the problem. Furthermore, the JSON +format is an open and well-known standard for data interchange. Due to the +large number of delegated metadata, compressed versions of *snapshot* metadata +SHOULD also be made available to clients. + + +PyPI and Key Requirements +========================= + +In this section, the kinds of keys required to sign for TUF roles on PyPI are +examined. TUF is agnostic with respect to choices of digital signature +algorithms. For the purpose of discussion, it is assumed that most digital +signatures will be produced with the well-tested and tried RSA algorithm [20]_. +Nevertheless, we do NOT recommend any particular digital signature algorithm in +this PEP because there are a few important constraints: first, cryptography +changes over time; second, package managers such as pip may wish to perform +signature verification in Python, without resorting to a compiled C library, in +order to be able to run on as many systems as Python supports; and third, TUF +recommends diversity of keys for certain applications. + + +Number Of Keys Recommended +-------------------------- + +The *timestamp*, *snapshot*, and *bins* roles require continuous delivery. +Even though their respective keys MUST be online, this PEP requires that the +keys be independent of each other. Different keys for online roles allow for +each of the keys to be placed on separate servers if need be, and prevents side +channel attacks that compromise one key from automatically compromising the +rest of the keys. Therefore, each of the *timestamp*, *snapshot*, and *bins* +roles MUST require (1, 1) keys. + +The *bins* role MAY delegate targets in an automated manner to a number of +roles called "bins", as discussed in the previous section. Each of the "bin" +roles SHOULD share the same key as the *bins* role, due to space efficiency, +and because there is no security advantage to requiring separate keys. + +The *root* role key is critical for security and should very rarely be used. +It is primarily used for key revocation, and it is the locus of trust for all +of PyPI. The *root* role signs for the keys that are authorized for each of +the top-level roles (including its own). Keys belonging to the *root* role are +intended to be very well-protected and used with the least frequency of all +keys. It is RECOMMENDED that every PSF board member own a (strong) root key. +A majority of them can then constitute a quorum to revoke or endow trust in all +top-level keys. Alternatively, the system administrators of PyPI could be +given responsibility for signing for the *root* role. Therefore, the *root* +role SHOULD require (t, n) keys, where n is the number of either all PyPI +administrators or all PSF board members, and t > 1 (so that at least two +members must sign the *root* role). + +The *targets* role will be used only to sign for the static delegation of all +targets to the *bins* role. Since these target delegations must be secured +against attacks in the event of a compromise, the keys for the *targets* role +MUST be offline and independent of other keys. For simplicity of key +management, without sacrificing security, it is RECOMMENDED that the keys of +the *targets* role be permanently discarded as soon as they have been created +and used to sign for the role. Therefore, the *targets* role SHOULD require +(1, 1) keys. Again, this is because the keys are going to be permanently +discarded and more offline keys will not help resist key recovery attacks [21]_ +unless diversity of keys is maintained. + + +Online and Offline Keys Recommended for Each Role +------------------------------------------------- + +In order to support continuous delivery, the *timestamp*, *snapshot*, *bins* +role keys MUST be online. + +As explained in the previous section, the *root* and *targets* role keys MUST +be offline for maximum security: these keys will be offline in the sense that +their private keys MUST NOT be stored on PyPI, though some of them MAY be +online in the private infrastructure of the project. + + +How Should Metadata be Generated? +================================= + +Project developers expect the distributions they upload to PyPI to be +immediately available for download. Unfortunately, there will be problems when +many readers and writers simultaneously access the same metadata and +distributions. That is, there needs to be a way to ensure consistency of +metadata and repository files when multiple developers simulaneously change the +same metadata or distributions. There are also issues with consistency on PyPI +without TUF, but the problem is more severe with signed metadata that MUST keep +track of the files available on PyPI in real-time. + +Suppose that PyPI generates a *snapshot*, which indicates the latest version of +every metadata except *timestamp*, at version 1 and a client requests this +*snapshot* from PyPI. While the client is busy downloading this *snapshot*, +PyPI then timestamps a new snapshot at, say, version 2. Without ensuring +consistency of metadata, the client would find itself with a copy of *snapshot* +that disagrees with what is available on PyPI, which is indistinguishable from +arbitrary metadata injected by an attacker. The problem would also occur for +mirrors attempting to sync with PyPI. + + +Consistent Snapshots +-------------------- + +There are problems with consistency on PyPI with or without TUF. TUF requires +that its metadata be consistent with the repository files, but how would the +metadata be kept consistent with projects that change all the time? As a +result, this proposal MUST address the problem of producing a consistent snapshot that captures the state of all known projects at a given time. Each -consistent snapshot can safely coexist with any other consistent snapshot and -deleted independently without affecting any other consistent snapshot. +snapshot should safely coexist with any other snapshot, and be able to be +deleted independently, without affecting any other snapshot. -The gist of the solution is that every metadata or data file written to disk -MUST include in its filename the `cryptographic hash`__ of the file. How would -this help clients which use the TUF protocol to securely and consistently -install or update a project from PyPI? +The solution presented in this PEP is that every metadata or data file managed +by PyPI and written to disk MUST include in its filename the `cryptographic +hash`__ of the file. How would this help clients that use the TUF protocol to +securely and consistently install or update a project from PyPI? __ https://en.wikipedia.org/wiki/Cryptographic_hash_function -Recall that the first step in the TUF protocol requires the client to download -the latest *timestamp* metadata. However, the client would not know in advance -the hash of the *timestamp* metadata file from the latest consistent snapshot. -Therefore, PyPI MUST redirect all HTTP GET requests for *timestamp* metadata to -the *timestamp* metadata file from the latest consistent snapshot. Since the -*timestamp* metadata is the root of a tree of cryptographic hashes pointing to -every other metadata or target file that are meant to exist together for -consistency, the client is then able to retrieve any file from this consistent -snapshot by deterministically including, in the request for the file, the hash -of the file in the filename. Assuming infinite disk space and no `hash -collisions`__, a client may safely read from one consistent snapshot while PyPI -produces another consistent snapshot. +The first step in the TUF protocol requires the client to download the latest +*timestamp* metadata. However, the client would not know in advance the hash +of the *timestamp* associated with the latest snapshot. Therefore, PyPI MUST +redirect all HTTP GET requests for *timestamp* to the *timestamp* referenced in +the latest snapshot. The *timestamp* role is the root of a tree of +cryptographic hashes that points to every other metadata that is meant to exist +together (i.e., clients request metadata in timestamp -> snapshot -> root -> +targets order). Clients are able to retrieve any file from this snapshot +by deterministically including, in the request for the file, the hash of the +file in the filename. Assuming infinite disk space and no `hash collisions`__, +a client may safely read from one snapshot while PyPI produces another +snapshot. __ https://en.wikipedia.org/wiki/Collision_(computer_science) -In this simple but effective manner, we are able to capture a consistent +In this simple but effective manner, PyPI is able to capture a consistent snapshot of all projects and the associated metadata at a given time. The next -subsection will explicate the implementation details of this idea. +subsection provides implementation details of this idea. + +Note: This PEP does not prohibit using advanced file systems or tools to +produce consistent snapshots. There are two important reasons for why this PEP +proposes the simple solution. First, the solution does not mandate that PyPI +use any particular file system or tool. Second, the generic file-system based +approach allows mirrors to use extant file transfer tools such as rsync to +efficiently transfer consistent snapshots from PyPI. Producing Consistent Snapshots ------------------------------ -Given a project, PyPI is responsible for updating, depending on the project, -either the *claimed*, *recently-claimed* or *unclaimed* metadata as well as -associated delegated targets metadata. Every project MUST upload its set of -metadata and targets in a single transaction. We will call this set of files -the project transaction. We will discuss later how PyPI MAY validate the files -in a project transaction. For now, let us focus on how PyPI will respond to a -project transaction. We will call this response the project transaction -process. There will also be a consistent snapshot process that we will define -momentarily; for now, it suffices to know that project transaction processes -and the consistent snapshot process must coordinate with each other. +Given a project, PyPI is responsible for updating the *bins* metadata (roles +delegated by the *bins* role and signed with an online key). Every project +MUST upload its release in a single transaction. The uploaded set of files is +called the "project transaction". How PyPI MAY validate the files in a project +transaction is discussed in a later section. For now, the focus is on how PyPI +will respond to a project transaction. -Also, every metadata and target file MUST include in its filename the `hex -digest`__ of its `SHA-256`__ hash. For this PEP, it is RECOMMENDED that PyPI -adopt a simple convention of the form filename.digest.ext, where filename is -the original filename without a copy of the hash, digest is the hex digest of -the hash, and ext is the filename extension. +Every metadata and target file MUST include in its filename the `hex digest`__ +of its `SHA-256`__ hash. For this PEP, it is RECOMMENDED that PyPI adopt a +simple convention of the form: digest.filename, where filename is the original +filename without a copy of the hash, and digest is the hex digest of the hash. __ http://docs.python.org/2/library/hashlib.html#hashlib.hash.hexdigest __ https://en.wikipedia.org/wiki/SHA-2 -When an *unclaimed* project uploads a new transaction, a project transaction -process MUST add all new targets and relevant delegated *unclaimed* metadata. -(We will see later in this section why the *unclaimed* role will delegate -targets to a number of delegated *unclaimed* roles.) Finally, the project -transaction process MUST inform the consistent snapshot process about new -delegated *unclaimed* metadata. +When a project uploads a new transaction, the project transaction process MUST +add all new targets and relevant delegated *bins* metadata. (It is shown later +in this section why the *bins* role will delegate targets to a number of +delegated *bins* roles.) Finally, the project transaction process MUST inform +the snapshot process about new delegated *bins* metadata. -When a *recently-claimed* project uploads a new a transaction, a project -transaction process MUST add all new targets and delegated targets metadata for -the project. If the project is new, then the project transaction process MUST -also add new *recently-claimed* metadata with public keys and threshold number -(which MUST be part of the transaction) for the project. Finally, the project -transaction process MUST inform the consistent snapshot process about new -*recently-claimed* metadata as well as the current set of delegated targets -metadata for the project. - -The process for a *claimed* project is slightly different. The difference is -that PyPI administrators will choose to move the project from the -*recently-claimed* role to the *claimed* role. A project transaction process -MUST then add new *recently-claimed* and *claimed* metadata to reflect this -migration. As is the case for a *recently-claimed* project, the project -transaction process MUST always add all new targets and delegated targets -metadata for the *claimed* project. Finally, the project transaction process -MUST inform the consistent snapshot process about new *recently-claimed* or -*claimed* metadata as well as the current set of delegated targets metadata for -the project. - -Project transaction processes SHOULD be automated, except when PyPI -administrators move a project from the *recently-claimed* role to the *claimed* -role. Project transaction processes MUST also be applied atomically: either -all metadata and targets, or none of them, are added. The project transaction -processes and consistent snapshot process SHOULD work concurrently. Finally, -project transaction processes SHOULD keep in memory the latest *claimed*, -*recently-claimed* and *unclaimed* metadata so that they will be correctly -updated in new consistent snapshots. +Project transaction processes SHOULD be automated and MUST also be applied +atomically: either all metadata and targets -- or none of them -- are added. +The project transaction and snapshot processes SHOULD work concurrently. +Finally, project transaction processes SHOULD keep in memory the latest *bins* +metadata so that they will be correctly updated in new consistent snapshots. All project transactions MAY be placed in a single queue and processed serially. Alternatively, the queue MAY be processed concurrently in order of -appearance provided that the following rules are observed: +appearance, provided that the following rules are observed: 1. No pair of project transaction processes must concurrently work on the same project. 2. No pair of project transaction processes must concurrently work on - *unclaimed* projects that belong to the same delegated *unclaimed* targets + *bins* projects that belong to the same delegated *bins* targets role. -3. No pair of project transaction processes must concurrently work on new - *recently-claimed* projects. - -4. No pair of project transaction processes must concurrently work on new - *claimed* projects. - -5. No project transaction process must work on a new *claimed* project while - another project transaction process is working on a new *recently-claimed* - project and vice versa. - These rules MUST be observed so that metadata is not read from or written to inconsistently. -The consistent snapshot process is fairly simple and SHOULD be automated. The -consistent snapshot process MUST keep in memory the latest working set of -*root*, *targets* and delegated targets metadata. Every minute or so, the -consistent snapshot process will sign for this latest working set. (Recall -that project transaction processes continuously inform the consistent snapshot -process about the latest delegated targets metadata in a concurrency-safe -manner. The consistent snapshot process will actually sign for a copy of the -latest working set while the actual latest working set in memory will be -updated with information continuously communicated by project transaction -processes.) Next, the consistent snapshot process MUST generate and sign new -*timestamp* metadata that will vouch for the *consistent-snapshot* metadata -generated in the previous step. Finally, the consistent snapshot process MUST -add new *timestamp* and *consistent-snapshot* metadata representing the latest -consistent snapshot. + +Snapshot Process +---------------- + +The snapshot process is fairly simple and SHOULD be automated. The snapshot +process MUST keep in memory the latest working set of *root*, *targets*, and +delegated roles. Every minute or so, the snapshot process will sign for this +latest working set. (Recall that project transaction processes continuously +inform the snapshot process about the latest delegated metadata in a +concurrency-safe manner. The snapshot process will actually sign for a copy of +the latest working set while the latest working set in memory will be updated +with information that is continuously communicated by the project transaction +processes.) The snapshot process MUST generate and sign new *timestamp* +metadata that will vouch for the metadata (*root*, *targets*, and delegated +roles) generated in the previous step. Finally, the snapshot process MUST make +available to clients the new *timestamp* and *snapshot* metadata representing +the latest snapshot. A few implementation notes are now in order. So far, we have seen only that new metadata and targets are added, but not that old metadata and targets are @@ -508,30 +650,19 @@ use something like a "mark-and-sweep" algorithm to delete sufficiently old consistent snapshots: in order to preserve the latest consistent snapshot, PyPI would walk objects beginning from the root (*timestamp*) of the latest -consistent snapshot, mark all visited objects, and delete all unmarked -objects. The last few consistent snapshots may be preserved in a similar -fashion. Deleting a consistent snapshot will cause clients to see nothing -thereafter but HTTP 404 responses to any request for a file in that consistent -snapshot. Clients SHOULD then retry their requests with the latest consistent +consistent snapshot, mark all visited objects, and delete all unmarked objects. +The last few consistent snapshots may be preserved in a similar fashion. +Deleting a consistent snapshot will cause clients to see nothing except HTTP +404 responses to any request for a file within that consistent snapshot. +Clients SHOULD then retry (as before) their requests with the latest consistent snapshot. -We do **not** consider updates to any consistent snapshot because `hash -collisions`__ are out of the scope of this PEP. In case a hash collision is -observed, PyPI MAY wish to check that the file being added is identical to the -file already stored. (Should a hash collision be observed, it is far more -likely the case that the file is identical rather than being a genuine -`collision attack`__.) Otherwise, PyPI MAY either overwrite the existing file -or ignore any write operation to an existing file. - -__ https://en.wikipedia.org/wiki/Collision_(computer_science) -__ https://en.wikipedia.org/wiki/Collision_attack - All clients, such as pip using the TUF protocol, MUST be modified to download every metadata and target file (except for *timestamp* metadata) by including, -in the request for the file, the hash of the file in the filename. Following -the filename convention recommended earlier, a request for the file at -filename.ext will be transformed to the equivalent request for the file at -filename.digest.ext. +in the request for the file, the cryptographic hash of the file in the +filename. Following the filename convention recommended earlier, a request for +the file at filename.ext will be transformed to the equivalent request for the +file at digest.filename. Finally, PyPI SHOULD use a `transaction log`__ to record project transaction processes and queues so that it will be easier to recover from errors after a @@ -540,487 +671,367 @@ __ https://en.wikipedia.org/wiki/Transaction_log -Metadata Validation -------------------- +Key Compromise Analysis +======================= -A *claimed* or *recently-claimed* project will need to upload in its -transaction to PyPI not just targets (a simple index as well as distributions) -but also TUF metadata. The project MAY do so by uploading a ZIP file -containing two directories, /metadata/ (containing delegated targets metadata -files) and /targets/ (containing targets such as the project simple index and -distributions which are signed for by the delegated targets metadata). +This PEP has covered the minimum security model, the TUF roles that should be +added to support continuous delivery of distributions, and how to generate and +sign the metadata of each role. The remaining sections discuss how PyPI +SHOULD audit repository metadata, and the methods PyPI can use to detect and +recover from a PyPI compromise. -Whenever the project uploads metadata or targets to PyPI, PyPI SHOULD check the -project TUF metadata for at least the following properties: +Table 1 summarizes a few of the attacks possible when a threshold number of +private cryptographic keys (belonging to any of the PyPI roles) are +compromised. The leftmost column lists the roles (or a combination of roles) +that have been compromised, and the columns to its right show whether the +compromised roles leaves clients susceptible to malicious updates, a freeze +attack, or metadata inconsistency attacks. -* A threshold number of the developers keys registered with PyPI by that - project MUST have signed for the delegated targets metadata file that - represents the "root" of targets for that project (e.g. metadata/targets/ - project.txt). ++-----------------+-------------------+----------------+--------------------------------+ +| Role Compromise | Malicious Updates | Freeze Attack | Metadata Inconsistency Attacks | ++=================+===================+================+================================+ +| timestamp | NO | YES | NO | +| | snapshot and | limited by | snapshot needs to cooperate | +| | targets or any | earliest root, | | +| | of the bins need | targets, or | | +| | to cooperate | bin expiry | | +| | | time | | ++-----------------+-------------------+----------------+--------------------------------+ +| snapshot | NO | NO | NO | +| | timestamp and | timestamp | timestamp needs to cooperate | +| | targets or any of | needs to | | +| | the bins need to | cooperate | | +| | cooperate | | | ++-----------------+-------------------+----------------+--------------------------------+ +| timestamp | NO | YES | YES | +| **AND** | targets or any | limited by | limited by earliest root, | +| snapshot | of the bins need | earliest root, | targets, or bin metadata | +| | to cooperate | targets, or | expiry time | +| | | bin metadata | | +| | | expiry time | | ++-----------------+-------------------+----------------+--------------------------------+ +| targets | NO | NOT APPLICABLE | NOT APPLICABLE | +| **OR** | timestamp and | need timestamp | need timestamp and snapshot | +| bin | snapshot need to | and snapshot | | +| | cooperate | | | ++-----------------+-------------------+----------------+--------------------------------+ +| timestamp | YES | YES | YES | +| **AND** | | limited by | limited by earliest root, | +| snapshot | | earliest root, | targets, or bin metadata | +| **AND** | | targets, or | expiry time | +| bin | | bin metadata | | +| | | expiry time | | ++-----------------+-------------------+----------------+--------------------------------+ +| root | YES | YES | YES | ++-----------------+-------------------+----------------+--------------------------------+ -* The signatures of delegated targets metadata files MUST be valid. +Table 1: Attacks possible by compromising certain combinations of role keys. +In `September 2013`__, it was shown how the latest version (at the time) of pip +was susceptible to these attacks and how TUF could protect users against them +[14]_. -* The delegated targets metadata files MUST NOT be expired. +__ https://mail.python.org/pipermail/distutils-sig/2013-September/022755.html -* The delegated targets metadata MUST be consistent with the targets. - -* A delegator MUST NOT delegate targets that were not delegated to itself by - another delegator. - -* A delegatee MUST NOT sign for targets that were not delegated to itself by a - delegator. - -* Every file MUST contain a unique copy of its hash in its filename following - the filename.digest.ext convention recommended earlier. - -If PyPI chooses to check the project TUF metadata, then PyPI MAY choose to -reject publishing any set of metadata or targets that do not meet these -requirements. - -PyPI MUST enforce access control by ensuring that each project can only write -to the TUF metadata for which it is responsible. It MUST do so by ensuring -that project transaction processes write to the correct metadata as well as -correct locations within those metadata. For example, a project transaction -process for an *unclaimed* project MUST write to the correct target paths in -the correct delegated *unclaimed* metadata for the targets of the project. - -On rare occasions, PyPI MAY wish to extend the TUF metadata format for projects -in a backward-incompatible manner. Note that PyPI will NOT be able to -automatically rewrite existing TUF metadata on behalf of projects in order to -upgrade the metadata to the new backward-incompatible format because this would -invalidate the signatures of the metadata as signed by developer keys. -Instead, package managers SHOULD be written to recognize and handle multiple -incompatible versions of TUF metadata so that *claimed* and *recently-claimed* -projects could be offered a reasonable time to migrate their metadata to newer -but backward-incompatible formats. - -The details of how each project manages its TUF metadata is beyond the scope of -this PEP. - - -Mirroring Protocol ------------------- - -The mirroring protocol as described in PEP 381 [9]_ SHOULD change to mirror -PyPI with TUF. - -A mirror SHOULD have to maintain for its clients only one consistent snapshot -which would represent the latest consistent snapshot from PyPI known to the -mirror. The mirror would then serve all HTTP requests for metadata or targets -by simply reading directly from this consistent snapshot directory. - -The mirroring protocol itself is fairly simple. The mirror would ask PyPI for -*timestamp* metadata from the latest consistent snapshot and proceed to copy -the entire consistent snapshot from the *timestamp* metadata onwards. If the -mirror encounters a failure to copy any metadata or target file while copying -the consistent snapshot, it SHOULD retrying resuming the copy of that -particular consistent snapshot. If PyPI has deleted that consistent snapshot, -then the mirror SHOULD delete the failed consistent snapshot and try -downloading the latest consistent snapshot instead. - -The mirror SHOULD point users to a previous consistent snapshot directory while -it is copying the latest consistent snapshot from PyPI. Only after the latest -consistent snapshot has been completely copied SHOULD the mirror switch clients -to the latest consistent snapshot. The mirror MAY then delete the previous -consistent snapshot once it finds that no client is reading from the previous -consistent snapshot. - -The mirror MAY use extant file transfer software such as rsync__ to mirror -PyPI. In that case, the mirror MUST first obtain the latest known timestamp -metadata from PyPI. The mirror MUST NOT immediately publish the latest known -timestamp metadata from PyPI. Instead, the mirror MUST first iteratively -transfer all new files from PyPI until there are no new files left to transfer. -Finally, the mirror MUST publish the latest known timestamp it fetched from -PyPI so that package managers such as pip may be directed to the latest -consistent snapshot known to the mirror. - -__ https://rsync.samba.org/ - - -Backup Process --------------- - -In order to be able to safely restore from static snapshots later in the event -of a compromise, PyPI SHOULD maintain a small number of its own mirrors to copy -PyPI consistent snapshots according to some schedule. The mirroring protocol -can be used immediately for this purpose. The mirrors must be secured and -isolated such that they are responsible only for mirroring PyPI. The mirrors -can be checked against one another to detect accidental or malicious failures. - - -Metadata Expiry Times ---------------------- - -The *root* and *targets* role metadata SHOULD expire in a year, because these -metadata files are expected to change very rarely. - -The *claimed* role metadata SHOULD expire in three to six months, because this -metadata is expected to be refreshed in that time frame. This time frame was -chosen to induce an easier administration process for PyPI. - -The *timestamp*, *consistent-snapshot*, *recently-claimed* and *unclaimed* role -metadata SHOULD expire in a day because a CDN or mirror SHOULD synchronize -itself with PyPI every day. Furthermore, this generous time frame also takes -into account client clocks that are highly skewed or adrift. - -The expiry times for the delegated targets metadata of a project is beyond the -scope of this PEP. - - -Metadata Scalability --------------------- - -Due to the growing number of projects and distributions, the TUF metadata will -also grow correspondingly. - -For example, consider the *unclaimed* role. In August 2013, we found that the -size of the *unclaimed* role metadata was about 42MB if the *unclaimed* role -itself signed for about 220K PyPI targets (which are simple indices and -distributions). We will not delve into details in this PEP, but TUF features a -so-called "`lazy bin walk`__" scheme which splits a large targets or delegated -targets metadata file into many small ones. This allows a TUF client updater -to intelligently download only a small number of TUF metadata files in order to -update any project signed for by the *unclaimed* role. For example, applying -this scheme to the previous repository resulted in pip downloading between -1.3KB and 111KB to install or upgrade a PyPI project via TUF. - -__ https://github.com/theupdateframework/tuf/issues/39 - -From our findings as of the time of writing, PyPI SHOULD split all targets in -the *unclaimed* role by delegating it to 1024 delegated targets role, each of -which would sign for PyPI targets whose hashes fall into that "bin" or -delegated targets role. We found that 1024 bins would result in the -*unclaimed* role metadata and each of its binned delegated targets role -metadata to be about the same size (40-50KB) for about 220K PyPI targets -(simple indices and distributions). - -It is possible to make the TUF metadata more compact by representing it in a -binary format as opposed to the JSON text format. Nevertheless, we believe -that a sufficiently large number of project and distributions will induce -scalability challenges at some point, and therefore the *unclaimed* role will -then still need delegations in order to address the problem. Furthermore, the -JSON format is an open and well-known standard for data interchange. - -Due to the large number of delegated target metadata files, compressed versions -of *consistent-snapshot* metadata SHOULD also be made available. - - -Key Management -============== - -In this section, we examine the kind of keys required to sign for TUF roles on -PyPI. TUF is agnostic with respect to choices of digital signature algorithms. -For the purpose of discussion, we will assume that most digital signatures will -be produced with the well-tested and tried RSA algorithm [20]_. Nevertheless, -we do NOT recommend any particular digital signature algorithm in this PEP -because there are a few important constraints: firstly, cryptography changes -over time; secondly, package managers such as pip may wish to perform signature -verification in Python, without resorting to a compiled C library, in order to -be able to run on as many systems as Python supports; finally, TUF recommends -diversity of keys for certain applications, and we will soon discuss these -exceptions. - - -Number Of Keys --------------- - -The *timestamp*, *consistent-snapshot*, *recently-claimed* and *unclaimed* -roles will need to support continuous delivery. Even though their respective -keys will then need to be online, we will require that the keys be independent -of each other. This allows for each of the keys to be placed on separate -servers if need be, and prevents side channel attacks that compromise one key -from automatically compromising the rest of the keys. Therefore, each of the -*timestamp*, *consistent-snapshot*, *recently-claimed* and *unclaimed* roles -MUST require (1, 1) keys. - -The *unclaimed* role MAY delegate targets in an automated manner to a number of -roles called "bins", as we discussed in the previous section. Each of the -"bin" roles SHOULD share the same key as the *unclaimed* role, due -simultaneously to space efficiency of metadata and because there is no security -advantage in requiring separate keys. - -The *root* role is critical for security and should very rarely be used. It is -primarily used for key revocation, and it is the root of trust for all of PyPI. -The *root* role signs for the keys that are authorized for each of the -top-level roles (including itself). The keys belonging to the *root* role are -intended to be very well-protected and used with the least frequency of all -keys. We propose that every PSF board member own a (strong) root key. A -majority of them can then constitute the quorum to revoke or endow trust in all -top-level keys. Alternatively, the system administrators of PyPI (instead of -PSF board members) could be responsible for signing for the *root* role. -Therefore, the *root* role SHOULD require (t, n) keys, where n is the number of -either all PyPI administrators or all PSF board members, and t > 1 (so that at -least two members must sign the *root* role). - -The *targets* role will be used only to sign for the static delegation of all -targets to the *claimed*, *recently-claimed* and *unclaimed* roles. Since -these target delegations must be secured against attacks in the event of a -compromise, the keys for the *targets* role MUST be offline and independent -from other keys. For simplicity of key management without sacrificing -security, it is RECOMMENDED that the keys of the *targets* role are permanently -discarded as soon as they have been created and used to sign for the role. -Therefore, the *targets* role SHOULD require (1, 1) keys. Again, this is -because the keys are going to be permanently discarded, and more offline keys -will not help against key recovery attacks [21]_ unless diversity of keys is -maintained. - -Similarly, the *claimed* role will be used only to sign for the dynamic -delegation of projects to their respective developer keys. Since these target -delegations must be secured against attacks in the event of a compromise, the -keys for the *claimed* role MUST be offline and independent from other keys. -Therefore, the *claimed* role SHOULD require (t, n) keys, where n is the number -of all PyPI administrators (in order to keep it manageable), and t ? 1 (so that -at least one member MUST sign the *claimed* role). While a stronger threshold -would indeed render the role more robust against a compromise of the *claimed* -keys (which is highly unlikely assuming that the keys are independent and -securely kept offline), we think that this trade-off is acceptable for the -important purpose of keeping the maintenance overhead for PyPI administrators -as little as possible. At the time of writing, we are keeping this point open -for discussion by the distutils-sig community. - -The number of developer keys is project-specific and thus beyond the scope of -this PEP. - - -Online and Offline Keys ------------------------ - -In order to support continuous delivery, the *timestamp*, -*consistent-snapshot*, *recently-claimed* and *unclaimed* role keys MUST be -online. - -As explained in the previous section, the *root*, *targets* and *claimed* role -keys MUST be offline for maximum security. Developers keys will be offline in -the sense that the private keys MUST NOT be stored on PyPI, though some of them -may be online on the private infrastructure of the project. - - -Key Strength ------------- - -At the time of writing, we recommend that all RSA keys (both offline and -online) SHOULD have a minimum key size of 3072 bits for data-protection -lifetimes beyond 2030 [22]_. - - -Diversity Of Keys ------------------ - -Due to the threats of weak key generation and implementation weaknesses [2]_, -the types of keys as well as the libraries used to generate them should vary -within TUF on PyPI. Our current implementation of TUF supports multiple -digital signature algorithms such as RSA (with OpenSSL [23]_ or PyCrypto [24]_) -and ed25519 [25]_. Furthermore, TUF supports the binding of other -cryptographic libraries that it does not immediately support "out of the box", -and so one MAY generate keys using other cryptographic libraries and use them -for TUF on PyPI. - -As such, the root role keys SHOULD be generated by a variety of digital -signature algorithms as implemented by different cryptographic libraries. - - -Key Compromise Analysis ------------------------ - -.. image:: https://raw.github.com/theupdateframework/pep-on-pypi-with-tuf/master/table1.png - -Table 1: Attacks possible by compromising certain combinations of role keys - - -Table 1 summarizes the kinds of attacks rendered possible by compromising a -threshold number of keys belonging to the TUF roles on PyPI. Except for the -*timestamp* and *consistent-snapshot* roles, the pairwise interaction of role -compromises may be found by taking the union of both rows. - -In September 2013, we showed how the latest version of pip then was susceptible -to these attacks and how TUF could protect users against them [14]_. - -An attacker who compromises developer keys for a project and who is able to -somehow upload malicious metadata and targets to PyPI will be able to serve -malicious updates to users of that project (and that project alone). Note that -compromising *targets* or any delegated targets role (except for project -targets metadata) does not immediately endow the attacker with the ability to -serve malicious updates. The attacker must also compromise the *timestamp* and -*consistent-snapshot* roles (which are both online and therefore more likely to -be compromised). This means that in order to launch any attack, one must be -not only be able to act as a man-in-the-middle but also compromise the -*timestamp* key (or the *root* keys and sign a new *timestamp* key). To launch -any attack other than a freeze attack, one must also compromise the -*consistent-snapshot* key. +Note that compromising *targets* or any delegated role (except for project +targets metadata) does not immediately allow an attacker to serve malicious +updates. The attacker must also compromise the *timestamp* and *snapshot* +roles (which are both online and therefore more likely to be compromised). +This means that in order to launch any attack, one must not only be able to +act as a man-in-the-middle but also compromise the *timestamp* key (or +compromise the *root* keys and sign a new *timestamp* key). To launch any +attack other than a freeze attack, one must also compromise the *snapshot* key. Finally, a compromise of the PyPI infrastructure MAY introduce malicious -updates to *recently-claimed* and *unclaimed* projects because the keys for -those roles are online. However, attackers cannot modify *claimed* projects in -such an event because *targets* and *claimed* metadata have been signed with -offline keys. Therefore, it is RECOMMENDED that high-value projects register -their developer keys with PyPI and sign for their own distributions. +updates to *bins* projects because the keys for these roles are online. The +maximum security model discussed in the appendix addresses this issue. PEP X +[VD: Link to PEP once it is completed] also covers the maximum security model +and goes into more detail on generating developer keys and signing uploaded +distributions. In the Event of a Key Compromise -------------------------------- -By a key compromise, we mean that the key as well as PyPI infrastructure has -been compromised and used to sign new metadata on PyPI. +A key compromise means that a threshold of keys (belonging to the metadata +roles on PyPI), as well as the PyPI infrastructure, have been compromised and +used to sign new metadata on PyPI. -If a threshold number of developer keys of a project have been compromised, -then the project MUST take the following steps: +If a threshold number of *timestamp*, *snapshot*, or *bins* keys have +been compromised, then PyPI MUST take the following steps: -1. The project metadata and targets MUST be restored to the last known good - consistent snapshot where the project was not known to be compromised. This - can be done by the developers repackaging and resigning all targets with the - new keys. +1. Revoke the *timestamp*, *snapshot* and *targets* role keys from + the *root* role. This is done by replacing the compromised *timestamp*, + *snapshot* and *targets* keys with newly issued keys. -2. The project delegated targets metadata MUST have their version numbers - incremented, expiry times suitably extended and signatures renewed. +2. Revoke the *bins* keys from the *targets* role by replacing their keys with + newly issued keys. Sign the new *targets* role metadata and discard the new + keys (because, as explained earlier, this increases the security of + *targets* metadata). -Whereas PyPI MUST take the following steps: - -1. Revoke the compromised developer keys from the delegation to the project by - the *recently-claimed* or *claimed* role. This is done by replacing the - compromised developer keys with newly issued developer keys. - -2. A new timestamped consistent snapshot MUST be issued. - -If a threshold number of *timestamp*, *consistent-snapshot*, *recently-claimed* -or *unclaimed* keys have been compromised, then PyPI MUST take the following -steps: - -1. Revoke the *timestamp*, *consistent-snapshot* and *targets* role keys from - the *root* role. This is done by replacing the compromised *timestamp*, - *consistent-snapshot* and *targets* keys with newly issued keys. - -2. Revoke the *recently-claimed* and *unclaimed* keys from the *targets* role - by replacing their keys with newly issued keys. Sign the new *targets* role - metadata and discard the new keys (because, as we explained earlier, this - increases the security of *targets* metadata). - -3. Clear all targets or delegations in the *recently-claimed* role and delete - all associated delegated targets metadata. Recently registered projects - SHOULD register their developer keys again with PyPI. - -4. All targets of the *recently-claimed* and *unclaimed* roles SHOULD be - compared with the last known good consistent snapshot where none of the - *timestamp*, *consistent-snapshot*, *recently-claimed* or *unclaimed* keys +3. All targets of the *bins* roles SHOULD be compared with the last known + good consistent snapshot where none of the *timestamp*, *snapshot*, or + *bins* keys were known to have been compromised. Added, updated or deleted targets in the compromised consistent snapshot that do not match the last known good consistent snapshot MAY be restored to their previous versions. After - ensuring the integrity of all *unclaimed* targets, the *unclaimed* metadata + ensuring the integrity of all *bins* targets, the *bins* metadata MUST be regenerated. -5. The *recently-claimed* and *unclaimed* metadata MUST have their version - numbers incremented, expiry times suitably extended and signatures renewed. +4. The *bins* metadata MUST have their version numbers incremented, expiry + times suitably extended, and signatures renewed. -6. A new timestamped consistent snapshot MUST be issued. +5. A new timestamped consistent snapshot MUST be issued. -This would preemptively protect all of these roles even though only one of them -may have been compromised. +Following these steps would preemptively protect all of these roles even though +only one of them may have been compromised. -If a threshold number of the *targets* or *claimed* keys have been compromised, -then there is little that an attacker could do without the *timestamp* and -*consistent-snapshot* keys. In this case, PyPI MUST simply revoke the -compromised *targets* or *claimed* keys by replacing them with new keys in the -*root* and *targets* roles respectively. - -If a threshold number of the *timestamp*, *consistent-snapshot* and *claimed* -keys have been compromised, then PyPI MUST take the following steps in addition -to the steps taken when either the *timestamp* or *consistent-snapshot* keys -are compromised: - -1. Revoke the *claimed* role keys from the *targets* role and replace them with - newly issued keys. - -2. All project targets of the *claimed* roles SHOULD be compared with the last - known good consistent snapshot where none of the *timestamp*, - *consistent-snapshot* or *claimed* keys were known to have been compromised. - Added, updated or deleted targets in the compromised consistent snapshot - that do not match the last known good consistent snapshot MAY be restored to - their previous versions. After ensuring the integrity of all *claimed* - project targets, the *claimed* metadata MUST be regenerated. - -3. The *claimed* metadata MUST have their version numbers incremented, expiry - times suitably extended and signatures renewed. - -If a threshold number of the *timestamp*, *consistent-snapshot* and *targets* -keys have been compromised, then PyPI MUST take the union of the steps taken -when the *claimed*, *recently-claimed* and *unclaimed* keys have been -compromised. - -If a threshold number of the *root* keys have been compromised, then PyPI MUST -take the steps taken when the *targets* role has been compromised as well as -replace all of the *root* keys. +If a threshold number of *root* keys have been compromised, then PyPI MUST take +the steps taken when the *targets* role has been compromised. All of the +*root* keys must also be replaced. It is also RECOMMENDED that PyPI sufficiently document compromises with security bulletins. These security bulletins will be most informative when -users of pip with TUF are unable to install or update a project because the -keys for the *timestamp*, *consistent-snapshot* or *root* roles are no longer -valid. They could then visit the PyPI web site to consult security bulletins -that would help to explain why they are no longer able to install or update, -and then take action accordingly. When a threshold number of *root* keys have -not been revoked due to a compromise, then new *root* metadata may be safely -updated because a threshold number of existing *root* keys will be used to sign -for the integrity of the new *root* metadata so that TUF clients will be able -to verify the integrity of the new *root* metadata with a threshold number of -previously known *root* keys. This will be the common case. Otherwise, in the -worst case where a threshold number of *root* keys have been revoked due to a +users of pip-with-TUF are unable to install or update a project because the +keys for the *timestamp*, *snapshot* or *root* roles are no longer valid. They +could then visit the PyPI web site to consult security bulletins that would +help to explain why they are no longer able to install or update, and then take +action accordingly. When a threshold number of *root* keys have not been +revoked due to a compromise, then new *root* metadata may be safely updated +because a threshold number of existing *root* keys will be used to sign for the +integrity of the new *root* metadata. TUF clients will be able to verify the +integrity of the new *root* metadata with a threshold number of previously +known *root* keys. This will be the common case. Otherwise, in the worst +case, where a threshold number of *root* keys have been revoked due to a compromise, an end-user may choose to update new *root* metadata with `out-of-band`__ mechanisms. __ https://en.wikipedia.org/wiki/Out-of-band#Authentication -Appendix: Rejected Proposals -============================ +Auditing Snapshots +------------------ +If a malicious party compromises PyPI, they can sign arbitrary files with any +of the online keys. The roles with offline keys (i.e., *root* and *targets*) +are still protected. To safely recover from a repository compromise, snapshots +should be audited to ensure files are only restored to trusted versions. -Alternative Proposals for Producing Consistent Snapshots --------------------------------------------------------- +When a repository compromise has been detected, the integrity of three types of +information must be validated: -The complete file snapshot (CFS) scheme uses file system directories to store -efficient consistent snapshots over time. In this scheme, every consistent -snapshot will be stored in a separate directory, wherein files that are shared -with previous consistent snapshots will be `hard links`__ instead of copies. +1. If the online keys of the repository have been compromised, they can be + revoked by having the *targets* role sign new metadata delegating to a new + key. -__ https://en.wikipedia.org/wiki/Hard_link +2. If the role metadata on the repository has been changed, this would impact + the metadata that is signed by online keys. Any role information created + since the last period should be discarded. As a result, developers of new + projects will need to re-register their projects. -The `differential file`__ snapshot (DFS) scheme is a variant of the CFS scheme, -wherein the next consistent snapshot directory will contain only the additions -of new files and updates to existing files of the previous consistent snapshot. -(The first consistent snapshot will contain a complete set of files known -then.) Deleted files will be marked as such in the next consistent snapshot -directory. This means that files will be resolved in this manner: First, set -the current consistent snapshot directory to be the latest consistent snapshot -directory. Then, any requested file will be seeked in the current consistent -snapshot directory. If the file exists in the current consistent snapshot -directory, then that file will be returned. If it has been marked as deleted -in the current consistent snapshot directory, then that file will be reported -as missing. Otherwise, the current consistent snapshot directory will be set -to the preceding consistent snapshot directory and the previous few steps will -be iterated until there is no preceding consistent snapshot to be considered, -at which point the file will be reported as missing. +3. If the packages themselves may have been tampered with, they can be + validated using the stored hash information for packages that existed at the + time of the last period. -__ http://dl.acm.org/citation.cfm?id=320484 +In order to safely restore snapshots in the event of a compromise, PyPI SHOULD +maintain a small number of its own mirrors to copy PyPI snapshots according to +some schedule. The mirroring protocol can be used immediately for this +purpose. The mirrors must be secured and isolated such that they are +responsible only for mirroring PyPI. The mirrors can be checked against one +another to detect accidental or malicious failures. -With the CFS scheme, the trade-off is the I/O costs of producing a consistent -snapshot with the file system. As of October 2013, we found that a fairly -modern computer with a 7200RPM hard disk drive required at least three minutes -to produce a consistent snapshot with the "cp -lr" command on the ext3__ file -system. Perhaps the I/O costs of this scheme may be ameliorated with advanced -tools or file systems such as ZFS__ or btrfs__. +Another approach is to generate the cryptographic hash of *snapshot* +periodically and tweet it. Perhaps a user comes forward with the actual +metadata and the repository maintainers can verify the metadata's cryptographic +hash. Alternatively, PyPI may periodically archive its own versions of +*snapshot* rather than rely on externally provided metadata. In this case, +PyPI SHOULD take the cryptographic hash of every package on the repository and +store this data on an offline device. If any package hash has changed, this +indicates an attack. -__ https://en.wikipedia.org/wiki/Ext3 -__ https://en.wikipedia.org/wiki/ZFS -__ https://en.wikipedia.org/wiki/Btrfs +As for attacks that serve different versions of metadata, or freeze a version +of a package at a specific version, they can be handled by TUF with techniques +like implicit key revocation and metadata mismatch detection [81]. -While the DFS scheme improves upon the CFS scheme in terms of producing faster -consistent snapshots, there are at least two trade-offs. The first is that a -web server will need to be modified to perform the "daisy chain" resolution of -a file. The second is that every now and then, the differential snapshots will -need to be "squashed" or merged together with the first consistent snapshot to -produce a new first consistent snapshot with the latest and complete set of -files. Although the merge cost may be amortized over time, this scheme is not -conceptually si +Appendix A: Repository Attacks Prevented by TUF +=============================================== +* **Arbitrary software installation**: An attacker installs anything they want + on the client system. That is, an attacker can provide arbitrary files in + respond to download requests and the files will not be detected as + illegitimate. + +* **Rollback attacks**: An attacker presents a software update system with + older files than those the client has already seen, causing the client to use + files older than those the client knows about. + +* **Indefinite freeze attacks**: An attacker continues to present a software + update system with the same files the client has already seen. The result is + that the client does not know that new files are available. + +* **Endless data attacks**: An attacker responds to a file download request + with an endless stream of data, causing harm to clients (e.g., a disk + partition filling up or memory exhaustion). + +* **Slow retrieval attacks**: An attacker responds to clients with a very slow + stream of data that essentially results in the client never continuing the + update process. + +* **Extraneous dependencies attacks**: An attacker indicates to clients that in + order to install the software they wanted, they also need to install + unrelated software. This unrelated software can be from a trusted source + but may have known vulnerabilities that are exploitable by the attacker. + +* **Mix-and-match attacks**: An attacker presents clients with a view of a + repository that includes files that never existed together on the repository + at the same time. This can result in, for example, outdated versions of + dependencies being installed. + +* **Wrong software installation**: An attacker provides a client with a trusted + file that is not the one the client wanted. + +* **Malicious mirrors preventing updates**: An attacker in control of one + repository mirror is able to prevent users from obtaining updates from + other, good mirrors. + +* **Vulnerability to key compromises**: An attacker who is able to compromise a + single key or less than a given threshold of keys can compromise clients. + This includes relying on a single online key (such as only being protected + by SSL) or a single offline key (such as most software update systems use + to sign files). + + +Appendix B: Extension to the Minimum Security Model +=================================================== + +The maximum security model and end-to-end signing have been intentionally +excluded from this PEP. Although both improve PyPI's ability to survive a +repository compromise and allow developers to sign their distributions, they +have been postponed for review as a potential future extension to PEP 458. PEP +X [VD: Link to PEP once it is completed], which discusses the extension in +detail, is available for review to those developers interested in the +end-to-end signing option. The maximum security model and end-to-end signing +are briefly covered in subsections that follow. + +There are several reasons for not initially supporting the features discussed +in this section: + +1. A build farm (distribution wheels on supported platforms are generated for + each project on PyPI infrastructure) may possibly complicate matters. PyPI + wants to support a build farm in the future. Unfortunately, if wheels are + auto-generated externally, developer signatures for these wheels are + unlikely. However, there might still be a benefit to generating wheels from + source distributions that are signed by developers (provided that + reproducible wheels are possible). Another possibility is to optionally + delegate trust of these wheels to an online role. + +2. An easy-to-use key management solution is needed for developers. + `miniLock`__ is one likely candidate for management and generation of keys. + Although developer signatures can remain optional, this approach may be + inadequate due to the great number of potentially unsigned dependencies each + distribution may have. If any one of these dependencies is unsigned, it + negates any benefit the project gains from signing its own distribution + (i.e., attackers would only need to compromise one of the unsigned + dependencies to attack end-users). Requiring developers to manually sign + distributions and manage keys is expected to render key signing an unused + feature. + + __ https://minilock.io/ + +3. A two-phase approach, where the minimum security model is implemented first + followed by the maximum security model, can simplify matters and give PyPI + administrators time to review the feasibility of end-to-end signing. + + +Maximum Security Model +---------------------- + +The maximum security model relies on developers signing their projects and +uploading signed metadata to PyPI. If the PyPI infrastructure were to be +compromised, attackers would be unable to serve malicious versions of claimed +projects without access to the project's developer key. Figure 3 depicts the +changes made to figure 2, namely that developer roles are now supported and +that three new delegated roles exist: *claimed*, *recently-claimed*, and +*unclaimed*. The *bins* role has been renamed *unclaimed* and can contain any +projects that have not been added to *claimed*. The strength of this model +(over the minimum security model) is in the offline keys provided by +developers. Although the minimum security model supports continuous delivery, +all of the projects are signed by an online key. An attacker can corrupt +packages in the minimum security model, but not in the maximum model without +also compromising a developer's key. + +.. image:: figure3.png + +Figure 3: An overview of the metadata layout in the maximum security model. +The maximum security model supports continuous delivery and survivable key +compromise. + + +End-to-End Signing +------------------ + +End-to-End signing allows both PyPI and developers to sign for the metadata +downloaded by clients. PyPI is trusted to make uploaded projects available to +clients (they sign the metadata for this part of the process), and developers +can sign the distributions that they upload. + +PEP X [VD: Link to PEP once it is completed] discusses the tools available to +developers who sign the distributions that they upload to PyPI. To summarize +PEP X, developers generate cryptographic keys and sign metadata in some +automated fashion, where the metadata includes the information required to +verify the authenticity of the distribution. The metadata is then uploaded to +PyPI by the client, where it will be available for download by package managers +such as pip (i.e., package managers that support TUF metadata). The entire +process is transparent to clients (using a package manager that supports TUF) +who download distributions from PyPI. + + +Appendix C: PEP 470 and Projects Hosted Externally +================================================== + +How should TUF handle distributions that are not hosted on PyPI? According to +`PEP 470`__, projects may opt to host their distributions externally and are +only required to provide PyPI a link to its external index, which package +managers like pip can use to find the project's distributions. PEP 470 does +not mention whether externally hosted projects are considered unverified by +default, as projects that use this option are not required to submit any +information about their distributions (e.g., file size and cryptographic hash) +when the project is registered, nor include a cryptographic hash of the file +in download links. + +__ http://www.python.org/dev/peps/pep-0470/ + +Potentional approaches that PyPI administrators MAY consider to handle +projects hosted externally: + +1. Download external distributions but do not verify them. The targets + metadata will not include information for externally hosted projects. + +2. PyPI will periodically download information from the external index. PyPI + will gather the external distribution's file size and hashes and generate + appropriate TUF metadata. + +3. External projects MUST submit to PyPI the file size and cryptographic hash + for a distribution. + +4. External projects MUST upload to PyPI a developer public key for the + index. The distribution MUST create TUF metadata that is stored at the + index, and signed with the developer's corresponding private key. The + client will fetch the external TUF metadata as part of the package + update process. + +5. External projects MUST upload to PyPI signed TUF metadata (as allowed by + the maximum security model) about the distributions that they host + externally, and a developer public key. Package managers verify + distributions by consulting the signed metadata uploaded to PyPI. + +Only one of the options listed above should be implemented on PyPI. Option +(4) or (5) is RECOMMENDED because external distributions are signed by +developers. External distributions that are forged (due to a compromised +PyPI account or external host) may be detected if external developers are +required to sign metadata, although this requirement is likely only practical +if an easy-to-use key management solution and developer scripts are provided +by PyPI. References @@ -1055,27 +1066,30 @@ .. [24] https://pypi.python.org/pypi/pycrypto .. [25] http://ed25519.cr.yp.to/ - Acknowledgements ================ -Nick Coghlan, Daniel Holth and the distutils-sig community in general for -helping us to think about how to usably and efficiently integrate TUF with +This material is based upon work supported by the National Science Foundation +under Grants No. CNS-1345049 and CNS-0959138. Any opinions, findings, and +conclusions or recommendations expressed in this material are those of the +author(s) and do not necessarily reflect the views of the National Science +Foundation. + +We thank Nick Coghlan, Daniel Holth and the distutils-sig community in general +for helping us to think about how to usably and efficiently integrate TUF with PyPI. -Roger Dingledine, Sebastian Hahn, Nick Mathewson, Martin Peck and Justin -Samuel for helping us to design TUF from its predecessor Thandy of the Tor -project. +Roger Dingledine, Sebastian Hahn, Nick Mathewson, Martin Peck and Justin Samuel +helped us to design TUF from its predecessor Thandy of the Tor project. -Konstantin Andrianov, Geremy Condra, Vladimir Diaz, Zane Fisher, Justin Samuel, -Tian Tian, Santiago Torres, John Ward, and Yuyu Zheng for helping us to develop -TUF. +We appreciate the efforts of Konstantin Andrianov, Geremy Condra, Zane Fisher, +Justin Samuel, Tian Tian, Santiago Torres, John Ward, and Yuyu Zheng to to +develop TUF. -Vladimir Diaz, Monzur Muhammad and Sai Teja Peddinti for helping us to review -this PEP. +Vladimir Diaz, Monzur Muhammad and Sai Teja Peddinti helped us to review this +PEP. -Zane Fisher for helping us to review and transcribe this PEP. - +Zane Fisher helped us to review and transcribe this PEP. Copyright ========= diff --git a/pep-0480.txt b/pep-0480.txt new file mode 100644 --- /dev/null +++ b/pep-0480.txt @@ -0,0 +1,890 @@ +PEP: 480 +Title: Surviving a Compromise of PyPI: The Maximum Security Model +Version: $Revision$ +Last-Modified: $Date$ +Author: Trishank Karthik Kuppusamy , + Vladimir Diaz , Donald Stufft , + Justin Cappos +BDFL-Delegate: Richard Jones +Discussions-To: DistUtils mailing list +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Requires: 458 +Created: 8-Oct-2014 + + +Abstract +======== + +Proposed is an extension to PEP 458 that adds support for end-to-end signing +and the maximum security model. End-to-end signing allows both PyPI and +developers to sign for the distributions that are downloaded by clients. The +minimum security model proposed by PEP 458 supports continuous delivery of +distributions (because they are signed by online keys), but that model does not +protect distributions in the event that PyPI is compromised. In the minimum +security model, attackers may sign for malicious distributions by compromising +the signing keys stored on PyPI infrastructure. The maximum security model, +described in this PEP, retains the benefits of PEP 458 (e.g., immediate +availability of distributions that are uploaded to PyPI), but additionally +ensures that end-users are not at risk of installing forged software if PyPI is +compromised. + +This PEP discusses the changes made to PEP 458 but excludes its informational +elements to primarily focus on the maximum security model. For example, an +overview of The Update Framework or the basic mechanisms in PEP 458 are not +covered here. The changes to PEP 458 include modifications to the snapshot +process, key compromise analysis, auditing snapshots, and the steps that should +be taken in the event of a PyPI compromise. The signing and key management +process that PyPI MAY RECOMMEND is discussed but not strictly defined. How the +release process should be implemented to manage keys and metadata is left to +the implementors of the signing tools. That is, this PEP delineates the +expected cryptographic key type and signature format included in metadata that +MUST be uploaded by developers in order to support end-to-end verification of +distributions. + + +Rationale +========= + +PEP 458 [1]_ proposes how PyPI should be integrated with The Update Framework +(TUF) [2]_. It explains how modern package managers like pip can be made more +secure, and the types of attacks that can be prevented if PyPI is modified on +the server side to include TUF metadata. Package managers can reference the +TUF metadata available on PyPI to download distributions more securely. + +PEP 458 also describes the metadata layout of the PyPI repository and employs +the minimum security model, which supports continuous delivery of projects and +uses online cryptographic keys to sign the distributions uploaded by +developers. Although the minimum security model guards against most attacks on +software updaters [5]_ [7]_, such as mix-and-match and extraneous dependencies +attacks, it can be improved to support end-to-end signing and to prohibit +forged distributions in the event that PyPI is compromised. + +The main strength of PEP 458 and the minimum security model is the automated +and simplified release process: developers may upload distributions and then +have PyPI sign for their distributions. Much of the release process is handled +in an automated fashion by online roles and this approach requires storing +cryptographic signing keys on the PyPI infrastructure. Unfortunately, +cryptographic keys that are stored online are vulnerable to theft. The maximum +security model, proposed in this PEP, permits developers to sign for the +distributions that they make available to PyPI users, and does not put +end-users at risk of downloading malicious distributions if the online keys +stored on PyPI infrastructure are compromised. + + +Threat Model +============ + +The threat model assumes the following: + +* Offline keys are safe and securely stored. + +* Attackers can compromise at least one of PyPI's trusted keys that are stored + online, and may do so at once or over a period of time. + +* Attackers can respond to client requests. + +* Attackers may control any number of developer keys for projects a client does + not want to install. + +Attackers are considered successful if they can cause a client to install (or +leave installed) something other than the most up-to-date version of the +software the client is updating. When an attacker is preventing the +installation of updates, the attacker's goal is that clients not realize that +anything is wrong. + + +Definitions +=========== + +The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", +"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be +interpreted as described in RFC `2119`__. + +__ http://www.ietf.org/rfc/rfc2119.txt + +This PEP focuses on integrating TUF with PyPI; however, the reader is +encouraged to read about TUF's design principles [2]_. It is also RECOMMENDED +that the reader be familiar with the TUF specification [3]_, and PEP 458 [1]_ +(which this PEP is extending). + +Terms used in this PEP are defined as follows: + +* Projects: Projects are software components that are made available for + integration. Projects include Python libraries, frameworks, scripts, + plugins, applications, collections of data or other resources, and various + combinations thereof. Public Python projects are typically registered on the + Python Package Index [4]_. + +* Releases: Releases are uniquely identified snapshots of a project [4]_. + +* Distributions: Distributions are the packaged files that are used to publish + and distribute a release. + +* Simple index: The HTML page that contains internal links to the + distributions of a project [4]_. + +* Roles: There is one *root* role in PyPI. There are multiple roles whose + responsibilities are delegated to them directly or indirectly by the *root* + role. The term "top-level role" refers to the *root* role and any role + delegated by the *root* role. Each role has a single metadata file that it is + trusted to provide. + +* Metadata: Metadata are files that describe roles, other metadata, and target + files. + +* Repository: A repository is a resource comprised of named metadata and target + files. Clients request metadata and target files stored on a repository. + +* Consistent snapshot: A set of TUF metadata and PyPI targets that capture the + complete state of all projects on PyPI as they existed at some fixed point in + time. + +* The *snapshot* (*release*) role: In order to prevent confusion due to the + different meanings of the term "release" used in PEP 426 [1]_ and the TUF + specification [3]_, the *release* role is renamed to the *snapshot* role. + +* Developer: Either the owner or maintainer of a project who is allowed to + update TUF metadata, as well as distribution metadata and files for a given + project. + +* Online key: A private cryptographic key that MUST be stored on the PyPI + server infrastructure. This usually allows automated signing with the key. + An attacker who compromises the PyPI infrastructure will be able to + immediately read these keys. + +* Offline key: A private cryptographic key that MUST be stored independent of + the PyPI server infrastructure. This prevents automated signing with the + key. An attacker who compromises the PyPI infrastructure will not be able to + immediately read these keys. + +* Threshold signature scheme: A role can increase its resilience to key + compromises by specifying that at least t out of n keys are REQUIRED to sign + its metadata. A compromise of t-1 keys is insufficient to compromise the + role itself. Saying that a role requires (t, n) keys denotes the threshold + signature property. + + +Maximum Security Model +====================== + +The maximum security model permits developers to sign their projects and to +upload signed metadata to PyPI. If the PyPI infrastructure were compromised, +attackers would be unable to serve malicious versions of a *claimed* project +without having access to that project's developer key. Figure 1 depicts the +changes made to the metadata layout of the minimum security model, namely that +developer roles are now supported and that three new delegated roles exist: +*claimed*, *recently-claimed*, and *unclaimed*. The *bins* role from the +minimum security model has been renamed *unclaimed* and can contain any +projects that have not been added to *claimed*. The *unclaimed* role functions +just as before (i.e., as explained in PEP 458, projects added to this role are +signed by PyPI with an online key). Offline keys provided by developers ensure +the strength of the maximum security model over the minimum model. Although +the minimum security model supports continuous delivery of projects, all +projects are signed by an online key. That is, an attacker is able to corrupt +packages in the minimum security model, but not in the maximum model, without +also compromising a developer's key. + +.. image:: figure1.png + +Figure 1: An overview of the metadata layout in the maximum security model. +The maximum security model supports continuous delivery and survivable key +compromise. + +Projects that are signed by developers and uploaded to PyPI for the first time +are added to the *recently-claimed* role. The *recently-claimed* role uses an +online key, so projects uploaded for the first time are immediately available +to clients. After some time has passed, PyPI administrators MAY periodically +move (e.g., every month) projects listed in *recently-claimed* to the *claimed* +role for maximum security. The *claimed* role uses an offline key, thus +projects added to this role cannot be easily forged if PyPI is compromised. + +The *recently-claimed* role is separate from the *unclaimed* role for usability +and efficiency, not security. If new project delegations were prepended to +*unclaimed* metadata, *unclaimed* would need to be re-downloaded every time a +project obtained a key. By separating out new projects, the amount of data +retrieved is reduced. From a usability standpoint, it also makes it easier for +administrators to see which projects are now claimed. This information is +needed when moving keys from *recently-claimed* to *claimed*, which is +discussed in more detail in the "Producing Consistent Snapshots" section. + + +End-to-End Signing +================== + +End-to-end signing allows both PyPI and developers to sign for the metadata +downloaded by clients. PyPI is trusted to make uploaded projects available to +clients (PyPI signs the metadata for this part of the process), and developers +sign the distributions that they upload to PyPI. + +In order to delegate trust to a project, developers are required to submit a +public key to PyPI. PyPI takes the project's public key and adds it to parent +metadata that PyPI then signs. After the initial trust is established, +developers are required to sign distributions that they upload to PyPI using +the public key's corresponding private key. The signed TUF metadata that +developers upload to PyPI includes information like the distribution's file +size and hash, which package managers use to verify distributions that are +downloaded. + +The practical implications of end-to-end signing is the extra administrative +work needed to delegate trust to a project, and the signed metadata that +developers MUST upload to PyPI along with the distribution. Specifically, PyPI +is expected to periodically sign metadata with an offline key by adding +projects to the *claimed* metadata file and signing it. In contrast, projects +are only ever signed with an online key in the minimum security model. +End-to-end signing does require manual intervention to delegate trust (i.e., to +sign metadata with an offline key), but this is a one-time cost and projects +have stronger protections against PyPI compromises thereafter. + + +Metadata Signatures, Key Management, and Signing Distributions +============================================================== + +This section discusses the tools, signature scheme, and signing methods that +PyPI MAY recommend to implementors of the signing tools. Developers are +expected to use these tools to sign and upload distributions to PyPI. To +summarize the RECOMMENDED tools and schemes discussed in the subsections below, +developers MAY generate cryptographic keys and sign metadata (with the Ed25519 +signature scheme) in some automated fashion, where the metadata includes the +information required to verify the authenticity of the distribution. +Developers then upload metadata to PyPI, where it will be available for +download by package managers such as pip (i.e., package managers that support +TUF metadata). The entire process is transparent to the end-users (using a +package manager that supports TUF) that download distributions from PyPI. + +The first three subsections (Cryptographic Signature Scheme, Cryptographic Key +Files, and Key Management) cover the cryptographic components of the developer +release process. That is, which key type PyPI supports, how keys may be +stored, and how keys may be generated. The two subsections that follow the +first three discuss the PyPI modules that SHOULD be modified to support TUF +metadata. For example, Twine and Distutils are two projects that SHOULD be +modified. Finally, the last subsection goes over the automated key management +and signing solution that is RECOMMENDED for the signing tools. + +TUF's design is flexible with respect to cryptographic key types, signatures, +and signing methods. The tools, modification, and methods discussed in the +following sections are RECOMMENDATIONS for the implementors of the signing +tools. + + +Cryptographic Signature Scheme: Ed25519 +--------------------------------------- + +The package manager (pip) shipped with CPython MUST work on non-CPython +interpreters and cannot have dependencies that have to be compiled (i.e., the +PyPI+TUF integration MUST NOT require compilation of C extensions in order to +verify cryptographic signatures). Verification of signatures MUST be done in +Python, and verifying RSA [11]_ signatures in pure-Python may be impractical due +to speed. Therefore, PyPI MAY use the `Ed25519`__ signature scheme. + +__ http://ed25519.cr.yp.to/ + +Ed25519 [12]_ is a public-key signature system that uses small cryptographic +signatures and keys. A `pure-Python implementation`__ of the Ed25519 signature +scheme is available. Verification of Ed25519 signatures is fast even when +performed in Python. + +__ https://github.com/pyca/ed25519 + + +Cryptographic Key Files +----------------------- + +The implementation MAY encrypt key files with AES-256-CTR-Mode and strengthen +passwords with PBKDF2-HMAC-SHA256 (100K iterations by default, but this may be +overridden by the developer). The current Python implementation of TUF can use +any cryptographic library (support for PyCA cryptography will be added in the +future), may override the default number of PBKDF2 iterations, and the KDF +tweaked to taste. + + +Key Management: miniLock +------------------------ + +An easy-to-use key management solution is needed. One solution is to derive a +private key from a password so that developers do not have to manage +cryptographic key files across multiple computers. `miniLock`__ is an example +of how this can be done. Developers may view the cryptographic key as a +secondary password. miniLock also works well with a signature scheme like +Ed25519, which only needs a very small key. + +__ https://github.com/kaepora/miniLock#-minilock + + +Third-party Upload Tools: Twine +------------------------------- + +Third-party tools like `Twine`__ MAY be modified (if they wish to support +distributions that include TUF metadata) to sign and upload developer projects +to PyPI. Twine is a utility for interacting with PyPI that uses TLS to upload +distributions, and prevents MITM attacks on usernames and passwords. + +__ https://github.com/pypa/twine + + +Distutils +--------- + +`Distutils`__ MAY be modified to sign metadata and to upload signed distributions +to PyPI. Distutils comes packaged with CPython and is the most widely-used +tool for uploading distributions to PyPI. + +__ https://docs.python.org/2/distutils/index.html#distutils-index + + +Automated Signing Solution +-------------------------- + +An easy-to-use key management solution is RECOMMENDED for developers. One +approach is to generate a cryptographic private key from a user password, akin +to miniLock. Although developer signatures can remain optional, this approach +may be inadequate due to the great number of potentially unsigned dependencies +each distribution may have. If any one of these dependencies is unsigned, it +negates any benefit the project gains from signing its own distribution (i.e., +attackers would only need to compromise one of the unsigned dependencies to +attack end-users). Requiring developers to manually sign distributions and +manage keys is expected to render key signing an unused feature. + +A default, PyPI-mediated key management and package signing solution that is +`transparent`__ to developers and does not require a key escrow (sharing of +encrypted private keys with PyPI) is RECOMMENDED for the signing tools. +Additionally, the signing tools SHOULD circumvent the sharing of private keys +across multiple machines of each developer. + +__ https://en.wikipedia.org/wiki/Transparency_%28human%E2%80%93computer_interaction%29 + +The following outlines an automated signing solution that a new developer MAY +follow to upload a distribution to PyPI: + +1. Register a PyPI project. +2. Enter a secondary password (independent of the PyPI user account password). +3. Optional: Add a new identity to the developer's PyPI user account from a + second machine (after a password prompt). +4. Upload project. + +Step 1 is the normal procedure followed by developers to `register a PyPI +project`__. + +__ https://pypi.python.org/pypi?:action=register_form + +Step 2 generates an encrypted key file (private), uploads an Ed25519 public key +to PyPI, and signs the TUF metadata that is generated for the distribution. + +Optionally adding a new identity from a second machine, by simply entering a +password, in step 3 also generates an encrypted private key file and uploads an +Ed25519 public key to PyPI. Separate identities MAY be created to allow a +developer, or other project maintainers, to sign releases on multiple machines. +An existing verified identity (its public key is contained in project metadata +or has been uploaded to PyPI) signs for new identities. By default, project +metadata has a signature threshold of "1" and other verified identities may +create new releases to satisfy the threshold. + +Step 4 uploads the distribution file and TUF metadata to PyPI. The "Snapshot +Process" section discusses in detail the procedure followed by developers to +upload a distribution to PyPI. + +Generation of cryptographic files and signatures is transparent to the +developers in the default case: developers need not be aware that packages are +automatically signed. However, the signing tools should be flexible; a single +project key may also be shared between multiple machines if manual key +management is preferred (e.g., ssh-copy-id). + +The `repository`__ and `developer`__ TUF tools currently support all of the +recommendations previously mentioned, except for the automated signing +solution, which SHOULD be added to Distutils, Twine, and other third-party +signing tools. The automated signing solution calls available repository tool +functions to sign metadata and to generate the cryptographic key files. + +__ https://github.com/theupdateframework/tuf/blob/develop/tuf/README.md +__ https://github.com/theupdateframework/tuf/blob/develop/tuf/README-developer-tools.md + + +Snapshot Process +---------------- + +The snapshot process is fairly simple and SHOULD be automated. The snapshot +process MUST keep in memory the latest working set of *root*, *targets*, and +delegated roles. Every minute or so the snapshot process will sign for this +latest working set. (Recall that project transaction processes continuously +inform the snapshot process about the latest delegated metadata in a +concurrency-safe manner. The snapshot process will actually sign for a copy of +the latest working set while the latest working set in memory will be updated +with information that is continuously communicated by the project transaction +processes.) The snapshot process MUST generate and sign new *timestamp* +metadata that will vouch for the metadata (*root*, *targets*, and delegated +roles) generated in the previous step. Finally, the snapshot process MUST make +available to clients the new *timestamp* and *snapshot* metadata representing +the latest snapshot. + +A *claimed* or *recently-claimed* project will need to upload in its +transaction to PyPI not just targets (a simple index as well as distributions) +but also TUF metadata. The project MAY do so by uploading a ZIP file containing +two directories, /metadata/ (containing delegated targets metadata files) and +/targets/ (containing targets such as the project simple index and +distributions that are signed by the delegated targets metadata). + +Whenever the project uploads metadata or targets to PyPI, PyPI SHOULD check the +project TUF metadata for at least the following properties: + +* A threshold number of the developers keys registered with PyPI by that + project MUST have signed for the delegated targets metadata file that + represents the "root" of targets for that project (e.g. metadata/targets/ + project.txt). +* The signatures of delegated targets metadata files MUST be valid. +* The delegated targets metadata files MUST NOT have expired. +* The delegated targets metadata MUST be consistent with the targets. +* A delegator MUST NOT delegate targets that were not delegated to itself by + another delegator. +* A delegatee MUST NOT sign for targets that were not delegated to itself by a + delegator. + +If PyPI chooses to check the project TUF metadata, then PyPI MAY choose to +reject publishing any set of metadata or targets that do not meet these +requirements. + +PyPI MUST enforce access control by ensuring that each project can only write +to the TUF metadata for which it is responsible. It MUST do so by ensuring that +project transaction processes write to the correct metadata as well as correct +locations within those metadata. For example, a project transaction process for +an unclaimed project MUST write to the correct target paths in the correct +delegated unclaimed metadata for the targets of the project. + +On rare occasions, PyPI MAY wish to extend the TUF metadata format for projects +in a backward-incompatible manner. Note that PyPI will NOT be able to +automatically rewrite existing TUF metadata on behalf of projects in order to +upgrade the metadata to the new backward-incompatible format because this would +invalidate the signatures of the metadata as signed by developer keys. +Instead, package managers SHOULD be written to recognize and handle multiple +incompatible versions of TUF metadata so that claimed and recently-claimed +projects could be offered a reasonable time to migrate their metadata to newer +but backward-incompatible formats. + +If PyPI eventually runs out of disk space to produce a new consistent snapshot, +then PyPI MAY then use something like a "mark-and-sweep" algorithm to delete +sufficiently outdated consistent snapshots. That is, only outdated metadata +like *timestamp* and *snapshot* that are no longer used are deleted. +Specifically, in order to preserve the latest consistent snapshot, PyPI would +walk objects -- beginning from the root (*timestamp*) -- of the latest +consistent snapshot, mark all visited objects, and delete all unmarked objects. +The last few consistent snapshots may be preserved in a similar fashion. +Deleting a consistent snapshot will cause clients to see nothing except HTTP +404 responses to any request for a target of the deleted consistent snapshot. +Clients SHOULD then retry (as before) their requests with the latest consistent +snapshot. + +All package managers that support TUF metadata MUST be modified to download +every metadata and target file (except for *timestamp* metadata) by including, +in the request for the file, the cryptographic hash of the file in the +filename. Following the filename convention RECOMMENDED in the next +subsection, a request for the file at filename.ext will be transformed to the +equivalent request for the file at digest.filename. + +Finally, PyPI SHOULD use a `transaction log`__ to record project transaction +processes and queues so that it will be easier to recover from errors after a +server failure. + +__ https://en.wikipedia.org/wiki/Transaction_log + + +Producing Consistent Snapshots +------------------------------ + +PyPI is responsible for updating, depending on the project, either the +*claimed*, *recently-claimed*, or *unclaimed* metadata and associated delegated +metadata. Every project MUST upload its set of metadata and targets in a single +transaction. The uploaded set of files is called the "project transaction." +How PyPI MAY validate files in a project transaction is discussed in a later +section. The focus of this section is on how PyPI will respond to a project +transaction. + +Every metadata and target file MUST include in its filename the `hex digest`__ +of its `SHA-256`__ hash, which PyPI may prepend to filenames after the files +have been uploaded. For this PEP, it is RECOMMENDED that PyPI adopt a simple +convention of the form: *digest.filename*, where filename is the original +filename without a copy of the hash, and digest is the hex digest of the hash. + +__ http://docs.python.org/2/library/hashlib.html#hashlib.hash.hexdigest +__ https://en.wikipedia.org/wiki/SHA-2 + +When an unclaimed project uploads a new transaction, a project transaction +process MUST add all new targets and relevant delegated unclaimed metadata. +The project transaction process MUST inform the snapshot process about new +delegated unclaimed metadata. + +When a *recently-claimed* project uploads a new transaction, a project +transaction process MUST add all new targets and delegated targets metadata for +the project. If the project is new, then the project transaction process MUST +also add new *recently-claimed* metadata with the public keys (which MUST be +part of the transaction) for the project. *recently-claimed* projects have a +threshold value of "1" set by the transaction process. Finally, the project +transaction process MUST inform the snapshot process about new +*recently-claimed* metadata, as well as the current set of delegated targets +metadata for the project. + +The transaction process for a claimed project is slightly different in that +PyPI administrators periodically move (a manual process that MAY occur every +two weeks to a month) projects from the *recently-claimed* role to the +*claimed* role. (Moving a project from *recently-claimed* to *claimed* is a +manual process because PyPI administrators have to use an offline key to sign +the claimed project's distribution.) A project transaction process MUST then +add new *recently-claimed* and *claimed* metadata to reflect this migration. As +is the case for a *recently-claimed* project, the project transaction process +MUST always add all new targets and delegated targets metadata for the claimed +project. Finally, the project transaction process MUST inform the consistent +snapshot process about new *recently-claimed* or *claimed* metadata, as well as +the current set of delegated targets metadata for the project. + +Project transaction processes SHOULD be automated, except when PyPI +administrators move a project from the *recently-claimed* role to the *claimed* +role. Project transaction processes MUST also be applied atomically: either all +metadata and targets -- or none of them -- are added. The project transaction +processes and snapshot process SHOULD work concurrently. Finally, project +transaction processes SHOULD keep in memory the latest *claimed*, +*recently-claimed*, and *unclaimed* metadata so that they will be correctly +updated in new consistent snapshots. + +The queue MAY be processed concurrently in order of appearance, provided that +the following rules are observed: + +1. No pair of project transaction processes may concurrently work on the same + project. + +2. No pair of project transaction processes may concurrently work on + *unclaimed* projects that belong to the same delegated *unclaimed* role. + +3. No pair of project transaction processes may concurrently work on new + recently-claimed projects. + +4. No pair of project transaction processes may concurrently work on new + claimed projects. + +5. No project transaction process may work on a new claimed project while + another project transaction process is working on a new recently-claimed + project and vice versa. + +These rules MUST be observed to ensure that metadata is not read from or +written to inconsistently. + + +Auditing Snapshots +------------------ + +If a malicious party compromises PyPI, they can sign arbitrary files with any +of the online keys. The roles with offline keys (i.e., *root* and *targets*) +are still protected. To safely recover from a repository compromise, snapshots +should be audited to ensure that files are only restored to trusted versions. + +When a repository compromise has been detected, the integrity of three types of +information must be validated: + +1. If the online keys of the repository have been compromised, they can be + revoked by having the *targets* role sign new metadata, delegated to a new + key. + +2. If the role metadata on the repository has been changed, this will impact + the metadata that is signed by online keys. Any role information created + since the compromise should be discarded. As a result, developers of new + projects will need to re-register their projects. + +3. If the packages themselves may have been tampered with, they can be + validated using the stored hash information for packages that existed in + trusted metadata before the compromise. Also, new distributions that are + signed by developers in the *claimed* role may be safely retained. However, + any distributions signed by developers in the *recently-claimed* or + *unclaimed* roles should be discarded. + +In order to safely restore snapshots in the event of a compromise, PyPI SHOULD +maintain a small number of its own mirrors to copy PyPI snapshots according to +some schedule. The mirroring protocol can be used immediately for this +purpose. The mirrors must be secured and isolated such that they are +responsible only for mirroring PyPI. The mirrors can be checked against one +another to detect accidental or malicious failures. + +Another approach is to periodically generate the cryptographic hash of +*snapshot* and tweet it. For example, upon receiving the tweet, a user comes +forward with the actual metadata and the repository maintainers are then able +to verify metadata's cryptographic hash. Alternatively, PyPI may periodically +archive its own versions of *snapshot* rather than rely on externally provided +metadata. In this case, PyPI SHOULD take the cryptographic hash of every +package on the repository and store this data on an offline device. If any +package hash has changed, this indicates an attack has occurred. + +Attacks that serve different versions of metadata or that freeze a version of a +package at a specific version can be handled by TUF with techniques such as +implicit key revocation and metadata mismatch detection [2]_. +n + +Key Compromise Analysis +======================= + +This PEP has covered the maximum security model, the TUF roles that should be +added to support continuous delivery of distributions, how to generate and sign +the metadata of each role, and how to support distributions that have been +signed by developers. The remaining sections discuss how PyPI SHOULD audit +repository metadata, and the methods PyPI can use to detect and recover from a +PyPI compromise. + +Table 1 summarizes a few of the attacks possible when a threshold number of +private cryptographic keys (belonging to any of the PyPI roles) are +compromised. The leftmost column lists the roles (or a combination of roles) +that have been compromised, and the columns to the right show whether the +compromised roles leaves clients susceptible to malicious updates, freeze +attacks, or metadata inconsistency attacks. + ++-------------------+-------------------+-----------------------+-----------------------+ +| Role Compromise | Malicious Updates | Freeze Attack | Metadata Inconsistency| +| | | | Attacks | ++===================+===================+=======================+=======================+ +| timetamp | NO | YES | NO | +| | snapshot and | limited by earliest | snapshot needs to | +| | targets or any | root, targets, or bin | cooperate | +| | of the delegated | metadata expiry time | | +| | roles need to | | | +| | cooperate | | | ++-------------------+-------------------+-----------------------+-----------------------+ +| snapshot | NO | NO | NO | +| | timestamp and | timestamp needs to | timestamp needs to | +| | targets or any of | coorperate | cooperate | +| | the delegated | | | +| | roles need to | | | +| | cooperate | | | ++-------------------+-------------------+-----------------------+-----------------------+ +| timestamp | NO | YES | YES | +| *AND* | targets or any | limited by earliest | limited by earliest | +| snapshot | of the delegated | root, targets, or bin | root, targets, or bin | +| | roles need to | metadata expiry time | metadata expiry time | +| | cooperate | | | +| | | | | ++-------------------+-------------------+-----------------------+-----------------------+ +| targets | NO | NOT APPLICABLE | NOT APPLICABLE | +| *OR* | timestamp and | need timestamp and | need timestamp | +| **claimed** | snapshot need to | snapshot | and snapshot | +| *OR* | cooperate | | | +| recently-claimed | | | | +| *OR* | | | | +| unclaimed | | | | +| *OR* | | | | +| **project** | | | | ++-------------------+-------------------+-----------------------+-----------------------+ +| (timestamp | YES | YES | YES | +| *AND* | | limited by earliest | limited by earliest | +| snapshot) | | root, targets, or bin | root, targets, or bin | +| *AND* | | metadata expiry time | metadata expiry time | +| **project** | | | | +| | | | | ++-------------------+-------------------+-----------------------+-----------------------+ +| (timestamp | YES | YES | YES | +| *AND* | but only of | limited by earliest | limited by earliest | +| snapshot) | projects not | root, targets, | root, targets, | +| *AND* | delegated by | claimed, | claimed, | +| (recently-claimed | claimed | recently-claimed, | recently-claimed, | +| *OR* | | project, or unclaimed | project, or unclaimed | +| unclaimed) | | metadata expiry time | metadata expiry time | ++-------------------+-------------------+-----------------------+-----------------------+ +| (timestamp | | YES | YES | +| *AND* | | limited by earliest | limited by earliest | +| snapshot) | | root, targets, | root, targets, | +| *AND* | YES | claimed, | claimed, | +| (targets *OR* | | recently-claimed, | recently-claimed, | +| **claimed**) | | project, or unclaimed | project, or unclaimed | +| | | metadata expiry time | metadata expiry time | ++-------------------+-------------------+-----------------------+-----------------------+ +| root | YES | YES | YES | ++-------------------+-------------------+-----------------------+-----------------------+ + +Table 1: Attacks that are possible by compromising certain combinations of role +keys. In `September 2013`__, it was shown how the latest version (at the time) +of pip was susceptible to these attacks and how TUF could protect users against +them [8]_. Roles signed by offline keys are in **bold**. + +__ https://mail.python.org/pipermail/distutils-sig/2013-September/022755.html + +Note that compromising *targets* or any delegated role (except for project +targets metadata) does not immediately allow an attacker to serve malicious +updates. The attacker must also compromise the *timestamp* and *snapshot* +roles (which are both online and therefore more likely to be compromised). +This means that in order to launch any attack, one must not only be able to act +as a man-in-the-middle, but also compromise the *timestamp* key (or compromise +the *root* keys and sign a new *timestamp* key). To launch any attack other +than a freeze attack, one must also compromise the *snapshot* key. Finally, a +compromise of the PyPI infrastructure MAY introduce malicious updates to +*recently-claimed* projects because the keys for these roles are online. + + +In the Event of a Key Compromise +-------------------------------- + +A key compromise means that a threshold of keys belonging to developers or the +roles on PyPI, as well as the PyPI infrastructure, have been compromised and +used to sign new metadata on PyPI. + +If a threshold number of developer keys of a project have been compromised, +the project MUST take the following steps: + +1. The project metadata and targets MUST be restored to the last known good + consistent snapshot where the project was not known to be compromised. This + can be done by developers repackaging and resigning all targets with + the new keys. + +2. The project's metadata MUST have its version numbers incremented, expiry + times suitably extended, and signatures renewed. + +Whereas PyPI MUST take the following steps: + +1. Revoke the compromised developer keys from the *recently-claimed* or + *claimed* role. This is done by replacing the compromised developer keys + with newly issued developer keys. + +2. A new timestamped consistent snapshot MUST be issued. + +If a threshold number of *timestamp*, *snapshot*, *recently-claimed*, or +*unclaimed* keys have been compromised, then PyPI MUST take the following +steps: + +1. Revoke the *timestamp*, *snapshot*, and *targets* role keys from the + root role. This is done by replacing the compromised *timestamp*, + *snapshot*, and *targets* keys with newly issued keys. + +2. Revoke the *recently-claimed* and *unclaimed* keys from the *targets* role + by replacing their keys with newly issued keys. Sign the new targets role + metadata and discard the new keys (because, as we explained earlier, this + increases the security of targets metadata). + +3. Clear all targets or delegations in the *recently-claimed* role and delete + all associated delegated targets metadata. Recently registered projects + SHOULD register their developer keys again with PyPI. + +4. All targets of the *recently-claimed* and *unclaimed* roles SHOULD be + compared with the last known good consistent snapshot where none of the + timestamp, snapshot, recently-claimed, or unclaimed keys were known to have + been compromised. Added, updated, or deleted targets in the compromised + consistent snapshot that do not match the last known good consistent + snapshot SHOULD be restored to their previous versions. After ensuring the + integrity of all unclaimed targets, the unclaimed metadata MUST be + regenerated. + +5. The *recently-claimed* and *unclaimed* metadata MUST have their version + numbers incremented, expiry times suitably extended, and signatures + renewed. + +6. A new timestamped consistent snapshot MUST be issued. + +This would preemptively protect all of these roles even though only one of them +may have been compromised. + +If a threshold number of the *targets* or *claimed* keys have been compromised, +then there is little that an attacker would be able do without the *timestamp* +and *snapshot* keys. In this case, PyPI MUST simply revoke the compromised +*targets* or *claimed* keys by replacing them with new keys in the *root* and +*targets* roles, respectively. + +If a threshold number of the *timestamp*, *snapshot*, and *claimed* keys have +been compromised, then PyPI MUST take the following steps in addition to the +steps taken when either the *timestamp* or *snapshot* keys are compromised: + +1. Revoke the *claimed* role keys from the targets role and replace them with + newly issued keys. + +2. All project targets of the claimed roles SHOULD be compared with the last + known good consistent snapshot where none of the *timestamp*, *snapshot*, + or *claimed* keys were known to have been compromised. Added, updated, or + deleted targets in the compromised consistent snapshot that do not match + the last known good consistent snapshot MAY be restored to their previous + versions. After ensuring the integrity of all claimed project targets, the + *claimed* metadata MUST be regenerated. + +3. The claimed metadata MUST have their version numbers incremented, expiry + times suitably extended, and signatures renewed. + +Following these steps would preemptively protect all of these roles even though +only one of them may have been compromised. + +If a threshold number of *root* keys have been compromised, then PyPI MUST take +the steps taken when the *targets* role has been compromised. All of the +*root* keys must also be replaced. + +It is also RECOMMENDED that PyPI sufficiently document compromises with +security bulletins. These security bulletins will be most informative when +users of pip-with-TUF are unable to install or update a project because the +keys for the *timestamp*, *snapshot*, or *root* roles are no longer valid. +Users could then visit the PyPI web site to consult security bulletins that +would help to explain why users are no longer able to install or update, and +then take action accordingly. When a threshold number of *root* keys have not +been revoked due to a compromise, then new *root* metadata may be safely +updated because a threshold number of existing *root* keys will be used to sign +for the integrity of the new *root* metadata. TUF clients will be able to +verify the integrity of the new *root* metadata with a threshold number of +previously known *root* keys. This will be the common case. In the worst +case, where a threshold number of *root* keys have been revoked due to a +compromise, an end-user may choose to update new *root* metadata with +`out-of-band`__ mechanisms. + +__ https://en.wikipedia.org/wiki/Out-of-band#Authentication + + +Appendix A: PyPI Build Farm and End-to-End Signing +================================================== + +PyPI administrators intend to support a central build farm. The PyPI build +farm will auto-generate a `Wheel`__, for each distribution that is uploaded by +developers, on PyPI infrastructure and on supported platforms. Package +managers will likely install projects by downloading these PyPI Wheels (which +can be installed much faster than source distributions) rather than the source +distributions signed by developers. The implications of having a central build +farm with end-to-end signing SHOULD be investigated before the maximum security +model is implemented. + +__ http://wheel.readthedocs.org/en/latest/ + +An issue with a central build farm and end-to-end signing is that developers +are unlikely to sign Wheel distributions once they have been generated on PyPI +infrastructure. However, generating wheels from source distributions that are +signed by developers can still be beneficial, provided that building Wheels is +a deterministic process. If deterministic builds are infeasible, developers +may delegate trust of these wheels to a PyPI role that signs for wheels with +an online key. + + +References +========== + +.. [1] https://www.python.org/dev/peps/pep-0458/ +.. [2] https://isis.poly.edu/~jcappos/papers/samuel_tuf_ccs_2010.pdf +.. [3] https://github.com/theupdateframework/tuf/blob/develop/docs/tuf-spec.txt +.. [4] http://www.python.org/dev/peps/pep-0426/ +.. [5] https://github.com/theupdateframework/pip/wiki/Attacks-on-software-repositories +.. [6] https://mail.python.org/pipermail/distutils-sig/2013-September/022773.html +.. [7] https://isis.poly.edu/~jcappos/papers/cappos_mirror_ccs_08.pdf +.. [8] https://mail.python.org/pipermail/distutils-sig/2013-September/022755.html +.. [9] https://pypi.python.org/security +.. [10] https://mail.python.org/pipermail/distutils-sig/2013-August/022154.html +.. [11] https://en.wikipedia.org/wiki/RSA_%28algorithm%29 +.. [12] http://ed25519.cr.yp.to/ + + +Acknowledgements +================ + +This material is based upon work supported by the National Science Foundation +under Grants No. CNS-1345049 and CNS-0959138. Any opinions, findings, and +conclusions or recommendations expressed in this material are those of the +author(s) and do not necessarily reflect the views of the National Science +Foundation. + +We thank Nick Coghlan, Daniel Holth and the distutils-sig community in general +for helping us to think about how to usably and efficiently integrate TUF with +PyPI. + +Roger Dingledine, Sebastian Hahn, Nick Mathewson, Martin Peck and Justin +Samuel helped us to design TUF from its predecessor Thandy of the Tor project. + +We appreciate the efforts of Konstantin Andrianov, Geremy Condra, Zane Fisher, +Justin Samuel, Tian Tian, Santiago Torres, John Ward, and Yuyu Zheng to develop +TUF. + + +Copyright +========= + +This document has been placed in the public domain. -- Repository URL: https://hg.python.org/peps From solipsis at pitrou.net Thu Nov 20 10:33:44 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 20 Nov 2014 10:33:44 +0100 Subject: [Python-checkins] Daily reference leaks (23ab1197df0b): sum=3 Message-ID: results for 23ab1197df0b on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogUYAATt', '-x'] From python-checkins at python.org Thu Nov 20 11:12:19 2014 From: python-checkins at python.org (ned.deily) Date: Thu, 20 Nov 2014 10:12:19 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgMjI4Nzg6?= =?utf-8?q?_PEP_477_-_=22make_install=22_and_=22make_altinstall=22_integra?= =?utf-8?q?tion?= Message-ID: <20141120101212.43934.96838@psf.io> https://hg.python.org/cpython/rev/07f4b6ecd04a changeset: 93514:07f4b6ecd04a branch: 2.7 parent: 93506:6e26b5291c41 user: Ned Deily date: Thu Nov 20 02:11:03 2014 -0800 summary: Issue 22878: PEP 477 - "make install" and "make altinstall" integration The backport of ensurepip to 2.7.9 allows pip to optionally be installed or upgraded using the bundled pip provided by the new ensurepip module. The option can be specified persistently using the configure option: ./configure --with-ensurepip[=upgrade|install|no] It can also be overridden on either the "install" or "altinstall" targets: make [alt]install ENSUREPIP=[upgrade|install|no] For Python 2, the default option is "no" (do not install pip). files: Doc/using/unix.rst | 2 ++ Doc/whatsnew/2.7.rst | 5 +++++ Mac/Makefile.in | 29 +++++++++++++++++++++++++++-- Makefile.pre.in | 32 +++++++++++++++++++++++++++----- Misc/NEWS | 7 +++++++ configure | 30 ++++++++++++++++++++++++++++++ configure.ac | 15 +++++++++++++++ 7 files changed, 113 insertions(+), 7 deletions(-) diff --git a/Doc/using/unix.rst b/Doc/using/unix.rst --- a/Doc/using/unix.rst +++ b/Doc/using/unix.rst @@ -59,6 +59,8 @@ of Python are available and can be installed with e.g. ``pkgutil -i python27``. +.. _building-python-on-unix: + Building Python =============== diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -2605,6 +2605,11 @@ all platforms (where X.Y stands for the version of the Python installation), along with the ``pip`` Python package and its dependencies. +For CPython :ref:`source builds on POSIX systems `, +the ``make install`` and ``make altinstall`` commands do not bootstrap ``pip`` +by default. This behaviour can be controlled through configure options, and +overridden through Makefile options. + On Windows and Mac OS X, the CPython installers now default to installing ``pip`` along with CPython itself (users may opt out of installing it during the installation process). Window users will need to opt in to the diff --git a/Mac/Makefile.in b/Mac/Makefile.in --- a/Mac/Makefile.in +++ b/Mac/Makefile.in @@ -3,9 +3,11 @@ # commandline in that case. VERSION=@VERSION@ +ENSUREPIP=@ENSUREPIP@ builddir = .. srcdir=@srcdir@ prefix=@prefix@ +exec_prefix=@exec_prefix@ LIBDEST=$(prefix)/lib/python$(VERSION) RUNSHARED=@RUNSHARED@ BUILDEXE=@BUILDEXEEXT@ @@ -21,7 +23,7 @@ export MACOSX_DEPLOYMENT_TARGET # These are normally glimpsed from the previous set -bindir=$(prefix)/bin +BINDIR= @bindir@ PYTHONAPPSDIR=@FRAMEWORKINSTALLAPPSPREFIX@/$(PYTHONFRAMEWORK) $(VERSION) APPINSTALLDIR=$(prefix)/Resources/Python.app @@ -92,6 +94,18 @@ ln -fs "$(prefix)/bin/$${fn}" "$(DESTDIR)$(FRAMEWORKUNIXTOOLSPREFIX)/bin/$${fn}" ;\ done endif + -if test "x$(ENSUREPIP)" != "xno" ; then \ + cd "$(DESTDIR)$(FRAMEWORKUNIXTOOLSPREFIX)/bin" && \ + for fn in \ + easy_install \ + pip \ + pip2 \ + ; \ + do \ + rm -f $${fn} ;\ + $(LN) -s $(BINDIR)/$${fn} $${fn} ;\ + done ;\ + fi # @@ -112,7 +126,18 @@ ln -fs "$(prefix)/bin/$${fn}" "$(DESTDIR)$(FRAMEWORKUNIXTOOLSPREFIX)/bin/$${fn}" ;\ done endif - ln -fs "$(prefix)/bin/2to3-$(VERSION)" "$(DESTDIR)$(FRAMEWORKUNIXTOOLSPREFIX)/bin/2to3-$(VERSION)" ;\ + ln -fs "$(prefix)/bin/2to3-$(VERSION)" "$(DESTDIR)$(FRAMEWORKUNIXTOOLSPREFIX)/bin/2to3-$(VERSION)" + -if test "x$(ENSUREPIP)" != "xno" ; then \ + cd "$(DESTDIR)$(FRAMEWORKUNIXTOOLSPREFIX)/bin" && \ + for fn in \ + easy_install-$(VERSION) \ + pip$(VERSION) \ + ; \ + do \ + rm -f $${fn} ;\ + $(LN) -s $(BINDIR)/$${fn} $${fn} ;\ + done ;\ + fi # By default most tools are installed without a version in their basename, to # make it easier to install (and use) several python versions side-by-side move diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -144,6 +144,9 @@ # Environment to run shared python without installed libraries RUNSHARED= @RUNSHARED@ +# ensurepip options +ENSUREPIP= @ENSUREPIP@ + # Modes for directories, executables and data files created by the # install process. Default to user-only-writable for all file types. DIRMODE= 755 @@ -829,12 +832,31 @@ $(TESTPYTHON) $(TESTPROG) $(MEMTESTOPTS) # Install everything -install: @FRAMEWORKINSTALLFIRST@ altinstall bininstall maninstall @FRAMEWORKINSTALLLAST@ +install: @FRAMEWORKINSTALLFIRST@ commoninstall bininstall maninstall @FRAMEWORKINSTALLLAST@ + if test "x$(ENSUREPIP)" != "xno" ; then \ + case $(ENSUREPIP) in \ + upgrade) ensurepip="--upgrade" ;; \ + install|*) ensurepip="" ;; \ + esac; \ + $(RUNSHARED) $(PYTHON_FOR_BUILD) -m ensurepip \ + $$ensurepip --root=$(DESTDIR)/ ; \ + fi # Install almost everything without disturbing previous versions -altinstall: @FRAMEWORKALTINSTALLFIRST@ altbininstall libinstall inclinstall \ - libainstall altmaninstall \ - sharedinstall oldsharedinstall @FRAMEWORKALTINSTALLLAST@ +altinstall: commoninstall + if test "x$(ENSUREPIP)" != "xno" ; then \ + case $(ENSUREPIP) in \ + upgrade) ensurepip="--altinstall --upgrade --no-default-pip" ;; \ + install|*) ensurepip="--altinstall --no-default-pip" ;; \ + esac; \ + $(RUNSHARED) $(PYTHON_FOR_BUILD) -m ensurepip \ + $$ensurepip --root=$(DESTDIR)/ ; \ + fi + +commoninstall: @FRAMEWORKALTINSTALLFIRST@ \ + altbininstall libinstall inclinstall libainstall \ + sharedinstall oldsharedinstall altmaninstall \ + @FRAMEWORKALTINSTALLLAST@ # Install shared libraries enabled by Setup DESTDIRS= $(exec_prefix) $(LIBDIR) $(BINLIBDEST) $(DESTSHARED) @@ -1371,7 +1393,7 @@ .PHONY: frameworkinstall frameworkinstallframework frameworkinstallstructure .PHONY: frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools .PHONY: frameworkaltinstallunixtools recheck autoconf clean clobber distclean -.PHONY: smelly funny patchcheck touch altmaninstall +.PHONY: smelly funny patchcheck touch altmaninstall commoninstall .PHONY: gdbhooks # IF YOU PUT ANYTHING HERE IT WILL GO AWAY diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -326,6 +326,13 @@ - Issue #22877: PEP 477 - OS X installer now installs pip. +- Issue #22878: PEP 477 - "make install" and "make altinstall" can now install + or upgrade pip, using the bundled pip provided by the backported ensurepip + module. A configure option, --with-ensurepip[=upgrade|install|no], is + available to set the option for subsequent installs; the default for Python 2 + in "no" (do not install or upgrade pip). The option can also be set with + "make [alt]install ENSUREPIP=[upgrade|install|no]". + Windows ------- diff --git a/configure b/configure --- a/configure +++ b/configure @@ -624,6 +624,7 @@ #endif" ac_subst_vars='LTLIBOBJS +ENSUREPIP SRCDIRS THREADHEADERS UNICODE_OBJS @@ -807,6 +808,7 @@ with_libc enable_big_digits enable_unicode +with_ensurepip ' ac_precious_vars='build_alias host_alias @@ -1486,6 +1488,9 @@ --with-fpectl enable SIGFPE catching --with-libm=STRING math library --with-libc=STRING C library + --with(out)-ensurepip=[=OPTION] + "install" or "upgrade" using bundled pip, default is + "no" Some influential environment variables: CC C compiler command @@ -14604,6 +14609,31 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } +# ensurepip option +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ensurepip" >&5 +$as_echo_n "checking for ensurepip... " >&6; } + +# Check whether --with-ensurepip was given. +if test "${with_ensurepip+set}" = set; then : + withval=$with_ensurepip; +else + with_ensurepip=no +fi + +case $with_ensurepip in #( + yes|upgrade) : + ENSUREPIP=upgrade ;; #( + install) : + ENSUREPIP=install ;; #( + no) : + ENSUREPIP=no ;; #( + *) : + as_fn_error $? "--with-ensurepip=upgrade|install|no" "$LINENO" 5 ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ENSUREPIP" >&5 +$as_echo "$ENSUREPIP" >&6; } + + # generate output files ac_config_files="$ac_config_files Makefile.pre Modules/Setup.config Misc/python.pc" diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -4552,6 +4552,21 @@ done AC_MSG_RESULT(done) +# ensurepip option +AC_MSG_CHECKING(for ensurepip) +AC_ARG_WITH(ensurepip, + [AS_HELP_STRING([--with(out)-ensurepip=@<:@=OPTION@:>@], + ["install" or "upgrade" using bundled pip, default is "no"])], + [], + [with_ensurepip=no]) +AS_CASE($with_ensurepip, + [yes|upgrade],[ENSUREPIP=upgrade], + [install],[ENSUREPIP=install], + [no],[ENSUREPIP=no], + [AC_MSG_ERROR([--with-ensurepip=upgrade|install|no])]) +AC_MSG_RESULT($ENSUREPIP) +AC_SUBST(ENSUREPIP) + # generate output files AC_CONFIG_FILES(Makefile.pre Modules/Setup.config Misc/python.pc) AC_CONFIG_FILES([Modules/ld_so_aix], [chmod +x Modules/ld_so_aix]) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 20 12:40:30 2014 From: python-checkins at python.org (nick.coghlan) Date: Thu, 20 Nov 2014 11:40:30 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322869=3A_Split_py?= =?utf-8?q?thonrun_into_two_modules?= Message-ID: <20141120114020.7140.72477@psf.io> https://hg.python.org/cpython/rev/b9775a92c1d0 changeset: 93515:b9775a92c1d0 parent: 93513:23ab1197df0b user: Nick Coghlan date: Thu Nov 20 21:39:37 2014 +1000 summary: Issue #22869: Split pythonrun into two modules - interpreter startup and shutdown code moved to a new pylifecycle.c module - Py_OptimizeFlag moved into the new module with the other global flags files: Include/Python.h | 1 + Include/object.h | 7 + Include/pydebug.h | 2 + Include/pyerrors.h | 1 + Include/pylifecycle.h | 124 ++ Include/pythonrun.h | 110 -- Lib/_pyio.py | 2 +- Makefile.pre.in | 2 + Misc/NEWS | 3 + Modules/atexitmodule.c | 2 +- Modules/signalmodule.c | 2 +- Objects/object.c | 16 + Python/compile.c | 2 - Python/pylifecycle.c | 1540 ++++++++++++++++++++++++++++ Python/pythonrun.c | 1472 +-------------------------- Python/sysmodule.c | 2 +- 16 files changed, 1701 insertions(+), 1587 deletions(-) diff --git a/Include/Python.h b/Include/Python.h --- a/Include/Python.h +++ b/Include/Python.h @@ -112,6 +112,7 @@ #include "pyarena.h" #include "modsupport.h" #include "pythonrun.h" +#include "pylifecycle.h" #include "ceval.h" #include "sysmodule.h" #include "intrcheck.h" diff --git a/Include/object.h b/Include/object.h --- a/Include/object.h +++ b/Include/object.h @@ -65,6 +65,7 @@ #error Py_LIMITED_API is incompatible with Py_DEBUG, Py_TRACE_REFS, and Py_REF_DEBUG #endif + #ifdef Py_TRACE_REFS /* Define pointers to support a doubly-linked list of all live heap objects. */ #define _PyObject_HEAD_EXTRA \ @@ -710,11 +711,17 @@ _Py_NegativeRefcount(__FILE__, __LINE__, \ (PyObject *)(OP)); \ } +/* Py_REF_DEBUG also controls the display of refcounts and memory block + * allocations at the interactive prompt and at interpreter shutdown + */ +PyAPI_FUNC(void) _PyDebug_PrintTotalRefs(void); +#define _PY_DEBUG_PRINT_TOTAL_REFS() _PyDebug_PrintTotalRefs() #else #define _Py_INC_REFTOTAL #define _Py_DEC_REFTOTAL #define _Py_REF_DEBUG_COMMA #define _Py_CHECK_REFCNT(OP) /* a semicolon */; +#define _PY_DEBUG_PRINT_TOTAL_REFS() #endif /* Py_REF_DEBUG */ #ifdef COUNT_ALLOCS diff --git a/Include/pydebug.h b/Include/pydebug.h --- a/Include/pydebug.h +++ b/Include/pydebug.h @@ -5,6 +5,8 @@ extern "C" { #endif +/* These global variable are defined in pylifecycle.c */ +/* XXX (ncoghlan): move these declarations to pylifecycle.h? */ PyAPI_DATA(int) Py_DebugFlag; PyAPI_DATA(int) Py_VerboseFlag; PyAPI_DATA(int) Py_QuietFlag; diff --git a/Include/pyerrors.h b/Include/pyerrors.h --- a/Include/pyerrors.h +++ b/Include/pyerrors.h @@ -99,6 +99,7 @@ #define _Py_NO_RETURN #endif +/* Defined in Python/pylifecycle.c */ PyAPI_FUNC(void) Py_FatalError(const char *message) _Py_NO_RETURN; #if defined(Py_DEBUG) || defined(Py_LIMITED_API) diff --git a/Include/pylifecycle.h b/Include/pylifecycle.h new file mode 100644 --- /dev/null +++ b/Include/pylifecycle.h @@ -0,0 +1,124 @@ + +/* Interfaces to configure, query, create & destroy the Python runtime */ + +#ifndef Py_PYLIFECYCLE_H +#define Py_PYLIFECYCLE_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_FUNC(void) Py_SetProgramName(wchar_t *); +PyAPI_FUNC(wchar_t *) Py_GetProgramName(void); + +PyAPI_FUNC(void) Py_SetPythonHome(wchar_t *); +PyAPI_FUNC(wchar_t *) Py_GetPythonHome(void); + +#ifndef Py_LIMITED_API +/* Only used by applications that embed the interpreter and need to + * override the standard encoding determination mechanism + */ +PyAPI_FUNC(int) Py_SetStandardStreamEncoding(const char *encoding, + const char *errors); +#endif + +PyAPI_FUNC(void) Py_Initialize(void); +PyAPI_FUNC(void) Py_InitializeEx(int); +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) _Py_InitializeEx_Private(int, int); +#endif +PyAPI_FUNC(void) Py_Finalize(void); +PyAPI_FUNC(int) Py_IsInitialized(void); +PyAPI_FUNC(PyThreadState *) Py_NewInterpreter(void); +PyAPI_FUNC(void) Py_EndInterpreter(PyThreadState *); + + +/* Py_PyAtExit is for the atexit module, Py_AtExit is for low-level + * exit functions. + */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) _Py_PyAtExit(void (*func)(void)); +#endif +PyAPI_FUNC(int) Py_AtExit(void (*func)(void)); + +PyAPI_FUNC(void) Py_Exit(int); + +/* Restore signals that the interpreter has called SIG_IGN on to SIG_DFL. */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) _Py_RestoreSignals(void); + +PyAPI_FUNC(int) Py_FdIsInteractive(FILE *, const char *); +#endif + +/* Bootstrap __main__ (defined in Modules/main.c) */ +PyAPI_FUNC(int) Py_Main(int argc, wchar_t **argv); + +/* In getpath.c */ +PyAPI_FUNC(wchar_t *) Py_GetProgramFullPath(void); +PyAPI_FUNC(wchar_t *) Py_GetPrefix(void); +PyAPI_FUNC(wchar_t *) Py_GetExecPrefix(void); +PyAPI_FUNC(wchar_t *) Py_GetPath(void); +PyAPI_FUNC(void) Py_SetPath(const wchar_t *); +#ifdef MS_WINDOWS +int _Py_CheckPython3(); +#endif + +/* In their own files */ +PyAPI_FUNC(const char *) Py_GetVersion(void); +PyAPI_FUNC(const char *) Py_GetPlatform(void); +PyAPI_FUNC(const char *) Py_GetCopyright(void); +PyAPI_FUNC(const char *) Py_GetCompiler(void); +PyAPI_FUNC(const char *) Py_GetBuildInfo(void); +#ifndef Py_LIMITED_API +PyAPI_FUNC(const char *) _Py_hgidentifier(void); +PyAPI_FUNC(const char *) _Py_hgversion(void); +#endif + +/* Internal -- various one-time initializations */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PyBuiltin_Init(void); +PyAPI_FUNC(PyObject *) _PySys_Init(void); +PyAPI_FUNC(void) _PyImport_Init(void); +PyAPI_FUNC(void) _PyExc_Init(PyObject * bltinmod); +PyAPI_FUNC(void) _PyImportHooks_Init(void); +PyAPI_FUNC(int) _PyFrame_Init(void); +PyAPI_FUNC(int) _PyFloat_Init(void); +PyAPI_FUNC(int) PyByteArray_Init(void); +PyAPI_FUNC(void) _PyRandom_Init(void); +#endif + +/* Various internal finalizers */ +#ifndef Py_LIMITED_API +PyAPI_FUNC(void) _PyExc_Fini(void); +PyAPI_FUNC(void) _PyImport_Fini(void); +PyAPI_FUNC(void) PyMethod_Fini(void); +PyAPI_FUNC(void) PyFrame_Fini(void); +PyAPI_FUNC(void) PyCFunction_Fini(void); +PyAPI_FUNC(void) PyDict_Fini(void); +PyAPI_FUNC(void) PyTuple_Fini(void); +PyAPI_FUNC(void) PyList_Fini(void); +PyAPI_FUNC(void) PySet_Fini(void); +PyAPI_FUNC(void) PyBytes_Fini(void); +PyAPI_FUNC(void) PyByteArray_Fini(void); +PyAPI_FUNC(void) PyFloat_Fini(void); +PyAPI_FUNC(void) PyOS_FiniInterrupts(void); +PyAPI_FUNC(void) _PyGC_DumpShutdownStats(void); +PyAPI_FUNC(void) _PyGC_Fini(void); +PyAPI_FUNC(void) PySlice_Fini(void); +PyAPI_FUNC(void) _PyType_Fini(void); +PyAPI_FUNC(void) _PyRandom_Fini(void); + +PyAPI_DATA(PyThreadState *) _Py_Finalizing; +#endif + +/* Signals */ +typedef void (*PyOS_sighandler_t)(int); +PyAPI_FUNC(PyOS_sighandler_t) PyOS_getsig(int); +PyAPI_FUNC(PyOS_sighandler_t) PyOS_setsig(int, PyOS_sighandler_t); + +/* Random */ +PyAPI_FUNC(int) _PyOS_URandom (void *buffer, Py_ssize_t size); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PYLIFECYCLE_H */ diff --git a/Include/pythonrun.h b/Include/pythonrun.h --- a/Include/pythonrun.h +++ b/Include/pythonrun.h @@ -22,30 +22,6 @@ } PyCompilerFlags; #endif -PyAPI_FUNC(void) Py_SetProgramName(wchar_t *); -PyAPI_FUNC(wchar_t *) Py_GetProgramName(void); - -PyAPI_FUNC(void) Py_SetPythonHome(wchar_t *); -PyAPI_FUNC(wchar_t *) Py_GetPythonHome(void); - -#ifndef Py_LIMITED_API -/* Only used by applications that embed the interpreter and need to - * override the standard encoding determination mechanism - */ -PyAPI_FUNC(int) Py_SetStandardStreamEncoding(const char *encoding, - const char *errors); -#endif - -PyAPI_FUNC(void) Py_Initialize(void); -PyAPI_FUNC(void) Py_InitializeEx(int); -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _Py_InitializeEx_Private(int, int); -#endif -PyAPI_FUNC(void) Py_Finalize(void); -PyAPI_FUNC(int) Py_IsInitialized(void); -PyAPI_FUNC(PyThreadState *) Py_NewInterpreter(void); -PyAPI_FUNC(void) Py_EndInterpreter(PyThreadState *); - #ifndef Py_LIMITED_API PyAPI_FUNC(int) PyRun_SimpleStringFlags(const char *, PyCompilerFlags *); PyAPI_FUNC(int) PyRun_AnyFileFlags(FILE *, const char *, PyCompilerFlags *); @@ -166,26 +142,6 @@ PyAPI_FUNC(void) PyErr_PrintEx(int); PyAPI_FUNC(void) PyErr_Display(PyObject *, PyObject *, PyObject *); -/* Py_PyAtExit is for the atexit module, Py_AtExit is for low-level - * exit functions. - */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _Py_PyAtExit(void (*func)(void)); -#endif -PyAPI_FUNC(int) Py_AtExit(void (*func)(void)); - -PyAPI_FUNC(void) Py_Exit(int); - -/* Restore signals that the interpreter has called SIG_IGN on to SIG_DFL. */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _Py_RestoreSignals(void); - -PyAPI_FUNC(int) Py_FdIsInteractive(FILE *, const char *); -#endif - -/* Bootstrap */ -PyAPI_FUNC(int) Py_Main(int argc, wchar_t **argv); - #ifndef Py_LIMITED_API /* Use macros for a bunch of old variants */ #define PyRun_String(str, s, g, l) PyRun_StringFlags(str, s, g, l, NULL) @@ -207,64 +163,6 @@ PyRun_FileExFlags(fp, p, s, g, l, 0, flags) #endif -/* In getpath.c */ -PyAPI_FUNC(wchar_t *) Py_GetProgramFullPath(void); -PyAPI_FUNC(wchar_t *) Py_GetPrefix(void); -PyAPI_FUNC(wchar_t *) Py_GetExecPrefix(void); -PyAPI_FUNC(wchar_t *) Py_GetPath(void); -PyAPI_FUNC(void) Py_SetPath(const wchar_t *); -#ifdef MS_WINDOWS -int _Py_CheckPython3(); -#endif - -/* In their own files */ -PyAPI_FUNC(const char *) Py_GetVersion(void); -PyAPI_FUNC(const char *) Py_GetPlatform(void); -PyAPI_FUNC(const char *) Py_GetCopyright(void); -PyAPI_FUNC(const char *) Py_GetCompiler(void); -PyAPI_FUNC(const char *) Py_GetBuildInfo(void); -#ifndef Py_LIMITED_API -PyAPI_FUNC(const char *) _Py_hgidentifier(void); -PyAPI_FUNC(const char *) _Py_hgversion(void); -#endif - -/* Internal -- various one-time initializations */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PyBuiltin_Init(void); -PyAPI_FUNC(PyObject *) _PySys_Init(void); -PyAPI_FUNC(void) _PyImport_Init(void); -PyAPI_FUNC(void) _PyExc_Init(PyObject * bltinmod); -PyAPI_FUNC(void) _PyImportHooks_Init(void); -PyAPI_FUNC(int) _PyFrame_Init(void); -PyAPI_FUNC(int) _PyFloat_Init(void); -PyAPI_FUNC(int) PyByteArray_Init(void); -PyAPI_FUNC(void) _PyRandom_Init(void); -#endif - -/* Various internal finalizers */ -#ifndef Py_LIMITED_API -PyAPI_FUNC(void) _PyExc_Fini(void); -PyAPI_FUNC(void) _PyImport_Fini(void); -PyAPI_FUNC(void) PyMethod_Fini(void); -PyAPI_FUNC(void) PyFrame_Fini(void); -PyAPI_FUNC(void) PyCFunction_Fini(void); -PyAPI_FUNC(void) PyDict_Fini(void); -PyAPI_FUNC(void) PyTuple_Fini(void); -PyAPI_FUNC(void) PyList_Fini(void); -PyAPI_FUNC(void) PySet_Fini(void); -PyAPI_FUNC(void) PyBytes_Fini(void); -PyAPI_FUNC(void) PyByteArray_Fini(void); -PyAPI_FUNC(void) PyFloat_Fini(void); -PyAPI_FUNC(void) PyOS_FiniInterrupts(void); -PyAPI_FUNC(void) _PyGC_DumpShutdownStats(void); -PyAPI_FUNC(void) _PyGC_Fini(void); -PyAPI_FUNC(void) PySlice_Fini(void); -PyAPI_FUNC(void) _PyType_Fini(void); -PyAPI_FUNC(void) _PyRandom_Fini(void); - -PyAPI_DATA(PyThreadState *) _Py_Finalizing; -#endif - /* Stuff with no proper home (yet) */ #ifndef Py_LIMITED_API PyAPI_FUNC(char *) PyOS_Readline(FILE *, FILE *, const char *); @@ -290,14 +188,6 @@ PyAPI_FUNC(int) PyOS_CheckStack(void); #endif -/* Signals */ -typedef void (*PyOS_sighandler_t)(int); -PyAPI_FUNC(PyOS_sighandler_t) PyOS_getsig(int); -PyAPI_FUNC(PyOS_sighandler_t) PyOS_setsig(int, PyOS_sighandler_t); - -/* Random */ -PyAPI_FUNC(int) _PyOS_URandom (void *buffer, Py_ssize_t size); - #ifdef __cplusplus } #endif diff --git a/Lib/_pyio.py b/Lib/_pyio.py --- a/Lib/_pyio.py +++ b/Lib/_pyio.py @@ -257,7 +257,7 @@ Trick so that open won't become a bound method when stored as a class variable (as dbm.dumb does). - See initstdio() in Python/pythonrun.c. + See initstdio() in Python/pylifecycle.c. """ __doc__ = DocDescriptor() diff --git a/Makefile.pre.in b/Makefile.pre.in --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -389,6 +389,7 @@ Python/pyctype.o \ Python/pyfpe.o \ Python/pyhash.o \ + Python/pylifecycle.o \ Python/pymath.o \ Python/pystate.o \ Python/pythonrun.o \ @@ -909,6 +910,7 @@ $(srcdir)/Include/pyerrors.h \ $(srcdir)/Include/pyfpe.h \ $(srcdir)/Include/pyhash.h \ + $(srcdir)/Include/pylifecycle.h \ $(srcdir)/Include/pymath.h \ $(srcdir)/Include/pygetopt.h \ $(srcdir)/Include/pymacro.h \ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #22869: Move the interpreter startup & shutdown code to a new + dedicated pylifecycle.c module + - Issue #22847: Improve method cache efficiency. - Issue #22335: Fix crash when trying to enlarge a bytearray to 0x7fffffff diff --git a/Modules/atexitmodule.c b/Modules/atexitmodule.c --- a/Modules/atexitmodule.c +++ b/Modules/atexitmodule.c @@ -60,7 +60,7 @@ modstate->ncallbacks = 0; } -/* Installed into pythonrun.c's atexit mechanism */ +/* Installed into pylifecycle.c's atexit mechanism */ static void atexit_callfuncs(void) diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -304,7 +304,7 @@ if (sig_num != SIGCHLD) #endif /* If the handler was not set up with sigaction, reinstall it. See - * Python/pythonrun.c for the implementation of PyOS_setsig which + * Python/pylifecycle.c for the implementation of PyOS_setsig which * makes this true. See also issue8354. */ PyOS_setsig(sig_num, signal_handler); #endif diff --git a/Objects/object.c b/Objects/object.c --- a/Objects/object.c +++ b/Objects/object.c @@ -33,6 +33,22 @@ total -= o->ob_refcnt; return total; } + +void +_PyDebug_PrintTotalRefs(void) { + PyObject *xoptions, *value; + _Py_IDENTIFIER(showrefcount); + + xoptions = PySys_GetXOptions(); + if (xoptions == NULL) + return; + value = _PyDict_GetItemId(xoptions, &PyId_showrefcount); + if (value == Py_True) + fprintf(stderr, + "[%" PY_FORMAT_SIZE_T "d refs, " + "%" PY_FORMAT_SIZE_T "d blocks]\n", + _Py_GetRefTotal(), _Py_GetAllocatedBlocks()); +} #endif /* Py_REF_DEBUG */ /* Object allocation routines used by NEWOBJ and NEWVAROBJ macros. diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -30,8 +30,6 @@ #include "symtable.h" #include "opcode.h" -int Py_OptimizeFlag = 0; - #define DEFAULT_BLOCK_SIZE 16 #define DEFAULT_BLOCKS 8 #define DEFAULT_CODE_SIZE 128 diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c new file mode 100644 --- /dev/null +++ b/Python/pylifecycle.c @@ -0,0 +1,1540 @@ + +/* Python interpreter top-level routines, including init/exit */ + +#include "Python.h" + +#include "Python-ast.h" +#undef Yield /* undefine macro conflicting with winbase.h */ +#include "grammar.h" +#include "node.h" +#include "token.h" +#include "parsetok.h" +#include "errcode.h" +#include "code.h" +#include "symtable.h" +#include "ast.h" +#include "marshal.h" +#include "osdefs.h" +#include + +#ifdef HAVE_SIGNAL_H +#include +#endif + +#ifdef MS_WINDOWS +#include "malloc.h" /* for alloca */ +#endif + +#ifdef HAVE_LANGINFO_H +#include +#endif + +#ifdef MS_WINDOWS +#undef BYTE +#include "windows.h" +#endif + +_Py_IDENTIFIER(flush); +_Py_IDENTIFIER(name); +_Py_IDENTIFIER(stdin); +_Py_IDENTIFIER(stdout); +_Py_IDENTIFIER(stderr); + +#ifdef __cplusplus +extern "C" { +#endif + +extern wchar_t *Py_GetPath(void); + +extern grammar _PyParser_Grammar; /* From graminit.c */ + +/* Forward */ +static void initmain(PyInterpreterState *interp); +static int initfsencoding(PyInterpreterState *interp); +static void initsite(void); +static int initstdio(void); +static void initsigs(void); +static void call_py_exitfuncs(void); +static void wait_for_thread_shutdown(void); +static void call_ll_exitfuncs(void); +extern int _PyUnicode_Init(void); +extern int _PyStructSequence_Init(void); +extern void _PyUnicode_Fini(void); +extern int _PyLong_Init(void); +extern void PyLong_Fini(void); +extern int _PyFaulthandler_Init(void); +extern void _PyFaulthandler_Fini(void); +extern void _PyHash_Fini(void); +extern int _PyTraceMalloc_Init(void); +extern int _PyTraceMalloc_Fini(void); + +#ifdef WITH_THREAD +extern void _PyGILState_Init(PyInterpreterState *, PyThreadState *); +extern void _PyGILState_Fini(void); +#endif /* WITH_THREAD */ + +/* Global configuration variable declarations are in pydebug.h */ +/* XXX (ncoghlan): move those declarations to pylifecycle.h? */ +int Py_DebugFlag; /* Needed by parser.c */ +int Py_VerboseFlag; /* Needed by import.c */ +int Py_QuietFlag; /* Needed by sysmodule.c */ +int Py_InteractiveFlag; /* Needed by Py_FdIsInteractive() below */ +int Py_InspectFlag; /* Needed to determine whether to exit at SystemExit */ +int Py_OptimizeFlag = 0; /* Needed by compile.c */ +int Py_NoSiteFlag; /* Suppress 'import site' */ +int Py_BytesWarningFlag; /* Warn on str(bytes) and str(buffer) */ +int Py_UseClassExceptionsFlag = 1; /* Needed by bltinmodule.c: deprecated */ +int Py_FrozenFlag; /* Needed by getpath.c */ +int Py_IgnoreEnvironmentFlag; /* e.g. PYTHONPATH, PYTHONHOME */ +int Py_DontWriteBytecodeFlag; /* Suppress writing bytecode files (*.py[co]) */ +int Py_NoUserSiteDirectory = 0; /* for -s and site.py */ +int Py_UnbufferedStdioFlag = 0; /* Unbuffered binary std{in,out,err} */ +int Py_HashRandomizationFlag = 0; /* for -R and PYTHONHASHSEED */ +int Py_IsolatedFlag = 0; /* for -I, isolate from user's env */ + +PyThreadState *_Py_Finalizing = NULL; + +/* Hack to force loading of object files */ +int (*_PyOS_mystrnicmp_hack)(const char *, const char *, Py_ssize_t) = \ + PyOS_mystrnicmp; /* Python/pystrcmp.o */ + +/* PyModule_GetWarningsModule is no longer necessary as of 2.6 +since _warnings is builtin. This API should not be used. */ +PyObject * +PyModule_GetWarningsModule(void) +{ + return PyImport_ImportModule("warnings"); +} + +static int initialized = 0; + +/* API to access the initialized flag -- useful for esoteric use */ + +int +Py_IsInitialized(void) +{ + return initialized; +} + +/* Helper to allow an embedding application to override the normal + * mechanism that attempts to figure out an appropriate IO encoding + */ + +static char *_Py_StandardStreamEncoding = NULL; +static char *_Py_StandardStreamErrors = NULL; + +int +Py_SetStandardStreamEncoding(const char *encoding, const char *errors) +{ + if (Py_IsInitialized()) { + /* This is too late to have any effect */ + return -1; + } + /* Can't call PyErr_NoMemory() on errors, as Python hasn't been + * initialised yet. + * + * However, the raw memory allocators are initialised appropriately + * as C static variables, so _PyMem_RawStrdup is OK even though + * Py_Initialize hasn't been called yet. + */ + if (encoding) { + _Py_StandardStreamEncoding = _PyMem_RawStrdup(encoding); + if (!_Py_StandardStreamEncoding) { + return -2; + } + } + if (errors) { + _Py_StandardStreamErrors = _PyMem_RawStrdup(errors); + if (!_Py_StandardStreamErrors) { + if (_Py_StandardStreamEncoding) { + PyMem_RawFree(_Py_StandardStreamEncoding); + } + return -3; + } + } + return 0; +} + +/* Global initializations. Can be undone by Py_Finalize(). Don't + call this twice without an intervening Py_Finalize() call. When + initializations fail, a fatal error is issued and the function does + not return. On return, the first thread and interpreter state have + been created. + + Locking: you must hold the interpreter lock while calling this. + (If the lock has not yet been initialized, that's equivalent to + having the lock, but you cannot use multiple threads.) + +*/ + +static int +add_flag(int flag, const char *envs) +{ + int env = atoi(envs); + if (flag < env) + flag = env; + if (flag < 1) + flag = 1; + return flag; +} + +static char* +get_codec_name(const char *encoding) +{ + char *name_utf8, *name_str; + PyObject *codec, *name = NULL; + + codec = _PyCodec_Lookup(encoding); + if (!codec) + goto error; + + name = _PyObject_GetAttrId(codec, &PyId_name); + Py_CLEAR(codec); + if (!name) + goto error; + + name_utf8 = _PyUnicode_AsString(name); + if (name_utf8 == NULL) + goto error; + name_str = _PyMem_RawStrdup(name_utf8); + Py_DECREF(name); + if (name_str == NULL) { + PyErr_NoMemory(); + return NULL; + } + return name_str; + +error: + Py_XDECREF(codec); + Py_XDECREF(name); + return NULL; +} + +static char* +get_locale_encoding(void) +{ +#ifdef MS_WINDOWS + char codepage[100]; + PyOS_snprintf(codepage, sizeof(codepage), "cp%d", GetACP()); + return get_codec_name(codepage); +#elif defined(HAVE_LANGINFO_H) && defined(CODESET) + char* codeset = nl_langinfo(CODESET); + if (!codeset || codeset[0] == '\0') { + PyErr_SetString(PyExc_ValueError, "CODESET is not set or empty"); + return NULL; + } + return get_codec_name(codeset); +#else + PyErr_SetNone(PyExc_NotImplementedError); + return NULL; +#endif +} + +static void +import_init(PyInterpreterState *interp, PyObject *sysmod) +{ + PyObject *importlib; + PyObject *impmod; + PyObject *sys_modules; + PyObject *value; + + /* Import _importlib through its frozen version, _frozen_importlib. */ + if (PyImport_ImportFrozenModule("_frozen_importlib") <= 0) { + Py_FatalError("Py_Initialize: can't import _frozen_importlib"); + } + else if (Py_VerboseFlag) { + PySys_FormatStderr("import _frozen_importlib # frozen\n"); + } + importlib = PyImport_AddModule("_frozen_importlib"); + if (importlib == NULL) { + Py_FatalError("Py_Initialize: couldn't get _frozen_importlib from " + "sys.modules"); + } + interp->importlib = importlib; + Py_INCREF(interp->importlib); + + /* Install _importlib as __import__ */ + impmod = PyInit_imp(); + if (impmod == NULL) { + Py_FatalError("Py_Initialize: can't import imp"); + } + else if (Py_VerboseFlag) { + PySys_FormatStderr("import imp # builtin\n"); + } + sys_modules = PyImport_GetModuleDict(); + if (Py_VerboseFlag) { + PySys_FormatStderr("import sys # builtin\n"); + } + if (PyDict_SetItemString(sys_modules, "_imp", impmod) < 0) { + Py_FatalError("Py_Initialize: can't save _imp to sys.modules"); + } + + value = PyObject_CallMethod(importlib, "_install", "OO", sysmod, impmod); + if (value == NULL) { + PyErr_Print(); + Py_FatalError("Py_Initialize: importlib install failed"); + } + Py_DECREF(value); + Py_DECREF(impmod); + + _PyImportZip_Init(); +} + + +void +_Py_InitializeEx_Private(int install_sigs, int install_importlib) +{ + PyInterpreterState *interp; + PyThreadState *tstate; + PyObject *bimod, *sysmod, *pstderr; + char *p; + extern void _Py_ReadyTypes(void); + + if (initialized) + return; + initialized = 1; + _Py_Finalizing = NULL; + +#if defined(HAVE_LANGINFO_H) && defined(HAVE_SETLOCALE) + /* Set up the LC_CTYPE locale, so we can obtain + the locale's charset without having to switch + locales. */ + setlocale(LC_CTYPE, ""); +#endif + + if ((p = Py_GETENV("PYTHONDEBUG")) && *p != '\0') + Py_DebugFlag = add_flag(Py_DebugFlag, p); + if ((p = Py_GETENV("PYTHONVERBOSE")) && *p != '\0') + Py_VerboseFlag = add_flag(Py_VerboseFlag, p); + if ((p = Py_GETENV("PYTHONOPTIMIZE")) && *p != '\0') + Py_OptimizeFlag = add_flag(Py_OptimizeFlag, p); + if ((p = Py_GETENV("PYTHONDONTWRITEBYTECODE")) && *p != '\0') + Py_DontWriteBytecodeFlag = add_flag(Py_DontWriteBytecodeFlag, p); + /* The variable is only tested for existence here; _PyRandom_Init will + check its value further. */ + if ((p = Py_GETENV("PYTHONHASHSEED")) && *p != '\0') + Py_HashRandomizationFlag = add_flag(Py_HashRandomizationFlag, p); + + _PyRandom_Init(); + + interp = PyInterpreterState_New(); + if (interp == NULL) + Py_FatalError("Py_Initialize: can't make first interpreter"); + + tstate = PyThreadState_New(interp); + if (tstate == NULL) + Py_FatalError("Py_Initialize: can't make first thread"); + (void) PyThreadState_Swap(tstate); + +#ifdef WITH_THREAD + /* We can't call _PyEval_FiniThreads() in Py_Finalize because + destroying the GIL might fail when it is being referenced from + another running thread (see issue #9901). + Instead we destroy the previously created GIL here, which ensures + that we can call Py_Initialize / Py_Finalize multiple times. */ + _PyEval_FiniThreads(); + + /* Auto-thread-state API */ + _PyGILState_Init(interp, tstate); +#endif /* WITH_THREAD */ + + _Py_ReadyTypes(); + + if (!_PyFrame_Init()) + Py_FatalError("Py_Initialize: can't init frames"); + + if (!_PyLong_Init()) + Py_FatalError("Py_Initialize: can't init longs"); + + if (!PyByteArray_Init()) + Py_FatalError("Py_Initialize: can't init bytearray"); + + if (!_PyFloat_Init()) + Py_FatalError("Py_Initialize: can't init float"); + + interp->modules = PyDict_New(); + if (interp->modules == NULL) + Py_FatalError("Py_Initialize: can't make modules dictionary"); + + /* Init Unicode implementation; relies on the codec registry */ + if (_PyUnicode_Init() < 0) + Py_FatalError("Py_Initialize: can't initialize unicode"); + if (_PyStructSequence_Init() < 0) + Py_FatalError("Py_Initialize: can't initialize structseq"); + + bimod = _PyBuiltin_Init(); + if (bimod == NULL) + Py_FatalError("Py_Initialize: can't initialize builtins modules"); + _PyImport_FixupBuiltin(bimod, "builtins"); + interp->builtins = PyModule_GetDict(bimod); + if (interp->builtins == NULL) + Py_FatalError("Py_Initialize: can't initialize builtins dict"); + Py_INCREF(interp->builtins); + + /* initialize builtin exceptions */ + _PyExc_Init(bimod); + + sysmod = _PySys_Init(); + if (sysmod == NULL) + Py_FatalError("Py_Initialize: can't initialize sys"); + interp->sysdict = PyModule_GetDict(sysmod); + if (interp->sysdict == NULL) + Py_FatalError("Py_Initialize: can't initialize sys dict"); + Py_INCREF(interp->sysdict); + _PyImport_FixupBuiltin(sysmod, "sys"); + PySys_SetPath(Py_GetPath()); + PyDict_SetItemString(interp->sysdict, "modules", + interp->modules); + + /* Set up a preliminary stderr printer until we have enough + infrastructure for the io module in place. */ + pstderr = PyFile_NewStdPrinter(fileno(stderr)); + if (pstderr == NULL) + Py_FatalError("Py_Initialize: can't set preliminary stderr"); + _PySys_SetObjectId(&PyId_stderr, pstderr); + PySys_SetObject("__stderr__", pstderr); + Py_DECREF(pstderr); + + _PyImport_Init(); + + _PyImportHooks_Init(); + + /* Initialize _warnings. */ + _PyWarnings_Init(); + + if (!install_importlib) + return; + + import_init(interp, sysmod); + + /* initialize the faulthandler module */ + if (_PyFaulthandler_Init()) + Py_FatalError("Py_Initialize: can't initialize faulthandler"); + + if (_PyTime_Init() < 0) + Py_FatalError("Py_Initialize: can't initialize time"); + + if (initfsencoding(interp) < 0) + Py_FatalError("Py_Initialize: unable to load the file system codec"); + + if (install_sigs) + initsigs(); /* Signal handling stuff, including initintr() */ + + if (_PyTraceMalloc_Init() < 0) + Py_FatalError("Py_Initialize: can't initialize tracemalloc"); + + initmain(interp); /* Module __main__ */ + if (initstdio() < 0) + Py_FatalError( + "Py_Initialize: can't initialize sys standard streams"); + + /* Initialize warnings. */ + if (PySys_HasWarnOptions()) { + PyObject *warnings_module = PyImport_ImportModule("warnings"); + if (warnings_module == NULL) { + fprintf(stderr, "'import warnings' failed; traceback:\n"); + PyErr_Print(); + } + Py_XDECREF(warnings_module); + } + + if (!Py_NoSiteFlag) + initsite(); /* Module site */ +} + +void +Py_InitializeEx(int install_sigs) +{ + _Py_InitializeEx_Private(install_sigs, 1); +} + +void +Py_Initialize(void) +{ + Py_InitializeEx(1); +} + + +#ifdef COUNT_ALLOCS +extern void dump_counts(FILE*); +#endif + +/* Flush stdout and stderr */ + +static int +file_is_closed(PyObject *fobj) +{ + int r; + PyObject *tmp = PyObject_GetAttrString(fobj, "closed"); + if (tmp == NULL) { + PyErr_Clear(); + return 0; + } + r = PyObject_IsTrue(tmp); + Py_DECREF(tmp); + if (r < 0) + PyErr_Clear(); + return r > 0; +} + +static void +flush_std_files(void) +{ + PyObject *fout = _PySys_GetObjectId(&PyId_stdout); + PyObject *ferr = _PySys_GetObjectId(&PyId_stderr); + PyObject *tmp; + + if (fout != NULL && fout != Py_None && !file_is_closed(fout)) { + tmp = _PyObject_CallMethodId(fout, &PyId_flush, ""); + if (tmp == NULL) + PyErr_WriteUnraisable(fout); + else + Py_DECREF(tmp); + } + + if (ferr != NULL && ferr != Py_None && !file_is_closed(ferr)) { + tmp = _PyObject_CallMethodId(ferr, &PyId_flush, ""); + if (tmp == NULL) + PyErr_Clear(); + else + Py_DECREF(tmp); + } +} + +/* Undo the effect of Py_Initialize(). + + Beware: if multiple interpreter and/or thread states exist, these + are not wiped out; only the current thread and interpreter state + are deleted. But since everything else is deleted, those other + interpreter and thread states should no longer be used. + + (XXX We should do better, e.g. wipe out all interpreters and + threads.) + + Locking: as above. + +*/ + +void +Py_Finalize(void) +{ + PyInterpreterState *interp; + PyThreadState *tstate; + + if (!initialized) + return; + + wait_for_thread_shutdown(); + + /* The interpreter is still entirely intact at this point, and the + * exit funcs may be relying on that. In particular, if some thread + * or exit func is still waiting to do an import, the import machinery + * expects Py_IsInitialized() to return true. So don't say the + * interpreter is uninitialized until after the exit funcs have run. + * Note that Threading.py uses an exit func to do a join on all the + * threads created thru it, so this also protects pending imports in + * the threads created via Threading. + */ + call_py_exitfuncs(); + + /* Get current thread state and interpreter pointer */ + tstate = PyThreadState_GET(); + interp = tstate->interp; + + /* Remaining threads (e.g. daemon threads) will automatically exit + after taking the GIL (in PyEval_RestoreThread()). */ + _Py_Finalizing = tstate; + initialized = 0; + + /* Flush stdout+stderr */ + flush_std_files(); + + /* Disable signal handling */ + PyOS_FiniInterrupts(); + + /* Collect garbage. This may call finalizers; it's nice to call these + * before all modules are destroyed. + * XXX If a __del__ or weakref callback is triggered here, and tries to + * XXX import a module, bad things can happen, because Python no + * XXX longer believes it's initialized. + * XXX Fatal Python error: Interpreter not initialized (version mismatch?) + * XXX is easy to provoke that way. I've also seen, e.g., + * XXX Exception exceptions.ImportError: 'No module named sha' + * XXX in ignored + * XXX but I'm unclear on exactly how that one happens. In any case, + * XXX I haven't seen a real-life report of either of these. + */ + PyGC_Collect(); +#ifdef COUNT_ALLOCS + /* With COUNT_ALLOCS, it helps to run GC multiple times: + each collection might release some types from the type + list, so they become garbage. */ + while (PyGC_Collect() > 0) + /* nothing */; +#endif + /* Destroy all modules */ + PyImport_Cleanup(); + + /* Flush stdout+stderr (again, in case more was printed) */ + flush_std_files(); + + /* Collect final garbage. This disposes of cycles created by + * class definitions, for example. + * XXX This is disabled because it caused too many problems. If + * XXX a __del__ or weakref callback triggers here, Python code has + * XXX a hard time running, because even the sys module has been + * XXX cleared out (sys.stdout is gone, sys.excepthook is gone, etc). + * XXX One symptom is a sequence of information-free messages + * XXX coming from threads (if a __del__ or callback is invoked, + * XXX other threads can execute too, and any exception they encounter + * XXX triggers a comedy of errors as subsystem after subsystem + * XXX fails to find what it *expects* to find in sys to help report + * XXX the exception and consequent unexpected failures). I've also + * XXX seen segfaults then, after adding print statements to the + * XXX Python code getting called. + */ +#if 0 + PyGC_Collect(); +#endif + + /* Disable tracemalloc after all Python objects have been destroyed, + so it is possible to use tracemalloc in objects destructor. */ + _PyTraceMalloc_Fini(); + + /* Destroy the database used by _PyImport_{Fixup,Find}Extension */ + _PyImport_Fini(); + + /* Cleanup typeobject.c's internal caches. */ + _PyType_Fini(); + + /* unload faulthandler module */ + _PyFaulthandler_Fini(); + + /* Debugging stuff */ +#ifdef COUNT_ALLOCS + dump_counts(stdout); +#endif + /* dump hash stats */ + _PyHash_Fini(); + + _PY_DEBUG_PRINT_TOTAL_REFS(); + +#ifdef Py_TRACE_REFS + /* Display all objects still alive -- this can invoke arbitrary + * __repr__ overrides, so requires a mostly-intact interpreter. + * Alas, a lot of stuff may still be alive now that will be cleaned + * up later. + */ + if (Py_GETENV("PYTHONDUMPREFS")) + _Py_PrintReferences(stderr); +#endif /* Py_TRACE_REFS */ + + /* Clear interpreter state and all thread states. */ + PyInterpreterState_Clear(interp); + + /* Now we decref the exception classes. After this point nothing + can raise an exception. That's okay, because each Fini() method + below has been checked to make sure no exceptions are ever + raised. + */ + + _PyExc_Fini(); + + /* Sundry finalizers */ + PyMethod_Fini(); + PyFrame_Fini(); + PyCFunction_Fini(); + PyTuple_Fini(); + PyList_Fini(); + PySet_Fini(); + PyBytes_Fini(); + PyByteArray_Fini(); + PyLong_Fini(); + PyFloat_Fini(); + PyDict_Fini(); + PySlice_Fini(); + _PyGC_Fini(); + _PyRandom_Fini(); + + /* Cleanup Unicode implementation */ + _PyUnicode_Fini(); + + /* reset file system default encoding */ + if (!Py_HasFileSystemDefaultEncoding && Py_FileSystemDefaultEncoding) { + PyMem_RawFree((char*)Py_FileSystemDefaultEncoding); + Py_FileSystemDefaultEncoding = NULL; + } + + /* XXX Still allocated: + - various static ad-hoc pointers to interned strings + - int and float free list blocks + - whatever various modules and libraries allocate + */ + + PyGrammar_RemoveAccelerators(&_PyParser_Grammar); + + /* Cleanup auto-thread-state */ +#ifdef WITH_THREAD + _PyGILState_Fini(); +#endif /* WITH_THREAD */ + + /* Delete current thread. After this, many C API calls become crashy. */ + PyThreadState_Swap(NULL); + PyInterpreterState_Delete(interp); + +#ifdef Py_TRACE_REFS + /* Display addresses (& refcnts) of all objects still alive. + * An address can be used to find the repr of the object, printed + * above by _Py_PrintReferences. + */ + if (Py_GETENV("PYTHONDUMPREFS")) + _Py_PrintReferenceAddresses(stderr); +#endif /* Py_TRACE_REFS */ +#ifdef PYMALLOC_DEBUG + if (Py_GETENV("PYTHONMALLOCSTATS")) + _PyObject_DebugMallocStats(stderr); +#endif + + call_ll_exitfuncs(); +} + +/* Create and initialize a new interpreter and thread, and return the + new thread. This requires that Py_Initialize() has been called + first. + + Unsuccessful initialization yields a NULL pointer. Note that *no* + exception information is available even in this case -- the + exception information is held in the thread, and there is no + thread. + + Locking: as above. + +*/ + +PyThreadState * +Py_NewInterpreter(void) +{ + PyInterpreterState *interp; + PyThreadState *tstate, *save_tstate; + PyObject *bimod, *sysmod; + + if (!initialized) + Py_FatalError("Py_NewInterpreter: call Py_Initialize first"); + + interp = PyInterpreterState_New(); + if (interp == NULL) + return NULL; + + tstate = PyThreadState_New(interp); + if (tstate == NULL) { + PyInterpreterState_Delete(interp); + return NULL; + } + + save_tstate = PyThreadState_Swap(tstate); + + /* XXX The following is lax in error checking */ + + interp->modules = PyDict_New(); + + bimod = _PyImport_FindBuiltin("builtins"); + if (bimod != NULL) { + interp->builtins = PyModule_GetDict(bimod); + if (interp->builtins == NULL) + goto handle_error; + Py_INCREF(interp->builtins); + } + + /* initialize builtin exceptions */ + _PyExc_Init(bimod); + + sysmod = _PyImport_FindBuiltin("sys"); + if (bimod != NULL && sysmod != NULL) { + PyObject *pstderr; + + interp->sysdict = PyModule_GetDict(sysmod); + if (interp->sysdict == NULL) + goto handle_error; + Py_INCREF(interp->sysdict); + PySys_SetPath(Py_GetPath()); + PyDict_SetItemString(interp->sysdict, "modules", + interp->modules); + /* Set up a preliminary stderr printer until we have enough + infrastructure for the io module in place. */ + pstderr = PyFile_NewStdPrinter(fileno(stderr)); + if (pstderr == NULL) + Py_FatalError("Py_Initialize: can't set preliminary stderr"); + _PySys_SetObjectId(&PyId_stderr, pstderr); + PySys_SetObject("__stderr__", pstderr); + Py_DECREF(pstderr); + + _PyImportHooks_Init(); + + import_init(interp, sysmod); + + if (initfsencoding(interp) < 0) + goto handle_error; + + if (initstdio() < 0) + Py_FatalError( + "Py_Initialize: can't initialize sys standard streams"); + initmain(interp); + if (!Py_NoSiteFlag) + initsite(); + } + + if (!PyErr_Occurred()) + return tstate; + +handle_error: + /* Oops, it didn't work. Undo it all. */ + + PyErr_PrintEx(0); + PyThreadState_Clear(tstate); + PyThreadState_Swap(save_tstate); + PyThreadState_Delete(tstate); + PyInterpreterState_Delete(interp); + + return NULL; +} + +/* Delete an interpreter and its last thread. This requires that the + given thread state is current, that the thread has no remaining + frames, and that it is its interpreter's only remaining thread. + It is a fatal error to violate these constraints. + + (Py_Finalize() doesn't have these constraints -- it zaps + everything, regardless.) + + Locking: as above. + +*/ + +void +Py_EndInterpreter(PyThreadState *tstate) +{ + PyInterpreterState *interp = tstate->interp; + + if (tstate != PyThreadState_GET()) + Py_FatalError("Py_EndInterpreter: thread is not current"); + if (tstate->frame != NULL) + Py_FatalError("Py_EndInterpreter: thread still has a frame"); + + wait_for_thread_shutdown(); + + if (tstate != interp->tstate_head || tstate->next != NULL) + Py_FatalError("Py_EndInterpreter: not the last thread"); + + PyImport_Cleanup(); + PyInterpreterState_Clear(interp); + PyThreadState_Swap(NULL); + PyInterpreterState_Delete(interp); +} + +#ifdef MS_WINDOWS +static wchar_t *progname = L"python"; +#else +static wchar_t *progname = L"python3"; +#endif + +void +Py_SetProgramName(wchar_t *pn) +{ + if (pn && *pn) + progname = pn; +} + +wchar_t * +Py_GetProgramName(void) +{ + return progname; +} + +static wchar_t *default_home = NULL; +static wchar_t env_home[MAXPATHLEN+1]; + +void +Py_SetPythonHome(wchar_t *home) +{ + default_home = home; +} + +wchar_t * +Py_GetPythonHome(void) +{ + wchar_t *home = default_home; + if (home == NULL && !Py_IgnoreEnvironmentFlag) { + char* chome = Py_GETENV("PYTHONHOME"); + if (chome) { + size_t size = Py_ARRAY_LENGTH(env_home); + size_t r = mbstowcs(env_home, chome, size); + if (r != (size_t)-1 && r < size) + home = env_home; + } + + } + return home; +} + +/* Create __main__ module */ + +static void +initmain(PyInterpreterState *interp) +{ + PyObject *m, *d, *loader; + m = PyImport_AddModule("__main__"); + if (m == NULL) + Py_FatalError("can't create __main__ module"); + d = PyModule_GetDict(m); + if (PyDict_GetItemString(d, "__builtins__") == NULL) { + PyObject *bimod = PyImport_ImportModule("builtins"); + if (bimod == NULL) { + Py_FatalError("Failed to retrieve builtins module"); + } + if (PyDict_SetItemString(d, "__builtins__", bimod) < 0) { + Py_FatalError("Failed to initialize __main__.__builtins__"); + } + Py_DECREF(bimod); + } + /* Main is a little special - imp.is_builtin("__main__") will return + * False, but BuiltinImporter is still the most appropriate initial + * setting for its __loader__ attribute. A more suitable value will + * be set if __main__ gets further initialized later in the startup + * process. + */ + loader = PyDict_GetItemString(d, "__loader__"); + if (loader == NULL || loader == Py_None) { + PyObject *loader = PyObject_GetAttrString(interp->importlib, + "BuiltinImporter"); + if (loader == NULL) { + Py_FatalError("Failed to retrieve BuiltinImporter"); + } + if (PyDict_SetItemString(d, "__loader__", loader) < 0) { + Py_FatalError("Failed to initialize __main__.__loader__"); + } + Py_DECREF(loader); + } +} + +static int +initfsencoding(PyInterpreterState *interp) +{ + PyObject *codec; + + if (Py_FileSystemDefaultEncoding == NULL) + { + Py_FileSystemDefaultEncoding = get_locale_encoding(); + if (Py_FileSystemDefaultEncoding == NULL) + Py_FatalError("Py_Initialize: Unable to get the locale encoding"); + + Py_HasFileSystemDefaultEncoding = 0; + interp->fscodec_initialized = 1; + return 0; + } + + /* the encoding is mbcs, utf-8 or ascii */ + codec = _PyCodec_Lookup(Py_FileSystemDefaultEncoding); + if (!codec) { + /* Such error can only occurs in critical situations: no more + * memory, import a module of the standard library failed, + * etc. */ + return -1; + } + Py_DECREF(codec); + interp->fscodec_initialized = 1; + return 0; +} + +/* Import the site module (not into __main__ though) */ + +static void +initsite(void) +{ + PyObject *m; + m = PyImport_ImportModule("site"); + if (m == NULL) { + fprintf(stderr, "Failed to import the site module\n"); + PyErr_Print(); + Py_Finalize(); + exit(1); + } + else { + Py_DECREF(m); + } +} + +static PyObject* +create_stdio(PyObject* io, + int fd, int write_mode, char* name, + char* encoding, char* errors) +{ + PyObject *buf = NULL, *stream = NULL, *text = NULL, *raw = NULL, *res; + const char* mode; + const char* newline; + PyObject *line_buffering; + int buffering, isatty; + _Py_IDENTIFIER(open); + _Py_IDENTIFIER(isatty); + _Py_IDENTIFIER(TextIOWrapper); + _Py_IDENTIFIER(mode); + + /* stdin is always opened in buffered mode, first because it shouldn't + make a difference in common use cases, second because TextIOWrapper + depends on the presence of a read1() method which only exists on + buffered streams. + */ + if (Py_UnbufferedStdioFlag && write_mode) + buffering = 0; + else + buffering = -1; + if (write_mode) + mode = "wb"; + else + mode = "rb"; + buf = _PyObject_CallMethodId(io, &PyId_open, "isiOOOi", + fd, mode, buffering, + Py_None, Py_None, Py_None, 0); + if (buf == NULL) + goto error; + + if (buffering) { + _Py_IDENTIFIER(raw); + raw = _PyObject_GetAttrId(buf, &PyId_raw); + if (raw == NULL) + goto error; + } + else { + raw = buf; + Py_INCREF(raw); + } + + text = PyUnicode_FromString(name); + if (text == NULL || _PyObject_SetAttrId(raw, &PyId_name, text) < 0) + goto error; + res = _PyObject_CallMethodId(raw, &PyId_isatty, ""); + if (res == NULL) + goto error; + isatty = PyObject_IsTrue(res); + Py_DECREF(res); + if (isatty == -1) + goto error; + if (isatty || Py_UnbufferedStdioFlag) + line_buffering = Py_True; + else + line_buffering = Py_False; + + Py_CLEAR(raw); + Py_CLEAR(text); + +#ifdef MS_WINDOWS + /* sys.stdin: enable universal newline mode, translate "\r\n" and "\r" + newlines to "\n". + sys.stdout and sys.stderr: translate "\n" to "\r\n". */ + newline = NULL; +#else + /* sys.stdin: split lines at "\n". + sys.stdout and sys.stderr: don't translate newlines (use "\n"). */ + newline = "\n"; +#endif + + stream = _PyObject_CallMethodId(io, &PyId_TextIOWrapper, "OsssO", + buf, encoding, errors, + newline, line_buffering); + Py_CLEAR(buf); + if (stream == NULL) + goto error; + + if (write_mode) + mode = "w"; + else + mode = "r"; + text = PyUnicode_FromString(mode); + if (!text || _PyObject_SetAttrId(stream, &PyId_mode, text) < 0) + goto error; + Py_CLEAR(text); + return stream; + +error: + Py_XDECREF(buf); + Py_XDECREF(stream); + Py_XDECREF(text); + Py_XDECREF(raw); + return NULL; +} + +static int +is_valid_fd(int fd) +{ + int dummy_fd; + if (fd < 0 || !_PyVerify_fd(fd)) + return 0; + dummy_fd = dup(fd); + if (dummy_fd < 0) + return 0; + close(dummy_fd); + return 1; +} + +/* Initialize sys.stdin, stdout, stderr and builtins.open */ +static int +initstdio(void) +{ + PyObject *iomod = NULL, *wrapper; + PyObject *bimod = NULL; + PyObject *m; + PyObject *std = NULL; + int status = 0, fd; + PyObject * encoding_attr; + char *pythonioencoding = NULL, *encoding, *errors; + + /* Hack to avoid a nasty recursion issue when Python is invoked + in verbose mode: pre-import the Latin-1 and UTF-8 codecs */ + if ((m = PyImport_ImportModule("encodings.utf_8")) == NULL) { + goto error; + } + Py_DECREF(m); + + if (!(m = PyImport_ImportModule("encodings.latin_1"))) { + goto error; + } + Py_DECREF(m); + + if (!(bimod = PyImport_ImportModule("builtins"))) { + goto error; + } + + if (!(iomod = PyImport_ImportModule("io"))) { + goto error; + } + if (!(wrapper = PyObject_GetAttrString(iomod, "OpenWrapper"))) { + goto error; + } + + /* Set builtins.open */ + if (PyObject_SetAttrString(bimod, "open", wrapper) == -1) { + Py_DECREF(wrapper); + goto error; + } + Py_DECREF(wrapper); + + encoding = _Py_StandardStreamEncoding; + errors = _Py_StandardStreamErrors; + if (!encoding || !errors) { + if (!errors) { + /* When the LC_CTYPE locale is the POSIX locale ("C locale"), + stdin and stdout use the surrogateescape error handler by + default, instead of the strict error handler. */ + char *loc = setlocale(LC_CTYPE, NULL); + if (loc != NULL && strcmp(loc, "C") == 0) + errors = "surrogateescape"; + } + + pythonioencoding = Py_GETENV("PYTHONIOENCODING"); + if (pythonioencoding) { + char *err; + pythonioencoding = _PyMem_Strdup(pythonioencoding); + if (pythonioencoding == NULL) { + PyErr_NoMemory(); + goto error; + } + err = strchr(pythonioencoding, ':'); + if (err) { + *err = '\0'; + err++; + if (*err && !_Py_StandardStreamErrors) { + errors = err; + } + } + if (*pythonioencoding && !encoding) { + encoding = pythonioencoding; + } + } + } + + /* Set sys.stdin */ + fd = fileno(stdin); + /* Under some conditions stdin, stdout and stderr may not be connected + * and fileno() may point to an invalid file descriptor. For example + * GUI apps don't have valid standard streams by default. + */ + if (!is_valid_fd(fd)) { + std = Py_None; + Py_INCREF(std); + } + else { + std = create_stdio(iomod, fd, 0, "", encoding, errors); + if (std == NULL) + goto error; + } /* if (fd < 0) */ + PySys_SetObject("__stdin__", std); + _PySys_SetObjectId(&PyId_stdin, std); + Py_DECREF(std); + + /* Set sys.stdout */ + fd = fileno(stdout); + if (!is_valid_fd(fd)) { + std = Py_None; + Py_INCREF(std); + } + else { + std = create_stdio(iomod, fd, 1, "", encoding, errors); + if (std == NULL) + goto error; + } /* if (fd < 0) */ + PySys_SetObject("__stdout__", std); + _PySys_SetObjectId(&PyId_stdout, std); + Py_DECREF(std); + +#if 1 /* Disable this if you have trouble debugging bootstrap stuff */ + /* Set sys.stderr, replaces the preliminary stderr */ + fd = fileno(stderr); + if (!is_valid_fd(fd)) { + std = Py_None; + Py_INCREF(std); + } + else { + std = create_stdio(iomod, fd, 1, "", encoding, "backslashreplace"); + if (std == NULL) + goto error; + } /* if (fd < 0) */ + + /* Same as hack above, pre-import stderr's codec to avoid recursion + when import.c tries to write to stderr in verbose mode. */ + encoding_attr = PyObject_GetAttrString(std, "encoding"); + if (encoding_attr != NULL) { + const char * std_encoding; + std_encoding = _PyUnicode_AsString(encoding_attr); + if (std_encoding != NULL) { + PyObject *codec_info = _PyCodec_Lookup(std_encoding); + Py_XDECREF(codec_info); + } + Py_DECREF(encoding_attr); + } + PyErr_Clear(); /* Not a fatal error if codec isn't available */ + + if (PySys_SetObject("__stderr__", std) < 0) { + Py_DECREF(std); + goto error; + } + if (_PySys_SetObjectId(&PyId_stderr, std) < 0) { + Py_DECREF(std); + goto error; + } + Py_DECREF(std); +#endif + + if (0) { + error: + status = -1; + } + + /* We won't need them anymore. */ + if (_Py_StandardStreamEncoding) { + PyMem_RawFree(_Py_StandardStreamEncoding); + _Py_StandardStreamEncoding = NULL; + } + if (_Py_StandardStreamErrors) { + PyMem_RawFree(_Py_StandardStreamErrors); + _Py_StandardStreamErrors = NULL; + } + PyMem_Free(pythonioencoding); + Py_XDECREF(bimod); + Py_XDECREF(iomod); + return status; +} + + +/* Print fatal error message and abort */ + +void +Py_FatalError(const char *msg) +{ + const int fd = fileno(stderr); + PyThreadState *tstate; + + fprintf(stderr, "Fatal Python error: %s\n", msg); + fflush(stderr); /* it helps in Windows debug build */ + if (PyErr_Occurred()) { + PyErr_PrintEx(0); + } + else { + tstate = _Py_atomic_load_relaxed(&_PyThreadState_Current); + if (tstate != NULL) { + fputc('\n', stderr); + fflush(stderr); + _Py_DumpTracebackThreads(fd, tstate->interp, tstate); + } + _PyFaulthandler_Fini(); + } + +#ifdef MS_WINDOWS + { + size_t len = strlen(msg); + WCHAR* buffer; + size_t i; + + /* Convert the message to wchar_t. This uses a simple one-to-one + conversion, assuming that the this error message actually uses ASCII + only. If this ceases to be true, we will have to convert. */ + buffer = alloca( (len+1) * (sizeof *buffer)); + for( i=0; i<=len; ++i) + buffer[i] = msg[i]; + OutputDebugStringW(L"Fatal Python error: "); + OutputDebugStringW(buffer); + OutputDebugStringW(L"\n"); + } +#ifdef _DEBUG + DebugBreak(); +#endif +#endif /* MS_WINDOWS */ + abort(); +} + +/* Clean up and exit */ + +#ifdef WITH_THREAD +#include "pythread.h" +#endif + +static void (*pyexitfunc)(void) = NULL; +/* For the atexit module. */ +void _Py_PyAtExit(void (*func)(void)) +{ + pyexitfunc = func; +} + +static void +call_py_exitfuncs(void) +{ + if (pyexitfunc == NULL) + return; + + (*pyexitfunc)(); + PyErr_Clear(); +} + +/* Wait until threading._shutdown completes, provided + the threading module was imported in the first place. + The shutdown routine will wait until all non-daemon + "threading" threads have completed. */ +static void +wait_for_thread_shutdown(void) +{ +#ifdef WITH_THREAD + _Py_IDENTIFIER(_shutdown); + PyObject *result; + PyThreadState *tstate = PyThreadState_GET(); + PyObject *threading = PyMapping_GetItemString(tstate->interp->modules, + "threading"); + if (threading == NULL) { + /* threading not imported */ + PyErr_Clear(); + return; + } + result = _PyObject_CallMethodId(threading, &PyId__shutdown, ""); + if (result == NULL) { + PyErr_WriteUnraisable(threading); + } + else { + Py_DECREF(result); + } + Py_DECREF(threading); +#endif +} + +#define NEXITFUNCS 32 +static void (*exitfuncs[NEXITFUNCS])(void); +static int nexitfuncs = 0; + +int Py_AtExit(void (*func)(void)) +{ + if (nexitfuncs >= NEXITFUNCS) + return -1; + exitfuncs[nexitfuncs++] = func; + return 0; +} + +static void +call_ll_exitfuncs(void) +{ + while (nexitfuncs > 0) + (*exitfuncs[--nexitfuncs])(); + + fflush(stdout); + fflush(stderr); +} + +void +Py_Exit(int sts) +{ + Py_Finalize(); + + exit(sts); +} + +static void +initsigs(void) +{ +#ifdef SIGPIPE + PyOS_setsig(SIGPIPE, SIG_IGN); +#endif +#ifdef SIGXFZ + PyOS_setsig(SIGXFZ, SIG_IGN); +#endif +#ifdef SIGXFSZ + PyOS_setsig(SIGXFSZ, SIG_IGN); +#endif + PyOS_InitInterrupts(); /* May imply initsignal() */ + if (PyErr_Occurred()) { + Py_FatalError("Py_Initialize: can't import signal"); + } +} + + +/* Restore signals that the interpreter has called SIG_IGN on to SIG_DFL. + * + * All of the code in this function must only use async-signal-safe functions, + * listed at `man 7 signal` or + * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html. + */ +void +_Py_RestoreSignals(void) +{ +#ifdef SIGPIPE + PyOS_setsig(SIGPIPE, SIG_DFL); +#endif +#ifdef SIGXFZ + PyOS_setsig(SIGXFZ, SIG_DFL); +#endif +#ifdef SIGXFSZ + PyOS_setsig(SIGXFSZ, SIG_DFL); +#endif +} + + +/* + * The file descriptor fd is considered ``interactive'' if either + * a) isatty(fd) is TRUE, or + * b) the -i flag was given, and the filename associated with + * the descriptor is NULL or "" or "???". + */ +int +Py_FdIsInteractive(FILE *fp, const char *filename) +{ + if (isatty((int)fileno(fp))) + return 1; + if (!Py_InteractiveFlag) + return 0; + return (filename == NULL) || + (strcmp(filename, "") == 0) || + (strcmp(filename, "???") == 0); +} + + +#if defined(USE_STACKCHECK) +#if defined(WIN32) && defined(_MSC_VER) + +/* Stack checking for Microsoft C */ + +#include +#include + +/* + * Return non-zero when we run out of memory on the stack; zero otherwise. + */ +int +PyOS_CheckStack(void) +{ + __try { + /* alloca throws a stack overflow exception if there's + not enough space left on the stack */ + alloca(PYOS_STACK_MARGIN * sizeof(void*)); + return 0; + } __except (GetExceptionCode() == STATUS_STACK_OVERFLOW ? + EXCEPTION_EXECUTE_HANDLER : + EXCEPTION_CONTINUE_SEARCH) { + int errcode = _resetstkoflw(); + if (errcode == 0) + { + Py_FatalError("Could not reset the stack!"); + } + } + return 1; +} + +#endif /* WIN32 && _MSC_VER */ + +/* Alternate implementations can be added here... */ + +#endif /* USE_STACKCHECK */ + + +/* Wrappers around sigaction() or signal(). */ + +PyOS_sighandler_t +PyOS_getsig(int sig) +{ +#ifdef HAVE_SIGACTION + struct sigaction context; + if (sigaction(sig, NULL, &context) == -1) + return SIG_ERR; + return context.sa_handler; +#else + PyOS_sighandler_t handler; +/* Special signal handling for the secure CRT in Visual Studio 2005 */ +#if defined(_MSC_VER) && _MSC_VER >= 1400 + switch (sig) { + /* Only these signals are valid */ + case SIGINT: + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGTERM: + case SIGBREAK: + case SIGABRT: + break; + /* Don't call signal() with other values or it will assert */ + default: + return SIG_ERR; + } +#endif /* _MSC_VER && _MSC_VER >= 1400 */ + handler = signal(sig, SIG_IGN); + if (handler != SIG_ERR) + signal(sig, handler); + return handler; +#endif +} + +/* + * All of the code in this function must only use async-signal-safe functions, + * listed at `man 7 signal` or + * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html. + */ +PyOS_sighandler_t +PyOS_setsig(int sig, PyOS_sighandler_t handler) +{ +#ifdef HAVE_SIGACTION + /* Some code in Modules/signalmodule.c depends on sigaction() being + * used here if HAVE_SIGACTION is defined. Fix that if this code + * changes to invalidate that assumption. + */ + struct sigaction context, ocontext; + context.sa_handler = handler; + sigemptyset(&context.sa_mask); + context.sa_flags = 0; + if (sigaction(sig, &context, &ocontext) == -1) + return SIG_ERR; + return ocontext.sa_handler; +#else + PyOS_sighandler_t oldhandler; + oldhandler = signal(sig, handler); +#ifdef HAVE_SIGINTERRUPT + siginterrupt(sig, 1); +#endif + return oldhandler; +#endif +} + +#ifdef __cplusplus +} +#endif diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -40,7 +40,6 @@ _Py_IDENTIFIER(last_traceback); _Py_IDENTIFIER(last_type); _Py_IDENTIFIER(last_value); -_Py_IDENTIFIER(name); _Py_IDENTIFIER(ps1); _Py_IDENTIFIER(ps2); _Py_IDENTIFIER(stdin); @@ -48,43 +47,13 @@ _Py_IDENTIFIER(stderr); _Py_static_string(PyId_string, ""); -#ifdef Py_REF_DEBUG -static -void _print_total_refs(void) { - PyObject *xoptions, *value; - _Py_IDENTIFIER(showrefcount); - - xoptions = PySys_GetXOptions(); - if (xoptions == NULL) - return; - value = _PyDict_GetItemId(xoptions, &PyId_showrefcount); - if (value == Py_True) - fprintf(stderr, - "[%" PY_FORMAT_SIZE_T "d refs, " - "%" PY_FORMAT_SIZE_T "d blocks]\n", - _Py_GetRefTotal(), _Py_GetAllocatedBlocks()); -} -#endif - -#ifndef Py_REF_DEBUG -#define PRINT_TOTAL_REFS() -#else /* Py_REF_DEBUG */ -#define PRINT_TOTAL_REFS() _print_total_refs() -#endif - #ifdef __cplusplus extern "C" { #endif -extern wchar_t *Py_GetPath(void); - extern grammar _PyParser_Grammar; /* From graminit.c */ /* Forward */ -static void initmain(PyInterpreterState *interp); -static int initfsencoding(PyInterpreterState *interp); -static void initsite(void); -static int initstdio(void); static void flush_io(void); static PyObject *run_mod(mod_ty, PyObject *, PyObject *, PyObject *, PyCompilerFlags *, PyArena *); @@ -92,1192 +61,6 @@ PyCompilerFlags *); static void err_input(perrdetail *); static void err_free(perrdetail *); -static void initsigs(void); -static void call_py_exitfuncs(void); -static void wait_for_thread_shutdown(void); -static void call_ll_exitfuncs(void); -extern int _PyUnicode_Init(void); -extern int _PyStructSequence_Init(void); -extern void _PyUnicode_Fini(void); -extern int _PyLong_Init(void); -extern void PyLong_Fini(void); -extern int _PyFaulthandler_Init(void); -extern void _PyFaulthandler_Fini(void); -extern void _PyHash_Fini(void); -extern int _PyTraceMalloc_Init(void); -extern int _PyTraceMalloc_Fini(void); - -#ifdef WITH_THREAD -extern void _PyGILState_Init(PyInterpreterState *, PyThreadState *); -extern void _PyGILState_Fini(void); -#endif /* WITH_THREAD */ - -int Py_DebugFlag; /* Needed by parser.c */ -int Py_VerboseFlag; /* Needed by import.c */ -int Py_QuietFlag; /* Needed by sysmodule.c */ -int Py_InteractiveFlag; /* Needed by Py_FdIsInteractive() below */ -int Py_InspectFlag; /* Needed to determine whether to exit at SystemExit */ -int Py_NoSiteFlag; /* Suppress 'import site' */ -int Py_BytesWarningFlag; /* Warn on str(bytes) and str(buffer) */ -int Py_DontWriteBytecodeFlag; /* Suppress writing bytecode files (*.py[co]) */ -int Py_UseClassExceptionsFlag = 1; /* Needed by bltinmodule.c: deprecated */ -int Py_FrozenFlag; /* Needed by getpath.c */ -int Py_IgnoreEnvironmentFlag; /* e.g. PYTHONPATH, PYTHONHOME */ -int Py_NoUserSiteDirectory = 0; /* for -s and site.py */ -int Py_UnbufferedStdioFlag = 0; /* Unbuffered binary std{in,out,err} */ -int Py_HashRandomizationFlag = 0; /* for -R and PYTHONHASHSEED */ -int Py_IsolatedFlag = 0; /* for -I, isolate from user's env */ - -PyThreadState *_Py_Finalizing = NULL; - -/* Hack to force loading of object files */ -int (*_PyOS_mystrnicmp_hack)(const char *, const char *, Py_ssize_t) = \ - PyOS_mystrnicmp; /* Python/pystrcmp.o */ - -/* PyModule_GetWarningsModule is no longer necessary as of 2.6 -since _warnings is builtin. This API should not be used. */ -PyObject * -PyModule_GetWarningsModule(void) -{ - return PyImport_ImportModule("warnings"); -} - -static int initialized = 0; - -/* API to access the initialized flag -- useful for esoteric use */ - -int -Py_IsInitialized(void) -{ - return initialized; -} - -/* Helper to allow an embedding application to override the normal - * mechanism that attempts to figure out an appropriate IO encoding - */ - -static char *_Py_StandardStreamEncoding = NULL; -static char *_Py_StandardStreamErrors = NULL; - -int -Py_SetStandardStreamEncoding(const char *encoding, const char *errors) -{ - if (Py_IsInitialized()) { - /* This is too late to have any effect */ - return -1; - } - /* Can't call PyErr_NoMemory() on errors, as Python hasn't been - * initialised yet. - * - * However, the raw memory allocators are initialised appropriately - * as C static variables, so _PyMem_RawStrdup is OK even though - * Py_Initialize hasn't been called yet. - */ - if (encoding) { - _Py_StandardStreamEncoding = _PyMem_RawStrdup(encoding); - if (!_Py_StandardStreamEncoding) { - return -2; - } - } - if (errors) { - _Py_StandardStreamErrors = _PyMem_RawStrdup(errors); - if (!_Py_StandardStreamErrors) { - if (_Py_StandardStreamEncoding) { - PyMem_RawFree(_Py_StandardStreamEncoding); - } - return -3; - } - } - return 0; -} - -/* Global initializations. Can be undone by Py_Finalize(). Don't - call this twice without an intervening Py_Finalize() call. When - initializations fail, a fatal error is issued and the function does - not return. On return, the first thread and interpreter state have - been created. - - Locking: you must hold the interpreter lock while calling this. - (If the lock has not yet been initialized, that's equivalent to - having the lock, but you cannot use multiple threads.) - -*/ - -static int -add_flag(int flag, const char *envs) -{ - int env = atoi(envs); - if (flag < env) - flag = env; - if (flag < 1) - flag = 1; - return flag; -} - -static char* -get_codec_name(const char *encoding) -{ - char *name_utf8, *name_str; - PyObject *codec, *name = NULL; - - codec = _PyCodec_Lookup(encoding); - if (!codec) - goto error; - - name = _PyObject_GetAttrId(codec, &PyId_name); - Py_CLEAR(codec); - if (!name) - goto error; - - name_utf8 = _PyUnicode_AsString(name); - if (name_utf8 == NULL) - goto error; - name_str = _PyMem_RawStrdup(name_utf8); - Py_DECREF(name); - if (name_str == NULL) { - PyErr_NoMemory(); - return NULL; - } - return name_str; - -error: - Py_XDECREF(codec); - Py_XDECREF(name); - return NULL; -} - -static char* -get_locale_encoding(void) -{ -#ifdef MS_WINDOWS - char codepage[100]; - PyOS_snprintf(codepage, sizeof(codepage), "cp%d", GetACP()); - return get_codec_name(codepage); -#elif defined(HAVE_LANGINFO_H) && defined(CODESET) - char* codeset = nl_langinfo(CODESET); - if (!codeset || codeset[0] == '\0') { - PyErr_SetString(PyExc_ValueError, "CODESET is not set or empty"); - return NULL; - } - return get_codec_name(codeset); -#else - PyErr_SetNone(PyExc_NotImplementedError); - return NULL; -#endif -} - -static void -import_init(PyInterpreterState *interp, PyObject *sysmod) -{ - PyObject *importlib; - PyObject *impmod; - PyObject *sys_modules; - PyObject *value; - - /* Import _importlib through its frozen version, _frozen_importlib. */ - if (PyImport_ImportFrozenModule("_frozen_importlib") <= 0) { - Py_FatalError("Py_Initialize: can't import _frozen_importlib"); - } - else if (Py_VerboseFlag) { - PySys_FormatStderr("import _frozen_importlib # frozen\n"); - } - importlib = PyImport_AddModule("_frozen_importlib"); - if (importlib == NULL) { - Py_FatalError("Py_Initialize: couldn't get _frozen_importlib from " - "sys.modules"); - } - interp->importlib = importlib; - Py_INCREF(interp->importlib); - - /* Install _importlib as __import__ */ - impmod = PyInit_imp(); - if (impmod == NULL) { - Py_FatalError("Py_Initialize: can't import imp"); - } - else if (Py_VerboseFlag) { - PySys_FormatStderr("import imp # builtin\n"); - } - sys_modules = PyImport_GetModuleDict(); - if (Py_VerboseFlag) { - PySys_FormatStderr("import sys # builtin\n"); - } - if (PyDict_SetItemString(sys_modules, "_imp", impmod) < 0) { - Py_FatalError("Py_Initialize: can't save _imp to sys.modules"); - } - - value = PyObject_CallMethod(importlib, "_install", "OO", sysmod, impmod); - if (value == NULL) { - PyErr_Print(); - Py_FatalError("Py_Initialize: importlib install failed"); - } - Py_DECREF(value); - Py_DECREF(impmod); - - _PyImportZip_Init(); -} - - -void -_Py_InitializeEx_Private(int install_sigs, int install_importlib) -{ - PyInterpreterState *interp; - PyThreadState *tstate; - PyObject *bimod, *sysmod, *pstderr; - char *p; - extern void _Py_ReadyTypes(void); - - if (initialized) - return; - initialized = 1; - _Py_Finalizing = NULL; - -#if defined(HAVE_LANGINFO_H) && defined(HAVE_SETLOCALE) - /* Set up the LC_CTYPE locale, so we can obtain - the locale's charset without having to switch - locales. */ - setlocale(LC_CTYPE, ""); -#endif - - if ((p = Py_GETENV("PYTHONDEBUG")) && *p != '\0') - Py_DebugFlag = add_flag(Py_DebugFlag, p); - if ((p = Py_GETENV("PYTHONVERBOSE")) && *p != '\0') - Py_VerboseFlag = add_flag(Py_VerboseFlag, p); - if ((p = Py_GETENV("PYTHONOPTIMIZE")) && *p != '\0') - Py_OptimizeFlag = add_flag(Py_OptimizeFlag, p); - if ((p = Py_GETENV("PYTHONDONTWRITEBYTECODE")) && *p != '\0') - Py_DontWriteBytecodeFlag = add_flag(Py_DontWriteBytecodeFlag, p); - /* The variable is only tested for existence here; _PyRandom_Init will - check its value further. */ - if ((p = Py_GETENV("PYTHONHASHSEED")) && *p != '\0') - Py_HashRandomizationFlag = add_flag(Py_HashRandomizationFlag, p); - - _PyRandom_Init(); - - interp = PyInterpreterState_New(); - if (interp == NULL) - Py_FatalError("Py_Initialize: can't make first interpreter"); - - tstate = PyThreadState_New(interp); - if (tstate == NULL) - Py_FatalError("Py_Initialize: can't make first thread"); - (void) PyThreadState_Swap(tstate); - -#ifdef WITH_THREAD - /* We can't call _PyEval_FiniThreads() in Py_Finalize because - destroying the GIL might fail when it is being referenced from - another running thread (see issue #9901). - Instead we destroy the previously created GIL here, which ensures - that we can call Py_Initialize / Py_Finalize multiple times. */ - _PyEval_FiniThreads(); - - /* Auto-thread-state API */ - _PyGILState_Init(interp, tstate); -#endif /* WITH_THREAD */ - - _Py_ReadyTypes(); - - if (!_PyFrame_Init()) - Py_FatalError("Py_Initialize: can't init frames"); - - if (!_PyLong_Init()) - Py_FatalError("Py_Initialize: can't init longs"); - - if (!PyByteArray_Init()) - Py_FatalError("Py_Initialize: can't init bytearray"); - - if (!_PyFloat_Init()) - Py_FatalError("Py_Initialize: can't init float"); - - interp->modules = PyDict_New(); - if (interp->modules == NULL) - Py_FatalError("Py_Initialize: can't make modules dictionary"); - - /* Init Unicode implementation; relies on the codec registry */ - if (_PyUnicode_Init() < 0) - Py_FatalError("Py_Initialize: can't initialize unicode"); - if (_PyStructSequence_Init() < 0) - Py_FatalError("Py_Initialize: can't initialize structseq"); - - bimod = _PyBuiltin_Init(); - if (bimod == NULL) - Py_FatalError("Py_Initialize: can't initialize builtins modules"); - _PyImport_FixupBuiltin(bimod, "builtins"); - interp->builtins = PyModule_GetDict(bimod); - if (interp->builtins == NULL) - Py_FatalError("Py_Initialize: can't initialize builtins dict"); - Py_INCREF(interp->builtins); - - /* initialize builtin exceptions */ - _PyExc_Init(bimod); - - sysmod = _PySys_Init(); - if (sysmod == NULL) - Py_FatalError("Py_Initialize: can't initialize sys"); - interp->sysdict = PyModule_GetDict(sysmod); - if (interp->sysdict == NULL) - Py_FatalError("Py_Initialize: can't initialize sys dict"); - Py_INCREF(interp->sysdict); - _PyImport_FixupBuiltin(sysmod, "sys"); - PySys_SetPath(Py_GetPath()); - PyDict_SetItemString(interp->sysdict, "modules", - interp->modules); - - /* Set up a preliminary stderr printer until we have enough - infrastructure for the io module in place. */ - pstderr = PyFile_NewStdPrinter(fileno(stderr)); - if (pstderr == NULL) - Py_FatalError("Py_Initialize: can't set preliminary stderr"); - _PySys_SetObjectId(&PyId_stderr, pstderr); - PySys_SetObject("__stderr__", pstderr); - Py_DECREF(pstderr); - - _PyImport_Init(); - - _PyImportHooks_Init(); - - /* Initialize _warnings. */ - _PyWarnings_Init(); - - if (!install_importlib) - return; - - import_init(interp, sysmod); - - /* initialize the faulthandler module */ - if (_PyFaulthandler_Init()) - Py_FatalError("Py_Initialize: can't initialize faulthandler"); - - if (_PyTime_Init() < 0) - Py_FatalError("Py_Initialize: can't initialize time"); - - if (initfsencoding(interp) < 0) - Py_FatalError("Py_Initialize: unable to load the file system codec"); - - if (install_sigs) - initsigs(); /* Signal handling stuff, including initintr() */ - - if (_PyTraceMalloc_Init() < 0) - Py_FatalError("Py_Initialize: can't initialize tracemalloc"); - - initmain(interp); /* Module __main__ */ - if (initstdio() < 0) - Py_FatalError( - "Py_Initialize: can't initialize sys standard streams"); - - /* Initialize warnings. */ - if (PySys_HasWarnOptions()) { - PyObject *warnings_module = PyImport_ImportModule("warnings"); - if (warnings_module == NULL) { - fprintf(stderr, "'import warnings' failed; traceback:\n"); - PyErr_Print(); - } - Py_XDECREF(warnings_module); - } - - if (!Py_NoSiteFlag) - initsite(); /* Module site */ -} - -void -Py_InitializeEx(int install_sigs) -{ - _Py_InitializeEx_Private(install_sigs, 1); -} - -void -Py_Initialize(void) -{ - Py_InitializeEx(1); -} - - -#ifdef COUNT_ALLOCS -extern void dump_counts(FILE*); -#endif - -/* Flush stdout and stderr */ - -static int -file_is_closed(PyObject *fobj) -{ - int r; - PyObject *tmp = PyObject_GetAttrString(fobj, "closed"); - if (tmp == NULL) { - PyErr_Clear(); - return 0; - } - r = PyObject_IsTrue(tmp); - Py_DECREF(tmp); - if (r < 0) - PyErr_Clear(); - return r > 0; -} - -static void -flush_std_files(void) -{ - PyObject *fout = _PySys_GetObjectId(&PyId_stdout); - PyObject *ferr = _PySys_GetObjectId(&PyId_stderr); - PyObject *tmp; - - if (fout != NULL && fout != Py_None && !file_is_closed(fout)) { - tmp = _PyObject_CallMethodId(fout, &PyId_flush, ""); - if (tmp == NULL) - PyErr_WriteUnraisable(fout); - else - Py_DECREF(tmp); - } - - if (ferr != NULL && ferr != Py_None && !file_is_closed(ferr)) { - tmp = _PyObject_CallMethodId(ferr, &PyId_flush, ""); - if (tmp == NULL) - PyErr_Clear(); - else - Py_DECREF(tmp); - } -} - -/* Undo the effect of Py_Initialize(). - - Beware: if multiple interpreter and/or thread states exist, these - are not wiped out; only the current thread and interpreter state - are deleted. But since everything else is deleted, those other - interpreter and thread states should no longer be used. - - (XXX We should do better, e.g. wipe out all interpreters and - threads.) - - Locking: as above. - -*/ - -void -Py_Finalize(void) -{ - PyInterpreterState *interp; - PyThreadState *tstate; - - if (!initialized) - return; - - wait_for_thread_shutdown(); - - /* The interpreter is still entirely intact at this point, and the - * exit funcs may be relying on that. In particular, if some thread - * or exit func is still waiting to do an import, the import machinery - * expects Py_IsInitialized() to return true. So don't say the - * interpreter is uninitialized until after the exit funcs have run. - * Note that Threading.py uses an exit func to do a join on all the - * threads created thru it, so this also protects pending imports in - * the threads created via Threading. - */ - call_py_exitfuncs(); - - /* Get current thread state and interpreter pointer */ - tstate = PyThreadState_GET(); - interp = tstate->interp; - - /* Remaining threads (e.g. daemon threads) will automatically exit - after taking the GIL (in PyEval_RestoreThread()). */ - _Py_Finalizing = tstate; - initialized = 0; - - /* Flush stdout+stderr */ - flush_std_files(); - - /* Disable signal handling */ - PyOS_FiniInterrupts(); - - /* Collect garbage. This may call finalizers; it's nice to call these - * before all modules are destroyed. - * XXX If a __del__ or weakref callback is triggered here, and tries to - * XXX import a module, bad things can happen, because Python no - * XXX longer believes it's initialized. - * XXX Fatal Python error: Interpreter not initialized (version mismatch?) - * XXX is easy to provoke that way. I've also seen, e.g., - * XXX Exception exceptions.ImportError: 'No module named sha' - * XXX in ignored - * XXX but I'm unclear on exactly how that one happens. In any case, - * XXX I haven't seen a real-life report of either of these. - */ - PyGC_Collect(); -#ifdef COUNT_ALLOCS - /* With COUNT_ALLOCS, it helps to run GC multiple times: - each collection might release some types from the type - list, so they become garbage. */ - while (PyGC_Collect() > 0) - /* nothing */; -#endif - /* Destroy all modules */ - PyImport_Cleanup(); - - /* Flush stdout+stderr (again, in case more was printed) */ - flush_std_files(); - - /* Collect final garbage. This disposes of cycles created by - * class definitions, for example. - * XXX This is disabled because it caused too many problems. If - * XXX a __del__ or weakref callback triggers here, Python code has - * XXX a hard time running, because even the sys module has been - * XXX cleared out (sys.stdout is gone, sys.excepthook is gone, etc). - * XXX One symptom is a sequence of information-free messages - * XXX coming from threads (if a __del__ or callback is invoked, - * XXX other threads can execute too, and any exception they encounter - * XXX triggers a comedy of errors as subsystem after subsystem - * XXX fails to find what it *expects* to find in sys to help report - * XXX the exception and consequent unexpected failures). I've also - * XXX seen segfaults then, after adding print statements to the - * XXX Python code getting called. - */ -#if 0 - PyGC_Collect(); -#endif - - /* Disable tracemalloc after all Python objects have been destroyed, - so it is possible to use tracemalloc in objects destructor. */ - _PyTraceMalloc_Fini(); - - /* Destroy the database used by _PyImport_{Fixup,Find}Extension */ - _PyImport_Fini(); - - /* Cleanup typeobject.c's internal caches. */ - _PyType_Fini(); - - /* unload faulthandler module */ - _PyFaulthandler_Fini(); - - /* Debugging stuff */ -#ifdef COUNT_ALLOCS - dump_counts(stdout); -#endif - /* dump hash stats */ - _PyHash_Fini(); - - PRINT_TOTAL_REFS(); - -#ifdef Py_TRACE_REFS - /* Display all objects still alive -- this can invoke arbitrary - * __repr__ overrides, so requires a mostly-intact interpreter. - * Alas, a lot of stuff may still be alive now that will be cleaned - * up later. - */ - if (Py_GETENV("PYTHONDUMPREFS")) - _Py_PrintReferences(stderr); -#endif /* Py_TRACE_REFS */ - - /* Clear interpreter state and all thread states. */ - PyInterpreterState_Clear(interp); - - /* Now we decref the exception classes. After this point nothing - can raise an exception. That's okay, because each Fini() method - below has been checked to make sure no exceptions are ever - raised. - */ - - _PyExc_Fini(); - - /* Sundry finalizers */ - PyMethod_Fini(); - PyFrame_Fini(); - PyCFunction_Fini(); - PyTuple_Fini(); - PyList_Fini(); - PySet_Fini(); - PyBytes_Fini(); - PyByteArray_Fini(); - PyLong_Fini(); - PyFloat_Fini(); - PyDict_Fini(); - PySlice_Fini(); - _PyGC_Fini(); - _PyRandom_Fini(); - - /* Cleanup Unicode implementation */ - _PyUnicode_Fini(); - - /* reset file system default encoding */ - if (!Py_HasFileSystemDefaultEncoding && Py_FileSystemDefaultEncoding) { - PyMem_RawFree((char*)Py_FileSystemDefaultEncoding); - Py_FileSystemDefaultEncoding = NULL; - } - - /* XXX Still allocated: - - various static ad-hoc pointers to interned strings - - int and float free list blocks - - whatever various modules and libraries allocate - */ - - PyGrammar_RemoveAccelerators(&_PyParser_Grammar); - - /* Cleanup auto-thread-state */ -#ifdef WITH_THREAD - _PyGILState_Fini(); -#endif /* WITH_THREAD */ - - /* Delete current thread. After this, many C API calls become crashy. */ - PyThreadState_Swap(NULL); - PyInterpreterState_Delete(interp); - -#ifdef Py_TRACE_REFS - /* Display addresses (& refcnts) of all objects still alive. - * An address can be used to find the repr of the object, printed - * above by _Py_PrintReferences. - */ - if (Py_GETENV("PYTHONDUMPREFS")) - _Py_PrintReferenceAddresses(stderr); -#endif /* Py_TRACE_REFS */ -#ifdef PYMALLOC_DEBUG - if (Py_GETENV("PYTHONMALLOCSTATS")) - _PyObject_DebugMallocStats(stderr); -#endif - - call_ll_exitfuncs(); -} - -/* Create and initialize a new interpreter and thread, and return the - new thread. This requires that Py_Initialize() has been called - first. - - Unsuccessful initialization yields a NULL pointer. Note that *no* - exception information is available even in this case -- the - exception information is held in the thread, and there is no - thread. - - Locking: as above. - -*/ - -PyThreadState * -Py_NewInterpreter(void) -{ - PyInterpreterState *interp; - PyThreadState *tstate, *save_tstate; - PyObject *bimod, *sysmod; - - if (!initialized) - Py_FatalError("Py_NewInterpreter: call Py_Initialize first"); - - interp = PyInterpreterState_New(); - if (interp == NULL) - return NULL; - - tstate = PyThreadState_New(interp); - if (tstate == NULL) { - PyInterpreterState_Delete(interp); - return NULL; - } - - save_tstate = PyThreadState_Swap(tstate); - - /* XXX The following is lax in error checking */ - - interp->modules = PyDict_New(); - - bimod = _PyImport_FindBuiltin("builtins"); - if (bimod != NULL) { - interp->builtins = PyModule_GetDict(bimod); - if (interp->builtins == NULL) - goto handle_error; - Py_INCREF(interp->builtins); - } - - /* initialize builtin exceptions */ - _PyExc_Init(bimod); - - sysmod = _PyImport_FindBuiltin("sys"); - if (bimod != NULL && sysmod != NULL) { - PyObject *pstderr; - - interp->sysdict = PyModule_GetDict(sysmod); - if (interp->sysdict == NULL) - goto handle_error; - Py_INCREF(interp->sysdict); - PySys_SetPath(Py_GetPath()); - PyDict_SetItemString(interp->sysdict, "modules", - interp->modules); - /* Set up a preliminary stderr printer until we have enough - infrastructure for the io module in place. */ - pstderr = PyFile_NewStdPrinter(fileno(stderr)); - if (pstderr == NULL) - Py_FatalError("Py_Initialize: can't set preliminary stderr"); - _PySys_SetObjectId(&PyId_stderr, pstderr); - PySys_SetObject("__stderr__", pstderr); - Py_DECREF(pstderr); - - _PyImportHooks_Init(); - - import_init(interp, sysmod); - - if (initfsencoding(interp) < 0) - goto handle_error; - - if (initstdio() < 0) - Py_FatalError( - "Py_Initialize: can't initialize sys standard streams"); - initmain(interp); - if (!Py_NoSiteFlag) - initsite(); - } - - if (!PyErr_Occurred()) - return tstate; - -handle_error: - /* Oops, it didn't work. Undo it all. */ - - PyErr_PrintEx(0); - PyThreadState_Clear(tstate); - PyThreadState_Swap(save_tstate); - PyThreadState_Delete(tstate); - PyInterpreterState_Delete(interp); - - return NULL; -} - -/* Delete an interpreter and its last thread. This requires that the - given thread state is current, that the thread has no remaining - frames, and that it is its interpreter's only remaining thread. - It is a fatal error to violate these constraints. - - (Py_Finalize() doesn't have these constraints -- it zaps - everything, regardless.) - - Locking: as above. - -*/ - -void -Py_EndInterpreter(PyThreadState *tstate) -{ - PyInterpreterState *interp = tstate->interp; - - if (tstate != PyThreadState_GET()) - Py_FatalError("Py_EndInterpreter: thread is not current"); - if (tstate->frame != NULL) - Py_FatalError("Py_EndInterpreter: thread still has a frame"); - - wait_for_thread_shutdown(); - - if (tstate != interp->tstate_head || tstate->next != NULL) - Py_FatalError("Py_EndInterpreter: not the last thread"); - - PyImport_Cleanup(); - PyInterpreterState_Clear(interp); - PyThreadState_Swap(NULL); - PyInterpreterState_Delete(interp); -} - -#ifdef MS_WINDOWS -static wchar_t *progname = L"python"; -#else -static wchar_t *progname = L"python3"; -#endif - -void -Py_SetProgramName(wchar_t *pn) -{ - if (pn && *pn) - progname = pn; -} - -wchar_t * -Py_GetProgramName(void) -{ - return progname; -} - -static wchar_t *default_home = NULL; -static wchar_t env_home[MAXPATHLEN+1]; - -void -Py_SetPythonHome(wchar_t *home) -{ - default_home = home; -} - -wchar_t * -Py_GetPythonHome(void) -{ - wchar_t *home = default_home; - if (home == NULL && !Py_IgnoreEnvironmentFlag) { - char* chome = Py_GETENV("PYTHONHOME"); - if (chome) { - size_t size = Py_ARRAY_LENGTH(env_home); - size_t r = mbstowcs(env_home, chome, size); - if (r != (size_t)-1 && r < size) - home = env_home; - } - - } - return home; -} - -/* Create __main__ module */ - -static void -initmain(PyInterpreterState *interp) -{ - PyObject *m, *d, *loader; - m = PyImport_AddModule("__main__"); - if (m == NULL) - Py_FatalError("can't create __main__ module"); - d = PyModule_GetDict(m); - if (PyDict_GetItemString(d, "__builtins__") == NULL) { - PyObject *bimod = PyImport_ImportModule("builtins"); - if (bimod == NULL) { - Py_FatalError("Failed to retrieve builtins module"); - } - if (PyDict_SetItemString(d, "__builtins__", bimod) < 0) { - Py_FatalError("Failed to initialize __main__.__builtins__"); - } - Py_DECREF(bimod); - } - /* Main is a little special - imp.is_builtin("__main__") will return - * False, but BuiltinImporter is still the most appropriate initial - * setting for its __loader__ attribute. A more suitable value will - * be set if __main__ gets further initialized later in the startup - * process. - */ - loader = PyDict_GetItemString(d, "__loader__"); - if (loader == NULL || loader == Py_None) { - PyObject *loader = PyObject_GetAttrString(interp->importlib, - "BuiltinImporter"); - if (loader == NULL) { - Py_FatalError("Failed to retrieve BuiltinImporter"); - } - if (PyDict_SetItemString(d, "__loader__", loader) < 0) { - Py_FatalError("Failed to initialize __main__.__loader__"); - } - Py_DECREF(loader); - } -} - -static int -initfsencoding(PyInterpreterState *interp) -{ - PyObject *codec; - - if (Py_FileSystemDefaultEncoding == NULL) - { - Py_FileSystemDefaultEncoding = get_locale_encoding(); - if (Py_FileSystemDefaultEncoding == NULL) - Py_FatalError("Py_Initialize: Unable to get the locale encoding"); - - Py_HasFileSystemDefaultEncoding = 0; - interp->fscodec_initialized = 1; - return 0; - } - - /* the encoding is mbcs, utf-8 or ascii */ - codec = _PyCodec_Lookup(Py_FileSystemDefaultEncoding); - if (!codec) { - /* Such error can only occurs in critical situations: no more - * memory, import a module of the standard library failed, - * etc. */ - return -1; - } - Py_DECREF(codec); - interp->fscodec_initialized = 1; - return 0; -} - -/* Import the site module (not into __main__ though) */ - -static void -initsite(void) -{ - PyObject *m; - m = PyImport_ImportModule("site"); - if (m == NULL) { - fprintf(stderr, "Failed to import the site module\n"); - PyErr_Print(); - Py_Finalize(); - exit(1); - } - else { - Py_DECREF(m); - } -} - -static PyObject* -create_stdio(PyObject* io, - int fd, int write_mode, char* name, - char* encoding, char* errors) -{ - PyObject *buf = NULL, *stream = NULL, *text = NULL, *raw = NULL, *res; - const char* mode; - const char* newline; - PyObject *line_buffering; - int buffering, isatty; - _Py_IDENTIFIER(open); - _Py_IDENTIFIER(isatty); - _Py_IDENTIFIER(TextIOWrapper); - _Py_IDENTIFIER(mode); - - /* stdin is always opened in buffered mode, first because it shouldn't - make a difference in common use cases, second because TextIOWrapper - depends on the presence of a read1() method which only exists on - buffered streams. - */ - if (Py_UnbufferedStdioFlag && write_mode) - buffering = 0; - else - buffering = -1; - if (write_mode) - mode = "wb"; - else - mode = "rb"; - buf = _PyObject_CallMethodId(io, &PyId_open, "isiOOOi", - fd, mode, buffering, - Py_None, Py_None, Py_None, 0); - if (buf == NULL) - goto error; - - if (buffering) { - _Py_IDENTIFIER(raw); - raw = _PyObject_GetAttrId(buf, &PyId_raw); - if (raw == NULL) - goto error; - } - else { - raw = buf; - Py_INCREF(raw); - } - - text = PyUnicode_FromString(name); - if (text == NULL || _PyObject_SetAttrId(raw, &PyId_name, text) < 0) - goto error; - res = _PyObject_CallMethodId(raw, &PyId_isatty, ""); - if (res == NULL) - goto error; - isatty = PyObject_IsTrue(res); - Py_DECREF(res); - if (isatty == -1) - goto error; - if (isatty || Py_UnbufferedStdioFlag) - line_buffering = Py_True; - else - line_buffering = Py_False; - - Py_CLEAR(raw); - Py_CLEAR(text); - -#ifdef MS_WINDOWS - /* sys.stdin: enable universal newline mode, translate "\r\n" and "\r" - newlines to "\n". - sys.stdout and sys.stderr: translate "\n" to "\r\n". */ - newline = NULL; -#else - /* sys.stdin: split lines at "\n". - sys.stdout and sys.stderr: don't translate newlines (use "\n"). */ - newline = "\n"; -#endif - - stream = _PyObject_CallMethodId(io, &PyId_TextIOWrapper, "OsssO", - buf, encoding, errors, - newline, line_buffering); - Py_CLEAR(buf); - if (stream == NULL) - goto error; - - if (write_mode) - mode = "w"; - else - mode = "r"; - text = PyUnicode_FromString(mode); - if (!text || _PyObject_SetAttrId(stream, &PyId_mode, text) < 0) - goto error; - Py_CLEAR(text); - return stream; - -error: - Py_XDECREF(buf); - Py_XDECREF(stream); - Py_XDECREF(text); - Py_XDECREF(raw); - return NULL; -} - -static int -is_valid_fd(int fd) -{ - int dummy_fd; - if (fd < 0 || !_PyVerify_fd(fd)) - return 0; - dummy_fd = dup(fd); - if (dummy_fd < 0) - return 0; - close(dummy_fd); - return 1; -} - -/* Initialize sys.stdin, stdout, stderr and builtins.open */ -static int -initstdio(void) -{ - PyObject *iomod = NULL, *wrapper; - PyObject *bimod = NULL; - PyObject *m; - PyObject *std = NULL; - int status = 0, fd; - PyObject * encoding_attr; - char *pythonioencoding = NULL, *encoding, *errors; - - /* Hack to avoid a nasty recursion issue when Python is invoked - in verbose mode: pre-import the Latin-1 and UTF-8 codecs */ - if ((m = PyImport_ImportModule("encodings.utf_8")) == NULL) { - goto error; - } - Py_DECREF(m); - - if (!(m = PyImport_ImportModule("encodings.latin_1"))) { - goto error; - } - Py_DECREF(m); - - if (!(bimod = PyImport_ImportModule("builtins"))) { - goto error; - } - - if (!(iomod = PyImport_ImportModule("io"))) { - goto error; - } - if (!(wrapper = PyObject_GetAttrString(iomod, "OpenWrapper"))) { - goto error; - } - - /* Set builtins.open */ - if (PyObject_SetAttrString(bimod, "open", wrapper) == -1) { - Py_DECREF(wrapper); - goto error; - } - Py_DECREF(wrapper); - - encoding = _Py_StandardStreamEncoding; - errors = _Py_StandardStreamErrors; - if (!encoding || !errors) { - if (!errors) { - /* When the LC_CTYPE locale is the POSIX locale ("C locale"), - stdin and stdout use the surrogateescape error handler by - default, instead of the strict error handler. */ - char *loc = setlocale(LC_CTYPE, NULL); - if (loc != NULL && strcmp(loc, "C") == 0) - errors = "surrogateescape"; - } - - pythonioencoding = Py_GETENV("PYTHONIOENCODING"); - if (pythonioencoding) { - char *err; - pythonioencoding = _PyMem_Strdup(pythonioencoding); - if (pythonioencoding == NULL) { - PyErr_NoMemory(); - goto error; - } - err = strchr(pythonioencoding, ':'); - if (err) { - *err = '\0'; - err++; - if (*err && !_Py_StandardStreamErrors) { - errors = err; - } - } - if (*pythonioencoding && !encoding) { - encoding = pythonioencoding; - } - } - } - - /* Set sys.stdin */ - fd = fileno(stdin); - /* Under some conditions stdin, stdout and stderr may not be connected - * and fileno() may point to an invalid file descriptor. For example - * GUI apps don't have valid standard streams by default. - */ - if (!is_valid_fd(fd)) { - std = Py_None; - Py_INCREF(std); - } - else { - std = create_stdio(iomod, fd, 0, "", encoding, errors); - if (std == NULL) - goto error; - } /* if (fd < 0) */ - PySys_SetObject("__stdin__", std); - _PySys_SetObjectId(&PyId_stdin, std); - Py_DECREF(std); - - /* Set sys.stdout */ - fd = fileno(stdout); - if (!is_valid_fd(fd)) { - std = Py_None; - Py_INCREF(std); - } - else { - std = create_stdio(iomod, fd, 1, "", encoding, errors); - if (std == NULL) - goto error; - } /* if (fd < 0) */ - PySys_SetObject("__stdout__", std); - _PySys_SetObjectId(&PyId_stdout, std); - Py_DECREF(std); - -#if 1 /* Disable this if you have trouble debugging bootstrap stuff */ - /* Set sys.stderr, replaces the preliminary stderr */ - fd = fileno(stderr); - if (!is_valid_fd(fd)) { - std = Py_None; - Py_INCREF(std); - } - else { - std = create_stdio(iomod, fd, 1, "", encoding, "backslashreplace"); - if (std == NULL) - goto error; - } /* if (fd < 0) */ - - /* Same as hack above, pre-import stderr's codec to avoid recursion - when import.c tries to write to stderr in verbose mode. */ - encoding_attr = PyObject_GetAttrString(std, "encoding"); - if (encoding_attr != NULL) { - const char * std_encoding; - std_encoding = _PyUnicode_AsString(encoding_attr); - if (std_encoding != NULL) { - PyObject *codec_info = _PyCodec_Lookup(std_encoding); - Py_XDECREF(codec_info); - } - Py_DECREF(encoding_attr); - } - PyErr_Clear(); /* Not a fatal error if codec isn't available */ - - if (PySys_SetObject("__stderr__", std) < 0) { - Py_DECREF(std); - goto error; - } - if (_PySys_SetObjectId(&PyId_stderr, std) < 0) { - Py_DECREF(std); - goto error; - } - Py_DECREF(std); -#endif - - if (0) { - error: - status = -1; - } - - /* We won't need them anymore. */ - if (_Py_StandardStreamEncoding) { - PyMem_RawFree(_Py_StandardStreamEncoding); - _Py_StandardStreamEncoding = NULL; - } - if (_Py_StandardStreamErrors) { - PyMem_RawFree(_Py_StandardStreamErrors); - _Py_StandardStreamErrors = NULL; - } - PyMem_Free(pythonioencoding); - Py_XDECREF(bimod); - Py_XDECREF(iomod); - return status; -} /* Parse input from a file and execute it */ @@ -1327,7 +110,7 @@ err = -1; for (;;) { ret = PyRun_InteractiveOneObject(fp, filename, flags); - PRINT_TOTAL_REFS(); + _PY_DEBUG_PRINT_TOTAL_REFS(); if (ret == E_EOF) { err = 0; break; @@ -2592,192 +1375,6 @@ } } -/* Print fatal error message and abort */ - -void -Py_FatalError(const char *msg) -{ - const int fd = fileno(stderr); - PyThreadState *tstate; - - fprintf(stderr, "Fatal Python error: %s\n", msg); - fflush(stderr); /* it helps in Windows debug build */ - if (PyErr_Occurred()) { - PyErr_PrintEx(0); - } - else { - tstate = _Py_atomic_load_relaxed(&_PyThreadState_Current); - if (tstate != NULL) { - fputc('\n', stderr); - fflush(stderr); - _Py_DumpTracebackThreads(fd, tstate->interp, tstate); - } - _PyFaulthandler_Fini(); - } - -#ifdef MS_WINDOWS - { - size_t len = strlen(msg); - WCHAR* buffer; - size_t i; - - /* Convert the message to wchar_t. This uses a simple one-to-one - conversion, assuming that the this error message actually uses ASCII - only. If this ceases to be true, we will have to convert. */ - buffer = alloca( (len+1) * (sizeof *buffer)); - for( i=0; i<=len; ++i) - buffer[i] = msg[i]; - OutputDebugStringW(L"Fatal Python error: "); - OutputDebugStringW(buffer); - OutputDebugStringW(L"\n"); - } -#ifdef _DEBUG - DebugBreak(); -#endif -#endif /* MS_WINDOWS */ - abort(); -} - -/* Clean up and exit */ - -#ifdef WITH_THREAD -#include "pythread.h" -#endif - -static void (*pyexitfunc)(void) = NULL; -/* For the atexit module. */ -void _Py_PyAtExit(void (*func)(void)) -{ - pyexitfunc = func; -} - -static void -call_py_exitfuncs(void) -{ - if (pyexitfunc == NULL) - return; - - (*pyexitfunc)(); - PyErr_Clear(); -} - -/* Wait until threading._shutdown completes, provided - the threading module was imported in the first place. - The shutdown routine will wait until all non-daemon - "threading" threads have completed. */ -static void -wait_for_thread_shutdown(void) -{ -#ifdef WITH_THREAD - _Py_IDENTIFIER(_shutdown); - PyObject *result; - PyThreadState *tstate = PyThreadState_GET(); - PyObject *threading = PyMapping_GetItemString(tstate->interp->modules, - "threading"); - if (threading == NULL) { - /* threading not imported */ - PyErr_Clear(); - return; - } - result = _PyObject_CallMethodId(threading, &PyId__shutdown, ""); - if (result == NULL) { - PyErr_WriteUnraisable(threading); - } - else { - Py_DECREF(result); - } - Py_DECREF(threading); -#endif -} - -#define NEXITFUNCS 32 -static void (*exitfuncs[NEXITFUNCS])(void); -static int nexitfuncs = 0; - -int Py_AtExit(void (*func)(void)) -{ - if (nexitfuncs >= NEXITFUNCS) - return -1; - exitfuncs[nexitfuncs++] = func; - return 0; -} - -static void -call_ll_exitfuncs(void) -{ - while (nexitfuncs > 0) - (*exitfuncs[--nexitfuncs])(); - - fflush(stdout); - fflush(stderr); -} - -void -Py_Exit(int sts) -{ - Py_Finalize(); - - exit(sts); -} - -static void -initsigs(void) -{ -#ifdef SIGPIPE - PyOS_setsig(SIGPIPE, SIG_IGN); -#endif -#ifdef SIGXFZ - PyOS_setsig(SIGXFZ, SIG_IGN); -#endif -#ifdef SIGXFSZ - PyOS_setsig(SIGXFSZ, SIG_IGN); -#endif - PyOS_InitInterrupts(); /* May imply initsignal() */ - if (PyErr_Occurred()) { - Py_FatalError("Py_Initialize: can't import signal"); - } -} - - -/* Restore signals that the interpreter has called SIG_IGN on to SIG_DFL. - * - * All of the code in this function must only use async-signal-safe functions, - * listed at `man 7 signal` or - * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html. - */ -void -_Py_RestoreSignals(void) -{ -#ifdef SIGPIPE - PyOS_setsig(SIGPIPE, SIG_DFL); -#endif -#ifdef SIGXFZ - PyOS_setsig(SIGXFZ, SIG_DFL); -#endif -#ifdef SIGXFSZ - PyOS_setsig(SIGXFSZ, SIG_DFL); -#endif -} - - -/* - * The file descriptor fd is considered ``interactive'' if either - * a) isatty(fd) is TRUE, or - * b) the -i flag was given, and the filename associated with - * the descriptor is NULL or "" or "???". - */ -int -Py_FdIsInteractive(FILE *fp, const char *filename) -{ - if (isatty((int)fileno(fp))) - return 1; - if (!Py_InteractiveFlag) - return 0; - return (filename == NULL) || - (strcmp(filename, "") == 0) || - (strcmp(filename, "???") == 0); -} - #if defined(USE_STACKCHECK) #if defined(WIN32) && defined(_MSC_VER) @@ -2816,73 +1413,6 @@ #endif /* USE_STACKCHECK */ - -/* Wrappers around sigaction() or signal(). */ - -PyOS_sighandler_t -PyOS_getsig(int sig) -{ -#ifdef HAVE_SIGACTION - struct sigaction context; - if (sigaction(sig, NULL, &context) == -1) - return SIG_ERR; - return context.sa_handler; -#else - PyOS_sighandler_t handler; -/* Special signal handling for the secure CRT in Visual Studio 2005 */ -#if defined(_MSC_VER) && _MSC_VER >= 1400 - switch (sig) { - /* Only these signals are valid */ - case SIGINT: - case SIGILL: - case SIGFPE: - case SIGSEGV: - case SIGTERM: - case SIGBREAK: - case SIGABRT: - break; - /* Don't call signal() with other values or it will assert */ - default: - return SIG_ERR; - } -#endif /* _MSC_VER && _MSC_VER >= 1400 */ - handler = signal(sig, SIG_IGN); - if (handler != SIG_ERR) - signal(sig, handler); - return handler; -#endif -} - -/* - * All of the code in this function must only use async-signal-safe functions, - * listed at `man 7 signal` or - * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html. - */ -PyOS_sighandler_t -PyOS_setsig(int sig, PyOS_sighandler_t handler) -{ -#ifdef HAVE_SIGACTION - /* Some code in Modules/signalmodule.c depends on sigaction() being - * used here if HAVE_SIGACTION is defined. Fix that if this code - * changes to invalidate that assumption. - */ - struct sigaction context, ocontext; - context.sa_handler = handler; - sigemptyset(&context.sa_mask); - context.sa_flags = 0; - if (sigaction(sig, &context, &ocontext) == -1) - return SIG_ERR; - return ocontext.sa_handler; -#else - PyOS_sighandler_t oldhandler; - oldhandler = signal(sig, handler); -#ifdef HAVE_SIGINTERRUPT - siginterrupt(sig, 1); -#endif - return oldhandler; -#endif -} - /* Deprecated C API functions still provided for binary compatiblity */ #undef PyParser_SimpleParseFile diff --git a/Python/sysmodule.c b/Python/sysmodule.c --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1681,7 +1681,7 @@ } #endif - /* stdin/stdout/stderr are now set by pythonrun.c */ + /* stdin/stdout/stderr are set in pylifecycle.c */ SET_SYS_FROM_STRING_BORROW("__displayhook__", PyDict_GetItemString(sysdict, "displayhook")); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 20 14:20:43 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 20 Nov 2014 13:20:43 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbywgdGVz?= =?utf-8?q?t=5Fevents=3A_Ignore_the_=22SSL_handshake_failed=22_log_in_debu?= =?utf-8?q?g_mode?= Message-ID: <20141120132040.130911.64441@psf.io> https://hg.python.org/cpython/rev/ab7b942dfaa8 changeset: 93517:ab7b942dfaa8 branch: 3.4 user: Victor Stinner date: Thu Nov 20 14:19:23 2014 +0100 summary: asyncio, test_events: Ignore the "SSL handshake failed" log in debug mode files: Lib/test/test_asyncio/test_events.py | 4 +++- 1 files changed, 3 insertions(+), 1 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 @@ -634,7 +634,9 @@ # validation will fail with self.assertRaises(ssl.SSLError) as cm: conn_fut = create_connection(ssl=True) - self._basetest_create_ssl_connection(conn_fut, check_sockname) + # Ignore the "SSL handshake failed" log in debug mode + with test_utils.disable_logger(): + self._basetest_create_ssl_connection(conn_fut, check_sockname) self.assertEqual(cm.exception.reason, 'CERTIFICATE_VERIFY_FAILED') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 20 14:20:43 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 20 Nov 2014 13:20:43 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbzogRml4?= =?utf-8?q?_formatting_of_the_=22Future_exception_was_never_retrieved=22_i?= =?utf-8?q?n?= Message-ID: <20141120132040.43946.89261@psf.io> https://hg.python.org/cpython/rev/307cf392914e changeset: 93516:307cf392914e branch: 3.4 parent: 93512:fb06c8ccfd41 user: Victor Stinner date: Thu Nov 20 14:16:31 2014 +0100 summary: asyncio: Fix formatting of the "Future exception was never retrieved" in release mode files: Lib/asyncio/futures.py | 7 +- Lib/test/test_asyncio/test_events.py | 34 ++++--- Lib/test/test_asyncio/test_futures.py | 65 +++++++++----- 3 files changed, 64 insertions(+), 42 deletions(-) diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -104,10 +104,11 @@ def __del__(self): if self.tb: - msg = 'Future/Task exception was never retrieved' + msg = 'Future/Task exception was never retrieved\n' if self.source_traceback: - msg += '\nFuture/Task created at (most recent call last):\n' - msg += ''.join(traceback.format_list(self.source_traceback)) + src = ''.join(traceback.format_list(self.source_traceback)) + msg += 'Future/Task created at (most recent call last):\n' + msg += '%s\n' % src.rstrip() msg += ''.join(self.tb).rstrip() self.loop.call_exception_handler({'message': msg}) 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 @@ -606,27 +606,29 @@ self.assertGreater(pr.nbytes, 0) tr.close() - if ssl: - def _dummy_ssl_create_context(self, purpose=ssl.Purpose.SERVER_AUTH, *, - cafile=None, capath=None, cadata=None): - """ - A ssl.create_default_context() replacement that doesn't enable - cert validation. - """ - self.assertEqual(purpose, ssl.Purpose.SERVER_AUTH) - return test_utils.dummy_ssl_context() - def _test_create_ssl_connection(self, httpd, create_connection, check_sockname=True): conn_fut = create_connection(ssl=test_utils.dummy_ssl_context()) self._basetest_create_ssl_connection(conn_fut, check_sockname) - # With ssl=True, ssl.create_default_context() should be called - with mock.patch('ssl.create_default_context', - side_effect=self._dummy_ssl_create_context) as m: - conn_fut = create_connection(ssl=True) - self._basetest_create_ssl_connection(conn_fut, check_sockname) - self.assertEqual(m.call_count, 1) + # ssl.Purpose was introduced in Python 3.4 + if hasattr(ssl, 'Purpose'): + def _dummy_ssl_create_context(purpose=ssl.Purpose.SERVER_AUTH, *, + cafile=None, capath=None, + cadata=None): + """ + A ssl.create_default_context() replacement that doesn't enable + cert validation. + """ + self.assertEqual(purpose, ssl.Purpose.SERVER_AUTH) + return test_utils.dummy_ssl_context() + + # With ssl=True, ssl.create_default_context() should be called + with mock.patch('ssl.create_default_context', + side_effect=_dummy_ssl_create_context) as m: + conn_fut = create_connection(ssl=True) + self._basetest_create_ssl_connection(conn_fut, check_sockname) + self.assertEqual(m.call_count, 1) # With the real ssl.create_default_context(), certificate # validation will fail 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 @@ -307,8 +307,8 @@ 'test_future_source_traceback')) @mock.patch('asyncio.base_events.logger') - def test_future_exception_never_retrieved(self, m_log): - self.loop.set_debug(True) + def check_future_exception_never_retrieved(self, debug, m_log): + self.loop.set_debug(debug) def memory_error(): try: @@ -318,40 +318,59 @@ exc = memory_error() future = asyncio.Future(loop=self.loop) - source_traceback = future._source_traceback + if debug: + source_traceback = future._source_traceback future.set_exception(exc) future = None test_utils.run_briefly(self.loop) support.gc_collect() if sys.version_info >= (3, 4): - frame = source_traceback[-1] - regex = (r'^Future exception was never retrieved\n' - r'future: \n' - r'source_traceback: Object created at \(most recent call last\):\n' - r' File' - r'.*\n' - r' File "{filename}", line {lineno}, in test_future_exception_never_retrieved\n' - r' future = asyncio\.Future\(loop=self\.loop\)$' - ).format(filename=re.escape(frame[0]), lineno=frame[1]) + if debug: + frame = source_traceback[-1] + regex = (r'^Future exception was never retrieved\n' + r'future: \n' + r'source_traceback: Object created at \(most recent call last\):\n' + r' File' + r'.*\n' + r' File "{filename}", line {lineno}, in check_future_exception_never_retrieved\n' + r' future = asyncio\.Future\(loop=self\.loop\)$' + ).format(filename=re.escape(frame[0]), lineno=frame[1]) + else: + regex = (r'^Future exception was never retrieved\n' + r'future: $' + ) exc_info = (type(exc), exc, exc.__traceback__) m_log.error.assert_called_once_with(mock.ANY, exc_info=exc_info) else: - frame = source_traceback[-1] - regex = (r'^Future/Task exception was never retrieved\n' - r'Future/Task created at \(most recent call last\):\n' - r' File' - r'.*\n' - r' File "{filename}", line {lineno}, in test_future_exception_never_retrieved\n' - r' future = asyncio\.Future\(loop=self\.loop\)\n' - r'Traceback \(most recent call last\):\n' - r'.*\n' - r'MemoryError$' - ).format(filename=re.escape(frame[0]), lineno=frame[1]) + if debug: + frame = source_traceback[-1] + regex = (r'^Future/Task exception was never retrieved\n' + r'Future/Task created at \(most recent call last\):\n' + r' File' + r'.*\n' + r' File "{filename}", line {lineno}, in check_future_exception_never_retrieved\n' + r' future = asyncio\.Future\(loop=self\.loop\)\n' + r'Traceback \(most recent call last\):\n' + r'.*\n' + r'MemoryError$' + ).format(filename=re.escape(frame[0]), lineno=frame[1]) + else: + regex = (r'^Future/Task exception was never retrieved\n' + r'Traceback \(most recent call last\):\n' + r'.*\n' + r'MemoryError$' + ) m_log.error.assert_called_once_with(mock.ANY, exc_info=False) message = m_log.error.call_args[0][0] self.assertRegex(message, re.compile(regex, re.DOTALL)) + def test_future_exception_never_retrieved(self): + self.check_future_exception_never_retrieved(False) + + def test_future_exception_never_retrieved_debug(self): + self.check_future_exception_never_retrieved(True) + def test_set_result_unless_cancelled(self): fut = asyncio.Future(loop=self.loop) fut.cancel() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 20 14:20:43 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 20 Nov 2014 13:20:43 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogTWVyZ2Ugd2l0aCAzLjQgKGFzeW5jaW8p?= Message-ID: <20141120132040.7142.51283@psf.io> https://hg.python.org/cpython/rev/3d3928940da3 changeset: 93518:3d3928940da3 parent: 93515:b9775a92c1d0 parent: 93517:ab7b942dfaa8 user: Victor Stinner date: Thu Nov 20 14:19:49 2014 +0100 summary: Merge with 3.4 (asyncio) files: Lib/asyncio/futures.py | 7 +- Lib/test/test_asyncio/test_events.py | 38 ++++--- Lib/test/test_asyncio/test_futures.py | 65 +++++++++----- 3 files changed, 67 insertions(+), 43 deletions(-) diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py --- a/Lib/asyncio/futures.py +++ b/Lib/asyncio/futures.py @@ -104,10 +104,11 @@ def __del__(self): if self.tb: - msg = 'Future/Task exception was never retrieved' + msg = 'Future/Task exception was never retrieved\n' if self.source_traceback: - msg += '\nFuture/Task created at (most recent call last):\n' - msg += ''.join(traceback.format_list(self.source_traceback)) + src = ''.join(traceback.format_list(self.source_traceback)) + msg += 'Future/Task created at (most recent call last):\n' + msg += '%s\n' % src.rstrip() msg += ''.join(self.tb).rstrip() self.loop.call_exception_handler({'message': msg}) 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 @@ -606,33 +606,37 @@ self.assertGreater(pr.nbytes, 0) tr.close() - if ssl: - def _dummy_ssl_create_context(self, purpose=ssl.Purpose.SERVER_AUTH, *, - cafile=None, capath=None, cadata=None): - """ - A ssl.create_default_context() replacement that doesn't enable - cert validation. - """ - self.assertEqual(purpose, ssl.Purpose.SERVER_AUTH) - return test_utils.dummy_ssl_context() - def _test_create_ssl_connection(self, httpd, create_connection, check_sockname=True): conn_fut = create_connection(ssl=test_utils.dummy_ssl_context()) self._basetest_create_ssl_connection(conn_fut, check_sockname) - # With ssl=True, ssl.create_default_context() should be called - with mock.patch('ssl.create_default_context', - side_effect=self._dummy_ssl_create_context) as m: - conn_fut = create_connection(ssl=True) - self._basetest_create_ssl_connection(conn_fut, check_sockname) - self.assertEqual(m.call_count, 1) + # ssl.Purpose was introduced in Python 3.4 + if hasattr(ssl, 'Purpose'): + def _dummy_ssl_create_context(purpose=ssl.Purpose.SERVER_AUTH, *, + cafile=None, capath=None, + cadata=None): + """ + A ssl.create_default_context() replacement that doesn't enable + cert validation. + """ + self.assertEqual(purpose, ssl.Purpose.SERVER_AUTH) + return test_utils.dummy_ssl_context() + + # With ssl=True, ssl.create_default_context() should be called + with mock.patch('ssl.create_default_context', + side_effect=_dummy_ssl_create_context) as m: + conn_fut = create_connection(ssl=True) + self._basetest_create_ssl_connection(conn_fut, check_sockname) + self.assertEqual(m.call_count, 1) # With the real ssl.create_default_context(), certificate # validation will fail with self.assertRaises(ssl.SSLError) as cm: conn_fut = create_connection(ssl=True) - self._basetest_create_ssl_connection(conn_fut, check_sockname) + # Ignore the "SSL handshake failed" log in debug mode + with test_utils.disable_logger(): + self._basetest_create_ssl_connection(conn_fut, check_sockname) self.assertEqual(cm.exception.reason, 'CERTIFICATE_VERIFY_FAILED') 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 @@ -307,8 +307,8 @@ 'test_future_source_traceback')) @mock.patch('asyncio.base_events.logger') - def test_future_exception_never_retrieved(self, m_log): - self.loop.set_debug(True) + def check_future_exception_never_retrieved(self, debug, m_log): + self.loop.set_debug(debug) def memory_error(): try: @@ -318,40 +318,59 @@ exc = memory_error() future = asyncio.Future(loop=self.loop) - source_traceback = future._source_traceback + if debug: + source_traceback = future._source_traceback future.set_exception(exc) future = None test_utils.run_briefly(self.loop) support.gc_collect() if sys.version_info >= (3, 4): - frame = source_traceback[-1] - regex = (r'^Future exception was never retrieved\n' - r'future: \n' - r'source_traceback: Object created at \(most recent call last\):\n' - r' File' - r'.*\n' - r' File "{filename}", line {lineno}, in test_future_exception_never_retrieved\n' - r' future = asyncio\.Future\(loop=self\.loop\)$' - ).format(filename=re.escape(frame[0]), lineno=frame[1]) + if debug: + frame = source_traceback[-1] + regex = (r'^Future exception was never retrieved\n' + r'future: \n' + r'source_traceback: Object created at \(most recent call last\):\n' + r' File' + r'.*\n' + r' File "{filename}", line {lineno}, in check_future_exception_never_retrieved\n' + r' future = asyncio\.Future\(loop=self\.loop\)$' + ).format(filename=re.escape(frame[0]), lineno=frame[1]) + else: + regex = (r'^Future exception was never retrieved\n' + r'future: $' + ) exc_info = (type(exc), exc, exc.__traceback__) m_log.error.assert_called_once_with(mock.ANY, exc_info=exc_info) else: - frame = source_traceback[-1] - regex = (r'^Future/Task exception was never retrieved\n' - r'Future/Task created at \(most recent call last\):\n' - r' File' - r'.*\n' - r' File "{filename}", line {lineno}, in test_future_exception_never_retrieved\n' - r' future = asyncio\.Future\(loop=self\.loop\)\n' - r'Traceback \(most recent call last\):\n' - r'.*\n' - r'MemoryError$' - ).format(filename=re.escape(frame[0]), lineno=frame[1]) + if debug: + frame = source_traceback[-1] + regex = (r'^Future/Task exception was never retrieved\n' + r'Future/Task created at \(most recent call last\):\n' + r' File' + r'.*\n' + r' File "{filename}", line {lineno}, in check_future_exception_never_retrieved\n' + r' future = asyncio\.Future\(loop=self\.loop\)\n' + r'Traceback \(most recent call last\):\n' + r'.*\n' + r'MemoryError$' + ).format(filename=re.escape(frame[0]), lineno=frame[1]) + else: + regex = (r'^Future/Task exception was never retrieved\n' + r'Traceback \(most recent call last\):\n' + r'.*\n' + r'MemoryError$' + ) m_log.error.assert_called_once_with(mock.ANY, exc_info=False) message = m_log.error.call_args[0][0] self.assertRegex(message, re.compile(regex, re.DOTALL)) + def test_future_exception_never_retrieved(self): + self.check_future_exception_never_retrieved(False) + + def test_future_exception_never_retrieved_debug(self): + self.check_future_exception_never_retrieved(True) + def test_set_result_unless_cancelled(self): fut = asyncio.Future(loop=self.loop) fut.cancel() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 20 15:05:19 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 20 Nov 2014 14:05:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E4_=28asyncio=29?= Message-ID: <20141120140507.130913.3418@psf.io> https://hg.python.org/cpython/rev/5dbe3c3d014b changeset: 93520:5dbe3c3d014b parent: 93518:3d3928940da3 parent: 93519:1b5d23a4a5fd user: Victor Stinner date: Thu Nov 20 15:04:31 2014 +0100 summary: Merge 3.4 (asyncio) files: Lib/asyncio/base_events.py | 11 ++- Lib/asyncio/unix_events.py | 5 +- Lib/test/test_asyncio/test_base_events.py | 26 ++++++---- Lib/test/test_asyncio/test_unix_events.py | 14 ++++- 4 files changed, 35 insertions(+), 21 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 @@ -357,7 +357,8 @@ Absolute time corresponds to the event loop's time() method. """ - if coroutines.iscoroutinefunction(callback): + if (coroutines.iscoroutine(callback) + or coroutines.iscoroutinefunction(callback)): raise TypeError("coroutines cannot be used with call_at()") if self._debug: self._assert_is_current_event_loop() @@ -384,7 +385,8 @@ return handle def _call_soon(self, callback, args, check_loop): - if coroutines.iscoroutinefunction(callback): + if (coroutines.iscoroutine(callback) + or coroutines.iscoroutinefunction(callback)): raise TypeError("coroutines cannot be used with call_soon()") if self._debug and check_loop: self._assert_is_current_event_loop() @@ -421,8 +423,9 @@ return handle def run_in_executor(self, executor, callback, *args): - if coroutines.iscoroutinefunction(callback): - raise TypeError("Coroutines cannot be used with run_in_executor()") + if (coroutines.iscoroutine(callback) + or coroutines.iscoroutinefunction(callback)): + raise TypeError("coroutines cannot be used with run_in_executor()") if isinstance(callback, events.Handle): assert not args assert not isinstance(callback, events.TimerHandle) 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 @@ -67,8 +67,9 @@ Raise ValueError if the signal number is invalid or uncatchable. Raise RuntimeError if there is a problem setting up the handler. """ - if coroutines.iscoroutinefunction(callback): - raise TypeError("coroutines cannot be used with call_soon()") + if (coroutines.iscoroutine(callback) + or coroutines.iscoroutinefunction(callback)): + raise TypeError("coroutines cannot be used with add_signal_handler()") self._check_signal(sig) try: # set_wakeup_fd() raises ValueError if this is not the 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 @@ -1107,19 +1107,23 @@ def test_call_coroutine(self): @asyncio.coroutine - def coroutine_function(): + def simple_coroutine(): pass - with self.assertRaises(TypeError): - self.loop.call_soon(coroutine_function) - with self.assertRaises(TypeError): - self.loop.call_soon_threadsafe(coroutine_function) - with self.assertRaises(TypeError): - self.loop.call_later(60, coroutine_function) - with self.assertRaises(TypeError): - self.loop.call_at(self.loop.time() + 60, coroutine_function) - with self.assertRaises(TypeError): - self.loop.run_in_executor(None, coroutine_function) + coro_func = simple_coroutine + coro_obj = coro_func() + self.addCleanup(coro_obj.close) + for func in (coro_func, coro_obj): + with self.assertRaises(TypeError): + self.loop.call_soon(func) + with self.assertRaises(TypeError): + self.loop.call_soon_threadsafe(func) + with self.assertRaises(TypeError): + self.loop.call_later(60, func) + with self.assertRaises(TypeError): + self.loop.call_at(self.loop.time() + 60, func) + with self.assertRaises(TypeError): + self.loop.run_in_executor(None, func) @mock.patch('asyncio.base_events.logger') def test_log_slow_callbacks(self, m_logger): 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 @@ -65,15 +65,21 @@ @mock.patch('asyncio.unix_events.signal') def test_add_signal_handler_coroutine_error(self, m_signal): + m_signal.NSIG = signal.NSIG @asyncio.coroutine def simple_coroutine(): yield from [] - self.assertRaises( - TypeError, - self.loop.add_signal_handler, - signal.SIGINT, simple_coroutine) + # callback must not be a coroutine function + coro_func = simple_coroutine + coro_obj = coro_func() + self.addCleanup(coro_obj.close) + for func in (coro_func, coro_obj): + self.assertRaisesRegex( + TypeError, 'coroutines cannot be used with add_signal_handler', + self.loop.add_signal_handler, + signal.SIGINT, func) @mock.patch('asyncio.unix_events.signal') def test_add_signal_handler(self, m_signal): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 20 15:05:19 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 20 Nov 2014 14:05:19 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbzogQ29y?= =?utf-8?q?outine_objects_are_now_rejected_with_a_TypeError_by_the_followi?= =?utf-8?q?ng?= Message-ID: <20141120140507.68812.20648@psf.io> https://hg.python.org/cpython/rev/1b5d23a4a5fd changeset: 93519:1b5d23a4a5fd branch: 3.4 parent: 93517:ab7b942dfaa8 user: Victor Stinner date: Thu Nov 20 15:03:52 2014 +0100 summary: asyncio: Coroutine objects are now rejected with a TypeError by the following functions: * add_signal_handler() * call_at() * call_later() * call_soon() * call_soon_threadsafe() * run_in_executor() Fix also the error message of add_signal_handler() (fix the name of the function). files: Lib/asyncio/base_events.py | 11 ++- Lib/asyncio/unix_events.py | 5 +- Lib/test/test_asyncio/test_base_events.py | 26 ++++++---- Lib/test/test_asyncio/test_unix_events.py | 14 ++++- 4 files changed, 35 insertions(+), 21 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 @@ -357,7 +357,8 @@ Absolute time corresponds to the event loop's time() method. """ - if coroutines.iscoroutinefunction(callback): + if (coroutines.iscoroutine(callback) + or coroutines.iscoroutinefunction(callback)): raise TypeError("coroutines cannot be used with call_at()") if self._debug: self._assert_is_current_event_loop() @@ -384,7 +385,8 @@ return handle def _call_soon(self, callback, args, check_loop): - if coroutines.iscoroutinefunction(callback): + if (coroutines.iscoroutine(callback) + or coroutines.iscoroutinefunction(callback)): raise TypeError("coroutines cannot be used with call_soon()") if self._debug and check_loop: self._assert_is_current_event_loop() @@ -421,8 +423,9 @@ return handle def run_in_executor(self, executor, callback, *args): - if coroutines.iscoroutinefunction(callback): - raise TypeError("Coroutines cannot be used with run_in_executor()") + if (coroutines.iscoroutine(callback) + or coroutines.iscoroutinefunction(callback)): + raise TypeError("coroutines cannot be used with run_in_executor()") if isinstance(callback, events.Handle): assert not args assert not isinstance(callback, events.TimerHandle) 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 @@ -67,8 +67,9 @@ Raise ValueError if the signal number is invalid or uncatchable. Raise RuntimeError if there is a problem setting up the handler. """ - if coroutines.iscoroutinefunction(callback): - raise TypeError("coroutines cannot be used with call_soon()") + if (coroutines.iscoroutine(callback) + or coroutines.iscoroutinefunction(callback)): + raise TypeError("coroutines cannot be used with add_signal_handler()") self._check_signal(sig) try: # set_wakeup_fd() raises ValueError if this is not the 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 @@ -1107,19 +1107,23 @@ def test_call_coroutine(self): @asyncio.coroutine - def coroutine_function(): + def simple_coroutine(): pass - with self.assertRaises(TypeError): - self.loop.call_soon(coroutine_function) - with self.assertRaises(TypeError): - self.loop.call_soon_threadsafe(coroutine_function) - with self.assertRaises(TypeError): - self.loop.call_later(60, coroutine_function) - with self.assertRaises(TypeError): - self.loop.call_at(self.loop.time() + 60, coroutine_function) - with self.assertRaises(TypeError): - self.loop.run_in_executor(None, coroutine_function) + coro_func = simple_coroutine + coro_obj = coro_func() + self.addCleanup(coro_obj.close) + for func in (coro_func, coro_obj): + with self.assertRaises(TypeError): + self.loop.call_soon(func) + with self.assertRaises(TypeError): + self.loop.call_soon_threadsafe(func) + with self.assertRaises(TypeError): + self.loop.call_later(60, func) + with self.assertRaises(TypeError): + self.loop.call_at(self.loop.time() + 60, func) + with self.assertRaises(TypeError): + self.loop.run_in_executor(None, func) @mock.patch('asyncio.base_events.logger') def test_log_slow_callbacks(self, m_logger): 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 @@ -65,15 +65,21 @@ @mock.patch('asyncio.unix_events.signal') def test_add_signal_handler_coroutine_error(self, m_signal): + m_signal.NSIG = signal.NSIG @asyncio.coroutine def simple_coroutine(): yield from [] - self.assertRaises( - TypeError, - self.loop.add_signal_handler, - signal.SIGINT, simple_coroutine) + # callback must not be a coroutine function + coro_func = simple_coroutine + coro_obj = coro_func() + self.addCleanup(coro_obj.close) + for func in (coro_func, coro_obj): + self.assertRaisesRegex( + TypeError, 'coroutines cannot be used with add_signal_handler', + self.loop.add_signal_handler, + signal.SIGINT, func) @mock.patch('asyncio.unix_events.signal') def test_add_signal_handler(self, m_signal): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 20 15:38:47 2014 From: python-checkins at python.org (donald.stufft) Date: Thu, 20 Nov 2014 14:38:47 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIyODI3?= =?utf-8?q?=3A_Backport_the_new_Distributing_and_Instaling_Docs_from_3=2E4?= Message-ID: <20141120143838.7146.46168@psf.io> https://hg.python.org/cpython/rev/8bc29f5ebeff changeset: 93521:8bc29f5ebeff branch: 2.7 parent: 93514:07f4b6ecd04a user: Donald Stufft date: Thu Nov 20 09:38:31 2014 -0500 summary: Issue #22827: Backport the new Distributing and Instaling Docs from 3.4 files: Doc/conf.py | 4 +- Doc/contents.rst | 12 +- Doc/distributing/index.rst | 170 +++++++++++++++++++ Doc/glossary.rst | 6 + Doc/installing/index.rst | 215 +++++++++++++++++++++++++ 5 files changed, 403 insertions(+), 4 deletions(-) diff --git a/Doc/conf.py b/Doc/conf.py --- a/Doc/conf.py +++ b/Doc/conf.py @@ -94,11 +94,11 @@ latex_documents = [ ('c-api/index', 'c-api.tex', 'The Python/C API', _stdauthor, 'manual'), - ('distutils/index', 'distutils.tex', + ('distributing/index', 'distributing.tex', 'Distributing Python Modules', _stdauthor, 'manual'), ('extending/index', 'extending.tex', 'Extending and Embedding Python', _stdauthor, 'manual'), - ('install/index', 'install.tex', + ('installing/index', 'installing.tex', 'Installing Python Modules', _stdauthor, 'manual'), ('library/index', 'library.tex', 'The Python Library Reference', _stdauthor, 'manual'), diff --git a/Doc/contents.rst b/Doc/contents.rst --- a/Doc/contents.rst +++ b/Doc/contents.rst @@ -11,8 +11,8 @@ library/index.rst extending/index.rst c-api/index.rst - distutils/index.rst - install/index.rst + distributing/index.rst + installing/index.rst howto/index.rst faq/index.rst glossary.rst @@ -21,3 +21,11 @@ bugs.rst copyright.rst license.rst + +.. to include legacy packaging docs in build + +.. toctree:: + :hidden: + + distutils/index.rst + install/index.rst diff --git a/Doc/distributing/index.rst b/Doc/distributing/index.rst new file mode 100644 --- /dev/null +++ b/Doc/distributing/index.rst @@ -0,0 +1,170 @@ +.. _distributing-index: + +############################### + Distributing Python Modules +############################### + +:Email: distutils-sig at python.org + + +As a popular open source development project, Python has an active +supporting community of contributors and users that also make their software +available for other Python developers to use under open source license terms. + +This allows Python users to share and collaborate effectively, benefiting +from the solutions others have already created to common (and sometimes +even rare!) problems, as well as potentially contributing their own +solutions to the common pool. + +This guide covers the distribution part of the process. For a guide to +installing other Python projects, refer to the +:ref:`installation guide `. + +.. note:: + + For corporate and other institutional users, be aware that many + organisations have their own policies around using and contributing to + open source software. Please take such policies into account when making + use of the distribution and installation tools provided with Python. + + +Key terms +========= + +* the `Python Packaging Index `__ is a public + repository of open source licensed packages made available for use by + other Python users +* the `Python Packaging Authority + `__ are the group of + developers and documentation authors responsible for the maintenance and + evolution of the standard packaging tools and the associated metadata and + file format standards. They maintain a variety of tools, documentation + and issue trackers on both `GitHub `__ and + `BitBucket `__. +* :mod:`distutils` is the original build and distribution system first added + to the Python standard library in 1998. While direct use of :mod:`distutils` + is being phased out, it still laid the foundation for the current packaging + and distribution infrastructure, and it not only remains part of the + standard library, but its name lives on in other ways (such as the name + of the mailing list used to coordinate Python packaging standards + development). +* `setuptools`_ is a (largely) drop-in replacement for :mod:`distutils` first + published in 2004. Its most notable addition over the unmodified + :mod:`distutils` tools was the ability to declare dependencies on other + packages. It is currently recommended as a more regularly updated + alternative to :mod:`distutils` that offers consistent support for more + recent packaging standards across a wide range of Python versions. +* `wheel`_ (in this context) is a project that adds the ``bdist_wheel`` + command to :mod:`distutils`/`setuptools`_. This produces a cross platform + binary packaging format (called "wheels" or "wheel files" and defined in + :pep:`427`) that allows Python libraries, even those including binary + extensions, to be installed on a system without needing to be built + locally. + +.. _setuptools: https://setuptools.pypa.io/en/latest/setuptools.html +.. _wheel: http://wheel.readthedocs.org + +Open source licensing and collaboration +======================================= + +In most parts of the world, software is automatically covered by copyright. +This means that other developers require explicit permission to copy, use, +modify and redistribute the software. + +Open source licensing is a way of explicitly granting such permission in a +relatively consistent way, allowing developers to share and collaborate +efficiently by making common solutions to various problems freely available. +This leaves many developers free to spend more time focusing on the problems +that are relatively unique to their specific situation. + +The distribution tools provided with Python are designed to make it +reasonably straightforward for developers to make their own contributions +back to that common pool of software if they choose to do so. + +The same distribution tools can also be used to distribute software within +an organisation, regardless of whether that software is published as open +source software or not. + + +Installing the tools +==================== + +The standard library does not include build tools that support modern +Python packaging standards, as the core development team has found that it +is important to have standard tools that work consistently, even on older +versions of Python. + +The currently recommended build and distribution tools can be installed +by invoking the ``pip`` module at the command line:: + + python -m pip install setuptools wheel twine + +.. note:: + + For POSIX users (including Mac OS X and Linux users), these instructions + assume the use of a :term:`virtual environment`. + + For Windows users, these instructions assume that the option to + adjust the system PATH environment variable was selected when installing + Python. + +The Python Packaging User Guide includes more details on the `currently +recommended tools`_. + +.. _currently recommended tools: https://packaging.python.org/en/latest/current.html#packaging-tool-recommendations + +Reading the guide +================= + +The Python Packaging User Guide covers the various key steps and elements +involved in creating a project: + +* `Project structure`_ +* `Building and packaging the project`_ +* `Uploading the project to the Python Packaging Index`_ + +.. _Project structure: \ + https://packaging.python.org/en/latest/distributing.html#creating-your-own-project +.. _Building and packaging the project: \ + https://packaging.python.org/en/latest/distributing.html#packaging-your-project +.. _Uploading the project to the Python Packaging Index: \ + https://packaging.python.org/en/latest/distributing.html#uploading-your-project-to-pypi + + +How do I...? +============ + +These are quick answers or links for some common tasks. + +... choose a name for my project? +--------------------------------- + +This isn't an easy topic, but here are a few tips: + +* check the Python Packaging Index to see if the name is already in use +* check popular hosting sites like GitHub, BitBucket, etc to see if there + is already a project with that name +* check what comes up in a web search for the name you're considering +* avoid particularly common words, especially ones with multiple meanings, + as they can make it difficult for users to find your software when + searching for it + + +... create and distribute binary extensions? +-------------------------------------------- + +This is actually quite a complex topic, with a variety of alternatives +available depending on exactly what you're aiming to achieve. See the +Python Packaging User Guide for more information and recommendations. + +.. seealso:: + + `Python Packaging User Guide: Binary Extensions + `__ + +.. other topics: + + Once the Development & Deployment part of PPUG is fleshed out, some of + those sections should be linked from new questions here (most notably, + we should have a question about avoiding depending on PyPI that links to + https://packaging.python.org/en/latest/deployment.html#pypi-mirrors-and-caches) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -720,6 +720,12 @@ the dictionary view to become a full list use ``list(dictview)``. See :ref:`dict-views`. + virtual environment + A cooperatively isolated runtime environment that allows Python users + and applications to install and upgrade Python distribution packages + without interfering with the behaviour of other Python applications + running on the same system. + virtual machine A computer defined entirely in software. Python's virtual machine executes the :term:`bytecode` emitted by the bytecode compiler. diff --git a/Doc/installing/index.rst b/Doc/installing/index.rst new file mode 100644 --- /dev/null +++ b/Doc/installing/index.rst @@ -0,0 +1,215 @@ +.. highlightlang:: none + +.. _installing-index: + +***************************** + Installing Python Modules +***************************** + +:Email: distutils-sig at python.org + +As a popular open source development project, Python has an active +supporting community of contributors and users that also make their software +available for other Python developers to use under open source license terms. + +This allows Python users to share and collaborate effectively, benefiting +from the solutions others have already created to common (and sometimes +even rare!) problems, as well as potentially contributing their own +solutions to the common pool. + +This guide covers the installation part of the process. For a guide to +creating and sharing your own Python projects, refer to the +:ref:`distribution guide `. + +.. note:: + + For corporate and other institutional users, be aware that many + organisations have their own policies around using and contributing to + open source software. Please take such policies into account when making + use of the distribution and installation tools provided with Python. + + +Key terms +========= + +* ``pip`` is the preferred installer program. Starting with Python 2.7.9, it + is included by default with the Python binary installers. +* a virtual environment is a semi-isolated Python environment that allows + packages to be installed for use by a particular application, rather than + being installed system wide +* ``virtualenv`` is a third party tools for creating virtual environments, it + is defaults to installing ``pip`` into all created virtual environments. +* the `Python Packaging Index `__ is a public + repository of open source licensed packages made available for use by + other Python users +* the `Python Packaging Authority + `__ are the group of + developers and documentation authors responsible for the maintenance and + evolution of the standard packaging tools and the associated metadata and + file format standards. They maintain a variety of tools, documentation + and issue trackers on both `GitHub `__ and + `BitBucket `__. +* ``distutils`` is the original build and distribution system first added to + the Python standard library in 1998. While direct use of ``distutils`` is + being phased out, it still laid the foundation for the current packaging + and distribution infrastructure, and it not only remains part of the + standard library, but its name lives on in other ways (such as the name + of the mailing list used to coordinate Python packaging standards + development). + + +Basic usage +=========== + +The standard packaging tools are all designed to be used from the command +line. + +The following command will install the latest version of a module and its +dependencies from the Python Packaging Index:: + + python -m pip install SomePackage + +.. note:: + + For POSIX users (including Mac OS X and Linux users), the examples in + this guide assume the use of a :term:`virtual environment`. You may install + ``virtualenv`` to provide such environments using either pip + (``pip install virtualenv``) or through your system package manager + (commonly called ``virtualenv`` or ``python-virtualenv``). + + For Windows users, the examples in this guide assume that the option to + adjust the system PATH environment variable was selected when installing + Python. + +It's also possible to specify an exact or minimum version directly on the +command line:: + + python -m pip install SomePackage==1.0.4 # specific version + python -m pip install 'SomePackage>=1.0.4' # minimum version + +Normally, if a suitable module is already installed, attempting to install +it again will have no effect. Upgrading existing modules must be requested +explicitly:: + + python -m pip install --upgrade SomePackage + +More information and resources regarding ``pip`` and its capabilities can be +found in the `Python Packaging User Guide `__. + +.. seealso:: + + `Python Packaging User Guide: Installing Python Distribution Packages + `__ + + +How do I ...? +============= + +These are quick answers or links for some common tasks. + +... install ``pip`` in versions of Python prior to Python 2.7.9? +---------------------------------------------------------------- + +Python only started bundling ``pip`` with Python 2.7.9. For earlier versions, +``pip`` needs to be "bootstrapped" as described in the Python Packaging +User Guide. + +.. seealso:: + + `Python Packaging User Guide: Setup for Installing Distribution Packages + `__ + + +.. installing-per-user-installation: + +... install packages just for the current user? +----------------------------------------------- + +Passing the ``--user`` option to ``python -m pip install`` will install a +package just for the current user, rather than for all users of the system. + + +... install scientific Python packages? +--------------------------------------- + +A number of scientific Python packages have complex binary dependencies, and +aren't currently easy to install using ``pip`` directly. At this point in +time, it will often be easier for users to install these packages by +`other means +`__ +rather than attempting to install them with ``pip``. + +.. seealso:: + + `Python Packaging User Guide: Installing Scientific Packages + `__ + + +... work with multiple versions of Python installed in parallel? +---------------------------------------------------------------- + +On Linux, Mac OS X and other POSIX systems, use the versioned Python commands +in combination with the ``-m`` switch to run the appropriate copy of +``pip``:: + + python2 -m pip install SomePackage # default Python 2 + python2.7 -m pip install SomePackage # specifically Python 2.7 + python3 -m pip install SomePackage # default Python 3 + python3.4 -m pip install SomePackage # specifically Python 3.4 + +(appropriately versioned ``pip`` commands may also be available) + +On Windows, use the ``py`` Python launcher in combination with the ``-m`` +switch:: + + py -2 -m pip install SomePackage # default Python 2 + py -2.7 -m pip install SomePackage # specifically Python 2.7 + py -3 -m pip install SomePackage # default Python 3 + py -3.4 -m pip install SomePackage # specifically Python 3.4 + +.. other questions: + + Once the Development & Deployment part of PPUG is fleshed out, some of + those sections should be linked from new questions here (most notably, + we should have a question about avoiding depending on PyPI that links to + https://packaging.python.org/en/latest/deployment.html#pypi-mirrors-and-caches) + + +Common installation issues +========================== + +Installing into the system Python on Linux +------------------------------------------ + +On Linux systems, a Python installation will typically be included as part +of the distribution. Installing into this Python installation requires +root access to the system, and may interfere with the operation of the +system package manager and other components of the system if a component +is unexpectedly upgraded using ``pip``. + +On such systems, it is often better to use a virtual environment or a +per-user installation when installing packages with ``pip``. + + +Installing binary extensions +---------------------------- + +Python has typically relied heavily on source based distribution, with end +users being expected to compile extension modules from source as part of +the installation process. + +With the introduction of support for the binary ``wheel`` format, and the +ability to publish wheels for at least Windows and Mac OS X through the +Python Packaging Index, this problem is expected to diminish over time, +as users are more regularly able to install pre-built extensions rather +than needing to build them themselves. + +Some of the solutions for installing `scientific software +`__ +that is not yet available as pre-built ``wheel`` files may also help with +obtaining other binary extensions without needing to build them locally. + +.. seealso:: + + `Python Packaging User Guide: Binary Extensions + `__ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 20 19:56:12 2014 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 20 Nov 2014 18:56:12 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Add_a_clarifying_paragraph_to?= =?utf-8?q?_PEP_0479=2C_and_another_post-history_date=2E?= Message-ID: <20141120185553.43952.76776@psf.io> https://hg.python.org/peps/rev/b218685f6a4d changeset: 5603:b218685f6a4d user: Guido van Rossum date: Thu Nov 20 10:55:48 2014 -0800 summary: Add a clarifying paragraph to PEP 0479, and another post-history date. files: pep-0479.txt | 16 +++++++++++++++- 1 files changed, 15 insertions(+), 1 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -8,7 +8,7 @@ Content-Type: text/x-rst Created: 15-Nov-2014 Python-Version: 3.5 -Post-History: 15-Nov-2014 +Post-History: 15-Nov-2014, 19-Nov-2014 Abstract @@ -179,6 +179,20 @@ in favor of changing list comprehensions to match generator expressions (!), the other was in favor of this PEP's main proposal. +The existing model has been compared to the perfectly-acceptable +issues inherent to every other case where an exception has special +meaning. For instance, an unexpected ``KeyError`` inside a +``__getitem__`` method will be interpreted as failure, rather than +permitted to bubble up. However, there is a difference. Dunder +methods use ``return`` to indicate normality, and ``raise`` to signal +abnormality; generators ``yield`` to indicate data, and ``return`` to +signal the abnormal state. This makes explicitly raising +``StopIteration`` entirely redundant, and potentially surprising. If +other dunder methods had dedicated keywords to distinguish between +their return paths, they too could turn unexpected exceptions into +``RuntimeError``; the fact that they cannot should not preclude +generators from doing so. + References ========== -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Thu Nov 20 20:08:22 2014 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 20 Nov 2014 19:08:22 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_479=3A_Use_a_shorter_=5F?= =?utf-8?q?=5Ffuture=5F=5F_name_=28generator=5Freturn=29=2E?= Message-ID: <20141120190809.119870.15675@psf.io> https://hg.python.org/peps/rev/944968d549a8 changeset: 5604:944968d549a8 user: Guido van Rossum date: Thu Nov 20 11:01:20 2014 -0800 summary: PEP 479: Use a shorter __future__ name (generator_return). files: pep-0479.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -90,7 +90,7 @@ mechanism to introduce this in Python 3.5, finally making it standard in Python 3.6 or 3.7. The proposed syntax is:: - from __future__ import replace_stopiteration_in_generators + from __future__ import generator_return Any generator function constructed under the influence of this directive will have the REPLACE_STOPITERATION flag set on its code -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Thu Nov 20 20:15:10 2014 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 20 Nov 2014 19:15:10 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Remove_=22implicitly-raised?= =?utf-8?q?=22_from_abstract=2C_it_is_just_confusing=2E?= Message-ID: <20141120191504.43938.70565@psf.io> https://hg.python.org/peps/rev/3cafc73b266a changeset: 5605:3cafc73b266a user: Guido van Rossum date: Thu Nov 20 11:14:58 2014 -0800 summary: Remove "implicitly-raised" from abstract, it is just confusing. files: pep-0479.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -19,7 +19,7 @@ comprehensions and generator expressions, reducing surprises such as the one that started this discussion [1]_. This is also the main backwards incompatibility of the proposal -- any generator that -depends on an implicitly-raised ``StopIteration`` to terminate it will +depends on raising ``StopIteration`` to terminate it will have to be rewritten to either catch that exception or use a for-loop. -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Thu Nov 20 20:31:27 2014 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 20 Nov 2014 19:31:27 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_479=3A_Add_link_to_issue_?= =?utf-8?q?22906=2E?= Message-ID: <20141120193051.68814.51436@psf.io> https://hg.python.org/peps/rev/dd19add74b21 changeset: 5606:dd19add74b21 user: Guido van Rossum date: Thu Nov 20 11:30:39 2014 -0800 summary: PEP 479: Add link to issue 22906. files: pep-0479.txt | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -224,6 +224,9 @@ .. [9] Thread on comp.lang.python started by Steven D'Aprano (https://mail.python.org/pipermail/python-list/2014-November/680757.html) +.. [10] Tracker issue with Proof-of-Concept patch + (http://bugs.python.org/issue22906) + Copyright ========= -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Fri Nov 21 00:25:07 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 20 Nov 2014 23:25:07 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbzogQmFz?= =?utf-8?q?eSelectorEventLoop=2Eclose=28=29_now_closes_the_self-pipe_befor?= =?utf-8?q?e_calling?= Message-ID: <20141120232504.130919.88374@psf.io> https://hg.python.org/cpython/rev/a08c3703f844 changeset: 93522:a08c3703f844 branch: 3.4 parent: 93519:1b5d23a4a5fd user: Victor Stinner date: Fri Nov 21 00:23:27 2014 +0100 summary: asyncio: BaseSelectorEventLoop.close() now closes the self-pipe before calling the parent close() method. If the event loop is already closed, the self-pipe is not unregistered from the selector. files: Lib/asyncio/selector_events.py | 4 +++- 1 files changed, 3 insertions(+), 1 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 @@ -68,10 +68,12 @@ address, waiter, extra) def close(self): + if self._running: + raise RuntimeError("Cannot close a running event loop") if self.is_closed(): return + self._close_self_pipe() super().close() - self._close_self_pipe() if self._selector is not None: self._selector.close() self._selector = None -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 21 00:25:07 2014 From: python-checkins at python.org (victor.stinner) Date: Thu, 20 Nov 2014 23:25:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_=28Merge_3=2E4=29_asyncio=3A_BaseSelectorEventLoop=2Eclo?= =?utf-8?q?se=28=29_now_closes_the_self-pipe?= Message-ID: <20141120232504.68820.97036@psf.io> https://hg.python.org/cpython/rev/7ce62e80d3cd changeset: 93523:7ce62e80d3cd parent: 93520:5dbe3c3d014b parent: 93522:a08c3703f844 user: Victor Stinner date: Fri Nov 21 00:23:59 2014 +0100 summary: (Merge 3.4) asyncio: BaseSelectorEventLoop.close() now closes the self-pipe before calling the parent close() method. If the event loop is already closed, the self-pipe is not unregistered from the selector. files: Lib/asyncio/selector_events.py | 4 +++- 1 files changed, 3 insertions(+), 1 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 @@ -68,10 +68,12 @@ address, waiter, extra) def close(self): + if self._running: + raise RuntimeError("Cannot close a running event loop") if self.is_closed(): return + self._close_self_pipe() super().close() - self._close_self_pipe() if self._selector is not None: self._selector.close() self._selector = None -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 21 00:44:10 2014 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 20 Nov 2014 23:44:10 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_479=3A_switch_to_=22from_?= =?utf-8?q?=5F=5Ffuture=5F=5F_import_generator=5Fstop=22=2E?= Message-ID: <20141120234408.7148.54117@psf.io> https://hg.python.org/peps/rev/5eb88d52c5a3 changeset: 5607:5eb88d52c5a3 user: Guido van Rossum date: Thu Nov 20 15:43:56 2014 -0800 summary: PEP 479: switch to "from __future__ import generator_stop". files: pep-0479.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -90,7 +90,7 @@ mechanism to introduce this in Python 3.5, finally making it standard in Python 3.6 or 3.7. The proposed syntax is:: - from __future__ import generator_return + from __future__ import generator_stop Any generator function constructed under the influence of this directive will have the REPLACE_STOPITERATION flag set on its code -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Fri Nov 21 01:24:00 2014 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 21 Nov 2014 00:24:00 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322796=3A_HTTP_coo?= =?utf-8?q?kie_parsing_is_now_stricter=2C_in_order_to_protect_against?= Message-ID: <20141121002353.7136.51457@psf.io> https://hg.python.org/cpython/rev/a065ab1c67a8 changeset: 93524:a065ab1c67a8 user: Antoine Pitrou date: Fri Nov 21 01:20:57 2014 +0100 summary: Issue #22796: HTTP cookie parsing is now stricter, in order to protect against potential injection attacks. files: Lib/http/cookies.py | 56 ++++++++++++++++------ Lib/test/test_http_cookies.py | 12 +--- Misc/NEWS | 3 + 3 files changed, 48 insertions(+), 23 deletions(-) diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py --- a/Lib/http/cookies.py +++ b/Lib/http/cookies.py @@ -533,10 +533,17 @@ return def __parse_string(self, str, patt=_CookiePattern): - i = 0 # Our starting point - n = len(str) # Length of string - M = None # current morsel + i = 0 # Our starting point + n = len(str) # Length of string + parsed_items = [] # Parsed (type, key, value) triples + morsel_seen = False # A key=value pair was previously encountered + TYPE_ATTRIBUTE = 1 + TYPE_KEYVALUE = 2 + + # We first parse the whole cookie string and reject it if it's + # syntactically invalid (this helps avoid some classes of injection + # attacks). while 0 <= i < n: # Start looking for a cookie match = patt.match(str, i) @@ -547,22 +554,41 @@ key, value = match.group("key"), match.group("val") i = match.end(0) - # Parse the key, value in case it's metainfo if key[0] == "$": - # We ignore attributes which pertain to the cookie - # mechanism as a whole. See RFC 2109. - # (Does anyone care?) - if M: - M[key[1:]] = value + if not morsel_seen: + # We ignore attributes which pertain to the cookie + # mechanism as a whole, such as "$Version". + # See RFC 2965. (Does anyone care?) + continue + parsed_items.append((TYPE_ATTRIBUTE, key[1:], value)) elif key.lower() in Morsel._reserved: - if M: - if value is None: - if key.lower() in Morsel._flags: - M[key] = True + if not morsel_seen: + # Invalid cookie string + return + if value is None: + if key.lower() in Morsel._flags: + parsed_items.append((TYPE_ATTRIBUTE, key, True)) else: - M[key] = _unquote(value) + # Invalid cookie string + return + else: + parsed_items.append((TYPE_ATTRIBUTE, key, _unquote(value))) elif value is not None: - rval, cval = self.value_decode(value) + parsed_items.append((TYPE_KEYVALUE, key, self.value_decode(value))) + morsel_seen = True + else: + # Invalid cookie string + return + + # The cookie string is valid, apply it. + M = None # current morsel + for tp, key, value in parsed_items: + if tp == TYPE_ATTRIBUTE: + assert M is not None + M[key] = value + else: + assert tp == TYPE_KEYVALUE + rval, cval = value self.__set(key, rval, cval) M = self[key] diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py --- a/Lib/test/test_http_cookies.py +++ b/Lib/test/test_http_cookies.py @@ -141,13 +141,6 @@ self.assertEqual(C['eggs']['httponly'], 'foo') self.assertEqual(C['eggs']['secure'], 'bar') - def test_bad_attrs(self): - # issue 16611: make sure we don't break backward compatibility. - C = cookies.SimpleCookie() - C.load('cookie=with; invalid; version; second=cookie;') - self.assertEqual(C.output(), - 'Set-Cookie: cookie=with\r\nSet-Cookie: second=cookie') - def test_extra_spaces(self): C = cookies.SimpleCookie() C.load('eggs = scrambled ; secure ; path = bar ; foo=foo ') @@ -182,7 +175,10 @@ def test_invalid_cookies(self): # Accepting these could be a security issue C = cookies.SimpleCookie() - for s in (']foo=x', '[foo=x', 'blah]foo=x', 'blah[foo=x'): + for s in (']foo=x', '[foo=x', 'blah]foo=x', 'blah[foo=x', + 'Set-Cookie: foo=bar', 'Set-Cookie: foo', + 'foo=bar; baz', 'baz; foo=bar', + 'secure;foo=bar', 'Version=1;foo=bar'): C.load(s) self.assertEqual(dict(C), {}) self.assertEqual(C.output(), '') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -188,6 +188,9 @@ Library ------- +- Issue #22796: HTTP cookie parsing is now stricter, in order to protect + against potential injection attacks. + - Issue #22370: Windows detection in pathlib is now more robust. - Issue #22841: Reject coroutines in asyncio add_signal_handler(). -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 21 01:46:49 2014 From: python-checkins at python.org (steve.dower) Date: Fri, 21 Nov 2014 00:46:49 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322869=3A_Add_pyli?= =?utf-8?q?fecycle=2Ec/=2Eh_files_to_pythoncore_project=2E?= Message-ID: <20141121004642.43958.4038@psf.io> https://hg.python.org/cpython/rev/31fd106bb68a changeset: 93525:31fd106bb68a user: Steve Dower date: Thu Nov 20 16:45:36 2014 -0800 summary: Issue #22869: Add pylifecycle.c/.h files to pythoncore project. files: PCbuild/pythoncore.vcxproj | 2 ++ PCbuild/pythoncore.vcxproj.filters | 6 ++++++ 2 files changed, 8 insertions(+), 0 deletions(-) diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -502,6 +502,7 @@ + @@ -734,6 +735,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -216,6 +216,9 @@ Include + + Include + Include @@ -890,6 +893,9 @@ Python + + Python + Python -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 21 02:05:24 2014 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 21 Nov 2014 01:05:24 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Add_regression?= =?utf-8?q?_issue_number_to_Misc/NEWS_entry=2E?= Message-ID: <20141121010514.119880.40076@psf.io> https://hg.python.org/cpython/rev/c9b4dc1ab7ae changeset: 93527:c9b4dc1ab7ae branch: 2.7 user: Antoine Pitrou date: Fri Nov 21 02:05:06 2014 +0100 summary: Add regression issue number to Misc/NEWS entry. files: Misc/NEWS | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,10 +10,10 @@ Core and Builtins ----------------- -- Backout issue #1856 patch (avoid crashes and lockups when daemon threads - run while the interpreter is shutting down; instead, these threads are - now killed when they try to take the GIL), as it seems to break some - existing code. +- Issue #21963: backout issue #1856 patch (avoid crashes and lockups when + daemon threads run while the interpreter is shutting down; instead, these + threads are now killed when they try to take the GIL), as it seems to + break some existing code. - Issue #22604: Fix assertion error in debug mode when dividing a complex number by (nan+0j). -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 21 02:05:24 2014 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 21 Nov 2014 01:05:24 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIxOTYz?= =?utf-8?q?=3A_backout_issue_=231856_patch_=28avoid_crashes_and_lockups_wh?= =?utf-8?q?en?= Message-ID: <20141121010514.68812.96958@psf.io> https://hg.python.org/cpython/rev/4ceca79d1c63 changeset: 93526:4ceca79d1c63 branch: 2.7 parent: 93521:8bc29f5ebeff user: Antoine Pitrou date: Fri Nov 21 02:04:21 2014 +0100 summary: Issue #21963: backout issue #1856 patch (avoid crashes and lockups when daemon threads run while the interpreter is shutting down; instead, these threads are now killed when they try to take the GIL), as it seems to break some existing code. files: Include/pythonrun.h | 2 - Lib/test/test_threading.py | 43 -------------------------- Misc/NEWS | 9 +++-- Python/ceval.c | 12 ------- Python/pythonrun.c | 9 +---- Python/thread_pthread.h | 4 +- 6 files changed, 8 insertions(+), 71 deletions(-) diff --git a/Include/pythonrun.h b/Include/pythonrun.h --- a/Include/pythonrun.h +++ b/Include/pythonrun.h @@ -147,8 +147,6 @@ PyAPI_FUNC(void) PyByteArray_Fini(void); PyAPI_FUNC(void) _PyRandom_Fini(void); -PyAPI_DATA(PyThreadState *) _Py_Finalizing; - /* Stuff with no proper home (yet) */ PyAPI_FUNC(char *) PyOS_Readline(FILE *, FILE *, char *); PyAPI_DATA(int) (*PyOS_InputHook)(void); diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -700,49 +700,6 @@ output = "end of worker thread\nend of main thread\n" self.assertScriptHasOutput(script, output) - @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") - def test_6_daemon_threads(self): - # Check that a daemon thread cannot crash the interpreter on shutdown - # by manipulating internal structures that are being disposed of in - # the main thread. - script = """if True: - import os - import random - import sys - import time - import threading - - thread_has_run = set() - - def random_io(): - '''Loop for a while sleeping random tiny amounts and doing some I/O.''' - while True: - in_f = open(os.__file__, 'rb') - stuff = in_f.read(200) - null_f = open(os.devnull, 'wb') - null_f.write(stuff) - time.sleep(random.random() / 1995) - null_f.close() - in_f.close() - thread_has_run.add(threading.current_thread()) - - def main(): - count = 0 - for _ in range(40): - new_thread = threading.Thread(target=random_io) - new_thread.daemon = True - new_thread.start() - count += 1 - while len(thread_has_run) < count: - time.sleep(0.001) - # Trigger process shutdown - sys.exit(0) - - main() - """ - rc, out, err = assert_python_ok('-c', script) - self.assertFalse(err) - @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") def test_reinit_tls_after_fork(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ Core and Builtins ----------------- +- Backout issue #1856 patch (avoid crashes and lockups when daemon threads + run while the interpreter is shutting down; instead, these threads are + now killed when they try to take the GIL), as it seems to break some + existing code. + - Issue #22604: Fix assertion error in debug mode when dividing a complex number by (nan+0j). @@ -360,10 +365,6 @@ - Issue #21831: Avoid integer overflow when large sizes and offsets are given to the buffer type. CVE-2014-7185. -- Issue #1856: Avoid crashes and lockups when daemon threads run while the - interpreter is shutting down; instead, these threads are now killed when they - try to take the GIL. - - Issue #19656: Running Python with the -3 option now also warns about non-ascii bytes literals. diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -355,12 +355,6 @@ if (interpreter_lock) { int err = errno; PyThread_acquire_lock(interpreter_lock, 1); - /* _Py_Finalizing is protected by the GIL */ - if (_Py_Finalizing && tstate != _Py_Finalizing) { - PyThread_release_lock(interpreter_lock); - PyThread_exit_thread(); - assert(0); /* unreachable */ - } errno = err; } #endif @@ -1025,12 +1019,6 @@ PyThread_acquire_lock(interpreter_lock, 1); - /* Check if we should make a quick exit. */ - if (_Py_Finalizing && _Py_Finalizing != tstate) { - PyThread_release_lock(interpreter_lock); - PyThread_exit_thread(); - } - if (PyThreadState_Swap(tstate) != NULL) Py_FatalError("ceval: orphan tstate"); diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -91,8 +91,6 @@ int Py_NoUserSiteDirectory = 0; /* for -s and site.py */ int Py_HashRandomizationFlag = 0; /* for -R and PYTHONHASHSEED */ -PyThreadState *_Py_Finalizing = NULL; - /* Hack to force loading of object files */ int (*_PyOS_mystrnicmp_hack)(const char *, const char *, Py_ssize_t) = \ @@ -165,7 +163,6 @@ if (initialized) return; initialized = 1; - _Py_Finalizing = NULL; if ((p = Py_GETENV("PYTHONDEBUG")) && *p != '\0') Py_DebugFlag = add_flag(Py_DebugFlag, p); @@ -425,16 +422,12 @@ * the threads created via Threading. */ call_sys_exitfunc(); + initialized = 0; /* Get current thread state and interpreter pointer */ tstate = PyThreadState_GET(); interp = tstate->interp; - /* Remaining threads (e.g. daemon threads) will automatically exit - after taking the GIL (in PyEval_RestoreThread()). */ - _Py_Finalizing = tstate; - initialized = 0; - /* Disable signal handling */ PyOS_FiniInterrupts(); diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -242,9 +242,9 @@ PyThread_exit_thread(void) { dprintf(("PyThread_exit_thread called\n")); - if (!initialized) + if (!initialized) { exit(0); - pthread_exit(0); + } } #ifdef USE_SEMAPHORES -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 21 06:14:23 2014 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 21 Nov 2014 05:14:23 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_479=3A_Fix_formatting_of_?= =?utf-8?q?examples=2E?= Message-ID: <20141121051422.130917.96819@psf.io> https://hg.python.org/peps/rev/73625fa16b36 changeset: 5609:73625fa16b36 user: Guido van Rossum date: Thu Nov 20 21:14:17 2014 -0800 summary: PEP 479: Fix formatting of examples. files: pep-0479.txt | 17 +++++++++++++++++ 1 files changed, 17 insertions(+), 0 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -106,25 +106,33 @@ existing Python versions, and will not be affected by __future__. Lib/ipaddress.py:: + if other == self: raise StopIteration + Becomes:: + if other == self: return In some cases, this can be combined with ``yield from`` to simplify the code, such as Lib/difflib.py:: + if context is None: while True: yield next(line_pair_iterator) + Becomes:: + if context is None: yield from line_pair_iterator return + (The ``return`` is necessary for a strictly-equivalent translation, though in this particular file, there is no further code, and the ``return`` can be elided.) For compatibility with pre-3.3 versions of Python, this could be written with an explicit ``for`` loop:: + if context is None: for line in line_pair_iterator: yield line @@ -132,6 +140,7 @@ More complicated iteration patterns will need explicit try/catch constructs. For example, a parser construct like this:: + def unwrap(f): while True: data = next(f) @@ -140,7 +149,9 @@ if line == "- end -": break data += line yield data + would need to be rewritten as:: + def parser(f): while True: try: @@ -152,7 +163,9 @@ yield data except StopIteration: return + or possibly:: + def parser(f): for data in f: while True: @@ -186,9 +199,11 @@ raise ``AttributeError``), ``__getitem__`` (can raise ``KeyError``), and so on. A helper function for an iterator can be written to follow the same protocol; for example:: + def helper(x, y): if x > y: return 1 / (x - y) raise StopIteration + def __next__(self): if self.a: return helper(self.b, self.c) return helper(self.d, self.e) @@ -201,8 +216,10 @@ Each time it is (re)started, it may either yield a value, or return (including "falling off the end"). A helper function for a generator can also be written, but it must also follow generator protocol:: + def helper(x, y): if x > y: yield 1 / (x - y) + def gen(self): if self.a: return (yield from helper(self.b, self.c)) return (yield from helper(self.d, self.e)) -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Fri Nov 21 06:14:23 2014 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 21 Nov 2014 05:14:23 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_New_examples=2C_explanations_?= =?utf-8?q?and_a_few_edits=2C_all_by_Chris=2E?= Message-ID: <20141121051422.43944.79292@psf.io> https://hg.python.org/peps/rev/43d99a738fa1 changeset: 5608:43d99a738fa1 user: Guido van Rossum date: Thu Nov 20 21:07:18 2014 -0800 summary: New examples, explanations and a few edits, all by Chris. files: pep-0479.txt | 127 +++++++++++++++++++++++++++++++++++++- 1 files changed, 122 insertions(+), 5 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -98,6 +98,120 @@ proposal. Once the feature becomes standard, the flag may be dropped; code should not inspect generators for it. +Examples +-------- + +Generators which explicitly raise StopIteration can generally be +changed to simply return instead. This will be compatible with all +existing Python versions, and will not be affected by __future__. + +Lib/ipaddress.py:: + if other == self: + raise StopIteration +Becomes:: + if other == self: + return + +In some cases, this can be combined with ``yield from`` to simplify +the code, such as Lib/difflib.py:: + if context is None: + while True: + yield next(line_pair_iterator) +Becomes:: + if context is None: + yield from line_pair_iterator + return +(The ``return`` is necessary for a strictly-equivalent translation, +though in this particular file, there is no further code, and the +``return`` can be elided.) For compatibility with pre-3.3 versions +of Python, this could be written with an explicit ``for`` loop:: + if context is None: + for line in line_pair_iterator: + yield line + return + +More complicated iteration patterns will need explicit try/catch +constructs. For example, a parser construct like this:: + def unwrap(f): + while True: + data = next(f) + while True: + line = next(f) + if line == "- end -": break + data += line + yield data +would need to be rewritten as:: + def parser(f): + while True: + try: + data = next(f) + while True: + line = next(f) + if line == "- end -": break + data += line + yield data + except StopIteration: + return +or possibly:: + def parser(f): + for data in f: + while True: + line = next(f) + if line == "- end -": break + data += line + yield data + +The latter form obscures the iteration by purporting to iterate over +the file with a ``for`` loop, but then also fetches more data from +the same iterator during the loop body. It does, however, clearly +differentiate between a "normal" termination (``StopIteration`` +instead of the initial line) and an "abnormal" termination (failing +to find the end marker in the inner loop, which will now raise +``RuntimeError``). + + +Explanation of generators, iterators, and StopIteration +======================================================= + +Under this proposal, generators and iterators would be distinct, but +related, concepts. Like the mixing of text and bytes in Python 2, +the mixing of generators and iterators has resulted in certain +perceived conveniences, but proper separation will make bugs more +visible. + +An iterator is an object with a ``__next__`` method. Like many other +dunder methods, it may either return a value, or raise a specific +exception - in this case, ``StopIteration`` - to signal that it has +no value to return. In this, it is similar to ``__getattr__`` (can +raise ``AttributeError``), ``__getitem__`` (can raise ``KeyError``), +and so on. A helper function for an iterator can be written to +follow the same protocol; for example:: + def helper(x, y): + if x > y: return 1 / (x - y) + raise StopIteration + def __next__(self): + if self.a: return helper(self.b, self.c) + return helper(self.d, self.e) + +Both forms of signalling are carried through: a returned value is +returned, an exception bubbles up. The helper is written to match +the protocol of the calling function. + +A generator function is one which contains a ``yield`` expression. +Each time it is (re)started, it may either yield a value, or return +(including "falling off the end"). A helper function for a generator +can also be written, but it must also follow generator protocol:: + def helper(x, y): + if x > y: yield 1 / (x - y) + def gen(self): + if self.a: return (yield from helper(self.b, self.c)) + return (yield from helper(self.d, self.e)) + +In both cases, any unexpected exception will bubble up. Due to the +nature of generators and iterators, an unexpected ``StopIteration`` +inside a generator will be converted into ``RuntimeError``, but +beyond that, all exceptions will propagate normally. + Alternate proposals =================== @@ -137,17 +251,20 @@ [7]_ that if an ``asyncio`` coroutine [8]_ accidentally raises ``StopIteration``, it currently terminates silently, which may present a hard-to-debug mystery to the developer. The main proposal turns -such accidents in clearly distinguishable ``RuntimeError`` exceptions, +such accidents into clearly distinguishable ``RuntimeError`` exceptions, but if that is rejected, this alternate proposal would enable ``asyncio`` to distinguish between a ``return`` statement and an accidentally-raised ``StopIteration`` exception. -Of the three outcomes listed above: +Of the three outcomes listed above, two change: -* A yielded value, obviously, would still be returned. -* If the frame is returned from, ``GeneratorReturn`` is raised. +* If a yield point is reached, the value, obviously, would still be + returned. +* If the frame is returned from, ``GeneratorReturn`` (rather than + ``StopIteration``) is raised. * If an instance of ``GeneratorReturn`` would be raised, instead an - instance of ``StopIteration`` would be raised. + instance of ``StopIteration`` would be raised. Any other exception + bubbles up normally. In the third case, the ``StopIteration`` would have the ``value`` of the original ``GeneratorReturn``, and would reference the original -- Repository URL: https://hg.python.org/peps From solipsis at pitrou.net Fri Nov 21 11:00:32 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 21 Nov 2014 11:00:32 +0100 Subject: [Python-checkins] Daily reference leaks (31fd106bb68a): sum=3 Message-ID: results for 31fd106bb68a on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogw_yCNJ', '-x'] From python-checkins at python.org Fri Nov 21 18:19:38 2014 From: python-checkins at python.org (brett.cannon) Date: Fri, 21 Nov 2014 17:19:38 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322834=3A_Have_imp?= =?utf-8?q?ort_suppress_FileNotFoundError_when_the_current?= Message-ID: <20141121171937.7124.50147@psf.io> https://hg.python.org/cpython/rev/8558fff73032 changeset: 93528:8558fff73032 parent: 93525:31fd106bb68a user: Brett Cannon date: Fri Nov 21 12:19:28 2014 -0500 summary: Issue #22834: Have import suppress FileNotFoundError when the current working directory no longer exists. Thanks to Martin Panter for the bug report. files: Doc/library/importlib.rst | 5 + Doc/reference/import.rst | 9 + Doc/whatsnew/3.5.rst | 6 + Lib/importlib/_bootstrap.py | 7 +- Lib/test/test_importlib/import_/test_path.py | 12 + Misc/NEWS | 5 +- Python/importlib.h | 2002 +++++---- 7 files changed, 1044 insertions(+), 1002 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -794,6 +794,11 @@ .. versionadded:: 3.4 + .. versionchanged:: 3.5 + If the current working directory -- represented by an empty string -- + is no longer valid then ``None`` is returned but no value is cached + in :data:`sys.path_importer_cache`. + .. classmethod:: find_module(fullname, path=None) A legacy wrapper around :meth:`find_spec`. diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -754,6 +754,15 @@ to ask the finder for a module spec, which is then used when loading the module. +The current working directory -- denoted by an empty string -- is handled +slightly differently from other entries on :data:`sys.path`. First, if the +current working directory is found to not exist, no value is stored in +:data:`sys.path_importer_cache`. Second, the value for the current working +directory is looked up fresh for each module lookup. Third, the path used for +:data:`sys.path_importer_cache` and returned by +:meth:`importlib.machinery.PathFinder.find_spec` will be the actual current +working directory and not the empty string. + Path entry finder protocol -------------------------- diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -436,6 +436,12 @@ bytes-like object is required, not 'sometype'". (Contributed by Ezio Melotti in :issue:`16518`.) +* If the current directory is set to a directory that no longer exists then + :exc:`FileNotFoundError` will no longer be raised and instead + :meth:`~importlib.machinery.FileFinder.find_spec` will return ``None`` + **without** caching ``None`` in :data:`sys.path_importer_cache` which is + different than the typical case (:issue:`22834`). + Changes in the C API -------------------- diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -1825,7 +1825,12 @@ """ if path == '': - path = _os.getcwd() + try: + path = _os.getcwd() + except FileNotFoundError: + # Don't cache the failure as the cwd can easily change to + # a valid directory later on. + return None try: finder = sys.path_importer_cache[path] except KeyError: diff --git a/Lib/test/test_importlib/import_/test_path.py b/Lib/test/test_importlib/import_/test_path.py --- a/Lib/test/test_importlib/import_/test_path.py +++ b/Lib/test/test_importlib/import_/test_path.py @@ -5,6 +5,7 @@ import os import sys +import tempfile from types import ModuleType import unittest import warnings @@ -158,6 +159,17 @@ got = self.machinery.PathFinder.find_spec('whatever', [path]) self.assertEqual(got, success_finder.spec) + def test_deleted_cwd(self): + # Issue #22834 + self.addCleanup(os.chdir, os.getcwd()) + with tempfile.TemporaryDirectory() as path: + os.chdir(path) + with util.import_state(path=['']): + # Do not want FileNotFoundError raised. + self.assertIsNone(self.machinery.PathFinder.find_spec('whatever')) + + + (Frozen_FinderTests, Source_FinderTests diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #22834: If the current working directory ends up being set to a + non-existent directory then import will no longer raise FileNotFoundError. + - Issue #22869: Move the interpreter startup & shutdown code to a new dedicated pylifecycle.c module @@ -235,7 +238,7 @@ - Issue #22776: Brought excluded code into the scope of a try block in SysLogHandler.emit(). - + - Issue #22665: Add missing get_terminal_size and SameFileError to shutil.__all__. diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 21 19:36:20 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 21 Nov 2014 18:36:20 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2319720=3A_Suppress?= =?utf-8?q?ed_context_for_some_exceptions_in_importlib=2E?= Message-ID: <20141121183618.7142.71588@psf.io> https://hg.python.org/cpython/rev/2de3c659a979 changeset: 93529:2de3c659a979 user: Serhiy Storchaka date: Fri Nov 21 20:33:57 2014 +0200 summary: Issue #19720: Suppressed context for some exceptions in importlib. files: Lib/importlib/__init__.py | 5 +++-- Lib/importlib/_bootstrap.py | 2 +- Lib/importlib/util.py | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Lib/importlib/__init__.py b/Lib/importlib/__init__.py --- a/Lib/importlib/__init__.py +++ b/Lib/importlib/__init__.py @@ -73,7 +73,7 @@ except KeyError: pass except AttributeError: - raise ValueError('{}.__loader__ is not set'.format(name)) + raise ValueError('{}.__loader__ is not set'.format(name)) from None spec = _bootstrap._find_spec(name, path) # We won't worry about malformed specs (missing attributes). @@ -138,7 +138,8 @@ parent = sys.modules[parent_name] except KeyError: msg = "parent {!r} not in sys.modules" - raise ImportError(msg.format(parent_name), name=parent_name) + raise ImportError(msg.format(parent_name), + name=parent_name) from None else: pkgpath = parent.__path__ else: diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -2172,7 +2172,7 @@ path = parent_module.__path__ except AttributeError: msg = (_ERR_MSG + '; {!r} is not a package').format(name, parent) - raise ImportError(msg, name=name) + raise ImportError(msg, name=name) from None spec = _find_spec(name, path) if spec is None: raise ImportError(_ERR_MSG.format(name), name=name) diff --git a/Lib/importlib/util.py b/Lib/importlib/util.py --- a/Lib/importlib/util.py +++ b/Lib/importlib/util.py @@ -56,7 +56,7 @@ try: spec = module.__spec__ except AttributeError: - raise ValueError('{}.__spec__ is not set'.format(name)) + raise ValueError('{}.__spec__ is not set'.format(name)) from None else: if spec is None: raise ValueError('{}.__spec__ is None'.format(name)) @@ -96,7 +96,7 @@ try: spec = module.__spec__ except AttributeError: - raise ValueError('{}.__spec__ is not set'.format(name)) + raise ValueError('{}.__spec__ is not set'.format(name)) from None else: if spec is None: raise ValueError('{}.__spec__ is None'.format(name)) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 21 19:53:22 2014 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 21 Nov 2014 18:53:22 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Added_myself_as_PEP_479_co-au?= =?utf-8?q?thor=2E?= Message-ID: <20141121185318.43946.14453@psf.io> https://hg.python.org/peps/rev/aef3daffdeb0 changeset: 5610:aef3daffdeb0 user: Guido van Rossum date: Fri Nov 21 10:53:13 2014 -0800 summary: Added myself as PEP 479 co-author. files: pep-0479.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -2,7 +2,7 @@ Title: Change StopIteration handling inside generators Version: $Revision$ Last-Modified: $Date$ -Author: Chris Angelico +Author: Chris Angelico , Guido van Rossum Status: Draft Type: Standards Track Content-Type: text/x-rst -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Fri Nov 21 21:00:08 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 21 Nov 2014 20:00:08 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzE3Mjkz?= =?utf-8?q?=3A_socket=2Egethostbyname=28=29_can_raise_an_exception_of_Free?= =?utf-8?q?BSD=2E?= Message-ID: <20141121200006.130915.85451@psf.io> https://hg.python.org/cpython/rev/97ceab0bd6f8 changeset: 93531:97ceab0bd6f8 branch: 3.4 parent: 93522:a08c3703f844 user: Serhiy Storchaka date: Fri Nov 21 21:55:39 2014 +0200 summary: Issue #17293: socket.gethostbyname() can raise an exception of FreeBSD. files: Lib/uuid.py | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/uuid.py b/Lib/uuid.py --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -361,7 +361,10 @@ def _arp_getnode(): """Get the hardware address on Unix by running arp.""" import os, socket - ip_addr = socket.gethostbyname(socket.gethostname()) + try: + ip_addr = socket.gethostbyname(socket.gethostname()) + except OSError: + return None # Try getting the MAC addr from arp based on our IP address (Solaris). return _find_mac('arp', '-an', [ip_addr], lambda i: -1) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 21 21:00:08 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 21 Nov 2014 20:00:08 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3Mjkz?= =?utf-8?q?=3A_socket=2Egethostbyname=28=29_can_raise_an_exception_of_Free?= =?utf-8?q?BSD=2E?= Message-ID: <20141121200006.119868.16120@psf.io> https://hg.python.org/cpython/rev/301d62ef5c0b changeset: 93530:301d62ef5c0b branch: 2.7 parent: 93527:c9b4dc1ab7ae user: Serhiy Storchaka date: Fri Nov 21 21:54:43 2014 +0200 summary: Issue #17293: socket.gethostbyname() can raise an exception of FreeBSD. files: Lib/uuid.py | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/uuid.py b/Lib/uuid.py --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -345,7 +345,10 @@ def _arp_getnode(): """Get the hardware address on Unix by running arp.""" import os, socket - ip_addr = socket.gethostbyname(socket.gethostname()) + try: + ip_addr = socket.gethostbyname(socket.gethostname()) + except EnvironmentError: + return None # Try getting the MAC addr from arp based on our IP address (Solaris). return _find_mac('arp', '-an', [ip_addr], lambda i: -1) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 21 21:00:08 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 21 Nov 2014 20:00:08 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2319720=3A_Suppressed_context_for_some_exceptions?= =?utf-8?q?_in_importlib=2E?= Message-ID: <20141121200006.7140.43865@psf.io> https://hg.python.org/cpython/rev/8f77f7bb46c7 changeset: 93532:8f77f7bb46c7 parent: 93529:2de3c659a979 parent: 93531:97ceab0bd6f8 user: Serhiy Storchaka date: Fri Nov 21 21:56:57 2014 +0200 summary: Issue #19720: Suppressed context for some exceptions in importlib. files: Lib/uuid.py | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Lib/uuid.py b/Lib/uuid.py --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -359,7 +359,10 @@ def _arp_getnode(): """Get the hardware address on Unix by running arp.""" import os, socket - ip_addr = socket.gethostbyname(socket.gethostname()) + try: + ip_addr = socket.gethostbyname(socket.gethostname()) + except OSError: + return None # Try getting the MAC addr from arp based on our IP address (Solaris). return _find_mac('arp', '-an', [os.fsencode(ip_addr)], lambda i: -1) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 22 05:34:06 2014 From: python-checkins at python.org (steve.dower) Date: Sat, 22 Nov 2014 04:34:06 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322869=3A_Remove_d?= =?utf-8?q?uplicate_stack_check_from_pythonrun=2Ec?= Message-ID: <20141122043405.55125.57733@psf.io> https://hg.python.org/cpython/rev/e7df0a47af16 changeset: 93533:e7df0a47af16 user: Steve Dower date: Fri Nov 21 20:33:12 2014 -0800 summary: Issue #22869: Remove duplicate stack check from pythonrun.c files: Python/pythonrun.c | 37 ---------------------------------- 1 files changed, 0 insertions(+), 37 deletions(-) diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1376,43 +1376,6 @@ } -#if defined(USE_STACKCHECK) -#if defined(WIN32) && defined(_MSC_VER) - -/* Stack checking for Microsoft C */ - -#include -#include - -/* - * Return non-zero when we run out of memory on the stack; zero otherwise. - */ -int -PyOS_CheckStack(void) -{ - __try { - /* alloca throws a stack overflow exception if there's - not enough space left on the stack */ - alloca(PYOS_STACK_MARGIN * sizeof(void*)); - return 0; - } __except (GetExceptionCode() == STATUS_STACK_OVERFLOW ? - EXCEPTION_EXECUTE_HANDLER : - EXCEPTION_CONTINUE_SEARCH) { - int errcode = _resetstkoflw(); - if (errcode == 0) - { - Py_FatalError("Could not reset the stack!"); - } - } - return 1; -} - -#endif /* WIN32 && _MSC_VER */ - -/* Alternate implementations can be added here... */ - -#endif /* USE_STACKCHECK */ - /* Deprecated C API functions still provided for binary compatiblity */ #undef PyParser_SimpleParseFile -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 22 06:37:43 2014 From: python-checkins at python.org (zach.ware) Date: Sat, 22 Nov 2014 05:37:43 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2322869=3A_Move_Py?= =?utf-8?q?OS=5FCheckStack_back_to_pythonrun=2Ec?= Message-ID: <20141122053743.116326.88978@psf.io> https://hg.python.org/cpython/rev/406965684327 changeset: 93534:406965684327 user: Zachary Ware date: Fri Nov 21 23:35:12 2014 -0600 summary: Closes #22869: Move PyOS_CheckStack back to pythonrun.c files: Python/pylifecycle.c | 38 -------------------------------- Python/pythonrun.c | 37 +++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1431,44 +1431,6 @@ } -#if defined(USE_STACKCHECK) -#if defined(WIN32) && defined(_MSC_VER) - -/* Stack checking for Microsoft C */ - -#include -#include - -/* - * Return non-zero when we run out of memory on the stack; zero otherwise. - */ -int -PyOS_CheckStack(void) -{ - __try { - /* alloca throws a stack overflow exception if there's - not enough space left on the stack */ - alloca(PYOS_STACK_MARGIN * sizeof(void*)); - return 0; - } __except (GetExceptionCode() == STATUS_STACK_OVERFLOW ? - EXCEPTION_EXECUTE_HANDLER : - EXCEPTION_CONTINUE_SEARCH) { - int errcode = _resetstkoflw(); - if (errcode == 0) - { - Py_FatalError("Could not reset the stack!"); - } - } - return 1; -} - -#endif /* WIN32 && _MSC_VER */ - -/* Alternate implementations can be added here... */ - -#endif /* USE_STACKCHECK */ - - /* Wrappers around sigaction() or signal(). */ PyOS_sighandler_t diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1376,6 +1376,43 @@ } +#if defined(USE_STACKCHECK) +#if defined(WIN32) && defined(_MSC_VER) + +/* Stack checking for Microsoft C */ + +#include +#include + +/* + * Return non-zero when we run out of memory on the stack; zero otherwise. + */ +int +PyOS_CheckStack(void) +{ + __try { + /* alloca throws a stack overflow exception if there's + not enough space left on the stack */ + alloca(PYOS_STACK_MARGIN * sizeof(void*)); + return 0; + } __except (GetExceptionCode() == STATUS_STACK_OVERFLOW ? + EXCEPTION_EXECUTE_HANDLER : + EXCEPTION_CONTINUE_SEARCH) { + int errcode = _resetstkoflw(); + if (errcode == 0) + { + Py_FatalError("Could not reset the stack!"); + } + } + return 1; +} + +#endif /* WIN32 && _MSC_VER */ + +/* Alternate implementations can be added here... */ + +#endif /* USE_STACKCHECK */ + /* Deprecated C API functions still provided for binary compatiblity */ #undef PyParser_SimpleParseFile -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Sat Nov 22 10:32:16 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 22 Nov 2014 10:32:16 +0100 Subject: [Python-checkins] Daily reference leaks (8f77f7bb46c7): sum=3 Message-ID: results for 8f77f7bb46c7 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog6Lg9_j', '-x'] From python-checkins at python.org Sat Nov 22 18:04:40 2014 From: python-checkins at python.org (zach.ware) Date: Sat, 22 Nov 2014 17:04:40 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322834=3A_cwd_can?= =?utf-8?q?=27t_not_exist_on_Windows=2C_skip_the_test?= Message-ID: <20141122170432.116332.62590@psf.io> https://hg.python.org/cpython/rev/d065e6474b67 changeset: 93535:d065e6474b67 user: Zachary Ware date: Sat Nov 22 17:03:46 2014 -0600 summary: Issue #22834: cwd can't not exist on Windows, skip the test files: Lib/test/test_importlib/import_/test_path.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_importlib/import_/test_path.py b/Lib/test/test_importlib/import_/test_path.py --- a/Lib/test/test_importlib/import_/test_path.py +++ b/Lib/test/test_importlib/import_/test_path.py @@ -159,6 +159,7 @@ got = self.machinery.PathFinder.find_spec('whatever', [path]) self.assertEqual(got, success_finder.spec) + @unittest.skipIf(sys.platform == 'win32', "cwd can't not exist on Windows") def test_deleted_cwd(self): # Issue #22834 self.addCleanup(os.chdir, os.getcwd()) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 22 23:27:14 2014 From: python-checkins at python.org (ned.deily) Date: Sat, 22 Nov 2014 22:27:14 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Add_downloads_?= =?utf-8?q?page_link_to_OS_X_installer_README_screens=2E?= Message-ID: <20141122222714.69781.15723@psf.io> https://hg.python.org/cpython/rev/4f335a16871e changeset: 93536:4f335a16871e branch: 2.7 parent: 93530:301d62ef5c0b user: Ned Deily date: Sat Nov 22 14:17:05 2014 -0800 summary: Add downloads page link to OS X installer README screens. files: Mac/BuildScript/resources/ReadMe.txt | 3 ++- Mac/BuildScript/resources/readme.rtf | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Mac/BuildScript/resources/ReadMe.txt b/Mac/BuildScript/resources/ReadMe.txt --- a/Mac/BuildScript/resources/ReadMe.txt +++ b/Mac/BuildScript/resources/ReadMe.txt @@ -25,7 +25,8 @@ [NEW for Python 2.7.9] ============================= -The Python installer now includes an option to automatically install or upgrade pip, a tool for installing and managing Python packages. This option is enabled by default and no Internet access is required. If you do not want the installer to do this, select the Customize option at the Installation Type step and uncheck the Install or ugprade pip option. +The Python installer now includes an option to automatically install or upgrade pip, a tool for installing and managing Python packages. This option is enabled by default and no Internet access is required. If you do not want the installer to do this, select the Customize option at the Installation Type step and uncheck the Install or ugprade pip option. For other changes in this +release, see the Release Notes link for this release at https://www.python.org/downloads/. ============================= Binary installer support for OS X 10.4 and 10.3.9 discontinued diff --git a/Mac/BuildScript/resources/readme.rtf b/Mac/BuildScript/resources/readme.rtf --- a/Mac/BuildScript/resources/readme.rtf +++ b/Mac/BuildScript/resources/readme.rtf @@ -1,4 +1,4 @@ -{\rtf1\ansi\ansicpg1252\cocoartf1343\cocoasubrtf140 +{\rtf1\ansi\ansicpg1252\cocoartf1343\cocoasubrtf160 {\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fmodern\fcharset0 CourierNewPSMT;} {\colortbl;\red255\green255\blue255;} \margl1440\margr1440\vieww15240\viewh15540\viewkind0 @@ -50,7 +50,9 @@ \i Installation Type \i0 step and uncheck the \i Install or ugprade pip -\i0 option.\ +\i0 option. For other changes in this release, see the +\i Release Notes +\i0 link for this release at {\field{\*\fldinst{HYPERLINK "https://www.python.org/downloads/"}}{\fldrslt https://www.python.org/downloads/}}.\ \ \b \ul Binary installer support for OS X 10.4 and 10.3.9 discontinued\ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 22 23:27:19 2014 From: python-checkins at python.org (ned.deily) Date: Sat, 22 Nov 2014 22:27:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Add_downloads_page_link_to_OS_X_installer_README_screens?= =?utf-8?q?=2E?= Message-ID: <20141122222718.55103.73367@psf.io> https://hg.python.org/cpython/rev/25037b214e1d changeset: 93538:25037b214e1d parent: 93535:d065e6474b67 parent: 93537:7d1bd8eed59e user: Ned Deily date: Sat Nov 22 14:26:33 2014 -0800 summary: Add downloads page link to OS X installer README screens. files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 22 23:27:19 2014 From: python-checkins at python.org (ned.deily) Date: Sat, 22 Nov 2014 22:27:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Add_downloads_?= =?utf-8?q?page_link_to_OS_X_installer_README_screens=2E?= Message-ID: <20141122222716.69791.66969@psf.io> https://hg.python.org/cpython/rev/7d1bd8eed59e changeset: 93537:7d1bd8eed59e branch: 3.4 parent: 93531:97ceab0bd6f8 user: Ned Deily date: Sat Nov 22 14:20:30 2014 -0800 summary: Add downloads page link to OS X installer README screens. files: Mac/BuildScript/resources/ReadMe.txt | 2 ++ Mac/BuildScript/resources/readme.rtf | 15 +++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Mac/BuildScript/resources/ReadMe.txt b/Mac/BuildScript/resources/ReadMe.txt --- a/Mac/BuildScript/resources/ReadMe.txt +++ b/Mac/BuildScript/resources/ReadMe.txt @@ -29,6 +29,8 @@ To make it easier to use scripts installed by third-party Python packages, with pip or by other means, the Shell profile updater option is now enabled by default, as has been the case with Python 2.7.x installers. You can also turn this option off by selecting Customize and unchecking the Shell profile updater option. You can also update your shell profile later by launching the Update Shell Profile command found in the /Applications/Python $VERSION folder. You may need to start a new terminal window for the changes to take effect. +For other changes in this release, see the Release Notes link for this release at https://www.python.org/downloads/. + ============================= Python 3 and Python 2 Co-existence ============================= diff --git a/Mac/BuildScript/resources/readme.rtf b/Mac/BuildScript/resources/readme.rtf --- a/Mac/BuildScript/resources/readme.rtf +++ b/Mac/BuildScript/resources/readme.rtf @@ -1,7 +1,7 @@ -{\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf210 +{\rtf1\ansi\ansicpg1252\cocoartf1343\cocoasubrtf160 {\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fmodern\fcharset0 CourierNewPSMT;} {\colortbl;\red255\green255\blue255;} -\margl1440\margr1440\vieww13020\viewh15160\viewkind0 +\margl1440\margr1440\vieww13380\viewh14600\viewkind0 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural \f0\fs24 \cf0 This package will install Python $FULL_VERSION for Mac OS X $MACOSX_DEPLOYMENT_TARGET for the following architecture(s): $ARCHITECTURES.\ @@ -41,8 +41,7 @@ \b \cf0 \ul \ulc0 New Installation Options and Defaults\ \ulnone [NEW for Python 3.4.0] \b0 \ -\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural -\cf0 \ +\ The Python installer now includes an option to automatically install or upgrade \f1 pip \f0 , a tool for installing and managing Python packages. This option is enabled by default and no Internet access is required. If you do not want the installer to do this, select the @@ -67,12 +66,12 @@ \f1 /Applications/Python $VERSION \f0 folder. You may need to start a new terminal window for the changes to take effect.\ \ -\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural +For other changes in this release, see the Release Notes link for this release at {\field{\*\fldinst{HYPERLINK "https://www.python.org/downloads/"}}{\fldrslt https://www.python.org/downloads/}}.\ +\ -\b \cf0 \ul \ulc0 Python 3 and Python 2 Co-existence\ -\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural +\b \ul Python 3 and Python 2 Co-existence\ -\b0 \cf0 \ulnone \ +\b0 \ulnone \ Python.org Python $VERSION and 2.7.x versions can both be installed on your system and will not conflict. Command names for Python 3 contain a 3 in them, \f1 python3 \f0 (or -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 22 23:41:54 2014 From: python-checkins at python.org (ned.deily) Date: Sat, 22 Nov 2014 22:41:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Really_add_downloads_page_?= =?utf-8?q?link_to_OS_X_installer_README_screens=2E?= Message-ID: <20141122224152.69775.78793@psf.io> https://hg.python.org/cpython/rev/23f8a511050a changeset: 93540:23f8a511050a parent: 93538:25037b214e1d user: Ned Deily date: Sat Nov 22 14:41:21 2014 -0800 summary: Really add downloads page link to OS X installer README screens. files: Mac/BuildScript/resources/ReadMe.txt | 6 ++++++ Mac/BuildScript/resources/readme.rtf | 10 +++++++++- 2 files changed, 15 insertions(+), 1 deletions(-) diff --git a/Mac/BuildScript/resources/ReadMe.txt b/Mac/BuildScript/resources/ReadMe.txt --- a/Mac/BuildScript/resources/ReadMe.txt +++ b/Mac/BuildScript/resources/ReadMe.txt @@ -7,6 +7,12 @@ To use IDLE or other programs that use the Tkinter graphical user interface toolkit, you need to install a newer third-party version of the Tcl/Tk frameworks. Visit https://www.python.org/download/mac/tcltk/ for current information about supported and recommended versions of Tcl/Tk for this version of Python and of Mac OS X. ============================= +New Installation Options and Defaults +============================= + +For other changes in this release, see the Release Notes link for this release at https://www.python.org/downloads/. + +============================= Python 3 and Python 2 Co-existence ============================= diff --git a/Mac/BuildScript/resources/readme.rtf b/Mac/BuildScript/resources/readme.rtf --- a/Mac/BuildScript/resources/readme.rtf +++ b/Mac/BuildScript/resources/readme.rtf @@ -1,4 +1,4 @@ -{\rtf1\ansi\ansicpg1252\cocoartf1343\cocoasubrtf140 +{\rtf1\ansi\ansicpg1252\cocoartf1343\cocoasubrtf160 {\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fmodern\fcharset0 CourierNewPSMT;} {\colortbl;\red255\green255\blue255;} \margl1440\margr1440\vieww13020\viewh15160\viewkind0 @@ -18,6 +18,14 @@ \b \ul \ \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural +\cf0 \ulc0 New Installation Options and Defaults\ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural +\cf0 \ulc0 \ + +\b0 \ulnone For other changes in this release, see the Release Notes link for this release at {\field{\*\fldinst{HYPERLINK "https://www.python.org/downloads/"}}{\fldrslt https://www.python.org/downloads/}}.\ + +\b \ul \ +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural \cf0 \ulc0 Python 3 and Python 2 Co-existence\ \b0 \ulnone \ -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 22 23:41:54 2014 From: python-checkins at python.org (ned.deily) Date: Sat, 22 Nov 2014 22:41:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Remove_line_br?= =?utf-8?q?eaks_in_OS_X_installer_README_screen=2E?= Message-ID: <20141122224152.55103.9862@psf.io> https://hg.python.org/cpython/rev/b171834c63e7 changeset: 93539:b171834c63e7 branch: 2.7 parent: 93536:4f335a16871e user: Ned Deily date: Sat Nov 22 14:35:43 2014 -0800 summary: Remove line breaks in OS X installer README screen. files: Mac/BuildScript/resources/ReadMe.txt | 18 ++------------- 1 files changed, 3 insertions(+), 15 deletions(-) diff --git a/Mac/BuildScript/resources/ReadMe.txt b/Mac/BuildScript/resources/ReadMe.txt --- a/Mac/BuildScript/resources/ReadMe.txt +++ b/Mac/BuildScript/resources/ReadMe.txt @@ -25,29 +25,17 @@ [NEW for Python 2.7.9] ============================= -The Python installer now includes an option to automatically install or upgrade pip, a tool for installing and managing Python packages. This option is enabled by default and no Internet access is required. If you do not want the installer to do this, select the Customize option at the Installation Type step and uncheck the Install or ugprade pip option. For other changes in this -release, see the Release Notes link for this release at https://www.python.org/downloads/. +The Python installer now includes an option to automatically install or upgrade pip, a tool for installing and managing Python packages. This option is enabled by default and no Internet access is required. If you do not want the installer to do this, select the Customize option at the Installation Type step and uncheck the Install or ugprade pip option. For other changes in this release, see the Release Notes link for this release at https://www.python.org/downloads/. ============================= Binary installer support for OS X 10.4 and 10.3.9 discontinued [CHANGED for Python 2.7.9] ============================= -As previously announced, binary installers for Python 2.7.9 from python.org -no longer support Mac OS X 10.3.9 (Panther) and 10.4.x (Tiger) systems. -These systems were last updated by Apple in 2005 and 2007. As of 2.7.9, the -32-bit-only installer supports PPC and Intel Macs running OS X 10.5 (Leopard). -10.5 was the last OS X release for PPC machines (G4 and G5). The 64-/32-bit -installer configuration remains unchanged and should normally be used on OS X -10.6 (Snow Leopard) and later systems. This aligns Python 2.7.x installer -configurations with those currently provided with Python 3.x. If needed, -it is still possible to build Python from source for 10.3.9 and 10.4. +As previously announced, binary installers for Python 2.7.9 from python.org no longer support Mac OS X 10.3.9 (Panther) and 10.4.x (Tiger) systems. These systems were last updated by Apple in 2005 and 2007. As of 2.7.9, the 32-bit-only installer supports PPC and Intel Macs running OS X 10.5 (Leopard). 10.5 was the last OS X release for PPC machines (G4 and G5). The 64-/32-bit installer configuration remains unchanged and should normally be used on OS X 10.6 (Snow Leopard) and later systems. This aligns Python 2.7.x installer configurations with those currently provided with Python 3.x. If needed, it is still possible to build Python from source for 10.3.9 and 10.4. ============================= Python 3 and Python 2 Co-existence ============================= -Python.org Python 2.7 and 3.x versions can both be installed on your system and -will not conflict. Python 2 command names contain a 2 or no digit: python2 (or -python2.7 or python), idle2 (or idle2.7 or idle), pip2 (or pip2.7 or pip), etc. -Command names for Python 3 contain a 3 in them: python3, idle3, pip3, etc. +Python.org Python 2.7 and 3.x versions can both be installed on your system and will not conflict. Python 2 command names contain a 2 or no digit: python2 (or python2.7 or python), idle2 (or idle2.7 or idle), pip2 (or pip2.7 or pip), etc. Command names for Python 3 contain a 3 in them: python3, idle3, pip3, etc. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 23 01:04:45 2014 From: python-checkins at python.org (ned.deily) Date: Sun, 23 Nov 2014 00:04:45 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fix_2to3_refer?= =?utf-8?q?ence_link_in_pyporting=2Erst=2E?= Message-ID: <20141123000439.69777.28845@psf.io> https://hg.python.org/cpython/rev/414332e55f6c changeset: 93541:414332e55f6c branch: 2.7 parent: 93539:b171834c63e7 user: Ned Deily date: Sat Nov 22 16:03:40 2014 -0800 summary: Fix 2to3 reference link in pyporting.rst. files: Doc/howto/pyporting.rst | 7 +++---- 1 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Doc/howto/pyporting.rst b/Doc/howto/pyporting.rst --- a/Doc/howto/pyporting.rst +++ b/Doc/howto/pyporting.rst @@ -565,10 +565,9 @@ --------------------------------------------------------- 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. +code, then you can use :ref:`2to3 <2to3-reference>` 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. Backporting Python 3 code to Python 2 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 23 06:56:38 2014 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 23 Nov 2014 05:56:38 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_PEP_479=3A__Don=27t_let_St?= =?utf-8?q?opIteration_bubble_out_of_calls_to_next=28=29_inside_a?= Message-ID: <20141123055630.84289.59648@psf.io> https://hg.python.org/cpython/rev/9eb0d0eb0992 changeset: 93542:9eb0d0eb0992 parent: 93540:23f8a511050a user: Raymond Hettinger date: Sat Nov 22 21:56:23 2014 -0800 summary: PEP 479: Don't let StopIteration bubble out of calls to next() inside a generator. files: Doc/library/itertools.rst | 20 ++++++++++++++++---- Lib/xml/etree/ElementPath.py | 15 ++++++++++++--- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -104,7 +104,10 @@ # accumulate([1,2,3,4,5]) --> 1 3 6 10 15 # accumulate([1,2,3,4,5], operator.mul) --> 1 2 6 24 120 it = iter(iterable) - total = next(it) + try: + total = next(it) + except StopIteration: + return yield total for element in it: total = func(total, element) @@ -405,7 +408,10 @@ def _grouper(self, tgtkey): while self.currkey == tgtkey: yield self.currvalue - self.currvalue = next(self.it) # Exit on StopIteration + try: + self.currvalue = next(self.it) + except StopIteration: + return self.currkey = self.keyfunc(self.currvalue) @@ -429,7 +435,10 @@ # islice('ABCDEFG', 0, None, 2) --> A C E G s = slice(*args) it = iter(range(s.start or 0, s.stop or sys.maxsize, s.step or 1)) - nexti = next(it) + try: + nexti = next(it) + except StopIteration: + return for i, element in enumerate(iterable): if i == nexti: yield element @@ -587,7 +596,10 @@ def gen(mydeque): while True: if not mydeque: # when the local deque is empty - newval = next(it) # fetch a new value and + try: + newval = next(it) # fetch a new value and + except StopIteration: + return for d in deques: # load it to all the deques d.append(newval) yield mydeque.popleft() diff --git a/Lib/xml/etree/ElementPath.py b/Lib/xml/etree/ElementPath.py --- a/Lib/xml/etree/ElementPath.py +++ b/Lib/xml/etree/ElementPath.py @@ -114,7 +114,10 @@ return select def prepare_descendant(next, token): - token = next() + try: + token = next() + except StopIteration: + return if token[0] == "*": tag = "*" elif not token[0]: @@ -148,7 +151,10 @@ signature = [] predicate = [] while 1: - token = next() + try: + token = next() + except StopIteration: + return if token[0] == "]": break if token[0] and token[0][:1] in "'\"": @@ -261,7 +267,10 @@ if path[:1] == "/": raise SyntaxError("cannot use absolute path on element") next = iter(xpath_tokenizer(path, namespaces)).__next__ - token = next() + try: + token = next() + except StopIteration: + return selector = [] while 1: try: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 23 07:14:48 2014 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 23 Nov 2014 06:14:48 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_PEP_479=3A__Use_the_return?= =?utf-8?q?-keyword_instead_of_raising_StopIteration_inside_a?= Message-ID: <20141123061447.84279.4879@psf.io> https://hg.python.org/cpython/rev/e8b3083bb148 changeset: 93543:e8b3083bb148 user: Raymond Hettinger date: Sat Nov 22 22:14:41 2014 -0800 summary: PEP 479: Use the return-keyword instead of raising StopIteration inside a generators. files: Lib/ipaddress.py | 2 +- Lib/mailbox.py | 2 +- Lib/test/test_buffer.py | 2 +- Lib/test/test_collections.py | 2 +- Lib/test/test_itertools.py | 2 -- Lib/test/test_sys_setprofile.py | 1 - 6 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -808,7 +808,7 @@ other.broadcast_address <= self.broadcast_address): raise ValueError('%s not contained in %s' % (other, self)) if other == self: - raise StopIteration + return # Make sure we're comparing the network of other. other = other.__class__('%s/%s' % (other.network_address, diff --git a/Lib/mailbox.py b/Lib/mailbox.py --- a/Lib/mailbox.py +++ b/Lib/mailbox.py @@ -1949,7 +1949,7 @@ while True: line = self.readline() if not line: - raise StopIteration + return yield line def tell(self): diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -216,7 +216,7 @@ for t in iter_mode(nitems, testobj): yield t if testobj != 'ndarray': - raise StopIteration + return yield struct_items(nitems, testobj) diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -511,7 +511,7 @@ class NextOnly: def __next__(self): yield 1 - raise StopIteration + return self.assertNotIsInstance(NextOnly(), Iterator) def test_Sized(self): diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -1803,8 +1803,6 @@ hist.append(3) yield 2 hist.append(4) - if x: - raise StopIteration hist = [] self.assertRaises(AssertionError, list, chain(gen1(), gen2(False))) diff --git a/Lib/test/test_sys_setprofile.py b/Lib/test/test_sys_setprofile.py --- a/Lib/test/test_sys_setprofile.py +++ b/Lib/test/test_sys_setprofile.py @@ -260,7 +260,6 @@ def f(): for i in range(2): yield i - raise StopIteration def g(p): for i in f(): pass -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Sun Nov 23 10:34:12 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 23 Nov 2014 10:34:12 +0100 Subject: [Python-checkins] Daily reference leaks (23f8a511050a): sum=3 Message-ID: results for 23f8a511050a on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogFDz2UQ', '-x'] From python-checkins at python.org Sun Nov 23 15:50:40 2014 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 23 Nov 2014 14:50:40 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Null_merge?= Message-ID: <20141123145039.84295.54126@psf.io> https://hg.python.org/cpython/rev/334659e8a625 changeset: 93545:334659e8a625 parent: 93543:e8b3083bb148 parent: 93544:653dfb1240d5 user: Antoine Pitrou date: Sun Nov 23 15:50:21 2014 +0100 summary: Null merge files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 23 15:50:40 2014 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 23 Nov 2014 14:50:40 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyNjM4?= =?utf-8?q?=3A_SSLv3_is_now_disabled_throughout_the_standard_library=2E?= Message-ID: <20141123145039.84283.5766@psf.io> https://hg.python.org/cpython/rev/653dfb1240d5 changeset: 93544:653dfb1240d5 branch: 3.4 parent: 93537:7d1bd8eed59e user: Antoine Pitrou date: Fri Oct 17 19:28:30 2014 +0200 summary: Issue #22638: SSLv3 is now disabled throughout the standard library. It can still be enabled by instantiating a SSLContext manually. files: Lib/ssl.py | 3 +++ Misc/NEWS | 3 +++ 2 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -458,6 +458,9 @@ context = SSLContext(protocol) # SSLv2 considered harmful. context.options |= OP_NO_SSLv2 + # SSLv3 has problematic security and is only required for really old + # clients such as IE6 on Windows XP + context.options |= OP_NO_SSLv3 if cert_reqs is not None: context.verify_mode = cert_reqs diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,9 @@ Library ------- +- Issue #22638: SSLv3 is now disabled throughout the standard library. + It can still be enabled by instantiating a SSLContext manually. + - Issue #22370: Windows detection in pathlib is now more robust. - Issue #22841: Reject coroutines in asyncio add_signal_handler(). -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 23 16:01:30 2014 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 23 Nov 2014 15:01:30 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322894=3A_TestCase=2EsubTest=28=29_would_cause_t?= =?utf-8?q?he_test_suite_to_be_stopped_when?= Message-ID: <20141123150128.84299.90937@psf.io> https://hg.python.org/cpython/rev/04103cece49d changeset: 93547:04103cece49d parent: 93545:334659e8a625 parent: 93546:993e8f795194 user: Antoine Pitrou date: Sun Nov 23 15:56:41 2014 +0100 summary: Issue #22894: TestCase.subTest() would cause the test suite to be stopped when in failfast mode, even in the absence of failures. files: Lib/unittest/result.py | 3 +- Lib/unittest/test/test_case.py | 28 ++++++++++++++++++++++ Misc/NEWS | 3 ++ 3 files changed, 33 insertions(+), 1 deletions(-) diff --git a/Lib/unittest/result.py b/Lib/unittest/result.py --- a/Lib/unittest/result.py +++ b/Lib/unittest/result.py @@ -121,7 +121,6 @@ self.failures.append((test, self._exc_info_to_string(err, test))) self._mirrorOutput = True - @failfast def addSubTest(self, test, subtest, err): """Called at the end of a subtest. 'err' is None if the subtest ended successfully, otherwise it's a @@ -130,6 +129,8 @@ # By default, we don't do anything with successful subtests, but # more sophisticated test results might want to record them. if err is not None: + if getattr(self, 'failfast', False): + self.stop() if issubclass(err[0], test.failureException): errors = self.failures else: diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py --- a/Lib/unittest/test/test_case.py +++ b/Lib/unittest/test/test_case.py @@ -397,6 +397,34 @@ Foo(events).run(result) self.assertEqual(events, expected) + def test_subtests_failfast(self): + # Ensure proper test flow with subtests and failfast (issue #22894) + events = [] + + class Foo(unittest.TestCase): + def test_a(self): + with self.subTest(): + events.append('a1') + events.append('a2') + + def test_b(self): + with self.subTest(): + events.append('b1') + with self.subTest(): + self.fail('failure') + events.append('b2') + + def test_c(self): + events.append('c') + + result = unittest.TestResult() + result.failfast = True + suite = unittest.makeSuite(Foo) + suite.run(result) + + expected = ['a1', 'a2', 'b1'] + self.assertEqual(events, expected) + # "This class attribute gives the exception raised by the test() method. # If a test framework needs to use a specialized exception, possibly to # carry additional information, it must subclass this exception in diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -191,6 +191,9 @@ Library ------- +- Issue #22894: TestCase.subTest() would cause the test suite to be stopped + when in failfast mode, even in the absence of failures. + - Issue #22796: HTTP cookie parsing is now stricter, in order to protect against potential injection attacks. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 23 16:01:30 2014 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 23 Nov 2014 15:01:30 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyODk0?= =?utf-8?q?=3A_TestCase=2EsubTest=28=29_would_cause_the_test_suite_to_be_s?= =?utf-8?q?topped_when?= Message-ID: <20141123150128.116320.52021@psf.io> https://hg.python.org/cpython/rev/993e8f795194 changeset: 93546:993e8f795194 branch: 3.4 parent: 93544:653dfb1240d5 user: Antoine Pitrou date: Sun Nov 23 15:55:11 2014 +0100 summary: Issue #22894: TestCase.subTest() would cause the test suite to be stopped when in failfast mode, even in the absence of failures. files: Lib/unittest/result.py | 3 +- Lib/unittest/test/test_case.py | 28 ++++++++++++++++++++++ Misc/NEWS | 3 ++ 3 files changed, 33 insertions(+), 1 deletions(-) diff --git a/Lib/unittest/result.py b/Lib/unittest/result.py --- a/Lib/unittest/result.py +++ b/Lib/unittest/result.py @@ -121,7 +121,6 @@ self.failures.append((test, self._exc_info_to_string(err, test))) self._mirrorOutput = True - @failfast def addSubTest(self, test, subtest, err): """Called at the end of a subtest. 'err' is None if the subtest ended successfully, otherwise it's a @@ -130,6 +129,8 @@ # By default, we don't do anything with successful subtests, but # more sophisticated test results might want to record them. if err is not None: + if getattr(self, 'failfast', False): + self.stop() if issubclass(err[0], test.failureException): errors = self.failures else: diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py --- a/Lib/unittest/test/test_case.py +++ b/Lib/unittest/test/test_case.py @@ -397,6 +397,34 @@ Foo(events).run(result) self.assertEqual(events, expected) + def test_subtests_failfast(self): + # Ensure proper test flow with subtests and failfast (issue #22894) + events = [] + + class Foo(unittest.TestCase): + def test_a(self): + with self.subTest(): + events.append('a1') + events.append('a2') + + def test_b(self): + with self.subTest(): + events.append('b1') + with self.subTest(): + self.fail('failure') + events.append('b2') + + def test_c(self): + events.append('c') + + result = unittest.TestResult() + result.failfast = True + suite = unittest.makeSuite(Foo) + suite.run(result) + + expected = ['a1', 'a2', 'b1'] + self.assertEqual(events, expected) + # "This class attribute gives the exception raised by the test() method. # If a test framework needs to use a specialized exception, possibly to # carry additional information, it must subclass this exception in diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,9 @@ Library ------- +- Issue #22894: TestCase.subTest() would cause the test suite to be stopped + when in failfast mode, even in the absence of failures. + - Issue #22638: SSLv3 is now disabled throughout the standard library. It can still be enabled by instantiating a SSLContext manually. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 23 16:01:30 2014 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 23 Nov 2014 15:01:30 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Update_importlib=2Eh?= Message-ID: <20141123150128.69795.80190@psf.io> https://hg.python.org/cpython/rev/dfe7d9fee0b5 changeset: 93548:dfe7d9fee0b5 user: Antoine Pitrou date: Sun Nov 23 16:01:20 2014 +0100 summary: Update importlib.h files: Python/importlib.h | 860 ++++++++++++++++---------------- 1 files changed, 430 insertions(+), 430 deletions(-) diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 23 16:26:30 2014 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 23 Nov 2014 15:26:30 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Backport_disab?= =?utf-8?q?ling_of_SSLv3_in_ssl=2E=5Fcreate=5Fstdlib=5Fcontext=28=29_=28is?= =?utf-8?b?c3VlICMyMjYzOCku?= Message-ID: <20141123152629.84281.55327@psf.io> https://hg.python.org/cpython/rev/f762cbb712de changeset: 93549:f762cbb712de branch: 2.7 parent: 93541:414332e55f6c user: Antoine Pitrou date: Fri Oct 17 19:28:30 2014 +0200 summary: Backport disabling of SSLv3 in ssl._create_stdlib_context() (issue #22638). The backport currently doesn't achieve anything since the function isn't used (yet). files: Lib/ssl.py | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -445,6 +445,9 @@ context = SSLContext(protocol) # SSLv2 considered harmful. context.options |= OP_NO_SSLv2 + # SSLv3 has problematic security and is only required for really old + # clients such as IE6 on Windows XP + context.options |= OP_NO_SSLv3 if cert_reqs is not None: context.verify_mode = cert_reqs -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 23 18:46:28 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 23 Nov 2014 17:46:28 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogaW5pdGlhbGl6ZSBf?= =?utf-8?q?makefile=5Frefs_earlier_so_things_don=27t_blow_up_when_close=28?= =?utf-8?q?=29_is?= Message-ID: <20141123174628.84295.16860@psf.io> https://hg.python.org/cpython/rev/588ebc8fd3da changeset: 93550:588ebc8fd3da branch: 2.7 user: Benjamin Peterson date: Sun Nov 23 11:16:48 2014 -0600 summary: initialize _makefile_refs earlier so things don't blow up when close() is called in the constructor files: Lib/ssl.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -483,6 +483,7 @@ server_hostname=None, _context=None): + self._makefile_refs = 0 if _context: self._context = _context else: @@ -565,7 +566,6 @@ except (OSError, ValueError): self.close() raise - self._makefile_refs = 0 @property def context(self): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 23 18:46:28 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 23 Nov 2014 17:46:28 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20141123174628.84287.23211@psf.io> https://hg.python.org/cpython/rev/ebfb966c8979 changeset: 93552:ebfb966c8979 parent: 93548:dfe7d9fee0b5 parent: 93551:3cc8b7227db4 user: Benjamin Peterson date: Sun Nov 23 11:43:43 2014 -0600 summary: merge 3.4 files: Doc/library/urllib.request.rst | 5 +---- 1 files changed, 1 insertions(+), 4 deletions(-) diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -57,10 +57,7 @@ point to a directory of hashed certificate files. More information can be found in :meth:`ssl.SSLContext.load_verify_locations`. - The *cadefault* parameter specifies whether to fall back to loading a - default certificate store defined by the underlying OpenSSL library if the - *cafile* and *capath* parameters are omitted. This will only work on - some non-Windows platforms. + The *cadefault* parameter is ignored. For http and https urls, this function returns a :class:`http.client.HTTPResponse` object which has the following -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 23 18:46:29 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 23 Nov 2014 17:46:29 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_document_that_?= =?utf-8?q?cadefault_does_nothing_now?= Message-ID: <20141123174628.55099.14448@psf.io> https://hg.python.org/cpython/rev/3cc8b7227db4 changeset: 93551:3cc8b7227db4 branch: 3.4 parent: 93546:993e8f795194 user: Benjamin Peterson date: Sun Nov 23 11:43:33 2014 -0600 summary: document that cadefault does nothing now files: Doc/library/urllib.request.rst | 5 +---- 1 files changed, 1 insertions(+), 4 deletions(-) diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -57,10 +57,7 @@ point to a directory of hashed certificate files. More information can be found in :meth:`ssl.SSLContext.load_verify_locations`. - The *cadefault* parameter specifies whether to fall back to loading a - default certificate store defined by the underlying OpenSSL library if the - *cafile* and *capath* parameters are omitted. This will only work on - some non-Windows platforms. + The *cadefault* parameter is ignored. For http and https urls, this function returns a :class:`http.client.HTTPResponse` object which has the following -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 23 18:46:29 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 23 Nov 2014 17:46:29 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_allow_passing_?= =?utf-8?q?cert/ssl_information_to_urllib2=2Eurlopen_and?= Message-ID: <20141123174628.84299.85124@psf.io> https://hg.python.org/cpython/rev/1882157b298a changeset: 93553:1882157b298a branch: 2.7 parent: 93550:588ebc8fd3da user: Benjamin Peterson date: Sun Nov 23 11:42:45 2014 -0600 summary: allow passing cert/ssl information to urllib2.urlopen and httplib.HTTPSConnection This is basically a backport of issues #9003 and #22366. files: Doc/library/httplib.rst | 24 +- Doc/library/urllib2.rst | 32 +- Lib/httplib.py | 35 ++- Lib/test/keycert2.pem | 31 ++ Lib/test/selfsigned_pythontestdotnet.pem | 16 + Lib/test/test_httplib.py | 158 +++++++++- Lib/test/test_ssl.py | 9 +- Lib/test/test_urllib2.py | 13 + Lib/test/test_urllib2_localnet.py | 59 ++++- Lib/urllib2.py | 48 ++- Misc/NEWS | 5 + 11 files changed, 378 insertions(+), 52 deletions(-) diff --git a/Doc/library/httplib.rst b/Doc/library/httplib.rst --- a/Doc/library/httplib.rst +++ b/Doc/library/httplib.rst @@ -70,12 +70,25 @@ *source_address* was added. -.. class:: HTTPSConnection(host[, port[, key_file[, cert_file[, strict[, timeout[, source_address]]]]]]) +.. class:: HTTPSConnection(host[, port[, key_file[, cert_file[, strict[, timeout[, source_address, context, check_hostname]]]]]]) A subclass of :class:`HTTPConnection` that uses SSL for communication with - secure servers. Default port is ``443``. *key_file* is the name of a PEM - formatted file that contains your private key. *cert_file* is a PEM formatted - certificate chain file. + secure servers. Default port is ``443``. If *context* is specified, it must + be a :class:`ssl.SSLContext` instance describing the various SSL options. + + *key_file* and *cert_file* are deprecated, please use + :meth:`ssl.SSLContext.load_cert_chain` instead, or let + :func:`ssl.create_default_context` select the system's trusted CA + certificates for you. + + Please read :ref:`ssl-security` for more information on best practices. + + .. note:: + If *context* is specified and has a :attr:`~ssl.SSLContext.verify_mode` + of either :data:`~ssl.CERT_OPTIONAL` or :data:`~ssl.CERT_REQUIRED`, then + by default *host* is matched against the host name(s) allowed by the + server's certificate. If you want to change that behaviour, you can + explicitly set *check_hostname* to False. .. warning:: This does not do any verification of the server's certificate. @@ -88,6 +101,9 @@ .. versionchanged:: 2.7 *source_address* was added. + .. versionchanged:: 2.7.9 + *context* and *check_hostname* was added. + .. class:: HTTPResponse(sock, debuglevel=0, strict=0) diff --git a/Doc/library/urllib2.rst b/Doc/library/urllib2.rst --- a/Doc/library/urllib2.rst +++ b/Doc/library/urllib2.rst @@ -22,13 +22,10 @@ The :mod:`urllib2` module defines the following functions: -.. function:: urlopen(url[, data][, timeout]) +.. function:: urlopen(url[, data[, timeout[, cafile[, capath[, cadefault[, context]]]]]) Open the URL *url*, which can be either a string or a :class:`Request` object. - .. warning:: - HTTPS requests do not do any verification of the server's certificate. - *data* may be a string specifying additional data to send to the server, or ``None`` if no such data is needed. Currently HTTP requests are the only ones that use *data*; the HTTP request will be a POST instead of a GET when the @@ -41,7 +38,19 @@ The optional *timeout* parameter specifies a timeout in seconds for blocking operations like the connection attempt (if not specified, the global default timeout setting will be used). This actually only works for HTTP, HTTPS and - FTP connections. + FTP connections. + + If *context* is specified, it must be a :class:`ssl.SSLContext` instance + describing the various SSL options. See :class:`~httplib.HTTPSConnection` for + more details. + + The optional *cafile* and *capath* parameters specify a set of trusted CA + certificates for HTTPS requests. *cafile* should point to a single file + containing a bundle of CA certificates, whereas *capath* should point to a + directory of hashed certificate files. More information can be found in + :meth:`ssl.SSLContext.load_verify_locations`. + + The *cadefault* parameter is ignored. This function returns a file-like object with three additional methods: @@ -66,7 +75,10 @@ handled through the proxy. .. versionchanged:: 2.6 - *timeout* was added. + *timeout* was added. + + .. versionchanged:: 2.7.9 + *cafile*, *capath*, *cadefault*, and *context* were added. .. function:: install_opener(opener) @@ -280,9 +292,13 @@ A class to handle opening of HTTP URLs. -.. class:: HTTPSHandler() +.. class:: HTTPSHandler([debuglevel[, context[, check_hostname]]]) - A class to handle opening of HTTPS URLs. + A class to handle opening of HTTPS URLs. *context* and *check_hostname* have + the same meaning as for :class:`httplib.HTTPSConnection`. + + .. versionchanged:: 2.7.9 + *context* and *check_hostname* were added. .. class:: FileHandler() diff --git a/Lib/httplib.py b/Lib/httplib.py --- a/Lib/httplib.py +++ b/Lib/httplib.py @@ -1187,21 +1187,44 @@ def __init__(self, host, port=None, key_file=None, cert_file=None, strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, - source_address=None): + source_address=None, context=None, check_hostname=None): HTTPConnection.__init__(self, host, port, strict, timeout, source_address) self.key_file = key_file self.cert_file = cert_file + if context is None: + context = ssl.create_default_context() + will_verify = context.verify_mode != ssl.CERT_NONE + if check_hostname is None: + check_hostname = will_verify + elif check_hostname and not will_verify: + raise ValueError("check_hostname needs a SSL context with " + "either CERT_OPTIONAL or CERT_REQUIRED") + if key_file or cert_file: + context.load_cert_chain(cert_file, key_file) + self._context = context + self._check_hostname = check_hostname def connect(self): "Connect to a host on a given (SSL) port." - sock = self._create_connection((self.host, self.port), - self.timeout, self.source_address) + HTTPConnection.connect(self) + if self._tunnel_host: - self.sock = sock - self._tunnel() - self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file) + server_hostname = self._tunnel_host + else: + server_hostname = self.host + sni_hostname = server_hostname if ssl.HAS_SNI else None + + self.sock = self._context.wrap_socket(self.sock, + server_hostname=sni_hostname) + if not self._context.check_hostname and self._check_hostname: + try: + ssl.match_hostname(self.sock.getpeercert(), server_hostname) + except Exception: + self.sock.shutdown(socket.SHUT_RDWR) + self.sock.close() + raise __all__.append("HTTPSConnection") diff --git a/Lib/test/keycert2.pem b/Lib/test/keycert2.pem new file mode 100644 --- /dev/null +++ b/Lib/test/keycert2.pem @@ -0,0 +1,31 @@ +-----BEGIN PRIVATE KEY----- +MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANcLaMB7T/Wi9DBc +PltGzgt8cxsv55m7PQPHMZvn6Ke8xmNqcmEzib8opRwKGrCV6TltKeFlNSg8dwQK +Tl4ktyTkGCVweRQJ37AkBayvEBml5s+QD4vlhqkJPsL/Nsd+fnqngOGc5+59+C6r +s3XpiLlF5ah/z8q92Mnw54nypw1JAgMBAAECgYBE3t2Mj7GbDLZB6rj5yKJioVfI +BD6bSJEQ7bGgqdQkLFwpKMU7BiN+ekjuwvmrRkesYZ7BFgXBPiQrwhU5J28Tpj5B +EOMYSIOHfzdalhxDGM1q2oK9LDFiCotTaSdEzMYadel5rmKXJ0zcK2Jho0PCuECf +tf/ghRxK+h1Hm0tKgQJBAO6MdGDSmGKYX6/5kPDje7we/lSLorSDkYmV0tmVShsc +JxgaGaapazceA/sHL3Myx7Eenkip+yPYDXEDFvAKNDECQQDmxsT9NOp6mo7ISvky +GFr2vVHsJ745BMWoma4rFjPBVnS8RkgK+b2EpDCdZSrQ9zw2r8sKTgrEyrDiGTEg +wJyZAkA8OOc0flYMJg2aHnYR6kwVjPmGHI5h5gk648EMPx0rROs1sXkiUwkHLCOz +HvhCq+Iv+9vX2lnVjbiu/CmxRdIxAkA1YEfzoKeTD+hyXxTgB04Sv5sRGegfXAEz +i8gC4zG5R/vcCA1lrHmvEiLEZL/QcT6WD3bQvVg0SAU9ZkI8pxARAkA7yqMSvP1l +gJXy44R+rzpLYb1/PtiLkIkaKG3x9TUfPnfD2jY09fPkZlfsRU3/uS09IkhSwimV +d5rWoljEfdou +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIICXTCCAcagAwIBAgIJALVQzebTtrXFMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNV +BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u +IFNvZnR3YXJlIEZvdW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTAeFw0x +NDExMjMxNzAwMDdaFw0yNDExMjAxNzAwMDdaMGIxCzAJBgNVBAYTAlhZMRcwFQYD +VQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZv +dW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTCBnzANBgkqhkiG9w0BAQEF +AAOBjQAwgYkCgYEA1wtowHtP9aL0MFw+W0bOC3xzGy/nmbs9A8cxm+fop7zGY2py +YTOJvyilHAoasJXpOW0p4WU1KDx3BApOXiS3JOQYJXB5FAnfsCQFrK8QGaXmz5AP +i+WGqQk+wv82x35+eqeA4Zzn7n34LquzdemIuUXlqH/Pyr3YyfDnifKnDUkCAwEA +AaMbMBkwFwYDVR0RBBAwDoIMZmFrZWhvc3RuYW1lMA0GCSqGSIb3DQEBBQUAA4GB +AKuay3vDKfWzt5+ch/HHBsert84ISot4fUjzXDA/oOgTOEjVcSShHxqNShMOW1oA +QYBpBB/5Kx5RkD/w6imhucxt2WQPRgjX4x4bwMipVH/HvFDp03mG51/Cpi1TyZ74 +El7qa/Pd4lHhOLzMKBA6503fpeYSFUIBxZbGLqylqRK7 +-----END CERTIFICATE----- diff --git a/Lib/test/selfsigned_pythontestdotnet.pem b/Lib/test/selfsigned_pythontestdotnet.pem new file mode 100644 --- /dev/null +++ b/Lib/test/selfsigned_pythontestdotnet.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIIChzCCAfCgAwIBAgIJAKGU95wKR8pSMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV +BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u +IFNvZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMMGnNlbGYtc2lnbmVkLnB5dGhv +bnRlc3QubmV0MB4XDTE0MTEwMjE4MDkyOVoXDTI0MTAzMDE4MDkyOVowcDELMAkG +A1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRo +b24gU29mdHdhcmUgRm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0 +aG9udGVzdC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANDXQXW9tjyZ +Xt0Iv2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vm +Sv/yIvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALv +EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjKTAnMCUGA1UdEQQeMByCGnNl +bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MA0GCSqGSIb3DQEBBQUAA4GBAIOXmdtM +eG9qzP9TiXW/Gc/zI4cBfdCpC+Y4gOfC9bQUC7hefix4iO3+iZjgy3X/FaRxUUoV +HKiXcXIaWqTSUWp45cSh0MbwZXudp6JIAptzdAhvvCrPKeC9i9GvxsPD4LtDAL97 +vSaxQBezA7hdxZd90/EeyMgVZgAnTCnvAWX9 +-----END CERTIFICATE----- diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -1,6 +1,7 @@ import httplib import array import httplib +import os import StringIO import socket import errno @@ -10,6 +11,14 @@ from test import test_support +here = os.path.dirname(__file__) +# Self-signed cert file for 'localhost' +CERT_localhost = os.path.join(here, 'keycert.pem') +# Self-signed cert file for 'fakehostname' +CERT_fakehostname = os.path.join(here, 'keycert2.pem') +# Self-signed cert file for self-signed.pythontest.net +CERT_selfsigned_pythontestdotnet = os.path.join(here, 'selfsigned_pythontestdotnet.pem') + HOST = test_support.HOST class FakeSocket: @@ -506,36 +515,140 @@ self.assertEqual(httpConn.sock.gettimeout(), 30) httpConn.close() +class HTTPSTest(TestCase): -class HTTPSTimeoutTest(TestCase): -# XXX Here should be tests for HTTPS, there isn't any right now! + def setUp(self): + if not hasattr(httplib, 'HTTPSConnection'): + self.skipTest('ssl support required') + + def make_server(self, certfile): + from test.ssl_servers import make_https_server + return make_https_server(self, certfile=certfile) def test_attributes(self): - # simple test to check it's storing it - if hasattr(httplib, 'HTTPSConnection'): - h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30) - self.assertEqual(h.timeout, 30) + # simple test to check it's storing the timeout + h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30) + self.assertEqual(h.timeout, 30) - @unittest.skipIf(not hasattr(httplib, 'HTTPS'), 'httplib.HTTPS not available') + def test_networked(self): + # Default settings: requires a valid cert from a trusted CA + import ssl + test_support.requires('network') + with test_support.transient_internet('self-signed.pythontest.net'): + h = httplib.HTTPSConnection('self-signed.pythontest.net', 443) + with self.assertRaises(ssl.SSLError) as exc_info: + h.request('GET', '/') + self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') + + def test_networked_noverification(self): + # Switch off cert verification + import ssl + test_support.requires('network') + with test_support.transient_internet('self-signed.pythontest.net'): + context = ssl._create_stdlib_context() + h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, + context=context) + h.request('GET', '/') + resp = h.getresponse() + self.assertIn('nginx', resp.getheader('server')) + + def test_networked_trusted_by_default_cert(self): + # Default settings: requires a valid cert from a trusted CA + test_support.requires('network') + with test_support.transient_internet('www.python.org'): + h = httplib.HTTPSConnection('www.python.org', 443) + h.request('GET', '/') + resp = h.getresponse() + content_type = resp.getheader('content-type') + self.assertIn('text/html', content_type) + + def test_networked_good_cert(self): + # We feed the server's cert as a validating cert + import ssl + test_support.requires('network') + with test_support.transient_internet('self-signed.pythontest.net'): + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + context.verify_mode = ssl.CERT_REQUIRED + context.load_verify_locations(CERT_selfsigned_pythontestdotnet) + h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context) + h.request('GET', '/') + resp = h.getresponse() + server_string = resp.getheader('server') + self.assertIn('nginx', server_string) + + def test_networked_bad_cert(self): + # We feed a "CA" cert that is unrelated to the server's cert + import ssl + test_support.requires('network') + with test_support.transient_internet('self-signed.pythontest.net'): + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + context.verify_mode = ssl.CERT_REQUIRED + context.load_verify_locations(CERT_localhost) + h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context) + with self.assertRaises(ssl.SSLError) as exc_info: + h.request('GET', '/') + self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') + + def test_local_unknown_cert(self): + # The custom cert isn't known to the default trust bundle + import ssl + server = self.make_server(CERT_localhost) + h = httplib.HTTPSConnection('localhost', server.port) + with self.assertRaises(ssl.SSLError) as exc_info: + h.request('GET', '/') + self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') + + def test_local_good_hostname(self): + # The (valid) cert validates the HTTP hostname + import ssl + server = self.make_server(CERT_localhost) + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + context.verify_mode = ssl.CERT_REQUIRED + context.load_verify_locations(CERT_localhost) + h = httplib.HTTPSConnection('localhost', server.port, context=context) + h.request('GET', '/nonexistent') + resp = h.getresponse() + self.assertEqual(resp.status, 404) + + def test_local_bad_hostname(self): + # The (valid) cert doesn't validate the HTTP hostname + import ssl + server = self.make_server(CERT_fakehostname) + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + context.verify_mode = ssl.CERT_REQUIRED + context.load_verify_locations(CERT_fakehostname) + h = httplib.HTTPSConnection('localhost', server.port, context=context) + with self.assertRaises(ssl.CertificateError): + h.request('GET', '/') + # Same with explicit check_hostname=True + h = httplib.HTTPSConnection('localhost', server.port, context=context, + check_hostname=True) + with self.assertRaises(ssl.CertificateError): + h.request('GET', '/') + # With check_hostname=False, the mismatching is ignored + h = httplib.HTTPSConnection('localhost', server.port, context=context, + check_hostname=False) + h.request('GET', '/nonexistent') + resp = h.getresponse() + self.assertEqual(resp.status, 404) + def test_host_port(self): # Check invalid host_port - # Note that httplib does not accept user:password@ in the host-port. for hp in ("www.python.org:abc", "user:password at www.python.org"): - self.assertRaises(httplib.InvalidURL, httplib.HTTP, hp) + self.assertRaises(httplib.InvalidURL, httplib.HTTPSConnection, hp) - for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", "fe80::207:e9ff:fe9b", - 8000), - ("pypi.python.org:443", "pypi.python.org", 443), - ("pypi.python.org", "pypi.python.org", 443), - ("pypi.python.org:", "pypi.python.org", 443), - ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443)): - http = httplib.HTTPS(hp) - c = http._conn - if h != c.host: - self.fail("Host incorrectly parsed: %s != %s" % (h, c.host)) - if p != c.port: - self.fail("Port incorrectly parsed: %s != %s" % (p, c.host)) + for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", + "fe80::207:e9ff:fe9b", 8000), + ("www.python.org:443", "www.python.org", 443), + ("www.python.org:", "www.python.org", 443), + ("www.python.org", "www.python.org", 443), + ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443), + ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b", + 443)): + c = httplib.HTTPSConnection(hp) + self.assertEqual(h, c.host) + self.assertEqual(p, c.port) class TunnelTests(TestCase): @@ -577,9 +690,10 @@ self.assertTrue('Host: destination.com' in conn.sock.data) + at test_support.reap_threads def test_main(verbose=None): test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest, - HTTPSTimeoutTest, SourceAddressTest, TunnelTests) + HTTPSTest, SourceAddressTest, TunnelTests) if __name__ == '__main__': test_main() 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 @@ -14,7 +14,7 @@ import errno import pprint import tempfile -import urllib +import urllib2 import traceback import weakref import platform @@ -2388,10 +2388,11 @@ d1 = f.read() d2 = '' # now fetch the same data from the HTTPS server - url = 'https://%s:%d/%s' % ( - HOST, server.port, os.path.split(CERTFILE)[1]) + url = 'https://localhost:%d/%s' % ( + server.port, os.path.split(CERTFILE)[1]) + context = ssl.create_default_context(cafile=CERTFILE) with support.check_py3k_warnings(): - f = urllib.urlopen(url) + f = urllib2.urlopen(url, context=context) try: dlen = f.info().getheader("content-length") if dlen and (int(dlen) > 0): diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -8,6 +8,11 @@ import urllib2 from urllib2 import Request, OpenerDirector +try: + import ssl +except ImportError: + ssl = None + # XXX # Request # CacheFTPHandler (hard to write) @@ -47,6 +52,14 @@ for string, list in tests: self.assertEqual(urllib2.parse_http_list(string), list) + @unittest.skipUnless(ssl, "ssl module required") + def test_cafile_and_context(self): + context = ssl.create_default_context() + with self.assertRaises(ValueError): + urllib2.urlopen( + "https://localhost", cafile="/nonexistent/path", context=context + ) + def test_request_headers_dict(): """ 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,3 +1,4 @@ +import os import base64 import urlparse import urllib2 @@ -10,6 +11,17 @@ mimetools = test_support.import_module('mimetools', deprecated=True) threading = test_support.import_module('threading') +try: + import ssl +except ImportError: + ssl = None + +here = os.path.dirname(__file__) +# Self-signed cert file for 'localhost' +CERT_localhost = os.path.join(here, 'keycert.pem') +# Self-signed cert file for 'fakehostname' +CERT_fakehostname = os.path.join(here, 'keycert2.pem') + # Loopback http server infrastructure class LoopbackHttpServer(BaseHTTPServer.HTTPServer): @@ -24,7 +36,7 @@ # Set the timeout of our listening socket really low so # that we can stop the server easily. - self.socket.settimeout(1.0) + self.socket.settimeout(0.1) def get_request(self): """BaseHTTPServer method, overridden.""" @@ -433,6 +445,19 @@ urllib2.install_opener(opener) super(TestUrlopen, self).setUp() + def urlopen(self, url, data=None, **kwargs): + l = [] + f = urllib2.urlopen(url, data, **kwargs) + try: + # Exercise various methods + l.extend(f.readlines(200)) + l.append(f.readline()) + l.append(f.read(1024)) + l.append(f.read()) + finally: + f.close() + return b"".join(l) + def start_server(self, responses): handler = GetRequestHandler(responses) @@ -443,6 +468,16 @@ handler.port = port return handler + def start_https_server(self, responses=None, **kwargs): + if not hasattr(urllib2, 'HTTPSHandler'): + self.skipTest('ssl support required') + from test.ssl_servers import make_https_server + if responses is None: + responses = [(200, [], b"we care a bit")] + handler = GetRequestHandler(responses) + server = make_https_server(self, handler_class=handler, **kwargs) + handler.port = server.port + return handler def test_redirection(self): expected_response = 'We got here...' @@ -513,6 +548,28 @@ finally: self.server.stop() + def test_https(self): + handler = self.start_https_server() + context = ssl.create_default_context(cafile=CERT_localhost) + data = self.urlopen("https://localhost:%s/bizarre" % handler.port, context=context) + self.assertEqual(data, b"we care a bit") + + def test_https_with_cafile(self): + handler = self.start_https_server(certfile=CERT_localhost) + import ssl + # Good cert + data = self.urlopen("https://localhost:%s/bizarre" % handler.port, + cafile=CERT_localhost) + self.assertEqual(data, b"we care a bit") + # Bad cert + with self.assertRaises(urllib2.URLError) as cm: + self.urlopen("https://localhost:%s/bizarre" % handler.port, + cafile=CERT_fakehostname) + # Good cert, but mismatching hostname + handler = self.start_https_server(certfile=CERT_fakehostname) + with self.assertRaises(ssl.CertificateError) as cm: + self.urlopen("https://localhost:%s/bizarre" % handler.port, + cafile=CERT_fakehostname) def test_sending_headers(self): handler = self.start_server([(200, [], "we don't care")]) diff --git a/Lib/urllib2.py b/Lib/urllib2.py --- a/Lib/urllib2.py +++ b/Lib/urllib2.py @@ -109,6 +109,14 @@ except ImportError: from StringIO import StringIO +# check for SSL +try: + import ssl +except ImportError: + _have_ssl = False +else: + _have_ssl = True + from urllib import (unwrap, unquote, splittype, splithost, quote, addinfourl, splitport, splittag, toBytes, splitattr, ftpwrapper, splituser, splitpasswd, splitvalue) @@ -120,11 +128,30 @@ __version__ = sys.version[:3] _opener = None -def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): +def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, + cafile=None, capath=None, cadefault=False, context=None): global _opener - if _opener is None: - _opener = build_opener() - return _opener.open(url, data, timeout) + if cafile or capath or cadefault: + if context is not None: + raise ValueError( + "You can't pass both context and any of cafile, capath, and " + "cadefault" + ) + if not _have_ssl: + raise ValueError('SSL support not available') + context = ssl._create_stdlib_context(cert_reqs=ssl.CERT_REQUIRED, + cafile=cafile, + capath=capath) + https_handler = HTTPSHandler(context=context, check_hostname=True) + opener = build_opener(https_handler) + elif context: + https_handler = HTTPSHandler(context=context) + opener = build_opener(https_handler) + elif _opener is None: + _opener = opener = build_opener() + else: + opener = _opener + return opener.open(url, data, timeout) def install_opener(opener): global _opener @@ -1121,7 +1148,7 @@ return request - def do_open(self, http_class, req): + def do_open(self, http_class, req, **http_conn_args): """Return an addinfourl object for the request, using http_class. http_class must implement the HTTPConnection API from httplib. @@ -1135,7 +1162,8 @@ if not host: raise URLError('no host given') - h = http_class(host, timeout=req.timeout) # will parse host:port + # will parse host:port + h = http_class(host, timeout=req.timeout, **http_conn_args) h.set_debuglevel(self._debuglevel) headers = dict(req.unredirected_hdrs) @@ -1203,8 +1231,14 @@ if hasattr(httplib, 'HTTPS'): class HTTPSHandler(AbstractHTTPHandler): + def __init__(self, debuglevel=0, context=None, check_hostname=None): + AbstractHTTPHandler.__init__(self, debuglevel) + self._context = context + self._check_hostname = check_hostname + def https_open(self, req): - return self.do_open(httplib.HTTPSConnection, req) + return self.do_open(httplib.HTTPSConnection, req, + context=self._context, check_hostname=self._check_hostname) https_request = AbstractHTTPHandler.do_request_ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -42,6 +42,11 @@ Library ------- +- Issue #9003 and #22366: httplib.HTTPSConnection, urllib2.HTTPSHandler and + urllib2.urlopen now take optional arguments to allow for server certificate + checking, as recommended in public uses of HTTPS. This backport is part of PEP + 467. + - Issue #12728: Different Unicode characters having the same uppercase but different lowercase are now matched in case-insensitive regular expressions. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 23 18:52:58 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 23 Nov 2014 17:52:58 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_remove_py3k_wa?= =?utf-8?q?rning_guard?= Message-ID: <20141123175258.69787.67727@psf.io> https://hg.python.org/cpython/rev/e6d63cfcd8e8 changeset: 93554:e6d63cfcd8e8 branch: 2.7 user: Benjamin Peterson date: Sun Nov 23 11:52:46 2014 -0600 summary: remove py3k warning guard files: Lib/test/test_ssl.py | 3 +-- 1 files changed, 1 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 @@ -2391,8 +2391,7 @@ url = 'https://localhost:%d/%s' % ( server.port, os.path.split(CERTFILE)[1]) context = ssl.create_default_context(cafile=CERTFILE) - with support.check_py3k_warnings(): - f = urllib2.urlopen(url, context=context) + f = urllib2.urlopen(url, context=context) try: dlen = f.info().getheader("content-length") if dlen and (int(dlen) > 0): -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 23 19:59:08 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 23 Nov 2014 18:59:08 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_remove_strange?= =?utf-8?q?_casts?= Message-ID: <20141123185907.69805.23514@psf.io> https://hg.python.org/cpython/rev/863a7bf95f18 changeset: 93555:863a7bf95f18 branch: 2.7 user: Benjamin Peterson date: Sun Nov 23 12:58:54 2014 -0600 summary: remove strange casts files: Objects/intobject.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Objects/intobject.c b/Objects/intobject.c --- a/Objects/intobject.c +++ b/Objects/intobject.c @@ -208,7 +208,7 @@ { #if SIZEOF_SIZE_T != SIZEOF_LONG PyNumberMethods *nb; - PyIntObject *io; + PyObject *io; Py_ssize_t val; #endif @@ -232,15 +232,15 @@ } if (nb->nb_long != 0) - io = (PyIntObject*) (*nb->nb_long) (op); + io = (*nb->nb_long)(op); else - io = (PyIntObject*) (*nb->nb_int) (op); + io = (*nb->nb_int)(op); if (io == NULL) return -1; if (!PyInt_Check(io)) { if (PyLong_Check(io)) { /* got a long? => retry int conversion */ - val = _PyLong_AsSsize_t((PyObject *)io); + val = _PyLong_AsSsize_t(io); Py_DECREF(io); if ((val == -1) && PyErr_Occurred()) return -1; -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 23 20:05:58 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 23 Nov 2014 19:05:58 +0000 Subject: [Python-checkins] =?utf-8?q?test=3A_testing?= Message-ID: <20141123190557.116322.78141@psf.io> https://hg.python.org/test/rev/b2abdad5f699 changeset: 218:b2abdad5f699 user: Benjamin Peterson date: Sun Nov 23 13:05:47 2014 -0600 summary: testing files: g | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/g b/g --- a/g +++ b/g @@ -1,1 +1,2 @@ gg +h -- Repository URL: https://hg.python.org/test From python-checkins at python.org Sun Nov 23 20:18:12 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 23 Nov 2014 19:18:12 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_fix_this_test_?= =?utf-8?q?when_sizeof=28long=29_=3C_sizeof=28size=5Ft=29?= Message-ID: <20141123191812.55107.24508@psf.io> https://hg.python.org/cpython/rev/a69da17e7060 changeset: 93556:a69da17e7060 branch: 2.7 user: Benjamin Peterson date: Sun Nov 23 13:17:57 2014 -0600 summary: fix this test when sizeof(long) < sizeof(size_t) files: Lib/test/test_sys.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -507,7 +507,7 @@ sentinel = ["sentinel"] self.assertIs(sys.getsizeof(InvalidSizeof(), sentinel), sentinel) - class OverflowSizeof(int): + class OverflowSizeof(long): def __sizeof__(self): return int(self) self.assertEqual(sys.getsizeof(OverflowSizeof(sys.maxsize)), -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 00:06:59 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 23 Nov 2014 23:06:59 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjMjI5MjEp?= Message-ID: <20141123230654.84283.86983@psf.io> https://hg.python.org/cpython/rev/24dfe7310cc1 changeset: 93558:24dfe7310cc1 parent: 93552:ebfb966c8979 parent: 93557:f2d4beb90a5b user: Benjamin Peterson date: Sun Nov 23 17:06:39 2014 -0600 summary: merge 3.4 (#22921) files: Doc/library/ssl.rst | 14 ++++---- Lib/asyncio/selector_events.py | 2 +- Lib/ftplib.py | 6 +-- Lib/http/client.py | 3 +- Lib/imaplib.py | 6 +-- Lib/nntplib.py | 3 +- Lib/poplib.py | 6 +-- Lib/smtplib.py | 6 +-- Lib/ssl.py | 7 +--- Lib/test/test_asyncio/test_events.py | 8 ----- Lib/test/test_asyncio/test_selector_events.py | 2 +- Lib/test/test_ftplib.py | 4 -- Lib/test/test_imaplib.py | 4 -- Lib/test/test_poplib.py | 4 -- Lib/test/test_ssl.py | 16 ++------- Modules/_ssl.c | 12 ------- 16 files changed, 24 insertions(+), 79 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -680,8 +680,7 @@ .. data:: HAS_SNI Whether the OpenSSL library has built-in support for the *Server Name - Indication* extension (as defined in :rfc:`4366`). When true, you can - use the *server_hostname* argument to :meth:`SSLContext.wrap_socket`. + Indication* extension (as defined in :rfc:`4366`). .. versionadded:: 3.2 @@ -1259,11 +1258,12 @@ On client connections, the optional parameter *server_hostname* specifies the hostname of the service which we are connecting to. This allows a single server to host multiple SSL-based services with distinct certificates, - quite similarly to HTTP virtual hosts. Specifying *server_hostname* - will raise a :exc:`ValueError` if the OpenSSL library doesn't have support - for it (that is, if :data:`HAS_SNI` is :const:`False`). Specifying - *server_hostname* will also raise a :exc:`ValueError` if *server_side* - is true. + quite similarly to HTTP virtual hosts. Specifying *server_hostname* will + raise a :exc:`ValueError` if *server_side* is true. + + .. versionchanged:: 3.5 + Always allow a server_hostname to be passed, even if OpenSSL does not + have SNI. .. method:: SSLContext.wrap_bio(incoming, outgoing, server_side=False, \ server_hostname=None) 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 @@ -708,7 +708,7 @@ 'server_side': server_side, 'do_handshake_on_connect': False, } - if server_hostname and not server_side and ssl.HAS_SNI: + if server_hostname and not server_side: wrap_kwargs['server_hostname'] = server_hostname sslsock = sslcontext.wrap_socket(rawsock, **wrap_kwargs) diff --git a/Lib/ftplib.py b/Lib/ftplib.py --- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -747,9 +747,8 @@ resp = self.voidcmd('AUTH TLS') else: resp = self.voidcmd('AUTH SSL') - server_hostname = self.host if ssl.HAS_SNI else None self.sock = self.context.wrap_socket(self.sock, - server_hostname=server_hostname) + server_hostname=self.host) self.file = self.sock.makefile(mode='r', encoding=self.encoding) return resp @@ -788,9 +787,8 @@ def ntransfercmd(self, cmd, rest=None): conn, size = FTP.ntransfercmd(self, cmd, rest) if self._prot_p: - server_hostname = self.host if ssl.HAS_SNI else None conn = self.context.wrap_socket(conn, - server_hostname=server_hostname) + server_hostname=self.host) return conn, size def abort(self): diff --git a/Lib/http/client.py b/Lib/http/client.py --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -1288,10 +1288,9 @@ server_hostname = self._tunnel_host else: server_hostname = self.host - sni_hostname = server_hostname if ssl.HAS_SNI else None self.sock = self._context.wrap_socket(self.sock, - server_hostname=sni_hostname) + server_hostname=server_hostname) if not self._context.check_hostname and self._check_hostname: try: ssl.match_hostname(self.sock.getpeercert(), server_hostname) diff --git a/Lib/imaplib.py b/Lib/imaplib.py --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -753,9 +753,8 @@ ssl_context = ssl._create_stdlib_context() typ, dat = self._simple_command(name) if typ == 'OK': - server_hostname = self.host if ssl.HAS_SNI else None self.sock = ssl_context.wrap_socket(self.sock, - server_hostname=server_hostname) + server_hostname=self.host) self.file = self.sock.makefile('rb') self._tls_established = True self._get_capabilities() @@ -1231,9 +1230,8 @@ def _create_socket(self): sock = IMAP4._create_socket(self) - server_hostname = self.host if ssl.HAS_SNI else None return self.ssl_context.wrap_socket(sock, - server_hostname=server_hostname) + server_hostname=self.host) def open(self, host='', port=IMAP4_SSL_PORT): """Setup connection to remote server on "host:port". diff --git a/Lib/nntplib.py b/Lib/nntplib.py --- a/Lib/nntplib.py +++ b/Lib/nntplib.py @@ -289,8 +289,7 @@ # Generate a default SSL context if none was passed. if context is None: context = ssl._create_stdlib_context() - server_hostname = hostname if ssl.HAS_SNI else None - return context.wrap_socket(sock, server_hostname=server_hostname) + return context.wrap_socket(sock, server_hostname=hostname) # The classes themselves diff --git a/Lib/poplib.py b/Lib/poplib.py --- a/Lib/poplib.py +++ b/Lib/poplib.py @@ -387,9 +387,8 @@ if context is None: context = ssl._create_stdlib_context() resp = self._shortcmd('STLS') - server_hostname = self.host if ssl.HAS_SNI else None self.sock = context.wrap_socket(self.sock, - server_hostname=server_hostname) + server_hostname=self.host) self.file = self.sock.makefile('rb') self._tls_established = True return resp @@ -430,9 +429,8 @@ def _create_socket(self, timeout): sock = POP3._create_socket(self, timeout) - server_hostname = self.host if ssl.HAS_SNI else None sock = self.context.wrap_socket(sock, - server_hostname=server_hostname) + server_hostname=self.host) return sock def stls(self, keyfile=None, certfile=None, context=None): diff --git a/Lib/smtplib.py b/Lib/smtplib.py --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -709,9 +709,8 @@ if context is None: context = ssl._create_stdlib_context(certfile=certfile, keyfile=keyfile) - server_hostname = self._host if ssl.HAS_SNI else None self.sock = context.wrap_socket(self.sock, - server_hostname=server_hostname) + server_hostname=self._host) self.file = None # RFC 3207: # The client MUST discard any knowledge obtained from @@ -940,9 +939,8 @@ print('connect:', (host, port), file=stderr) new_socket = socket.create_connection((host, port), timeout, self.source_address) - server_hostname = self._host if ssl.HAS_SNI else None new_socket = self.context.wrap_socket(new_socket, - server_hostname=server_hostname) + server_hostname=self._host) return new_socket __all__.append("SMTP_SSL") diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -655,12 +655,7 @@ raise ValueError("server_hostname can only be specified " "in client mode") if self._context.check_hostname and not server_hostname: - if HAS_SNI: - raise ValueError("check_hostname requires server_hostname") - else: - raise ValueError("check_hostname requires server_hostname, " - "but it's not supported by your OpenSSL " - "library") + raise ValueError("check_hostname requires server_hostname") self.server_side = server_side self.server_hostname = server_hostname self.do_handshake_on_connect = do_handshake_on_connect 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 @@ -12,9 +12,6 @@ import ssl except ImportError: ssl = None - HAS_SNI = False -else: - from ssl import HAS_SNI import subprocess import sys import threading @@ -857,7 +854,6 @@ server.close() @unittest.skipIf(ssl is None, 'No ssl module') - @unittest.skipUnless(HAS_SNI, 'No SNI support in ssl module') def test_create_server_ssl_verify_failed(self): proto = MyProto(loop=self.loop) server, host, port = self._make_ssl_server( @@ -882,7 +878,6 @@ server.close() @unittest.skipIf(ssl is None, 'No ssl module') - @unittest.skipUnless(HAS_SNI, 'No SNI support in ssl module') @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'No UNIX Sockets') def test_create_unix_server_ssl_verify_failed(self): proto = MyProto(loop=self.loop) @@ -909,7 +904,6 @@ server.close() @unittest.skipIf(ssl is None, 'No ssl module') - @unittest.skipUnless(HAS_SNI, 'No SNI support in ssl module') def test_create_server_ssl_match_failed(self): proto = MyProto(loop=self.loop) server, host, port = self._make_ssl_server( @@ -937,7 +931,6 @@ server.close() @unittest.skipIf(ssl is None, 'No ssl module') - @unittest.skipUnless(HAS_SNI, 'No SNI support in ssl module') @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'No UNIX Sockets') def test_create_unix_server_ssl_verified(self): proto = MyProto(loop=self.loop) @@ -963,7 +956,6 @@ server.close() @unittest.skipIf(ssl is None, 'No ssl module') - @unittest.skipUnless(HAS_SNI, 'No SNI support in ssl module') def test_create_server_ssl_verified(self): proto = MyProto(loop=self.loop) server, host, port = self._make_ssl_server( 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 @@ -1408,7 +1408,7 @@ self.assertEqual(tr._conn_lost, 1) self.assertEqual(1, self.loop.remove_reader_count[1]) - @unittest.skipIf(ssl is None or not ssl.HAS_SNI, 'No SNI support') + @unittest.skipIf(ssl is None, 'No SSL support') def test_server_hostname(self): _SelectorSslTransport( self.loop, self.sock, self.protocol, self.sslcontext, diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -15,9 +15,6 @@ import ssl except ImportError: ssl = None - HAS_SNI = False -else: - from ssl import HAS_SNI from unittest import TestCase, skipUnless from test import support @@ -927,7 +924,6 @@ self.client.ccc() self.assertRaises(ValueError, self.client.sock.unwrap) - @skipUnless(HAS_SNI, 'No SNI support in ssl module') def test_check_hostname(self): self.client.quit() ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) 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 @@ -19,9 +19,6 @@ import ssl except ImportError: ssl = None - HAS_SNI = False -else: - from ssl import HAS_SNI CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "keycert3.pem") CAFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "pycacert.pem") @@ -387,7 +384,6 @@ imap_class = IMAP4_SSL @reap_threads - @unittest.skipUnless(HAS_SNI, 'No SNI support in ssl module') def test_ssl_verified(self): ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ssl_context.verify_mode = ssl.CERT_REQUIRED diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py --- a/Lib/test/test_poplib.py +++ b/Lib/test/test_poplib.py @@ -21,13 +21,10 @@ SUPPORTS_SSL = False if hasattr(poplib, 'POP3_SSL'): import ssl - from ssl import HAS_SNI SUPPORTS_SSL = True CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "keycert3.pem") CAFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "pycacert.pem") -else: - HAS_SNI = False requires_ssl = skipUnless(SUPPORTS_SSL, 'SSL not supported') @@ -334,7 +331,6 @@ self.assertEqual(resp, expected) @requires_ssl - @skipUnless(HAS_SNI, 'No SNI support in ssl module') def test_stls_context(self): expected = b'+OK Begin TLS negotiation' ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) 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 @@ -1428,11 +1428,8 @@ # Same with a server hostname s = ctx.wrap_socket(socket.socket(socket.AF_INET), server_hostname="svn.python.org") - if ssl.HAS_SNI: - s.connect(("svn.python.org", 443)) - s.close() - else: - self.assertRaises(ValueError, s.connect, ("svn.python.org", 443)) + s.connect(("svn.python.org", 443)) + s.close() # This should fail because we have no verification certs ctx.verify_mode = ssl.CERT_REQUIRED s = ctx.wrap_socket(socket.socket(socket.AF_INET)) @@ -1696,12 +1693,8 @@ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ctx.verify_mode = ssl.CERT_REQUIRED ctx.load_verify_locations(SVN_PYTHON_ORG_ROOT_CERT) - if ssl.HAS_SNI: - ctx.check_hostname = True - sslobj = ctx.wrap_bio(incoming, outgoing, False, 'svn.python.org') - else: - ctx.check_hostname = False - sslobj = ctx.wrap_bio(incoming, outgoing, False) + ctx.check_hostname = True + sslobj = ctx.wrap_bio(incoming, outgoing, False, 'svn.python.org') self.assertIs(sslobj._sslobj.owner, sslobj) self.assertIsNone(sslobj.cipher()) self.assertRaises(ValueError, sslobj.getpeercert) @@ -2283,7 +2276,6 @@ cert = s.getpeercert() self.assertTrue(cert, "Can't get peer certificate.") - @needs_sni def test_check_hostname(self): if support.verbose: sys.stdout.write("\n") diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2922,12 +2922,6 @@ &sock, &server_side, "idna", &hostname)) return NULL; -#if !HAVE_SNI - PyMem_Free(hostname); - PyErr_SetString(PyExc_ValueError, "server_hostname is not supported " - "by your OpenSSL library"); - return NULL; -#endif } res = (PyObject *) newPySSLSocket(self, sock, server_side, hostname, @@ -2955,14 +2949,8 @@ &server_side, &hostname_obj)) return NULL; if (hostname_obj != Py_None) { -#if HAVE_SNI if (!PyArg_Parse(hostname_obj, "et", "idna", &hostname)) return NULL; -#else - PyErr_SetString(PyExc_ValueError, "server_hostname is not supported " - "by your OpenSSL library"); - return NULL; -#endif } res = (PyObject *) newPySSLSocket(self, NULL, server_side, hostname, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 00:06:59 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 23 Nov 2014 23:06:59 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogZG9uJ3QgcmVxdWly?= =?utf-8?q?e_OpenSSL_SNI_to_pass_hostname_to_ssl_functions_=28=2322921=29?= Message-ID: <20141123230654.116324.46636@psf.io> https://hg.python.org/cpython/rev/f2d4beb90a5b changeset: 93557:f2d4beb90a5b branch: 3.4 parent: 93551:3cc8b7227db4 user: Benjamin Peterson date: Sun Nov 23 17:04:34 2014 -0600 summary: don't require OpenSSL SNI to pass hostname to ssl functions (#22921) Patch by Donald Stufft. files: Doc/library/ssl.rst | 14 +++++----- Lib/asyncio/selector_events.py | 2 +- Lib/ftplib.py | 6 +-- Lib/http/client.py | 3 +- Lib/imaplib.py | 6 +-- Lib/nntplib.py | 3 +- Lib/poplib.py | 6 +-- Lib/smtplib.py | 6 +-- Lib/ssl.py | 7 +---- Lib/test/test_asyncio/test_events.py | 8 ----- Lib/test/test_asyncio/test_selector_events.py | 2 +- Lib/test/test_ftplib.py | 4 -- Lib/test/test_imaplib.py | 4 -- Lib/test/test_poplib.py | 4 -- Lib/test/test_ssl.py | 8 +---- Modules/_ssl.c | 6 ---- 16 files changed, 22 insertions(+), 67 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -664,8 +664,7 @@ .. data:: HAS_SNI Whether the OpenSSL library has built-in support for the *Server Name - Indication* extension (as defined in :rfc:`4366`). When true, you can - use the *server_hostname* argument to :meth:`SSLContext.wrap_socket`. + Indication* extension (as defined in :rfc:`4366`). .. versionadded:: 3.2 @@ -1227,11 +1226,12 @@ On client connections, the optional parameter *server_hostname* specifies the hostname of the service which we are connecting to. This allows a single server to host multiple SSL-based services with distinct certificates, - quite similarly to HTTP virtual hosts. Specifying *server_hostname* - will raise a :exc:`ValueError` if the OpenSSL library doesn't have support - for it (that is, if :data:`HAS_SNI` is :const:`False`). Specifying - *server_hostname* will also raise a :exc:`ValueError` if *server_side* - is true. + quite similarly to HTTP virtual hosts. Specifying *server_hostname* will + raise a :exc:`ValueError` if *server_side* is true. + + .. versionchanged:: 3.5 + Always allow a server_hostname to be passed, even if OpenSSL does not + have SNI. .. method:: SSLContext.session_stats() 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 @@ -708,7 +708,7 @@ 'server_side': server_side, 'do_handshake_on_connect': False, } - if server_hostname and not server_side and ssl.HAS_SNI: + if server_hostname and not server_side: wrap_kwargs['server_hostname'] = server_hostname sslsock = sslcontext.wrap_socket(rawsock, **wrap_kwargs) diff --git a/Lib/ftplib.py b/Lib/ftplib.py --- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -747,9 +747,8 @@ resp = self.voidcmd('AUTH TLS') else: resp = self.voidcmd('AUTH SSL') - server_hostname = self.host if ssl.HAS_SNI else None self.sock = self.context.wrap_socket(self.sock, - server_hostname=server_hostname) + server_hostname=self.host) self.file = self.sock.makefile(mode='r', encoding=self.encoding) return resp @@ -788,9 +787,8 @@ def ntransfercmd(self, cmd, rest=None): conn, size = FTP.ntransfercmd(self, cmd, rest) if self._prot_p: - server_hostname = self.host if ssl.HAS_SNI else None conn = self.context.wrap_socket(conn, - server_hostname=server_hostname) + server_hostname=self.host) return conn, size def abort(self): diff --git a/Lib/http/client.py b/Lib/http/client.py --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -1224,10 +1224,9 @@ server_hostname = self._tunnel_host else: server_hostname = self.host - sni_hostname = server_hostname if ssl.HAS_SNI else None self.sock = self._context.wrap_socket(self.sock, - server_hostname=sni_hostname) + server_hostname=server_hostname) if not self._context.check_hostname and self._check_hostname: try: ssl.match_hostname(self.sock.getpeercert(), server_hostname) diff --git a/Lib/imaplib.py b/Lib/imaplib.py --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -745,9 +745,8 @@ ssl_context = ssl._create_stdlib_context() typ, dat = self._simple_command(name) if typ == 'OK': - server_hostname = self.host if ssl.HAS_SNI else None self.sock = ssl_context.wrap_socket(self.sock, - server_hostname=server_hostname) + server_hostname=self.host) self.file = self.sock.makefile('rb') self._tls_established = True self._get_capabilities() @@ -1223,9 +1222,8 @@ def _create_socket(self): sock = IMAP4._create_socket(self) - server_hostname = self.host if ssl.HAS_SNI else None return self.ssl_context.wrap_socket(sock, - server_hostname=server_hostname) + server_hostname=self.host) def open(self, host='', port=IMAP4_SSL_PORT): """Setup connection to remote server on "host:port". diff --git a/Lib/nntplib.py b/Lib/nntplib.py --- a/Lib/nntplib.py +++ b/Lib/nntplib.py @@ -289,8 +289,7 @@ # Generate a default SSL context if none was passed. if context is None: context = ssl._create_stdlib_context() - server_hostname = hostname if ssl.HAS_SNI else None - return context.wrap_socket(sock, server_hostname=server_hostname) + return context.wrap_socket(sock, server_hostname=hostname) # The classes themselves diff --git a/Lib/poplib.py b/Lib/poplib.py --- a/Lib/poplib.py +++ b/Lib/poplib.py @@ -387,9 +387,8 @@ if context is None: context = ssl._create_stdlib_context() resp = self._shortcmd('STLS') - server_hostname = self.host if ssl.HAS_SNI else None self.sock = context.wrap_socket(self.sock, - server_hostname=server_hostname) + server_hostname=self.host) self.file = self.sock.makefile('rb') self._tls_established = True return resp @@ -430,9 +429,8 @@ def _create_socket(self, timeout): sock = POP3._create_socket(self, timeout) - server_hostname = self.host if ssl.HAS_SNI else None sock = self.context.wrap_socket(sock, - server_hostname=server_hostname) + server_hostname=self.host) return sock def stls(self, keyfile=None, certfile=None, context=None): diff --git a/Lib/smtplib.py b/Lib/smtplib.py --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -684,9 +684,8 @@ if context is None: context = ssl._create_stdlib_context(certfile=certfile, keyfile=keyfile) - server_hostname = self._host if ssl.HAS_SNI else None self.sock = context.wrap_socket(self.sock, - server_hostname=server_hostname) + server_hostname=self._host) self.file = None # RFC 3207: # The client MUST discard any knowledge obtained from @@ -915,9 +914,8 @@ print('connect:', (host, port), file=stderr) new_socket = socket.create_connection((host, port), timeout, self.source_address) - server_hostname = self._host if ssl.HAS_SNI else None new_socket = self.context.wrap_socket(new_socket, - server_hostname=server_hostname) + server_hostname=self._host) return new_socket __all__.append("SMTP_SSL") diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -538,12 +538,7 @@ raise ValueError("server_hostname can only be specified " "in client mode") if self._context.check_hostname and not server_hostname: - if HAS_SNI: - raise ValueError("check_hostname requires server_hostname") - else: - raise ValueError("check_hostname requires server_hostname, " - "but it's not supported by your OpenSSL " - "library") + raise ValueError("check_hostname requires server_hostname") self.server_side = server_side self.server_hostname = server_hostname self.do_handshake_on_connect = do_handshake_on_connect 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 @@ -12,9 +12,6 @@ import ssl except ImportError: ssl = None - HAS_SNI = False -else: - from ssl import HAS_SNI import subprocess import sys import threading @@ -857,7 +854,6 @@ server.close() @unittest.skipIf(ssl is None, 'No ssl module') - @unittest.skipUnless(HAS_SNI, 'No SNI support in ssl module') def test_create_server_ssl_verify_failed(self): proto = MyProto(loop=self.loop) server, host, port = self._make_ssl_server( @@ -882,7 +878,6 @@ server.close() @unittest.skipIf(ssl is None, 'No ssl module') - @unittest.skipUnless(HAS_SNI, 'No SNI support in ssl module') @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'No UNIX Sockets') def test_create_unix_server_ssl_verify_failed(self): proto = MyProto(loop=self.loop) @@ -909,7 +904,6 @@ server.close() @unittest.skipIf(ssl is None, 'No ssl module') - @unittest.skipUnless(HAS_SNI, 'No SNI support in ssl module') def test_create_server_ssl_match_failed(self): proto = MyProto(loop=self.loop) server, host, port = self._make_ssl_server( @@ -937,7 +931,6 @@ server.close() @unittest.skipIf(ssl is None, 'No ssl module') - @unittest.skipUnless(HAS_SNI, 'No SNI support in ssl module') @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'No UNIX Sockets') def test_create_unix_server_ssl_verified(self): proto = MyProto(loop=self.loop) @@ -963,7 +956,6 @@ server.close() @unittest.skipIf(ssl is None, 'No ssl module') - @unittest.skipUnless(HAS_SNI, 'No SNI support in ssl module') def test_create_server_ssl_verified(self): proto = MyProto(loop=self.loop) server, host, port = self._make_ssl_server( 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 @@ -1408,7 +1408,7 @@ self.assertEqual(tr._conn_lost, 1) self.assertEqual(1, self.loop.remove_reader_count[1]) - @unittest.skipIf(ssl is None or not ssl.HAS_SNI, 'No SNI support') + @unittest.skipIf(ssl is None, 'No SSL support') def test_server_hostname(self): _SelectorSslTransport( self.loop, self.sock, self.protocol, self.sslcontext, diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -15,9 +15,6 @@ import ssl except ImportError: ssl = None - HAS_SNI = False -else: - from ssl import HAS_SNI from unittest import TestCase, skipUnless from test import support @@ -927,7 +924,6 @@ self.client.ccc() self.assertRaises(ValueError, self.client.sock.unwrap) - @skipUnless(HAS_SNI, 'No SNI support in ssl module') def test_check_hostname(self): self.client.quit() ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) 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 @@ -18,9 +18,6 @@ import ssl except ImportError: ssl = None - HAS_SNI = False -else: - from ssl import HAS_SNI CERTFILE = None CAFILE = None @@ -352,7 +349,6 @@ imap_class = IMAP4_SSL @reap_threads - @unittest.skipUnless(HAS_SNI, 'No SNI support in ssl module') def test_ssl_verified(self): ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ssl_context.verify_mode = ssl.CERT_REQUIRED diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py --- a/Lib/test/test_poplib.py +++ b/Lib/test/test_poplib.py @@ -21,13 +21,10 @@ SUPPORTS_SSL = False if hasattr(poplib, 'POP3_SSL'): import ssl - from ssl import HAS_SNI SUPPORTS_SSL = True CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "keycert3.pem") CAFILE = os.path.join(os.path.dirname(__file__) or os.curdir, "pycacert.pem") -else: - HAS_SNI = False requires_ssl = skipUnless(SUPPORTS_SSL, 'SSL not supported') @@ -334,7 +331,6 @@ self.assertEqual(resp, expected) @requires_ssl - @skipUnless(HAS_SNI, 'No SNI support in ssl module') def test_stls_context(self): expected = b'+OK Begin TLS negotiation' ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) 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 @@ -1281,11 +1281,8 @@ # Same with a server hostname s = ctx.wrap_socket(socket.socket(socket.AF_INET), server_hostname="svn.python.org") - if ssl.HAS_SNI: - s.connect(("svn.python.org", 443)) - s.close() - else: - self.assertRaises(ValueError, s.connect, ("svn.python.org", 443)) + s.connect(("svn.python.org", 443)) + s.close() # This should fail because we have no verification certs ctx.verify_mode = ssl.CERT_REQUIRED s = ctx.wrap_socket(socket.socket(socket.AF_INET)) @@ -2038,7 +2035,6 @@ cert = s.getpeercert() self.assertTrue(cert, "Can't get peer certificate.") - @needs_sni def test_check_hostname(self): if support.verbose: sys.stdout.write("\n") diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2806,12 +2806,6 @@ &sock, &server_side, "idna", &hostname)) return NULL; -#if !HAVE_SNI - PyMem_Free(hostname); - PyErr_SetString(PyExc_ValueError, "server_hostname is not supported " - "by your OpenSSL library"); - return NULL; -#endif } res = (PyObject *) newPySSLSocket(self, sock, server_side, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 03:10:38 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 24 Nov 2014 02:10:38 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_correct_versio?= =?utf-8?q?nchanged_version?= Message-ID: <20141124021037.84295.92859@psf.io> https://hg.python.org/cpython/rev/9ec68665ca7e changeset: 93559:9ec68665ca7e branch: 3.4 parent: 93557:f2d4beb90a5b user: Benjamin Peterson date: Sun Nov 23 20:09:31 2014 -0600 summary: correct versionchanged version files: Doc/library/ssl.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -1229,7 +1229,7 @@ quite similarly to HTTP virtual hosts. Specifying *server_hostname* will raise a :exc:`ValueError` if *server_side* is true. - .. versionchanged:: 3.5 + .. versionchanged:: 3.4.3 Always allow a server_hostname to be passed, even if OpenSSL does not have SNI. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 03:10:38 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 24 Nov 2014 02:10:38 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40IChudWxsKQ==?= Message-ID: <20141124021038.55125.22714@psf.io> https://hg.python.org/cpython/rev/fc81a4b381e1 changeset: 93560:fc81a4b381e1 parent: 93558:24dfe7310cc1 parent: 93559:9ec68665ca7e user: Benjamin Peterson date: Sun Nov 23 20:10:25 2014 -0600 summary: merge 3.4 (null) files: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 03:13:47 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 24 Nov 2014 02:13:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_allow_hostname?= =?utf-8?q?_to_be_passed_to_SSLContext_even_if_OpenSSL_doesn=27t_support_S?= =?utf-8?q?NI?= Message-ID: <20141124021345.116304.82317@psf.io> https://hg.python.org/cpython/rev/ce4073afd992 changeset: 93561:ce4073afd992 branch: 2.7 parent: 93556:a69da17e7060 user: Benjamin Peterson date: Sun Nov 23 20:13:31 2014 -0600 summary: allow hostname to be passed to SSLContext even if OpenSSL doesn't support SNI (closes #22921) Patch from Donald Stufft. files: Doc/library/ssl.rst | 14 +++++++------- Lib/httplib.py | 3 +-- Lib/ssl.py | 7 +------ Lib/test/test_ssl.py | 8 ++------ Modules/_ssl.c | 6 ------ 5 files changed, 11 insertions(+), 27 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -645,8 +645,7 @@ .. data:: HAS_SNI Whether the OpenSSL library has built-in support for the *Server Name - Indication* extension (as defined in :rfc:`4366`). When true, you can - use the *server_hostname* argument to :meth:`SSLContext.wrap_socket`. + Indication* extension (as defined in :rfc:`4366`). .. versionadded:: 2.7.9 @@ -1136,11 +1135,12 @@ On client connections, the optional parameter *server_hostname* specifies the hostname of the service which we are connecting to. This allows a single server to host multiple SSL-based services with distinct certificates, - quite similarly to HTTP virtual hosts. Specifying *server_hostname* - will raise a :exc:`ValueError` if the OpenSSL library doesn't have support - for it (that is, if :data:`HAS_SNI` is :const:`False`). Specifying - *server_hostname* will also raise a :exc:`ValueError` if *server_side* - is true. + quite similarly to HTTP virtual hosts. Specifying *server_hostname* will + raise a :exc:`ValueError` if *server_side* is true. + + .. versionchanged:: 3.5 + Always allow a server_hostname to be passed, even if OpenSSL does not + have SNI. .. method:: SSLContext.session_stats() diff --git a/Lib/httplib.py b/Lib/httplib.py --- a/Lib/httplib.py +++ b/Lib/httplib.py @@ -1214,10 +1214,9 @@ server_hostname = self._tunnel_host else: server_hostname = self.host - sni_hostname = server_hostname if ssl.HAS_SNI else None self.sock = self._context.wrap_socket(self.sock, - server_hostname=sni_hostname) + server_hostname=server_hostname) if not self._context.check_hostname and self._check_hostname: try: ssl.match_hostname(self.sock.getpeercert(), server_hostname) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -527,12 +527,7 @@ raise ValueError("server_hostname can only be specified " "in client mode") if self._context.check_hostname and not server_hostname: - if HAS_SNI: - raise ValueError("check_hostname requires server_hostname") - else: - raise ValueError("check_hostname requires server_hostname, " - "but it's not supported by your OpenSSL " - "library") + raise ValueError("check_hostname requires server_hostname") self.server_side = server_side self.server_hostname = server_hostname self.do_handshake_on_connect = do_handshake_on_connect 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 @@ -1323,11 +1323,8 @@ # Same with a server hostname s = ctx.wrap_socket(socket.socket(socket.AF_INET), server_hostname="svn.python.org") - if ssl.HAS_SNI: - s.connect(("svn.python.org", 443)) - s.close() - else: - self.assertRaises(ValueError, s.connect, ("svn.python.org", 443)) + s.connect(("svn.python.org", 443)) + s.close() # This should fail because we have no verification certs ctx.verify_mode = ssl.CERT_REQUIRED s = ctx.wrap_socket(socket.socket(socket.AF_INET)) @@ -2089,7 +2086,6 @@ cert = s.getpeercert() self.assertTrue(cert, "Can't get peer certificate.") - @needs_sni def test_check_hostname(self): if support.verbose: sys.stdout.write("\n") diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2824,12 +2824,6 @@ &sock, &server_side, "idna", &hostname, &ssl_sock)) return NULL; -#if !HAVE_SNI - PyMem_Free(hostname); - PyErr_SetString(PyExc_ValueError, "server_hostname is not supported " - "by your OpenSSL library"); - return NULL; -#endif } res = (PyObject *) newPySSLSocket(self, sock, server_side, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 03:14:11 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 24 Nov 2014 02:14:11 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_fix_versioncha?= =?utf-8?q?nged_version?= Message-ID: <20141124021409.55125.71050@psf.io> https://hg.python.org/cpython/rev/e94f407efd76 changeset: 93562:e94f407efd76 branch: 2.7 user: Benjamin Peterson date: Sun Nov 23 20:13:55 2014 -0600 summary: fix versionchanged version files: Doc/library/ssl.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -1138,7 +1138,7 @@ quite similarly to HTTP virtual hosts. Specifying *server_hostname* will raise a :exc:`ValueError` if *server_side* is true. - .. versionchanged:: 3.5 + .. versionchanged:: 2.7.9 Always allow a server_hostname to be passed, even if OpenSSL does not have SNI. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 03:17:23 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 24 Nov 2014 02:17:23 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_add_NEWS_note_?= =?utf-8?q?for_=2322921?= Message-ID: <20141124021723.116324.31065@psf.io> https://hg.python.org/cpython/rev/060fd5d09063 changeset: 93564:060fd5d09063 branch: 3.4 parent: 93559:9ec68665ca7e user: Benjamin Peterson date: Sun Nov 23 20:15:31 2014 -0600 summary: add NEWS note for #22921 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 @@ -36,6 +36,9 @@ Library ------- +- Issue #22921: Allow SSLContext to take the *hostname* parameter even if + OpenSSL doesn't support SNI. + - Issue #22894: TestCase.subTest() would cause the test suite to be stopped when in failfast mode, even in the absence of failures. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 03:17:23 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 24 Nov 2014 02:17:23 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20141124021723.116320.71861@psf.io> https://hg.python.org/cpython/rev/8cb4d114ae82 changeset: 93565:8cb4d114ae82 parent: 93560:fc81a4b381e1 parent: 93564:060fd5d09063 user: Benjamin Peterson date: Sun Nov 23 20:17:06 2014 -0600 summary: merge 3.4 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 @@ -191,6 +191,9 @@ Library ------- +- Issue #22921: Allow SSLContext to take the *hostname* parameter even if + OpenSSL doesn't support SNI. + - Issue #22894: TestCase.subTest() would cause the test suite to be stopped when in failfast mode, even in the absence of failures. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 03:17:23 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 24 Nov 2014 02:17:23 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_add_NEWS_note_?= =?utf-8?q?for_=2322921?= Message-ID: <20141124021722.84285.31489@psf.io> https://hg.python.org/cpython/rev/40f9e91f3626 changeset: 93563:40f9e91f3626 branch: 2.7 user: Benjamin Peterson date: Sun Nov 23 20:15:31 2014 -0600 summary: add NEWS note for #22921 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 @@ -42,6 +42,9 @@ Library ------- +- Issue #22921: Allow SSLContext to take the *hostname* parameter even if + OpenSSL doesn't support SNI. + - Issue #9003 and #22366: httplib.HTTPSConnection, urllib2.HTTPSHandler and urllib2.urlopen now take optional arguments to allow for server certificate checking, as recommended in public uses of HTTPS. This backport is part of PEP -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 03:38:29 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 24 Nov 2014 02:38:29 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjMjI3ODgp?= Message-ID: <20141124023829.116322.39438@psf.io> https://hg.python.org/cpython/rev/ec4d19736b15 changeset: 93567:ec4d19736b15 parent: 93565:8cb4d114ae82 parent: 93566:5864ec6ba484 user: Benjamin Peterson date: Sun Nov 23 20:38:13 2014 -0600 summary: merge 3.4 (#22788) files: Doc/library/logging.handlers.rst | 15 ++++++++++----- Lib/logging/handlers.py | 9 +++++++-- Lib/test/test_logging.py | 19 +++++-------------- Misc/NEWS | 2 ++ 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -839,17 +839,22 @@ ``POST`` semantics. -.. class:: HTTPHandler(host, url, method='GET', secure=False, credentials=None) +.. class:: HTTPHandler(host, url, method='GET', secure=False, credentials=None, context=None) Returns a new instance of the :class:`HTTPHandler` class. The *host* can be - of the form ``host:port``, should you need to use a specific port number. - If no *method* is specified, ``GET`` is used. If *secure* is true, an HTTPS - connection will be used. If *credentials* is specified, it should be a - 2-tuple consisting of userid and password, which will be placed in an HTTP + of the form ``host:port``, should you need to use a specific port number. If + no *method* is specified, ``GET`` is used. If *secure* is true, a HTTPS + connection will be used. The *context* parameter may be set to a + :class:`ssl.SSLContext` instance to configure the SSL settings used for the + HTTPS connection. If *credentials* is specified, it should be a 2-tuple + consisting of userid and password, which will be placed in a HTTP 'Authorization' header using Basic authentication. If you specify credentials, you should also specify secure=True so that your userid and password are not passed in cleartext across the wire. + .. versionchanged:: 3.4.3 + The *context* parameter was added. + .. method:: mapLogRecord(record) Provides a dictionary, based on ``record``, which is to be URL-encoded diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -1089,7 +1089,8 @@ A class which sends records to a Web server, using either GET or POST semantics. """ - def __init__(self, host, url, method="GET", secure=False, credentials=None): + def __init__(self, host, url, method="GET", secure=False, credentials=None, + context=None): """ Initialize the instance with the host, the request URL, and the method ("GET" or "POST") @@ -1098,11 +1099,15 @@ method = method.upper() if method not in ["GET", "POST"]: raise ValueError("method must be GET or POST") + if not secure and context is not None: + raise ValueError("context parameter only makes sense " + "with secure=True") self.host = host self.url = url self.method = method self.secure = secure self.credentials = credentials + self.context = context def mapLogRecord(self, record): """ @@ -1122,7 +1127,7 @@ import http.client, urllib.parse host = self.host if self.secure: - h = http.client.HTTPSConnection(host) + h = http.client.HTTPSConnection(host, context=self.context) else: h = http.client.HTTPConnection(host) url = self.url 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 @@ -1663,21 +1663,11 @@ localhost_cert = os.path.join(here, "keycert.pem") sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) sslctx.load_cert_chain(localhost_cert) - # Unfortunately, HTTPHandler doesn't allow us to change the - # SSLContext used by HTTPSConnection, so we have to - # monkeypatch. This can be cleaned up if issue 22788 is - # fixed. - old = ssl._create_default_https_context - def restore_handler(): - ssl._create_default_https_context = old - self.addCleanup(restore_handler) - def hack_create_ctx(): - ctx = old() - ctx.load_verify_locations(localhost_cert) - return ctx - ssl._create_default_https_context = hack_create_ctx + + context = ssl.create_default_context(cafile=localhost_cert) else: sslctx = None + context = None self.server = server = TestHTTPServer(addr, self.handle_request, 0.01, sslctx=sslctx) server.start() @@ -1685,7 +1675,8 @@ host = 'localhost:%d' % server.server_port secure_client = secure and sslctx self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob', - secure=secure_client) + secure=secure_client, + context=context) self.log_data = None root_logger.addHandler(self.h_hdlr) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -191,6 +191,8 @@ Library ------- +- Issue #22788: Add *context* parameter to logging.handlers.HTTPHandler. + - Issue #22921: Allow SSLContext to take the *hostname* parameter even if OpenSSL doesn't support SNI. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 03:38:29 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 24 Nov 2014 02:38:29 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_add_context_pa?= =?utf-8?q?rameter_to_HTTPHandler_=28closes_=2322788=29?= Message-ID: <20141124023828.55113.13@psf.io> https://hg.python.org/cpython/rev/5864ec6ba484 changeset: 93566:5864ec6ba484 branch: 3.4 parent: 93564:060fd5d09063 user: Benjamin Peterson date: Sun Nov 23 20:36:44 2014 -0600 summary: add context parameter to HTTPHandler (closes #22788) files: Doc/library/logging.handlers.rst | 15 ++++++++++----- Lib/logging/handlers.py | 9 +++++++-- Lib/test/test_logging.py | 19 +++++-------------- Misc/NEWS | 2 ++ 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -839,17 +839,22 @@ ``POST`` semantics. -.. class:: HTTPHandler(host, url, method='GET', secure=False, credentials=None) +.. class:: HTTPHandler(host, url, method='GET', secure=False, credentials=None, context=None) Returns a new instance of the :class:`HTTPHandler` class. The *host* can be - of the form ``host:port``, should you need to use a specific port number. - If no *method* is specified, ``GET`` is used. If *secure* is true, an HTTPS - connection will be used. If *credentials* is specified, it should be a - 2-tuple consisting of userid and password, which will be placed in an HTTP + of the form ``host:port``, should you need to use a specific port number. If + no *method* is specified, ``GET`` is used. If *secure* is true, a HTTPS + connection will be used. The *context* parameter may be set to a + :class:`ssl.SSLContext` instance to configure the SSL settings used for the + HTTPS connection. If *credentials* is specified, it should be a 2-tuple + consisting of userid and password, which will be placed in a HTTP 'Authorization' header using Basic authentication. If you specify credentials, you should also specify secure=True so that your userid and password are not passed in cleartext across the wire. + .. versionchanged:: 3.4.3 + The *context* parameter was added. + .. method:: mapLogRecord(record) Provides a dictionary, based on ``record``, which is to be URL-encoded diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -1089,7 +1089,8 @@ A class which sends records to a Web server, using either GET or POST semantics. """ - def __init__(self, host, url, method="GET", secure=False, credentials=None): + def __init__(self, host, url, method="GET", secure=False, credentials=None, + context=None): """ Initialize the instance with the host, the request URL, and the method ("GET" or "POST") @@ -1098,11 +1099,15 @@ method = method.upper() if method not in ["GET", "POST"]: raise ValueError("method must be GET or POST") + if not secure and context is not None: + raise ValueError("context parameter only makes sense " + "with secure=True") self.host = host self.url = url self.method = method self.secure = secure self.credentials = credentials + self.context = context def mapLogRecord(self, record): """ @@ -1122,7 +1127,7 @@ import http.client, urllib.parse host = self.host if self.secure: - h = http.client.HTTPSConnection(host) + h = http.client.HTTPSConnection(host, context=self.context) else: h = http.client.HTTPConnection(host) url = self.url 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 @@ -1667,21 +1667,11 @@ localhost_cert = os.path.join(here, "keycert.pem") sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) sslctx.load_cert_chain(localhost_cert) - # Unfortunately, HTTPHandler doesn't allow us to change the - # SSLContext used by HTTPSConnection, so we have to - # monkeypatch. This can be cleaned up if issue 22788 is - # fixed. - old = ssl._create_default_https_context - def restore_handler(): - ssl._create_default_https_context = old - self.addCleanup(restore_handler) - def hack_create_ctx(): - ctx = old() - ctx.load_verify_locations(localhost_cert) - return ctx - ssl._create_default_https_context = hack_create_ctx + + context = ssl.create_default_context(cafile=localhost_cert) else: sslctx = None + context = None self.server = server = TestHTTPServer(addr, self.handle_request, 0.01, sslctx=sslctx) server.start() @@ -1689,7 +1679,8 @@ host = 'localhost:%d' % server.server_port secure_client = secure and sslctx self.h_hdlr = logging.handlers.HTTPHandler(host, '/frob', - secure=secure_client) + secure=secure_client, + context=context) self.log_data = None root_logger.addHandler(self.h_hdlr) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,8 @@ Library ------- +- Issue #22788: Add *context* parameter to logging.handlers.HTTPHandler. + - Issue #22921: Allow SSLContext to take the *hostname* parameter even if OpenSSL doesn't support SNI. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 03:38:49 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 24 Nov 2014 02:38:49 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_update_versionchanged?= Message-ID: <20141124023848.55113.97207@psf.io> https://hg.python.org/cpython/rev/91b4dc856011 changeset: 93568:91b4dc856011 user: Benjamin Peterson date: Sun Nov 23 20:38:37 2014 -0600 summary: update versionchanged files: Doc/library/logging.handlers.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/logging.handlers.rst b/Doc/library/logging.handlers.rst --- a/Doc/library/logging.handlers.rst +++ b/Doc/library/logging.handlers.rst @@ -852,7 +852,7 @@ credentials, you should also specify secure=True so that your userid and password are not passed in cleartext across the wire. - .. versionchanged:: 3.4.3 + .. versionchanged:: 3.5 The *context* parameter was added. .. method:: mapLogRecord(record) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 03:55:41 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 24 Nov 2014 02:55:41 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogZ2l2ZSB1cmxsaWIu?= =?utf-8?q?urlopen_a_context_parameter_=28closes_=2322927=29?= Message-ID: <20141124025537.55121.51077@psf.io> https://hg.python.org/cpython/rev/c84f36a5f556 changeset: 93569:c84f36a5f556 branch: 2.7 parent: 93563:40f9e91f3626 user: Benjamin Peterson date: Sun Nov 23 20:55:24 2014 -0600 summary: give urllib.urlopen a context parameter (closes #22927) files: Doc/library/urllib.rst | 18 ++++++++++++++---- Lib/httplib.py | 5 +++-- Lib/test/test_urllibnet.py | 20 +++++++++++++++++++- Lib/urllib.py | 24 +++++++++++++++--------- Misc/NEWS | 3 +++ 5 files changed, 54 insertions(+), 16 deletions(-) diff --git a/Doc/library/urllib.rst b/Doc/library/urllib.rst --- a/Doc/library/urllib.rst +++ b/Doc/library/urllib.rst @@ -31,7 +31,7 @@ High-level interface -------------------- -.. function:: urlopen(url[, data[, proxies]]) +.. function:: urlopen(url[, data[, proxies[, context]]]) Open a network object denoted by a URL for reading. If the URL does not have a scheme identifier, or if it has :file:`file:` as its scheme @@ -122,8 +122,12 @@ filehandle = urllib.urlopen(some_url, proxies=None) filehandle = urllib.urlopen(some_url) - Proxies which require authentication for use are not currently supported; this - is considered an implementation limitation. + Proxies which require authentication for use are not currently supported; + this is considered an implementation limitation. + + The *context* parameter may be set to a :class:`ssl.SSLContext` instance to + configure the SSL settings that are used if :func:`urlopen` makes a HTTPS + connection. .. versionchanged:: 2.3 Added the *proxies* support. @@ -132,6 +136,9 @@ Added :meth:`getcode` to returned object and support for the :envvar:`no_proxy` environment variable. + .. versionchanged:: 2.7.9 + The *context* parameter was added. + .. deprecated:: 2.6 The :func:`urlopen` function has been removed in Python 3 in favor of :func:`urllib2.urlopen`. @@ -292,7 +299,7 @@ URL Opener objects ------------------ -.. class:: URLopener([proxies[, **x509]]) +.. class:: URLopener([proxies[, context[, **x509]]]) Base class for opening and reading URLs. Unless you need to support opening objects using schemes other than :file:`http:`, :file:`ftp:`, or :file:`file:`, @@ -309,6 +316,9 @@ value is ``None``, in which case environmental proxy settings will be used if present, as discussed in the definition of :func:`urlopen`, above. + The *context* parameter may be a :class:`ssl.SSLContext` instance. If given, + it defines the SSL settings the opener uses to make HTTPS connections. + Additional keyword parameters, collected in *x509*, may be used for authentication of the client when using the :file:`https:` scheme. The keywords *key_file* and *cert_file* are supported to provide an SSL key and certificate; diff --git a/Lib/httplib.py b/Lib/httplib.py --- a/Lib/httplib.py +++ b/Lib/httplib.py @@ -1238,14 +1238,15 @@ _connection_class = HTTPSConnection def __init__(self, host='', port=None, key_file=None, cert_file=None, - strict=None): + strict=None, context=None): # provide a default host, pass the X509 cert info # urf. compensate for bad input. if port == 0: port = None self._setup(self._connection_class(host, port, key_file, - cert_file, strict)) + cert_file, strict, + context=context)) # we never actually use these for anything, but we keep them # here for compatibility with post-1.5.2 CVS. 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 @@ -7,6 +7,15 @@ import os import time +try: + import ssl +except ImportError: + ssl = None + +here = os.path.dirname(__file__) +# Self-signed cert file for self-signed.pythontest.net +CERT_selfsigned_pythontestdotnet = os.path.join(here, 'selfsigned_pythontestdotnet.pem') + mimetools = test_support.import_module("mimetools", deprecated=True) @@ -195,6 +204,14 @@ self.fail('Date value not in %r format', dateformat) + at unittest.skipIf(ssl is None, "requires ssl") +class urlopen_HttpsTests(unittest.TestCase): + + def test_context_argument(self): + context = ssl.create_default_context(cafile=CERT_selfsigned_pythontestdotnet) + response = urllib.urlopen("https://self-signed.pythontest.net", context=context) + self.assertIn("Python", response.read()) + def test_main(): test_support.requires('network') @@ -202,7 +219,8 @@ ("urllib.urlopen.. has been removed", DeprecationWarning)): test_support.run_unittest(URLTimeoutTest, urlopenNetworkTests, - urlretrieveNetworkTests) + urlretrieveNetworkTests, + urlopen_HttpsTests) if __name__ == "__main__": test_main() diff --git a/Lib/urllib.py b/Lib/urllib.py --- a/Lib/urllib.py +++ b/Lib/urllib.py @@ -69,15 +69,15 @@ # Shortcut for basic usage _urlopener = None -def urlopen(url, data=None, proxies=None): +def urlopen(url, data=None, proxies=None, context=None): """Create a file-like object for the specified URL to read from.""" from warnings import warnpy3k warnpy3k("urllib.urlopen() has been removed in Python 3.0 in " "favor of urllib2.urlopen()", stacklevel=2) global _urlopener - if proxies is not None: - opener = FancyURLopener(proxies=proxies) + if proxies is not None or context is not None: + opener = FancyURLopener(proxies=proxies, context=context) elif not _urlopener: opener = FancyURLopener() _urlopener = opener @@ -87,11 +87,15 @@ return opener.open(url) else: return opener.open(url, data) -def urlretrieve(url, filename=None, reporthook=None, data=None): +def urlretrieve(url, filename=None, reporthook=None, data=None, context=None): global _urlopener - if not _urlopener: - _urlopener = FancyURLopener() - return _urlopener.retrieve(url, filename, reporthook, data) + if context is not None: + opener = FancyURLopener(context=context) + elif not _urlopener: + _urlopener = opener = FancyURLopener() + else: + opener = _urlopener + return opener.retrieve(url, filename, reporthook, data) def urlcleanup(): if _urlopener: _urlopener.cleanup() @@ -126,13 +130,14 @@ version = "Python-urllib/%s" % __version__ # Constructor - def __init__(self, proxies=None, **x509): + def __init__(self, proxies=None, context=None, **x509): if proxies is None: proxies = getproxies() assert hasattr(proxies, 'has_key'), "proxies must be a mapping" self.proxies = proxies self.key_file = x509.get('key_file') self.cert_file = x509.get('cert_file') + self.context = context self.addheaders = [('User-Agent', self.version)] self.__tempfiles = [] self.__unlink = os.unlink # See cleanup() @@ -422,7 +427,8 @@ auth = None h = httplib.HTTPS(host, 0, key_file=self.key_file, - cert_file=self.cert_file) + cert_file=self.cert_file, + context=self.context) if data is not None: h.putrequest('POST', selector) h.putheader('Content-Type', diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -42,6 +42,9 @@ Library ------- +- Issue #22927: Allow urllib.urlopen to take a *context* parameter to control + SSL settings for HTTPS connections. + - Issue #22921: Allow SSLContext to take the *hostname* parameter even if OpenSSL doesn't support SNI. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 04:02:22 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 24 Nov 2014 03:02:22 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogcGVwIDQ3NjogdmVy?= =?utf-8?q?ify_certificates_by_default_=28=2322417=29?= Message-ID: <20141124030214.69797.92049@psf.io> https://hg.python.org/cpython/rev/fb83916c3ea1 changeset: 93570:fb83916c3ea1 branch: 2.7 user: Benjamin Peterson date: Sun Nov 23 21:02:02 2014 -0600 summary: pep 476: verify certificates by default (#22417) files: Doc/library/httplib.rst | 8 +++-- Doc/library/xmlrpclib.rst | 7 ++-- Doc/whatsnew/2.7.rst | 23 ++++++++++++++++ Lib/httplib.py | 2 +- Lib/ssl.py | 11 ++++++- Lib/test/test_httplib.py | 3 +- Lib/test/test_urllib2_localnet.py | 27 +++++++++++++++++- Misc/NEWS | 2 + 8 files changed, 69 insertions(+), 14 deletions(-) diff --git a/Doc/library/httplib.rst b/Doc/library/httplib.rst --- a/Doc/library/httplib.rst +++ b/Doc/library/httplib.rst @@ -90,9 +90,6 @@ server's certificate. If you want to change that behaviour, you can explicitly set *check_hostname* to False. - .. warning:: - This does not do any verification of the server's certificate. - .. versionadded:: 2.0 .. versionchanged:: 2.6 @@ -104,6 +101,11 @@ .. versionchanged:: 2.7.9 *context* and *check_hostname* was added. + This class now performs all the necessary certificate and hostname checks + by default. To revert to the previous, unverified, behavior + :func:`ssl._create_unverified_context` can be passed to the *context* + parameter. + .. class:: HTTPResponse(sock, debuglevel=0, strict=0) diff --git a/Doc/library/xmlrpclib.rst b/Doc/library/xmlrpclib.rst --- a/Doc/library/xmlrpclib.rst +++ b/Doc/library/xmlrpclib.rst @@ -34,11 +34,10 @@ constructed data. If you need to parse untrusted or unauthenticated data see :ref:`xml-vulnerabilities`. -.. warning:: +.. versionchanged:: 2.7.9 - In the case of https URIs, :mod:`xmlrpclib` does not do any verification of - the server's certificate. - + For https URIs, :mod:`xmlrpclib` now performs all the necessary certificate + and hostname checks by default .. class:: ServerProxy(uri[, transport[, encoding[, verbose[, allow_none[, use_datetime]]]]]) diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -2646,6 +2646,29 @@ PEP written by Donald Stufft and Nick Coghlan, implemented by Donald Stufft, Nick Coghlan, Martin von L?wis and Ned Deily. +PEP 476: Enabling certificate verification by default for stdlib http clients +----------------------------------------------------------------------------- + +:mod:`httplib` and modules which use it, such as :mod:`urllib2` and +:mod:`xmlrpclib`, will now verify that the server presents a certificate +which is signed by a CA in the platform trust store and whose hostname matches +the hostname being requested by default, significantly improving security for +many applications. + +For applications which require the old previous behavior, they can pass an +alternate context:: + + import urllib2 + import ssl + + # This disables all verification + context = ssl._create_unverified_context() + + # This allows using a specific certificate for the host, which doesn't need + # to be in the trust store + context = ssl.create_default_context(cafile="/path/to/file.crt") + + urllib2.urlopen("https://invalid-cert", context=context) .. ====================================================================== diff --git a/Lib/httplib.py b/Lib/httplib.py --- a/Lib/httplib.py +++ b/Lib/httplib.py @@ -1193,7 +1193,7 @@ self.key_file = key_file self.cert_file = cert_file if context is None: - context = ssl.create_default_context() + context = ssl._create_default_https_context() will_verify = context.verify_mode != ssl.CERT_NONE if check_hostname is None: check_hostname = will_verify diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -427,8 +427,7 @@ context.load_default_certs(purpose) return context - -def _create_stdlib_context(protocol=PROTOCOL_SSLv23, cert_reqs=None, +def _create_unverified_context(protocol=PROTOCOL_SSLv23, cert_reqs=None, check_hostname=False, purpose=Purpose.SERVER_AUTH, certfile=None, keyfile=None, cafile=None, capath=None, cadata=None): @@ -469,6 +468,14 @@ return context +# Used by http.client if no context is explicitly passed. +_create_default_https_context = create_default_context + + +# Backwards compatibility alias, even though it's not a public name. +_create_stdlib_context = _create_unverified_context + + class SSLSocket(socket): """This class implements a subtype of socket.socket that wraps the underlying OS socket in an SSL context when necessary, and diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -1,10 +1,9 @@ import httplib import array -import httplib -import os import StringIO import socket import errno +import os import unittest TestCase = unittest.TestCase 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 @@ -5,6 +5,7 @@ import BaseHTTPServer import unittest import hashlib +import ssl from test import test_support @@ -562,15 +563,37 @@ cafile=CERT_localhost) self.assertEqual(data, b"we care a bit") # Bad cert - with self.assertRaises(urllib2.URLError) as cm: + with self.assertRaises(urllib2.URLError): self.urlopen("https://localhost:%s/bizarre" % handler.port, cafile=CERT_fakehostname) # Good cert, but mismatching hostname handler = self.start_https_server(certfile=CERT_fakehostname) - with self.assertRaises(ssl.CertificateError) as cm: + with self.assertRaises(ssl.CertificateError): self.urlopen("https://localhost:%s/bizarre" % handler.port, cafile=CERT_fakehostname) + def test_https_with_cadefault(self): + handler = self.start_https_server(certfile=CERT_localhost) + # Self-signed cert should fail verification with system certificate store + with self.assertRaises(urllib2.URLError): + self.urlopen("https://localhost:%s/bizarre" % handler.port, + cadefault=True) + + def test_https_sni(self): + if ssl is None: + self.skipTest("ssl module required") + if not ssl.HAS_SNI: + self.skipTest("SNI support required in OpenSSL") + sni_name = [None] + def cb_sni(ssl_sock, server_name, initial_context): + sni_name[0] = server_name + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + context.set_servername_callback(cb_sni) + handler = self.start_https_server(context=context, certfile=CERT_localhost) + context = ssl.create_default_context(cafile=CERT_localhost) + self.urlopen("https://localhost:%s" % handler.port, context=context) + self.assertEqual(sni_name[0], "localhost") + def test_sending_headers(self): handler = self.start_server([(200, [], "we don't care")]) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -42,6 +42,8 @@ Library ------- +- Issue #22417: Verify certificates by default in httplib (PEP 476). + - Issue #22927: Allow urllib.urlopen to take a *context* parameter to control SSL settings for HTTPS connections. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 04:05:54 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 24 Nov 2014 03:05:54 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_mark_476_finished?= Message-ID: <20141124030554.84295.65488@psf.io> https://hg.python.org/peps/rev/aa68cfb92e9e changeset: 5611:aa68cfb92e9e user: Benjamin Peterson date: Sun Nov 23 21:05:32 2014 -0600 summary: mark 476 finished files: pep-0476.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0476.txt b/pep-0476.txt --- a/pep-0476.txt +++ b/pep-0476.txt @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Alex Gaynor -Status: Accepted +Status: Final Type: Standards Track Content-Type: text/x-rst Created: 28-August-2014 -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Mon Nov 24 05:03:10 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 24 Nov 2014 04:03:10 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogc2tpcCB0ZXN0X2dk?= =?utf-8?q?b_on_OpenIndiana?= Message-ID: <20141124040259.55109.46471@psf.io> https://hg.python.org/cpython/rev/38acbe503145 changeset: 93571:38acbe503145 branch: 2.7 user: Benjamin Peterson date: Sun Nov 23 22:02:47 2014 -0600 summary: skip test_gdb on OpenIndiana files: Lib/test/test_gdb.py | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -25,6 +25,9 @@ if gdb_major_version < 7: raise unittest.SkipTest("gdb versions before 7.0 didn't support python embedding" " Saw:\n" + gdb_version) +if sys.platform == "solaris": + raise unittest.SkipTest("test doesn't work very well on Solaris") + # Location of custom hooks file in a repository checkout. checkout_hook_path = os.path.join(os.path.dirname(sys.executable), -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 05:23:11 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 24 Nov 2014 04:23:11 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_loosen_solaris?= =?utf-8?q?_test?= Message-ID: <20141124042310.69779.90363@psf.io> https://hg.python.org/cpython/rev/f0cc690f9d33 changeset: 93572:f0cc690f9d33 branch: 2.7 user: Benjamin Peterson date: Sun Nov 23 22:22:59 2014 -0600 summary: loosen solaris test files: Lib/test/test_gdb.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -25,7 +25,7 @@ if gdb_major_version < 7: raise unittest.SkipTest("gdb versions before 7.0 didn't support python embedding" " Saw:\n" + gdb_version) -if sys.platform == "solaris": +if sys.platform.startswith("solaris"): raise unittest.SkipTest("test doesn't work very well on Solaris") -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 05:34:17 2014 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 24 Nov 2014 04:34:17 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_is_OpenIndiana?= =?utf-8?q?_actually_sunos=3F?= Message-ID: <20141124043416.116316.56897@psf.io> https://hg.python.org/cpython/rev/d1b4e523a163 changeset: 93573:d1b4e523a163 branch: 2.7 user: Benjamin Peterson date: Sun Nov 23 22:34:04 2014 -0600 summary: is OpenIndiana actually sunos? files: Lib/test/test_gdb.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -25,7 +25,7 @@ if gdb_major_version < 7: raise unittest.SkipTest("gdb versions before 7.0 didn't support python embedding" " Saw:\n" + gdb_version) -if sys.platform.startswith("solaris"): +if sys.platform.startswith("sunos"): raise unittest.SkipTest("test doesn't work very well on Solaris") -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 05:56:22 2014 From: python-checkins at python.org (ned.deily) Date: Mon, 24 Nov 2014 04:56:22 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fix_faulty_ind?= =?utf-8?q?ent=2E?= Message-ID: <20141124045622.126778.48672@psf.io> https://hg.python.org/cpython/rev/41ea764e8321 changeset: 93574:41ea764e8321 branch: 2.7 user: Ned Deily date: Sun Nov 23 20:55:55 2014 -0800 summary: Fix faulty indent. files: Doc/library/urllib2.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/urllib2.rst b/Doc/library/urllib2.rst --- a/Doc/library/urllib2.rst +++ b/Doc/library/urllib2.rst @@ -38,7 +38,7 @@ The optional *timeout* parameter specifies a timeout in seconds for blocking operations like the connection attempt (if not specified, the global default timeout setting will be used). This actually only works for HTTP, HTTPS and - FTP connections. + FTP connections. If *context* is specified, it must be a :class:`ssl.SSLContext` instance describing the various SSL options. See :class:`~httplib.HTTPSConnection` for -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Mon Nov 24 10:31:59 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 24 Nov 2014 10:31:59 +0100 Subject: [Python-checkins] Daily reference leaks (8cb4d114ae82): sum=1 Message-ID: results for 8cb4d114ae82 on branch "default" -------------------------------------------- test_collections leaked [-2, -2, 2] references, sum=-2 test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog72Ezzs', '-x'] From python-checkins at python.org Mon Nov 24 22:26:03 2014 From: python-checkins at python.org (berker.peksag) Date: Mon, 24 Nov 2014 21:26:03 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322934=3A_Update_t?= =?utf-8?q?he_comment_to_mention_Programs/=5Ffreeze=5Fimportlib=2Ec=2E?= Message-ID: <20141124212554.126774.19937@psf.io> https://hg.python.org/cpython/rev/0ddcc455e001 changeset: 93575:0ddcc455e001 parent: 93568:91b4dc856011 user: Berker Peksag date: Mon Nov 24 23:26:08 2014 +0200 summary: Issue #22934: Update the comment to mention Programs/_freeze_importlib.c. files: Programs/_freeze_importlib.c | 2 +- Python/importlib.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Programs/_freeze_importlib.c b/Programs/_freeze_importlib.c --- a/Programs/_freeze_importlib.c +++ b/Programs/_freeze_importlib.c @@ -28,7 +28,7 @@ const struct _frozen *PyImport_FrozenModules; #endif -const char header[] = "/* Auto-generated by Modules/_freeze_importlib.c */"; +const char header[] = "/* Auto-generated by Programs/_freeze_importlib.c */"; int main(int argc, char *argv[]) diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 22:46:58 2014 From: python-checkins at python.org (berker.peksag) Date: Mon, 24 Nov 2014 21:46:58 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIwMzUx?= =?utf-8?q?=3A_Add_examples_for_csv=2EDictReader_and_csv=2EDictWriter=2E?= Message-ID: <20141124214651.116308.16284@psf.io> https://hg.python.org/cpython/rev/268ceaa78cf9 changeset: 93576:268ceaa78cf9 branch: 3.4 parent: 93566:5864ec6ba484 user: Berker Peksag date: Mon Nov 24 23:46:30 2014 +0200 summary: Issue #20351: Add examples for csv.DictReader and csv.DictWriter. Patch by Charles-Axel Dein. files: Doc/library/csv.rst | 25 +++++++++++++++++++++++++ 1 files changed, 25 insertions(+), 0 deletions(-) diff --git a/Doc/library/csv.rst b/Doc/library/csv.rst --- a/Doc/library/csv.rst +++ b/Doc/library/csv.rst @@ -158,6 +158,18 @@ the optional *restval* parameter. Any other optional or keyword arguments are passed to the underlying :class:`reader` instance. + A short usage example:: + + >>> import csv + >>> with open('names.csv') as csvfile: + ... reader = csv.DictReader(csvfile) + ... for row in reader: + ... print(row['first_name'], row['last_name']) + ... + Baked Beans + Lovely Spam + Wonderful Spam + .. class:: DictWriter(csvfile, fieldnames, restval='', extrasaction='raise', \ dialect='excel', *args, **kwds) @@ -180,6 +192,19 @@ objects are not ordered, there is not enough information available to deduce the order in which the row should be written to the *csvfile*. + A short usage example:: + + import csv + + with open('names.csv', 'w') as csvfile: + fieldnames = ['first_name', 'last_name'] + writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + + writer.writeheader() + writer.writerow({'first_name': 'Baked', 'last_name': 'Beans'}) + writer.writerow({'first_name': 'Lovely', 'last_name': 'Spam'}) + writer.writerow({'first_name': 'Wonderful', 'last_name': 'Spam'}) + .. class:: Dialect -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 22:46:58 2014 From: python-checkins at python.org (berker.peksag) Date: Mon, 24 Nov 2014 21:46:58 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2320351=3A_Add_examples_for_csv=2EDictReader_and_?= =?utf-8?q?csv=2EDictWriter=2E?= Message-ID: <20141124214651.126780.74929@psf.io> https://hg.python.org/cpython/rev/c2b36196b7f5 changeset: 93577:c2b36196b7f5 parent: 93575:0ddcc455e001 parent: 93576:268ceaa78cf9 user: Berker Peksag date: Mon Nov 24 23:47:06 2014 +0200 summary: Issue #20351: Add examples for csv.DictReader and csv.DictWriter. Patch by Charles-Axel Dein. files: Doc/library/csv.rst | 25 +++++++++++++++++++++++++ 1 files changed, 25 insertions(+), 0 deletions(-) diff --git a/Doc/library/csv.rst b/Doc/library/csv.rst --- a/Doc/library/csv.rst +++ b/Doc/library/csv.rst @@ -159,6 +159,18 @@ the optional *restval* parameter. Any other optional or keyword arguments are passed to the underlying :class:`reader` instance. + A short usage example:: + + >>> import csv + >>> with open('names.csv') as csvfile: + ... reader = csv.DictReader(csvfile) + ... for row in reader: + ... print(row['first_name'], row['last_name']) + ... + Baked Beans + Lovely Spam + Wonderful Spam + .. class:: DictWriter(csvfile, fieldnames, restval='', extrasaction='raise', \ dialect='excel', *args, **kwds) @@ -181,6 +193,19 @@ objects are not ordered, there is not enough information available to deduce the order in which the row should be written to the *csvfile*. + A short usage example:: + + import csv + + with open('names.csv', 'w') as csvfile: + fieldnames = ['first_name', 'last_name'] + writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + + writer.writeheader() + writer.writerow({'first_name': 'Baked', 'last_name': 'Beans'}) + writer.writerow({'first_name': 'Lovely', 'last_name': 'Spam'}) + writer.writerow({'first_name': 'Wonderful', 'last_name': 'Spam'}) + .. class:: Dialect -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 22:50:35 2014 From: python-checkins at python.org (berker.peksag) Date: Mon, 24 Nov 2014 21:50:35 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIwMzUx?= =?utf-8?q?=3A_Add_examples_for_csv=2EDictReader_and_csv=2EDictWriter=2E?= Message-ID: <20141124215032.84275.32023@psf.io> https://hg.python.org/cpython/rev/e504c3bc6897 changeset: 93578:e504c3bc6897 branch: 2.7 parent: 93574:41ea764e8321 user: Berker Peksag date: Mon Nov 24 23:50:46 2014 +0200 summary: Issue #20351: Add examples for csv.DictReader and csv.DictWriter. Patch by Charles-Axel Dein. files: Doc/library/csv.rst | 25 +++++++++++++++++++++++++ 1 files changed, 25 insertions(+), 0 deletions(-) diff --git a/Doc/library/csv.rst b/Doc/library/csv.rst --- a/Doc/library/csv.rst +++ b/Doc/library/csv.rst @@ -180,6 +180,18 @@ of the optional *restval* parameter. Any other optional or keyword arguments are passed to the underlying :class:`reader` instance. + A short usage example:: + + >>> import csv + >>> with open('names.csv') as csvfile: + ... reader = csv.DictReader(csvfile) + ... for row in reader: + ... print(row['first_name'], row['last_name']) + ... + Baked Beans + Lovely Spam + Wonderful Spam + .. class:: DictWriter(csvfile, fieldnames, restval='', extrasaction='raise', \ dialect='excel', *args, **kwds) @@ -202,6 +214,19 @@ objects are not ordered, there is not enough information available to deduce the order in which the row should be written to the *csvfile*. + A short usage example:: + + import csv + + with open('names.csv', 'w') as csvfile: + fieldnames = ['first_name', 'last_name'] + writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + + writer.writeheader() + writer.writerow({'first_name': 'Baked', 'last_name': 'Beans'}) + writer.writerow({'first_name': 'Lovely', 'last_name': 'Spam'}) + writer.writerow({'first_name': 'Wonderful', 'last_name': 'Spam'}) + .. class:: Dialect -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Mon Nov 24 22:56:53 2014 From: python-checkins at python.org (berker.peksag) Date: Mon, 24 Nov 2014 21:56:53 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE2MDU2?= =?utf-8?q?=3A_Rename_test_methods_to_avoid_conflict=2E?= Message-ID: <20141124215650.69781.96246@psf.io> https://hg.python.org/cpython/rev/fd786e4e331c changeset: 93579:fd786e4e331c branch: 2.7 user: Berker Peksag date: Mon Nov 24 23:57:00 2014 +0200 summary: Issue #16056: Rename test methods to avoid conflict. files: Lib/test/test_ftplib.py | 4 -- Lib/test/test_unicode.py | 2 +- Lib/test/test_weakset.py | 54 ---------------------------- 3 files changed, 1 insertions(+), 59 deletions(-) diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py --- a/Lib/test/test_ftplib.py +++ b/Lib/test/test_ftplib.py @@ -484,10 +484,6 @@ dir = self.client.cwd('/foo') self.assertEqual(dir, '250 cwd ok') - def test_mkd(self): - dir = self.client.mkd('/foo') - self.assertEqual(dir, '/foo') - def test_pwd(self): dir = self.client.pwd() self.assertEqual(dir, 'pwd ok') 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 @@ -484,7 +484,7 @@ u'X\U00010427X\U00010427') @requires_wide_build - def test_capitalize(self): + def test_capitalize_wide_build(self): string_tests.CommonTest.test_capitalize(self) self.assertEqual(u'\U0001044F'.capitalize(), u'\U00010427') self.assertEqual(u'\U0001044F\U0001044F'.capitalize(), diff --git a/Lib/test/test_weakset.py b/Lib/test/test_weakset.py --- a/Lib/test/test_weakset.py +++ b/Lib/test/test_weakset.py @@ -11,7 +11,6 @@ import collections import gc import contextlib -from UserString import UserString as ustr class Foo: @@ -449,59 +448,6 @@ self.assertGreaterEqual(n2, 0) self.assertLessEqual(n2, n1) - def test_weak_destroy_while_iterating(self): - # Issue #7105: iterators shouldn't crash when a key is implicitly removed - # Create new items to be sure no-one else holds a reference - items = [ustr(c) for c in ('a', 'b', 'c')] - s = WeakSet(items) - it = iter(s) - next(it) # Trigger internal iteration - # Destroy an item - del items[-1] - gc.collect() # just in case - # We have removed either the first consumed items, or another one - self.assertIn(len(list(it)), [len(items), len(items) - 1]) - del it - # The removal has been committed - self.assertEqual(len(s), len(items)) - - def test_weak_destroy_and_mutate_while_iterating(self): - # Issue #7105: iterators shouldn't crash when a key is implicitly removed - items = [ustr(c) for c in string.ascii_letters] - s = WeakSet(items) - @contextlib.contextmanager - def testcontext(): - try: - it = iter(s) - # Start iterator - yielded = ustr(str(next(it))) - # Schedule an item for removal and recreate it - u = ustr(str(items.pop())) - if yielded == u: - # The iterator still has a reference to the removed item, - # advance it (issue #20006). - next(it) - gc.collect() # just in case - yield u - finally: - it = None # should commit all removals - - with testcontext() as u: - self.assertFalse(u in s) - with testcontext() as u: - self.assertRaises(KeyError, s.remove, u) - self.assertFalse(u in s) - with testcontext() as u: - s.add(u) - self.assertTrue(u in s) - t = s.copy() - with testcontext() as u: - s.update(t) - self.assertEqual(len(s), len(t)) - with testcontext() as u: - s.clear() - self.assertEqual(len(s), 0) - def test_main(verbose=None): test_support.run_unittest(TestWeakSet) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 25 03:09:01 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 25 Nov 2014 02:09:01 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_dl-files_has_a_new_hostname?= Message-ID: <20141125020858.126768.16006@psf.io> https://hg.python.org/peps/rev/7417d67f0750 changeset: 5612:7417d67f0750 user: Benjamin Peterson date: Mon Nov 24 20:08:44 2014 -0600 summary: dl-files has a new hostname files: pep-0101.txt | 22 +++++++++++----------- 1 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pep-0101.txt b/pep-0101.txt --- a/pep-0101.txt +++ b/pep-0101.txt @@ -35,7 +35,7 @@ which hopefully will be on the "web of trust" with at least one of the other release managers. - * Access to ``dl-files.psf.io``, the server that hosts download files. + * Access to ``dl-files.iad1.psf.io``, the server that hosts download files. You'll be uploading files directly here. * Shell access to ``hg.python.org``, the Python Mercurial host. You'll @@ -335,11 +335,11 @@ - Now he runs msi.py with ActivePython or Python with pywin32. The WE checksums the files (*.msi, *.chm, *-pdb.zip), uploads them to - dl-files.psf.io together with gpg signature files, and emails you the + dl-files.iad1.psf.io together with gpg signature files, and emails you the location and md5sums. - ___ The ME builds Mac installer packages and uploads them to dl-files.psf.io - together with gpg signature files. + ___ The ME builds Mac installer packages and uploads them to + dl-files.iad1.psf.io together with gpg signature files. ___ Time to build the source tarball. Be sure to update your clone to the correct branch. E.g. @@ -367,7 +367,7 @@ tarballs and signatures in a subdirectory called 'X.Y.ZaN/src', and the built docs in 'X.Y.ZaN/docs' (for final releases). - ___ scp or rsync all the files to your home directory on dl-files.psf.io. + ___ scp or rsync all the files to your home directory on dl-files.iad1.psf.io. While you're waiting for the files to finish uploading, you can continue on with the remaining tasks. You can also ask folks on #python-dev @@ -401,13 +401,13 @@ freshly unpacked directory looks weird, you better stop now and figure out what the problem is. - ___ Now you need to go to dl-files.psf.io and move all the files in - place over there. Our policy is that every Python version gets its own + ___ Now you need to go to dl-files.iad1.psf.io and move all the files in place + over there. Our policy is that every Python version gets its own directory, but each directory contains all releases of that version. - ___ On dl-files.psf.io, cd /srv/www.python.org/ftp/python/X.Y.Z creating - it if necessary. Make sure it is owned by group 'downloads' and - group-writable. + ___ On dl-files.iad1.psf.io, cd /srv/www.python.org/ftp/python/X.Y.Z + creating it if necessary. Make sure it is owned by group 'downloads' + and group-writable. ___ Move the release .tgz, and .tar.xz files into place, as well as the .asc GPG signature files. The Win/Mac binaries are usually put there @@ -498,7 +498,7 @@ production release" paragraph as appropriate Note, you don't have to copy any release files into this directory; - they only live on dl-files.psf.io in the ftp directory. + they only live on dl-files.iad1.psf.io in the ftp directory. ___ Edit `download/releases/content.ht` to update the version numbers for this release. There are a bunch of places you need to touch: -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Tue Nov 25 06:25:43 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 25 Nov 2014 05:25:43 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogZGVidWdnaW5nOiBw?= =?utf-8?q?rint_ca_certs_loaded_into_default_ctx?= Message-ID: <20141125052540.126770.19317@psf.io> https://hg.python.org/cpython/rev/28fecaa8a74c changeset: 93580:28fecaa8a74c branch: 2.7 user: Benjamin Peterson date: Mon Nov 24 23:25:29 2014 -0600 summary: debugging: print ca certs loaded into default ctx files: Lib/test/test_httplib.py | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -554,6 +554,9 @@ def test_networked_trusted_by_default_cert(self): # Default settings: requires a valid cert from a trusted CA test_support.requires('network') + if test_support.verbose: + import ssl + print(ssl._create_default_https_context().get_ca_certs()) with test_support.transient_internet('www.python.org'): h = httplib.HTTPSConnection('www.python.org', 443) h.request('GET', '/') -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Tue Nov 25 10:33:19 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 25 Nov 2014 10:33:19 +0100 Subject: [Python-checkins] Daily reference leaks (c2b36196b7f5): sum=3 Message-ID: results for c2b36196b7f5 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogj3EMlb', '-x'] From python-checkins at python.org Tue Nov 25 13:14:28 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 25 Nov 2014 12:14:28 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2319676=3A_Added_th?= =?utf-8?q?e_=22namereplace=22_error_handler=2E?= Message-ID: <20141125121330.84283.66481@psf.io> https://hg.python.org/cpython/rev/32d08aacffe0 changeset: 93581:32d08aacffe0 parent: 93577:c2b36196b7f5 user: Serhiy Storchaka date: Tue Nov 25 13:57:17 2014 +0200 summary: Issue #19676: Added the "namereplace" error handler. files: Doc/c-api/codec.rst | 5 + Doc/howto/unicode.rst | 7 +- Doc/library/codecs.rst | 17 +++ Doc/library/functions.rst | 3 + Doc/library/io.rst | 7 +- Include/codecs.h | 3 + Lib/codecs.py | 3 + Lib/test/test_codeccallbacks.py | 100 ++++++++++++++++++- Lib/test/test_codecs.py | 7 + Misc/NEWS | 2 + Python/codecs.c | 108 ++++++++++++++++++++ 11 files changed, 255 insertions(+), 7 deletions(-) diff --git a/Doc/c-api/codec.rst b/Doc/c-api/codec.rst --- a/Doc/c-api/codec.rst +++ b/Doc/c-api/codec.rst @@ -116,3 +116,8 @@ Replace the unicode encode error with backslash escapes (``\x``, ``\u`` and ``\U``). +.. c:function:: PyObject* PyCodec_NameReplaceErrors(PyObject *exc) + + Replace the unicode encode error with `\N{...}` escapes. + + .. versionadded: 3.4 diff --git a/Doc/howto/unicode.rst b/Doc/howto/unicode.rst --- a/Doc/howto/unicode.rst +++ b/Doc/howto/unicode.rst @@ -325,8 +325,9 @@ :meth:`~bytes.decode` method but supports a few more possible handlers. As well as ``'strict'``, ``'ignore'``, and ``'replace'`` (which in this case inserts a question mark instead of the unencodable character), there is -also ``'xmlcharrefreplace'`` (inserts an XML character reference) and -``backslashreplace`` (inserts a ``\uNNNN`` escape sequence). +also ``'xmlcharrefreplace'`` (inserts an XML character reference), +``backslashreplace`` (inserts a ``\uNNNN`` escape sequence) and +``namereplace`` (inserts a ``\N{...}`` escape sequence). The following example shows the different results:: @@ -346,6 +347,8 @@ b'ꀀabcd޴' >>> u.encode('ascii', 'backslashreplace') b'\\ua000abcd\\u07b4' + >>> u.encode('ascii', 'namereplace') + b'\\N{YI SYLLABLE IT}abcd\\u07b4' The low-level routines for registering and accessing the available encodings are found in the :mod:`codecs` module. Implementing new diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -98,6 +98,8 @@ reference (for encoding only) * ``'backslashreplace'``: replace with backslashed escape sequences (for encoding only) + * ``'namereplace'``: replace with ``\N{...}`` escape sequences (for + encoding only) * ``'surrogateescape'``: on decoding, replace with code points in the Unicode Private Use Area ranging from U+DC80 to U+DCFF. These private code points will then be turned back into the same bytes when the @@ -232,6 +234,11 @@ Implements the ``backslashreplace`` error handling (for encoding only): the unencodable character is replaced by a backslashed escape sequence. +.. function:: namereplace_errors(exception) + + Implements the ``namereplace`` error handling (for encoding only): the + unencodable character is replaced by a ``\N{...}`` escape sequence. + To simplify working with encoded files or stream, the module also defines these utility functions: @@ -363,6 +370,9 @@ | ``'backslashreplace'`` | Replace with backslashed escape sequences | | | (only for encoding). | +-------------------------+-----------------------------------------------+ +| ``'namereplace'`` | Replace with ``\N{...}`` escape sequences | +| | (only for encoding). | ++-------------------------+-----------------------------------------------+ | ``'surrogateescape'`` | Replace byte with surrogate U+DCxx, as defined| | | in :pep:`383`. | +-------------------------+-----------------------------------------------+ @@ -384,6 +394,9 @@ .. versionchanged:: 3.4 The ``'surrogatepass'`` error handlers now works with utf-16\* and utf-32\* codecs. +.. versionadded:: 3.4 + The ``'namereplace'`` error handler. + The set of allowed values can be extended via :meth:`register_error`. @@ -477,6 +490,8 @@ * ``'backslashreplace'`` Replace with backslashed escape sequences. + * ``'namereplace'`` Replace with ``\N{...}`` escape sequences. + The *errors* argument will be assigned to an attribute of the same name. Assigning to this attribute makes it possible to switch between different error handling strategies during the lifetime of the :class:`IncrementalEncoder` @@ -625,6 +640,8 @@ * ``'backslashreplace'`` Replace with backslashed escape sequences. + * ``'namereplace'`` Replace with ``\N{...}`` escape sequences. + The *errors* argument will be assigned to an attribute of the same name. Assigning to this attribute makes it possible to switch between different error handling strategies during the lifetime of the :class:`StreamWriter` object. diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -975,6 +975,9 @@ replaces unsupported characters with Python's backslashed escape sequences. + * ``'namereplace'`` (also only supported when writing) + replaces unsupported characters with ``\N{...}`` escape sequences. + .. index:: single: universal newlines; open() built-in function diff --git a/Doc/library/io.rst b/Doc/library/io.rst --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -827,9 +827,10 @@ errors can lead to data loss.) ``'replace'`` causes a replacement marker (such as ``'?'``) to be inserted where there is malformed data. When writing, ``'xmlcharrefreplace'`` (replace with the appropriate XML character - reference) or ``'backslashreplace'`` (replace with backslashed escape - sequences) can be used. Any other error handling name that has been - registered with :func:`codecs.register_error` is also valid. + reference), ``'backslashreplace'`` (replace with backslashed escape + sequences) or ``'namereplace'`` (replace with ``\N{...}`` escape sequences) + can be used. Any other error handling name that has been registered with + :func:`codecs.register_error` is also valid. .. index:: single: universal newlines; io.TextIOWrapper class diff --git a/Include/codecs.h b/Include/codecs.h --- a/Include/codecs.h +++ b/Include/codecs.h @@ -225,6 +225,9 @@ /* replace the unicode encode error with backslash escapes (\x, \u and \U) */ PyAPI_FUNC(PyObject *) PyCodec_BackslashReplaceErrors(PyObject *exc); +/* replace the unicode encode error with backslash escapes (\N, \x, \u and \U) */ +PyAPI_FUNC(PyObject *) PyCodec_NameReplaceErrors(PyObject *exc); + PyAPI_DATA(const char *) Py_hexdigits; #ifdef __cplusplus diff --git a/Lib/codecs.py b/Lib/codecs.py --- a/Lib/codecs.py +++ b/Lib/codecs.py @@ -22,6 +22,7 @@ "BOM_UTF32", "BOM_UTF32_LE", "BOM_UTF32_BE", "strict_errors", "ignore_errors", "replace_errors", "xmlcharrefreplace_errors", + "backslashreplace_errors", "namereplace_errors", "register_error", "lookup_error"] ### Constants @@ -1085,6 +1086,7 @@ replace_errors = lookup_error("replace") xmlcharrefreplace_errors = lookup_error("xmlcharrefreplace") backslashreplace_errors = lookup_error("backslashreplace") + namereplace_errors = lookup_error("namereplace") except LookupError: # In --disable-unicode builds, these error handler are missing strict_errors = None @@ -1092,6 +1094,7 @@ replace_errors = None xmlcharrefreplace_errors = None backslashreplace_errors = None + namereplace_errors = None # Tell modulefinder that using codecs probably needs the encodings # package diff --git a/Lib/test/test_codeccallbacks.py b/Lib/test/test_codeccallbacks.py --- a/Lib/test/test_codeccallbacks.py +++ b/Lib/test/test_codeccallbacks.py @@ -158,6 +158,22 @@ sout = b"a\xac\\u1234\xa4\\u8000\\U0010ffff" self.assertEqual(sin.encode("iso-8859-15", "backslashreplace"), sout) + def test_nameescape(self): + # Does the same as backslashescape, but prefers ``\N{...}`` escape + # sequences. + sin = "a\xac\u1234\u20ac\u8000\U0010ffff" + sout = (b'a\\N{NOT SIGN}\\N{ETHIOPIC SYLLABLE SEE}\\N{EURO SIGN}' + b'\\N{CJK UNIFIED IDEOGRAPH-8000}\\U0010ffff') + self.assertEqual(sin.encode("ascii", "namereplace"), sout) + + sout = (b'a\xac\\N{ETHIOPIC SYLLABLE SEE}\\N{EURO SIGN}' + b'\\N{CJK UNIFIED IDEOGRAPH-8000}\\U0010ffff') + self.assertEqual(sin.encode("latin-1", "namereplace"), sout) + + sout = (b'a\xac\\N{ETHIOPIC SYLLABLE SEE}\xa4' + b'\\N{CJK UNIFIED IDEOGRAPH-8000}\\U0010ffff') + self.assertEqual(sin.encode("iso-8859-15", "namereplace"), sout) + def test_decoding_callbacks(self): # This is a test for a decoding callback handler # that allows the decoding of the invalid sequence @@ -297,7 +313,7 @@ def test_longstrings(self): # test long strings to check for memory overflow problems errors = [ "strict", "ignore", "replace", "xmlcharrefreplace", - "backslashreplace"] + "backslashreplace", "namereplace"] # register the handlers under different names, # to prevent the codec from recognizing the name for err in errors: @@ -611,6 +627,81 @@ ("\\udfff", 1) ) + def test_badandgoodnamereplaceexceptions(self): + # "namereplace" complains about a non-exception passed in + self.assertRaises( + TypeError, + codecs.namereplace_errors, + 42 + ) + # "namereplace" complains about the wrong exception types + self.assertRaises( + TypeError, + codecs.namereplace_errors, + UnicodeError("ouch") + ) + # "namereplace" can only be used for encoding + self.assertRaises( + TypeError, + codecs.namereplace_errors, + UnicodeDecodeError("ascii", bytearray(b"\xff"), 0, 1, "ouch") + ) + self.assertRaises( + TypeError, + codecs.namereplace_errors, + UnicodeTranslateError("\u3042", 0, 1, "ouch") + ) + # Use the correct exception + self.assertEqual( + codecs.namereplace_errors( + UnicodeEncodeError("ascii", "\u3042", 0, 1, "ouch")), + ("\\N{HIRAGANA LETTER A}", 1) + ) + self.assertEqual( + codecs.namereplace_errors( + UnicodeEncodeError("ascii", "\x00", 0, 1, "ouch")), + ("\\x00", 1) + ) + self.assertEqual( + codecs.namereplace_errors( + UnicodeEncodeError("ascii", "\xff", 0, 1, "ouch")), + ("\\N{LATIN SMALL LETTER Y WITH DIAERESIS}", 1) + ) + self.assertEqual( + codecs.namereplace_errors( + UnicodeEncodeError("ascii", "\u0100", 0, 1, "ouch")), + ("\\N{LATIN CAPITAL LETTER A WITH MACRON}", 1) + ) + self.assertEqual( + codecs.namereplace_errors( + UnicodeEncodeError("ascii", "\uffff", 0, 1, "ouch")), + ("\\uffff", 1) + ) + if SIZEOF_WCHAR_T > 0: + self.assertEqual( + codecs.namereplace_errors( + UnicodeEncodeError("ascii", "\U00010000", + 0, 1, "ouch")), + ("\\N{LINEAR B SYLLABLE B008 A}", 1) + ) + self.assertEqual( + codecs.namereplace_errors( + UnicodeEncodeError("ascii", "\U0010ffff", + 0, 1, "ouch")), + ("\\U0010ffff", 1) + ) + # Lone surrogates (regardless of unicode width) + self.assertEqual( + codecs.namereplace_errors( + UnicodeEncodeError("ascii", "\ud800", 0, 1, "ouch")), + ("\\ud800", 1) + ) + self.assertEqual( + codecs.namereplace_errors( + UnicodeEncodeError("ascii", "\udfff", 0, 1, "ouch")), + ("\\udfff", 1) + ) + def test_badhandlerresults(self): results = ( 42, "foo", (1,2,3), ("foo", 1, 3), ("foo", None), ("foo",), ("foo", 1, 3), ("foo", None), ("foo",) ) encs = ("ascii", "latin-1", "iso-8859-1", "iso-8859-15") @@ -651,6 +742,10 @@ codecs.backslashreplace_errors, codecs.lookup_error("backslashreplace") ) + self.assertEqual( + codecs.namereplace_errors, + codecs.lookup_error("namereplace") + ) def test_unencodablereplacement(self): def unencrepl(exc): @@ -804,7 +899,8 @@ class D(dict): def __getitem__(self, key): raise ValueError - for err in ("strict", "replace", "xmlcharrefreplace", "backslashreplace", "test.posreturn"): + for err in ("strict", "replace", "xmlcharrefreplace", + "backslashreplace", "namereplace", "test.posreturn"): self.assertRaises(UnicodeError, codecs.charmap_encode, "\xff", err, {0xff: None}) self.assertRaises(ValueError, codecs.charmap_encode, "\xff", err, D()) self.assertRaises(TypeError, codecs.charmap_encode, "\xff", err, {0xff: 300}) 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 @@ -349,6 +349,8 @@ self.assertRaises(UnicodeEncodeError, "\ud800".encode, self.encoding) self.assertEqual("[\uDC80]".encode(self.encoding, "backslashreplace"), "[\\udc80]".encode(self.encoding)) + self.assertEqual("[\uDC80]".encode(self.encoding, "namereplace"), + "[\\udc80]".encode(self.encoding)) self.assertEqual("[\uDC80]".encode(self.encoding, "xmlcharrefreplace"), "[�]".encode(self.encoding)) self.assertEqual("[\uDC80]".encode(self.encoding, "ignore"), @@ -808,6 +810,7 @@ ('\udc80', 'ignore', b''), ('\udc80', 'replace', b'?'), ('\udc80', 'backslashreplace', b'\\udc80'), + ('\udc80', 'namereplace', b'\\udc80'), ('\udc80', 'surrogatepass', b'\xed\xb2\x80'), )) else: @@ -869,6 +872,8 @@ self.assertRaises(UnicodeDecodeError, b"\xed\xa0\x80".decode, "cp65001") self.assertEqual("[\uDC80]".encode("cp65001", "backslashreplace"), b'[\\udc80]') + self.assertEqual("[\uDC80]".encode("cp65001", "namereplace"), + b'[\\udc80]') self.assertEqual("[\uDC80]".encode("cp65001", "xmlcharrefreplace"), b'[�]') self.assertEqual("[\uDC80]".encode("cp65001", "surrogateescape"), @@ -2824,6 +2829,8 @@ ('[\xff]', 'replace', b'[y]'), ('[\u20ac]', 'replace', b'[?]'), ('[\xff]', 'backslashreplace', b'[\\xff]'), + ('[\xff]', 'namereplace', + b'[\\N{LATIN SMALL LETTER Y WITH DIAERESIS}]'), ('[\xff]', 'xmlcharrefreplace', b'[ÿ]'), ('\udcff', 'strict', None), ('[\udcff]', 'surrogateescape', b'[\xff]'), diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -191,6 +191,8 @@ Library ------- +- Issue #19676: Added the "namereplace" error handler. + - Issue #22788: Add *context* parameter to logging.handlers.HTTPHandler. - Issue #22921: Allow SSLContext to take the *hostname* parameter even if diff --git a/Python/codecs.c b/Python/codecs.c --- a/Python/codecs.c +++ b/Python/codecs.c @@ -9,6 +9,7 @@ ------------------------------------------------------------------------ */ #include "Python.h" +#include "ucnhash.h" #include const char *Py_hexdigits = "0123456789abcdef"; @@ -933,6 +934,97 @@ } } +static _PyUnicode_Name_CAPI *ucnhash_CAPI = NULL; +static int ucnhash_initialized = 0; + +PyObject *PyCodec_NameReplaceErrors(PyObject *exc) +{ + if (PyObject_IsInstance(exc, PyExc_UnicodeEncodeError)) { + PyObject *restuple; + PyObject *object; + Py_ssize_t i; + Py_ssize_t start; + Py_ssize_t end; + PyObject *res; + unsigned char *outp; + int ressize; + Py_UCS4 c; + char buffer[256]; /* NAME_MAXLEN */ + if (PyUnicodeEncodeError_GetStart(exc, &start)) + return NULL; + if (PyUnicodeEncodeError_GetEnd(exc, &end)) + return NULL; + if (!(object = PyUnicodeEncodeError_GetObject(exc))) + return NULL; + if (!ucnhash_initialized) { + /* load the unicode data module */ + ucnhash_CAPI = (_PyUnicode_Name_CAPI *)PyCapsule_Import( + PyUnicodeData_CAPSULE_NAME, 1); + ucnhash_initialized = 1; + } + for (i = start, ressize = 0; i < end; ++i) { + /* object is guaranteed to be "ready" */ + c = PyUnicode_READ_CHAR(object, i); + if (ucnhash_CAPI && + ucnhash_CAPI->getname(NULL, c, buffer, sizeof(buffer), 1)) { + ressize += 1+1+1+strlen(buffer)+1; + } + else if (c >= 0x10000) { + ressize += 1+1+8; + } + else if (c >= 0x100) { + ressize += 1+1+4; + } + else + ressize += 1+1+2; + } + res = PyUnicode_New(ressize, 127); + if (res==NULL) + return NULL; + for (i = start, outp = PyUnicode_1BYTE_DATA(res); + i < end; ++i) { + c = PyUnicode_READ_CHAR(object, i); + *outp++ = '\\'; + if (ucnhash_CAPI && + ucnhash_CAPI->getname(NULL, c, buffer, sizeof(buffer), 1)) { + *outp++ = 'N'; + *outp++ = '{'; + strcpy((char *)outp, buffer); + outp += strlen(buffer); + *outp++ = '}'; + continue; + } + if (c >= 0x00010000) { + *outp++ = 'U'; + *outp++ = Py_hexdigits[(c>>28)&0xf]; + *outp++ = Py_hexdigits[(c>>24)&0xf]; + *outp++ = Py_hexdigits[(c>>20)&0xf]; + *outp++ = Py_hexdigits[(c>>16)&0xf]; + *outp++ = Py_hexdigits[(c>>12)&0xf]; + *outp++ = Py_hexdigits[(c>>8)&0xf]; + } + else if (c >= 0x100) { + *outp++ = 'u'; + *outp++ = Py_hexdigits[(c>>12)&0xf]; + *outp++ = Py_hexdigits[(c>>8)&0xf]; + } + else + *outp++ = 'x'; + *outp++ = Py_hexdigits[(c>>4)&0xf]; + *outp++ = Py_hexdigits[c&0xf]; + } + + assert(_PyUnicode_CheckConsistency(res, 1)); + restuple = Py_BuildValue("(Nn)", res, end); + Py_DECREF(object); + return restuple; + } + else { + wrong_exception_type(exc); + return NULL; + } +} + #define ENC_UNKNOWN -1 #define ENC_UTF8 0 #define ENC_UTF16BE 1 @@ -1276,6 +1368,11 @@ return PyCodec_BackslashReplaceErrors(exc); } +static PyObject *namereplace_errors(PyObject *self, PyObject *exc) +{ + return PyCodec_NameReplaceErrors(exc); +} + static PyObject *surrogatepass_errors(PyObject *self, PyObject *exc) { return PyCodec_SurrogatePassErrors(exc); @@ -1346,6 +1443,17 @@ } }, { + "namereplace", + { + "namereplace_errors", + namereplace_errors, + METH_O, + PyDoc_STR("Implements the 'namereplace' error handling, " + "which replaces an unencodable character with a " + "\\N{...} escape sequence.") + } + }, + { "surrogatepass", { "surrogatepass", -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 25 17:25:02 2014 From: python-checkins at python.org (victor.stinner) Date: Tue, 25 Nov 2014 16:25:02 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogQ2xvc2VzICMyMjY4?= =?utf-8?q?5=2C_asyncio=3A_Set_the_transport_of_stdout_and_stderr_StreamRe?= =?utf-8?q?ader?= Message-ID: <20141125162457.116316.84886@psf.io> https://hg.python.org/cpython/rev/f75d40c02f0a changeset: 93582:f75d40c02f0a branch: 3.4 parent: 93576:268ceaa78cf9 user: Victor Stinner date: Tue Nov 25 17:20:33 2014 +0100 summary: Closes #22685, asyncio: Set the transport of stdout and stderr StreamReader objects in the SubprocessStreamProtocol. It allows to pause the transport to not buffer too much stdout or stderr data. files: Lib/asyncio/subprocess.py | 17 ++++- Lib/test/test_asyncio/test_subprocess.py | 32 ++++++++++++ 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/Lib/asyncio/subprocess.py b/Lib/asyncio/subprocess.py --- a/Lib/asyncio/subprocess.py +++ b/Lib/asyncio/subprocess.py @@ -41,15 +41,22 @@ def connection_made(self, transport): self._transport = transport - if transport.get_pipe_transport(1): + + stdout_transport = transport.get_pipe_transport(1) + if stdout_transport is not None: self.stdout = streams.StreamReader(limit=self._limit, loop=self._loop) - if transport.get_pipe_transport(2): + self.stdout.set_transport(stdout_transport) + + stderr_transport = transport.get_pipe_transport(2) + if stderr_transport is not None: self.stderr = streams.StreamReader(limit=self._limit, loop=self._loop) - stdin = transport.get_pipe_transport(0) - if stdin is not None: - self.stdin = streams.StreamWriter(stdin, + self.stderr.set_transport(stderr_transport) + + stdin_transport = transport.get_pipe_transport(0) + if stdin_transport is not None: + self.stdin = streams.StreamWriter(stdin_transport, protocol=self, reader=None, loop=self._loop) diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -4,6 +4,7 @@ import signal import sys import unittest +from unittest import mock from test import support if sys.platform != 'win32': from asyncio import unix_events @@ -161,6 +162,37 @@ self.loop.run_until_complete(proc.communicate(large_data)) self.loop.run_until_complete(proc.wait()) + def test_pause_reading(self): + @asyncio.coroutine + def test_pause_reading(): + limit = 100 + + code = '\n'.join(( + 'import sys', + 'sys.stdout.write("x" * %s)' % (limit * 2 + 1), + 'sys.stdout.flush()', + )) + proc = yield from asyncio.create_subprocess_exec( + sys.executable, '-c', code, + stdin=asyncio.subprocess.PIPE, + stdout=asyncio.subprocess.PIPE, + limit=limit, + loop=self.loop) + stdout_transport = proc._transport.get_pipe_transport(1) + stdout_transport.pause_reading = mock.Mock() + + yield from proc.wait() + + # The child process produced more than limit bytes of output, + # the stream reader transport should pause the protocol to not + # allocate too much memory. + return stdout_transport.pause_reading.called + + # Issue #22685: Ensure that the stream reader pauses the protocol + # when the child process produces too much data + called = self.loop.run_until_complete(test_pause_reading()) + self.assertTrue(called) + if sys.platform != 'win32': # Unix -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 25 17:25:06 2014 From: python-checkins at python.org (victor.stinner) Date: Tue, 25 Nov 2014 16:25:06 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_=28Merge_3=2E4=29_Closes_=2322685=2C_asyncio=3A_Set_the_?= =?utf-8?q?transport_of_stdout_and_stderr?= Message-ID: <20141125162457.126790.90473@psf.io> https://hg.python.org/cpython/rev/7da2288183d1 changeset: 93583:7da2288183d1 parent: 93581:32d08aacffe0 parent: 93582:f75d40c02f0a user: Victor Stinner date: Tue Nov 25 17:21:43 2014 +0100 summary: (Merge 3.4) Closes #22685, asyncio: Set the transport of stdout and stderr StreamReader objects in the SubprocessStreamProtocol. It allows to pause the transport to not buffer too much stdout or stderr data. files: Lib/asyncio/subprocess.py | 17 ++++- Lib/test/test_asyncio/test_subprocess.py | 32 ++++++++++++ 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/Lib/asyncio/subprocess.py b/Lib/asyncio/subprocess.py --- a/Lib/asyncio/subprocess.py +++ b/Lib/asyncio/subprocess.py @@ -41,15 +41,22 @@ def connection_made(self, transport): self._transport = transport - if transport.get_pipe_transport(1): + + stdout_transport = transport.get_pipe_transport(1) + if stdout_transport is not None: self.stdout = streams.StreamReader(limit=self._limit, loop=self._loop) - if transport.get_pipe_transport(2): + self.stdout.set_transport(stdout_transport) + + stderr_transport = transport.get_pipe_transport(2) + if stderr_transport is not None: self.stderr = streams.StreamReader(limit=self._limit, loop=self._loop) - stdin = transport.get_pipe_transport(0) - if stdin is not None: - self.stdin = streams.StreamWriter(stdin, + self.stderr.set_transport(stderr_transport) + + stdin_transport = transport.get_pipe_transport(0) + if stdin_transport is not None: + self.stdin = streams.StreamWriter(stdin_transport, protocol=self, reader=None, loop=self._loop) diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -4,6 +4,7 @@ import signal import sys import unittest +from unittest import mock from test import support if sys.platform != 'win32': from asyncio import unix_events @@ -161,6 +162,37 @@ self.loop.run_until_complete(proc.communicate(large_data)) self.loop.run_until_complete(proc.wait()) + def test_pause_reading(self): + @asyncio.coroutine + def test_pause_reading(): + limit = 100 + + code = '\n'.join(( + 'import sys', + 'sys.stdout.write("x" * %s)' % (limit * 2 + 1), + 'sys.stdout.flush()', + )) + proc = yield from asyncio.create_subprocess_exec( + sys.executable, '-c', code, + stdin=asyncio.subprocess.PIPE, + stdout=asyncio.subprocess.PIPE, + limit=limit, + loop=self.loop) + stdout_transport = proc._transport.get_pipe_transport(1) + stdout_transport.pause_reading = mock.Mock() + + yield from proc.wait() + + # The child process produced more than limit bytes of output, + # the stream reader transport should pause the protocol to not + # allocate too much memory. + return stdout_transport.pause_reading.called + + # Issue #22685: Ensure that the stream reader pauses the protocol + # when the child process produces too much data + called = self.loop.run_until_complete(test_pause_reading()) + self.assertTrue(called) + if sys.platform != 'win32': # Unix -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 25 17:59:11 2014 From: python-checkins at python.org (berker.peksag) Date: Tue, 25 Nov 2014 16:59:11 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2319676=3A_Tweak_do?= =?utf-8?q?cumentation_a_bit=2E?= Message-ID: <20141125165901.55111.1743@psf.io> https://hg.python.org/cpython/rev/b6fab008d63a changeset: 93584:b6fab008d63a user: Berker Peksag date: Tue Nov 25 18:59:20 2014 +0200 summary: Issue #19676: Tweak documentation a bit. * Updated version info to 3.5 * Fixed a markup error * Added a versionadded directive to namereplace_errors documentation files: Doc/c-api/codec.rst | 4 ++-- Doc/library/codecs.rst | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Doc/c-api/codec.rst b/Doc/c-api/codec.rst --- a/Doc/c-api/codec.rst +++ b/Doc/c-api/codec.rst @@ -118,6 +118,6 @@ .. c:function:: PyObject* PyCodec_NameReplaceErrors(PyObject *exc) - Replace the unicode encode error with `\N{...}` escapes. + Replace the unicode encode error with ``\N{...}`` escapes. - .. versionadded: 3.4 + .. versionadded:: 3.5 diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -239,6 +239,8 @@ Implements the ``namereplace`` error handling (for encoding only): the unencodable character is replaced by a ``\N{...}`` escape sequence. + .. versionadded:: 3.5 + To simplify working with encoded files or stream, the module also defines these utility functions: @@ -394,7 +396,7 @@ .. versionchanged:: 3.4 The ``'surrogatepass'`` error handlers now works with utf-16\* and utf-32\* codecs. -.. versionadded:: 3.4 +.. versionadded:: 3.5 The ``'namereplace'`` error handler. The set of allowed values can be extended via :meth:`register_error`. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 25 18:45:55 2014 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 25 Nov 2014 17:45:55 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Clarify_that_after_raising_Ru?= =?utf-8?q?ntimeError_a_generator_will_raise_StopIteration=2E?= Message-ID: <20141125174531.84285.36683@psf.io> https://hg.python.org/peps/rev/1522bae42b07 changeset: 5613:1522bae42b07 user: Guido van Rossum date: Tue Nov 25 09:24:47 2014 -0800 summary: Clarify that after raising RuntimeError a generator will raise StopIteration. files: pep-0479.txt | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -57,7 +57,7 @@ This affects the third outcome listed above, without altering any other effects. Furthermore, it only affects this outcome when the -exception raised is StopIteration (or a subclass thereof). +exception raised is ``StopIteration`` (or a subclass thereof). Note that the proposed replacement happens at the point where the exception is about to bubble out of the frame, i.e. after any @@ -66,6 +66,12 @@ not affected (the point being that ``StopIteration`` means that the generator terminated "normally", i.e. it did not raise an exception). +A subtle issue is what will happen if the caller, having caught the +``RuntimeError``, calls the generator object's ``__next__()`` method +again. The answer is that it from this point on it will raise +``StopIteration`` -- the behavior is the same as when any other +exception was raised by the generator. + Consequences for existing code ============================== -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Tue Nov 25 18:45:55 2014 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 25 Nov 2014 17:45:55 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Updates_and_figures_for_PEP_4?= =?utf-8?q?58_and_PEP_480_by_Vladimir_Diaz=2E?= Message-ID: <20141125174532.69787.71995@psf.io> https://hg.python.org/peps/rev/59259922c4f2 changeset: 5614:59259922c4f2 user: Guido van Rossum date: Tue Nov 25 09:45:28 2014 -0800 summary: Updates and figures for PEP 458 and PEP 480 by Vladimir Diaz. files: pep-0458.txt | 58 ++++++++++++++---------------- pep-0458/figure1.png | Bin pep-0458/figure2.png | Bin pep-0458/figure3.png | Bin pep-0480.txt | 4 +- pep-0480/figure1.png | Bin 6 files changed, 30 insertions(+), 32 deletions(-) diff --git a/pep-0458.txt b/pep-0458.txt --- a/pep-0458.txt +++ b/pep-0458.txt @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Trishank Karthik Kuppusamy , - Vladimir Diaz , + Vladimir Diaz , Donald Stufft , Justin Cappos BDFL-Delegate: Richard Jones Discussions-To: DistUtils mailing list @@ -44,12 +44,11 @@ documentation`__, which exists for this purpose. Support for project distributions that are signed by developers (maximum security model) is also not discussed in this PEP, but is outlined in the appendix as a possible future -extension and covered in detail in PEP X [VD: Link to PEP once it is -completed]. The PEP X extension focuses on the maximum security model, which -requires more PyPI administrative work (none by clients), but it also proposes -an easy-to-use key management solution for developers, how to interface with a -potential future build farm on PyPI infrastructure, and discusses the -feasibility of end-to-end signing. +extension and covered in detail in PEP 480 [26]_. The PEP 480 extension +focuses on the maximum security model, which requires more PyPI administrative +work (none by clients), but it also proposes an easy-to-use key management +solution for developers, how to interface with a potential future build farm on +PyPI infrastructure, and discusses the feasibility of end-to-end signing. __ https://github.com/theupdateframework/tuf/tree/develop/tuf/client#updaterpy @@ -164,9 +163,8 @@ * Metadata: Metadata are signed files that describe roles, other metadata, and target files. -* Repository: A repository is a resource compromised of named metadata and - target files. Clients request metadata and target files stored on a - repository. +* Repository: A repository is a resource comprised of named metadata and target + files. Clients request metadata and target files stored on a repository. * Consistent snapshot: A set of TUF metadata and PyPI targets that capture the complete state of all projects on PyPI as they existed at some fixed point in @@ -302,7 +300,7 @@ responsibilities without exception. Figure 1 provides a table of the roles used in TUF. -.. image:: figure1.png +.. image:: pep-0458/figure1.png Figure 1: An overview of the TUF roles. @@ -322,7 +320,7 @@ trusted to sign for files available on PyPI. The next two sections cover the details of signing repository files and the types of keys used for each role. -.. image:: figure2.png +.. image:: pep-0458/figure2.png Figure 2: An overview of the role metadata available on PyPI. @@ -743,10 +741,9 @@ Finally, a compromise of the PyPI infrastructure MAY introduce malicious updates to *bins* projects because the keys for these roles are online. The -maximum security model discussed in the appendix addresses this issue. PEP X -[VD: Link to PEP once it is completed] also covers the maximum security model -and goes into more detail on generating developer keys and signing uploaded -distributions. +maximum security model discussed in the appendix addresses this issue. PEP 480 +also covers the maximum security model and goes into more detail on generating +developer keys and signing uploaded distributions. In the Event of a Key Compromise @@ -908,10 +905,10 @@ excluded from this PEP. Although both improve PyPI's ability to survive a repository compromise and allow developers to sign their distributions, they have been postponed for review as a potential future extension to PEP 458. PEP -X [VD: Link to PEP once it is completed], which discusses the extension in -detail, is available for review to those developers interested in the -end-to-end signing option. The maximum security model and end-to-end signing -are briefly covered in subsections that follow. +480 [26]_, which discusses the extension in detail, is available for review to +those developers interested in the end-to-end signing option. The maximum +security model and end-to-end signing are briefly covered in subsections that +follow. There are several reasons for not initially supporting the features discussed in this section: @@ -960,7 +957,7 @@ packages in the minimum security model, but not in the maximum model without also compromising a developer's key. -.. image:: figure3.png +.. image:: pep-0458/figure3.png Figure 3: An overview of the metadata layout in the maximum security model. The maximum security model supports continuous delivery and survivable key @@ -975,15 +972,15 @@ clients (they sign the metadata for this part of the process), and developers can sign the distributions that they upload. -PEP X [VD: Link to PEP once it is completed] discusses the tools available to -developers who sign the distributions that they upload to PyPI. To summarize -PEP X, developers generate cryptographic keys and sign metadata in some -automated fashion, where the metadata includes the information required to -verify the authenticity of the distribution. The metadata is then uploaded to -PyPI by the client, where it will be available for download by package managers -such as pip (i.e., package managers that support TUF metadata). The entire -process is transparent to clients (using a package manager that supports TUF) -who download distributions from PyPI. +PEP 480 [26]_ discusses the tools available to developers who sign the +distributions that they upload to PyPI. To summarize PEP 480, developers +generate cryptographic keys and sign metadata in some automated fashion, where +the metadata includes the information required to verify the authenticity of +the distribution. The metadata is then uploaded to PyPI by the client, where +it will be available for download by package managers such as pip (i.e., +package managers that support TUF metadata). The entire process is transparent +to clients (using a package manager that supports TUF) who download +distributions from PyPI. Appendix C: PEP 470 and Projects Hosted Externally @@ -1065,6 +1062,7 @@ .. [23] https://www.openssl.org/ .. [24] https://pypi.python.org/pypi/pycrypto .. [25] http://ed25519.cr.yp.to/ +.. [26] https://www.python.org/dev/peps/pep-0480/ Acknowledgements ================ diff --git a/pep-0458/figure1.png b/pep-0458/figure1.png new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b08801b5841cd35da8f719549e2c5377793e35f1 GIT binary patch [stripped] diff --git a/pep-0458/figure2.png b/pep-0458/figure2.png new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cb535f631bcb8277ef9c3e4e4bc4f9a0765b5519 GIT binary patch [stripped] diff --git a/pep-0458/figure3.png b/pep-0458/figure3.png new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a31edf1702d26556382973306a8f216e7f304418 GIT binary patch [stripped] diff --git a/pep-0480.txt b/pep-0480.txt --- a/pep-0480.txt +++ b/pep-0480.txt @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Trishank Karthik Kuppusamy , - Vladimir Diaz , Donald Stufft , + Vladimir Diaz , Donald Stufft , Justin Cappos BDFL-Delegate: Richard Jones Discussions-To: DistUtils mailing list @@ -186,7 +186,7 @@ packages in the minimum security model, but not in the maximum model, without also compromising a developer's key. -.. image:: figure1.png +.. image:: pep-0480/figure1.png Figure 1: An overview of the metadata layout in the maximum security model. The maximum security model supports continuous delivery and survivable key diff --git a/pep-0480/figure1.png b/pep-0480/figure1.png new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a31edf1702d26556382973306a8f216e7f304418 GIT binary patch [stripped] -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Tue Nov 25 19:07:53 2014 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 25 Nov 2014 18:07:53 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Clarify_what_happens_on_g=2Et?= =?utf-8?q?hrow=28StopIteration=29=2E?= Message-ID: <20141125180739.126774.35289@psf.io> https://hg.python.org/peps/rev/2da36288f80b changeset: 5615:2da36288f80b user: Guido van Rossum date: Tue Nov 25 10:07:35 2014 -0800 summary: Clarify what happens on g.throw(StopIteration). files: pep-0479.txt | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -72,6 +72,12 @@ ``StopIteration`` -- the behavior is the same as when any other exception was raised by the generator. +Another logical consequence of the proposal: if somone uses +``g.throw(StopIteration)`` to throw a ``StopIteration`` exception into +a generator, if the generator doesn't catch it (which it could do +using a ``try/except`` around the ``yield``), it will be transformed +into ``RuntimeError``. + Consequences for existing code ============================== -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Tue Nov 25 21:54:58 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 25 Nov 2014 20:54:58 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_remove_incorre?= =?utf-8?q?ct_plural?= Message-ID: <20141125205454.116308.43694@psf.io> https://hg.python.org/cpython/rev/0551b8c66b91 changeset: 93585:0551b8c66b91 branch: 2.7 parent: 93580:28fecaa8a74c user: Benjamin Peterson date: Tue Nov 25 14:54:45 2014 -0600 summary: remove incorrect plural files: Doc/library/re.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/re.rst b/Doc/library/re.rst --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -366,7 +366,7 @@ database. ``\S`` - When the :const:`UNICODE` flags is not specified, matches any non-whitespace + When the :const:`UNICODE` flag is not specified, matches any non-whitespace character; this is equivalent to the set ``[^ \t\n\r\f\v]`` The :const:`LOCALE` flag has no extra effect on non-whitespace match. If :const:`UNICODE` is set, then any character not marked as space in the -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 25 22:17:21 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 25 Nov 2014 21:17:21 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogZG9uJ3QgZmFpbCB0?= =?utf-8?q?ests_when_www=2Epython=2Eorg_can=27t_be_validated_by_the_system?= Message-ID: <20141125211714.84281.4592@psf.io> https://hg.python.org/cpython/rev/2e4888fa8b60 changeset: 93586:2e4888fa8b60 branch: 2.7 user: Benjamin Peterson date: Tue Nov 25 15:16:55 2014 -0600 summary: don't fail tests when www.python.org can't be validated by the system files: Lib/test/test_httplib.py | 4 +--- Lib/test/test_robotparser.py | 5 +++-- Lib/test/test_support.py | 13 +++++++++++++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -551,12 +551,10 @@ resp = h.getresponse() self.assertIn('nginx', resp.getheader('server')) + @test_support.system_must_validate_cert def test_networked_trusted_by_default_cert(self): # Default settings: requires a valid cert from a trusted CA test_support.requires('network') - if test_support.verbose: - import ssl - print(ssl._create_default_https_context().get_ca_certs()) with test_support.transient_internet('www.python.org'): h = httplib.HTTPSConnection('www.python.org', 443) h.request('GET', '/') diff --git a/Lib/test/test_robotparser.py b/Lib/test/test_robotparser.py --- a/Lib/test/test_robotparser.py +++ b/Lib/test/test_robotparser.py @@ -276,14 +276,15 @@ self.assertEqual(parser.can_fetch("*", robots_url), False) @unittest.skipUnless(HAVE_HTTPS, 'need SSL support to download license') + @test_support.system_must_validate_cert def testPythonOrg(self): test_support.requires('network') with test_support.transient_internet('www.python.org'): parser = robotparser.RobotFileParser( - "http://www.python.org/robots.txt") + "https://www.python.org/robots.txt") parser.read() self.assertTrue( - parser.can_fetch("*", "http://www.python.org/robots.txt")) + parser.can_fetch("*", "https://www.python.org/robots.txt")) def test_main(): 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 @@ -481,6 +481,19 @@ IPV6_ENABLED = _is_ipv6_enabled() +def system_must_validate_cert(f): + """Skip the test on TLS certificate validation failures.""" + @functools.wraps(f) + def dec(*args, **kwargs): + try: + f(*args, **kwargs) + except IOError as e: + if e.reason == "CERTIFICATE_VERIFY_FAILED": + raise unittest.SkipTest("system does not contain " + "necessary certificates") + raise + return dec + FUZZ = 1e-6 def fcmp(x, y): # fuzzy comparison function -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 25 22:44:14 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 25 Nov 2014 21:44:14 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_handle_errors_?= =?utf-8?q?without_a_reason_attribute?= Message-ID: <20141125214413.126768.89938@psf.io> https://hg.python.org/cpython/rev/8ca79131ca65 changeset: 93587:8ca79131ca65 branch: 2.7 user: Benjamin Peterson date: Tue Nov 25 15:43:58 2014 -0600 summary: handle errors without a reason attribute files: Lib/test/test_support.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) 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 @@ -488,7 +488,7 @@ try: f(*args, **kwargs) except IOError as e: - if e.reason == "CERTIFICATE_VERIFY_FAILED": + if getattr(e, "reason", "") == "CERTIFICATE_VERIFY_FAILED": raise unittest.SkipTest("system does not contain " "necessary certificates") raise -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Tue Nov 25 23:12:45 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 25 Nov 2014 22:12:45 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_use_more_ugly_?= =?utf-8?q?but_hopefully_more_robust_method?= Message-ID: <20141125221242.69779.4318@psf.io> https://hg.python.org/cpython/rev/c34ac8c16af3 changeset: 93588:c34ac8c16af3 branch: 2.7 user: Benjamin Peterson date: Tue Nov 25 16:12:32 2014 -0600 summary: use more ugly but hopefully more robust method files: Lib/test/test_support.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) 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 @@ -488,7 +488,7 @@ try: f(*args, **kwargs) except IOError as e: - if getattr(e, "reason", "") == "CERTIFICATE_VERIFY_FAILED": + if "CERTIFICATE_VERIFY_FAILED" in str(e): raise unittest.SkipTest("system does not contain " "necessary certificates") raise -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 00:04:40 2014 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 25 Nov 2014 23:04:40 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Move_PEP_480_figure_out_of_su?= =?utf-8?q?bdir_--_that_does_not_work_on_python=2Eorg=2E?= Message-ID: <20141125230439.126764.35826@psf.io> https://hg.python.org/peps/rev/ca6abc65224d changeset: 5616:ca6abc65224d user: Guido van Rossum date: Tue Nov 25 15:04:35 2014 -0800 summary: Move PEP 480 figure out of subdir -- that does not work on python.org. files: pep-0480/figure1.png | 0 pep-0480.txt | 2 +- 2 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0480/figure1.png b/pep-0480-1.png rename from pep-0480/figure1.png rename to pep-0480-1.png diff --git a/pep-0480.txt b/pep-0480.txt --- a/pep-0480.txt +++ b/pep-0480.txt @@ -186,7 +186,7 @@ packages in the minimum security model, but not in the maximum model, without also compromising a developer's key. -.. image:: pep-0480/figure1.png +.. image:: pep-0480-1.png Figure 1: An overview of the metadata layout in the maximum security model. The maximum security model supports continuous delivery and survivable key -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Wed Nov 26 00:37:42 2014 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 25 Nov 2014 23:37:42 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_disable_tests_?= =?utf-8?q?that_always_fail_on_windows_=28=2322943=29?= Message-ID: <20141125233719.84291.97223@psf.io> https://hg.python.org/cpython/rev/e5ed983bc784 changeset: 93589:e5ed983bc784 branch: 2.7 user: Benjamin Peterson date: Tue Nov 25 17:37:09 2014 -0600 summary: disable tests that always fail on windows (#22943) files: Lib/bsddb/test/test_queue.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/bsddb/test/test_queue.py b/Lib/bsddb/test/test_queue.py --- a/Lib/bsddb/test/test_queue.py +++ b/Lib/bsddb/test/test_queue.py @@ -10,6 +10,7 @@ #---------------------------------------------------------------------- + at unittest.skip("fails on Windows; see issue 22943") class SimpleQueueTestCase(unittest.TestCase): def setUp(self): self.filename = get_new_database_path() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 01:06:07 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 26 Nov 2014 00:06:07 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogZG9uJ3QgZmFpbCB0?= =?utf-8?q?ests_when_www=2Epython=2Eorg_can=27t_be_validated_by_the_system?= Message-ID: <20141126000551.69793.65795@psf.io> https://hg.python.org/cpython/rev/ca7d00b9d425 changeset: 93590:ca7d00b9d425 branch: 3.4 parent: 93582:f75d40c02f0a user: Benjamin Peterson date: Tue Nov 25 15:16:55 2014 -0600 summary: don't fail tests when www.python.org can't be validated by the system files: Lib/test/support/__init__.py | 12 ++++++++++++ Lib/test/test_httplib.py | 1 + 2 files changed, 13 insertions(+), 0 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -691,6 +691,18 @@ IPV6_ENABLED = _is_ipv6_enabled() +def system_must_validate_cert(f): + """Skip the test on TLS certificate validation failures.""" + @functools.wraps(f) + def dec(*args, **kwargs): + try: + f(*args, **kwargs) + except IOError as e: + if e.reason == "CERTIFICATE_VERIFY_FAILED": + raise unittest.SkipTest("system does not contain " + "necessary certificates") + raise + return dec # A constant likely larger than the underlying OS pipe buffer size, to # make writes blocking. diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -794,6 +794,7 @@ resp = h.getresponse() self.assertIn('nginx', resp.getheader('server')) + @support.system_must_validate_cert def test_networked_trusted_by_default_cert(self): # Default settings: requires a valid cert from a trusted CA support.requires('network') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 01:06:06 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 26 Nov 2014 00:06:06 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_handle_errors_?= =?utf-8?q?without_a_reason_attribute?= Message-ID: <20141126000552.55123.63398@psf.io> https://hg.python.org/cpython/rev/e635c3ba75c8 changeset: 93591:e635c3ba75c8 branch: 3.4 user: Benjamin Peterson date: Tue Nov 25 15:43:58 2014 -0600 summary: handle errors without a reason attribute files: Lib/test/support/__init__.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -698,7 +698,7 @@ try: f(*args, **kwargs) except IOError as e: - if e.reason == "CERTIFICATE_VERIFY_FAILED": + if "CERTIFICATE_VERIFY_FAILED" in str(e): raise unittest.SkipTest("system does not contain " "necessary certificates") raise -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 01:06:07 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 26 Nov 2014 00:06:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20141126000552.116332.80719@psf.io> https://hg.python.org/cpython/rev/81b5268efff6 changeset: 93592:81b5268efff6 parent: 93584:b6fab008d63a parent: 93591:e635c3ba75c8 user: Benjamin Peterson date: Tue Nov 25 18:05:40 2014 -0600 summary: merge 3.4 files: Lib/test/support/__init__.py | 12 ++++++++++++ Lib/test/test_httplib.py | 1 + 2 files changed, 13 insertions(+), 0 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -691,6 +691,18 @@ IPV6_ENABLED = _is_ipv6_enabled() +def system_must_validate_cert(f): + """Skip the test on TLS certificate validation failures.""" + @functools.wraps(f) + def dec(*args, **kwargs): + try: + f(*args, **kwargs) + except IOError as e: + if "CERTIFICATE_VERIFY_FAILED" in str(e): + raise unittest.SkipTest("system does not contain " + "necessary certificates") + raise + return dec # A constant likely larger than the underlying OS pipe buffer size, to # make writes blocking. diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -1028,6 +1028,7 @@ resp = h.getresponse() self.assertIn('nginx', resp.getheader('server')) + @support.system_must_validate_cert def test_networked_trusted_by_default_cert(self): # Default settings: requires a valid cert from a trusted CA support.requires('network') -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 01:28:51 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 26 Nov 2014 00:28:51 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Added_tag_v2?= =?utf-8?q?=2E7=2E9rc1_for_changeset_40eada278702?= Message-ID: <20141126002849.84299.16209@psf.io> https://hg.python.org/cpython/rev/080dba0e66e4 changeset: 93595:080dba0e66e4 branch: 2.7 user: Benjamin Peterson date: Tue Nov 25 18:27:39 2014 -0600 summary: Added tag v2.7.9rc1 for changeset 40eada278702 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -166,3 +166,4 @@ e32e3a9f390212463c22509d0f9aead8051cee63 v2.7.7rc1 f89216059edf77660ef1eb2a98e88352551da1d6 v2.7.7 ee879c0ffa11caaa34bf01537e1c4411dd948552 v2.7.8 +40eada278702349a2b2f334aa9d91fa7090ea1e3 v2.7.9rc1 -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 01:28:51 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 26 Nov 2014 00:28:51 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogMi43LjlyYzE=?= Message-ID: <20141126002848.84285.39993@psf.io> https://hg.python.org/cpython/rev/40eada278702 changeset: 93594:40eada278702 branch: 2.7 tag: v2.7.9rc1 user: Benjamin Peterson date: Tue Nov 25 18:27:24 2014 -0600 summary: 2.7.9rc1 files: Include/patchlevel.h | 8 ++++---- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/NEWS | 8 ++++---- Misc/RPM/python-2.7.spec | 2 +- README | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -22,12 +22,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 2 #define PY_MINOR_VERSION 7 -#define PY_MICRO_VERSION 8 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL -#define PY_RELEASE_SERIAL 0 +#define PY_MICRO_VERSION 9 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA +#define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "2.7.8+" +#define PY_VERSION "2.7.9rc1" /*--end constants--*/ /* Subversion Revision number of this file (not of the repository). Empty diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -15,5 +15,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "2.7.8" +__version__ = "2.7.9rc1" #--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 = "2.7.8" +IDLE_VERSION = "2.7.9rc1" 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 2.7.9? -========================== - -*Release date: XXXX-XX-XX* +What's New in Python 2.7.9 release candidate 1? +=============================================== + +*Release date: 2014-11-25* Core and Builtins ----------------- diff --git a/Misc/RPM/python-2.7.spec b/Misc/RPM/python-2.7.spec --- a/Misc/RPM/python-2.7.spec +++ b/Misc/RPM/python-2.7.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 2.7.8 +%define version 2.7.9rc1 %define libvers 2.7 #--end constants-- %define release 1pydotorg diff --git a/README b/README --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Python version 2.7.8 +This is Python version 2.7.9 ============================ Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 01:28:48 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 26 Nov 2014 00:28:48 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_update_pydoc-t?= =?utf-8?q?opics?= Message-ID: <20141126002848.116326.21704@psf.io> https://hg.python.org/cpython/rev/9f11ee6aa006 changeset: 93593:9f11ee6aa006 branch: 2.7 parent: 93589:e5ed983bc784 user: Benjamin Peterson date: Tue Nov 25 18:25:06 2014 -0600 summary: update pydoc-topics files: Lib/pydoc_data/topics.py | 159 +++++++++++++------------- 1 files changed, 80 insertions(+), 79 deletions(-) diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,79 +1,80 @@ -# Autogenerated by Sphinx on Sun Jun 29 18:55:25 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\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 is recursively defined as\nfollows.\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\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`` statement in the\n current code block: the name is bound to the object in the current\n local namespace.\n\n * Otherwise: the name is bound to the object in the current global\n namespace.\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 a plain integer. If it is negative, the\n sequence\'s length is added to it. The resulting value must be a\n nonnegative integer less than the sequence\'s length, and the\n sequence is asked to assign the assigned object to its item with\n that index. If the index is out of range, ``IndexError`` is raised\n (assignment to a subscripted sequence cannot add new items to a\n 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* 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 (small) integers. If either\n 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\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 literals and various numeric literals:\n\n literal ::= stringliteral | integer | longinteger\n | floatnumber | imagnumber\n\nEvaluation of a literal yields an object of the given type (string,\ninteger, long integer, floating point number, complex number) with the\ngiven value. The value may be approximated in the case of floating\npoint and imaginary (complex) literals. See section *Literals* for\ndetails.\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 in new-style classes.\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 not simply execute ``self.name = value`` --- this would\n cause a recursive call to itself. Instead, it should insert the\n value in the dictionary of instance attributes, e.g.,\n ``self.__dict__[name] = value``. For new-style classes, rather\n than accessing the instance dictionary, it should call the base\n 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\n\nMore attribute access for new-style classes\n===========================================\n\nThe following methods only apply to new-style classes.\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 for new-style\n classes*.\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. Note that descriptors are only invoked for new\nstyle objects or classes (ones that subclass ``object()`` or\n``type()``).\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 a new-style object instance, ``a.x`` is transformed\n into the call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a new-style class, ``A.x`` is transformed into the\n call: ``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 both old and new-style classes have a\ndictionary for attribute storage. This wastes space for objects\nhaving very few instance variables. The space consumption can become\nacute when creating large numbers of instances.\n\nThe default can be overridden by defining *__slots__* in a new-style\nclass definition. The *__slots__* declaration takes a sequence of\ninstance variables and reserves just enough space in each instance to\nhold a value for each variable. Space is saved because *__dict__* is\nnot created for each instance.\n\n__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 new-style class, *__slots__* reserves space for the declared\n variables and prevents the automatic creation of *__dict__* and\n *__weakref__* for each instance.\n\n New in version 2.2.\n\nNotes on using *__slots__*\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 Changed in version 2.3: Previously, adding ``\'__dict__\'`` to the\n *__slots__* declaration would not enable the assignment of new\n attributes not specifically listed in the sequence of instance\n variable names.\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 Changed in version 2.3: Previously, adding ``\'__weakref__\'`` to the\n *__slots__* declaration would not enable support for weak\n references.\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 ``long``, ``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 Changed in version 2.6: Previously, *__class__* assignment raised an\n error if either new or old class had *__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, e.g., a module, list, or an instance. This\nobject is then asked to produce the attribute whose name is the\nidentifier. If this attribute is not available, the exception\n``AttributeError`` is raised. Otherwise, the type and value of the\nobject produced is determined by the object. Multiple evaluations of\nthe same attribute reference 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 (plain or long) and the other must be a sequence.\nIn the former case, the numbers are converted to a common type and\nthen multiplied together. In the latter case, sequence repetition is\nperformed; a negative 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. Plain or long integer division yields an\ninteger of the same type; the result is that of mathematical division\nwith the \'floor\' function applied to the result. Division by zero\nraises 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 [2].\n\nThe integer division and modulo operators are connected by the\nfollowing identity: ``x == (x/y)*y + (x%y)``. Integer division and\nmodulo are also connected with the built-in function ``divmod()``:\n``divmod(x, y) == (x/y, x%y)``. These identities don\'t hold for\nfloating point numbers; there similar identities hold approximately\nwhere ``x/y`` is replaced by ``floor(x/y)`` or ``floor(x/y) - 1`` [3].\n\nIn addition to performing the modulo operation on numbers, the ``%``\noperator is also overloaded by string and unicode objects to perform\nstring formatting (also known as interpolation). The syntax for string\nformatting is described in the Python Library Reference, section\n*String Formatting Operations*.\n\nDeprecated since version 2.3: The floor division operator, the modulo\noperator, and the ``divmod()`` function are no longer defined for\ncomplex numbers. Instead, convert to a floating point number using\nthe ``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 plain or long integers. The arguments are converted to a common\ntype.\n\nThe ``^`` operator yields the bitwise XOR (exclusive OR) of its\narguments, which must be plain or long integers. The arguments are\nconverted to a common type.\n\nThe ``|`` operator yields the bitwise (inclusive) OR of its arguments,\nwhich must be plain or long integers. The arguments are converted to\na common type.\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 ``func_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`` statement or the built-in ``eval()``\nfunction.\n\nSee *The standard type hierarchy* for more information.\n', - 'bltin-ellipsis-object': '\nThe Ellipsis Object\n*******************\n\nThis object is used by extended slice notation (see *Slicings*). It\nsupports no special operations. There is exactly one ellipsis object,\nnamed ``Ellipsis`` (a built-in name).\n\nIt is written as ``Ellipsis``. When in a subscript, it can also be\nwritten as ``...``, for example ``seq[...]``.\n', - 'bltin-null-object': "\nThe Null Object\n***************\n\nThis object is returned by functions that don't explicitly return a\nvalue. It supports no special operations. There is exactly one null\nobject, named ``None`` (a built-in name).\n\nIt is written as ``None``.\n", - 'bltin-type-objects': "\nType Objects\n************\n\nType objects represent the various object types. An object's type is\naccessed by the built-in function ``type()``. There are no special\noperations on types. The standard module ``types`` defines names for\nall standard built-in types.\n\nTypes are written like this: ````.\n", - 'booleans': '\nBoolean operations\n******************\n\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. (See the ``__nonzero__()`` special method for a way to\nchange this.)\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 [","]\n | expression genexpr_for] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," "**" expression]\n | "*" expression ["," "*" expression] ["," "**" 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 certain class instances\nthemselves are callable; extensions may define additional callable\nobject types). All argument expressions are evaluated before the call\nis attempted. Please refer to section *Function definitions* for the\nsyntax 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. Formal parameters using the syntax ``(sublist)`` cannot be\nused as keyword argument names; the outermost sublist corresponds to a\nsingle unnamed argument slot, and the argument value is assigned to\nthe sublist using the usual tuple assignment rules after all other\nparameter processing is done.\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 ::= "class" classname [inheritance] ":" suite\n inheritance ::= "(" [expression_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. It first evaluates the\ninheritance list, if present. Each item in the inheritance list\nshould evaluate to a class object or class type which allows\nsubclassing. The class\'s suite is then executed in a new execution\nframe (see section *Naming and binding*), using a newly created local\nnamespace and the original global namespace. (Usually, the suite\ncontains only function definitions.) When the class\'s suite finishes\nexecution, its execution frame is discarded but its local namespace is\nsaved. [4] A class object is then created using the inheritance list\nfor the base classes and the saved local namespace for the attribute\ndictionary. The class name is bound to this class object in the\noriginal local namespace.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass variables; they are shared by all instances. To create instance\nvariables, they can be set in a method with ``self.name = value``.\nBoth class and instance variables are accessible through the notation\n"``self.name``", and an instance variable hides a class variable with\nthe same name when accessed in this way. Class variables can be used\nas defaults for instance variables, but using mutable values there can\nlead to unexpected results. For *new-style class*es, descriptors can\nbe used to create instance variables with different implementation\ndetails.\n\nClass definitions, like function definitions, may be wrapped by one or\nmore *decorator* expressions. The evaluation rules for the decorator\nexpressions are the same as for functions. The result must be a class\nobject, which is then bound to the class name.\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack 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 forms ``<>`` and ``!=`` are equivalent; for consistency with C,\n``!=`` is preferred; where ``!=`` is mentioned below ``<>`` is also\naccepted. The ``<>`` spelling is considered obsolescent.\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,\nobjects of different types *always* compare unequal, and are ordered\nconsistently but arbitrarily. You can control comparison behavior of\nobjects of non-built-in types by defining a ``__cmp__`` method or rich\ncomparison methods like ``__gt__``, described in section *Special\nmethod names*.\n\n(This unusual definition of comparison was used to simplify the\ndefinition of operations like sorting and the ``in`` and ``not in``\noperators. In the future, the comparison rules for objects of\ndifferent types are likely to change.)\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* Strings are compared lexicographically using the numeric equivalents\n (the result of the built-in function ``ord()``) of their characters.\n Unicode and 8-bit strings are fully interoperable in this behavior.\n [4]\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, ``cmp([1,2,x], [1,2,y])`` returns\n the same as ``cmp(x,y)``. If the corresponding element does not\n exist, the shorter sequence is ordered first (for example, ``[1,2] <\n [1,2,3]``).\n\n* Mappings (dictionaries) compare equal if and only if their sorted\n (key, value) lists compare equal. [5] Outcomes other than equality\n are resolved consistently, but are not otherwise defined. [6]\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\nThe operators ``in`` and ``not in`` test for collection membership.\n``x in s`` evaluates to true if *x* is a member of the collection *s*,\nand false otherwise. ``x not in s`` returns the negation of ``x in\ns``. The collection membership test has traditionally been bound to\nsequences; an object is a member of a collection if the collection is\na sequence and contains an element equal to that object. However, it\nmake sense for many other object types to support membership tests\nwithout being a sequence. In particular, dictionaries (for keys) and\nsets support membership testing.\n\nFor the list and tuple types, ``x in y`` is true if and only if there\nexists an index *i* such that ``x == y[i]`` is true.\n\nFor the Unicode and string types, ``x in y`` is true if and only if\n*x* is a substring of *y*. An equivalent test is ``y.find(x) != -1``.\nNote, *x* and *y* need not be the same type; consequently, ``u\'ab\' in\n\'abc\'`` will return ``True``. Empty strings are always considered to\nbe a substring of any other string, so ``"" in "abc"`` will return\n``True``.\n\nChanged in version 2.3: Previously, *x* was required to be a string of\nlength ``1``.\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. [7]\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. Function and class\ndefinitions are also syntactically compound 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`` statements 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 | decorated\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, and then the suite is executed. When the items are\nexhausted (which is immediately when the sequence is empty), the suite\nin 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``\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\nThe target list is not deleted when the loop is finished, but if the\nsequence is empty, it will not have been assigned to at all by the\nloop. Hint: the built-in function ``range()`` returns a sequence of\nintegers suitable to emulate the effect of Pascal\'s ``for i := a to b\ndo``; e.g., ``range(3)`` returns the list ``[0, 1, 2]``.\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 internal\n counter is used to keep track of which item is used next, and this\n is incremented on each iteration. When this counter has reached the\n length of the sequence the loop terminates. This means that if the\n suite deletes the current (or a previous) item from the sequence,\n the next item will be skipped (since it gets the index of the\n 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\nChanged in version 2.5: In previous versions of Python,\n``try``...``except``...``finally`` did not work. ``try``...``except``\nhad to be nested in ``try``...``finally``.\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 in that except clause, if present, and the except\nclause\'s suite is executed. All except clauses must have an\nexecutable block. When the end of this block is reached, execution\ncontinues normally after the entire try statement. (This means that\nif two nested handlers exist for the same exception, and the exception\noccurs in the try clause of the inner handler, the outer handler will\nnot handle the exception.)\n\nBefore an except clause\'s suite is executed, details about the\nexception are assigned to three variables in the ``sys`` module:\n``sys.exc_type`` receives the object identifying the exception;\n``sys.exc_value`` receives the exception\'s parameter;\n``sys.exc_traceback`` receives a traceback object (see section *The\nstandard type hierarchy*) identifying the point in the program where\nthe exception occurred. These details are also available through the\n``sys.exc_info()`` function, which returns a tuple ``(exc_type,\nexc_value, exc_traceback)``. Use of the corresponding variables is\ndeprecated in favor of this function, since their use is unsafe in a\nthreaded program. As of Python 1.5, the variables are restored to\ntheir previous values (before the call) when returning from a function\nthat handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is 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\nThe return value of a function is determined by the last ``return``\nstatement executed. Since the ``finally`` clause always executes, a\n``return`` statement executed in the ``finally`` clause will always be\nthe last one executed:\n\n >>> def foo():\n ... try:\n ... return \'try\'\n ... finally:\n ... return \'finally\'\n ...\n >>> foo()\n \'finally\'\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\nNew in version 2.5.\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\nNote: In Python 2.5, the ``with`` statement is only allowed when the\n ``with_statement`` feature has been enabled. It is always enabled\n in Python 2.6.\n\nChanged in version 2.7: 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 decorated ::= decorators (classdef | funcdef)\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n funcdef ::= "def" funcname "(" [parameter_list] ")" ":" suite\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" identifier ["," "**" identifier]\n | "**" identifier\n | defparameter [","] )\n defparameter ::= parameter ["=" expression]\n sublist ::= parameter ("," parameter)* [","]\n parameter ::= identifier | "(" sublist ")"\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 top-level *parameters* have the form *parameter*\n``=`` *expression*, the function is said to have "default parameter\nvalues." For a parameter with a default value, the corresponding\n*argument* may be omitted from a call, in which case the parameter\'s\ndefault value is substituted. If a parameter has a default value, all\nfollowing parameters must also have a default value --- this is a\nsyntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that the same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary.\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.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= "class" classname [inheritance] ":" suite\n inheritance ::= "(" [expression_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. It first evaluates the\ninheritance list, if present. Each item in the inheritance list\nshould evaluate to a class object or class type which allows\nsubclassing. The class\'s suite is then executed in a new execution\nframe (see section *Naming and binding*), using a newly created local\nnamespace and the original global namespace. (Usually, the suite\ncontains only function definitions.) When the class\'s suite finishes\nexecution, its execution frame is discarded but its local namespace is\nsaved. [4] A class object is then created using the inheritance list\nfor the base classes and the saved local namespace for the attribute\ndictionary. The class name is bound to this class object in the\noriginal local namespace.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass variables; they are shared by all instances. To create instance\nvariables, they can be set in a method with ``self.name = value``.\nBoth class and instance variables are accessible through the notation\n"``self.name``", and an instance variable hides a class variable with\nthe same name when accessed in this way. Class variables can be used\nas defaults for instance variables, but using mutable values there can\nlead to unexpected results. For *new-style class*es, descriptors can\nbe used to create instance variables with different implementation\ndetails.\n\nClass definitions, like function definitions, may be wrapped by one or\nmore *decorator* expressions. The evaluation rules for the decorator\nexpressions are the same as for functions. The result must be a class\nobject, which is then bound to the class name.\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack 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\nNew in version 2.5.\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," the arguments\nare coerced using the coercion rules listed at *Coercion rules*. If\nboth arguments are standard numeric types, the following coercions are\napplied:\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, if either argument is a long integer, the other is\n converted to long integer;\n\n* otherwise, both must be plain integers and no conversion is\n necessary.\n\nSome additional rules apply for certain operators (e.g., a string left\nargument to the \'%\' operator). Extensions can define their own\ncoercions.\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_traceback`` 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.exc_traceback`` or ``sys.last_traceback``. Circular\n references which are garbage are detected when the option cycle\n detector is enabled (it\'s on by default), but can only be cleaned\n up if there are no Python-level ``__del__()`` methods involved.\n Refer to the documentation for the ``gc`` module for more\n information about how ``__del__()`` methods are handled by the\n cycle detector, particularly the description of the ``garbage``\n value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\n See also the *-R* command-line option.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function and by string\n conversions (reverse quotes) to compute the "official" string\n representation of an object. If at all possible, this should look\n like a valid Python expression that could be used to recreate an\n object with the same value (given an appropriate environment). If\n this is not possible, a string of the form ``<...some useful\n description...>`` should be returned. The return value must be a\n string object. If a class defines ``__repr__()`` but not\n ``__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 the ``str()`` built-in function and by the ``print``\n statement to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__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 New in version 2.1.\n\n These are the so-called "rich comparison" methods, and are called\n for comparison operators in preference to ``__cmp__()`` below. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` call ``x.__ne__(y)``, ``x>y`` calls ``x.__gt__(y)``, and\n ``x>=y`` calls ``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.__cmp__(self, other)\n\n Called by comparison operations if rich comparison (see above) is\n not defined. Should return a negative integer if ``self < other``,\n zero if ``self == other``, a positive integer if ``self > other``.\n If no ``__cmp__()``, ``__eq__()`` or ``__ne__()`` operation is\n defined, class instances are compared by object identity\n ("address"). See also the description of ``__hash__()`` for some\n important notes on creating *hashable* objects which support custom\n comparison operations and are usable as dictionary keys. (Note: the\n restriction that exceptions are not propagated by ``__cmp__()`` has\n been removed since Python 1.5.)\n\nobject.__rcmp__(self, other)\n\n Changed in version 2.1: No longer supported.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define a ``__cmp__()`` or ``__eq__()`` method\n it should not define a ``__hash__()`` operation either; if it\n defines ``__cmp__()`` or ``__eq__()`` but not ``__hash__()``, its\n instances will not be usable in hashed collections. If a class\n defines mutable objects and implements a ``__cmp__()`` or\n ``__eq__()`` method, it should not implement ``__hash__()``, since\n hashable collection implementations require that a object\'s hash\n value is immutable (if the object\'s hash value changes, it will be\n in the wrong hash bucket).\n\n User-defined classes have ``__cmp__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns a result derived from\n ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__cmp__()`` or ``__eq__()`` such that\n the hash value returned is no longer appropriate (e.g. by switching\n to a value-based concept of equality instead of the default\n identity based equality) can explicitly flag themselves as being\n unhashable by setting ``__hash__ = None`` in the class definition.\n Doing so means that not only will instances of the class raise an\n appropriate ``TypeError`` when a program attempts to retrieve their\n hash value, but they will also be correctly identified as\n unhashable when checking ``isinstance(obj, collections.Hashable)``\n (unlike classes which define their own ``__hash__()`` to explicitly\n raise ``TypeError``).\n\n Changed in version 2.5: ``__hash__()`` may now also return a long\n integer object; the 32-bit integer is then derived from the hash of\n that object.\n\n Changed in version 2.6: ``__hash__`` may now be set to ``None`` to\n explicitly flag instances of a class as unhashable.\n\nobject.__nonzero__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``, or their integer\n equivalents ``0`` or ``1``. When this method is not defined,\n ``__len__()`` is called, if it is defined, and the object is\n considered true if its result is nonzero. If a class defines\n neither ``__len__()`` nor ``__nonzero__()``, all its instances are\n considered true.\n\nobject.__unicode__(self)\n\n Called to implement ``unicode()`` built-in; should return a Unicode\n object. When this method is not defined, string conversion is\n attempted, and the result of string conversion is converted to\n Unicode using the system default encoding.\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\n``pdb.py`` can also be invoked as a script to debug other scripts.\nFor example:\n\n python -m pdb myscript.py\n\nWhen invoked as a script, pdb will automatically enter post-mortem\ndebugging if the program being debugged exits abnormally. After post-\nmortem debugging (or after normal exit of the program), pdb will\nrestart the program. Automatic restarting preserves pdb\'s state (such\nas breakpoints) and in most cases is more useful than quitting the\ndebugger upon program\'s exit.\n\nNew in version 2.4: Restarting post-mortem behavior added.\n\nThe typical usage to break into the debugger from a running program is\nto insert\n\n import pdb; pdb.set_trace()\n\nat the location you want to break into the debugger. You can then\nstep through the code following this statement, and continue running\nwithout the debugger using the ``c`` command.\n\nThe typical usage to inspect a crashed program is:\n\n >>> import pdb\n >>> import mymodule\n >>> mymodule.test()\n Traceback (most recent call last):\n File "", line 1, in ?\n File "./mymodule.py", line 4, in test\n test2()\n File "./mymodule.py", line 3, in test2\n print spam\n NameError: spam\n >>> pdb.pm()\n > ./mymodule.py(3)test2()\n -> print spam\n (Pdb)\n\nThe module defines the following functions; each enters the debugger\nin a slightly different way:\n\npdb.run(statement[, globals[, locals]])\n\n Execute the *statement* (given as a string) under debugger control.\n The debugger prompt appears before any code is executed; you can\n set breakpoints and type ``continue``, or you can step through the\n statement using ``step`` or ``next`` (all these commands are\n explained below). The optional *globals* and *locals* arguments\n specify the environment in which the code is executed; by default\n the dictionary of the module ``__main__`` is used. (See the\n explanation of the ``exec`` statement or the ``eval()`` built-in\n function.)\n\npdb.runeval(expression[, globals[, locals]])\n\n Evaluate the *expression* (given as a string) under debugger\n control. When ``runeval()`` returns, it returns the value of the\n expression. Otherwise this function is similar to ``run()``.\n\npdb.runcall(function[, argument, ...])\n\n Call the *function* (a function or method object, not a string)\n with the given arguments. When ``runcall()`` returns, it returns\n whatever the function call returned. The debugger prompt appears\n as soon as the function is entered.\n\npdb.set_trace()\n\n Enter the debugger at the calling stack frame. This is useful to\n hard-code a breakpoint at a given point in a program, even if the\n code is not otherwise being debugged (e.g. when an assertion\n fails).\n\npdb.post_mortem([traceback])\n\n Enter post-mortem debugging of the given *traceback* object. If no\n *traceback* is given, it uses the one of the exception that is\n currently being handled (an exception must be being handled if the\n default is to be used).\n\npdb.pm()\n\n Enter post-mortem debugging of the traceback found in\n ``sys.last_traceback``.\n\nThe ``run*`` functions and ``set_trace()`` are aliases for\ninstantiating the ``Pdb`` class and calling the method of the same\nname. If you want to access further features, you have to do this\nyourself:\n\nclass class pdb.Pdb(completekey=\'tab\', stdin=None, stdout=None, skip=None)\n\n ``Pdb`` is the debugger class.\n\n The *completekey*, *stdin* and *stdout* arguments are passed to the\n underlying ``cmd.Cmd`` class; see the description there.\n\n The *skip* argument, if given, must be an iterable of glob-style\n module name patterns. The debugger will not step into frames that\n originate in a module that matches one of these patterns. [1]\n\n Example call to enable tracing with *skip*:\n\n import pdb; pdb.Pdb(skip=[\'django.*\']).set_trace()\n\n New in version 2.7: The *skip* argument.\n\n run(statement[, globals[, locals]])\n runeval(expression[, globals[, locals]])\n runcall(function[, argument, ...])\n set_trace()\n\n See the documentation for the functions explained above.\n', - '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\nIt is illegal to delete a name from the local namespace if it occurs\nas a free variable in a nested block.\n\nDeletion of attribute references, subscriptions and slicings is passed\nto the primary object involved; deletion of a slicing is in general\nequivalent to assignment of an empty slice of the right type (but even\nthis is determined by the sliced object).\n', - 'dict': '\nDictionary displays\n*******************\n\nA dictionary display is a possibly empty series of key/datum pairs\nenclosed in curly braces:\n\n dict_display ::= "{" [key_datum_list | dict_comprehension] "}"\n key_datum_list ::= key_datum ("," key_datum)* [","]\n key_datum ::= expression ":" expression\n dict_comprehension ::= expression ":" expression comp_for\n\nA dictionary display yields a new dictionary object.\n\nIf a comma-separated sequence of key/datum pairs is given, they are\nevaluated from left to right to define the entries of the dictionary:\neach key object is used as a key into the dictionary to store the\ncorresponding datum. This means that you can specify the same key\nmultiple times in the key/datum list, and the final dictionary\'s value\nfor that key will be the last one given.\n\nA dict comprehension, in contrast to list and set comprehensions,\nneeds two expressions separated with a colon followed by the usual\n"for" and "if" clauses. When the comprehension is run, the resulting\nkey and value elements are inserted in the new dictionary in the order\nthey are produced.\n\nRestrictions on the types of the key values are listed earlier in\nsection *The standard type hierarchy*. (To summarize, the key type\nshould be *hashable*, which excludes all mutable objects.) Clashes\nbetween duplicate keys are not detected; the last datum (textually\nrightmost in the display) stored for a given key value prevails.\n', - 'dynamic-features': '\nInteraction with dynamic features\n*********************************\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nIf ``exec`` is used in a function and the function contains or is a\nnested block with free variables, the compiler will raise a\n``SyntaxError`` unless the exec explicitly specifies the local\nnamespace for the ``exec``. (In other words, ``exec obj`` would be\nillegal, but ``exec obj in ns`` would be legal.)\n\nThe ``eval()``, ``execfile()``, and ``input()`` functions and the\n``exec`` statement do not have access to the full environment for\nresolving names. Names may be resolved in the local and global\nnamespaces of the caller. Free variables are not resolved in the\nnearest enclosing namespace, but in the global namespace. [1] The\n``exec`` statement and the ``eval()`` and ``execfile()`` functions\nhave optional arguments to override the global and local namespace.\nIf only one namespace is specified, 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\nExceptions can also be identified by strings, in which case the\n``except`` clause is selected by object identity. An arbitrary value\ncan be raised along with the identifying string which can be passed to\nthe handler.\n\nNote: Messages to exceptions 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 these\n operations is not available at the time the module is compiled.\n', - 'exec': '\nThe ``exec`` statement\n**********************\n\n exec_stmt ::= "exec" or_expr ["in" expression ["," expression]]\n\nThis statement supports dynamic execution of Python code. The first\nexpression should evaluate to either a Unicode string, a *Latin-1*\nencoded string, an open file object, a code object, or a tuple. If it\nis a string, the string is parsed as a suite of Python statements\nwhich is then executed (unless a syntax error occurs). [1] If it is an\nopen file, the file is parsed until EOF and executed. If it is a code\nobject, it is simply executed. For the interpretation of a tuple, see\nbelow. In all cases, the code that\'s executed is expected to be valid\nas file input (see section *File input*). Be aware that the\n``return`` and ``yield`` statements may not be used outside of\nfunction definitions even within the context of code passed to the\n``exec`` statement.\n\nIn all cases, if the optional parts are omitted, the code is executed\nin the current scope. If only the first expression after ``in`` is\nspecified, it should be a dictionary, which will be used for both the\nglobal and the local variables. If two expressions are given, they\nare used for the global and local variables, respectively. If\nprovided, *locals* can be any mapping object. Remember that at module\nlevel, globals and locals are the same dictionary. If two separate\nobjects are given as *globals* and *locals*, the code will be executed\nas if it were embedded in a class definition.\n\nThe first expression may also be a tuple of length 2 or 3. In this\ncase, the optional parts must be omitted. The form ``exec(expr,\nglobals)`` is equivalent to ``exec expr in globals``, while the form\n``exec(expr, globals, locals)`` is equivalent to ``exec expr in\nglobals, locals``. The tuple form of ``exec`` provides compatibility\nwith Python 3, where ``exec`` is a function rather than a statement.\n\nChanged in version 2.4: Formerly, *locals* was required to be a\ndictionary.\n\nAs a side effect, an implementation may insert additional keys into\nthe dictionaries given besides those corresponding to variable names\nset by the executed code. For example, the current implementation may\nadd a reference to the dictionary of the built-in module\n``__builtin__`` under the key ``__builtins__`` (!).\n\n**Programmer\'s hints:** dynamic evaluation of expressions is supported\nby the built-in function ``eval()``. The built-in functions\n``globals()`` and ``locals()`` return the current global and local\ndictionary, respectively, which may be useful to pass around for use\nby ``exec``.\n\n-[ Footnotes ]-\n\n[1] Note that the parser only accepts the Unix-style end of line\n convention. If you are reading the code from a file, make sure to\n use *universal newlines* mode to convert Windows or Mac-style\n newlines.\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 file read by the\nbuilt-in function ``execfile()`` is a code block. The string argument\npassed to the built-in function ``eval()`` and to the ``exec``\nstatement is a code block. The expression read and evaluated by the\nbuilt-in function ``input()`` 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 generator expressions since\nthey are implemented using a function scope. This means that the\nfollowing 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.\nIf a name is bound at the module level, it is a global variable. (The\nvariables of the module code block are local and global.) If a\nvariable is used in a code block but not defined there, it is a *free\nvariable*.\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, in the\nsecond position of an ``except`` clause header or after ``as`` in a\n``with`` statement. The ``import`` statement of the form ``from ...\nimport *`` binds all names defined in the imported module, except\nthose beginning with an underscore. This form may only be used at the\nmodule level.\n\nA target occurring in a ``del`` statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name). It\nis illegal to unbind a name that is referenced by an enclosing scope;\nthe compiler will report a ``SyntaxError``.\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the global statement occurs within a block, all uses of the 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 ``__builtin__``. The global namespace is searched\nfirst. If the name is not found there, the builtins namespace is\nsearched. The global 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\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``__builtin__`` (note: no \'s\'); when in any other module,\n``__builtins__`` is an alias for the dictionary of the ``__builtin__``\nmodule 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 ``__builtin__`` (no \'s\') module and modify its attributes\nappropriately.\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\nIf ``exec`` is used in a function and the function contains or is a\nnested block with free variables, the compiler will raise a\n``SyntaxError`` unless the exec explicitly specifies the local\nnamespace for the ``exec``. (In other words, ``exec obj`` would be\nillegal, but ``exec obj in ns`` would be legal.)\n\nThe ``eval()``, ``execfile()``, and ``input()`` functions and the\n``exec`` statement do not have access to the full environment for\nresolving names. Names may be resolved in the local and global\nnamespaces of the caller. Free variables are not resolved in the\nnearest enclosing namespace, but in the global namespace. [1] The\n``exec`` statement and the ``eval()`` and ``execfile()`` functions\nhave optional arguments to override the global and local namespace.\nIf only one namespace is specified, 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\nExceptions can also be identified by strings, in which case the\n``except`` clause is selected by object identity. An arbitrary value\ncan be raised along with the identifying string which can be passed to\nthe handler.\n\nNote: Messages to exceptions 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 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 of floating point numbers can\nlook like octal integers, but are interpreted using radix 10. For\nexample, ``077e010`` is legal, and denotes the same number as\n``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, and then the suite is executed. When the items are\nexhausted (which is immediately when the sequence is empty), the suite\nin 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``\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\nThe target list is not deleted when the loop is finished, but if the\nsequence is empty, it will not have been assigned to at all by the\nloop. Hint: the built-in function ``range()`` returns a sequence of\nintegers suitable to emulate the effect of Pascal\'s ``for i := a to b\ndo``; e.g., ``range(3)`` returns the list ``[0, 1, 2]``.\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 internal\n counter is used to keep track of which item is used next, and this\n is incremented on each iteration. When this counter has reached the\n length of the sequence the loop terminates. This means that if the\n suite deletes the current (or a previous) item from the sequence,\n the next item will be skipped (since it gets the index of the\n 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"\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 2.7: 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\nTwo conversion flags are currently supported: ``\'!s\'`` which calls\n``str()`` on the value, and ``\'!r\'`` which calls ``repr()``.\n\nSome examples:\n\n "Harold\'s a clever {0!s}" # Calls str() on the argument first\n "Bring out the holy {name!r}" # Calls repr() on the argument first\n\nThe *format_spec* field contains a specification of how the value\nshould be presented, including such details as field width, alignment,\npadding, decimal precision and so on. Each value type can define 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 is only valid for integers, and only for binary,\noctal, or hexadecimal output. If present, it specifies that the\noutput will be prefixed by ``\'0b\'``, ``\'0o\'``, or ``\'0x\'``,\nrespectively.\n\nThe ``\',\'`` option signals the use of a comma for a thousands\nseparator. For a locale aware separator, use the ``\'n\'`` integer\npresentation type instead.\n\nChanged in version 2.7: 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\'``. |\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 | The same as ``\'g\'``. |\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\') # 2.7+ 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(object):\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.5\n >>> total = 22\n >>> \'Correct answers: {:.2%}\'.format(points/total)\n \'Correct answers: 88.64%\'\n\nUsing type-specific formatting:\n\n >>> import datetime\n >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)\n >>> \'{:%Y-%m-%d %H:%M:%S}\'.format(d)\n \'2010-07-04 12:15:58\'\n\nNesting arguments and more complex examples:\n\n >>> for align, text in zip(\'<^>\', [\'left\', \'center\', \'right\']):\n ... \'{0:{fill}{align}16}\'.format(text, fill=align, align=align)\n ...\n \'left<<<<<<<<<<<<\'\n \'^^^^^center^^^^^\'\n \'>>>>>>>>>>>right\'\n >>>\n >>> octets = [192, 168, 0, 1]\n >>> \'{:02X}{:02X}{:02X}{:02X}\'.format(*octets)\n \'C0A80001\'\n >>> int(_, 16)\n 3232235521\n >>>\n >>> width = 5\n >>> for num in range(5,12):\n ... for base in \'dXob\':\n ... print \'{0:{width}{base}}\'.format(num, base=base, width=width),\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 decorated ::= decorators (classdef | funcdef)\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n funcdef ::= "def" funcname "(" [parameter_list] ")" ":" suite\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" identifier ["," "**" identifier]\n | "**" identifier\n | defparameter [","] )\n defparameter ::= parameter ["=" expression]\n sublist ::= parameter ("," parameter)* [","]\n parameter ::= identifier | "(" sublist ")"\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 top-level *parameters* have the form *parameter*\n``=`` *expression*, the function is said to have "default parameter\nvalues." For a parameter with a default value, the corresponding\n*argument* may be omitted from a call, in which case the parameter\'s\ndefault value is substituted. If a parameter has a default value, all\nfollowing parameters must also have a default value --- this is a\nsyntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that the same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary.\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.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n', - 'global': '\nThe ``global`` statement\n************************\n\n global_stmt ::= "global" identifier ("," identifier)*\n\nThe ``global`` statement is a declaration which holds for the entire\ncurrent code block. It means that the listed identifiers are to be\ninterpreted as globals. It would be impossible to assign to a global\nvariable without ``global``, although free variables may refer to\nglobals without being declared global.\n\nNames listed in a ``global`` statement must not be used in the same\ncode block textually preceding that ``global`` statement.\n\nNames listed in a ``global`` statement must not be defined as formal\nparameters or in a ``for`` loop control target, ``class`` definition,\nfunction definition, or ``import`` statement.\n\n**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 an\n``exec`` statement does not affect the code block *containing* the\n``exec`` statement, and code contained in an ``exec`` statement is\nunaffected by ``global`` statements in the code containing the\n``exec`` statement. The same applies to the ``eval()``,\n``execfile()`` 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 ``__builtin__`` module.\n When not in interactive mode, ``_`` has no special meaning and is\n not 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\n identifier ::= (letter|"_") (letter | digit | "_")*\n letter ::= lowercase | uppercase\n lowercase ::= "a"..."z"\n uppercase ::= "A"..."Z"\n digit ::= "0"..."9"\n\nIdentifiers are unlimited in length. Case is significant.\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 and del from not while\n as elif global or with\n assert else if pass yield\n break except import print\n class exec in raise\n continue finally is return\n def for lambda try\n\nChanged in version 2.4: ``None`` became a constant and is now\nrecognized by the compiler as a name for the built-in object ``None``.\nAlthough it is not a keyword, you cannot assign a different object to\nit.\n\nChanged in version 2.5: Using ``as`` and ``with`` as identifiers\ntriggers a warning. To use them as keywords, enable the\n``with_statement`` future feature .\n\nChanged in version 2.6: ``as`` and ``with`` are full keywords.\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 ``__builtin__`` module.\n When not in interactive mode, ``_`` has no special meaning and is\n not defined. See section *The import statement*.\n\n Note: The name ``_`` is often used in conjunction with\n internationalization; refer to the documentation for the\n ``gettext`` module for more information on this convention.\n\n``__*__``\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of ``__*__`` names, in any context, that does\n not follow explicitly documented use, is subject to breakage\n without warning.\n\n``__*``\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', - 'if': '\nThe ``if`` statement\n********************\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n', - 'imaginary': '\nImaginary literals\n******************\n\nImaginary literals are described by the following lexical definitions:\n\n imagnumber ::= (floatnumber | intpart) ("j" | "J")\n\nAn imaginary literal yields a complex number with a real part of 0.0.\nComplex numbers are represented as a pair of floating point numbers\nand have the same restrictions on their range. To create a complex\nnumber with a nonzero real part, add a floating point number to it,\ne.g., ``(3+4j)``. Some examples of imaginary literals:\n\n 3.14j 10.j 10j .001j 1e100j 3.14e-10j\n', - 'import': '\nThe ``import`` statement\n************************\n\n import_stmt ::= "import" module ["as" name] ( "," module ["as" name] )*\n | "from" relative_module "import" identifier ["as" name]\n ( "," identifier ["as" name] )*\n | "from" relative_module "import" "(" identifier ["as" name]\n ( "," identifier ["as" name] )* [","] ")"\n | "from" module "import" "*"\n module ::= (identifier ".")* identifier\n relative_module ::= "."* module | "."+\n name ::= identifier\n\nImport statements are executed in two steps: (1) find a module, and\ninitialize it if necessary; (2) define a name or names in the local\nnamespace (of the scope where the ``import`` statement occurs). The\nstatement comes in two forms differing on whether it uses the ``from``\nkeyword. The first form (without ``from``) repeats these steps for\neach identifier in the list. The form with ``from`` performs step (1)\nonce, and then performs step (2) repeatedly.\n\nTo understand how step (1) occurs, one must first understand how\nPython handles hierarchical naming of modules. To help organize\nmodules and provide a hierarchy in naming, Python has a concept of\npackages. A package can contain other packages and modules while\nmodules cannot contain other modules or packages. From a file system\nperspective, packages are directories and modules are files. The\noriginal specification for packages is still available to read,\nalthough minor details have changed since the writing of that\ndocument.\n\nOnce the name of the module is known (unless otherwise specified, the\nterm "module" will refer to both packages and modules), searching for\nthe module or package can begin. The first place checked is\n``sys.modules``, the cache of all modules that have been imported\npreviously. If the module is found there then it is used in step (2)\nof import.\n\nIf the module is not found in the cache, then ``sys.meta_path`` is\nsearched (the specification for ``sys.meta_path`` can be found in\n**PEP 302**). The object is a list of *finder* objects which are\nqueried in order as to whether they know how to load the module by\ncalling their ``find_module()`` method with the name of the module. If\nthe module happens to be contained within a package (as denoted by the\nexistence of a dot in the name), then a second argument to\n``find_module()`` is given as the value of the ``__path__`` attribute\nfrom the parent package (everything up to the last dot in the name of\nthe module being imported). If a finder can find the module it returns\na *loader* (discussed later) or returns ``None``.\n\nIf none of the finders on ``sys.meta_path`` are able to find the\nmodule then some implicitly defined finders are queried.\nImplementations of Python vary in what implicit meta path finders are\ndefined. The one they all do define, though, is one that handles\n``sys.path_hooks``, ``sys.path_importer_cache``, and ``sys.path``.\n\nThe implicit finder searches for the requested module in the "paths"\nspecified in one of two places ("paths" do not have to be file system\npaths). If the module being imported is supposed to be contained\nwithin a package then the second argument passed to ``find_module()``,\n``__path__`` on the parent package, is used as the source of paths. If\nthe module is not contained in a package then ``sys.path`` is used as\nthe source of paths.\n\nOnce the source of paths is chosen it is iterated over to find a\nfinder that can handle that path. The dict at\n``sys.path_importer_cache`` caches finders for paths and is checked\nfor a finder. If the path does not have a finder cached then\n``sys.path_hooks`` is searched by calling each object in the list with\na single argument of the path, returning a finder or raises\n``ImportError``. If a finder is returned then it is cached in\n``sys.path_importer_cache`` and then used for that path entry. If no\nfinder can be found but the path exists then a value of ``None`` is\nstored in ``sys.path_importer_cache`` to signify that an implicit,\nfile-based finder that handles modules stored as individual files\nshould be used for that path. If the path does not exist then a finder\nwhich always returns ``None`` is placed in the cache for the path.\n\nIf no finder can find the module then ``ImportError`` is raised.\nOtherwise some finder returned a loader whose ``load_module()`` method\nis called with the name of the module to load (see **PEP 302** for the\noriginal definition of loaders). A loader has several responsibilities\nto perform on a module it loads. First, if the module already exists\nin ``sys.modules`` (a possibility if the loader is called outside of\nthe import machinery) then it is to use that module for initialization\nand not a new module. But if the module does not exist in\n``sys.modules`` then it is to be added to that dict before\ninitialization begins. If an error occurs during loading of the module\nand it was added to ``sys.modules`` it is to be removed from the dict.\nIf an error occurs but the module was already in ``sys.modules`` it is\nleft in the dict.\n\nThe loader must set several attributes on the module. ``__name__`` is\nto be set to the name of the module. ``__file__`` is to be the "path"\nto the file unless the module is built-in (and thus listed in\n``sys.builtin_module_names``) in which case the attribute is not set.\nIf what is being imported is a package then ``__path__`` is to be set\nto a list of paths to be searched when looking for modules and\npackages contained within the package being imported. ``__package__``\nis optional but should be set to the name of package that contains the\nmodule or package (the empty string is used for module not contained\nin a package). ``__loader__`` is also optional but should be set to\nthe loader object that is loading the module.\n\nIf an error occurs during loading then the loader raises\n``ImportError`` if some other exception is not already being\npropagated. Otherwise the loader returns the module that was loaded\nand initialized.\n\nWhen step (1) finishes without raising an exception, step (2) can\nbegin.\n\nThe first form of ``import`` statement binds the module name in the\nlocal namespace to the module object, and then goes on to import the\nnext identifier, if any. If the module name is followed by ``as``,\nthe name following ``as`` is used as the local name for the module.\n\nThe ``from`` form does not bind the module name: it goes through the\nlist of identifiers, looks each one of them up in the module found in\nstep (1), and binds the name in the local namespace to the object thus\nfound. As with the first form of ``import``, an alternate local name\ncan be supplied by specifying "``as`` localname". If a name is not\nfound, ``ImportError`` is raised. If the list of identifiers is\nreplaced by a star (``\'*\'``), all public names defined in the module\nare bound in the local namespace of the ``import`` statement..\n\nThe *public names* defined by a module are determined by checking the\nmodule\'s namespace for a variable named ``__all__``; if defined, it\nmust be a sequence of strings which are names defined or imported by\nthat module. The names given in ``__all__`` are all considered public\nand are required to exist. If ``__all__`` is not defined, the set of\npublic names includes all names found in the module\'s namespace which\ndo not begin with an underscore character (``\'_\'``). ``__all__``\nshould contain the entire public API. It is intended to avoid\naccidentally exporting items that are not part of the API (such as\nlibrary modules which were imported and used within the module).\n\nThe ``from`` form with ``*`` may only occur in a module scope. If the\nwild card form of import --- ``import *`` --- is used in a function\nand the function contains or is a nested block with free variables,\nthe compiler will 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 2.6 are ``unicode_literals``,\n``print_function``, ``absolute_import``, ``division``, ``generators``,\n``nested_scopes`` and ``with_statement``. ``generators``,\n``with_statement``, ``nested_scopes`` are redundant in Python version\n2.6 and above because they are always enabled.\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 an ``exec`` statement or calls to the built-in\nfunctions ``compile()`` and ``execfile()`` that occur in a module\n``M`` containing a future statement will, by default, use the new\nsyntax or semantics associated with the future statement. This can,\nstarting with Python 2.2 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:\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 forms ``<>`` and ``!=`` are equivalent; for consistency with C,\n``!=`` is preferred; where ``!=`` is mentioned below ``<>`` is also\naccepted. The ``<>`` spelling is considered obsolescent.\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,\nobjects of different types *always* compare unequal, and are ordered\nconsistently but arbitrarily. You can control comparison behavior of\nobjects of non-built-in types by defining a ``__cmp__`` method or rich\ncomparison methods like ``__gt__``, described in section *Special\nmethod names*.\n\n(This unusual definition of comparison was used to simplify the\ndefinition of operations like sorting and the ``in`` and ``not in``\noperators. In the future, the comparison rules for objects of\ndifferent types are likely to change.)\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* Strings are compared lexicographically using the numeric equivalents\n (the result of the built-in function ``ord()``) of their characters.\n Unicode and 8-bit strings are fully interoperable in this behavior.\n [4]\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, ``cmp([1,2,x], [1,2,y])`` returns\n the same as ``cmp(x,y)``. If the corresponding element does not\n exist, the shorter sequence is ordered first (for example, ``[1,2] <\n [1,2,3]``).\n\n* Mappings (dictionaries) compare equal if and only if their sorted\n (key, value) lists compare equal. [5] Outcomes other than equality\n are resolved consistently, but are not otherwise defined. [6]\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\nThe operators ``in`` and ``not in`` test for collection membership.\n``x in s`` evaluates to true if *x* is a member of the collection *s*,\nand false otherwise. ``x not in s`` returns the negation of ``x in\ns``. The collection membership test has traditionally been bound to\nsequences; an object is a member of a collection if the collection is\na sequence and contains an element equal to that object. However, it\nmake sense for many other object types to support membership tests\nwithout being a sequence. In particular, dictionaries (for keys) and\nsets support membership testing.\n\nFor the list and tuple types, ``x in y`` is true if and only if there\nexists an index *i* such that ``x == y[i]`` is true.\n\nFor the Unicode and string types, ``x in y`` is true if and only if\n*x* is a substring of *y*. An equivalent test is ``y.find(x) != -1``.\nNote, *x* and *y* need not be the same type; consequently, ``u\'ab\' in\n\'abc\'`` will return ``True``. Empty strings are always considered to\nbe a substring of any other string, so ``"" in "abc"`` will return\n``True``.\n\nChanged in version 2.3: Previously, *x* was required to be a string of\nlength ``1``.\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. [7]\n', - 'integers': '\nInteger and long integer literals\n*********************************\n\nInteger and long integer literals are described by the following\nlexical definitions:\n\n longinteger ::= integer ("l" | "L")\n integer ::= decimalinteger | octinteger | hexinteger | bininteger\n decimalinteger ::= nonzerodigit digit* | "0"\n octinteger ::= "0" ("o" | "O") octdigit+ | "0" octdigit+\n hexinteger ::= "0" ("x" | "X") hexdigit+\n bininteger ::= "0" ("b" | "B") bindigit+\n nonzerodigit ::= "1"..."9"\n octdigit ::= "0"..."7"\n bindigit ::= "0" | "1"\n hexdigit ::= digit | "a"..."f" | "A"..."F"\n\nAlthough both lower case ``\'l\'`` and upper case ``\'L\'`` are allowed as\nsuffix for long integers, it is strongly recommended to always use\n``\'L\'``, since the letter ``\'l\'`` looks too much like the digit\n``\'1\'``.\n\nPlain integer literals that are above the largest representable plain\ninteger (e.g., 2147483647 when using 32-bit arithmetic) are accepted\nas if they were long integers instead. [1] There is no limit for long\ninteger literals apart from what can be stored in available memory.\n\nSome examples of plain integer literals (first row) and long integer\nliterals (second and third rows):\n\n 7 2147483647 0177\n 3L 79228162514264337593543950336L 0377L 0x100000000L\n 79228162514264337593543950336 0xdeadbeef\n', - 'lambda': '\nLambdas\n*******\n\n lambda_expr ::= "lambda" [parameter_list]: expression\n old_lambda_expr ::= "lambda" [parameter_list]: old_expression\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 name(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.\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 | list_comprehension] "]"\n list_comprehension ::= expression list_for\n list_for ::= "for" target_list "in" old_expression_list [list_iter]\n old_expression_list ::= old_expression [("," old_expression)+ [","]]\n old_expression ::= or_test | old_lambda_expr\n list_iter ::= list_for | list_if\n list_if ::= "if" old_expression [list_iter]\n\nA list display yields a new list object. Its contents are specified\nby providing either a list of expressions or a list comprehension.\nWhen a comma-separated list of expressions is supplied, its elements\nare evaluated from left to right and placed into the list object in\nthat order. When a list comprehension is supplied, it consists of a\nsingle expression followed by at least one ``for`` clause and zero or\nmore ``for`` or ``if`` clauses. In this case, the elements of the new\nlist are those that would be produced by considering each of the\n``for`` or ``if`` clauses a block, nesting from left to right, and\nevaluating the expression to produce a list element each time the\ninnermost block is reached [1].\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 file read by the\nbuilt-in function ``execfile()`` is a code block. The string argument\npassed to the built-in function ``eval()`` and to the ``exec``\nstatement is a code block. The expression read and evaluated by the\nbuilt-in function ``input()`` 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 generator expressions since\nthey are implemented using a function scope. This means that the\nfollowing 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.\nIf a name is bound at the module level, it is a global variable. (The\nvariables of the module code block are local and global.) If a\nvariable is used in a code block but not defined there, it is a *free\nvariable*.\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, in the\nsecond position of an ``except`` clause header or after ``as`` in a\n``with`` statement. The ``import`` statement of the form ``from ...\nimport *`` binds all names defined in the imported module, except\nthose beginning with an underscore. This form may only be used at the\nmodule level.\n\nA target occurring in a ``del`` statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name). It\nis illegal to unbind a name that is referenced by an enclosing scope;\nthe compiler will report a ``SyntaxError``.\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the global statement occurs within a block, all uses of the 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 ``__builtin__``. The global namespace is searched\nfirst. If the name is not found there, the builtins namespace is\nsearched. The global 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\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``__builtin__`` (note: no 's'); when in any other module,\n``__builtins__`` is an alias for the dictionary of the ``__builtin__``\nmodule 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 ``__builtin__`` (no 's') module and modify its attributes\nappropriately.\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\nIf ``exec`` is used in a function and the function contains or is a\nnested block with free variables, the compiler will raise a\n``SyntaxError`` unless the exec explicitly specifies the local\nnamespace for the ``exec``. (In other words, ``exec obj`` would be\nillegal, but ``exec obj in ns`` would be legal.)\n\nThe ``eval()``, ``execfile()``, and ``input()`` functions and the\n``exec`` statement do not have access to the full environment for\nresolving names. Names may be resolved in the local and global\nnamespaces of the caller. Free variables are not resolved in the\nnearest enclosing namespace, but in the global namespace. [1] The\n``exec`` statement and the ``eval()`` and ``execfile()`` functions\nhave optional arguments to override the global and local namespace.\nIf only one namespace is specified, it is used for both.\n", - 'numbers': "\nNumeric literals\n****************\n\nThere are four types of numeric literals: plain integers, long\nintegers, floating point numbers, and imaginary numbers. There are no\ncomplex literals (complex numbers can be formed by adding a real\nnumber and an imaginary 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.__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()``,\n ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``, ``|``). For\n instance, to evaluate the expression ``x + y``, where *x* is an\n 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__()`` (described below). Note\n that ``__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.__div__(self, other)\nobject.__truediv__(self, other)\n\n The division operator (``/``) is implemented by these methods. The\n ``__truediv__()`` method is used when ``__future__.division`` is in\n effect, otherwise ``__div__()`` is used. If only one of these two\n methods is defined, the object will not support division in the\n alternate context; ``TypeError`` will be raised instead.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rdiv__(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()``,\n ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``, ``|``) with\n reflected (swapped) operands. These functions are only called if\n the left operand does not support the corresponding operation and\n the operands are of different types. [2] For instance, to evaluate\n the expression ``x - y``, where *y* is an instance of a class that\n has an ``__rsub__()`` method, ``y.__rsub__(x)`` is called if\n ``x.__sub__(y)`` returns *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.__idiv__(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.__long__(self)\nobject.__float__(self)\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``long()``, and ``float()``. Should return a value of\n the appropriate type.\n\nobject.__oct__(self)\nobject.__hex__(self)\n\n Called to implement the built-in functions ``oct()`` and ``hex()``.\n Should return a string value.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing). Must return\n an integer (int or long).\n\n New in version 2.5.\n\nobject.__coerce__(self, other)\n\n Called to implement "mixed-mode" numeric arithmetic. Should either\n return a 2-tuple containing *self* and *other* converted to a\n common numeric type, or ``None`` if conversion is impossible. When\n the common type would be the type of ``other``, it is sufficient to\n return ``None``, since the interpreter will also ask the other\n object to attempt a coercion (but sometimes, if the implementation\n of the other type cannot be changed, it is useful to do the\n conversion to the other type here). A return value of\n ``NotImplemented`` is equivalent to returning ``None``.\n', - 'objects': '\nObjects, values and types\n*************************\n\n*Objects* are Python\'s abstraction for data. All data in a Python\nprogram is represented by objects or by relations between objects. (In\na sense, and in conformance to Von Neumann\'s model of a "stored\nprogram computer," code is also represented by objects.)\n\nEvery object has an identity, a type and a value. An object\'s\n*identity* never changes once it has been created; you may think of it\nas the object\'s address in memory. The \'``is``\' operator compares the\nidentity of two objects; the ``id()`` function returns an integer\nrepresenting its identity (currently implemented as its address). An\nobject\'s *type* is also unchangeable. [1] An object\'s type determines\nthe operations that the object supports (e.g., "does it have a\nlength?") and also defines the possible values for objects of that\ntype. The ``type()`` function returns an object\'s type (which is an\nobject itself). The *value* of some objects can change. Objects\nwhose value can change are said to be *mutable*; objects whose value\nis unchangeable once they are created are called *immutable*. (The\nvalue of an immutable container object that contains a reference to a\nmutable object can change when the latter\'s value is changed; however\nthe container is still considered immutable, because the collection of\nobjects it contains cannot be changed. So, immutability is not\nstrictly the same as having an unchangeable value, it is more subtle.)\nAn object\'s mutability is determined by its type; for instance,\nnumbers, strings and tuples are immutable, while dictionaries and\nlists are mutable.\n\nObjects are never explicitly destroyed; however, when they become\nunreachable they may be garbage-collected. An implementation is\nallowed to postpone garbage collection or omit it altogether --- it is\na matter of implementation quality how garbage collection is\nimplemented, as long as no objects are collected that are still\nreachable.\n\n**CPython implementation detail:** CPython currently uses a reference-\ncounting scheme with (optional) delayed detection of cyclically linked\ngarbage, which collects most objects as soon as they become\nunreachable, but is not guaranteed to collect garbage containing\ncircular references. See the documentation of the ``gc`` module for\ninformation on controlling the collection of cyclic garbage. Other\nimplementations act differently and CPython may change. Do not depend\non immediate finalization of objects when they become unreachable (ex:\nalways close files).\n\nNote that the use of the implementation\'s tracing or debugging\nfacilities may keep objects alive that would normally be collectable.\nAlso note that catching an exception with a \'``try``...``except``\'\nstatement may keep objects alive.\n\nSome objects contain references to "external" resources such as open\nfiles or windows. It is understood that these resources are freed\nwhen the object is garbage-collected, but since garbage collection is\nnot guaranteed to happen, such objects also provide an explicit way to\nrelease the external resource, usually a ``close()`` method. Programs\nare strongly recommended to explicitly close such objects. The\n\'``try``...``finally``\' statement provides a convenient way to do\nthis.\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| | [8] |\n+-------------------------------------------------+---------------------------------------+\n| ``+x``, ``-x``, ``~x`` | Positive, negative, bitwise NOT |\n+-------------------------------------------------+---------------------------------------+\n| ``**`` | Exponentiation [9] |\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, string |\n| | conversion |\n+-------------------------------------------------+---------------------------------------+\n\n-[ Footnotes ]-\n\n[1] In Python 2.3 and later releases, a list comprehension "leaks" the\n control variables of each ``for`` it contains into the containing\n scope. However, this behavior is deprecated, and relying on it\n will not work in Python 3.\n\n[2] 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[3] If x is very close to an exact integer multiple of y, it\'s\n possible for ``floor(x/y)`` to be one larger than ``(x-x%y)/y``\n due to rounding. In such cases, Python returns the latter result,\n in order to preserve that ``divmod(x,y)[0] * y + x % y`` be very\n close to ``x``.\n\n[4] While comparisons between unicode strings make sense at the byte\n level, they may be counter-intuitive to users. For example, the\n strings ``u"\\u00C7"`` and ``u"\\u0043\\u0327"`` compare differently,\n even 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[5] The implementation computes this efficiently, without constructing\n lists or sorting.\n\n[6] Earlier versions of Python used lexicographic comparison of the\n sorted (key, value) lists, but this was very expensive for the\n common case of comparing for equality. An even earlier version of\n Python compared dictionaries by identity only, but this caused\n surprises because people expected to be able to test a dictionary\n for emptiness by comparing it to ``{}``.\n\n[7] 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[8] The ``%`` operator is also used for string formatting; the same\n precedence applies.\n\n[9] 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. The result type is that of the\narguments after coercion.\n\nWith mixed operand types, the coercion rules for binary arithmetic\noperators apply. For int and long int operands, the result has the\nsame type as the operands (after coercion) unless the second argument\nis negative; in that case, all arguments are converted to float and a\nfloat result is delivered. For example, ``10**2`` returns ``100``, but\n``10**-2`` returns ``0.01``. (This last feature was added in Python\n2.2. In Python 2.1 and before, if both arguments were of integer types\nand the second argument was negative, an exception was raised).\n\nRaising ``0.0`` to a negative power results in a\n``ZeroDivisionError``. Raising a negative number to a fractional power\nresults in a ``ValueError``.\n', - 'print': '\nThe ``print`` statement\n***********************\n\n print_stmt ::= "print" ([expression ("," expression)* [","]]\n | ">>" expression [("," expression)+ [","]])\n\n``print`` evaluates each expression in turn and writes the resulting\nobject to standard output (see below). If an object is not a string,\nit is first converted to a string using the rules for string\nconversions. The (resulting or original) string is then written. A\nspace is written before each object is (converted and) written, unless\nthe output system believes it is positioned at the beginning of a\nline. This is the case (1) when no characters have yet been written\nto standard output, (2) when the last character written to standard\noutput is a whitespace character except ``\' \'``, or (3) when the last\nwrite operation on standard output was not a ``print`` statement. (In\nsome cases it may be functional to write an empty string to standard\noutput for this reason.)\n\nNote: Objects which act like file objects but which are not the built-in\n file objects often do not properly emulate this aspect of the file\n object\'s behavior, so it is best not to rely on this.\n\nA ``\'\\n\'`` character is written at the end, unless the ``print``\nstatement ends with a comma. This is the only action if the statement\ncontains just the keyword ``print``.\n\nStandard output is defined as the file object named ``stdout`` in the\nbuilt-in module ``sys``. If no such object exists, or if it does not\nhave a ``write()`` method, a ``RuntimeError`` exception is raised.\n\n``print`` also has an extended form, defined by the second portion of\nthe syntax described above. This form is sometimes referred to as\n"``print`` chevron." In this form, the first expression after the\n``>>`` must evaluate to a "file-like" object, specifically an object\nthat has a ``write()`` method as described above. With this extended\nform, the subsequent expressions are printed to this file object. If\nthe first expression evaluates to ``None``, then ``sys.stdout`` is\nused as the file for output.\n', - 'raise': '\nThe ``raise`` statement\n***********************\n\n raise_stmt ::= "raise" [expression ["," expression ["," expression]]]\n\nIf no expressions are present, ``raise`` re-raises the last exception\nthat was active in the current scope. If no exception is active in\nthe current scope, a ``TypeError`` exception is raised indicating that\nthis is an error (if running under IDLE, a ``Queue.Empty`` exception\nis raised instead).\n\nOtherwise, ``raise`` evaluates the expressions to get three objects,\nusing ``None`` as the value of omitted expressions. The first two\nobjects are used to determine the *type* and *value* of the exception.\n\nIf the first object is an instance, the type of the exception is the\nclass of the instance, the instance itself is the value, and the\nsecond object must be ``None``.\n\nIf the first object is a class, it becomes the type of the exception.\nThe second object is used to determine the exception value: If it is\nan instance of the class, the instance becomes the exception value. If\nthe second object is a tuple, it is used as the argument list for the\nclass constructor; if it is ``None``, an empty argument list is used,\nand any other object is treated as a single argument to the\nconstructor. The instance so created by calling the constructor is\nused as the exception value.\n\nIf a third object is present and not ``None``, it must be a traceback\nobject (see section *The standard type hierarchy*), and it is\nsubstituted instead of the current location as the place where the\nexception occurred. If the third object is present and not a\ntraceback object or ``None``, a ``TypeError`` exception is raised.\nThe three-expression form of ``raise`` is useful to re-raise an\nexception transparently in an except clause, but ``raise`` with no\nexpressions should be preferred if the exception to be re-raised was\nthe most recently active exception in the current scope.\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information about handling exceptions is in section\n*The try statement*.\n', - 'return': '\nThe ``return`` statement\n************************\n\n return_stmt ::= "return" [expression_list]\n\n``return`` may only occur syntactically nested in a function\ndefinition, not within a nested class definition.\n\nIf an expression list is present, it is evaluated, else ``None`` is\nsubstituted.\n\n``return`` leaves the current function call with the expression list\n(or ``None``) as return value.\n\nWhen ``return`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nleaving the function.\n\nIn a generator function, the ``return`` statement is not allowed to\ninclude an ``expression_list``. In that context, a bare ``return``\nindicates that the generator is done and will cause ``StopIteration``\nto be raised.\n', - 'sequence-types': "\nEmulating container types\n*************************\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. (For backwards compatibility, the method\n``__getslice__()`` (see below) can also be defined to handle simple,\nbut not extended slices.) It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``has_key()``,\n``get()``, ``clear()``, ``setdefault()``, ``iterkeys()``,\n``itervalues()``, ``iteritems()``, ``pop()``, ``popitem()``,\n``copy()``, and ``update()`` behaving similar to those for Python's\nstandard dictionary objects. The ``UserDict`` module provides a\n``DictMixin`` class to help create those methods from a base set of\n``__getitem__()``, ``__setitem__()``, ``__delitem__()``, and\n``keys()``. Mutable sequences should provide methods ``append()``,\n``count()``, ``index()``, ``extend()``, ``insert()``, ``pop()``,\n``remove()``, ``reverse()`` and ``sort()``, like Python standard list\nobjects. Finally, sequence types should implement addition (meaning\nconcatenation) and multiplication (meaning repetition) by defining the\nmethods ``__add__()``, ``__radd__()``, ``__iadd__()``, ``__mul__()``,\n``__rmul__()`` and ``__imul__()`` described below; they should not\ndefine ``__coerce__()`` or other numerical operators. It is\nrecommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should be equivalent of ``has_key()``;\nfor sequences, 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``iterkeys()``; 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 ``__nonzero__()`` method and whose\n ``__len__()`` method returns zero is considered to be false in a\n Boolean context.\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 ``iterkeys()``.\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\n New in version 2.6.\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 plain or long integers as arguments. The\narguments are converted to a common type. They shift the first\nargument to the left or right by the number of bits given by the\nsecond argument.\n\nA right shift by *n* bits is defined as division by ``pow(2, n)``. A\nleft shift by *n* bits is defined as multiplication with ``pow(2,\nn)``. Negative shift counts raise a ``ValueError`` exception.\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 ::= simple_slicing | extended_slicing\n simple_slicing ::= primary "[" short_slice "]"\n extended_slicing ::= primary "[" slice_list "]"\n slice_list ::= slice_item ("," slice_item)* [","]\n slice_item ::= expression | proper_slice | ellipsis\n proper_slice ::= short_slice | long_slice\n short_slice ::= [lower_bound] ":" [upper_bound]\n long_slice ::= short_slice ":" [stride]\n lower_bound ::= expression\n upper_bound ::= expression\n stride ::= expression\n ellipsis ::= "..."\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 nor ellipses). Similarly, when the slice\nlist has exactly one short slice and no trailing comma, the\ninterpretation as a simple slicing takes priority over that as an\nextended slicing.\n\nThe semantics for a simple slicing are as follows. The primary must\nevaluate to a sequence object. The lower and upper bound expressions,\nif present, must evaluate to plain integers; defaults are zero and the\n``sys.maxint``, respectively. If either bound is negative, the\nsequence\'s length is added to it. The slicing now selects all items\nwith index *k* such that ``i <= k < j`` where *i* and *j* are the\nspecified lower and upper bounds. This may be an empty sequence. It\nis not an error if *i* or *j* lie outside the range of valid indexes\n(such items don\'t exist so they aren\'t selected).\n\nThe semantics for an extended slicing are as follows. The primary\nmust evaluate to a mapping object, and it is indexed with a key that\nis constructed 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 an ellipsis slice\nitem is the built-in ``Ellipsis`` object. The conversion of a proper\nslice is a slice object (see section *The standard type hierarchy*)\nwhose ``start``, ``stop`` and ``step`` attributes are the values of\nthe expressions 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\nobject.__methods__\n\n Deprecated since version 2.2: Use the built-in function ``dir()``\n to get a list of an object\'s attributes. This attribute is no\n longer available.\n\nobject.__members__\n\n Deprecated since version 2.2: Use the built-in function ``dir()``\n to get a list of an object\'s attributes. This attribute is no\n longer available.\n\ninstance.__class__\n\n The class to which a class instance belongs.\n\nclass.__bases__\n\n The tuple of base classes of a class object.\n\nclass.__name__\n\n The name of the class or type.\n\nThe following attributes are only supported by *new-style class*es.\n\nclass.__mro__\n\n This attribute is a tuple of classes that are considered when\n looking for base classes during method resolution.\n\nclass.mro()\n\n This method can be overridden by a metaclass to customize the\n method resolution order for its instances. It is called at class\n instantiation, and its result is stored in ``__mro__``.\n\nclass.__subclasses__()\n\n Each new-style class keeps a list of weak references to its\n immediate subclasses. This method returns a list of all those\n references still alive. Example:\n\n >>> int.__subclasses__()\n []\n\n-[ Footnotes ]-\n\n[1] Additional information on these special methods may be found in\n the Python Reference Manual (*Basic customization*).\n\n[2] As a consequence, the list ``[1, 2]`` is considered equal to\n ``[1.0, 2.0]``, and similarly for tuples.\n\n[3] They must have since the parser can\'t tell the type of the\n operands.\n\n[4] 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\n[6] The advantage of leaving the newline on is that returning an empty\n string is then an unambiguous EOF indication. It is also possible\n (in cases where it might matter, for example, if you want to make\n an exact copy of a file while scanning its lines) to tell whether\n the last line of a file ended in a newline or not (yes this\n happens!).\n', - 'specialnames': '\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named ``__getitem__()``, and ``x`` is an instance of this\nclass, then ``x[i]`` is roughly equivalent to ``x.__getitem__(i)`` for\nold-style classes and ``type(x).__getitem__(x, i)`` for new-style\nclasses. Except where mentioned, attempts to execute an operation\nraise an 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_traceback`` 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.exc_traceback`` or ``sys.last_traceback``. Circular\n references which are garbage are detected when the option cycle\n detector is enabled (it\'s on by default), but can only be cleaned\n up if there are no Python-level ``__del__()`` methods involved.\n Refer to the documentation for the ``gc`` module for more\n information about how ``__del__()`` methods are handled by the\n cycle detector, particularly the description of the ``garbage``\n value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\n See also the *-R* command-line option.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function and by string\n conversions (reverse quotes) to compute the "official" string\n representation of an object. If at all possible, this should look\n like a valid Python expression that could be used to recreate an\n object with the same value (given an appropriate environment). If\n this is not possible, a string of the form ``<...some useful\n description...>`` should be returned. The return value must be a\n string object. If a class defines ``__repr__()`` but not\n ``__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 the ``str()`` built-in function and by the ``print``\n statement to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__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 New in version 2.1.\n\n These are the so-called "rich comparison" methods, and are called\n for comparison operators in preference to ``__cmp__()`` below. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` call ``x.__ne__(y)``, ``x>y`` calls ``x.__gt__(y)``, and\n ``x>=y`` calls ``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.__cmp__(self, other)\n\n Called by comparison operations if rich comparison (see above) is\n not defined. Should return a negative integer if ``self < other``,\n zero if ``self == other``, a positive integer if ``self > other``.\n If no ``__cmp__()``, ``__eq__()`` or ``__ne__()`` operation is\n defined, class instances are compared by object identity\n ("address"). See also the description of ``__hash__()`` for some\n important notes on creating *hashable* objects which support custom\n comparison operations and are usable as dictionary keys. (Note: the\n restriction that exceptions are not propagated by ``__cmp__()`` has\n been removed since Python 1.5.)\n\nobject.__rcmp__(self, other)\n\n Changed in version 2.1: No longer supported.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define a ``__cmp__()`` or ``__eq__()`` method\n it should not define a ``__hash__()`` operation either; if it\n defines ``__cmp__()`` or ``__eq__()`` but not ``__hash__()``, its\n instances will not be usable in hashed collections. If a class\n defines mutable objects and implements a ``__cmp__()`` or\n ``__eq__()`` method, it should not implement ``__hash__()``, since\n hashable collection implementations require that a object\'s hash\n value is immutable (if the object\'s hash value changes, it will be\n in the wrong hash bucket).\n\n User-defined classes have ``__cmp__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns a result derived from\n ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__cmp__()`` or ``__eq__()`` such that\n the hash value returned is no longer appropriate (e.g. by switching\n to a value-based concept of equality instead of the default\n identity based equality) can explicitly flag themselves as being\n unhashable by setting ``__hash__ = None`` in the class definition.\n Doing so means that not only will instances of the class raise an\n appropriate ``TypeError`` when a program attempts to retrieve their\n hash value, but they will also be correctly identified as\n unhashable when checking ``isinstance(obj, collections.Hashable)``\n (unlike classes which define their own ``__hash__()`` to explicitly\n raise ``TypeError``).\n\n Changed in version 2.5: ``__hash__()`` may now also return a long\n integer object; the 32-bit integer is then derived from the hash of\n that object.\n\n Changed in version 2.6: ``__hash__`` may now be set to ``None`` to\n explicitly flag instances of a class as unhashable.\n\nobject.__nonzero__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``, or their integer\n equivalents ``0`` or ``1``. When this method is not defined,\n ``__len__()`` is called, if it is defined, and the object is\n considered true if its result is nonzero. If a class defines\n neither ``__len__()`` nor ``__nonzero__()``, all its instances are\n considered true.\n\nobject.__unicode__(self)\n\n Called to implement ``unicode()`` built-in; should return a Unicode\n object. When this method is not defined, string conversion is\n attempted, and the result of string conversion is converted to\n Unicode using the system default encoding.\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 in new-style classes.\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 not simply execute ``self.name = value`` --- this would\n cause a recursive call to itself. Instead, it should insert the\n value in the dictionary of instance attributes, e.g.,\n ``self.__dict__[name] = value``. For new-style classes, rather\n than accessing the instance dictionary, it should call the base\n 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\n\nMore attribute access for new-style classes\n-------------------------------------------\n\nThe following methods only apply to new-style classes.\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 for new-style\n classes*.\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. Note that descriptors are only invoked for new\nstyle objects or classes (ones that subclass ``object()`` or\n``type()``).\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 a new-style object instance, ``a.x`` is transformed\n into the call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a new-style class, ``A.x`` is transformed into the\n call: ``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 both old and new-style classes have a\ndictionary for attribute storage. This wastes space for objects\nhaving very few instance variables. The space consumption can become\nacute when creating large numbers of instances.\n\nThe default can be overridden by defining *__slots__* in a new-style\nclass definition. The *__slots__* declaration takes a sequence of\ninstance variables and reserves just enough space in each instance to\nhold a value for each variable. Space is saved because *__dict__* is\nnot created for each instance.\n\n__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 new-style class, *__slots__* reserves space for the declared\n variables and prevents the automatic creation of *__dict__* and\n *__weakref__* for each instance.\n\n New in version 2.2.\n\nNotes on using *__slots__*\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 Changed in version 2.3: Previously, adding ``\'__dict__\'`` to the\n *__slots__* declaration would not enable the assignment of new\n attributes not specifically listed in the sequence of instance\n variable names.\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 Changed in version 2.3: Previously, adding ``\'__weakref__\'`` to the\n *__slots__* declaration would not enable support for weak\n references.\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 ``long``, ``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 Changed in version 2.6: Previously, *__class__* assignment raised an\n error if either new or old class had *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, new-style classes are constructed using ``type()``. A\nclass definition is read into a separate namespace and the value of\nclass name is bound to the result of ``type(name, bases, dict)``.\n\nWhen the class definition is read, if *__metaclass__* is defined then\nthe callable assigned to it will be called instead of ``type()``. This\nallows classes or functions to be written which monitor or alter the\nclass creation process:\n\n* Modifying the class dictionary prior to the class being created.\n\n* Returning an instance of another class -- essentially performing the\n role of a factory function.\n\nThese steps will have to be performed in the metaclass\'s ``__new__()``\nmethod -- ``type.__new__()`` can then be called from this method to\ncreate a class with different properties. This example adds a new\nelement to the class dictionary before creating the class:\n\n class metacls(type):\n def __new__(mcs, name, bases, dict):\n dict[\'foo\'] = \'metacls was here\'\n return type.__new__(mcs, name, bases, dict)\n\nYou can of course also override other class methods (or add new\nmethods); for example defining a custom ``__call__()`` method in the\nmetaclass allows custom behavior when the class is called, e.g. not\nalways creating a new instance.\n\n__metaclass__\n\n This variable can be any callable accepting arguments for ``name``,\n ``bases``, and ``dict``. Upon class creation, the callable is used\n instead of the built-in ``type()``.\n\n New in version 2.2.\n\nThe appropriate metaclass is determined by the following precedence\nrules:\n\n* If ``dict[\'__metaclass__\']`` exists, it is used.\n\n* Otherwise, if there is at least one base class, its metaclass is\n used (this looks for a *__class__* attribute first and if not found,\n uses its type).\n\n* Otherwise, if a global variable named __metaclass__ exists, it is\n used.\n\n* Otherwise, the old-style, classic metaclass (types.ClassType) is\n used.\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored including logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\n\nCustomizing instance and subclass checks\n========================================\n\nNew in version 2.6.\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. (For backwards compatibility, the method\n``__getslice__()`` (see below) can also be defined to handle simple,\nbut not extended slices.) It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``has_key()``,\n``get()``, ``clear()``, ``setdefault()``, ``iterkeys()``,\n``itervalues()``, ``iteritems()``, ``pop()``, ``popitem()``,\n``copy()``, and ``update()`` behaving similar to those for Python\'s\nstandard dictionary objects. The ``UserDict`` module provides a\n``DictMixin`` class to help create those methods from a base set of\n``__getitem__()``, ``__setitem__()``, ``__delitem__()``, and\n``keys()``. Mutable sequences should provide methods ``append()``,\n``count()``, ``index()``, ``extend()``, ``insert()``, ``pop()``,\n``remove()``, ``reverse()`` and ``sort()``, like Python standard list\nobjects. Finally, sequence types should implement addition (meaning\nconcatenation) and multiplication (meaning repetition) by defining the\nmethods ``__add__()``, ``__radd__()``, ``__iadd__()``, ``__mul__()``,\n``__rmul__()`` and ``__imul__()`` described below; they should not\ndefine ``__coerce__()`` or other numerical operators. It is\nrecommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should be equivalent of ``has_key()``;\nfor sequences, 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``iterkeys()``; 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 ``__nonzero__()`` method and whose\n ``__len__()`` method returns zero is considered to be false in a\n Boolean context.\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 ``iterkeys()``.\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\n New in version 2.6.\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\nAdditional methods for emulation of sequence types\n==================================================\n\nThe following optional methods can be defined to further emulate\nsequence objects. Immutable sequences methods should at most only\ndefine ``__getslice__()``; mutable sequences might define all three\nmethods.\n\nobject.__getslice__(self, i, j)\n\n Deprecated since version 2.0: Support slice objects as parameters\n to the ``__getitem__()`` method. (However, built-in types in\n CPython currently still implement ``__getslice__()``. Therefore,\n you have to override it in derived classes when implementing\n slicing.)\n\n Called to implement evaluation of ``self[i:j]``. The returned\n object should be of the same type as *self*. Note that missing *i*\n or *j* in the slice expression are replaced by zero or\n ``sys.maxint``, respectively. If negative indexes are used in the\n slice, the length of the sequence is added to that index. If the\n instance does not implement the ``__len__()`` method, an\n ``AttributeError`` is raised. No guarantee is made that indexes\n adjusted this way are not still negative. Indexes which are\n greater than the length of the sequence are not modified. If no\n ``__getslice__()`` is found, a slice object is created instead, and\n passed to ``__getitem__()`` instead.\n\nobject.__setslice__(self, i, j, sequence)\n\n Called to implement assignment to ``self[i:j]``. Same notes for *i*\n and *j* as for ``__getslice__()``.\n\n This method is deprecated. If no ``__setslice__()`` is found, or\n for extended slicing of the form ``self[i:j:k]``, a slice object is\n created, and passed to ``__setitem__()``, instead of\n ``__setslice__()`` being called.\n\nobject.__delslice__(self, i, j)\n\n Called to implement deletion of ``self[i:j]``. Same notes for *i*\n and *j* as for ``__getslice__()``. This method is deprecated. If no\n ``__delslice__()`` is found, or for extended slicing of the form\n ``self[i:j:k]``, a slice object is created, and passed to\n ``__delitem__()``, instead of ``__delslice__()`` being called.\n\nNotice that these methods are only invoked when a single slice with a\nsingle colon is used, and the slice method is available. For slice\noperations involving extended slice notation, or in absence of the\nslice methods, ``__getitem__()``, ``__setitem__()`` or\n``__delitem__()`` is called with a slice object as argument.\n\nThe following example demonstrate how to make your program or module\ncompatible with earlier versions of Python (assuming that methods\n``__getitem__()``, ``__setitem__()`` and ``__delitem__()`` support\nslice objects as arguments):\n\n class MyClass:\n ...\n def __getitem__(self, index):\n ...\n def __setitem__(self, index, value):\n ...\n def __delitem__(self, index):\n ...\n\n if sys.version_info < (2, 0):\n # They won\'t be defined if version is at least 2.0 final\n\n def __getslice__(self, i, j):\n return self[max(0, i):max(0, j):]\n def __setslice__(self, i, j, seq):\n self[max(0, i):max(0, j):] = seq\n def __delslice__(self, i, j):\n del self[max(0, i):max(0, j):]\n ...\n\nNote the calls to ``max()``; these are necessary because of the\nhandling of negative indices before the ``__*slice__()`` methods are\ncalled. When negative indexes are used, the ``__*item__()`` methods\nreceive them as provided, but the ``__*slice__()`` methods get a\n"cooked" form of the index values. For each negative index value, the\nlength of the sequence is added to the index before calling the method\n(which may still result in a negative index); this is the customary\nhandling of negative indexes by the built-in sequence types, and the\n``__*item__()`` methods are expected to do this as well. However,\nsince they should already be doing that, negative indexes cannot be\npassed in; they must be constrained to the bounds of the sequence\nbefore being passed to the ``__*item__()`` methods. Calling ``max(0,\ni)`` conveniently returns the proper value.\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.__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()``,\n ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``, ``|``). For\n instance, to evaluate the expression ``x + y``, where *x* is an\n 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__()`` (described below). Note\n that ``__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.__div__(self, other)\nobject.__truediv__(self, other)\n\n The division operator (``/``) is implemented by these methods. The\n ``__truediv__()`` method is used when ``__future__.division`` is in\n effect, otherwise ``__div__()`` is used. If only one of these two\n methods is defined, the object will not support division in the\n alternate context; ``TypeError`` will be raised instead.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rdiv__(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()``,\n ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``, ``|``) with\n reflected (swapped) operands. These functions are only called if\n the left operand does not support the corresponding operation and\n the operands are of different types. [2] For instance, to evaluate\n the expression ``x - y``, where *y* is an instance of a class that\n has an ``__rsub__()`` method, ``y.__rsub__(x)`` is called if\n ``x.__sub__(y)`` returns *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.__idiv__(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.__long__(self)\nobject.__float__(self)\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``long()``, and ``float()``. Should return a value of\n the appropriate type.\n\nobject.__oct__(self)\nobject.__hex__(self)\n\n Called to implement the built-in functions ``oct()`` and ``hex()``.\n Should return a string value.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing). Must return\n an integer (int or long).\n\n New in version 2.5.\n\nobject.__coerce__(self, other)\n\n Called to implement "mixed-mode" numeric arithmetic. Should either\n return a 2-tuple containing *self* and *other* converted to a\n common numeric type, or ``None`` if conversion is impossible. When\n the common type would be the type of ``other``, it is sufficient to\n return ``None``, since the interpreter will also ask the other\n object to attempt a coercion (but sometimes, if the implementation\n of the other type cannot be changed, it is useful to do the\n conversion to the other type here). A return value of\n ``NotImplemented`` is equivalent to returning ``None``.\n\n\nCoercion rules\n==============\n\nThis section used to document the rules for coercion. As the language\nhas evolved, the coercion rules have become hard to document\nprecisely; documenting what one version of one particular\nimplementation does is undesirable. Instead, here are some informal\nguidelines regarding coercion. In Python 3, coercion will not be\nsupported.\n\n* If the left operand of a % operator is a string or Unicode object,\n no coercion takes place and the string formatting operation is\n invoked instead.\n\n* It is no longer recommended to define a coercion operation. Mixed-\n mode operations on types that don\'t define coercion pass the\n original arguments to the operation.\n\n* New-style classes (those derived from ``object``) never invoke the\n ``__coerce__()`` method in response to a binary operator; the only\n time ``__coerce__()`` is invoked is when the built-in function\n ``coerce()`` is called.\n\n* For most intents and purposes, an operator that returns\n ``NotImplemented`` is treated the same as one that is not\n implemented at all.\n\n* Below, ``__op__()`` and ``__rop__()`` are used to signify the\n generic method names corresponding to an operator; ``__iop__()`` is\n used for the corresponding in-place operator. For example, for the\n operator \'``+``\', ``__add__()`` and ``__radd__()`` are used for the\n left and right variant of the binary operator, and ``__iadd__()``\n for the in-place variant.\n\n* For objects *x* and *y*, first ``x.__op__(y)`` is tried. If this is\n not implemented or returns ``NotImplemented``, ``y.__rop__(x)`` is\n tried. If this is also not implemented or returns\n ``NotImplemented``, a ``TypeError`` exception is raised. But see\n the following exception:\n\n* Exception to the previous item: if the left operand is an instance\n of a built-in type or a new-style class, and the right operand is an\n instance of a proper subclass of that type or class and overrides\n the base\'s ``__rop__()`` method, the right operand\'s ``__rop__()``\n method is tried *before* the left operand\'s ``__op__()`` method.\n\n This is done so that a subclass can completely override binary\n operators. Otherwise, the left operand\'s ``__op__()`` method would\n always accept the right operand: when an instance of a given class\n is expected, an instance of a subclass of that class is always\n acceptable.\n\n* When either operand type defines a coercion, this coercion is called\n before that type\'s ``__op__()`` or ``__rop__()`` method is called,\n but no sooner. If the coercion returns an object of a different\n type for the operand whose coercion is invoked, part of the process\n is redone using the new object.\n\n* When an in-place operator (like \'``+=``\') is used, if the left\n operand implements ``__iop__()``, it is invoked without any\n coercion. When the operation falls back to ``__op__()`` and/or\n ``__rop__()``, the normal coercion rules apply.\n\n* In ``x + y``, if *x* is a sequence that implements sequence\n concatenation, sequence concatenation is invoked.\n\n* In ``x * y``, if one operand is a sequence that implements sequence\n repetition, and the other is an integer (``int`` or ``long``),\n sequence repetition is invoked.\n\n* Rich comparisons (implemented by methods ``__eq__()`` and so on)\n never use coercion. Three-way comparison (implemented by\n ``__cmp__()``) does use coercion under the same conditions as other\n binary operations use it.\n\n* In the current implementation, the built-in numeric types ``int``,\n ``long``, ``float``, and ``complex`` do not use coercion. All these\n types implement a ``__coerce__()`` method, for use by the built-in\n ``coerce()`` function.\n\n Changed in version 2.7.\n\n\nWith Statement Context Managers\n===============================\n\nNew in version 2.5.\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 for old-style classes\n===========================================\n\nFor old-style classes, special methods are always looked up in exactly\nthe same way as any other method or attribute. This is the case\nregardless of whether the method is being looked up explicitly as in\n``x.__getitem__(i)`` or implicitly as in ``x[i]``.\n\nThis behaviour means that special methods may exhibit different\nbehaviour for different instances of a single old-style class if the\nappropriate special attributes are set differently:\n\n >>> class C:\n ... pass\n ...\n >>> c1 = C()\n >>> c2 = C()\n >>> c1.__len__ = lambda: 5\n >>> c2.__len__ = lambda: 9\n >>> len(c1)\n 5\n >>> len(c2)\n 9\n\n\nSpecial method lookup for new-style classes\n===========================================\n\nFor new-style classes, implicit invocations of special methods are\nonly guaranteed to work correctly if defined on an object\'s type, not\nin the object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception (unlike the equivalent example\nwith old-style classes):\n\n >>> class C(object):\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as ``__hash__()`` and ``__repr__()`` that are implemented\nby all objects, including type objects. If the implicit lookup of\nthese methods used the conventional lookup process, they would fail\nwhen invoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe ``__getattribute__()`` method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print "Metaclass getattribute invoked"\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object):\n ... __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\nBelow are listed the string methods which both 8-bit strings and\nUnicode objects support. Some of them are also available on\n``bytearray`` objects.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, unicode, list, tuple,\nbytearray, buffer, xrange* section. To output formatted strings use\ntemplate strings or the ``%`` operator described in the *String\nFormatting Operations* section. Also, see the ``re`` module for string\nfunctions based on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\n For 8-bit strings, this method is locale-dependent.\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\n Changed in version 2.4: Support for the *fillchar* argument.\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.decode([encoding[, errors]])\n\n Decodes the string using the codec registered for *encoding*.\n *encoding* defaults to the default string encoding. *errors* may\n be given to set a different error handling scheme. The default is\n ``\'strict\'``, meaning that encoding errors raise ``UnicodeError``.\n Other possible values are ``\'ignore\'``, ``\'replace\'`` and any other\n name registered via ``codecs.register_error()``, see section *Codec\n Base Classes*.\n\n New in version 2.2.\n\n Changed in version 2.3: Support for other error handling schemes\n added.\n\n Changed in version 2.7: Support for keyword arguments added.\n\nstr.encode([encoding[, errors]])\n\n Return an encoded version of the string. Default encoding is the\n current default string encoding. *errors* may be given to set a\n different error handling scheme. The default for *errors* is\n ``\'strict\'``, meaning that encoding errors raise a\n ``UnicodeError``. Other possible values are ``\'ignore\'``,\n ``\'replace\'``, ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and\n any other name registered via ``codecs.register_error()``, see\n section *Codec Base Classes*. For a list of possible encodings, see\n section *Standard Encodings*.\n\n New in version 2.0.\n\n Changed in version 2.3: Support for ``\'xmlcharrefreplace\'`` and\n ``\'backslashreplace\'`` and other error handling schemes added.\n\n Changed in version 2.7: 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\n Changed in version 2.5: Accept tuples as *suffix*.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. 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\n This method of string formatting is the new standard in Python 3,\n and should be preferred to the ``%`` formatting described in\n *String Formatting Operations* in new code.\n\n New in version 2.6.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise.\n\n For 8-bit strings, this method is locale-dependent.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise.\n\n For 8-bit strings, this method is locale-dependent.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise.\n\n For 8-bit strings, this method is locale-dependent.\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\n For 8-bit strings, this method is locale-dependent.\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise.\n\n For 8-bit strings, this method is locale-dependent.\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\n For 8-bit strings, this method is locale-dependent.\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\n For 8-bit strings, this method is locale-dependent.\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. The separator between elements is the\n 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\n Changed in version 2.4: Support for the *fillchar* argument.\n\nstr.lower()\n\n Return a copy of the string with all the cased characters [4]\n converted to lowercase.\n\n For 8-bit strings, this method is locale-dependent.\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\n Changed in version 2.2.2: Support for the *chars* argument.\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\n New in version 2.5.\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\n Changed in version 2.4: Support for the *fillchar* argument.\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\n New in version 2.5.\n\nstr.rsplit([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\n New in version 2.4.\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\n Changed in version 2.2.2: Support for the *chars* argument.\n\nstr.split([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified 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\n Changed in version 2.5: Accept tuples as *prefix*.\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\n Changed in version 2.2.2: Support for the *chars* argument.\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa.\n\n For 8-bit strings, this method is locale-dependent.\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\n For 8-bit strings, this method is locale-dependent.\n\nstr.translate(table[, deletechars])\n\n Return a copy of the string where all characters occurring in the\n optional argument *deletechars* are removed, and the remaining\n characters have been mapped through the given translation table,\n which must be a string of length 256.\n\n You can use the ``maketrans()`` helper function in the ``string``\n module to create a translation table. For string objects, set the\n *table* argument to ``None`` for translations that only delete\n characters:\n\n >>> \'read this short text\'.translate(None, \'aeiou\')\n \'rd ths shrt txt\'\n\n New in version 2.6: Support for a ``None`` *table* argument.\n\n For Unicode objects, the ``translate()`` method does not accept the\n optional *deletechars* argument. Instead, it returns a copy of the\n *s* where all characters have been mapped through the given\n translation table which must be a mapping of Unicode ordinals to\n Unicode ordinals, Unicode strings or ``None``. Unmapped characters\n are left untouched. Characters mapped to ``None`` are deleted.\n Note, a more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see ``encodings.cp1251``\n 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 For 8-bit strings, this method is locale-dependent.\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\n New in version 2.2.2.\n\nThe following methods are present only on unicode objects:\n\nunicode.isnumeric()\n\n Return ``True`` if there are only numeric characters in S,\n ``False`` otherwise. Numeric characters include digit characters,\n and all characters that have the Unicode numeric value property,\n e.g. U+2155, VULGAR FRACTION ONE FIFTH.\n\nunicode.isdecimal()\n\n Return ``True`` if there are only decimal characters in S,\n ``False`` otherwise. Decimal characters include digit characters,\n and all characters that can be used to form decimal-radix numbers,\n e.g. U+0660, ARABIC-INDIC DIGIT ZERO.\n', - 'strings': '\nString literals\n***************\n\nString literals are described by the following lexical definitions:\n\n stringliteral ::= [stringprefix](shortstring | longstring)\n stringprefix ::= "r" | "u" | "ur" | "R" | "U" | "UR" | "Ur" | "uR"\n | "b" | "B" | "br" | "Br" | "bR" | "BR"\n shortstring ::= "\'" shortstringitem* "\'" | \'"\' shortstringitem* \'"\'\n longstring ::= "\'\'\'" longstringitem* "\'\'\'"\n | \'"""\' longstringitem* \'"""\'\n shortstringitem ::= shortstringchar | escapeseq\n longstringitem ::= longstringchar | escapeseq\n shortstringchar ::= \n longstringchar ::= \n escapeseq ::= "\\" \n\nOne syntactic restriction not indicated by these productions is that\nwhitespace is not allowed between the ``stringprefix`` and the rest of\nthe string literal. The source character set is defined by the\nencoding declaration; it is ASCII if no encoding declaration is given\nin the source file; see section *Encoding declarations*.\n\nIn plain English: String literals can be enclosed in matching single\nquotes (``\'``) or double quotes (``"``). They can also be enclosed in\nmatching groups of three single or double quotes (these are generally\nreferred to as *triple-quoted strings*). The backslash (``\\``)\ncharacter is used to escape characters that otherwise have a special\nmeaning, such as newline, backslash itself, or the quote character.\nString literals may optionally be prefixed with a letter ``\'r\'`` or\n``\'R\'``; such strings are called *raw strings* and use different rules\nfor interpreting backslash escape sequences. A prefix of ``\'u\'`` or\n``\'U\'`` makes the string a Unicode string. Unicode strings use the\nUnicode character set as defined by the Unicode Consortium and ISO\n10646. Some additional escape sequences, described below, are\navailable in Unicode strings. A prefix of ``\'b\'`` or ``\'B\'`` is\nignored in Python 2; it indicates that the literal should become a\nbytes literal in Python 3 (e.g. when code is automatically converted\nwith 2to3). A ``\'u\'`` or ``\'b\'`` prefix may be followed by an ``\'r\'``\nprefix.\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`` | 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| ``\\N{name}`` | Character named *name* in the | |\n| | Unicode database (Unicode only) | |\n+-------------------+-----------------------------------+---------+\n| ``\\r`` | ASCII Carriage Return (CR) | |\n+-------------------+-----------------------------------+---------+\n| ``\\t`` | ASCII Horizontal Tab (TAB) | |\n+-------------------+-----------------------------------+---------+\n| ``\\uxxxx`` | Character with 16-bit hex value | (1) |\n| | *xxxx* (Unicode only) | |\n+-------------------+-----------------------------------+---------+\n| ``\\Uxxxxxxxx`` | Character with 32-bit hex value | (2) |\n| | *xxxxxxxx* (Unicode only) | |\n+-------------------+-----------------------------------+---------+\n| ``\\v`` | ASCII Vertical Tab (VT) | |\n+-------------------+-----------------------------------+---------+\n| ``\\ooo`` | Character with octal value *ooo* | (3,5) |\n+-------------------+-----------------------------------+---------+\n| ``\\xhh`` | Character with hex value *hh* | (4,5) |\n+-------------------+-----------------------------------+---------+\n\nNotes:\n\n1. Individual code units which form parts of a surrogate pair can be\n encoded using this escape sequence.\n\n2. Any Unicode character can be encoded this way, but characters\n outside the Basic Multilingual Plane (BMP) will be encoded using a\n surrogate pair if Python is compiled to use 16-bit code units (the\n default).\n\n3. As in Standard C, up to three octal digits are accepted.\n\n4. Unlike in Standard C, exactly two hex digits are required.\n\n5. In a string literal, hexadecimal and octal escapes denote the byte\n with the given value; it is not necessary that the byte encodes a\n character in the source character set. In a Unicode literal, these\n escapes denote a Unicode character with the given value.\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 marked as "(Unicode only)"\nin the table above fall into the category of unrecognized escapes for\nnon-Unicode string literals.\n\nWhen an ``\'r\'`` or ``\'R\'`` prefix is present, a character following a\nbackslash is included in the string without change, and *all\nbackslashes are left in the string*. For example, the string literal\n``r"\\n"`` consists of two characters: a backslash and a lowercase\n``\'n\'``. String quotes can be escaped with a backslash, but the\nbackslash remains in the string; for example, ``r"\\""`` is a valid\nstring literal consisting of two characters: a backslash and a double\nquote; ``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\nWhen an ``\'r\'`` or ``\'R\'`` prefix is used in conjunction with a\n``\'u\'`` or ``\'U\'`` prefix, then the ``\\uXXXX`` and ``\\UXXXXXXXX``\nescape sequences are processed while *all other backslashes are left\nin the string*. For example, the string literal ``ur"\\u0062\\n"``\nconsists of three Unicode characters: \'LATIN SMALL LETTER B\', \'REVERSE\nSOLIDUS\', and \'LATIN SMALL LETTER N\'. Backslashes can be escaped with\na preceding backslash; however, both remain in the string. As a\nresult, ``\\uXXXX`` escape sequences are only recognized when there are\nan odd number of backslashes.\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 of a sequence or mapping type.\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 a\nplain integer. If this value is negative, the length of the sequence\nis added to it (so that, e.g., ``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).\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``, ``0L``, ``0.0``,\n ``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 ``__nonzero__()`` or ``__len__()`` method, when that method returns\n the 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\nChanged in version 2.5: In previous versions of Python,\n``try``...``except``...``finally`` did not work. ``try``...``except``\nhad to be nested in ``try``...``finally``.\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 in that except clause, if present, and the except\nclause\'s suite is executed. All except clauses must have an\nexecutable block. When the end of this block is reached, execution\ncontinues normally after the entire try statement. (This means that\nif two nested handlers exist for the same exception, and the exception\noccurs in the try clause of the inner handler, the outer handler will\nnot handle the exception.)\n\nBefore an except clause\'s suite is executed, details about the\nexception are assigned to three variables in the ``sys`` module:\n``sys.exc_type`` receives the object identifying the exception;\n``sys.exc_value`` receives the exception\'s parameter;\n``sys.exc_traceback`` receives a traceback object (see section *The\nstandard type hierarchy*) identifying the point in the program where\nthe exception occurred. These details are also available through the\n``sys.exc_info()`` function, which returns a tuple ``(exc_type,\nexc_value, exc_traceback)``. Use of the corresponding variables is\ndeprecated in favor of this function, since their use is unsafe in a\nthreaded program. As of Python 1.5, the variables are restored to\ntheir previous values (before the call) when returning from a function\nthat handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is 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\nThe return value of a function is determined by the last ``return``\nstatement executed. Since the ``finally`` clause always executes, a\n``return`` statement executed in the ``finally`` clause will always be\nthe last one executed:\n\n >>> def foo():\n ... try:\n ... return \'try\'\n ... finally:\n ... return \'finally\'\n ...\n >>> foo()\n \'finally\'\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.).\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 built-in name\n ``Ellipsis``. It is used to indicate the presence of the ``...``\n syntax in a slice. 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 three types of integers:\n\n Plain integers\n These represent numbers in the range -2147483648 through\n 2147483647. (The range may be larger on machines with a\n larger natural word size, but not smaller.) When the result\n of an operation would fall outside this range, the result is\n normally returned as a long integer (in some cases, the\n exception ``OverflowError`` is raised instead). For the\n purpose of shift and mask operations, integers are assumed to\n have a binary, 2\'s complement notation using 32 or more bits,\n and hiding no bits from the user (i.e., all 4294967296\n different bit patterns correspond to different values).\n\n Long integers\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\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 plain integers, 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 and the least surprises when\n switching between the plain and long integer domains. Any\n operation, if it yields a result in the plain integer domain,\n will yield the same result in the long integer domain or when\n using mixed operands. The switch between domains is transparent\n to the programmer.\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``\n These represent complex numbers as a pair of machine-level\n double precision floating point numbers. The same caveats apply\n as for floating point numbers. The real and imaginary parts of a\n complex number ``z`` can be retrieved through the read-only\n attributes ``z.real`` and ``z.imag``.\n\nSequences\n These represent finite ordered sets indexed by non-negative\n numbers. The built-in function ``len()`` returns the number of\n items of a sequence. When the length of a sequence is *n*, the\n index set contains the numbers 0, 1, ..., *n*-1. Item *i* of\n sequence *a* is selected by ``a[i]``.\n\n Sequences also support slicing: ``a[i:j]`` selects all items with\n index *k* such that *i* ``<=`` *k* ``<`` *j*. When used as an\n expression, a slice is a sequence of the same type. This implies\n that the index set is renumbered so that it starts at 0.\n\n Some sequences also support "extended slicing" with a third "step"\n parameter: ``a[i:j:k]`` selects all items of *a* with index *x*\n where ``x = i + n*k``, *n* ``>=`` ``0`` and *i* ``<=`` *x* ``<``\n *j*.\n\n Sequences are distinguished according to their mutability:\n\n Immutable sequences\n An object of an immutable sequence type cannot change once it is\n created. (If the object contains references to other objects,\n these other objects may be mutable and may be changed; however,\n the collection of objects directly referenced by an immutable\n object cannot change.)\n\n The following types are immutable sequences:\n\n Strings\n The items of a string are characters. There is no separate\n character type; a character is represented by a string of one\n item. Characters represent (at least) 8-bit bytes. The\n built-in functions ``chr()`` and ``ord()`` convert between\n characters and nonnegative integers representing the byte\n values. Bytes with the values 0-127 usually represent the\n corresponding ASCII values, but the interpretation of values\n is up to the program. The string data type is also used to\n represent arrays of bytes, e.g., to hold data read from a\n file.\n\n (On systems whose native character set is not ASCII, strings\n may use EBCDIC in their internal representation, provided the\n functions ``chr()`` and ``ord()`` implement a mapping between\n ASCII and EBCDIC, and string comparison preserves the ASCII\n order. Or perhaps someone can propose a better rule?)\n\n Unicode\n The items of a Unicode object are Unicode code units. A\n Unicode code unit is represented by a Unicode object of one\n item and can hold either a 16-bit or 32-bit value\n representing a Unicode ordinal (the maximum value for the\n ordinal is given in ``sys.maxunicode``, and depends on how\n Python is configured at compile time). Surrogate pairs may\n be present in the Unicode object, and will be reported as two\n separate items. The built-in functions ``unichr()`` and\n ``ord()`` convert between code units and nonnegative integers\n representing the Unicode ordinals as defined in the Unicode\n Standard 3.0. Conversion from and to other encodings are\n possible through the Unicode method ``encode()`` and the\n built-in function ``unicode()``.\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 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.\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``, ``gdbm``, and ``bsddb`` provide\n additional examples of mapping types.\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 | ``func_doc`` | string, or ``None`` if | |\n | | unavailable. | |\n +-------------------------+---------------------------------+-------------+\n | ``__name__`` | The function\'s name. | Writable |\n | ``func_name`` | | |\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 | ``func_defaults`` | 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 | ``func_code`` | the compiled function body. | |\n +-------------------------+---------------------------------+-------------+\n | ``__globals__`` | A reference to the dictionary | Read-only |\n | ``func_globals`` | 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 | ``func_dict`` | arbitrary function attributes. | |\n +-------------------------+---------------------------------+-------------+\n | ``__closure__`` | ``None`` or a tuple of cells | Read-only |\n | ``func_closure`` | that contain bindings for the | |\n | | function\'s free variables. | |\n +-------------------------+---------------------------------+-------------+\n\n Most of the attributes labelled "Writable" check the type of the\n assigned value.\n\n Changed in version 2.4: ``func_name`` is now writable.\n\n Changed in version 2.6: The double-underscore attributes\n ``__closure__``, ``__code__``, ``__defaults__``, and\n ``__globals__`` were introduced as aliases for the corresponding\n ``func_*`` attributes for forwards compatibility with Python 3.\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 User-defined methods\n A user-defined method object combines a class, a class instance\n (or ``None``) and any callable object (normally a user-defined\n function).\n\n Special read-only attributes: ``im_self`` is the class instance\n object, ``im_func`` is the function object; ``im_class`` is the\n class of ``im_self`` for bound methods or the class that asked\n for the method for unbound methods; ``__doc__`` is the method\'s\n documentation (same as ``im_func.__doc__``); ``__name__`` is the\n method name (same as ``im_func.__name__``); ``__module__`` is\n the name of the module the method was defined in, or ``None`` if\n unavailable.\n\n Changed in version 2.2: ``im_self`` used to refer to the class\n that defined the method.\n\n Changed in version 2.6: For Python 3 forward-compatibility,\n ``im_func`` is also available as ``__func__``, and ``im_self``\n as ``__self__``.\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, an unbound\n user-defined method object, or a class method object. When the\n attribute is a user-defined method object, a new method object\n is only created if the class from which it is being retrieved is\n the same as, or a derived class of, the class stored in the\n original method object; otherwise, the original method object is\n used as it is.\n\n When a user-defined method object is created by retrieving a\n user-defined function object from a class, its ``im_self``\n attribute is ``None`` and the method object is said to be\n unbound. When one is created by retrieving a user-defined\n function object from a class via one of its instances, its\n ``im_self`` attribute is the instance, and the method object is\n said to be bound. In either case, the new method\'s ``im_class``\n attribute is the class from which the retrieval takes place, and\n its ``im_func`` 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 ``im_func``\n attribute of the new instance is not the original method object\n but its ``im_func`` attribute.\n\n When a user-defined method object is created by retrieving a\n class method object from a class or instance, its ``im_self``\n attribute is the class itself, and its ``im_func`` attribute is\n the function object underlying the class method.\n\n When an unbound user-defined method object is called, the\n underlying function (``im_func``) is called, with the\n restriction that the first argument must be an instance of the\n proper class (``im_class``) or of a derived class thereof.\n\n When a bound user-defined method object is called, the\n underlying function (``im_func``) is called, inserting the class\n instance (``im_self``) in front of the argument list. For\n instance, when ``C`` is a class which contains a definition for\n a function ``f()``, and ``x`` is an instance of ``C``, calling\n ``x.f(1)`` is equivalent to calling ``C.f(x, 1)``.\n\n When a user-defined method object is derived from a class method\n object, the "class instance" stored in ``im_self`` will actually\n be the class itself, so that calling either ``x.f(1)`` or\n ``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 (unbound or\n bound) method object happens each time the attribute is\n retrieved from the class or instance. In some cases, a fruitful\n optimization is to assign the attribute to a local variable and\n call that local variable. Also notice that this transformation\n only happens for user-defined functions; other callable objects\n (and all non-callable objects) are retrieved without\n transformation. It is also important to note that user-defined\n functions which are attributes of a class instance are not\n converted to bound methods; this *only* happens when the\n function is an attribute of the class.\n\n Generator functions\n A function or method which uses the ``yield`` statement (see\n section *The yield statement*) is called a *generator function*.\n Such a function, when called, always returns an iterator object\n which can be used to execute the body of the function: calling\n the iterator\'s ``next()`` method will cause the function to\n execute until it provides a value using the ``yield`` statement.\n When the function executes a ``return`` statement or falls off\n the end, a ``StopIteration`` exception is raised and the\n iterator will have reached the end of the set of values to be\n returned.\n\n Built-in functions\n A built-in function object is a wrapper around a C function.\n Examples of built-in functions are ``len()`` and ``math.sin()``\n (``math`` is a standard built-in module). The number and type of\n the arguments are determined by the C function. Special read-\n only attributes: ``__doc__`` is the function\'s documentation\n string, or ``None`` if unavailable; ``__name__`` is the\n function\'s name; ``__self__`` is set to ``None`` (but see the\n next item); ``__module__`` is the name of the module the\n function was defined in or ``None`` if unavailable.\n\n Built-in methods\n This is really a different disguise of a built-in function, this\n time containing an object passed to the C function as an\n implicit extra argument. An example of a built-in method is\n ``alist.append()``, assuming *alist* is a list object. In this\n case, the special read-only attribute ``__self__`` is set to the\n object denoted by *alist*.\n\n Class Types\n Class types, or "new-style classes," are callable. These\n objects normally act as factories for new instances of\n themselves, but variations are possible for class types that\n override ``__new__()``. The arguments of the call are passed to\n ``__new__()`` and, in the typical case, to ``__init__()`` to\n initialize the new instance.\n\n Classic Classes\n Class objects are described below. When a class object is\n called, a new class instance (also described below) is created\n and returned. This implies a call to the class\'s ``__init__()``\n method if it has one. Any arguments are passed on to the\n ``__init__()`` method. If there is no ``__init__()`` method,\n the class must be called without arguments.\n\n Class instances\n Class instances are described below. Class instances are\n callable only when the class has a ``__call__()`` method;\n ``x(arguments)`` is a shorthand for ``x.__call__(arguments)``.\n\nModules\n Modules are imported by the ``import`` statement (see section *The\n import statement*). A module object has a namespace implemented by\n a dictionary object (this is the dictionary referenced by the\n func_globals attribute of functions defined in the module).\n Attribute references are translated to lookups in this dictionary,\n e.g., ``m.x`` is equivalent to ``m.__dict__["x"]``. A module object\n does not contain the code object used to initialize the module\n (since it isn\'t needed once the initialization is done).\n\n Attribute assignment updates the module\'s namespace dictionary,\n e.g., ``m.x = 1`` is equivalent to ``m.__dict__["x"] = 1``.\n\n Special read-only attribute: ``__dict__`` is the module\'s namespace\n as a dictionary object.\n\n **CPython implementation detail:** Because of the way CPython\n clears module dictionaries, the module dictionary will be cleared\n when the module falls out of scope even if the dictionary still has\n live references. To avoid this, copy the dictionary or keep the\n module around while using its dictionary directly.\n\n Predefined (writable) attributes: ``__name__`` is the module\'s\n name; ``__doc__`` is the module\'s documentation string, or ``None``\n if unavailable; ``__file__`` is the pathname of the file from which\n the module was loaded, if it was loaded from a file. The\n ``__file__`` attribute is not present for C modules that are\n statically linked into the interpreter; for extension modules\n loaded dynamically from a shared library, it is the pathname of the\n shared library file.\n\nClasses\n Both class types (new-style classes) and class objects (old-\n style/classic classes) are typically created by class definitions\n (see section *Class definitions*). A class has a namespace\n implemented by a dictionary object. Class attribute references are\n translated to lookups in this dictionary, e.g., ``C.x`` is\n translated to ``C.__dict__["x"]`` (although for new-style classes\n in particular there are a number of hooks which allow for other\n means of locating attributes). When the attribute name is not found\n there, the attribute search continues in the base classes. For\n old-style classes, the search is depth-first, left-to-right in the\n order of occurrence in the base class list. New-style classes use\n the more complex C3 method resolution order which behaves correctly\n even in the presence of \'diamond\' inheritance structures where\n there are multiple inheritance paths leading back to a common\n ancestor. Additional details on the C3 MRO used by new-style\n classes can be found in the documentation accompanying the 2.3\n release at http://www.python.org/download/releases/2.3/mro/.\n\n When a class attribute reference (for class ``C``, say) would yield\n a user-defined function object or an unbound user-defined method\n object whose associated class is either ``C`` or one of its base\n classes, it is transformed into an unbound user-defined method\n object whose ``im_class`` attribute is ``C``. When it would yield a\n class method object, it is transformed into a bound user-defined\n method object whose ``im_self`` attribute is ``C``. When it would\n yield a static method object, it is transformed into the object\n wrapped by the static method object. See section *Implementing\n Descriptors* for another way in which attributes retrieved from a\n class may differ from those actually contained in its ``__dict__``\n (note that only new-style classes support descriptors).\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 or an unbound user-defined method object whose\n associated class is the class (call it ``C``) of the instance for\n which the attribute reference was initiated or one of its bases, it\n is transformed into a bound user-defined method object whose\n ``im_class`` attribute is ``C`` and whose ``im_self`` attribute is\n the instance. Static method and class method objects are also\n transformed, as if they had been retrieved from class ``C``; see\n above under "Classes". See section *Implementing Descriptors* for\n another way in which attributes of a class retrieved via its\n instances may differ from the objects actually stored in the\n class\'s ``__dict__``. If no class attribute is found, and the\n object\'s class has a ``__getattr__()`` method, that is called to\n 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\n instead of updating the instance dictionary directly.\n\n Class instances can pretend to be numbers, sequences, or mappings\n if they have methods with certain special names. See section\n *Special method names*.\n\n Special attributes: ``__dict__`` is the attribute dictionary;\n ``__class__`` is the instance\'s class.\n\nFiles\n A file object represents an open file. File objects are created by\n the ``open()`` built-in function, and also by ``os.popen()``,\n ``os.fdopen()``, and the ``makefile()`` method of socket objects\n (and perhaps by other functions or methods provided by extension\n modules). The objects ``sys.stdin``, ``sys.stdout`` and\n ``sys.stderr`` are initialized to file objects corresponding to the\n interpreter\'s standard input, output and error streams. See *File\n Objects* for complete documentation of file objects.\n\nInternal types\n A few types used internally by the interpreter are exposed to the\n user. Their definitions may change with future versions of the\n interpreter, but they are mentioned here for completeness.\n\n Code objects\n Code objects represent *byte-compiled* executable Python code,\n or *bytecode*. The difference between a code object and a\n function object is that the function object contains an explicit\n reference to the function\'s globals (the module in which it was\n defined), while a code object contains no context; also the\n default argument values are stored in the function object, not\n in the code object (because they represent values calculated at\n run-time). Unlike function objects, code objects are immutable\n and contain no references (directly or indirectly) to mutable\n objects.\n\n Special read-only attributes: ``co_name`` gives the function\n name; ``co_argcount`` is the number of positional arguments\n (including arguments with default values); ``co_nlocals`` is the\n number of local variables used by the function (including\n arguments); ``co_varnames`` is a tuple containing the names of\n the local variables (starting with the argument names);\n ``co_cellvars`` is a tuple containing the names of local\n variables that are referenced by nested functions;\n ``co_freevars`` is a tuple containing the names of free\n variables; ``co_code`` is a string representing the sequence of\n bytecode instructions; ``co_consts`` is a tuple containing the\n literals used by the bytecode; ``co_names`` is a tuple\n containing the names used by the bytecode; ``co_filename`` is\n the filename from which the code was compiled;\n ``co_firstlineno`` is the first line number of the function;\n ``co_lnotab`` is a string encoding the mapping from bytecode\n offsets to line numbers (for details see the source code of the\n interpreter); ``co_stacksize`` is the required stack size\n (including local variables); ``co_flags`` is an integer encoding\n a number of flags for the interpreter.\n\n The following flag bits are defined for ``co_flags``: bit\n ``0x04`` is set if the function uses the ``*arguments`` syntax\n to accept an arbitrary number of positional arguments; bit\n ``0x08`` is set if the function uses the ``**keywords`` syntax\n to accept arbitrary keyword arguments; bit ``0x20`` is set if\n the function is a generator.\n\n Future feature declarations (``from __future__ import\n division``) also use bits in ``co_flags`` to indicate whether a\n code object was compiled with a particular feature enabled: bit\n ``0x2000`` is set if the function was compiled with future\n division enabled; bits ``0x10`` and ``0x1000`` were used in\n earlier versions of Python.\n\n Other bits in ``co_flags`` are reserved for internal use.\n\n If a code object represents a function, the first item in\n ``co_consts`` is the documentation string of the function, or\n ``None`` if undefined.\n\n Frame objects\n Frame objects represent execution frames. They may occur in\n traceback objects (see below).\n\n Special read-only attributes: ``f_back`` is to the previous\n stack frame (towards the caller), or ``None`` if this is the\n bottom stack frame; ``f_code`` is the code object being executed\n in this frame; ``f_locals`` is the dictionary used to look up\n local variables; ``f_globals`` is used for global variables;\n ``f_builtins`` is used for built-in (intrinsic) names;\n ``f_restricted`` is a flag indicating whether the function is\n executing in restricted execution mode; ``f_lasti`` gives the\n precise instruction (this is an index into the bytecode string\n 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_exc_type``, ``f_exc_value``,\n ``f_exc_traceback`` represent the last exception raised in the\n parent frame provided another exception was ever raised in the\n current frame (in all other cases they are None); ``f_lineno``\n is the current line number of the frame --- writing to this from\n within a trace function jumps to the given line (only for the\n bottom-most frame). A debugger can implement a Jump command\n (aka Set Next Statement) by writing to f_lineno.\n\n Traceback objects\n Traceback objects represent a stack trace of an exception. A\n traceback object is created when an exception occurs. When the\n search for an exception handler unwinds the execution stack, at\n each unwound level a traceback object is inserted in front of\n the current traceback. When an exception handler is entered,\n the stack trace is made available to the program. (See section\n *The try statement*.) It is accessible as ``sys.exc_traceback``,\n and also as the third item of the tuple returned by\n ``sys.exc_info()``. The latter is the preferred interface,\n since it works correctly when the program is using multiple\n threads. When the program contains no suitable handler, the\n stack trace is written (nicely formatted) to the standard error\n stream; if the interpreter is interactive, it is also made\n available to the user as ``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 when *extended slice\n syntax* is used. This is a slice using two colons, or multiple\n slices or ellipses separated by commas, e.g., ``a[i:j:step]``,\n ``a[i:j, k:l]``, or ``a[..., i:j]``. They are also created by\n the built-in ``slice()`` 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 extended slice that the slice\n object would describe if applied to a sequence of *length*\n items. It returns a tuple of three integers; respectively\n these are the *start* and *stop* indices and the *step* or\n stride length of the slice. Missing or out-of-bounds indices\n are handled in a manner consistent with regular slices.\n\n New in version 2.3.\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 *iterable*\n object. Each item in the iterable must itself be an iterable 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 New in version 2.2.\n\n Changed in version 2.3: Support for building a dictionary from\n keyword arguments added.\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 New in version 2.5: If a subclass of dict defines a method\n ``__missing__()``, if the key *key* is not present, the\n ``d[key]`` operation calls that method with the key *key* as\n argument. The ``d[key]`` operation then returns or raises\n whatever is returned or raised by the ``__missing__(key)`` call\n if the key is not present. No other operations or methods invoke\n ``__missing__()``. If ``__missing__()`` is not defined,\n ``KeyError`` is raised. ``__missing__()`` must be a method; it\n cannot be an instance variable. For an example, see\n ``collections.defaultdict``.\n\n d[key] = value\n\n Set ``d[key]`` to *value*.\n\n del d[key]\n\n Remove ``d[key]`` from *d*. Raises a ``KeyError`` if *key* is\n not in the map.\n\n key in d\n\n Return ``True`` if *d* has a key *key*, else ``False``.\n\n New in version 2.2.\n\n key not in d\n\n Equivalent to ``not key in d``.\n\n New in version 2.2.\n\n iter(d)\n\n Return an iterator over the keys of the dictionary. This is a\n shortcut for ``iterkeys()``.\n\n clear()\n\n Remove all items from the dictionary.\n\n copy()\n\n Return a shallow copy of the dictionary.\n\n 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 New in version 2.3.\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 has_key(key)\n\n Test for the presence of *key* in the dictionary. ``has_key()``\n is deprecated in favor of ``key in d``.\n\n items()\n\n Return a copy of the dictionary\'s list of ``(key, value)``\n pairs.\n\n **CPython implementation detail:** Keys and values are listed in\n an arbitrary order which is non-random, varies across Python\n implementations, and depends on the dictionary\'s history of\n insertions and deletions.\n\n If ``items()``, ``keys()``, ``values()``, ``iteritems()``,\n ``iterkeys()``, and ``itervalues()`` are called with no\n intervening modifications to the dictionary, the lists will\n directly correspond. This allows the creation of ``(value,\n key)`` pairs using ``zip()``: ``pairs = zip(d.values(),\n d.keys())``. The same relationship holds for the ``iterkeys()``\n and ``itervalues()`` methods: ``pairs = zip(d.itervalues(),\n d.iterkeys())`` provides the same value for ``pairs``. Another\n way to create the same list is ``pairs = [(v, k) for (k, v) in\n d.iteritems()]``.\n\n iteritems()\n\n Return an iterator over the dictionary\'s ``(key, value)`` pairs.\n See the note for ``dict.items()``.\n\n Using ``iteritems()`` while adding or deleting entries in the\n dictionary may raise a ``RuntimeError`` or fail to iterate over\n all entries.\n\n New in version 2.2.\n\n iterkeys()\n\n Return an iterator over the dictionary\'s keys. See the note for\n ``dict.items()``.\n\n Using ``iterkeys()`` while adding or deleting entries in the\n dictionary may raise a ``RuntimeError`` or fail to iterate over\n all entries.\n\n New in version 2.2.\n\n itervalues()\n\n Return an iterator over the dictionary\'s values. See the note\n for ``dict.items()``.\n\n Using ``itervalues()`` while adding or deleting entries in the\n dictionary may raise a ``RuntimeError`` or fail to iterate over\n all entries.\n\n New in version 2.2.\n\n keys()\n\n Return a copy of the dictionary\'s list of keys. See the note\n for ``dict.items()``.\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 New in version 2.3.\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 Changed in version 2.4: Allowed the argument to be an iterable\n of key/value pairs and allowed keyword arguments.\n\n values()\n\n Return a copy of the dictionary\'s list of values. See the note\n for ``dict.items()``.\n\n viewitems()\n\n Return a new view of the dictionary\'s items (``(key, value)``\n pairs). See below for documentation of view objects.\n\n New in version 2.7.\n\n viewkeys()\n\n Return a new view of the dictionary\'s keys. See below for\n documentation of view objects.\n\n New in version 2.7.\n\n viewvalues()\n\n Return a new view of the dictionary\'s values. See below for\n documentation of view objects.\n\n New in version 2.7.\n\n\nDictionary view objects\n=======================\n\nThe objects returned by ``dict.viewkeys()``, ``dict.viewvalues()`` and\n``dict.viewitems()`` are *view objects*. They provide a dynamic view\non the dictionary\'s entries, which means that when the dictionary\nchanges, the view reflects these changes.\n\nDictionary views can be iterated over to yield their respective data,\nand support membership tests:\n\nlen(dictview)\n\n Return the number of entries in the dictionary.\n\niter(dictview)\n\n Return an iterator over the keys, values or items (represented as\n tuples of ``(key, value)``) in the dictionary.\n\n Keys and values are iterated over in an arbitrary order which is\n non-random, varies across Python implementations, and depends on\n the dictionary\'s history of insertions and deletions. If keys,\n values and items views are iterated over with no intervening\n modifications to the dictionary, the order of items will directly\n correspond. This allows the creation of ``(value, key)`` pairs\n using ``zip()``: ``pairs = zip(d.values(), d.keys())``. Another\n way to create the same list is ``pairs = [(v, k) for (k, v) in\n d.items()]``.\n\n Iterating views while adding or deleting entries in the dictionary\n may raise a ``RuntimeError`` or fail to iterate over all entries.\n\nx in dictview\n\n Return ``True`` if *x* is in the underlying dictionary\'s keys,\n values or items (in the latter case, *x* should be a ``(key,\n value)`` tuple).\n\nKeys views are set-like since their entries are unique and hashable.\nIf all values are hashable, so that (key, value) pairs are unique and\nhashable, then the items view is also set-like. (Values views are not\ntreated as set-like since the entries are generally not unique.) Then\nthese set operations are available ("other" refers either to another\nview or a set):\n\ndictview & other\n\n Return the intersection of the dictview and the other object as a\n new set.\n\ndictview | other\n\n Return the union of the dictview and the other object as a new set.\n\ndictview - other\n\n Return the difference between the dictview and the other object\n (all elements in *dictview* that aren\'t in *other*) as a new set.\n\ndictview ^ other\n\n Return the symmetric difference (all elements either in *dictview*\n or *other*, but not in both) of the dictview and the other object\n as a new set.\n\nAn example of dictionary view usage:\n\n >>> dishes = {\'eggs\': 2, \'sausage\': 1, \'bacon\': 1, \'spam\': 500}\n >>> keys = dishes.viewkeys()\n >>> values = dishes.viewvalues()\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', - '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\nThe implementation adds two special read-only attributes to class\ninstance methods: ``m.im_self`` is the object on which the method\noperates, and ``m.im_func`` is the function implementing the method.\nCalling ``m(arg-1, arg-2, ..., arg-n)`` is completely equivalent to\ncalling ``m.im_func(m.im_self, arg-1, arg-2, ..., arg-n)``.\n\nClass instance methods are either *bound* or *unbound*, referring to\nwhether the method was accessed through an instance or a class,\nrespectively. When a method is unbound, its ``im_self`` attribute\nwill be ``None`` and if called, an explicit ``self`` object must be\npassed as the first argument. In this case, ``self`` must be an\ninstance of the unbound method\'s class (or a subclass of that class),\notherwise a ``TypeError`` is raised.\n\nLike function objects, methods objects support getting arbitrary\nattributes. However, since method attributes are actually stored on\nthe underlying function object (``meth.im_func``), setting method\nattributes on either bound or unbound methods is disallowed.\nAttempting to set an attribute on a method results in an\n``AttributeError`` being raised. In order to set a method attribute,\nyou need to explicitly set it on the 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: \'instancemethod\' object has no attribute \'whoami\'\n >>> c.method.im_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 --- ``str``, ``unicode``, ``list``, ``tuple``, ``bytearray``, ``buffer``, ``xrange``\n***************************************************************************************************\n\nThere are seven sequence types: strings, Unicode strings, lists,\ntuples, bytearrays, buffers, and xrange objects.\n\nFor other containers see the built in ``dict`` and ``set`` classes,\nand the ``collections`` module.\n\nString literals are written in single or double quotes: ``\'xyzzy\'``,\n``"frobozz"``. See *String literals* for more about string literals.\nUnicode strings are much like strings, but are specified in the syntax\nusing a preceding ``\'u\'`` character: ``u\'abc\'``, ``u"def"``. In\naddition to the functionality described here, there are also string-\nspecific methods described in the *String Methods* section. Lists are\nconstructed with square brackets, separating items with commas: ``[a,\nb, c]``. Tuples are constructed by the comma operator (not within\nsquare brackets), with or without enclosing parentheses, but an empty\ntuple must have the enclosing parentheses, such as ``a, b, c`` or\n``()``. A single item tuple must have a trailing comma, such as\n``(d,)``.\n\nBytearray objects are created with the built-in function\n``bytearray()``.\n\nBuffer objects are not directly supported by Python syntax, but can be\ncreated by calling the built-in function ``buffer()``. They don\'t\nsupport concatenation or repetition.\n\nObjects of type xrange are similar to buffers in that there is no\nspecific syntax to create them, but they are created using the\n``xrange()`` function. They don\'t support slicing, concatenation or\nrepetition, and using ``in``, ``not in``, ``min()`` or ``max()`` on\nthem is inefficient.\n\nMost sequence types support the following operations. The ``in`` and\n``not in`` operations have the same priorities as the comparison\noperations. The ``+`` and ``*`` operations have the same priority as\nthe corresponding numeric operations. [3] Additional methods are\nprovided for *Mutable Sequence Types*.\n\nThis table lists the sequence operations sorted in ascending priority\n(operations in the same box have the same priority). In the table,\n*s* and *t* are sequences of the same type; *n*, *i* and *j* are\nintegers:\n\n+--------------------+----------------------------------+------------+\n| Operation | Result | Notes |\n+====================+==================================+============+\n| ``x in s`` | ``True`` if an item of *s* is | (1) |\n| | equal to *x*, else ``False`` | |\n+--------------------+----------------------------------+------------+\n| ``x not in s`` | ``False`` if an item of *s* is | (1) |\n| | equal to *x*, else ``True`` | |\n+--------------------+----------------------------------+------------+\n| ``s + t`` | the concatenation of *s* and *t* | (6) |\n+--------------------+----------------------------------+------------+\n| ``s * n, n * s`` | *n* shallow copies of *s* | (2) |\n| | concatenated | |\n+--------------------+----------------------------------+------------+\n| ``s[i]`` | *i*th item of *s*, origin 0 | (3) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j]`` | slice of *s* from *i* to *j* | (3)(4) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j:k]`` | slice of *s* from *i* to *j* | (3)(5) |\n| | with step *k* | |\n+--------------------+----------------------------------+------------+\n| ``len(s)`` | length of *s* | |\n+--------------------+----------------------------------+------------+\n| ``min(s)`` | smallest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``max(s)`` | largest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.index(x)`` | index of the first occurrence of | |\n| | *x* in *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.count(x)`` | total number of occurrences of | |\n| | *x* in *s* | |\n+--------------------+----------------------------------+------------+\n\nSequence types also support comparisons. In particular, tuples and\nlists are compared lexicographically by comparing corresponding\nelements. This means that to compare equal, every element must compare\nequal and the two sequences must be of the same type and have the same\nlength. (For full details see *Comparisons* in the language\nreference.)\n\nNotes:\n\n1. When *s* is a string or Unicode string object the ``in`` and ``not\n in`` operations act like a substring test. In Python versions\n before 2.3, *x* had to be a string of length 1. In Python 2.3 and\n beyond, *x* may be a string of any length.\n\n2. Values of *n* less than ``0`` are treated as ``0`` (which yields an\n empty sequence of the same type as *s*). Note also that the copies\n are shallow; nested structures are not copied. This often haunts\n new Python programmers; consider:\n\n >>> lists = [[]] * 3\n >>> lists\n [[], [], []]\n >>> lists[0].append(3)\n >>> lists\n [[3], [3], [3]]\n\n What has happened is that ``[[]]`` is a one-element list containing\n an empty list, so all three elements of ``[[]] * 3`` are (pointers\n to) this single empty list. Modifying any of the elements of\n ``lists`` modifies this single list. You can create a list of\n different lists this way:\n\n >>> lists = [[] for i in range(3)]\n >>> lists[0].append(3)\n >>> lists[1].append(5)\n >>> lists[2].append(7)\n >>> lists\n [[3], [5], [7]]\n\n3. If *i* or *j* is negative, the index is relative to the end of the\n string: ``len(s) + i`` or ``len(s) + j`` is substituted. But note\n that ``-0`` is still ``0``.\n\n4. The slice of *s* from *i* to *j* is defined as the sequence of\n items with index *k* such that ``i <= k < j``. If *i* or *j* is\n greater than ``len(s)``, use ``len(s)``. If *i* is omitted or\n ``None``, use ``0``. If *j* is omitted or ``None``, use\n ``len(s)``. If *i* is greater than or equal to *j*, the slice is\n empty.\n\n5. The slice of *s* from *i* to *j* with step *k* is defined as the\n sequence of items with index ``x = i + n*k`` such that ``0 <= n <\n (j-i)/k``. In other words, the indices are ``i``, ``i+k``,\n ``i+2*k``, ``i+3*k`` and so on, stopping when *j* is reached (but\n never including *j*). If *i* or *j* is greater than ``len(s)``,\n use ``len(s)``. If *i* or *j* are omitted or ``None``, they become\n "end" values (which end depends on the sign of *k*). Note, *k*\n cannot be zero. If *k* is ``None``, it is treated like ``1``.\n\n6. **CPython implementation detail:** If *s* and *t* are both strings,\n some Python implementations such as CPython can usually perform an\n in-place optimization for assignments of the form ``s = s + t`` or\n ``s += t``. When applicable, this optimization makes quadratic\n run-time much less likely. This optimization is both version and\n implementation dependent. For performance sensitive code, it is\n preferable to use the ``str.join()`` method which assures\n consistent linear concatenation performance across versions and\n implementations.\n\n Changed in version 2.4: Formerly, string concatenation never\n occurred in-place.\n\n\nString Methods\n==============\n\nBelow are listed the string methods which both 8-bit strings and\nUnicode objects support. Some of them are also available on\n``bytearray`` objects.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, unicode, list, tuple,\nbytearray, buffer, xrange* section. To output formatted strings use\ntemplate strings or the ``%`` operator described in the *String\nFormatting Operations* section. Also, see the ``re`` module for string\nfunctions based on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\n For 8-bit strings, this method is locale-dependent.\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\n Changed in version 2.4: Support for the *fillchar* argument.\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.decode([encoding[, errors]])\n\n Decodes the string using the codec registered for *encoding*.\n *encoding* defaults to the default string encoding. *errors* may\n be given to set a different error handling scheme. The default is\n ``\'strict\'``, meaning that encoding errors raise ``UnicodeError``.\n Other possible values are ``\'ignore\'``, ``\'replace\'`` and any other\n name registered via ``codecs.register_error()``, see section *Codec\n Base Classes*.\n\n New in version 2.2.\n\n Changed in version 2.3: Support for other error handling schemes\n added.\n\n Changed in version 2.7: Support for keyword arguments added.\n\nstr.encode([encoding[, errors]])\n\n Return an encoded version of the string. Default encoding is the\n current default string encoding. *errors* may be given to set a\n different error handling scheme. The default for *errors* is\n ``\'strict\'``, meaning that encoding errors raise a\n ``UnicodeError``. Other possible values are ``\'ignore\'``,\n ``\'replace\'``, ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and\n any other name registered via ``codecs.register_error()``, see\n section *Codec Base Classes*. For a list of possible encodings, see\n section *Standard Encodings*.\n\n New in version 2.0.\n\n Changed in version 2.3: Support for ``\'xmlcharrefreplace\'`` and\n ``\'backslashreplace\'`` and other error handling schemes added.\n\n Changed in version 2.7: 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\n Changed in version 2.5: Accept tuples as *suffix*.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. 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\n This method of string formatting is the new standard in Python 3,\n and should be preferred to the ``%`` formatting described in\n *String Formatting Operations* in new code.\n\n New in version 2.6.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise.\n\n For 8-bit strings, this method is locale-dependent.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise.\n\n For 8-bit strings, this method is locale-dependent.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise.\n\n For 8-bit strings, this method is locale-dependent.\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\n For 8-bit strings, this method is locale-dependent.\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise.\n\n For 8-bit strings, this method is locale-dependent.\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\n For 8-bit strings, this method is locale-dependent.\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\n For 8-bit strings, this method is locale-dependent.\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. The separator between elements is the\n 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\n Changed in version 2.4: Support for the *fillchar* argument.\n\nstr.lower()\n\n Return a copy of the string with all the cased characters [4]\n converted to lowercase.\n\n For 8-bit strings, this method is locale-dependent.\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\n Changed in version 2.2.2: Support for the *chars* argument.\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\n New in version 2.5.\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\n Changed in version 2.4: Support for the *fillchar* argument.\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\n New in version 2.5.\n\nstr.rsplit([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\n New in version 2.4.\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\n Changed in version 2.2.2: Support for the *chars* argument.\n\nstr.split([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified 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\n Changed in version 2.5: Accept tuples as *prefix*.\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\n Changed in version 2.2.2: Support for the *chars* argument.\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa.\n\n For 8-bit strings, this method is locale-dependent.\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\n For 8-bit strings, this method is locale-dependent.\n\nstr.translate(table[, deletechars])\n\n Return a copy of the string where all characters occurring in the\n optional argument *deletechars* are removed, and the remaining\n characters have been mapped through the given translation table,\n which must be a string of length 256.\n\n You can use the ``maketrans()`` helper function in the ``string``\n module to create a translation table. For string objects, set the\n *table* argument to ``None`` for translations that only delete\n characters:\n\n >>> \'read this short text\'.translate(None, \'aeiou\')\n \'rd ths shrt txt\'\n\n New in version 2.6: Support for a ``None`` *table* argument.\n\n For Unicode objects, the ``translate()`` method does not accept the\n optional *deletechars* argument. Instead, it returns a copy of the\n *s* where all characters have been mapped through the given\n translation table which must be a mapping of Unicode ordinals to\n Unicode ordinals, Unicode strings or ``None``. Unmapped characters\n are left untouched. Characters mapped to ``None`` are deleted.\n Note, a more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see ``encodings.cp1251``\n 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 For 8-bit strings, this method is locale-dependent.\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\n New in version 2.2.2.\n\nThe following methods are present only on unicode objects:\n\nunicode.isnumeric()\n\n Return ``True`` if there are only numeric characters in S,\n ``False`` otherwise. Numeric characters include digit characters,\n and all characters that have the Unicode numeric value property,\n e.g. U+2155, VULGAR FRACTION ONE FIFTH.\n\nunicode.isdecimal()\n\n Return ``True`` if there are only decimal characters in S,\n ``False`` otherwise. Decimal characters include digit characters,\n and all characters that can be used to form decimal-radix numbers,\n e.g. U+0660, ARABIC-INDIC DIGIT ZERO.\n\n\nString Formatting Operations\n============================\n\nString and Unicode objects have one unique built-in operation: the\n``%`` operator (modulo). This is also known as the string\n*formatting* or *interpolation* operator. Given ``format % values``\n(where *format* is a string or Unicode object), ``%`` conversion\nspecifications in *format* are replaced with zero or more elements of\n*values*. The effect is similar to the using ``sprintf()`` in the C\nlanguage. If *format* is a Unicode object, or if any of the objects\nbeing converted using the ``%s`` conversion are Unicode objects, the\nresult will also be a Unicode object.\n\nIf *format* requires a single argument, *values* may be a single non-\ntuple object. [5] Otherwise, *values* must be a tuple with exactly\nthe number of items specified by the format string, or a single\nmapping object (for example, a dictionary).\n\nA conversion specifier contains two or more characters and has the\nfollowing components, which must occur in this order:\n\n1. The ``\'%\'`` character, which marks the start of the specifier.\n\n2. Mapping key (optional), consisting of a parenthesised sequence of\n characters (for example, ``(somename)``).\n\n3. Conversion flags (optional), which affect the result of some\n conversion types.\n\n4. Minimum field width (optional). If specified as an ``\'*\'``\n (asterisk), the actual width is read from the next element of the\n tuple in *values*, and the object to convert comes after the\n minimum field width and optional precision.\n\n5. Precision (optional), given as a ``\'.\'`` (dot) followed by the\n precision. If specified as ``\'*\'`` (an asterisk), the actual width\n is read from the next element of the tuple in *values*, and the\n value to convert comes after the precision.\n\n6. Length modifier (optional).\n\n7. Conversion type.\n\nWhen the right argument is a dictionary (or other mapping type), then\nthe formats in the string *must* include a parenthesised mapping key\ninto that dictionary inserted immediately after the ``\'%\'`` character.\nThe mapping key selects the value to be formatted from the mapping.\nFor example:\n\n>>> print \'%(language)s has %(number)03d quote types.\' % \\\n... {"language": "Python", "number": 2}\nPython has 002 quote types.\n\nIn this case no ``*`` specifiers may occur in a format (since they\nrequire a sequential parameter list).\n\nThe conversion flag characters are:\n\n+-----------+-----------------------------------------------------------------------+\n| Flag | Meaning |\n+===========+=======================================================================+\n| ``\'#\'`` | The value conversion will use the "alternate form" (where defined |\n| | below). |\n+-----------+-----------------------------------------------------------------------+\n| ``\'0\'`` | The conversion will be zero padded for numeric values. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'-\'`` | The converted value is left adjusted (overrides the ``\'0\'`` |\n| | conversion if both are given). |\n+-----------+-----------------------------------------------------------------------+\n| ``\' \'`` | (a space) A blank should be left before a positive number (or empty |\n| | string) produced by a signed conversion. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'+\'`` | A sign character (``\'+\'`` or ``\'-\'``) will precede the conversion |\n| | (overrides a "space" flag). |\n+-----------+-----------------------------------------------------------------------+\n\nA length modifier (``h``, ``l``, or ``L``) may be present, but is\nignored as it is not necessary for Python -- so e.g. ``%ld`` is\nidentical to ``%d``.\n\nThe conversion types are:\n\n+--------------+-------------------------------------------------------+---------+\n| Conversion | Meaning | Notes |\n+==============+=======================================================+=========+\n| ``\'d\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'i\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'o\'`` | Signed octal value. | (1) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'u\'`` | Obsolete type -- it is identical to ``\'d\'``. | (7) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'x\'`` | Signed hexadecimal (lowercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'X\'`` | Signed hexadecimal (uppercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'e\'`` | Floating point exponential format (lowercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'E\'`` | Floating point exponential format (uppercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'f\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'F\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'g\'`` | Floating point format. Uses lowercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'G\'`` | Floating point format. Uses uppercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'c\'`` | Single character (accepts integer or single character | |\n| | string). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'r\'`` | String (converts any Python object using *repr()*). | (5) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'s\'`` | String (converts any Python object using ``str()``). | (6) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'%\'`` | No argument is converted, results in a ``\'%\'`` | |\n| | character in the result. | |\n+--------------+-------------------------------------------------------+---------+\n\nNotes:\n\n1. The alternate form causes a leading zero (``\'0\'``) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n2. The alternate form causes a leading ``\'0x\'`` or ``\'0X\'`` (depending\n on whether the ``\'x\'`` or ``\'X\'`` format was used) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n3. The alternate form causes the result to always contain a decimal\n point, even if no digits follow it.\n\n The precision determines the number of digits after the decimal\n point and defaults to 6.\n\n4. The alternate form causes the result to always contain a decimal\n point, and trailing zeroes are not removed as they would otherwise\n be.\n\n The precision determines the number of significant digits before\n and after the decimal point and defaults to 6.\n\n5. The ``%r`` conversion was added in Python 2.0.\n\n The precision determines the maximal number of characters used.\n\n6. If the object or format provided is a ``unicode`` string, the\n resulting string will also be ``unicode``.\n\n The precision determines the maximal number of characters used.\n\n7. See **PEP 237**.\n\nSince Python strings have an explicit length, ``%s`` conversions do\nnot assume that ``\'\\0\'`` is the end of the string.\n\nChanged in version 2.7: ``%f`` conversions for numbers whose absolute\nvalue is over 1e50 are no longer replaced by ``%g`` conversions.\n\nAdditional string operations are defined in standard modules\n``string`` and ``re``.\n\n\nXRange Type\n===========\n\nThe ``xrange`` type is an immutable sequence which is commonly used\nfor looping. The advantage of the ``xrange`` type is that an\n``xrange`` object will always take the same amount of memory, no\nmatter the size of the range it represents. There are no consistent\nperformance advantages.\n\nXRange objects have very little behavior: they only support indexing,\niteration, and the ``len()`` function.\n\n\nMutable Sequence Types\n======================\n\nList and ``bytearray`` objects support additional operations that\nallow in-place modification of the object. Other mutable sequence\ntypes (when added to the language) should also support these\noperations. Strings and tuples are immutable sequence types: such\nobjects cannot be modified once created. The following operations are\ndefined on mutable sequence types (where *x* is an arbitrary object):\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | same as ``s[len(s):len(s)] = | (2) |\n| | [x]`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(x)`` | same as ``s[len(s):len(s)] = x`` | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.count(x)`` | return number of *i*\'s for which | |\n| | ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.index(x[, i[, j]])`` | return smallest *k* such that | (4) |\n| | ``s[k] == x`` and ``i <= k < j`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | same as ``s[i:i] = [x]`` | (5) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | same as ``x = s[i]; del s[i]; | (6) |\n| | return x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | same as ``del s[s.index(x)]`` | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (7) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.sort([cmp[, key[, | sort the items of *s* in place | (7)(8)(9)(10) |\n| reverse]]])`` | | |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. The C implementation of Python has historically accepted multiple\n parameters and implicitly joined them into a tuple; this no longer\n works in Python 2.0. Use of this misfeature has been deprecated\n since Python 1.4.\n\n3. *x* can be any iterable object.\n\n4. Raises ``ValueError`` when *x* is not found in *s*. When a negative\n index is passed as the second or third parameter to the ``index()``\n method, the list length is added, as for slice indices. If it is\n still negative, it is truncated to zero, as for slice indices.\n\n Changed in version 2.3: Previously, ``index()`` didn\'t have\n arguments for specifying start and stop positions.\n\n5. When a negative index is passed as the first parameter to the\n ``insert()`` method, the list length is added, as for slice\n indices. If it is still negative, it is truncated to zero, as for\n slice indices.\n\n Changed in version 2.3: Previously, all negative indices were\n truncated to zero.\n\n6. The ``pop()`` method\'s optional argument *i* defaults to ``-1``, so\n that by default the last item is removed and returned.\n\n7. The ``sort()`` and ``reverse()`` methods modify the list in place\n for economy of space when sorting or reversing a large list. To\n remind you that they operate by side effect, they don\'t return the\n sorted or reversed list.\n\n8. The ``sort()`` method takes optional arguments for controlling the\n comparisons.\n\n *cmp* specifies a custom comparison function of two arguments (list\n items) which should return a negative, zero or positive number\n depending on whether the first argument is considered smaller than,\n equal to, or larger than the second argument: ``cmp=lambda x,y:\n cmp(x.lower(), y.lower())``. The default value is ``None``.\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: ``key=str.lower``. The\n default value is ``None``.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n In general, the *key* and *reverse* conversion processes are much\n faster than specifying an equivalent *cmp* function. This is\n because *cmp* is called multiple times for each list element while\n *key* and *reverse* touch each element only once. Use\n ``functools.cmp_to_key()`` to convert an old-style *cmp* function\n to a *key* function.\n\n Changed in version 2.3: Support for ``None`` as an equivalent to\n omitting *cmp* was added.\n\n Changed in version 2.4: Support for *key* and *reverse* was added.\n\n9. Starting with Python 2.3, the ``sort()`` method is guaranteed to be\n stable. A sort is stable if it guarantees not to change the\n relative order of elements that compare equal --- this is helpful\n for sorting in multiple passes (for example, sort by department,\n then by salary grade).\n\n10. **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 2.3 and newer makes the\n list appear empty for the duration, and raises ``ValueError`` if\n it can detect that the list has been mutated during a sort.\n', - 'typesseq-mutable': "\nMutable Sequence Types\n**********************\n\nList and ``bytearray`` objects support additional operations that\nallow in-place modification of the object. Other mutable sequence\ntypes (when added to the language) should also support these\noperations. Strings and tuples are immutable sequence types: such\nobjects cannot be modified once created. The following operations are\ndefined on mutable sequence types (where *x* is an arbitrary object):\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | same as ``s[len(s):len(s)] = | (2) |\n| | [x]`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(x)`` | same as ``s[len(s):len(s)] = x`` | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.count(x)`` | return number of *i*'s for which | |\n| | ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.index(x[, i[, j]])`` | return smallest *k* such that | (4) |\n| | ``s[k] == x`` and ``i <= k < j`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | same as ``s[i:i] = [x]`` | (5) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | same as ``x = s[i]; del s[i]; | (6) |\n| | return x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | same as ``del s[s.index(x)]`` | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (7) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.sort([cmp[, key[, | sort the items of *s* in place | (7)(8)(9)(10) |\n| reverse]]])`` | | |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. The C implementation of Python has historically accepted multiple\n parameters and implicitly joined them into a tuple; this no longer\n works in Python 2.0. Use of this misfeature has been deprecated\n since Python 1.4.\n\n3. *x* can be any iterable object.\n\n4. Raises ``ValueError`` when *x* is not found in *s*. When a negative\n index is passed as the second or third parameter to the ``index()``\n method, the list length is added, as for slice indices. If it is\n still negative, it is truncated to zero, as for slice indices.\n\n Changed in version 2.3: Previously, ``index()`` didn't have\n arguments for specifying start and stop positions.\n\n5. When a negative index is passed as the first parameter to the\n ``insert()`` method, the list length is added, as for slice\n indices. If it is still negative, it is truncated to zero, as for\n slice indices.\n\n Changed in version 2.3: Previously, all negative indices were\n truncated to zero.\n\n6. The ``pop()`` method's optional argument *i* defaults to ``-1``, so\n that by default the last item is removed and returned.\n\n7. The ``sort()`` and ``reverse()`` methods modify the list in place\n for economy of space when sorting or reversing a large list. To\n remind you that they operate by side effect, they don't return the\n sorted or reversed list.\n\n8. The ``sort()`` method takes optional arguments for controlling the\n comparisons.\n\n *cmp* specifies a custom comparison function of two arguments (list\n items) which should return a negative, zero or positive number\n depending on whether the first argument is considered smaller than,\n equal to, or larger than the second argument: ``cmp=lambda x,y:\n cmp(x.lower(), y.lower())``. The default value is ``None``.\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: ``key=str.lower``. The\n default value is ``None``.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n In general, the *key* and *reverse* conversion processes are much\n faster than specifying an equivalent *cmp* function. This is\n because *cmp* is called multiple times for each list element while\n *key* and *reverse* touch each element only once. Use\n ``functools.cmp_to_key()`` to convert an old-style *cmp* function\n to a *key* function.\n\n Changed in version 2.3: Support for ``None`` as an equivalent to\n omitting *cmp* was added.\n\n Changed in version 2.4: Support for *key* and *reverse* was added.\n\n9. Starting with Python 2.3, the ``sort()`` method is guaranteed to be\n stable. A sort is stable if it guarantees not to change the\n relative order of elements that compare equal --- this is helpful\n for sorting in multiple passes (for example, sort by department,\n then by salary grade).\n\n10. **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 2.3 and newer makes the\n list appear empty for the duration, and raises ``ValueError`` if\n it can detect that the list has been mutated during a sort.\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\nplain or long integer argument. The bitwise inversion of ``x`` is\ndefined as ``-(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\nNew in version 2.5.\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\nNote: In Python 2.5, the ``with`` statement is only allowed when the\n ``with_statement`` feature has been enabled. It is always enabled\n in Python 2.6.\n\nChanged in version 2.7: 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 generator\'s ``next()``\nmethod 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\nAs of Python version 2.5, the ``yield`` statement is now allowed in\nthe ``try`` clause of a ``try`` ... ``finally`` construct. If the\ngenerator is not resumed before it is finalized (by reaching a zero\nreference count or by being garbage collected), the generator-\niterator\'s ``close()`` method will be called, allowing any pending\n``finally`` clauses to execute.\n\nFor full details of ``yield`` semantics, refer to the *Yield\nexpressions* section.\n\nNote: In Python 2.2, the ``yield`` statement was only allowed when the\n ``generators`` feature has been enabled. This ``__future__`` import\n statement was used to enable the feature:\n\n from __future__ import generators\n\nSee also:\n\n **PEP 0255** - Simple Generators\n The proposal for adding generators and the ``yield`` statement\n to Python.\n\n **PEP 0342** - Coroutines via Enhanced Generators\n The proposal that, among other generator enhancements, proposed\n allowing ``yield`` to appear inside a ``try`` ... ``finally``\n block.\n'} +# -*- coding: utf-8 -*- +# Autogenerated by Sphinx on Tue Nov 25 18:24:45 2014 +topics = {'assert': u'\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': u'\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\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 is recursively defined as\nfollows.\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\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" statement in the\n current code block: the name is bound to the object in the current\n local namespace.\n\n * Otherwise: the name is bound to the object in the current global\n namespace.\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 a plain integer. If it is negative, the\n sequence\'s length is added to it. The resulting value must be a\n nonnegative integer less than the sequence\'s length, and the\n sequence is asked to assign the assigned object to its item with\n that index. If the index is out of range, "IndexError" is raised\n (assignment to a subscripted sequence cannot add new items to a\n 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* 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 (small) integers.\n If either bound is negative, the sequence\'s length is added to it.\n The resulting bounds are clipped to lie between zero and the\n sequence\'s length, inclusive. Finally, the sequence object is asked\n to replace the slice with the items of the assigned sequence. The\n length of the slice may be different from the length of the assigned\n sequence, thus changing the length of the target sequence, if the\n object 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\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': u'\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': u"\nLiterals\n********\n\nPython supports string literals and various numeric literals:\n\n literal ::= stringliteral | integer | longinteger\n | floatnumber | imagnumber\n\nEvaluation of a literal yields an object of the given type (string,\ninteger, long integer, floating point number, complex number) with the\ngiven value. The value may be approximated in the case of floating\npoint and imaginary (complex) literals. See section *Literals* for\ndetails.\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': u'\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 in new-style classes.\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 not simply execute "self.name = value" --- this would cause\n a recursive call to itself. Instead, it should insert the value in\n the dictionary of instance attributes, e.g., "self.__dict__[name] =\n value". For new-style classes, rather than accessing the instance\n dictionary, it should call the base class method with the same\n name, for example, "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\n\nMore attribute access for new-style classes\n===========================================\n\nThe following methods only apply to new-style classes.\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 for new-style\n classes*.\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. Note that descriptors are only invoked for new\nstyle objects or classes (ones that subclass "object()" or "type()").\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 a new-style object instance, "a.x" is transformed\n into the call: "type(a).__dict__[\'x\'].__get__(a, type(a))".\n\nClass Binding\n If binding to a new-style class, "A.x" is transformed into the\n call: "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 both old and new-style classes have a\ndictionary for attribute storage. This wastes space for objects\nhaving very few instance variables. The space consumption can become\nacute when creating large numbers of instances.\n\nThe default can be overridden by defining *__slots__* in a new-style\nclass definition. The *__slots__* declaration takes a sequence of\ninstance variables and reserves just enough space in each instance to\nhold a value for each variable. Space is saved because *__dict__* is\nnot created for each instance.\n\n__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 new-style class, *__slots__* reserves space for the declared\n variables and prevents the automatic creation of *__dict__* and\n *__weakref__* for each instance.\n\n New in version 2.2.\n\nNotes on using *__slots__*\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 Changed in version 2.3: Previously, adding "\'__dict__\'" to the\n *__slots__* declaration would not enable the assignment of new\n attributes not specifically listed in the sequence of instance\n variable names.\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 Changed in version 2.3: Previously, adding "\'__weakref__\'" to the\n *__slots__* declaration would not enable support for weak\n references.\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 "long", "str" 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 Changed in version 2.6: Previously, *__class__* assignment raised an\n error if either new or old class had *__slots__*.\n', + 'attribute-references': u'\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, e.g., a module, list, or an instance. This\nobject is then asked to produce the attribute whose name is the\nidentifier. If this attribute is not available, the exception\n"AttributeError" is raised. Otherwise, the type and value of the\nobject produced is determined by the object. Multiple evaluations of\nthe same attribute reference may yield different objects.\n', + 'augassign': u'\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': u'\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 (plain or long) and the other must be a sequence. In the\nformer case, the numbers are converted to a common type and then\nmultiplied together. In the latter case, sequence repetition is\nperformed; a negative 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. Plain or long integer division yields an\ninteger of the same type; the result is that of mathematical division\nwith the \'floor\' function applied to the result. Division by zero\nraises 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 [2].\n\nThe integer division and modulo operators are connected by the\nfollowing identity: "x == (x/y)*y + (x%y)". Integer division and\nmodulo are also connected with the built-in function "divmod()":\n"divmod(x, y) == (x/y, x%y)". These identities don\'t hold for\nfloating point numbers; there similar identities hold approximately\nwhere "x/y" is replaced by "floor(x/y)" or "floor(x/y) - 1" [3].\n\nIn addition to performing the modulo operation on numbers, the "%"\noperator is also overloaded by string and unicode objects to perform\nstring formatting (also known as interpolation). The syntax for string\nformatting is described in the Python Library Reference, section\n*String Formatting Operations*.\n\nDeprecated since version 2.3: The floor division operator, the modulo\noperator, and the "divmod()" function are no longer defined for\ncomplex numbers. Instead, convert to a floating point number using\nthe "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': u'\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 plain or long integers. The arguments are converted to a common\ntype.\n\nThe "^" operator yields the bitwise XOR (exclusive OR) of its\narguments, which must be plain or long integers. The arguments are\nconverted to a common type.\n\nThe "|" operator yields the bitwise (inclusive) OR of its arguments,\nwhich must be plain or long integers. The arguments are converted to\na common type.\n', + 'bltin-code-objects': u'\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 "func_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" statement or the built-in "eval()"\nfunction.\n\nSee *The standard type hierarchy* for more information.\n', + 'bltin-ellipsis-object': u'\nThe Ellipsis Object\n*******************\n\nThis object is used by extended slice notation (see *Slicings*). It\nsupports no special operations. There is exactly one ellipsis object,\nnamed "Ellipsis" (a built-in name).\n\nIt is written as "Ellipsis". When in a subscript, it can also be\nwritten as "...", for example "seq[...]".\n', + 'bltin-null-object': u'\nThe Null Object\n***************\n\nThis object is returned by functions that don\'t explicitly return a\nvalue. It supports no special operations. There is exactly one null\nobject, named "None" (a built-in name).\n\nIt is written as "None".\n', + 'bltin-type-objects': u'\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': u'\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. (See the "__nonzero__()" special method for a way to change\nthis.)\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': u'\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': u'\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': u'\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 [","]\n | expression genexpr_for] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," "**" 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 certain class instances\nthemselves are callable; extensions may define additional callable\nobject types). All argument expressions are evaluated before the call\nis attempted. Please refer to section *Function definitions* for the\nsyntax 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. Formal parameters using the syntax "(sublist)" cannot be used\nas keyword argument names; the outermost sublist corresponds to a\nsingle unnamed argument slot, and the argument value is assigned to\nthe sublist using the usual tuple assignment rules after all other\nparameter processing is done.\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': u'\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= "class" classname [inheritance] ":" suite\n inheritance ::= "(" [expression_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. It first evaluates the\ninheritance list, if present. Each item in the inheritance list\nshould evaluate to a class object or class type which allows\nsubclassing. The class\'s suite is then executed in a new execution\nframe (see section *Naming and binding*), using a newly created local\nnamespace and the original global namespace. (Usually, the suite\ncontains only function definitions.) When the class\'s suite finishes\nexecution, its execution frame is discarded but its local namespace is\nsaved. [4] A class object is then created using the inheritance list\nfor the base classes and the saved local namespace for the attribute\ndictionary. The class name is bound to this class object in the\noriginal local namespace.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass variables; they are shared by all instances. To create instance\nvariables, they can be set in a method with "self.name = value". Both\nclass and instance variables are accessible through the notation\n""self.name"", and an instance variable hides a class variable with\nthe same name when accessed in this way. Class variables can be used\nas defaults for instance variables, but using mutable values there can\nlead to unexpected results. For *new-style class*es, descriptors can\nbe used to create instance variables with different implementation\ndetails.\n\nClass definitions, like function definitions, may be wrapped by one or\nmore *decorator* expressions. The evaluation rules for the decorator\nexpressions are the same as for functions. The result must be a class\nobject, which is then bound to the class name.\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack 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': u'\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 forms "<>" and "!=" are equivalent; for consistency with C, "!="\nis preferred; where "!=" is mentioned below "<>" is also accepted.\nThe "<>" spelling is considered obsolescent.\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, objects of\ndifferent types *always* compare unequal, and are ordered consistently\nbut arbitrarily. You can control comparison behavior of objects of\nnon-built-in types by defining a "__cmp__" method or rich comparison\nmethods like "__gt__", described in section *Special method names*.\n\n(This unusual definition of comparison was used to simplify the\ndefinition of operations like sorting and the "in" and "not in"\noperators. In the future, the comparison rules for objects of\ndifferent types are likely to change.)\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* Strings are compared lexicographically using the numeric\n equivalents (the result of the built-in function "ord()") of their\n characters. Unicode and 8-bit strings are fully interoperable in\n this behavior. [4]\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, "cmp([1,2,x], [1,2,y])" returns\n the same as "cmp(x,y)". If the corresponding element does not\n exist, the shorter sequence is ordered first (for example, "[1,2] <\n [1,2,3]").\n\n* Mappings (dictionaries) compare equal if and only if their sorted\n (key, value) lists compare equal. [5] Outcomes other than equality\n are resolved consistently, but are not otherwise defined. [6]\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\nThe operators "in" and "not in" test for collection membership. "x in\ns" evaluates to true if *x* is a member of the collection *s*, and\nfalse otherwise. "x not in s" returns the negation of "x in s". The\ncollection membership test has traditionally been bound to sequences;\nan object is a member of a collection if the collection is a sequence\nand contains an element equal to that object. However, it make sense\nfor many other object types to support membership tests without being\na sequence. In particular, dictionaries (for keys) and sets support\nmembership testing.\n\nFor the list and tuple types, "x in y" is true if and only if there\nexists an index *i* such that "x == y[i]" is true.\n\nFor the Unicode and string types, "x in y" is true if and only if *x*\nis a substring of *y*. An equivalent test is "y.find(x) != -1".\nNote, *x* and *y* need not be the same type; consequently, "u\'ab\' in\n\'abc\'" will return "True". Empty strings are always considered to be a\nsubstring of any other string, so """ in "abc"" will return "True".\n\nChanged in version 2.3: Previously, *x* was required to be a string of\nlength "1".\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. [7]\n', + 'compound': u'\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. Function and class definitions are\nalso syntactically compound 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" statements 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 | decorated\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, and then the suite is executed. When the items are\nexhausted (which is immediately when the sequence is empty), the suite\nin 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\nThe target list is not deleted when the loop is finished, but if the\nsequence is empty, it will not have been assigned to at all by the\nloop. Hint: the built-in function "range()" returns a sequence of\nintegers suitable to emulate the effect of Pascal\'s "for i := a to b\ndo"; e.g., "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" | ",") identifier]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nChanged in version 2.5: In previous versions of Python,\n"try"..."except"..."finally" did not work. "try"..."except" had to be\nnested in "try"..."finally".\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 in that except clause, if present, and the except\nclause\'s suite is executed. All except clauses must have an\nexecutable block. When the end of this block is reached, execution\ncontinues normally after the entire try statement. (This means that\nif two nested handlers exist for the same exception, and the exception\noccurs in the try clause of the inner handler, the outer handler will\nnot handle the exception.)\n\nBefore an except clause\'s suite is executed, details about the\nexception are assigned to three variables in the "sys" module:\n"sys.exc_type" receives the object identifying the exception;\n"sys.exc_value" receives the exception\'s parameter;\n"sys.exc_traceback" receives a traceback object (see section *The\nstandard type hierarchy*) identifying the point in the program where\nthe exception occurred. These details are also available through the\n"sys.exc_info()" function, which returns a tuple "(exc_type,\nexc_value, exc_traceback)". Use of the corresponding variables is\ndeprecated in favor of this function, since their use is unsafe in a\nthreaded program. As of Python 1.5, the variables are restored to\ntheir previous values (before the call) when returning from a function\nthat handled an exception.\n\nThe optional "else" clause is executed if and when control flows off\nthe end of the "try" clause. [2] Exceptions in the "else" clause 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\n"finally" clause. If the "finally" clause raises another exception or\nexecutes a "return" or "break" statement, the saved exception is\ndiscarded:\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\nThe return value of a function is determined by the last "return"\nstatement executed. Since the "finally" clause always executes, a\n"return" statement executed in the "finally" clause will always be the\nlast one executed:\n\n >>> def foo():\n ... try:\n ... return \'try\'\n ... finally:\n ... return \'finally\'\n ...\n >>> foo()\n \'finally\'\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\nNew in version 2.5.\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\nNote: In Python 2.5, the "with" statement is only allowed when the\n "with_statement" feature has been enabled. It is always enabled in\n Python 2.6.\n\nChanged in version 2.7: 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 decorated ::= decorators (classdef | funcdef)\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n funcdef ::= "def" funcname "(" [parameter_list] ")" ":" suite\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" identifier ["," "**" identifier]\n | "**" identifier\n | defparameter [","] )\n defparameter ::= parameter ["=" expression]\n sublist ::= parameter ("," parameter)* [","]\n parameter ::= identifier | "(" sublist ")"\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 top-level *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 must also have a default value --- this is a syntactic\nrestriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that the same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use "None" as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n""*identifier"" is present, it is initialized to a tuple receiving 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.\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.\n\n**Programmer\'s note:** Functions are first-class objects. A ""def""\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= "class" classname [inheritance] ":" suite\n inheritance ::= "(" [expression_list] ")"\n classname ::= identifier\n\nA class definition is an executable statement. It first evaluates the\ninheritance list, if present. Each item in the inheritance list\nshould evaluate to a class object or class type which allows\nsubclassing. The class\'s suite is then executed in a new execution\nframe (see section *Naming and binding*), using a newly created local\nnamespace and the original global namespace. (Usually, the suite\ncontains only function definitions.) When the class\'s suite finishes\nexecution, its execution frame is discarded but its local namespace is\nsaved. [4] A class object is then created using the inheritance list\nfor the base classes and the saved local namespace for the attribute\ndictionary. The class name is bound to this class object in the\noriginal local namespace.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass variables; they are shared by all instances. To create instance\nvariables, they can be set in a method with "self.name = value". Both\nclass and instance variables are accessible through the notation\n""self.name"", and an instance variable hides a class variable with\nthe same name when accessed in this way. Class variables can be used\nas defaults for instance variables, but using mutable values there can\nlead to unexpected results. For *new-style class*es, descriptors can\nbe used to create instance variables with different implementation\ndetails.\n\nClass definitions, like function definitions, may be wrapped by one or\nmore *decorator* expressions. The evaluation rules for the decorator\nexpressions are the same as for functions. The result must be a class\nobject, which is then bound to the class name.\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack 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': u'\nWith Statement Context Managers\n*******************************\n\nNew in version 2.5.\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': u'\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': u'\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," the arguments\nare coerced using the coercion rules listed at *Coercion rules*. If\nboth arguments are standard numeric types, the following coercions are\napplied:\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, if either argument is a long integer, the other is\n converted to long integer;\n\n* otherwise, both must be plain integers and no conversion is\n necessary.\n\nSome additional rules apply for certain operators (e.g., a string left\nargument to the \'%\' operator). Extensions can define their own\ncoercions.\n', + 'customization': u'\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_traceback" 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.exc_traceback" or "sys.last_traceback". Circular references\n which are garbage are detected when the option cycle detector is\n enabled (it\'s on by default), but can only be cleaned up if there\n are no Python-level "__del__()" methods involved. Refer to the\n documentation for the "gc" module for more information about how\n "__del__()" methods are handled by the cycle detector,\n particularly the description of the "garbage" value.\n\n Warning: Due to the precarious circumstances under which\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\n See also the *-R* command-line option.\n\nobject.__repr__(self)\n\n Called by the "repr()" built-in function and by string conversions\n (reverse quotes) to compute the "official" string representation of\n an object. If at all possible, this should look like a valid\n Python expression that could be used to recreate an object with the\n same value (given an appropriate environment). If this is not\n possible, a string of the form "<...some useful description...>"\n should be returned. The return value must be a string object. If a\n class defines "__repr__()" but not "__str__()", then "__repr__()"\n is also used when an "informal" string representation of instances\n 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 the "str()" built-in function and by the "print"\n statement to compute the "informal" string representation of an\n object. This differs from "__repr__()" in that it does not have to\n be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__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 New in version 2.1.\n\n These are the so-called "rich comparison" methods, and are called\n for comparison operators in preference to "__cmp__()" below. The\n correspondence between operator symbols and method names is as\n follows: "xy" call "x.__ne__(y)",\n "x>y" calls "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.__cmp__(self, other)\n\n Called by comparison operations if rich comparison (see above) is\n not defined. Should return a negative integer if "self < other",\n zero if "self == other", a positive integer if "self > other". If\n no "__cmp__()", "__eq__()" or "__ne__()" operation is defined,\n class instances are compared by object identity ("address"). See\n also the description of "__hash__()" for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys. (Note: the\n restriction that exceptions are not propagated by "__cmp__()" has\n been removed since Python 1.5.)\n\nobject.__rcmp__(self, other)\n\n Changed in version 2.1: No longer supported.\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 If a class does not define a "__cmp__()" or "__eq__()" method it\n should not define a "__hash__()" operation either; if it defines\n "__cmp__()" or "__eq__()" but not "__hash__()", its instances will\n not be usable in hashed collections. If a class defines mutable\n objects and implements a "__cmp__()" or "__eq__()" method, it\n should not implement "__hash__()", since hashable collection\n implementations require that a object\'s hash value is immutable (if\n the object\'s hash value changes, it will be in the wrong hash\n bucket).\n\n User-defined classes have "__cmp__()" and "__hash__()" methods by\n default; with them, all objects compare unequal (except with\n themselves) and "x.__hash__()" returns a result derived from\n "id(x)".\n\n Classes which inherit a "__hash__()" method from a parent class but\n change the meaning of "__cmp__()" or "__eq__()" such that the hash\n value returned is no longer appropriate (e.g. by switching to a\n value-based concept of equality instead of the default identity\n based equality) can explicitly flag themselves as being unhashable\n by setting "__hash__ = None" in the class definition. Doing so\n means that not only will instances of the class raise an\n appropriate "TypeError" when a program attempts to retrieve their\n hash value, but they will also be correctly identified as\n unhashable when checking "isinstance(obj, collections.Hashable)"\n (unlike classes which define their own "__hash__()" to explicitly\n raise "TypeError").\n\n Changed in version 2.5: "__hash__()" may now also return a long\n integer object; the 32-bit integer is then derived from the hash of\n that object.\n\n Changed in version 2.6: "__hash__" may now be set to "None" to\n explicitly flag instances of a class as unhashable.\n\nobject.__nonzero__(self)\n\n Called to implement truth value testing and the built-in operation\n "bool()"; should return "False" or "True", or their integer\n equivalents "0" or "1". When this method is not defined,\n "__len__()" is called, if it is defined, and the object is\n considered true if its result is nonzero. If a class defines\n neither "__len__()" nor "__nonzero__()", all its instances are\n considered true.\n\nobject.__unicode__(self)\n\n Called to implement "unicode()" built-in; should return a Unicode\n object. When this method is not defined, string conversion is\n attempted, and the result of string conversion is converted to\n Unicode using the system default encoding.\n', + 'debugger': u'\n"pdb" --- The Python Debugger\n*****************************\n\n**Source code:** Lib/pdb.py\n\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\n"pdb.py" can also be invoked as a script to debug other scripts. For\nexample:\n\n python -m pdb myscript.py\n\nWhen invoked as a script, pdb will automatically enter post-mortem\ndebugging if the program being debugged exits abnormally. After post-\nmortem debugging (or after normal exit of the program), pdb will\nrestart the program. Automatic restarting preserves pdb\'s state (such\nas breakpoints) and in most cases is more useful than quitting the\ndebugger upon program\'s exit.\n\nNew in version 2.4: Restarting post-mortem behavior added.\n\nThe typical usage to break into the debugger from a running program is\nto insert\n\n import pdb; pdb.set_trace()\n\nat the location you want to break into the debugger. You can then\nstep through the code following this statement, and continue running\nwithout the debugger using the "c" command.\n\nThe typical usage to inspect a crashed program is:\n\n >>> import pdb\n >>> import mymodule\n >>> mymodule.test()\n Traceback (most recent call last):\n File "", line 1, in ?\n File "./mymodule.py", line 4, in test\n test2()\n File "./mymodule.py", line 3, in test2\n print spam\n NameError: spam\n >>> pdb.pm()\n > ./mymodule.py(3)test2()\n -> print spam\n (Pdb)\n\nThe module defines the following functions; each enters the debugger\nin a slightly different way:\n\npdb.run(statement[, globals[, locals]])\n\n Execute the *statement* (given as a string) under debugger control.\n The debugger prompt appears before any code is executed; you can\n set breakpoints and type "continue", or you can step through the\n statement using "step" or "next" (all these commands are explained\n below). The optional *globals* and *locals* arguments specify the\n environment in which the code is executed; by default the\n dictionary of the module "__main__" is used. (See the explanation\n of the "exec" statement or the "eval()" built-in function.)\n\npdb.runeval(expression[, globals[, locals]])\n\n Evaluate the *expression* (given as a string) under debugger\n control. When "runeval()" returns, it returns the value of the\n expression. Otherwise this function is similar to "run()".\n\npdb.runcall(function[, argument, ...])\n\n Call the *function* (a function or method object, not a string)\n with the given arguments. When "runcall()" returns, it returns\n whatever the function call returned. The debugger prompt appears\n as soon as the function is entered.\n\npdb.set_trace()\n\n Enter the debugger at the calling stack frame. This is useful to\n hard-code a breakpoint at a given point in a program, even if the\n code is not otherwise being debugged (e.g. when an assertion\n fails).\n\npdb.post_mortem([traceback])\n\n Enter post-mortem debugging of the given *traceback* object. If no\n *traceback* is given, it uses the one of the exception that is\n currently being handled (an exception must be being handled if the\n default is to be used).\n\npdb.pm()\n\n Enter post-mortem debugging of the traceback found in\n "sys.last_traceback".\n\nThe "run*" functions and "set_trace()" are aliases for 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)\n\n "Pdb" is the debugger class.\n\n The *completekey*, *stdin* and *stdout* arguments are passed to the\n underlying "cmd.Cmd" class; see the description there.\n\n The *skip* argument, if given, must be an iterable of glob-style\n module name patterns. The debugger will not step into frames that\n originate in a module that matches one of these patterns. [1]\n\n Example call to enable tracing with *skip*:\n\n import pdb; pdb.Pdb(skip=[\'django.*\']).set_trace()\n\n New in version 2.7: The *skip* argument.\n\n run(statement[, globals[, locals]])\n runeval(expression[, globals[, locals]])\n runcall(function[, argument, ...])\n set_trace()\n\n See the documentation for the functions explained above.\n', + 'del': u'\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\nIt is illegal to delete a name from the local namespace if it occurs\nas a free variable in a nested block.\n\nDeletion of attribute references, subscriptions and slicings is passed\nto the primary object involved; deletion of a slicing is in general\nequivalent to assignment of an empty slice of the right type (but even\nthis is determined by the sliced object).\n', + 'dict': u'\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': u'\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\nIf "exec" is used in a function and the function contains or is a\nnested block with free variables, the compiler will raise a\n"SyntaxError" unless the exec explicitly specifies the local namespace\nfor the "exec". (In other words, "exec obj" would be illegal, but\n"exec obj in ns" would be legal.)\n\nThe "eval()", "execfile()", and "input()" functions and the "exec"\nstatement do not have access to the full environment for resolving\nnames. Names may be resolved in the local and global namespaces of\nthe caller. Free variables are not resolved in the nearest enclosing\nnamespace, but in the global namespace. [1] The "exec" statement and\nthe "eval()" and "execfile()" functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n', + 'else': u'\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': u'\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\nExceptions can also be identified by strings, in which case the\n"except" clause is selected by object identity. An arbitrary value\ncan be raised along with the identifying string which can be passed to\nthe handler.\n\nNote: Messages to exceptions 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', + 'exec': u'\nThe "exec" statement\n********************\n\n exec_stmt ::= "exec" or_expr ["in" expression ["," expression]]\n\nThis statement supports dynamic execution of Python code. The first\nexpression should evaluate to either a Unicode string, a *Latin-1*\nencoded string, an open file object, a code object, or a tuple. If it\nis a string, the string is parsed as a suite of Python statements\nwhich is then executed (unless a syntax error occurs). [1] If it is an\nopen file, the file is parsed until EOF and executed. If it is a code\nobject, it is simply executed. For the interpretation of a tuple, see\nbelow. In all cases, the code that\'s executed is expected to be valid\nas file input (see section *File input*). Be aware that the "return"\nand "yield" statements may not be used outside of function definitions\neven within the context of code passed to the "exec" statement.\n\nIn all cases, if the optional parts are omitted, the code is executed\nin the current scope. If only the first expression after "in" is\nspecified, it should be a dictionary, which will be used for both the\nglobal and the local variables. If two expressions are given, they\nare used for the global and local variables, respectively. If\nprovided, *locals* can be any mapping object. Remember that at module\nlevel, globals and locals are the same dictionary. If two separate\nobjects are given as *globals* and *locals*, the code will be executed\nas if it were embedded in a class definition.\n\nThe first expression may also be a tuple of length 2 or 3. In this\ncase, the optional parts must be omitted. The form "exec(expr,\nglobals)" is equivalent to "exec expr in globals", while the form\n"exec(expr, globals, locals)" is equivalent to "exec expr in globals,\nlocals". The tuple form of "exec" provides compatibility with Python\n3, where "exec" is a function rather than a statement.\n\nChanged in version 2.4: Formerly, *locals* was required to be a\ndictionary.\n\nAs a side effect, an implementation may insert additional keys into\nthe dictionaries given besides those corresponding to variable names\nset by the executed code. For example, the current implementation may\nadd a reference to the dictionary of the built-in module "__builtin__"\nunder the key "__builtins__" (!).\n\n**Programmer\'s hints:** dynamic evaluation of expressions is supported\nby the built-in function "eval()". The built-in functions "globals()"\nand "locals()" return the current global and local dictionary,\nrespectively, which may be useful to pass around for use by "exec".\n\n-[ Footnotes ]-\n\n[1] Note that the parser only accepts the Unix-style end of line\n convention. If you are reading the code from a file, make sure to\n use *universal newlines* mode to convert Windows or Mac-style\n newlines.\n', + 'execmodel': u'\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 file read by the\nbuilt-in function "execfile()" is a code block. The string argument\npassed to the built-in function "eval()" and to the "exec" statement\nis a code block. The expression read and evaluated by the built-in\nfunction "input()" 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 generator expressions since\nthey are implemented using a function scope. This means that the\nfollowing 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.\nIf a name is bound at the module level, it is a global variable. (The\nvariables of the module code block are local and global.) If a\nvariable is used in a code block but not defined there, it is a *free\nvariable*.\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, in the\nsecond position of an "except" clause header or after "as" in a "with"\nstatement. The "import" statement of the form "from ... import *"\nbinds all names defined in the imported module, except those beginning\nwith an underscore. This form may only be used at the module level.\n\nA target occurring in a "del" statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name). It\nis illegal to unbind a name that is referenced by an enclosing scope;\nthe compiler will report a "SyntaxError".\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the global statement occurs within a block, all uses of the 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 "__builtin__". The global namespace is searched first.\nIf the name is not found there, the builtins namespace is searched.\nThe global 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 "__builtin__" (note: no\n\'s\'); when in any other module, "__builtins__" is an alias for the\ndictionary of the "__builtin__" module itself. "__builtins__" can be\nset to a user-created dictionary to create a weak form of restricted\nexecution.\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 "__builtin__" (no \'s\') module and modify its attributes\nappropriately.\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\nIf "exec" is used in a function and the function contains or is a\nnested block with free variables, the compiler will raise a\n"SyntaxError" unless the exec explicitly specifies the local namespace\nfor the "exec". (In other words, "exec obj" would be illegal, but\n"exec obj in ns" would be legal.)\n\nThe "eval()", "execfile()", and "input()" functions and the "exec"\nstatement do not have access to the full environment for resolving\nnames. Names may be resolved in the local and global namespaces of\nthe caller. Free variables are not resolved in the nearest enclosing\nnamespace, but in the global namespace. [1] The "exec" statement and\nthe "eval()" and "execfile()" 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\nExceptions can also be identified by strings, in which case the\n"except" clause is selected by object identity. An arbitrary value\ncan be raised along with the identifying string which can be passed to\nthe handler.\n\nNote: Messages to exceptions 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': u'\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': u'\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 of floating point numbers can\nlook like octal integers, but are interpreted using radix 10. For\nexample, "077e010" is legal, and denotes the same number as "77e10".\nThe allowed range of floating point literals is implementation-\ndependent. 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': u'\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, and then the suite is executed. When the items are\nexhausted (which is immediately when the sequence is empty), the suite\nin 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\nThe target list is not deleted when the loop is finished, but if the\nsequence is empty, it will not have been assigned to at all by the\nloop. Hint: the built-in function "range()" returns a sequence of\nintegers suitable to emulate the effect of Pascal\'s "for i := a to b\ndo"; e.g., "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': u'\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"\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 2.7: 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\nTwo conversion flags are currently supported: "\'!s\'" which calls\n"str()" on the value, and "\'!r\'" which calls "repr()".\n\nSome examples:\n\n "Harold\'s a clever {0!s}" # Calls str() on the argument first\n "Bring out the holy {name!r}" # Calls repr() on the argument first\n\nThe *format_spec* field contains a specification of how the value\nshould be presented, including such details as field width, alignment,\npadding, decimal precision and so on. Each value type can define 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 | | space (this is the default for most objects). |\n +-----------+------------------------------------------------------------+\n | "\'>\'" | Forces the field to be right-aligned within the available |\n | | space (this is the default for numbers). |\n +-----------+------------------------------------------------------------+\n | "\'=\'" | Forces the padding to be placed after the sign (if any) |\n | | but before the digits. This is used for printing fields |\n | | in the form \'+000000120\'. This alignment option is only |\n | | valid for numeric types. |\n +-----------+------------------------------------------------------------+\n | "\'^\'" | Forces the field to be centered within the available |\n | | space. |\n +-----------+------------------------------------------------------------+\n\nNote that unless a minimum field width is defined, the field width\nwill always be the same size as the data to fill it, so that the\nalignment option has no meaning in this case.\n\nThe *sign* option is only valid for number types, and can be one of\nthe following:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | "\'+\'" | indicates that a sign should be used for both positive as |\n | | well as negative numbers. |\n +-----------+------------------------------------------------------------+\n | "\'-\'" | indicates that a sign should be used only for negative |\n | | numbers (this is the default behavior). |\n +-----------+------------------------------------------------------------+\n | space | indicates that a leading space should be used on positive |\n | | numbers, and a minus sign on negative numbers. |\n +-----------+------------------------------------------------------------+\n\nThe "\'#\'" option is only valid for integers, and only for binary,\noctal, or hexadecimal output. If present, it specifies that the\noutput will be prefixed by "\'0b\'", "\'0o\'", or "\'0x\'", respectively.\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 2.7: 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 | | 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 the |\n | | current locale setting to insert the appropriate number |\n | | 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\'"\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 | | 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\'". |\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 "p-1" |\n | | would have exponent "exp". Then if "-4 <= exp < p", the |\n | | number is formatted with presentation type "\'f\'" and |\n | | precision "p-1-exp". Otherwise, the number is formatted |\n | | with presentation type "\'e\'" and precision "p-1". In both |\n | | cases insignificant trailing zeros are removed from the |\n | | significand, and the decimal point is also removed if |\n | | there are no remaining digits following it. Positive and |\n | | negative infinity, positive and negative zero, and nans, |\n | | are formatted as "inf", "-inf", "0", "-0" and "nan" |\n | | respectively, regardless of the precision. A precision of |\n | | "0" is treated as equivalent to a precision of "1". The |\n | | default precision is "6". |\n +-----------+------------------------------------------------------------+\n | "\'G\'" | General format. Same as "\'g\'" except switches to "\'E\'" if |\n | | the number gets too large. The representations of infinity |\n | | and NaN are uppercased, too. |\n +-----------+------------------------------------------------------------+\n | "\'n\'" | Number. This is the same as "\'g\'", except that it uses the |\n | | current locale setting to insert the appropriate number |\n | | 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 | The same as "\'g\'". |\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\') # 2.7+ 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(object):\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.5\n >>> total = 22\n >>> \'Correct answers: {:.2%}\'.format(points/total)\n \'Correct answers: 88.64%\'\n\nUsing type-specific formatting:\n\n >>> import datetime\n >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)\n >>> \'{:%Y-%m-%d %H:%M:%S}\'.format(d)\n \'2010-07-04 12:15:58\'\n\nNesting arguments and more complex examples:\n\n >>> for align, text in zip(\'<^>\', [\'left\', \'center\', \'right\']):\n ... \'{0:{fill}{align}16}\'.format(text, fill=align, align=align)\n ...\n \'left<<<<<<<<<<<<\'\n \'^^^^^center^^^^^\'\n \'>>>>>>>>>>>right\'\n >>>\n >>> octets = [192, 168, 0, 1]\n >>> \'{:02X}{:02X}{:02X}{:02X}\'.format(*octets)\n \'C0A80001\'\n >>> int(_, 16)\n 3232235521\n >>>\n >>> width = 5\n >>> for num in range(5,12):\n ... for base in \'dXob\':\n ... print \'{0:{width}{base}}\'.format(num, base=base, width=width),\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': u'\nFunction definitions\n********************\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n decorated ::= decorators (classdef | funcdef)\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n funcdef ::= "def" funcname "(" [parameter_list] ")" ":" suite\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" identifier ["," "**" identifier]\n | "**" identifier\n | defparameter [","] )\n defparameter ::= parameter ["=" expression]\n sublist ::= parameter ("," parameter)* [","]\n parameter ::= identifier | "(" sublist ")"\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 top-level *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 must also have a default value --- this is a syntactic\nrestriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that the same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use "None" as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n""*identifier"" is present, it is initialized to a tuple receiving 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.\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.\n\n**Programmer\'s note:** Functions are first-class objects. A ""def""\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n', + 'global': u'\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 an "exec"\nstatement does not affect the code block *containing* the "exec"\nstatement, and code contained in an "exec" statement is unaffected by\n"global" statements in the code containing the "exec" statement. The\nsame applies to the "eval()", "execfile()" and "compile()" functions.\n', + 'id-classes': u'\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 "__builtin__" 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 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': u'\nIdentifiers and keywords\n************************\n\nIdentifiers (also referred to as *names*) are described by the\nfollowing lexical definitions:\n\n identifier ::= (letter|"_") (letter | digit | "_")*\n letter ::= lowercase | uppercase\n lowercase ::= "a"..."z"\n uppercase ::= "A"..."Z"\n digit ::= "0"..."9"\n\nIdentifiers are unlimited in length. Case is significant.\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 and del from not while\n as elif global or with\n assert else if pass yield\n break except import print\n class exec in raise\n continue finally is return\n def for lambda try\n\nChanged in version 2.4: "None" became a constant and is now recognized\nby the compiler as a name for the built-in object "None". Although it\nis not a keyword, you cannot assign a different object to it.\n\nChanged in version 2.5: Using "as" and "with" as identifiers triggers\na warning. To use them as keywords, enable the "with_statement"\nfuture feature .\n\nChanged in version 2.6: "as" and "with" are full keywords.\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 "__builtin__" 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 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': u'\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': u'\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': u'\nThe "import" statement\n**********************\n\n import_stmt ::= "import" module ["as" name] ( "," module ["as" name] )*\n | "from" relative_module "import" identifier ["as" name]\n ( "," identifier ["as" name] )*\n | "from" relative_module "import" "(" identifier ["as" name]\n ( "," identifier ["as" name] )* [","] ")"\n | "from" module "import" "*"\n module ::= (identifier ".")* identifier\n relative_module ::= "."* module | "."+\n name ::= identifier\n\nImport statements are executed in two steps: (1) find a module, and\ninitialize it if necessary; (2) define a name or names in the local\nnamespace (of the scope where the "import" statement occurs). The\nstatement comes in two forms differing on whether it uses the "from"\nkeyword. The first form (without "from") repeats these steps for each\nidentifier in the list. The form with "from" performs step (1) once,\nand then performs step (2) repeatedly.\n\nTo understand how step (1) occurs, one must first understand how\nPython handles hierarchical naming of modules. To help organize\nmodules and provide a hierarchy in naming, Python has a concept of\npackages. A package can contain other packages and modules while\nmodules cannot contain other modules or packages. From a file system\nperspective, packages are directories and modules are files.\n\nOnce the name of the module is known (unless otherwise specified, the\nterm "module" will refer to both packages and modules), searching for\nthe module or package can begin. The first place checked is\n"sys.modules", the cache of all modules that have been imported\npreviously. If the module is found there then it is used in step (2)\nof import.\n\nIf the module is not found in the cache, then "sys.meta_path" is\nsearched (the specification for "sys.meta_path" can be found in **PEP\n302**). The object is a list of *finder* objects which are queried in\norder as to whether they know how to load the module by calling their\n"find_module()" method with the name of the module. If the module\nhappens to be contained within a package (as denoted by the existence\nof a dot in the name), then a second argument to "find_module()" is\ngiven as the value of the "__path__" attribute from the parent package\n(everything up to the last dot in the name of the module being\nimported). If a finder can find the module it returns a *loader*\n(discussed later) or returns "None".\n\nIf none of the finders on "sys.meta_path" are able to find the module\nthen some implicitly defined finders are queried. Implementations of\nPython vary in what implicit meta path finders are defined. The one\nthey all do define, though, is one that handles "sys.path_hooks",\n"sys.path_importer_cache", and "sys.path".\n\nThe implicit finder searches for the requested module in the "paths"\nspecified in one of two places ("paths" do not have to be file system\npaths). If the module being imported is supposed to be contained\nwithin a package then the second argument passed to "find_module()",\n"__path__" on the parent package, is used as the source of paths. If\nthe module is not contained in a package then "sys.path" is used as\nthe source of paths.\n\nOnce the source of paths is chosen it is iterated over to find a\nfinder that can handle that path. The dict at\n"sys.path_importer_cache" caches finders for paths and is checked for\na finder. If the path does not have a finder cached then\n"sys.path_hooks" is searched by calling each object in the list with a\nsingle argument of the path, returning a finder or raises\n"ImportError". If a finder is returned then it is cached in\n"sys.path_importer_cache" and then used for that path entry. If no\nfinder can be found but the path exists then a value of "None" is\nstored in "sys.path_importer_cache" to signify that an implicit, file-\nbased finder that handles modules stored as individual files should be\nused for that path. If the path does not exist then a finder which\nalways returns "None" is placed in the cache for the path.\n\nIf no finder can find the module then "ImportError" is raised.\nOtherwise some finder returned a loader whose "load_module()" method\nis called with the name of the module to load (see **PEP 302** for the\noriginal definition of loaders). A loader has several responsibilities\nto perform on a module it loads. First, if the module already exists\nin "sys.modules" (a possibility if the loader is called outside of the\nimport machinery) then it is to use that module for initialization and\nnot a new module. But if the module does not exist in "sys.modules"\nthen it is to be added to that dict before initialization begins. If\nan error occurs during loading of the module and it was added to\n"sys.modules" it is to be removed from the dict. If an error occurs\nbut the module was already in "sys.modules" it is left in the dict.\n\nThe loader must set several attributes on the module. "__name__" is to\nbe set to the name of the module. "__file__" is to be the "path" to\nthe file unless the module is built-in (and thus listed in\n"sys.builtin_module_names") in which case the attribute is not set. If\nwhat is being imported is a package then "__path__" is to be set to a\nlist of paths to be searched when looking for modules and packages\ncontained within the package being imported. "__package__" is optional\nbut should be set to the name of package that contains the module or\npackage (the empty string is used for module not contained in a\npackage). "__loader__" is also optional but should be set to the\nloader object that is loading the module.\n\nIf an error occurs during loading then the loader raises "ImportError"\nif some other exception is not already being propagated. Otherwise the\nloader returns the module that was loaded and initialized.\n\nWhen step (1) finishes without raising an exception, step (2) can\nbegin.\n\nThe first form of "import" statement binds the module name in the\nlocal namespace to the module object, and then goes on to import the\nnext identifier, if any. If the module name is followed by "as", the\nname following "as" is used as the local name for the module.\n\nThe "from" form does not bind the module name: it goes through the\nlist of identifiers, looks each one of them up in the module found in\nstep (1), and binds the name in the local namespace to the object thus\nfound. As with the first form of "import", an alternate local name\ncan be supplied by specifying ""as" localname". If a name is not\nfound, "ImportError" is raised. If the list of identifiers is\nreplaced by a star ("\'*\'"), all public names defined in the module are\nbound in the local namespace of the "import" statement..\n\nThe *public names* defined by a module are determined by checking the\nmodule\'s namespace for a variable named "__all__"; if defined, it 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. If the\nwild card form of import --- "import *" --- is used in a function and\nthe function contains or is a nested block with free variables, the\ncompiler will 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" 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 2.6 are "unicode_literals",\n"print_function", "absolute_import", "division", "generators",\n"nested_scopes" and "with_statement". "generators", "with_statement",\n"nested_scopes" are redundant in Python version 2.6 and above because\nthey are always enabled.\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 an "exec" statement or calls to the built-in\nfunctions "compile()" and "execfile()" that occur in a module "M"\ncontaining a future statement will, by default, use the new syntax or\nsemantics associated with the future statement. This can, starting\nwith Python 2.2 be controlled by optional arguments to "compile()" ---\nsee 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': u'\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 forms "<>" and "!=" are equivalent; for consistency with C, "!="\nis preferred; where "!=" is mentioned below "<>" is also accepted.\nThe "<>" spelling is considered obsolescent.\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, objects of\ndifferent types *always* compare unequal, and are ordered consistently\nbut arbitrarily. You can control comparison behavior of objects of\nnon-built-in types by defining a "__cmp__" method or rich comparison\nmethods like "__gt__", described in section *Special method names*.\n\n(This unusual definition of comparison was used to simplify the\ndefinition of operations like sorting and the "in" and "not in"\noperators. In the future, the comparison rules for objects of\ndifferent types are likely to change.)\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* Strings are compared lexicographically using the numeric\n equivalents (the result of the built-in function "ord()") of their\n characters. Unicode and 8-bit strings are fully interoperable in\n this behavior. [4]\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, "cmp([1,2,x], [1,2,y])" returns\n the same as "cmp(x,y)". If the corresponding element does not\n exist, the shorter sequence is ordered first (for example, "[1,2] <\n [1,2,3]").\n\n* Mappings (dictionaries) compare equal if and only if their sorted\n (key, value) lists compare equal. [5] Outcomes other than equality\n are resolved consistently, but are not otherwise defined. [6]\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\nThe operators "in" and "not in" test for collection membership. "x in\ns" evaluates to true if *x* is a member of the collection *s*, and\nfalse otherwise. "x not in s" returns the negation of "x in s". The\ncollection membership test has traditionally been bound to sequences;\nan object is a member of a collection if the collection is a sequence\nand contains an element equal to that object. However, it make sense\nfor many other object types to support membership tests without being\na sequence. In particular, dictionaries (for keys) and sets support\nmembership testing.\n\nFor the list and tuple types, "x in y" is true if and only if there\nexists an index *i* such that "x == y[i]" is true.\n\nFor the Unicode and string types, "x in y" is true if and only if *x*\nis a substring of *y*. An equivalent test is "y.find(x) != -1".\nNote, *x* and *y* need not be the same type; consequently, "u\'ab\' in\n\'abc\'" will return "True". Empty strings are always considered to be a\nsubstring of any other string, so """ in "abc"" will return "True".\n\nChanged in version 2.3: Previously, *x* was required to be a string of\nlength "1".\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. [7]\n', + 'integers': u'\nInteger and long integer literals\n*********************************\n\nInteger and long integer literals are described by the following\nlexical definitions:\n\n longinteger ::= integer ("l" | "L")\n integer ::= decimalinteger | octinteger | hexinteger | bininteger\n decimalinteger ::= nonzerodigit digit* | "0"\n octinteger ::= "0" ("o" | "O") octdigit+ | "0" octdigit+\n hexinteger ::= "0" ("x" | "X") hexdigit+\n bininteger ::= "0" ("b" | "B") bindigit+\n nonzerodigit ::= "1"..."9"\n octdigit ::= "0"..."7"\n bindigit ::= "0" | "1"\n hexdigit ::= digit | "a"..."f" | "A"..."F"\n\nAlthough both lower case "\'l\'" and upper case "\'L\'" are allowed as\nsuffix for long integers, it is strongly recommended to always use\n"\'L\'", since the letter "\'l\'" looks too much like the digit "\'1\'".\n\nPlain integer literals that are above the largest representable plain\ninteger (e.g., 2147483647 when using 32-bit arithmetic) are accepted\nas if they were long integers instead. [1] There is no limit for long\ninteger literals apart from what can be stored in available memory.\n\nSome examples of plain integer literals (first row) and long integer\nliterals (second and third rows):\n\n 7 2147483647 0177\n 3L 79228162514264337593543950336L 0377L 0x100000000L\n 79228162514264337593543950336 0xdeadbeef\n', + 'lambda': u'\nLambdas\n*******\n\n lambda_expr ::= "lambda" [parameter_list]: expression\n old_lambda_expr ::= "lambda" [parameter_list]: old_expression\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 name(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.\n', + 'lists': u'\nList displays\n*************\n\nA list display is a possibly empty series of expressions enclosed in\nsquare brackets:\n\n list_display ::= "[" [expression_list | list_comprehension] "]"\n list_comprehension ::= expression list_for\n list_for ::= "for" target_list "in" old_expression_list [list_iter]\n old_expression_list ::= old_expression [("," old_expression)+ [","]]\n old_expression ::= or_test | old_lambda_expr\n list_iter ::= list_for | list_if\n list_if ::= "if" old_expression [list_iter]\n\nA list display yields a new list object. Its contents are specified\nby providing either a list of expressions or a list comprehension.\nWhen a comma-separated list of expressions is supplied, its elements\nare evaluated from left to right and placed into the list object in\nthat order. When a list comprehension is supplied, it consists of a\nsingle expression followed by at least one "for" clause and zero or\nmore "for" or "if" clauses. In this case, the elements of the new\nlist are those that would be produced by considering each of the "for"\nor "if" clauses a block, nesting from left to right, and evaluating\nthe expression to produce a list element each time the innermost block\nis reached [1].\n', + 'naming': u'\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 file read by the\nbuilt-in function "execfile()" is a code block. The string argument\npassed to the built-in function "eval()" and to the "exec" statement\nis a code block. The expression read and evaluated by the built-in\nfunction "input()" 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 generator expressions since\nthey are implemented using a function scope. This means that the\nfollowing 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.\nIf a name is bound at the module level, it is a global variable. (The\nvariables of the module code block are local and global.) If a\nvariable is used in a code block but not defined there, it is a *free\nvariable*.\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, in the\nsecond position of an "except" clause header or after "as" in a "with"\nstatement. The "import" statement of the form "from ... import *"\nbinds all names defined in the imported module, except those beginning\nwith an underscore. This form may only be used at the module level.\n\nA target occurring in a "del" statement is also considered bound for\nthis purpose (though the actual semantics are to unbind the name). It\nis illegal to unbind a name that is referenced by an enclosing scope;\nthe compiler will report a "SyntaxError".\n\nEach assignment or import statement occurs within a block defined by a\nclass or function definition or at the module level (the top-level\ncode block).\n\nIf a name binding operation occurs anywhere within a code block, all\nuses of the name within the block are treated as references to the\ncurrent block. This can lead to errors when a name is used within a\nblock before it is bound. This rule is subtle. Python lacks\ndeclarations and allows name binding operations to occur anywhere\nwithin a code block. The local variables of a code block can be\ndetermined by scanning the entire text of the block for name binding\noperations.\n\nIf the global statement occurs within a block, all uses of the 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 "__builtin__". The global namespace is searched first.\nIf the name is not found there, the builtins namespace is searched.\nThe global 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 "__builtin__" (note: no\n\'s\'); when in any other module, "__builtins__" is an alias for the\ndictionary of the "__builtin__" module itself. "__builtins__" can be\nset to a user-created dictionary to create a weak form of restricted\nexecution.\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 "__builtin__" (no \'s\') module and modify its attributes\nappropriately.\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\nIf "exec" is used in a function and the function contains or is a\nnested block with free variables, the compiler will raise a\n"SyntaxError" unless the exec explicitly specifies the local namespace\nfor the "exec". (In other words, "exec obj" would be illegal, but\n"exec obj in ns" would be legal.)\n\nThe "eval()", "execfile()", and "input()" functions and the "exec"\nstatement do not have access to the full environment for resolving\nnames. Names may be resolved in the local and global namespaces of\nthe caller. Free variables are not resolved in the nearest enclosing\nnamespace, but in the global namespace. [1] The "exec" statement and\nthe "eval()" and "execfile()" functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n', + 'numbers': u'\nNumeric literals\n****************\n\nThere are four types of numeric literals: plain integers, long\nintegers, floating point numbers, and imaginary numbers. There are no\ncomplex literals (complex numbers can be formed by adding a real\nnumber and an imaginary 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': u'\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.__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__()" (described\n below). Note that "__pow__()" should be defined to accept an\n optional third argument if the ternary version of the built-in\n "pow()" function 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.__div__(self, other)\nobject.__truediv__(self, other)\n\n The division operator ("/") is implemented by these methods. The\n "__truediv__()" method is used when "__future__.division" is in\n effect, otherwise "__div__()" is used. If only one of these two\n methods is defined, the object will not support division in the\n alternate context; "TypeError" will be raised instead.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rdiv__(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.__idiv__(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.__long__(self)\nobject.__float__(self)\n\n Called to implement the built-in functions "complex()", "int()",\n "long()", and "float()". Should return a value of the appropriate\n type.\n\nobject.__oct__(self)\nobject.__hex__(self)\n\n Called to implement the built-in functions "oct()" and "hex()".\n Should return a string value.\n\nobject.__index__(self)\n\n Called to implement "operator.index()". Also called whenever\n Python needs an integer object (such as in slicing). Must return\n an integer (int or long).\n\n New in version 2.5.\n\nobject.__coerce__(self, other)\n\n Called to implement "mixed-mode" numeric arithmetic. Should either\n return a 2-tuple containing *self* and *other* converted to a\n common numeric type, or "None" if conversion is impossible. When\n the common type would be the type of "other", it is sufficient to\n return "None", since the interpreter will also ask the other object\n to attempt a coercion (but sometimes, if the implementation of the\n other type cannot be changed, it is useful to do the conversion to\n the other type here). A return value of "NotImplemented" is\n equivalent to returning "None".\n', + 'objects': u'\nObjects, values and types\n*************************\n\n*Objects* are Python\'s abstraction for data. All data in a Python\nprogram is represented by objects or by relations between objects. (In\na sense, and in conformance to Von Neumann\'s model of a "stored\nprogram computer," code is also represented by objects.)\n\nEvery object has an identity, a type and a value. An object\'s\n*identity* never changes once it has been created; you may think of it\nas the object\'s address in memory. The \'"is"\' operator compares the\nidentity of two objects; the "id()" function returns an integer\nrepresenting its identity (currently implemented as its address). An\nobject\'s *type* is also unchangeable. [1] An object\'s type determines\nthe operations that the object supports (e.g., "does it have a\nlength?") and also defines the possible values for objects of that\ntype. The "type()" function returns an object\'s type (which is an\nobject itself). The *value* of some objects can change. Objects\nwhose value can change are said to be *mutable*; objects whose value\nis unchangeable once they are created are called *immutable*. (The\nvalue of an immutable container object that contains a reference to a\nmutable object can change when the latter\'s value is changed; however\nthe container is still considered immutable, because the collection of\nobjects it contains cannot be changed. So, immutability is not\nstrictly the same as having an unchangeable value, it is more subtle.)\nAn object\'s mutability is determined by its type; for instance,\nnumbers, strings and tuples are immutable, while dictionaries and\nlists are mutable.\n\nObjects are never explicitly destroyed; however, when they become\nunreachable they may be garbage-collected. An implementation is\nallowed to postpone garbage collection or omit it altogether --- it is\na matter of implementation quality how garbage collection is\nimplemented, as long as no objects are collected that are still\nreachable.\n\n**CPython implementation detail:** CPython currently uses a reference-\ncounting scheme with (optional) delayed detection of cyclically linked\ngarbage, which collects most objects as soon as they become\nunreachable, but is not guaranteed to collect garbage containing\ncircular references. See the documentation of the "gc" module for\ninformation on controlling the collection of cyclic garbage. Other\nimplementations act differently and CPython may change. Do not depend\non immediate finalization of objects when they become unreachable (ex:\nalways close files).\n\nNote that the use of the implementation\'s tracing or debugging\nfacilities may keep objects alive that would normally be collectable.\nAlso note that catching an exception with a \'"try"..."except"\'\nstatement may keep objects alive.\n\nSome objects contain references to "external" resources such as open\nfiles or windows. It is understood that these resources are freed\nwhen the object is garbage-collected, but since garbage collection is\nnot guaranteed to happen, such objects also provide an explicit way to\nrelease the external resource, usually a "close()" method. Programs\nare strongly recommended to explicitly close such objects. The\n\'"try"..."finally"\' statement provides a convenient way 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': u'\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| | [8] |\n+-------------------------------------------------+---------------------------------------+\n| "+x", "-x", "~x" | Positive, negative, bitwise NOT |\n+-------------------------------------------------+---------------------------------------+\n| "**" | Exponentiation [9] |\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, string |\n| | conversion |\n+-------------------------------------------------+---------------------------------------+\n\n-[ Footnotes ]-\n\n[1] In Python 2.3 and later releases, a list comprehension "leaks"\n the control variables of each "for" it contains into the\n containing scope. However, this behavior is deprecated, and\n relying on it will not work in Python 3.\n\n[2] 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[3] If x is very close to an exact integer multiple of y, it\'s\n possible for "floor(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[4] While comparisons between unicode strings make sense at the\n byte level, they may be counter-intuitive to users. For example,\n the strings "u"\\u00C7"" and "u"\\u0043\\u0327"" compare differently,\n even 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[5] The implementation computes this efficiently, without\n constructing lists or sorting.\n\n[6] Earlier versions of Python used lexicographic comparison of\n the sorted (key, value) lists, but this was very expensive for the\n common case of comparing for equality. An even earlier version of\n Python compared dictionaries by identity only, but this caused\n surprises because people expected to be able to test a dictionary\n for emptiness by comparing it to "{}".\n\n[7] 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[8] The "%" operator is also used for string formatting; the same\n precedence applies.\n\n[9] 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': u'\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': u'\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. The result type is that of the\narguments after coercion.\n\nWith mixed operand types, the coercion rules for binary arithmetic\noperators apply. For int and long int operands, the result has the\nsame type as the operands (after coercion) unless the second argument\nis negative; in that case, all arguments are converted to float and a\nfloat result is delivered. For example, "10**2" returns "100", but\n"10**-2" returns "0.01". (This last feature was added in Python 2.2.\nIn Python 2.1 and before, if both arguments were of integer types and\nthe second argument was negative, an exception was raised).\n\nRaising "0.0" to a negative power results in a "ZeroDivisionError".\nRaising a negative number to a fractional power results in a\n"ValueError".\n', + 'print': u'\nThe "print" statement\n*********************\n\n print_stmt ::= "print" ([expression ("," expression)* [","]]\n | ">>" expression [("," expression)+ [","]])\n\n"print" evaluates each expression in turn and writes the resulting\nobject to standard output (see below). If an object is not a string,\nit is first converted to a string using the rules for string\nconversions. The (resulting or original) string is then written. A\nspace is written before each object is (converted and) written, unless\nthe output system believes it is positioned at the beginning of a\nline. This is the case (1) when no characters have yet been written\nto standard output, (2) when the last character written to standard\noutput is a whitespace character except "\' \'", or (3) when the last\nwrite operation on standard output was not a "print" statement. (In\nsome cases it may be functional to write an empty string to standard\noutput for this reason.)\n\nNote: Objects which act like file objects but which are not the\n built-in file objects often do not properly emulate this aspect of\n the file object\'s behavior, so it is best not to rely on this.\n\nA "\'\\n\'" character is written at the end, unless the "print" statement\nends with a comma. This is the only action if the statement contains\njust the keyword "print".\n\nStandard output is defined as the file object named "stdout" in the\nbuilt-in module "sys". If no such object exists, or if it does not\nhave a "write()" method, a "RuntimeError" exception is raised.\n\n"print" also has an extended form, defined by the second portion of\nthe syntax described above. This form is sometimes referred to as\n""print" chevron." In this form, the first expression after the ">>"\nmust evaluate to a "file-like" object, specifically an object that has\na "write()" method as described above. With this extended form, the\nsubsequent expressions are printed to this file object. If the first\nexpression evaluates to "None", then "sys.stdout" is used as the file\nfor output.\n', + 'raise': u'\nThe "raise" statement\n*********************\n\n raise_stmt ::= "raise" [expression ["," expression ["," expression]]]\n\nIf no expressions are present, "raise" re-raises the last exception\nthat was active in the current scope. If no exception is active in\nthe current scope, a "TypeError" exception is raised indicating that\nthis is an error (if running under IDLE, a "Queue.Empty" exception is\nraised instead).\n\nOtherwise, "raise" evaluates the expressions to get three objects,\nusing "None" as the value of omitted expressions. The first two\nobjects are used to determine the *type* and *value* of the exception.\n\nIf the first object is an instance, the type of the exception is the\nclass of the instance, the instance itself is the value, and the\nsecond object must be "None".\n\nIf the first object is a class, it becomes the type of the exception.\nThe second object is used to determine the exception value: If it is\nan instance of the class, the instance becomes the exception value. If\nthe second object is a tuple, it is used as the argument list for the\nclass constructor; if it is "None", an empty argument list is used,\nand any other object is treated as a single argument to the\nconstructor. The instance so created by calling the constructor is\nused as the exception value.\n\nIf a third object is present and not "None", it must be a traceback\nobject (see section *The standard type hierarchy*), and it is\nsubstituted instead of the current location as the place where the\nexception occurred. If the third object is present and not a\ntraceback object or "None", a "TypeError" exception is raised. The\nthree-expression form of "raise" is useful to re-raise an exception\ntransparently in an except clause, but "raise" with no expressions\nshould be preferred if the exception to be re-raised was the most\nrecently active exception in the current scope.\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': u'\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 is not allowed to\ninclude an "expression_list". In that context, a bare "return"\nindicates that the generator is done and will cause "StopIteration" to\nbe raised.\n', + 'sequence-types': u'\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. (For backwards compatibility, the method\n"__getslice__()" (see below) can also be defined to handle simple, but\nnot extended slices.) It is also recommended that mappings provide the\nmethods "keys()", "values()", "items()", "has_key()", "get()",\n"clear()", "setdefault()", "iterkeys()", "itervalues()",\n"iteritems()", "pop()", "popitem()", "copy()", and "update()" behaving\nsimilar to those for Python\'s standard dictionary objects. The\n"UserDict" module provides a "DictMixin" class to help create those\nmethods from a base set of "__getitem__()", "__setitem__()",\n"__delitem__()", and "keys()". Mutable sequences should provide\nmethods "append()", "count()", "index()", "extend()", "insert()",\n"pop()", "remove()", "reverse()" and "sort()", like Python standard\nlist objects. Finally, sequence types should implement addition\n(meaning concatenation) and multiplication (meaning repetition) by\ndefining the methods "__add__()", "__radd__()", "__iadd__()",\n"__mul__()", "__rmul__()" and "__imul__()" described below; they\nshould not define "__coerce__()" or 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 be equivalent of "has_key()"; for sequences,\nit should search through the values. It is further recommended that\nboth mappings and sequences implement the "__iter__()" method to allow\nefficient iteration through the container; for mappings, "__iter__()"\nshould be the same as "iterkeys()"; 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 "__nonzero__()" method and whose "__len__()"\n method returns zero is considered to be false in a Boolean context.\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 "iterkeys()".\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\n New in version 2.6.\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': u'\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 plain or long integers as arguments. The\narguments are converted to a common type. They shift the first\nargument to the left or right by the number of bits given by the\nsecond argument.\n\nA right shift by *n* bits is defined as division by "pow(2, n)". A\nleft shift by *n* bits is defined as multiplication with "pow(2, n)".\nNegative shift counts raise a "ValueError" exception.\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': u'\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 ::= simple_slicing | extended_slicing\n simple_slicing ::= primary "[" short_slice "]"\n extended_slicing ::= primary "[" slice_list "]"\n slice_list ::= slice_item ("," slice_item)* [","]\n slice_item ::= expression | proper_slice | ellipsis\n proper_slice ::= short_slice | long_slice\n short_slice ::= [lower_bound] ":" [upper_bound]\n long_slice ::= short_slice ":" [stride]\n lower_bound ::= expression\n upper_bound ::= expression\n stride ::= expression\n ellipsis ::= "..."\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 nor ellipses). Similarly, when the slice\nlist has exactly one short slice and no trailing comma, the\ninterpretation as a simple slicing takes priority over that as an\nextended slicing.\n\nThe semantics for a simple slicing are as follows. The primary must\nevaluate to a sequence object. The lower and upper bound expressions,\nif present, must evaluate to plain integers; defaults are zero and the\n"sys.maxint", respectively. If either bound is negative, the\nsequence\'s length is added to it. The slicing now selects all items\nwith index *k* such that "i <= k < j" where *i* and *j* are the\nspecified lower and upper bounds. This may be an empty sequence. It\nis not an error if *i* or *j* lie outside the range of valid indexes\n(such items don\'t exist so they aren\'t selected).\n\nThe semantics for an extended slicing are as follows. The primary\nmust evaluate to a mapping object, and it is indexed with a key that\nis constructed 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 an ellipsis slice\nitem is the built-in "Ellipsis" object. The conversion of a proper\nslice is a slice object (see section *The standard type hierarchy*)\nwhose "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': u'\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\nobject.__methods__\n\n Deprecated since version 2.2: Use the built-in function "dir()" to\n get a list of an object\'s attributes. This attribute is no longer\n available.\n\nobject.__members__\n\n Deprecated since version 2.2: Use the built-in function "dir()" to\n get a list of an object\'s attributes. This attribute is no longer\n available.\n\ninstance.__class__\n\n The class to which a class instance belongs.\n\nclass.__bases__\n\n The tuple of base classes of a class object.\n\nclass.__name__\n\n The name of the class or type.\n\nThe following attributes are only supported by *new-style class*es.\n\nclass.__mro__\n\n This attribute is a tuple of classes that are considered when\n looking for base classes during method resolution.\n\nclass.mro()\n\n This method can be overridden by a metaclass to customize the\n method resolution order for its instances. It is called at class\n instantiation, and its result is stored in "__mro__".\n\nclass.__subclasses__()\n\n Each new-style class keeps a list of weak references to its\n immediate subclasses. This method returns a list of all those\n references still alive. Example:\n\n >>> int.__subclasses__()\n []\n\n-[ Footnotes ]-\n\n[1] Additional information on these special methods may be found\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\n[6] The advantage of leaving the newline on is that returning an\n empty string is then an unambiguous EOF indication. It is also\n possible (in cases where it might matter, for example, if you want\n to make an exact copy of a file while scanning its lines) to tell\n whether the last line of a file ended in a newline or not (yes\n this happens!).\n', + 'specialnames': u'\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 "x.__getitem__(i)" for old-style\nclasses and "type(x).__getitem__(x, i)" for new-style classes. Except\nwhere mentioned, attempts to execute an operation raise an exception\nwhen no appropriate method is defined (typically "AttributeError" or\n"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_traceback" 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.exc_traceback" or "sys.last_traceback". Circular references\n which are garbage are detected when the option cycle detector is\n enabled (it\'s on by default), but can only be cleaned up if there\n are no Python-level "__del__()" methods involved. Refer to the\n documentation for the "gc" module for more information about how\n "__del__()" methods are handled by the cycle detector,\n particularly the description of the "garbage" value.\n\n Warning: Due to the precarious circumstances under which\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\n See also the *-R* command-line option.\n\nobject.__repr__(self)\n\n Called by the "repr()" built-in function and by string conversions\n (reverse quotes) to compute the "official" string representation of\n an object. If at all possible, this should look like a valid\n Python expression that could be used to recreate an object with the\n same value (given an appropriate environment). If this is not\n possible, a string of the form "<...some useful description...>"\n should be returned. The return value must be a string object. If a\n class defines "__repr__()" but not "__str__()", then "__repr__()"\n is also used when an "informal" string representation of instances\n 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 the "str()" built-in function and by the "print"\n statement to compute the "informal" string representation of an\n object. This differs from "__repr__()" in that it does not have to\n be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__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 New in version 2.1.\n\n These are the so-called "rich comparison" methods, and are called\n for comparison operators in preference to "__cmp__()" below. The\n correspondence between operator symbols and method names is as\n follows: "xy" call "x.__ne__(y)",\n "x>y" calls "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.__cmp__(self, other)\n\n Called by comparison operations if rich comparison (see above) is\n not defined. Should return a negative integer if "self < other",\n zero if "self == other", a positive integer if "self > other". If\n no "__cmp__()", "__eq__()" or "__ne__()" operation is defined,\n class instances are compared by object identity ("address"). See\n also the description of "__hash__()" for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys. (Note: the\n restriction that exceptions are not propagated by "__cmp__()" has\n been removed since Python 1.5.)\n\nobject.__rcmp__(self, other)\n\n Changed in version 2.1: No longer supported.\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 If a class does not define a "__cmp__()" or "__eq__()" method it\n should not define a "__hash__()" operation either; if it defines\n "__cmp__()" or "__eq__()" but not "__hash__()", its instances will\n not be usable in hashed collections. If a class defines mutable\n objects and implements a "__cmp__()" or "__eq__()" method, it\n should not implement "__hash__()", since hashable collection\n implementations require that a object\'s hash value is immutable (if\n the object\'s hash value changes, it will be in the wrong hash\n bucket).\n\n User-defined classes have "__cmp__()" and "__hash__()" methods by\n default; with them, all objects compare unequal (except with\n themselves) and "x.__hash__()" returns a result derived from\n "id(x)".\n\n Classes which inherit a "__hash__()" method from a parent class but\n change the meaning of "__cmp__()" or "__eq__()" such that the hash\n value returned is no longer appropriate (e.g. by switching to a\n value-based concept of equality instead of the default identity\n based equality) can explicitly flag themselves as being unhashable\n by setting "__hash__ = None" in the class definition. Doing so\n means that not only will instances of the class raise an\n appropriate "TypeError" when a program attempts to retrieve their\n hash value, but they will also be correctly identified as\n unhashable when checking "isinstance(obj, collections.Hashable)"\n (unlike classes which define their own "__hash__()" to explicitly\n raise "TypeError").\n\n Changed in version 2.5: "__hash__()" may now also return a long\n integer object; the 32-bit integer is then derived from the hash of\n that object.\n\n Changed in version 2.6: "__hash__" may now be set to "None" to\n explicitly flag instances of a class as unhashable.\n\nobject.__nonzero__(self)\n\n Called to implement truth value testing and the built-in operation\n "bool()"; should return "False" or "True", or their integer\n equivalents "0" or "1". When this method is not defined,\n "__len__()" is called, if it is defined, and the object is\n considered true if its result is nonzero. If a class defines\n neither "__len__()" nor "__nonzero__()", all its instances are\n considered true.\n\nobject.__unicode__(self)\n\n Called to implement "unicode()" built-in; should return a Unicode\n object. When this method is not defined, string conversion is\n attempted, and the result of string conversion is converted to\n Unicode using the system default encoding.\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 in new-style classes.\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 not simply execute "self.name = value" --- this would cause\n a recursive call to itself. Instead, it should insert the value in\n the dictionary of instance attributes, e.g., "self.__dict__[name] =\n value". For new-style classes, rather than accessing the instance\n dictionary, it should call the base class method with the same\n name, for example, "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\n\nMore attribute access for new-style classes\n-------------------------------------------\n\nThe following methods only apply to new-style classes.\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 for new-style\n classes*.\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. Note that descriptors are only invoked for new\nstyle objects or classes (ones that subclass "object()" or "type()").\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 a new-style object instance, "a.x" is transformed\n into the call: "type(a).__dict__[\'x\'].__get__(a, type(a))".\n\nClass Binding\n If binding to a new-style class, "A.x" is transformed into the\n call: "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 both old and new-style classes have a\ndictionary for attribute storage. This wastes space for objects\nhaving very few instance variables. The space consumption can become\nacute when creating large numbers of instances.\n\nThe default can be overridden by defining *__slots__* in a new-style\nclass definition. The *__slots__* declaration takes a sequence of\ninstance variables and reserves just enough space in each instance to\nhold a value for each variable. Space is saved because *__dict__* is\nnot created for each instance.\n\n__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 new-style class, *__slots__* reserves space for the declared\n variables and prevents the automatic creation of *__dict__* and\n *__weakref__* for each instance.\n\n New in version 2.2.\n\nNotes on using *__slots__*\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 Changed in version 2.3: Previously, adding "\'__dict__\'" to the\n *__slots__* declaration would not enable the assignment of new\n attributes not specifically listed in the sequence of instance\n variable names.\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 Changed in version 2.3: Previously, adding "\'__weakref__\'" to the\n *__slots__* declaration would not enable support for weak\n references.\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 "long", "str" 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 Changed in version 2.6: Previously, *__class__* assignment raised an\n error if either new or old class had *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, new-style classes are constructed using "type()". A class\ndefinition is read into a separate namespace and the value of class\nname is bound to the result of "type(name, bases, dict)".\n\nWhen the class definition is read, if *__metaclass__* is defined then\nthe callable assigned to it will be called instead of "type()". This\nallows classes or functions to be written which monitor or alter the\nclass creation process:\n\n* Modifying the class dictionary prior to the class being created.\n\n* Returning an instance of another class -- essentially performing\n the role of a factory function.\n\nThese steps will have to be performed in the metaclass\'s "__new__()"\nmethod -- "type.__new__()" can then be called from this method to\ncreate a class with different properties. This example adds a new\nelement to the class dictionary before creating the class:\n\n class metacls(type):\n def __new__(mcs, name, bases, dict):\n dict[\'foo\'] = \'metacls was here\'\n return type.__new__(mcs, name, bases, dict)\n\nYou can of course also override other class methods (or add new\nmethods); for example defining a custom "__call__()" method in the\nmetaclass allows custom behavior when the class is called, e.g. not\nalways creating a new instance.\n\n__metaclass__\n\n This variable can be any callable accepting arguments for "name",\n "bases", and "dict". Upon class creation, the callable is used\n instead of the built-in "type()".\n\n New in version 2.2.\n\nThe appropriate metaclass is determined by the following precedence\nrules:\n\n* If "dict[\'__metaclass__\']" exists, it is used.\n\n* Otherwise, if there is at least one base class, its metaclass is\n used (this looks for a *__class__* attribute first and if not found,\n uses its type).\n\n* Otherwise, if a global variable named __metaclass__ exists, it is\n used.\n\n* Otherwise, the old-style, classic metaclass (types.ClassType) is\n used.\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored including logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\n\nCustomizing instance and subclass checks\n========================================\n\nNew in version 2.6.\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. (For backwards compatibility, the method\n"__getslice__()" (see below) can also be defined to handle simple, but\nnot extended slices.) It is also recommended that mappings provide the\nmethods "keys()", "values()", "items()", "has_key()", "get()",\n"clear()", "setdefault()", "iterkeys()", "itervalues()",\n"iteritems()", "pop()", "popitem()", "copy()", and "update()" behaving\nsimilar to those for Python\'s standard dictionary objects. The\n"UserDict" module provides a "DictMixin" class to help create those\nmethods from a base set of "__getitem__()", "__setitem__()",\n"__delitem__()", and "keys()". Mutable sequences should provide\nmethods "append()", "count()", "index()", "extend()", "insert()",\n"pop()", "remove()", "reverse()" and "sort()", like Python standard\nlist objects. Finally, sequence types should implement addition\n(meaning concatenation) and multiplication (meaning repetition) by\ndefining the methods "__add__()", "__radd__()", "__iadd__()",\n"__mul__()", "__rmul__()" and "__imul__()" described below; they\nshould not define "__coerce__()" or 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 be equivalent of "has_key()"; for sequences,\nit should search through the values. It is further recommended that\nboth mappings and sequences implement the "__iter__()" method to allow\nefficient iteration through the container; for mappings, "__iter__()"\nshould be the same as "iterkeys()"; 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 "__nonzero__()" method and whose "__len__()"\n method returns zero is considered to be false in a Boolean context.\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 "iterkeys()".\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\n New in version 2.6.\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\nAdditional methods for emulation of sequence types\n==================================================\n\nThe following optional methods can be defined to further emulate\nsequence objects. Immutable sequences methods should at most only\ndefine "__getslice__()"; mutable sequences might define all three\nmethods.\n\nobject.__getslice__(self, i, j)\n\n Deprecated since version 2.0: Support slice objects as parameters\n to the "__getitem__()" method. (However, built-in types in CPython\n currently still implement "__getslice__()". Therefore, you have to\n override it in derived classes when implementing slicing.)\n\n Called to implement evaluation of "self[i:j]". The returned object\n should be of the same type as *self*. Note that missing *i* or *j*\n in the slice expression are replaced by zero or "sys.maxint",\n respectively. If negative indexes are used in the slice, the\n length of the sequence is added to that index. If the instance does\n not implement the "__len__()" method, an "AttributeError" is\n raised. No guarantee is made that indexes adjusted this way are not\n still negative. Indexes which are greater than the length of the\n sequence are not modified. If no "__getslice__()" is found, a slice\n object is created instead, and passed to "__getitem__()" instead.\n\nobject.__setslice__(self, i, j, sequence)\n\n Called to implement assignment to "self[i:j]". Same notes for *i*\n and *j* as for "__getslice__()".\n\n This method is deprecated. If no "__setslice__()" is found, or for\n extended slicing of the form "self[i:j:k]", a slice object is\n created, and passed to "__setitem__()", instead of "__setslice__()"\n being called.\n\nobject.__delslice__(self, i, j)\n\n Called to implement deletion of "self[i:j]". Same notes for *i* and\n *j* as for "__getslice__()". This method is deprecated. If no\n "__delslice__()" is found, or for extended slicing of the form\n "self[i:j:k]", a slice object is created, and passed to\n "__delitem__()", instead of "__delslice__()" being called.\n\nNotice that these methods are only invoked when a single slice with a\nsingle colon is used, and the slice method is available. For slice\noperations involving extended slice notation, or in absence of the\nslice methods, "__getitem__()", "__setitem__()" or "__delitem__()" is\ncalled with a slice object as argument.\n\nThe following example demonstrate how to make your program or module\ncompatible with earlier versions of Python (assuming that methods\n"__getitem__()", "__setitem__()" and "__delitem__()" support slice\nobjects as arguments):\n\n class MyClass:\n ...\n def __getitem__(self, index):\n ...\n def __setitem__(self, index, value):\n ...\n def __delitem__(self, index):\n ...\n\n if sys.version_info < (2, 0):\n # They won\'t be defined if version is at least 2.0 final\n\n def __getslice__(self, i, j):\n return self[max(0, i):max(0, j):]\n def __setslice__(self, i, j, seq):\n self[max(0, i):max(0, j):] = seq\n def __delslice__(self, i, j):\n del self[max(0, i):max(0, j):]\n ...\n\nNote the calls to "max()"; these are necessary because of the handling\nof negative indices before the "__*slice__()" methods are called.\nWhen negative indexes are used, the "__*item__()" methods receive them\nas provided, but the "__*slice__()" methods get a "cooked" form of the\nindex values. For each negative index value, the length of the\nsequence is added to the index before calling the method (which may\nstill result in a negative index); this is the customary handling of\nnegative indexes by the built-in sequence types, and the "__*item__()"\nmethods are expected to do this as well. However, since they should\nalready be doing that, negative indexes cannot be passed in; they must\nbe constrained to the bounds of the sequence before being passed to\nthe "__*item__()" methods. Calling "max(0, i)" conveniently returns\nthe proper value.\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.__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__()" (described\n below). Note that "__pow__()" should be defined to accept an\n optional third argument if the ternary version of the built-in\n "pow()" function 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.__div__(self, other)\nobject.__truediv__(self, other)\n\n The division operator ("/") is implemented by these methods. The\n "__truediv__()" method is used when "__future__.division" is in\n effect, otherwise "__div__()" is used. If only one of these two\n methods is defined, the object will not support division in the\n alternate context; "TypeError" will be raised instead.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rdiv__(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.__idiv__(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.__long__(self)\nobject.__float__(self)\n\n Called to implement the built-in functions "complex()", "int()",\n "long()", and "float()". Should return a value of the appropriate\n type.\n\nobject.__oct__(self)\nobject.__hex__(self)\n\n Called to implement the built-in functions "oct()" and "hex()".\n Should return a string value.\n\nobject.__index__(self)\n\n Called to implement "operator.index()". Also called whenever\n Python needs an integer object (such as in slicing). Must return\n an integer (int or long).\n\n New in version 2.5.\n\nobject.__coerce__(self, other)\n\n Called to implement "mixed-mode" numeric arithmetic. Should either\n return a 2-tuple containing *self* and *other* converted to a\n common numeric type, or "None" if conversion is impossible. When\n the common type would be the type of "other", it is sufficient to\n return "None", since the interpreter will also ask the other object\n to attempt a coercion (but sometimes, if the implementation of the\n other type cannot be changed, it is useful to do the conversion to\n the other type here). A return value of "NotImplemented" is\n equivalent to returning "None".\n\n\nCoercion rules\n==============\n\nThis section used to document the rules for coercion. As the language\nhas evolved, the coercion rules have become hard to document\nprecisely; documenting what one version of one particular\nimplementation does is undesirable. Instead, here are some informal\nguidelines regarding coercion. In Python 3, coercion will not be\nsupported.\n\n* If the left operand of a % operator is a string or Unicode object,\n no coercion takes place and the string formatting operation is\n invoked instead.\n\n* It is no longer recommended to define a coercion operation. Mixed-\n mode operations on types that don\'t define coercion pass the\n original arguments to the operation.\n\n* New-style classes (those derived from "object") never invoke the\n "__coerce__()" method in response to a binary operator; the only\n time "__coerce__()" is invoked is when the built-in function\n "coerce()" is called.\n\n* For most intents and purposes, an operator that returns\n "NotImplemented" is treated the same as one that is not implemented\n at all.\n\n* Below, "__op__()" and "__rop__()" are used to signify the generic\n method names corresponding to an operator; "__iop__()" is used for\n the corresponding in-place operator. For example, for the operator\n \'"+"\', "__add__()" and "__radd__()" are used for the left and right\n variant of the binary operator, and "__iadd__()" for the in-place\n variant.\n\n* For objects *x* and *y*, first "x.__op__(y)" is tried. If this is\n not implemented or returns "NotImplemented", "y.__rop__(x)" is\n tried. If this is also not implemented or returns "NotImplemented",\n a "TypeError" exception is raised. But see the following exception:\n\n* Exception to the previous item: if the left operand is an instance\n of a built-in type or a new-style class, and the right operand is an\n instance of a proper subclass of that type or class and overrides\n the base\'s "__rop__()" method, the right operand\'s "__rop__()"\n method is tried *before* the left operand\'s "__op__()" method.\n\n This is done so that a subclass can completely override binary\n operators. Otherwise, the left operand\'s "__op__()" method would\n always accept the right operand: when an instance of a given class\n is expected, an instance of a subclass of that class is always\n acceptable.\n\n* When either operand type defines a coercion, this coercion is\n called before that type\'s "__op__()" or "__rop__()" method is\n called, but no sooner. If the coercion returns an object of a\n different type for the operand whose coercion is invoked, part of\n the process is redone using the new object.\n\n* When an in-place operator (like \'"+="\') is used, if the left\n operand implements "__iop__()", it is invoked without any coercion.\n When the operation falls back to "__op__()" and/or "__rop__()", the\n normal coercion rules apply.\n\n* In "x + y", if *x* is a sequence that implements sequence\n concatenation, sequence concatenation is invoked.\n\n* In "x * y", if one operand is a sequence that implements sequence\n repetition, and the other is an integer ("int" or "long"), sequence\n repetition is invoked.\n\n* Rich comparisons (implemented by methods "__eq__()" and so on)\n never use coercion. Three-way comparison (implemented by\n "__cmp__()") does use coercion under the same conditions as other\n binary operations use it.\n\n* In the current implementation, the built-in numeric types "int",\n "long", "float", and "complex" do not use coercion. All these types\n implement a "__coerce__()" method, for use by the built-in\n "coerce()" function.\n\n Changed in version 2.7: The complex type no longer makes implicit\n calls to the "__coerce__()" method for mixed-type binary arithmetic\n operations.\n\n\nWith Statement Context Managers\n===============================\n\nNew in version 2.5.\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 for old-style classes\n===========================================\n\nFor old-style classes, special methods are always looked up in exactly\nthe same way as any other method or attribute. This is the case\nregardless of whether the method is being looked up explicitly as in\n"x.__getitem__(i)" or implicitly as in "x[i]".\n\nThis behaviour means that special methods may exhibit different\nbehaviour for different instances of a single old-style class if the\nappropriate special attributes are set differently:\n\n >>> class C:\n ... pass\n ...\n >>> c1 = C()\n >>> c2 = C()\n >>> c1.__len__ = lambda: 5\n >>> c2.__len__ = lambda: 9\n >>> len(c1)\n 5\n >>> len(c2)\n 9\n\n\nSpecial method lookup for new-style classes\n===========================================\n\nFor new-style classes, implicit invocations of special methods are\nonly guaranteed to work correctly if defined on an object\'s type, not\nin the object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception (unlike the equivalent example\nwith old-style classes):\n\n >>> class C(object):\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as "__hash__()" and "__repr__()" that are implemented 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):\n ... __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': u'\nString Methods\n**************\n\nBelow are listed the string methods which both 8-bit strings and\nUnicode objects support. Some of them are also available on\n"bytearray" objects.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, unicode, list, tuple,\nbytearray, buffer, xrange* section. To output formatted strings use\ntemplate strings or the "%" operator described in the *String\nFormatting Operations* section. Also, see the "re" module for string\nfunctions based on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\n For 8-bit strings, this method is locale-dependent.\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\n Changed in version 2.4: Support for the *fillchar* argument.\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.decode([encoding[, errors]])\n\n Decodes the string using the codec registered for *encoding*.\n *encoding* defaults to the default string encoding. *errors* may\n be given to set a different error handling scheme. The default is\n "\'strict\'", meaning that encoding errors raise "UnicodeError".\n Other possible values are "\'ignore\'", "\'replace\'" and any other\n name registered via "codecs.register_error()", see section *Codec\n Base Classes*.\n\n New in version 2.2.\n\n Changed in version 2.3: Support for other error handling schemes\n added.\n\n Changed in version 2.7: Support for keyword arguments added.\n\nstr.encode([encoding[, errors]])\n\n Return an encoded version of the string. Default encoding is the\n current default string encoding. *errors* may be given to set a\n different error handling scheme. The default for *errors* is\n "\'strict\'", meaning that encoding errors raise a "UnicodeError".\n Other 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 New in version 2.0.\n\n Changed in version 2.3: Support for "\'xmlcharrefreplace\'" and\n "\'backslashreplace\'" and other error handling schemes added.\n\n Changed in version 2.7: 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\n Changed in version 2.5: Accept tuples as *suffix*.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. 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\n This method of string formatting is the new standard in Python 3,\n and should be preferred to the "%" formatting described in *String\n Formatting Operations* in new code.\n\n New in version 2.6.\n\nstr.index(sub[, start[, end]])\n\n Like "find()", but raise "ValueError" when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise.\n\n For 8-bit strings, this method is locale-dependent.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise.\n\n For 8-bit strings, this method is locale-dependent.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise.\n\n For 8-bit strings, this method is locale-dependent.\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\n For 8-bit strings, this method is locale-dependent.\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise.\n\n For 8-bit strings, this method is locale-dependent.\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\n For 8-bit strings, this method is locale-dependent.\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\n For 8-bit strings, this method is locale-dependent.\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. The separator between elements is the\n 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\n Changed in version 2.4: Support for the *fillchar* argument.\n\nstr.lower()\n\n Return a copy of the string with all the cased characters [4]\n converted to lowercase.\n\n For 8-bit strings, this method is locale-dependent.\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\n Changed in version 2.2.2: Support for the *chars* argument.\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\n New in version 2.5.\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\n Changed in version 2.4: Support for the *fillchar* argument.\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\n New in version 2.5.\n\nstr.rsplit([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n "None", any whitespace string is a separator. Except for splitting\n from the right, "rsplit()" behaves like "split()" which is\n described in detail below.\n\n New in version 2.4.\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\n Changed in version 2.2.2: Support for the *chars* argument.\n\nstr.split([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most "maxsplit+1"\n elements). If *maxsplit* is not specified 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\n Changed in version 2.5: Accept tuples as *prefix*.\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\n Changed in version 2.2.2: Support for the *chars* argument.\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa.\n\n For 8-bit strings, this method is locale-dependent.\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\n For 8-bit strings, this method is locale-dependent.\n\nstr.translate(table[, deletechars])\n\n Return a copy of the string where all characters occurring in the\n optional argument *deletechars* are removed, and the remaining\n characters have been mapped through the given translation table,\n which must be a string of length 256.\n\n You can use the "maketrans()" helper function in the "string"\n module to create a translation table. For string objects, set the\n *table* argument to "None" for translations that only delete\n characters:\n\n >>> \'read this short text\'.translate(None, \'aeiou\')\n \'rd ths shrt txt\'\n\n New in version 2.6: Support for a "None" *table* argument.\n\n For Unicode objects, the "translate()" method does not accept the\n optional *deletechars* argument. Instead, it returns a copy of the\n *s* where all characters have been mapped through the given\n translation table which must be a mapping of Unicode ordinals to\n Unicode ordinals, Unicode strings or "None". Unmapped characters\n are left untouched. Characters mapped to "None" are deleted. Note,\n a more flexible approach is to create a custom character mapping\n codec using the "codecs" module (see "encodings.cp1251" for an\n 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 For 8-bit strings, this method is locale-dependent.\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\n New in version 2.2.2.\n\nThe following methods are present only on unicode objects:\n\nunicode.isnumeric()\n\n Return "True" if there are only numeric characters in S, "False"\n otherwise. Numeric characters include digit characters, and all\n characters that have the Unicode numeric value property, e.g.\n U+2155, VULGAR FRACTION ONE FIFTH.\n\nunicode.isdecimal()\n\n Return "True" if there are only decimal characters in S, "False"\n otherwise. Decimal characters include digit characters, and all\n characters that can be used to form decimal-radix numbers, e.g.\n U+0660, ARABIC-INDIC DIGIT ZERO.\n', + 'strings': u'\nString literals\n***************\n\nString literals are described by the following lexical definitions:\n\n stringliteral ::= [stringprefix](shortstring | longstring)\n stringprefix ::= "r" | "u" | "ur" | "R" | "U" | "UR" | "Ur" | "uR"\n | "b" | "B" | "br" | "Br" | "bR" | "BR"\n shortstring ::= "\'" shortstringitem* "\'" | \'"\' shortstringitem* \'"\'\n longstring ::= "\'\'\'" longstringitem* "\'\'\'"\n | \'"""\' longstringitem* \'"""\'\n shortstringitem ::= shortstringchar | escapeseq\n longstringitem ::= longstringchar | escapeseq\n shortstringchar ::= \n longstringchar ::= \n escapeseq ::= "\\" \n\nOne syntactic restriction not indicated by these productions is that\nwhitespace is not allowed between the "stringprefix" and the rest of\nthe string literal. The source character set is defined by the\nencoding declaration; it is ASCII if no encoding declaration is given\nin the source file; see section *Encoding declarations*.\n\nIn plain English: String literals can be enclosed in matching single\nquotes ("\'") or double quotes ("""). They can also be enclosed in\nmatching groups of three single or double quotes (these are generally\nreferred to as *triple-quoted strings*). The backslash ("\\")\ncharacter is used to escape characters that otherwise have a special\nmeaning, such as newline, backslash itself, or the quote character.\nString literals may optionally be prefixed with a letter "\'r\'" or\n"\'R\'"; such strings are called *raw strings* and use different rules\nfor interpreting backslash escape sequences. A prefix of "\'u\'" or\n"\'U\'" makes the string a Unicode string. Unicode strings use the\nUnicode character set as defined by the Unicode Consortium and ISO\n10646. Some additional escape sequences, described below, are\navailable in Unicode strings. A prefix of "\'b\'" or "\'B\'" is ignored in\nPython 2; it indicates that the literal should become a bytes literal\nin Python 3 (e.g. when code is automatically converted with 2to3). A\n"\'u\'" or "\'b\'" prefix may be followed by an "\'r\'" prefix.\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" | 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| "\\N{name}" | Character named *name* in the | |\n| | Unicode database (Unicode only) | |\n+-------------------+-----------------------------------+---------+\n| "\\r" | ASCII Carriage Return (CR) | |\n+-------------------+-----------------------------------+---------+\n| "\\t" | ASCII Horizontal Tab (TAB) | |\n+-------------------+-----------------------------------+---------+\n| "\\uxxxx" | Character with 16-bit hex value | (1) |\n| | *xxxx* (Unicode only) | |\n+-------------------+-----------------------------------+---------+\n| "\\Uxxxxxxxx" | Character with 32-bit hex value | (2) |\n| | *xxxxxxxx* (Unicode only) | |\n+-------------------+-----------------------------------+---------+\n| "\\v" | ASCII Vertical Tab (VT) | |\n+-------------------+-----------------------------------+---------+\n| "\\ooo" | Character with octal value *ooo* | (3,5) |\n+-------------------+-----------------------------------+---------+\n| "\\xhh" | Character with hex value *hh* | (4,5) |\n+-------------------+-----------------------------------+---------+\n\nNotes:\n\n1. Individual code units which form parts of a surrogate pair can\n be encoded using this escape sequence.\n\n2. Any Unicode character can be encoded this way, but characters\n outside the Basic Multilingual Plane (BMP) will be encoded using a\n surrogate pair if Python is compiled to use 16-bit code units (the\n default).\n\n3. As in Standard C, up to three octal digits are accepted.\n\n4. Unlike in Standard C, exactly two hex digits are required.\n\n5. In a string literal, hexadecimal and octal escapes denote the\n byte with the given value; it is not necessary that the byte\n encodes a character in the source character set. In a Unicode\n literal, these escapes denote a Unicode character with the given\n value.\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 marked as "(Unicode only)"\nin the table above fall into the category of unrecognized escapes for\nnon-Unicode string literals.\n\nWhen an "\'r\'" or "\'R\'" prefix is present, a character following a\nbackslash is included in the string without change, and *all\nbackslashes are left in the string*. For example, the string literal\n"r"\\n"" consists of two characters: a backslash and a lowercase "\'n\'".\nString quotes can be escaped with a backslash, but the backslash\nremains in the string; for example, "r"\\""" is a valid string literal\nconsisting of two characters: a backslash and a double quote; "r"\\""\nis not a valid string literal (even a raw string cannot end in an odd\nnumber of backslashes). Specifically, *a raw string cannot end in a\nsingle backslash* (since the backslash would escape the following\nquote character). Note also that a single backslash followed by a\nnewline is interpreted as those two characters as part of the string,\n*not* as a line continuation.\n\nWhen an "\'r\'" or "\'R\'" prefix is used in conjunction with a "\'u\'" or\n"\'U\'" prefix, then the "\\uXXXX" and "\\UXXXXXXXX" escape sequences are\nprocessed while *all other backslashes are left in the string*. For\nexample, the string literal "ur"\\u0062\\n"" consists of three Unicode\ncharacters: \'LATIN SMALL LETTER B\', \'REVERSE SOLIDUS\', and \'LATIN\nSMALL LETTER N\'. Backslashes can be escaped with a preceding\nbackslash; however, both remain in the string. As a result, "\\uXXXX"\nescape sequences are only recognized when there are an odd number of\nbackslashes.\n', + 'subscriptions': u'\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 of a sequence or mapping type.\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 a\nplain integer. If this value is negative, the length of the sequence\nis added to it (so that, e.g., "x[-1]" selects the last item of "x".)\nThe resulting value must be a nonnegative integer less than the number\nof items in the sequence, and the subscription selects the item whose\nindex is that value (counting from zero).\n\nA string\'s items are characters. A character is not a separate data\ntype but a string of exactly one character.\n', + 'truth': u'\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", "0L", "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 "__nonzero__()" 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': u'\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" | ",") identifier]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nChanged in version 2.5: In previous versions of Python,\n"try"..."except"..."finally" did not work. "try"..."except" had to be\nnested in "try"..."finally".\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 in that except clause, if present, and the except\nclause\'s suite is executed. All except clauses must have an\nexecutable block. When the end of this block is reached, execution\ncontinues normally after the entire try statement. (This means that\nif two nested handlers exist for the same exception, and the exception\noccurs in the try clause of the inner handler, the outer handler will\nnot handle the exception.)\n\nBefore an except clause\'s suite is executed, details about the\nexception are assigned to three variables in the "sys" module:\n"sys.exc_type" receives the object identifying the exception;\n"sys.exc_value" receives the exception\'s parameter;\n"sys.exc_traceback" receives a traceback object (see section *The\nstandard type hierarchy*) identifying the point in the program where\nthe exception occurred. These details are also available through the\n"sys.exc_info()" function, which returns a tuple "(exc_type,\nexc_value, exc_traceback)". Use of the corresponding variables is\ndeprecated in favor of this function, since their use is unsafe in a\nthreaded program. As of Python 1.5, the variables are restored to\ntheir previous values (before the call) when returning from a function\nthat handled an exception.\n\nThe optional "else" clause is executed if and when control flows off\nthe end of the "try" clause. [2] Exceptions in the "else" clause 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\n"finally" clause. If the "finally" clause raises another exception or\nexecutes a "return" or "break" statement, the saved exception is\ndiscarded:\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\nThe return value of a function is determined by the last "return"\nstatement executed. Since the "finally" clause always executes, a\n"return" statement executed in the "finally" clause will always be the\nlast one executed:\n\n >>> def foo():\n ... try:\n ... return \'try\'\n ... finally:\n ... return \'finally\'\n ...\n >>> foo()\n \'finally\'\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': u'\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.).\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 built-in name\n "Ellipsis". It is used to indicate the presence of the "..." syntax\n in a slice. 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 three types of integers:\n\n Plain integers\n These represent numbers in the range -2147483648 through\n 2147483647. (The range may be larger on machines with a\n larger natural word size, but not smaller.) When the result\n of an operation would fall outside this range, the result is\n normally returned as a long integer (in some cases, the\n exception "OverflowError" is raised instead). For the\n purpose of shift and mask operations, integers are assumed to\n have a binary, 2\'s complement notation using 32 or more bits,\n and hiding no bits from the user (i.e., all 4294967296\n different bit patterns correspond to different values).\n\n Long integers\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\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 plain\n integers, 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 and the least surprises when\n switching between the plain and long integer domains. Any\n operation, if it yields a result in the plain integer domain,\n will yield the same result in the long integer domain or when\n using mixed operands. The switch between domains is transparent\n to the programmer.\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 are\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"\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 The items of a string are characters. There is no separate\n character type; a character is represented by a string of one\n item. Characters represent (at least) 8-bit bytes. The\n built-in functions "chr()" and "ord()" convert between\n characters and nonnegative integers representing the byte\n values. Bytes with the values 0-127 usually represent the\n corresponding ASCII values, but the interpretation of values\n is up to the program. The string data type is also used to\n represent arrays of bytes, e.g., to hold data read from a\n file.\n\n (On systems whose native character set is not ASCII, strings\n may use EBCDIC in their internal representation, provided the\n functions "chr()" and "ord()" implement a mapping between\n ASCII and EBCDIC, and string comparison preserves the ASCII\n order. Or perhaps someone can propose a better rule?)\n\n Unicode\n The items of a Unicode object are Unicode code units. A\n Unicode code unit is represented by a Unicode object of one\n item and can hold either a 16-bit or 32-bit value\n representing a Unicode ordinal (the maximum value for the\n ordinal is given in "sys.maxunicode", and depends on how\n Python is configured at compile time). Surrogate pairs may\n be present in the Unicode object, and will be reported as two\n separate items. The built-in functions "unichr()" and\n "ord()" convert between code units and nonnegative integers\n representing the Unicode ordinals as defined in the Unicode\n Standard 3.0. Conversion from and to other encodings are\n possible through the Unicode method "encode()" and the built-\n in function "unicode()".\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 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.\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", "gdbm", and "bsddb" provide\n additional examples of mapping types.\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__" "func_doc" | The function\'s documentation | Writable |\n | | string, or "None" if | |\n | | unavailable. | |\n +-------------------------+---------------------------------+-------------+\n | "__name__" "func_name" | The function\'s name. | Writable |\n +-------------------------+---------------------------------+-------------+\n | "__module__" | The name of the module the | Writable |\n | | function was defined in, or | |\n | | "None" if unavailable. | |\n +-------------------------+---------------------------------+-------------+\n | "__defaults__" | A tuple containing default | Writable |\n | "func_defaults" | argument values for those | |\n | | arguments that have defaults, | |\n | | or "None" if no arguments have | |\n | | a default value. | |\n +-------------------------+---------------------------------+-------------+\n | "__code__" "func_code" | The code object representing | Writable |\n | | the compiled function body. | |\n +-------------------------+---------------------------------+-------------+\n | "__globals__" | A reference to the dictionary | Read-only |\n | "func_globals" | 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__" "func_dict" | The namespace supporting | Writable |\n | | arbitrary function attributes. | |\n +-------------------------+---------------------------------+-------------+\n | "__closure__" | "None" or a tuple of cells that | Read-only |\n | "func_closure" | contain bindings for the | |\n | | function\'s free variables. | |\n +-------------------------+---------------------------------+-------------+\n\n Most of the attributes labelled "Writable" check the type of the\n assigned value.\n\n Changed in version 2.4: "func_name" is now writable.\n\n Changed in version 2.6: The double-underscore attributes\n "__closure__", "__code__", "__defaults__", and "__globals__"\n were introduced as aliases for the corresponding "func_*"\n attributes for forwards compatibility with Python 3.\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 User-defined methods\n A user-defined method object combines a class, a class instance\n (or "None") and any callable object (normally a user-defined\n function).\n\n Special read-only attributes: "im_self" is the class instance\n object, "im_func" is the function object; "im_class" is the\n class of "im_self" for bound methods or the class that asked for\n the method for unbound methods; "__doc__" is the method\'s\n documentation (same as "im_func.__doc__"); "__name__" is the\n method name (same as "im_func.__name__"); "__module__" is the\n name of the module the method was defined in, or "None" if\n unavailable.\n\n Changed in version 2.2: "im_self" used to refer to the class\n that defined the method.\n\n Changed in version 2.6: For Python 3 forward-compatibility,\n "im_func" is also available as "__func__", and "im_self" as\n "__self__".\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, an unbound\n user-defined method object, or a class method object. When the\n attribute is a user-defined method object, a new method object\n is only created if the class from which it is being retrieved is\n the same as, or a derived class of, the class stored in the\n original method object; otherwise, the original method object is\n used as it is.\n\n When a user-defined method object is created by retrieving a\n user-defined function object from a class, its "im_self"\n attribute is "None" and the method object is said to be unbound.\n When one is created by retrieving a user-defined function object\n from a class via one of its instances, its "im_self" attribute\n is the instance, and the method object is said to be bound. In\n either case, the new method\'s "im_class" attribute is the class\n from which the retrieval takes place, and its "im_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 "im_func"\n attribute of the new instance is not the original method object\n but its "im_func" attribute.\n\n When a user-defined method object is created by retrieving a\n class method object from a class or instance, its "im_self"\n attribute is the class itself, and its "im_func" attribute is\n the function object underlying the class method.\n\n When an unbound user-defined method object is called, the\n underlying function ("im_func") is called, with the restriction\n that the first argument must be an instance of the proper class\n ("im_class") or of a derived class thereof.\n\n When a bound user-defined method object is called, the\n underlying function ("im_func") is called, inserting the class\n instance ("im_self") in front of the argument list. For\n instance, when "C" is a class which contains a definition for a\n function "f()", and "x" is an instance of "C", calling "x.f(1)"\n is equivalent to calling "C.f(x, 1)".\n\n When a user-defined method object is derived from a class method\n object, the "class instance" stored in "im_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 (unbound or\n bound) method object happens each time the attribute is\n retrieved from the class or instance. In some cases, a fruitful\n optimization is to assign the attribute to a local variable and\n call that local variable. Also notice that this transformation\n only happens for user-defined functions; other callable objects\n (and all non-callable objects) are retrieved without\n transformation. It is also important to note that user-defined\n functions which are attributes of a class instance are not\n converted to bound methods; this *only* happens when the\n function is an attribute of the class.\n\n Generator functions\n A function or method which uses the "yield" statement (see\n section *The yield statement*) is called a *generator function*.\n Such a function, when called, always returns an iterator object\n which can be used to execute the body of the function: calling\n the iterator\'s "next()" method will cause the function to\n execute until it provides a value using the "yield" statement.\n When the function executes a "return" statement or falls off the\n end, a "StopIteration" exception is raised and the iterator will\n have reached the end of the set of 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 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 Class Types\n Class types, or "new-style classes," are callable. These\n objects normally act as factories for new instances of\n themselves, but variations are possible for class types that\n override "__new__()". The arguments of the call are passed to\n "__new__()" and, in the typical case, to "__init__()" to\n initialize the new instance.\n\n Classic Classes\n Class objects are described below. When a class object is\n called, a new class instance (also described below) is created\n and returned. This implies a call to the class\'s "__init__()"\n method if it has one. Any arguments are passed on to the\n "__init__()" method. If there is no "__init__()" method, the\n class must be called without arguments.\n\n Class instances\n Class instances are described below. Class instances are\n callable only when the class has a "__call__()" method;\n "x(arguments)" is a shorthand for "x.__call__(arguments)".\n\nModules\n Modules are imported by the "import" statement (see section *The\n import statement*). A module object has a namespace implemented by\n a dictionary object (this is the dictionary referenced by the\n func_globals attribute of functions defined in the module).\n Attribute references are translated to lookups in this dictionary,\n e.g., "m.x" is equivalent to "m.__dict__["x"]". A module object\n does not contain the code object used to initialize the module\n (since it isn\'t needed once the initialization is done).\n\n Attribute assignment updates the module\'s namespace dictionary,\n e.g., "m.x = 1" is equivalent to "m.__dict__["x"] = 1".\n\n Special read-only attribute: "__dict__" is the module\'s namespace\n as a dictionary object.\n\n **CPython implementation detail:** Because of the way CPython\n clears module dictionaries, the module dictionary will be cleared\n when the module falls out of scope even if the dictionary still has\n live references. To avoid this, copy the dictionary or keep the\n module around while using its dictionary directly.\n\n Predefined (writable) attributes: "__name__" is the module\'s 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 is not present for C modules that are statically linked\n into the interpreter; for extension modules loaded dynamically from\n a shared library, it is the pathname of the shared library file.\n\nClasses\n Both class types (new-style classes) and class objects (old-\n style/classic classes) are typically created by class definitions\n (see section *Class definitions*). A class has a namespace\n implemented by a dictionary object. Class attribute references are\n translated to lookups in this dictionary, e.g., "C.x" is translated\n to "C.__dict__["x"]" (although for new-style classes in particular\n there are a number of hooks which allow for other means of locating\n attributes). When the attribute name is not found there, the\n attribute search continues in the base classes. For old-style\n classes, the search is depth-first, left-to-right in the order of\n occurrence in the base class list. New-style classes use the more\n complex C3 method resolution order which behaves correctly even in\n the presence of \'diamond\' inheritance structures where there are\n multiple inheritance paths leading back to a common ancestor.\n Additional details on the C3 MRO used by new-style classes can be\n found in the documentation accompanying the 2.3 release at\n https://www.python.org/download/releases/2.3/mro/.\n\n When a class attribute reference (for class "C", say) would yield a\n user-defined function object or an unbound user-defined method\n object whose associated class is either "C" or one of its base\n classes, it is transformed into an unbound user-defined method\n object whose "im_class" attribute is "C". When it would yield a\n class method object, it is transformed into a bound user-defined\n method object whose "im_self" attribute is "C". When it would\n yield a static method object, it is transformed into the object\n wrapped by the static method object. See section *Implementing\n Descriptors* for another way in which attributes retrieved from a\n class may differ from those actually contained in its "__dict__"\n (note that only new-style classes support descriptors).\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 or an unbound user-defined method object whose\n associated class is the class (call it "C") of the instance for\n which the attribute reference was initiated or one of its bases, it\n is transformed into a bound user-defined method object whose\n "im_class" attribute is "C" and whose "im_self" attribute is the\n instance. Static method and class method objects are also\n transformed, as if they had been retrieved from class "C"; see\n above under "Classes". See section *Implementing Descriptors* for\n another way in which attributes of a class retrieved via its\n instances may differ from the objects actually stored in the\n class\'s "__dict__". If no class attribute is found, and the\n object\'s class has a "__getattr__()" method, that is called to\n 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\nFiles\n A file object represents an open file. File objects are created by\n the "open()" built-in function, and also by "os.popen()",\n "os.fdopen()", and the "makefile()" method of socket objects (and\n perhaps by other functions or methods provided by extension\n modules). The objects "sys.stdin", "sys.stdout" and "sys.stderr"\n are initialized to file objects corresponding to the interpreter\'s\n standard input, output and error streams. See *File Objects* for\n complete documentation of file objects.\n\nInternal types\n A few types used internally by the interpreter are exposed to the\n user. Their definitions may change with future versions of the\n interpreter, but they are mentioned here for completeness.\n\n Code objects\n Code objects represent *byte-compiled* executable Python code,\n or *bytecode*. The difference between a code object and a\n function object is that the function object contains an explicit\n reference to the function\'s globals (the module in which it was\n defined), while a code object contains no context; also the\n default argument values are stored in the function object, not\n in the code object (because they represent values calculated at\n run-time). Unlike function objects, code objects are immutable\n and contain no references (directly or indirectly) to mutable\n objects.\n\n Special read-only attributes: "co_name" gives the function 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;\n "f_restricted" is a flag indicating whether the function is\n executing in restricted execution mode; "f_lasti" gives the\n precise instruction (this is an index into the bytecode string\n 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_exc_type", "f_exc_value",\n "f_exc_traceback" represent the last exception raised in the\n parent frame provided another exception was ever raised in the\n current frame (in all other cases they are None); "f_lineno" is\n the current line number of the frame --- writing to this from\n within a trace function jumps to the given line (only for the\n bottom-most frame). A debugger can implement a Jump command\n (aka Set Next Statement) by writing to f_lineno.\n\n Traceback objects\n Traceback objects represent a stack trace of an exception. A\n traceback object is created when an exception occurs. When the\n search for an exception handler unwinds the execution stack, at\n each unwound level a traceback object is inserted in front of\n the current traceback. When an exception handler is entered,\n the stack trace is made available to the program. (See section\n *The try statement*.) It is accessible as "sys.exc_traceback",\n and also as the third item of the tuple returned by\n "sys.exc_info()". The latter is the preferred interface, since\n it works correctly when the program is using multiple threads.\n When the program contains no suitable handler, the stack trace\n is written (nicely formatted) to the standard error stream; if\n the interpreter is interactive, it is also made available to the\n 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 when *extended slice\n syntax* is used. This is a slice using two colons, or multiple\n slices or ellipses separated by commas, e.g., "a[i:j:step]",\n "a[i:j, k:l]", or "a[..., i:j]". They are also created by the\n built-in "slice()" 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 extended slice that the slice\n object would describe if applied to a sequence of *length*\n items. It returns a tuple of three integers; respectively\n these are the *start* and *stop* indices and the *step* or\n stride length of the slice. Missing or out-of-bounds indices\n are handled in a manner consistent with regular slices.\n\n New in version 2.3.\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': u'\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': u'\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 *iterable*\n object. Each item in the iterable must itself be an iterable 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 New in version 2.2.\n\n Changed in version 2.3: Support for building a dictionary from\n keyword arguments added.\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 New in version 2.5: If a subclass of dict defines a method\n "__missing__()", if the key *key* is not present, the "d[key]"\n operation calls that method with the key *key* as argument. The\n "d[key]" operation then returns or raises whatever is returned\n or raised by the "__missing__(key)" call if the key is not\n present. No other operations or methods invoke "__missing__()".\n If "__missing__()" is not defined, "KeyError" is raised.\n "__missing__()" must be a method; it cannot be an instance\n variable. For an example, see "collections.defaultdict".\n\n d[key] = value\n\n Set "d[key]" to *value*.\n\n del d[key]\n\n Remove "d[key]" from *d*. Raises a "KeyError" if *key* is not\n in the map.\n\n key in d\n\n Return "True" if *d* has a key *key*, else "False".\n\n New in version 2.2.\n\n key not in d\n\n Equivalent to "not key in d".\n\n New in version 2.2.\n\n iter(d)\n\n Return an iterator over the keys of the dictionary. This is a\n shortcut for "iterkeys()".\n\n clear()\n\n Remove all items from the dictionary.\n\n copy()\n\n Return a shallow copy of the dictionary.\n\n 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 New in version 2.3.\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 has_key(key)\n\n Test for the presence of *key* in the dictionary. "has_key()"\n is deprecated in favor of "key in d".\n\n items()\n\n Return a copy of the dictionary\'s list of "(key, value)" pairs.\n\n **CPython implementation detail:** Keys and values are listed in\n an arbitrary order which is non-random, varies across Python\n implementations, and depends on the dictionary\'s history of\n insertions and deletions.\n\n If "items()", "keys()", "values()", "iteritems()", "iterkeys()",\n and "itervalues()" are called with no intervening modifications\n to the dictionary, the lists will directly correspond. This\n allows the creation of "(value, key)" pairs using "zip()":\n "pairs = zip(d.values(), d.keys())". The same relationship\n holds for the "iterkeys()" and "itervalues()" methods: "pairs =\n zip(d.itervalues(), d.iterkeys())" provides the same value for\n "pairs". Another way to create the same list is "pairs = [(v, k)\n for (k, v) in d.iteritems()]".\n\n iteritems()\n\n Return an iterator over the dictionary\'s "(key, value)" pairs.\n See the note for "dict.items()".\n\n Using "iteritems()" while adding or deleting entries in the\n dictionary may raise a "RuntimeError" or fail to iterate over\n all entries.\n\n New in version 2.2.\n\n iterkeys()\n\n Return an iterator over the dictionary\'s keys. See the note for\n "dict.items()".\n\n Using "iterkeys()" while adding or deleting entries in the\n dictionary may raise a "RuntimeError" or fail to iterate over\n all entries.\n\n New in version 2.2.\n\n itervalues()\n\n Return an iterator over the dictionary\'s values. See the note\n for "dict.items()".\n\n Using "itervalues()" while adding or deleting entries in the\n dictionary may raise a "RuntimeError" or fail to iterate over\n all entries.\n\n New in version 2.2.\n\n keys()\n\n Return a copy of the dictionary\'s list of keys. See the note\n for "dict.items()".\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 New in version 2.3.\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 Changed in version 2.4: Allowed the argument to be an iterable\n of key/value pairs and allowed keyword arguments.\n\n values()\n\n Return a copy of the dictionary\'s list of values. See the note\n for "dict.items()".\n\n viewitems()\n\n Return a new view of the dictionary\'s items ("(key, value)"\n pairs). See below for documentation of view objects.\n\n New in version 2.7.\n\n viewkeys()\n\n Return a new view of the dictionary\'s keys. See below for\n documentation of view objects.\n\n New in version 2.7.\n\n viewvalues()\n\n Return a new view of the dictionary\'s values. See below for\n documentation of view objects.\n\n New in version 2.7.\n\n\nDictionary view objects\n=======================\n\nThe objects returned by "dict.viewkeys()", "dict.viewvalues()" and\n"dict.viewitems()" 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 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 and\nhashable, then the items view is also set-like. (Values views are not\ntreated as set-like since the entries are generally not unique.) Then\nthese set operations are available ("other" refers either to another\nview or a set):\n\ndictview & other\n\n Return the intersection of the dictview and the other object as a\n new set.\n\ndictview | other\n\n Return the union of the dictview and the other object as a new set.\n\ndictview - other\n\n Return the difference between the dictview and the other object\n (all elements in *dictview* that aren\'t in *other*) as a new set.\n\ndictview ^ other\n\n Return the symmetric difference (all elements either in *dictview*\n or *other*, but not in both) of the dictview and the other object\n as a new set.\n\nAn example of dictionary view usage:\n\n >>> dishes = {\'eggs\': 2, \'sausage\': 1, \'bacon\': 1, \'spam\': 500}\n >>> keys = dishes.viewkeys()\n >>> values = dishes.viewvalues()\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', + 'typesmethods': u'\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\nThe implementation adds two special read-only attributes to class\ninstance methods: "m.im_self" is the object on which the method\noperates, and "m.im_func" is the function implementing the method.\nCalling "m(arg-1, arg-2, ..., arg-n)" is completely equivalent to\ncalling "m.im_func(m.im_self, arg-1, arg-2, ..., arg-n)".\n\nClass instance methods are either *bound* or *unbound*, referring to\nwhether the method was accessed through an instance or a class,\nrespectively. When a method is unbound, its "im_self" attribute will\nbe "None" and if called, an explicit "self" object must be passed as\nthe first argument. In this case, "self" must be an instance of the\nunbound method\'s class (or a subclass of that class), otherwise a\n"TypeError" is raised.\n\nLike function objects, methods objects support getting arbitrary\nattributes. However, since method attributes are actually stored on\nthe underlying function object ("meth.im_func"), setting method\nattributes on either bound or unbound methods is disallowed.\nAttempting to set an attribute on a method results in an\n"AttributeError" being raised. In order to set a method attribute,\nyou need to explicitly set it on the 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: \'instancemethod\' object has no attribute \'whoami\'\n >>> c.method.im_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': u'\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': u'\nSequence Types --- "str", "unicode", "list", "tuple", "bytearray", "buffer", "xrange"\n*************************************************************************************\n\nThere are seven sequence types: strings, Unicode strings, lists,\ntuples, bytearrays, buffers, and xrange objects.\n\nFor other containers see the built in "dict" and "set" classes, and\nthe "collections" module.\n\nString literals are written in single or double quotes: "\'xyzzy\'",\n""frobozz"". See *String literals* for more about string literals.\nUnicode strings are much like strings, but are specified in the syntax\nusing a preceding "\'u\'" character: "u\'abc\'", "u"def"". In addition to\nthe functionality described here, there are also string-specific\nmethods described in the *String Methods* section. Lists are\nconstructed with square brackets, separating items with commas: "[a,\nb, c]". Tuples are constructed by the comma operator (not within\nsquare brackets), with or without enclosing parentheses, but an empty\ntuple must have the enclosing parentheses, such as "a, b, c" or "()".\nA single item tuple must have a trailing comma, such as "(d,)".\n\nBytearray objects are created with the built-in function\n"bytearray()".\n\nBuffer objects are not directly supported by Python syntax, but can be\ncreated by calling the built-in function "buffer()". They don\'t\nsupport concatenation or repetition.\n\nObjects of type xrange are similar to buffers in that there is no\nspecific syntax to create them, but they are created using the\n"xrange()" function. They don\'t support slicing, concatenation or\nrepetition, and using "in", "not in", "min()" or "max()" on them is\ninefficient.\n\nMost sequence types support the following operations. The "in" and\n"not in" operations have the same priorities as the comparison\noperations. The "+" and "*" operations have the same priority as the\ncorresponding numeric operations. [3] Additional methods are provided\nfor *Mutable Sequence Types*.\n\nThis table lists the sequence operations sorted in ascending priority.\nIn the table, *s* and *t* are sequences of the same type; *n*, *i* and\n*j* are integers:\n\n+--------------------+----------------------------------+------------+\n| Operation | Result | Notes |\n+====================+==================================+============+\n| "x in s" | "True" if an item of *s* is | (1) |\n| | equal to *x*, else "False" | |\n+--------------------+----------------------------------+------------+\n| "x not in s" | "False" if an item of *s* is | (1) |\n| | equal to *x*, else "True" | |\n+--------------------+----------------------------------+------------+\n| "s + t" | the concatenation of *s* and *t* | (6) |\n+--------------------+----------------------------------+------------+\n| "s * n, n * s" | *n* shallow copies of *s* | (2) |\n| | concatenated | |\n+--------------------+----------------------------------+------------+\n| "s[i]" | *i*th item of *s*, origin 0 | (3) |\n+--------------------+----------------------------------+------------+\n| "s[i:j]" | slice of *s* from *i* to *j* | (3)(4) |\n+--------------------+----------------------------------+------------+\n| "s[i:j:k]" | slice of *s* from *i* to *j* | (3)(5) |\n| | with step *k* | |\n+--------------------+----------------------------------+------------+\n| "len(s)" | length of *s* | |\n+--------------------+----------------------------------+------------+\n| "min(s)" | smallest item of *s* | |\n+--------------------+----------------------------------+------------+\n| "max(s)" | largest item of *s* | |\n+--------------------+----------------------------------+------------+\n| "s.index(x)" | index of the first occurrence of | |\n| | *x* in *s* | |\n+--------------------+----------------------------------+------------+\n| "s.count(x)" | total number of occurrences of | |\n| | *x* in *s* | |\n+--------------------+----------------------------------+------------+\n\nSequence types also support comparisons. In particular, tuples and\nlists are compared lexicographically by comparing corresponding\nelements. This means that to compare equal, every element must compare\nequal and the two sequences must be of the same type and have the same\nlength. (For full details see *Comparisons* in the language\nreference.)\n\nNotes:\n\n1. When *s* is a string or Unicode string object the "in" and "not\n in" operations act like a substring test. In Python versions\n before 2.3, *x* had to be a string of length 1. In Python 2.3 and\n beyond, *x* may be a string of any length.\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. **CPython implementation detail:** If *s* and *t* are both\n strings, some Python implementations such as CPython can usually\n perform an in-place optimization for assignments of the form "s = s\n + t" or "s += t". When applicable, this optimization makes\n quadratic run-time much less likely. This optimization is both\n version and implementation dependent. For performance sensitive\n code, it is preferable to use the "str.join()" method which assures\n consistent linear concatenation performance across versions and\n implementations.\n\n Changed in version 2.4: Formerly, string concatenation never\n occurred in-place.\n\n\nString Methods\n==============\n\nBelow are listed the string methods which both 8-bit strings and\nUnicode objects support. Some of them are also available on\n"bytearray" objects.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, unicode, list, tuple,\nbytearray, buffer, xrange* section. To output formatted strings use\ntemplate strings or the "%" operator described in the *String\nFormatting Operations* section. Also, see the "re" module for string\nfunctions based on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\n For 8-bit strings, this method is locale-dependent.\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\n Changed in version 2.4: Support for the *fillchar* argument.\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.decode([encoding[, errors]])\n\n Decodes the string using the codec registered for *encoding*.\n *encoding* defaults to the default string encoding. *errors* may\n be given to set a different error handling scheme. The default is\n "\'strict\'", meaning that encoding errors raise "UnicodeError".\n Other possible values are "\'ignore\'", "\'replace\'" and any other\n name registered via "codecs.register_error()", see section *Codec\n Base Classes*.\n\n New in version 2.2.\n\n Changed in version 2.3: Support for other error handling schemes\n added.\n\n Changed in version 2.7: Support for keyword arguments added.\n\nstr.encode([encoding[, errors]])\n\n Return an encoded version of the string. Default encoding is the\n current default string encoding. *errors* may be given to set a\n different error handling scheme. The default for *errors* is\n "\'strict\'", meaning that encoding errors raise a "UnicodeError".\n Other 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 New in version 2.0.\n\n Changed in version 2.3: Support for "\'xmlcharrefreplace\'" and\n "\'backslashreplace\'" and other error handling schemes added.\n\n Changed in version 2.7: 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\n Changed in version 2.5: Accept tuples as *suffix*.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. 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\n This method of string formatting is the new standard in Python 3,\n and should be preferred to the "%" formatting described in *String\n Formatting Operations* in new code.\n\n New in version 2.6.\n\nstr.index(sub[, start[, end]])\n\n Like "find()", but raise "ValueError" when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise.\n\n For 8-bit strings, this method is locale-dependent.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise.\n\n For 8-bit strings, this method is locale-dependent.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise.\n\n For 8-bit strings, this method is locale-dependent.\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\n For 8-bit strings, this method is locale-dependent.\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise.\n\n For 8-bit strings, this method is locale-dependent.\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\n For 8-bit strings, this method is locale-dependent.\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\n For 8-bit strings, this method is locale-dependent.\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. The separator between elements is the\n 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\n Changed in version 2.4: Support for the *fillchar* argument.\n\nstr.lower()\n\n Return a copy of the string with all the cased characters [4]\n converted to lowercase.\n\n For 8-bit strings, this method is locale-dependent.\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\n Changed in version 2.2.2: Support for the *chars* argument.\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\n New in version 2.5.\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\n Changed in version 2.4: Support for the *fillchar* argument.\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\n New in version 2.5.\n\nstr.rsplit([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n "None", any whitespace string is a separator. Except for splitting\n from the right, "rsplit()" behaves like "split()" which is\n described in detail below.\n\n New in version 2.4.\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\n Changed in version 2.2.2: Support for the *chars* argument.\n\nstr.split([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most "maxsplit+1"\n elements). If *maxsplit* is not specified 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\n Changed in version 2.5: Accept tuples as *prefix*.\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\n Changed in version 2.2.2: Support for the *chars* argument.\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa.\n\n For 8-bit strings, this method is locale-dependent.\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\n For 8-bit strings, this method is locale-dependent.\n\nstr.translate(table[, deletechars])\n\n Return a copy of the string where all characters occurring in the\n optional argument *deletechars* are removed, and the remaining\n characters have been mapped through the given translation table,\n which must be a string of length 256.\n\n You can use the "maketrans()" helper function in the "string"\n module to create a translation table. For string objects, set the\n *table* argument to "None" for translations that only delete\n characters:\n\n >>> \'read this short text\'.translate(None, \'aeiou\')\n \'rd ths shrt txt\'\n\n New in version 2.6: Support for a "None" *table* argument.\n\n For Unicode objects, the "translate()" method does not accept the\n optional *deletechars* argument. Instead, it returns a copy of the\n *s* where all characters have been mapped through the given\n translation table which must be a mapping of Unicode ordinals to\n Unicode ordinals, Unicode strings or "None". Unmapped characters\n are left untouched. Characters mapped to "None" are deleted. Note,\n a more flexible approach is to create a custom character mapping\n codec using the "codecs" module (see "encodings.cp1251" for an\n 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 For 8-bit strings, this method is locale-dependent.\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\n New in version 2.2.2.\n\nThe following methods are present only on unicode objects:\n\nunicode.isnumeric()\n\n Return "True" if there are only numeric characters in S, "False"\n otherwise. Numeric characters include digit characters, and all\n characters that have the Unicode numeric value property, e.g.\n U+2155, VULGAR FRACTION ONE FIFTH.\n\nunicode.isdecimal()\n\n Return "True" if there are only decimal characters in S, "False"\n otherwise. Decimal characters include digit characters, and all\n characters that can be used to form decimal-radix numbers, e.g.\n U+0660, ARABIC-INDIC DIGIT ZERO.\n\n\nString Formatting Operations\n============================\n\nString and Unicode objects have one unique built-in operation: the "%"\noperator (modulo). This is also known as the string *formatting* or\n*interpolation* operator. Given "format % values" (where *format* is\na string or Unicode object), "%" conversion specifications in *format*\nare replaced with zero or more elements of *values*. The effect is\nsimilar to the using "sprintf()" in the C language. If *format* is a\nUnicode object, or if any of the objects being converted using the\n"%s" conversion are Unicode objects, the result will also be a Unicode\nobject.\n\nIf *format* requires a single argument, *values* may be a single non-\ntuple object. [5] Otherwise, *values* must be a tuple with exactly\nthe number of items specified by the format string, or a single\nmapping object (for example, a dictionary).\n\nA conversion specifier contains two or more characters and has the\nfollowing components, which must occur in this order:\n\n1. The "\'%\'" character, which marks the start of the specifier.\n\n2. Mapping key (optional), consisting of a parenthesised sequence\n of characters (for example, "(somename)").\n\n3. Conversion flags (optional), which affect the result of some\n conversion types.\n\n4. Minimum field width (optional). If specified as an "\'*\'"\n (asterisk), the actual width is read from the next element of the\n tuple in *values*, and the object to convert comes after the\n minimum field width and optional precision.\n\n5. Precision (optional), given as a "\'.\'" (dot) followed by the\n precision. If specified as "\'*\'" (an asterisk), the actual width\n is read from the next element of the tuple in *values*, and the\n value to convert comes after the precision.\n\n6. Length modifier (optional).\n\n7. Conversion type.\n\nWhen the right argument is a dictionary (or other mapping type), then\nthe formats in the string *must* include a parenthesised mapping key\ninto that dictionary inserted immediately after the "\'%\'" character.\nThe mapping key selects the value to be formatted from the mapping.\nFor example:\n\n>>> print \'%(language)s has %(number)03d quote types.\' % \\\n... {"language": "Python", "number": 2}\nPython has 002 quote types.\n\nIn this case no "*" specifiers may occur in a format (since they\nrequire a sequential parameter list).\n\nThe conversion flag characters are:\n\n+-----------+-----------------------------------------------------------------------+\n| Flag | Meaning |\n+===========+=======================================================================+\n| "\'#\'" | The value conversion will use the "alternate form" (where defined |\n| | below). |\n+-----------+-----------------------------------------------------------------------+\n| "\'0\'" | The conversion will be zero padded for numeric values. |\n+-----------+-----------------------------------------------------------------------+\n| "\'-\'" | The converted value is left adjusted (overrides the "\'0\'" conversion |\n| | if both are given). |\n+-----------+-----------------------------------------------------------------------+\n| "\' \'" | (a space) A blank should be left before a positive number (or empty |\n| | string) produced by a signed conversion. |\n+-----------+-----------------------------------------------------------------------+\n| "\'+\'" | A sign character ("\'+\'" or "\'-\'") will precede the conversion |\n| | (overrides a "space" flag). |\n+-----------+-----------------------------------------------------------------------+\n\nA length modifier ("h", "l", or "L") may be present, but is ignored as\nit is not necessary for Python -- so e.g. "%ld" is identical to "%d".\n\nThe conversion types are:\n\n+--------------+-------------------------------------------------------+---------+\n| Conversion | Meaning | Notes |\n+==============+=======================================================+=========+\n| "\'d\'" | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| "\'i\'" | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| "\'o\'" | Signed octal value. | (1) |\n+--------------+-------------------------------------------------------+---------+\n| "\'u\'" | Obsolete type -- it is identical to "\'d\'". | (7) |\n+--------------+-------------------------------------------------------+---------+\n| "\'x\'" | Signed hexadecimal (lowercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| "\'X\'" | Signed hexadecimal (uppercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| "\'e\'" | Floating point exponential format (lowercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| "\'E\'" | Floating point exponential format (uppercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| "\'f\'" | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| "\'F\'" | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| "\'g\'" | Floating point format. Uses lowercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| "\'G\'" | Floating point format. Uses uppercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| "\'c\'" | Single character (accepts integer or single character | |\n| | string). | |\n+--------------+-------------------------------------------------------+---------+\n| "\'r\'" | String (converts any Python object using *repr()*). | (5) |\n+--------------+-------------------------------------------------------+---------+\n| "\'s\'" | String (converts any Python object using "str()"). | (6) |\n+--------------+-------------------------------------------------------+---------+\n| "\'%\'" | No argument is converted, results in a "\'%\'" | |\n| | character in the result. | |\n+--------------+-------------------------------------------------------+---------+\n\nNotes:\n\n1. The alternate form causes a leading zero ("\'0\'") to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n2. The alternate form causes a leading "\'0x\'" or "\'0X\'" (depending\n on whether the "\'x\'" or "\'X\'" format was used) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n3. The alternate form causes the result to always contain a decimal\n point, even if no digits follow it.\n\n The precision determines the number of digits after the decimal\n point and defaults to 6.\n\n4. The alternate form causes the result to always contain a decimal\n point, and trailing zeroes are not removed as they would otherwise\n be.\n\n The precision determines the number of significant digits before\n and after the decimal point and defaults to 6.\n\n5. The "%r" conversion was added in Python 2.0.\n\n The precision determines the maximal number of characters used.\n\n6. If the object or format provided is a "unicode" string, the\n resulting string will also be "unicode".\n\n The precision determines the maximal number of characters used.\n\n7. See **PEP 237**.\n\nSince Python strings have an explicit length, "%s" conversions do not\nassume that "\'\\0\'" is the end of the string.\n\nChanged in version 2.7: "%f" conversions for numbers whose absolute\nvalue is over 1e50 are no longer replaced by "%g" conversions.\n\nAdditional string operations are defined in standard modules "string"\nand "re".\n\n\nXRange Type\n===========\n\nThe "xrange" type is an immutable sequence which is commonly used for\nlooping. The advantage of the "xrange" type is that an "xrange"\nobject will always take the same amount of memory, no matter the size\nof the range it represents. There are no consistent performance\nadvantages.\n\nXRange objects have very little behavior: they only support indexing,\niteration, and the "len()" function.\n\n\nMutable Sequence Types\n======================\n\nList and "bytearray" objects support additional operations that allow\nin-place modification of the object. Other mutable sequence types\n(when added to the language) should also support these operations.\nStrings and tuples are immutable sequence types: such objects cannot\nbe modified once created. The following operations are defined on\nmutable sequence types (where *x* is an arbitrary object):\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| "s[i] = x" | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j] = t" | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "del s[i:j]" | same as "s[i:j] = []" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j:k] = t" | the elements of "s[i:j:k]" are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "del s[i:j:k]" | removes the elements of | |\n| | "s[i:j:k]" from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.append(x)" | same as "s[len(s):len(s)] = [x]" | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.extend(x)" | same as "s[len(s):len(s)] = x" | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.count(x)" | return number of *i*\'s for which | |\n| | "s[i] == x" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.index(x[, i[, j]])" | return smallest *k* such that | (4) |\n| | "s[k] == x" and "i <= k < j" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.insert(i, x)" | same as "s[i:i] = [x]" | (5) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.pop([i])" | same as "x = s[i]; del s[i]; | (6) |\n| | return x" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.remove(x)" | same as "del s[s.index(x)]" | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.reverse()" | reverses the items of *s* in | (7) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.sort([cmp[, key[, | sort the items of *s* in place | (7)(8)(9)(10) |\n| reverse]]])" | | |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. The C implementation of Python has historically accepted\n multiple parameters and implicitly joined them into a tuple; this\n no longer works in Python 2.0. Use of this misfeature has been\n deprecated since Python 1.4.\n\n3. *x* can be any iterable object.\n\n4. Raises "ValueError" when *x* is not found in *s*. When a\n negative index is passed as the second or third parameter to the\n "index()" method, the list length is added, as for slice indices.\n If it is still negative, it is truncated to zero, as for slice\n indices.\n\n Changed in version 2.3: Previously, "index()" didn\'t have arguments\n for specifying start and stop positions.\n\n5. When a negative index is passed as the first parameter to the\n "insert()" method, the list length is added, as for slice indices.\n If it is still negative, it is truncated to zero, as for slice\n indices.\n\n Changed in version 2.3: Previously, all negative indices were\n truncated to zero.\n\n6. The "pop()" method\'s optional argument *i* defaults to "-1", so\n that by default the last item is removed and returned.\n\n7. The "sort()" and "reverse()" methods modify the list in place\n for economy of space when sorting or reversing a large list. To\n remind you that they operate by side effect, they don\'t return the\n sorted or reversed list.\n\n8. The "sort()" method takes optional arguments for controlling the\n comparisons.\n\n *cmp* specifies a custom comparison function of two arguments (list\n items) which should return a negative, zero or positive number\n depending on whether the first argument is considered smaller than,\n equal to, or larger than the second argument: "cmp=lambda x,y:\n cmp(x.lower(), y.lower())". The default value is "None".\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: "key=str.lower". The\n default value is "None".\n\n *reverse* is a boolean value. If set to "True", then the list\n elements are sorted as if each comparison were reversed.\n\n In general, the *key* and *reverse* conversion processes are much\n faster than specifying an equivalent *cmp* function. This is\n because *cmp* is called multiple times for each list element while\n *key* and *reverse* touch each element only once. Use\n "functools.cmp_to_key()" to convert an old-style *cmp* function to\n a *key* function.\n\n Changed in version 2.3: Support for "None" as an equivalent to\n omitting *cmp* was added.\n\n Changed in version 2.4: Support for *key* and *reverse* was added.\n\n9. Starting with Python 2.3, the "sort()" method is guaranteed to\n be stable. A sort is stable if it guarantees not to change the\n relative order of elements that compare equal --- this is helpful\n for sorting in multiple passes (for example, sort by department,\n then by salary grade).\n\n10. **CPython implementation detail:** While a list is being\n sorted, the effect of attempting to mutate, or even inspect, the\n list is undefined. The C implementation of Python 2.3 and newer\n makes the list appear empty for the duration, and raises\n "ValueError" if it can detect that the list has been mutated\n during a sort.\n', + 'typesseq-mutable': u'\nMutable Sequence Types\n**********************\n\nList and "bytearray" objects support additional operations that allow\nin-place modification of the object. Other mutable sequence types\n(when added to the language) should also support these operations.\nStrings and tuples are immutable sequence types: such objects cannot\nbe modified once created. The following operations are defined on\nmutable sequence types (where *x* is an arbitrary object):\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| "s[i] = x" | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j] = t" | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "del s[i:j]" | same as "s[i:j] = []" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s[i:j:k] = t" | the elements of "s[i:j:k]" are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| "del s[i:j:k]" | removes the elements of | |\n| | "s[i:j:k]" from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.append(x)" | same as "s[len(s):len(s)] = [x]" | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.extend(x)" | same as "s[len(s):len(s)] = x" | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.count(x)" | return number of *i*\'s for which | |\n| | "s[i] == x" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.index(x[, i[, j]])" | return smallest *k* such that | (4) |\n| | "s[k] == x" and "i <= k < j" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.insert(i, x)" | same as "s[i:i] = [x]" | (5) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.pop([i])" | same as "x = s[i]; del s[i]; | (6) |\n| | return x" | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.remove(x)" | same as "del s[s.index(x)]" | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.reverse()" | reverses the items of *s* in | (7) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| "s.sort([cmp[, key[, | sort the items of *s* in place | (7)(8)(9)(10) |\n| reverse]]])" | | |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. The C implementation of Python has historically accepted\n multiple parameters and implicitly joined them into a tuple; this\n no longer works in Python 2.0. Use of this misfeature has been\n deprecated since Python 1.4.\n\n3. *x* can be any iterable object.\n\n4. Raises "ValueError" when *x* is not found in *s*. When a\n negative index is passed as the second or third parameter to the\n "index()" method, the list length is added, as for slice indices.\n If it is still negative, it is truncated to zero, as for slice\n indices.\n\n Changed in version 2.3: Previously, "index()" didn\'t have arguments\n for specifying start and stop positions.\n\n5. When a negative index is passed as the first parameter to the\n "insert()" method, the list length is added, as for slice indices.\n If it is still negative, it is truncated to zero, as for slice\n indices.\n\n Changed in version 2.3: Previously, all negative indices were\n truncated to zero.\n\n6. The "pop()" method\'s optional argument *i* defaults to "-1", so\n that by default the last item is removed and returned.\n\n7. The "sort()" and "reverse()" methods modify the list in place\n for economy of space when sorting or reversing a large list. To\n remind you that they operate by side effect, they don\'t return the\n sorted or reversed list.\n\n8. The "sort()" method takes optional arguments for controlling the\n comparisons.\n\n *cmp* specifies a custom comparison function of two arguments (list\n items) which should return a negative, zero or positive number\n depending on whether the first argument is considered smaller than,\n equal to, or larger than the second argument: "cmp=lambda x,y:\n cmp(x.lower(), y.lower())". The default value is "None".\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: "key=str.lower". The\n default value is "None".\n\n *reverse* is a boolean value. If set to "True", then the list\n elements are sorted as if each comparison were reversed.\n\n In general, the *key* and *reverse* conversion processes are much\n faster than specifying an equivalent *cmp* function. This is\n because *cmp* is called multiple times for each list element while\n *key* and *reverse* touch each element only once. Use\n "functools.cmp_to_key()" to convert an old-style *cmp* function to\n a *key* function.\n\n Changed in version 2.3: Support for "None" as an equivalent to\n omitting *cmp* was added.\n\n Changed in version 2.4: Support for *key* and *reverse* was added.\n\n9. Starting with Python 2.3, the "sort()" method is guaranteed to\n be stable. A sort is stable if it guarantees not to change the\n relative order of elements that compare equal --- this is helpful\n for sorting in multiple passes (for example, sort by department,\n then by salary grade).\n\n10. **CPython implementation detail:** While a list is being\n sorted, the effect of attempting to mutate, or even inspect, the\n list is undefined. The C implementation of Python 2.3 and newer\n makes the list appear empty for the duration, and raises\n "ValueError" if it can detect that the list has been mutated\n during a sort.\n', + 'unary': u'\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\nplain or long integer argument. The bitwise inversion of "x" is\ndefined as "-(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': u'\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': u'\nThe "with" statement\n********************\n\nNew in version 2.5.\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\nNote: In Python 2.5, the "with" statement is only allowed when the\n "with_statement" feature has been enabled. It is always enabled in\n Python 2.6.\n\nChanged in version 2.7: 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': u'\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 generator\'s "next()"\nmethod 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\nAs of Python version 2.5, the "yield" statement is now allowed in the\n"try" clause of a "try" ... "finally" construct. If the generator is\nnot resumed before it is finalized (by reaching a zero reference count\nor by being garbage collected), the generator-iterator\'s "close()"\nmethod will be called, allowing any pending "finally" clauses to\nexecute.\n\nFor full details of "yield" semantics, refer to the *Yield\nexpressions* section.\n\nNote: In Python 2.2, the "yield" statement was only allowed when the\n "generators" feature has been enabled. This "__future__" import\n statement was used to enable the feature:\n\n from __future__ import generators\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 that, among other generator enhancements, proposed\n allowing "yield" to appear inside a "try" ... "finally" block.\n'} -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 01:33:19 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 26 Nov 2014 00:33:19 +0000 Subject: [Python-checkins] =?utf-8?q?release=3A_import_readline_otherwise_?= =?utf-8?q?it_doesn=27t_get_initialized_for_input=28=29?= Message-ID: <20141126003310.69803.78502@psf.io> https://hg.python.org/release/rev/070f43581846 changeset: 88:070f43581846 user: Benjamin Peterson date: Tue Nov 25 18:33:01 2014 -0600 summary: import readline otherwise it doesn't get initialized for input() files: release.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/release.py b/release.py --- a/release.py +++ b/release.py @@ -11,6 +11,7 @@ import hashlib import optparse import re +import readline import subprocess import shutil -- Repository URL: https://hg.python.org/release From python-checkins at python.org Wed Nov 26 01:44:10 2014 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 26 Nov 2014 00:44:10 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Move_PEP_458_figures_out_of_s?= =?utf-8?q?ubdirectory=2E?= Message-ID: <20141126004403.69781.78689@psf.io> https://hg.python.org/peps/rev/43b268607d6e changeset: 5617:43b268607d6e user: Guido van Rossum date: Tue Nov 25 16:43:59 2014 -0800 summary: Move PEP 458 figures out of subdirectory. files: pep-0458/figure1.png | 0 pep-0458/figure2.png | 0 pep-0458/figure3.png | 0 pep-0458.txt | 6 +++--- 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pep-0458/figure1.png b/pep-0458-1.png rename from pep-0458/figure1.png rename to pep-0458-1.png diff --git a/pep-0458/figure2.png b/pep-0458-2.png rename from pep-0458/figure2.png rename to pep-0458-2.png diff --git a/pep-0458/figure3.png b/pep-0458-3.png rename from pep-0458/figure3.png rename to pep-0458-3.png diff --git a/pep-0458.txt b/pep-0458.txt --- a/pep-0458.txt +++ b/pep-0458.txt @@ -300,7 +300,7 @@ responsibilities without exception. Figure 1 provides a table of the roles used in TUF. -.. image:: pep-0458/figure1.png +.. image:: pep-0458-1.png Figure 1: An overview of the TUF roles. @@ -320,7 +320,7 @@ trusted to sign for files available on PyPI. The next two sections cover the details of signing repository files and the types of keys used for each role. -.. image:: pep-0458/figure2.png +.. image:: pep-0458-2.png Figure 2: An overview of the role metadata available on PyPI. @@ -957,7 +957,7 @@ packages in the minimum security model, but not in the maximum model without also compromising a developer's key. -.. image:: pep-0458/figure3.png +.. image:: pep-0458-3.png Figure 3: An overview of the metadata layout in the maximum security model. The maximum security model supports continuous delivery and survivable key -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Wed Nov 26 01:44:23 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 26 Nov 2014 00:44:23 +0000 Subject: [Python-checkins] =?utf-8?q?release=3A_adapt_for_dl-files?= Message-ID: <20141126004420.84301.69538@psf.io> https://hg.python.org/release/rev/1caf757e09fe changeset: 89:1caf757e09fe user: Benjamin Peterson date: Tue Nov 25 18:44:11 2014 -0600 summary: adapt for dl-files files: add-to-pydotorg.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/add-to-pydotorg.py b/add-to-pydotorg.py --- a/add-to-pydotorg.py +++ b/add-to-pydotorg.py @@ -41,7 +41,7 @@ sys.exit() base_url = 'https://www.python.org/api/v1/' -ftp_root = '/data/ftp.python.org/pub/python/' +ftp_root = '/srv/www.python.org/ftp/python/' download_root = 'https://www.python.org/ftp/python/' headers = {'Authorization': 'ApiKey %s' % auth_info, 'Content-Type': 'application/json'} -- Repository URL: https://hg.python.org/release From python-checkins at python.org Wed Nov 26 02:15:56 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 26 Nov 2014 01:15:56 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogYWRkIDIuNy4xMCBu?= =?utf-8?q?ews_section?= Message-ID: <20141126011551.116312.53450@psf.io> https://hg.python.org/cpython/rev/323f51ce8d86 changeset: 93596:323f51ce8d86 branch: 2.7 user: Benjamin Peterson date: Tue Nov 25 19:15:39 2014 -0600 summary: add 2.7.10 news section files: Misc/NEWS | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-) 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 2.7.10? +============================ + +*Release date: XXXX-XX-XX* + +Core and Builtins +----------------- + +Library +------- + + What's New in Python 2.7.9 release candidate 1? =============================================== -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 03:17:23 2014 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 26 Nov 2014 02:17:23 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_No_empty_promises_in_the_abst?= =?utf-8?q?ract=2E_Extend_rationale=2E?= Message-ID: <20141126021716.116312.66001@psf.io> https://hg.python.org/peps/rev/d53cc8342ddd changeset: 5618:d53cc8342ddd user: Guido van Rossum date: Tue Nov 25 18:17:13 2014 -0800 summary: No empty promises in the abstract. Extend rationale. files: pep-0479.txt | 36 +++++++++++++++++++++++++++++------- 1 files changed, 29 insertions(+), 7 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -14,13 +14,10 @@ Abstract ======== -This PEP proposes a semantic change to ``StopIteration`` when raised -inside a generator. This would unify the behaviour of list -comprehensions and generator expressions, reducing surprises such as -the one that started this discussion [1]_. This is also the main -backwards incompatibility of the proposal -- any generator that -depends on raising ``StopIteration`` to terminate it will -have to be rewritten to either catch that exception or use a for-loop. +This PEP proposes a backwards incompatible change to generators: when +``StopIteration`` is raised inside a generator, it is replaced it with +``RuntimeError``. (More precisely, this happens when the exception is +about to bubble out of the generator's stack frame.) Rationale @@ -32,6 +29,31 @@ cause a noisy and easily-debugged traceback. Currently, ``StopIteration`` can be absorbed by the generator construct. +The main goal of the proposal is to ease debugging in the situation +where an unguarded ``next()`` call (perhaps several stack frames deep) +raises ``StopIteration`` and causes the iteration controlled by the +generator to terminate silently. (When another exception is raised, a +traceback is printed pinpointing the cause of the problem.) + +The proposal also clears up the confusion about how to terminate a +generator: the proper way is ``return``, not ``raise StopIteration``. + +Finally, the proposal reduces the difference between list +comprehensions and generator expressions, preventing surprises such as +the one that started this discussion [1]_. Henceforth, the following +statements will produce the same result if either produces a result at +all:: + + a = list(F(x) for x in xs if P(x)) + a = [F(x) for x in xs if P(x)] + +With the current state of affairs, it is possible to write a function +``F(x)`` or a predicate ``P(x)`` that causes the first form to produce +a (truncated) result, while the second form raises an exception +(namely, ``StopIteration``). With the proposed change, both forms +will raise an exception at this point (albeit ``RuntimeError`` in the +first case and ``StopIteration`` in the second). + Background information ====================== -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Wed Nov 26 06:32:23 2014 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 26 Nov 2014 05:32:23 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Add_transition_plan=2E?= Message-ID: <20141126053218.116310.85853@psf.io> https://hg.python.org/peps/rev/427e505d1237 changeset: 5619:427e505d1237 user: Guido van Rossum date: Tue Nov 25 21:32:14 2014 -0800 summary: Add transition plan. files: pep-0479.txt | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -264,6 +264,18 @@ beyond that, all exceptions will propagate normally. +Transition plan +=============== + +- Python 3.5: Enable new semantics under ``__future__`` import; silent + deprecation warning if ``StopIteration`` bubbles out of a generator + not under ``__future__`` import. + +- Python 3.6: non-silent deprecation warning. + +- Python 3.7: enable new semantics everywhere. + + Alternate proposals =================== -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Wed Nov 26 06:43:03 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 26 Nov 2014 05:43:03 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_update_2=2E7=2E9_release_date?= =?utf-8?q?s?= Message-ID: <20141126054258.55107.86043@psf.io> https://hg.python.org/peps/rev/5e80f39d6a8f changeset: 5620:5e80f39d6a8f user: Benjamin Peterson date: Tue Nov 25 23:42:40 2014 -0600 summary: update 2.7.9 release dates files: pep-0373.txt | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0373.txt b/pep-0373.txt --- a/pep-0373.txt +++ b/pep-0373.txt @@ -71,8 +71,8 @@ Planned future release dates: -- 2.7.9rc1 2014-11-22 -- 2.7.9 2014-12-05 +- 2.7.9rc1 2014-11-26 +- 2.7.9 2014-12-10 - 2.7.10 June 2015 - beyond this date, releases as needed -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Wed Nov 26 07:06:17 2014 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 26 Nov 2014 06:06:17 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Another_major_editing_pass=2E?= =?utf-8?q?_Move_=5F=5Ffuture=5F=5F_into_spec=2E_Add_section_about?= Message-ID: <20141126060616.116314.51977@psf.io> https://hg.python.org/peps/rev/574b60a51ebd changeset: 5621:574b60a51ebd user: Guido van Rossum date: Tue Nov 25 22:05:29 2014 -0800 summary: Another major editing pass. Move __future__ into spec. Add section about compatible code. files: pep-0479.txt | 75 +++++++++++++++++++++++++-------------- 1 files changed, 47 insertions(+), 28 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -14,10 +14,12 @@ Abstract ======== -This PEP proposes a backwards incompatible change to generators: when -``StopIteration`` is raised inside a generator, it is replaced it with -``RuntimeError``. (More precisely, this happens when the exception is -about to bubble out of the generator's stack frame.) +This PEP proposes a change to generators: when ``StopIteration`` is +raised inside a generator, it is replaced it with ``RuntimeError``. +(More precisely, this happens when the exception is about to bubble +out of the generator's stack frame.) Because the change is backwards +incompatible, the feature is initially introduced using a +``__future__`` statement. Rationale @@ -100,6 +102,17 @@ using a ``try/except`` around the ``yield``), it will be transformed into ``RuntimeError``. +During the transition phase, the new feature must be enabled +per-module using:: + + from __future__ import generator_stop + +Any generator function constructed under the influence of this +directive will have the ``REPLACE_STOPITERATION`` flag set on its code +object, and generators with the flag set will behave according to this +proposal. Once the feature becomes standard, the flag may be dropped; +code should not inspect generators for it. + Consequences for existing code ============================== @@ -116,28 +129,34 @@ yield from helper()" rather than just "helper()".""") There are also examples of generator expressions floating around that -rely on a StopIteration raised by the expression, the target or the -predicate (rather than by the __next__() call implied in the ``for`` +rely on a ``StopIteration`` raised by the expression, the target or the +predicate (rather than by the ``__next__()`` call implied in the ``for`` loop proper). -As this can break code, it is proposed to utilize the ``__future__`` -mechanism to introduce this in Python 3.5, finally making it standard -in Python 3.6 or 3.7. The proposed syntax is:: +Writing backwards and forwards compatible code +---------------------------------------------- - from __future__ import generator_stop +With the exception of hacks that raise ``StopIteration`` to exit a +generator expression, it is easy to write code that works equally well +under older Python versions as under the new semantics. -Any generator function constructed under the influence of this -directive will have the REPLACE_STOPITERATION flag set on its code -object, and generators with the flag set will behave according to this -proposal. Once the feature becomes standard, the flag may be dropped; -code should not inspect generators for it. +This is done by enclosing those places in the generator body where a +``StopIteration`` is expected (e.g. bare ``next()`` calls or in some +cases helper functions that are expected to raise ``StopIteration``) +in a ``try/except`` construct that returns when ``StopIteration`` +returns. The ``try/except`` construct should appear directly in the +generator function; doing this in a helper function that is not itself +a generator does not work. If ``raise StopIteration`` occurs directly +in a generator, simply replace it with ``return``. -Examples --------- -Generators which explicitly raise StopIteration can generally be +Examples of breakage +-------------------- + +Generators which explicitly raise ``StopIteration`` can generally be changed to simply return instead. This will be compatible with all -existing Python versions, and will not be affected by __future__. +existing Python versions, and will not be affected by ``__future__``. +Here are some illustrations from the standard library. Lib/ipaddress.py:: @@ -164,7 +183,7 @@ (The ``return`` is necessary for a strictly-equivalent translation, though in this particular file, there is no further code, and the -``return`` can be elided.) For compatibility with pre-3.3 versions +``return`` can be omitted.) For compatibility with pre-3.3 versions of Python, this could be written with an explicit ``for`` loop:: if context is None: @@ -172,10 +191,10 @@ yield line return -More complicated iteration patterns will need explicit try/catch -constructs. For example, a parser construct like this:: +More complicated iteration patterns will need explicit ``try/except`` +constructs. For example, a hypothetical parser like this:: - def unwrap(f): + def parser(f): while True: data = next(f) while True: @@ -227,7 +246,7 @@ visible. An iterator is an object with a ``__next__`` method. Like many other -dunder methods, it may either return a value, or raise a specific +special methods, it may either return a value, or raise a specific exception - in this case, ``StopIteration`` - to signal that it has no value to return. In this, it is similar to ``__getattr__`` (can raise ``AttributeError``), ``__getitem__`` (can raise ``KeyError``), @@ -271,9 +290,9 @@ deprecation warning if ``StopIteration`` bubbles out of a generator not under ``__future__`` import. -- Python 3.6: non-silent deprecation warning. +- Python 3.6: Non-silent deprecation warning. -- Python 3.7: enable new semantics everywhere. +- Python 3.7: Enable new semantics everywhere. Alternate proposals @@ -363,12 +382,12 @@ issues inherent to every other case where an exception has special meaning. For instance, an unexpected ``KeyError`` inside a ``__getitem__`` method will be interpreted as failure, rather than -permitted to bubble up. However, there is a difference. Dunder +permitted to bubble up. However, there is a difference. Special methods use ``return`` to indicate normality, and ``raise`` to signal abnormality; generators ``yield`` to indicate data, and ``return`` to signal the abnormal state. This makes explicitly raising ``StopIteration`` entirely redundant, and potentially surprising. If -other dunder methods had dedicated keywords to distinguish between +other special methods had dedicated keywords to distinguish between their return paths, they too could turn unexpected exceptions into ``RuntimeError``; the fact that they cannot should not preclude generators from doing so. -- Repository URL: https://hg.python.org/peps From solipsis at pitrou.net Wed Nov 26 10:32:01 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 26 Nov 2014 10:32:01 +0100 Subject: [Python-checkins] Daily reference leaks (81b5268efff6): sum=6 Message-ID: results for 81b5268efff6 on branch "default" -------------------------------------------- test_collections leaked [0, 4, -2] references, sum=2 test_collections leaked [0, 2, -1] memory blocks, sum=1 test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/refloge6yzZs', '-x'] From python-checkins at python.org Wed Nov 26 11:14:10 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 26 Nov 2014 10:14:10 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2319676=3A_Fixed_in?= =?utf-8?q?teger_overflow_issue_in_=22namereplace=22_error_handler=2E?= Message-ID: <20141126101353.84299.18537@psf.io> https://hg.python.org/cpython/rev/21d1571c0533 changeset: 93597:21d1571c0533 parent: 93592:81b5268efff6 user: Serhiy Storchaka date: Wed Nov 26 12:11:40 2014 +0200 summary: Issue #19676: Fixed integer overflow issue in "namereplace" error handler. files: Python/codecs.c | 16 +++++++++++----- 1 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Python/codecs.c b/Python/codecs.c --- a/Python/codecs.c +++ b/Python/codecs.c @@ -947,7 +947,8 @@ Py_ssize_t end; PyObject *res; unsigned char *outp; - int ressize; + Py_ssize_t ressize; + int replsize; Py_UCS4 c; char buffer[256]; /* NAME_MAXLEN */ if (PyUnicodeEncodeError_GetStart(exc, &start)) @@ -967,17 +968,21 @@ c = PyUnicode_READ_CHAR(object, i); if (ucnhash_CAPI && ucnhash_CAPI->getname(NULL, c, buffer, sizeof(buffer), 1)) { - ressize += 1+1+1+strlen(buffer)+1; + replsize = 1+1+1+strlen(buffer)+1; } else if (c >= 0x10000) { - ressize += 1+1+8; + replsize = 1+1+8; } else if (c >= 0x100) { - ressize += 1+1+4; + replsize = 1+1+4; } else - ressize += 1+1+2; + replsize = 1+1+2; + if (ressize > PY_SSIZE_T_MAX - replsize) + break; + ressize += replsize; } + end = i; res = PyUnicode_New(ressize, 127); if (res==NULL) return NULL; @@ -1014,6 +1019,7 @@ *outp++ = Py_hexdigits[c&0xf]; } + assert(out == start + ressize); assert(_PyUnicode_CheckConsistency(res, 1)); restuple = Py_BuildValue("(Nn)", res, end); Py_DECREF(object); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 16:52:45 2014 From: python-checkins at python.org (steve.dower) Date: Wed, 26 Nov 2014 15:52:45 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogVXBkYXRlIG1zaS5w?= =?utf-8?q?y_and_uuids=2Epy_for_2=2E7=2E9_releases?= Message-ID: <20141126155245.84293.68246@psf.io> https://hg.python.org/cpython/rev/4cf3ea8d565b changeset: 93598:4cf3ea8d565b branch: 2.7 parent: 93596:323f51ce8d86 user: Steve Dower date: Tue Nov 25 22:43:06 2014 -0800 summary: Update msi.py and uuids.py for 2.7.9 releases files: Tools/msi/msi.py | 8 ++++---- Tools/msi/uuids.py | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py --- a/Tools/msi/msi.py +++ b/Tools/msi/msi.py @@ -912,9 +912,9 @@ ("Tk", "tk-8*", "license.terms"), ("Tix", "tix-*", "license.terms")): out.write("\nThis copy of Python includes a copy of %s, which is licensed under the following terms:\n\n" % name) - dirs = glob.glob(srcdir+"/../"+pat) + dirs = glob.glob(srcdir+"/externals/"+pat) if not dirs: - raise ValueError, "Could not find "+srcdir+"/../"+pat + raise ValueError, "Could not find "+srcdir+"/externals/"+pat if len(dirs) > 2: raise ValueError, "Multiple copies of "+pat dir = dirs[0] @@ -1117,7 +1117,7 @@ lib.start_component("TkDLLs", tcltk) lib.add_file("_tkinter.pyd") dlls.append("_tkinter.pyd") - tcldir = os.path.normpath(srcdir+("/../tcltk%s/bin" % tclsuffix)) + tcldir = os.path.normpath(srcdir+("/externals/tcltk%s/bin" % tclsuffix)) for f in glob.glob1(tcldir, "*.dll"): lib.add_file(f, src=os.path.join(tcldir, f)) # check whether there are any unknown extensions @@ -1141,7 +1141,7 @@ lib.add_file('libpython%s%s.a' % (major, minor)) if have_tcl: # Add Tcl/Tk - tcldirs = [(root, '../tcltk%s/lib' % tclsuffix, 'tcl')] + tcldirs = [(root, 'externals/tcltk%s/lib' % tclsuffix, 'tcl')] tcltk.set_current() while tcldirs: parent, phys, dir = tcldirs.pop() diff --git a/Tools/msi/uuids.py b/Tools/msi/uuids.py --- a/Tools/msi/uuids.py +++ b/Tools/msi/uuids.py @@ -66,4 +66,6 @@ '2.7.7121':'{5E0D187D-238B-4e96-9C75-C4CF141F5385}', # 2.7.7rc1 '2.7.7150':'{049CA433-77A0-4e48-AC76-180A282C4E10}', # 2.7.7 '2.7.8150':'{61121B12-88BD-4261-A6EE-AB32610A56DD}', # 2.7.8 + '2.7.9121':'{AAB1E8FF-6D00-4409-8F13-BE365AB92FFE}', # 2.7.9rc1 + '2.7.9150':'{79F081BF-7454-43DB-BD8F-9EE596813232}', # 2.7.9 } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 18:20:35 2014 From: python-checkins at python.org (steve.dower) Date: Wed, 26 Nov 2014 17:20:35 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Adds_missing_f?= =?utf-8?q?iles_to_msi=2Epy?= Message-ID: <20141126172035.55103.62039@psf.io> https://hg.python.org/cpython/rev/1dee86f69af7 changeset: 93599:1dee86f69af7 branch: 2.7 user: Steve Dower date: Wed Nov 26 09:20:00 2014 -0800 summary: Adds missing files to msi.py files: Tools/msi/msi.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py --- a/Tools/msi/msi.py +++ b/Tools/msi/msi.py @@ -1019,6 +1019,8 @@ # Add additional files dirs[dir]=lib lib.glob("*.txt") + lib.glob("*.whl") + lib.glob("*.0") if dir=='site-packages': lib.add_file("README.txt", src="README") continue -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 18:33:19 2014 From: python-checkins at python.org (steve.dower) Date: Wed, 26 Nov 2014 17:33:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Adds_missing_r?= =?utf-8?q?evocation=2Ecrl_test_file_to_msi=2Epy?= Message-ID: <20141126173257.69775.73461@psf.io> https://hg.python.org/cpython/rev/ac2175c5b743 changeset: 93600:ac2175c5b743 branch: 2.7 user: Steve Dower date: Wed Nov 26 09:32:41 2014 -0800 summary: Adds missing revocation.crl test file to msi.py files: Tools/msi/msi.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Tools/msi/msi.py b/Tools/msi/msi.py --- a/Tools/msi/msi.py +++ b/Tools/msi/msi.py @@ -1045,6 +1045,7 @@ lib.add_file("check_soundcard.vbs") lib.add_file("empty.vbs") lib.add_file("Sine-1000Hz-300ms.aif") + lib.add_file("revocation.crl") lib.glob("*.uue") lib.glob("*.pem") lib.glob("*.pck") -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 18:34:36 2014 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 26 Nov 2014 17:34:36 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Chris_A=3A_Mention_Mark_Shann?= =?utf-8?q?on=27s_counterproposal_of_changing_next=28=29=2E_One_small?= Message-ID: <20141126173431.126790.4287@psf.io> https://hg.python.org/peps/rev/9695a84dc696 changeset: 5622:9695a84dc696 user: Guido van Rossum date: Wed Nov 26 09:34:12 2014 -0800 summary: Chris A: Mention Mark Shannon's counterproposal of changing next(). One small copy-edit. files: pep-0479.txt | 22 ++++++++++++++++++++-- 1 files changed, 20 insertions(+), 2 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -143,8 +143,8 @@ This is done by enclosing those places in the generator body where a ``StopIteration`` is expected (e.g. bare ``next()`` calls or in some cases helper functions that are expected to raise ``StopIteration``) -in a ``try/except`` construct that returns when ``StopIteration`` -returns. The ``try/except`` construct should appear directly in the +in a ``try/except`` construct that returns when ``StopIteration`` is +raised. The ``try/except`` construct should appear directly in the generator function; doing this in a helper function that is not itself a generator does not work. If ``raise StopIteration`` occurs directly in a generator, simply replace it with ``return``. @@ -364,6 +364,21 @@ bubble out would still be potentially wrong, depending on the use made of the distinction between the two exception types. +Converting the exception inside next() +-------------------------------------- + +Mark Shannon suggested [11]_ that the problem could be solved in +``next()`` rather than at the boundary of generator functions. By +having ``next()`` catch ``StopIteration`` and raise instead +``ValueError``, all unexpected ``StopIteration`` bubbling would be +prevented; however, the backward-incompatibility concerns are far +more serious than for the current proposal, as every ``next()`` call +now needs to be rewritten to guard against ``ValueError`` instead of +``StopIteration`` - not to mention that there is no way to write one +block of code which reliably works on multiple versions of Python. +(Using a dedicated exception type, perhaps subclassing ``ValueError``, +would help this; however, all code would still need to be rewritten.) + Criticism ========= @@ -426,6 +441,9 @@ .. [10] Tracker issue with Proof-of-Concept patch (http://bugs.python.org/issue22906) +.. [11] Post from Mark Shannon with alternate proposal + (https://mail.python.org/pipermail/python-dev/2014-November/137129.html) + Copyright ========= -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Wed Nov 26 19:07:14 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 26 Nov 2014 18:07:14 +0000 Subject: [Python-checkins] =?utf-8?q?release=3A_only_send_gpg_sig_if_it_ex?= =?utf-8?q?ists?= Message-ID: <20141126180702.116320.7641@psf.io> https://hg.python.org/release/rev/4f6f8bb7881d changeset: 90:4f6f8bb7881d user: Benjamin Peterson date: Wed Nov 26 12:06:23 2014 -0600 summary: only send gpg sig if it exists files: add-to-pydotorg.py | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/add-to-pydotorg.py b/add-to-pydotorg.py --- a/add-to-pydotorg.py +++ b/add-to-pydotorg.py @@ -100,7 +100,7 @@ def build_file_dict(release, rfile, rel_pk, file_desc, os_pk, add_desc): """Return a dictionary with all needed fields for a ReleaseFile object.""" - return dict( + d = dict( name = file_desc, slug = slug_for(release) + '-' + make_slug(file_desc)[:40], os = '/api/v1/downloads/os/%s/' % os_pk, @@ -108,7 +108,6 @@ description = add_desc, is_source = os_pk == 3, url = download_root + '%s/%s' % (release[:5], rfile), - gpg_signature_file = sigfile_for(release[:5], rfile), md5_sum = md5sum_for(release, rfile), filesize = filesize_for(release, rfile), download_button = 'tar.xz' in rfile or @@ -116,6 +115,9 @@ 'macosx10.6.pkg' in rfile or ('.msi' in rfile and not 'amd64' in rfile), ) + if os.path.exists(ftp_root + "%s/%s.asc" % (release[:5], rfile)): + d["gpg_signature_file"] = sigfile_for(release[:5], rfile) + return d def list_files(release): """List all of the release's download files.""" -- Repository URL: https://hg.python.org/release From python-checkins at python.org Wed Nov 26 20:58:41 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 26 Nov 2014 19:58:41 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_add_readline=2Eappend=5Fhi?= =?utf-8?q?story=5Ffile_=28closes_=2322940=29?= Message-ID: <20141126195834.84295.69186@psf.io> https://hg.python.org/cpython/rev/ff00588791be changeset: 93601:ff00588791be parent: 93597:21d1571c0533 user: Benjamin Peterson date: Wed Nov 26 13:58:16 2014 -0600 summary: add readline.append_history_file (closes #22940) patch by "bru" files: Doc/library/readline.rst | 29 ++++++++++++++++++- Lib/test/test_readline.py | 40 ++++++++++++++++++++++++++- Misc/NEWS | 2 + Modules/readline.c | 37 ++++++++++++++++++++++++ 4 files changed, 106 insertions(+), 2 deletions(-) diff --git a/Doc/library/readline.rst b/Doc/library/readline.rst --- a/Doc/library/readline.rst +++ b/Doc/library/readline.rst @@ -59,6 +59,14 @@ Save a readline history file. The default filename is :file:`~/.history`. +.. function:: append_history_file(nelements[, filename]) + + Append the last *nelements* of history to a file. The default filename is + :file:`~/.history`. The file must already exist. + + .. versionadded:: 3.5 + + .. function:: clear_history() Clear the current history. (Note: this function is not available if the @@ -209,6 +217,26 @@ This code is actually automatically run when Python is run in :ref:`interactive mode ` (see :ref:`rlcompleter-config`). +The following example achieves the same goal but supports concurrent interactive +sessions, by only appending the new history. :: + + import atexit + import os + import realine + histfile = os.path.join(os.path.expanduser("~"), ".python_history") + + try: + readline.read_history_file(histfile) + h_len = readline.get_history_length() + except FileNotFoundError: + open(histfile, 'wb').close() + h_len = 0 + + def save(prev_h_len, histfile): + new_h_len = readline.get_history_length() + readline.append_history_file(new_h_len - prev_h_len, histfile) + atexit.register(save, h_len, histfile) + The following example extends the :class:`code.InteractiveConsole` class to support history save/restore. :: @@ -234,4 +262,3 @@ def save_history(self, histfile): readline.write_history_file(histfile) - diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py --- a/Lib/test/test_readline.py +++ b/Lib/test/test_readline.py @@ -2,8 +2,9 @@ Very minimal unittests for parts of the readline module. """ import os +import tempfile import unittest -from test.support import run_unittest, import_module +from test.support import run_unittest, import_module, unlink from test.script_helper import assert_python_ok # Skip tests if there is no readline module @@ -42,6 +43,43 @@ self.assertEqual(readline.get_current_history_length(), 1) + def test_write_read_append(self): + hfile = tempfile.NamedTemporaryFile(delete=False) + hfile.close() + hfilename = hfile.name + self.addCleanup(unlink, hfilename) + + # test write-clear-read == nop + readline.clear_history() + readline.add_history("first line") + readline.add_history("second line") + readline.write_history_file(hfilename) + + readline.clear_history() + self.assertEqual(readline.get_current_history_length(), 0) + + readline.read_history_file(hfilename) + self.assertEqual(readline.get_current_history_length(), 2) + self.assertEqual(readline.get_history_item(1), "first line") + self.assertEqual(readline.get_history_item(2), "second line") + + # test append + readline.append_history_file(1, hfilename) + readline.clear_history() + readline.read_history_file(hfilename) + self.assertEqual(readline.get_current_history_length(), 3) + self.assertEqual(readline.get_history_item(1), "first line") + self.assertEqual(readline.get_history_item(2), "second line") + self.assertEqual(readline.get_history_item(3), "second line") + + # test 'no such file' behaviour + os.unlink(hfilename) + with self.assertRaises(FileNotFoundError): + readline.append_history_file(1, hfilename) + + # write_history_file can create the target + readline.write_history_file(hfilename) + class TestReadline(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -191,6 +191,8 @@ Library ------- +- Issue #22940: Add readline.append_history_file. + - Issue #19676: Added the "namereplace" error handler. - Issue #22788: Add *context* parameter to logging.handlers.HTTPHandler. diff --git a/Modules/readline.c b/Modules/readline.c --- a/Modules/readline.c +++ b/Modules/readline.c @@ -237,6 +237,41 @@ The default filename is ~/.history."); +/* Exported function to save part of a readline history file */ + +static PyObject * +append_history_file(PyObject *self, PyObject *args) +{ + int nelements; + PyObject *filename_obj = Py_None, *filename_bytes; + char *filename; + int err; + if (!PyArg_ParseTuple(args, "i|O:append_history_file", &nelements, &filename_obj)) + return NULL; + if (filename_obj != Py_None) { + if (!PyUnicode_FSConverter(filename_obj, &filename_bytes)) + return NULL; + filename = PyBytes_AsString(filename_bytes); + } else { + filename_bytes = NULL; + filename = NULL; + } + errno = err = append_history(nelements, filename); + if (!err && _history_length >= 0) + history_truncate_file(filename, _history_length); + Py_XDECREF(filename_bytes); + errno = err; + if (errno) + return PyErr_SetFromErrno(PyExc_IOError); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(doc_append_history_file, +"append_history_file(nelements[, filename]) -> None\n\ +Append the last nelements of the history list to file.\n\ +The default filename is ~/.history."); + + /* Set history length */ static PyObject* @@ -747,6 +782,8 @@ METH_VARARGS, doc_read_history_file}, {"write_history_file", write_history_file, METH_VARARGS, doc_write_history_file}, + {"append_history_file", append_history_file, + METH_VARARGS, doc_append_history_file}, {"get_history_item", get_history_item, METH_VARARGS, doc_get_history_item}, {"get_current_history_length", (PyCFunction)get_current_history_length, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 21:21:04 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 26 Nov 2014 20:21:04 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_fix_variable_name?= Message-ID: <20141126202100.84297.36470@psf.io> https://hg.python.org/cpython/rev/ce8a8531d29a changeset: 93602:ce8a8531d29a user: Benjamin Peterson date: Wed Nov 26 14:20:51 2014 -0600 summary: fix variable name files: Python/codecs.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/codecs.c b/Python/codecs.c --- a/Python/codecs.c +++ b/Python/codecs.c @@ -1019,7 +1019,7 @@ *outp++ = Py_hexdigits[c&0xf]; } - assert(out == start + ressize); + assert(outp == start + ressize); assert(_PyUnicode_CheckConsistency(res, 1)); restuple = Py_BuildValue("(Nn)", res, end); Py_DECREF(object); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 21:35:24 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 26 Nov 2014 20:35:24 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_only_support_append=5Fhist?= =?utf-8?q?ory_if_readline_has_it?= Message-ID: <20141126203521.84295.28194@psf.io> https://hg.python.org/cpython/rev/031ab6d4a0f3 changeset: 93603:031ab6d4a0f3 user: Benjamin Peterson date: Wed Nov 26 14:35:12 2014 -0600 summary: only support append_history if readline has it files: Lib/test/test_readline.py | 2 + Modules/readline.c | 4 ++ configure | 43 +++++++++++++++++++++++++++ configure.ac | 4 ++ pyconfig.h.in | 3 + 5 files changed, 56 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py --- a/Lib/test/test_readline.py +++ b/Lib/test/test_readline.py @@ -43,6 +43,8 @@ self.assertEqual(readline.get_current_history_length(), 1) + @unittest.skipUnless(hasattr(readline, "append_history"), + "append_history not available") def test_write_read_append(self): hfile = tempfile.NamedTemporaryFile(delete=False) hfile.close() diff --git a/Modules/readline.c b/Modules/readline.c --- a/Modules/readline.c +++ b/Modules/readline.c @@ -237,6 +237,7 @@ The default filename is ~/.history."); +#ifdef HAVE_RL_APPEND_HISTORY /* Exported function to save part of a readline history file */ static PyObject * @@ -270,6 +271,7 @@ "append_history_file(nelements[, filename]) -> None\n\ Append the last nelements of the history list to file.\n\ The default filename is ~/.history."); +#endif /* Set history length */ @@ -782,7 +784,9 @@ METH_VARARGS, doc_read_history_file}, {"write_history_file", write_history_file, METH_VARARGS, doc_write_history_file}, +#ifdef HAVE_RL_APPEND_HISTORY {"append_history_file", append_history_file, +#endif METH_VARARGS, doc_append_history_file}, {"get_history_item", get_history_item, METH_VARARGS, doc_get_history_item}, diff --git a/configure b/configure --- a/configure +++ b/configure @@ -14529,6 +14529,49 @@ fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for append_history in -lreadline" >&5 +$as_echo_n "checking for append_history in -lreadline... " >&6; } +if ${ac_cv_lib_readline_append_history+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lreadline $READLINE_LIBS $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char append_history (); +int +main () +{ +return append_history (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_readline_append_history=yes +else + ac_cv_lib_readline_append_history=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_append_history" >&5 +$as_echo "$ac_cv_lib_readline_append_history" >&6; } +if test "x$ac_cv_lib_readline_append_history" = xyes; then : + +$as_echo "#define HAVE_RL_APPEND_HISTORY 1" >>confdefs.h + +fi + + # End of readline checks: restore LIBS LIBS=$LIBS_no_readline diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -4308,6 +4308,10 @@ [Define if you can turn off readline's signal handling.]), ) fi +AC_CHECK_LIB(readline, append_history, + AC_DEFINE(HAVE_RL_APPEND_HISTORY, 1, + [Define if readline supports append_history]), ,$READLINE_LIBS) + # End of readline checks: restore LIBS LIBS=$LIBS_no_readline diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -690,6 +690,9 @@ /* Define to 1 if you have the `renameat' function. */ #undef HAVE_RENAMEAT +/* Define if readline supports append_history */ +#undef HAVE_RL_APPEND_HISTORY + /* Define if you have readline 2.1 */ #undef HAVE_RL_CALLBACK -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 21:36:23 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 26 Nov 2014 20:36:23 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_use_skipUnless?= Message-ID: <20141126203620.55109.7528@psf.io> https://hg.python.org/cpython/rev/812f31cbe6be changeset: 93604:812f31cbe6be branch: 3.4 parent: 93591:e635c3ba75c8 user: Benjamin Peterson date: Wed Nov 26 14:35:56 2014 -0600 summary: use skipUnless files: Lib/test/test_readline.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py --- a/Lib/test/test_readline.py +++ b/Lib/test/test_readline.py @@ -16,9 +16,9 @@ why the tests cover only a small subset of the interface. """ - @unittest.skipIf(not hasattr(readline, 'clear_history'), - "The history update test cannot be run because the " - "clear_history method is not available.") + @unittest.skipUnless(hasattr(readline, "clear_history"), + "The history update test cannot be run because the " + "clear_history method is not available.") def testHistoryUpdates(self): readline.clear_history() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 21:36:23 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 26 Nov 2014 20:36:23 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20141126203620.126780.41547@psf.io> https://hg.python.org/cpython/rev/6528f943c1bd changeset: 93605:6528f943c1bd parent: 93603:031ab6d4a0f3 parent: 93604:812f31cbe6be user: Benjamin Peterson date: Wed Nov 26 14:36:08 2014 -0600 summary: merge 3.4 files: Lib/test/test_readline.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py --- a/Lib/test/test_readline.py +++ b/Lib/test/test_readline.py @@ -17,9 +17,9 @@ why the tests cover only a small subset of the interface. """ - @unittest.skipIf(not hasattr(readline, 'clear_history'), - "The history update test cannot be run because the " - "clear_history method is not available.") + @unittest.skipUnless(hasattr(readline, "clear_history"), + "The history update test cannot be run because the " + "clear_history method is not available.") def testHistoryUpdates(self): readline.clear_history() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 21:37:36 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 26 Nov 2014 20:37:36 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_use_skipUnless?= Message-ID: <20141126203732.116316.54839@psf.io> https://hg.python.org/cpython/rev/3f5ac9f43027 changeset: 93606:3f5ac9f43027 branch: 2.7 parent: 93600:ac2175c5b743 user: Benjamin Peterson date: Wed Nov 26 14:35:56 2014 -0600 summary: use skipUnless files: Lib/test/test_readline.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py --- a/Lib/test/test_readline.py +++ b/Lib/test/test_readline.py @@ -15,9 +15,9 @@ That's why the tests cover only a small subset of the interface. """ - @unittest.skipIf(not hasattr(readline, 'clear_history'), - "The history update test cannot be run because the " - "clear_history method is not available.") + @unittest.skipUnless(hasattr(readline, "clear_history"), + "The history update test cannot be run because the " + "clear_history method is not available.") def testHistoryUpdates(self): readline.clear_history() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 21:42:12 2014 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 26 Nov 2014 20:42:12 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_correct_assertion?= Message-ID: <20141126204209.126764.78991@psf.io> https://hg.python.org/cpython/rev/edc8a0bb95aa changeset: 93607:edc8a0bb95aa parent: 93605:6528f943c1bd user: Benjamin Peterson date: Wed Nov 26 14:39:54 2014 -0600 summary: correct assertion files: Python/codecs.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/codecs.c b/Python/codecs.c --- a/Python/codecs.c +++ b/Python/codecs.c @@ -1019,7 +1019,7 @@ *outp++ = Py_hexdigits[c&0xf]; } - assert(outp == start + ressize); + assert(outp == PyUnicode_1BYTE_DATA(res) + ressize); assert(_PyUnicode_CheckConsistency(res, 1)); restuple = Py_BuildValue("(Nn)", res, end); Py_DECREF(object); -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Wed Nov 26 22:03:13 2014 From: python-checkins at python.org (ned.deily) Date: Wed, 26 Nov 2014 21:03:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_22940=3A_fixes_to_ed?= =?utf-8?q?itline_support?= Message-ID: <20141126210305.55115.10674@psf.io> https://hg.python.org/cpython/rev/c8bcede1b37a changeset: 93608:c8bcede1b37a user: Ned Deily date: Wed Nov 26 13:02:33 2014 -0800 summary: Issue 22940: fixes to editline support files: Lib/test/test_readline.py | 2 +- Modules/readline.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py --- a/Lib/test/test_readline.py +++ b/Lib/test/test_readline.py @@ -43,7 +43,7 @@ self.assertEqual(readline.get_current_history_length(), 1) - @unittest.skipUnless(hasattr(readline, "append_history"), + @unittest.skipUnless(hasattr(readline, "append_history_file"), "append_history not available") def test_write_read_append(self): hfile = tempfile.NamedTemporaryFile(delete=False) diff --git a/Modules/readline.c b/Modules/readline.c --- a/Modules/readline.c +++ b/Modules/readline.c @@ -786,8 +786,8 @@ METH_VARARGS, doc_write_history_file}, #ifdef HAVE_RL_APPEND_HISTORY {"append_history_file", append_history_file, + METH_VARARGS, doc_append_history_file}, #endif - METH_VARARGS, doc_append_history_file}, {"get_history_item", get_history_item, METH_VARARGS, doc_get_history_item}, {"get_current_history_length", (PyCFunction)get_current_history_length, -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 05:58:49 2014 From: python-checkins at python.org (zach.ware) Date: Thu, 27 Nov 2014 04:58:49 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E4?= Message-ID: <20141127045848.84299.7520@psf.io> https://hg.python.org/cpython/rev/7fe7ef360941 changeset: 93610:7fe7ef360941 parent: 93608:c8bcede1b37a parent: 93609:6fce36de7916 user: Zachary Ware date: Wed Nov 26 22:58:25 2014 -0600 summary: Merge with 3.4 files: Doc/library/pydoc.rst | 10 ++++------ 1 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Doc/library/pydoc.rst b/Doc/library/pydoc.rst --- a/Doc/library/pydoc.rst +++ b/Doc/library/pydoc.rst @@ -66,11 +66,6 @@ documentation at ``http://localhost:1234/`` in your preferred Web browser. Specifying ``0`` as the port number will select an arbitrary unused port. -:program:`pydoc -g` will start the server and additionally bring up a -small :mod:`tkinter`\ -based graphical interface to help you search for -documentation pages. The ``-g`` option is deprecated, since the server can -now be controlled directly from HTTP clients. - :program:`pydoc -b` will start the server and additionally open a web browser to a module index page. Each served page has a navigation bar at the top where you can *Get* help on an individual item, *Search* all modules with a @@ -90,7 +85,10 @@ Reference Manual pages. .. versionchanged:: 3.2 - Added the ``-b`` option, deprecated the ``-g`` option. + Added the ``-b`` option. + +.. versionchanged:: 3.3 + The ``-g`` command line option was removed. .. versionchanged:: 3.4 :mod:`pydoc` now uses :func:`inspect.signature` rather than -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 05:58:48 2014 From: python-checkins at python.org (zach.ware) Date: Thu, 27 Nov 2014 04:58:48 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogcHlkb2M6IFJlbW92?= =?utf-8?q?e_mention_of_=27-g=27_command_line_option=2C_document_its_remov?= =?utf-8?b?YWwu?= Message-ID: <20141127045848.84299.77260@psf.io> https://hg.python.org/cpython/rev/6fce36de7916 changeset: 93609:6fce36de7916 branch: 3.4 parent: 93604:812f31cbe6be user: Zachary Ware date: Wed Nov 26 22:57:35 2014 -0600 summary: pydoc: Remove mention of '-g' command line option, document its removal. files: Doc/library/pydoc.rst | 10 ++++------ 1 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Doc/library/pydoc.rst b/Doc/library/pydoc.rst --- a/Doc/library/pydoc.rst +++ b/Doc/library/pydoc.rst @@ -66,11 +66,6 @@ documentation at ``http://localhost:1234/`` in your preferred Web browser. Specifying ``0`` as the port number will select an arbitrary unused port. -:program:`pydoc -g` will start the server and additionally bring up a -small :mod:`tkinter`\ -based graphical interface to help you search for -documentation pages. The ``-g`` option is deprecated, since the server can -now be controlled directly from HTTP clients. - :program:`pydoc -b` will start the server and additionally open a web browser to a module index page. Each served page has a navigation bar at the top where you can *Get* help on an individual item, *Search* all modules with a @@ -90,7 +85,10 @@ Reference Manual pages. .. versionchanged:: 3.2 - Added the ``-b`` option, deprecated the ``-g`` option. + Added the ``-b`` option. + +.. versionchanged:: 3.3 + The ``-g`` command line option was removed. .. versionchanged:: 3.4 :mod:`pydoc` now uses :func:`inspect.signature` rather than -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 06:06:06 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 27 Nov 2014 05:06:06 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_remove_tautolo?= =?utf-8?q?gical_condition_=28closes_=2322954=29?= Message-ID: <20141127050606.55099.26922@psf.io> https://hg.python.org/cpython/rev/a498e599ce6a changeset: 93611:a498e599ce6a branch: 3.4 parent: 93609:6fce36de7916 user: Benjamin Peterson date: Wed Nov 26 23:03:11 2014 -0600 summary: remove tautological condition (closes #22954) files: Objects/typeobject.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5342,7 +5342,7 @@ "%s.__new__(%s) is not safe, use %s.__new__()", type->tp_name, subtype->tp_name, - staticbase == NULL ? "?" : staticbase->tp_name); + staticbase->tp_name); return NULL; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 06:06:07 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 27 Nov 2014 05:06:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjMjI5NTQp?= Message-ID: <20141127050606.116326.99526@psf.io> https://hg.python.org/cpython/rev/d502b5d60e00 changeset: 93612:d502b5d60e00 parent: 93610:7fe7ef360941 parent: 93611:a498e599ce6a user: Benjamin Peterson date: Wed Nov 26 23:03:34 2014 -0600 summary: merge 3.4 (#22954) files: Objects/typeobject.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5381,7 +5381,7 @@ "%s.__new__(%s) is not safe, use %s.__new__()", type->tp_name, subtype->tp_name, - staticbase == NULL ? "?" : staticbase->tp_name); + staticbase->tp_name); return NULL; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 06:06:07 2014 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 27 Nov 2014 05:06:07 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_remove_tautolo?= =?utf-8?q?gical_condition_=28closes_=2322954=29?= Message-ID: <20141127050607.116318.5445@psf.io> https://hg.python.org/cpython/rev/ec21b41e588b changeset: 93613:ec21b41e588b branch: 2.7 parent: 93606:3f5ac9f43027 user: Benjamin Peterson date: Wed Nov 26 23:03:11 2014 -0600 summary: remove tautological condition (closes #22954) files: Objects/typeobject.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4798,7 +4798,7 @@ "%s.__new__(%s) is not safe, use %s.__new__()", type->tp_name, subtype->tp_name, - staticbase == NULL ? "?" : staticbase->tp_name); + staticbase->tp_name); return NULL; } -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 06:18:14 2014 From: python-checkins at python.org (ethan.furman) Date: Thu, 27 Nov 2014 05:18:14 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogKDMuNCkgSXNzdWUy?= =?utf-8?q?2780=3A_reword_NotImplemented_docs_to_emphasise_should?= Message-ID: <20141127051811.84291.12017@psf.io> https://hg.python.org/cpython/rev/ebb8865dcf54 changeset: 93614:ebb8865dcf54 branch: 3.4 parent: 93611:a498e599ce6a user: Ethan Furman date: Wed Nov 26 21:15:35 2014 -0800 summary: (3.4) Issue22780: reword NotImplemented docs to emphasise should files: Doc/library/constants.rst | 21 ++++++++++++++++++--- Doc/library/numbers.rst | 2 ++ Doc/reference/datamodel.rst | 7 ++++++- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Doc/library/constants.rst b/Doc/library/constants.rst --- a/Doc/library/constants.rst +++ b/Doc/library/constants.rst @@ -26,9 +26,24 @@ .. data:: NotImplemented - Special value which can be returned by the "rich comparison" special methods - (:meth:`__eq__`, :meth:`__lt__`, and friends), to indicate that the comparison - is not implemented with respect to the other type. + Special value which should be returned by the binary special methods + (e.g. :meth:`__eq__`, :meth:`__lt__`, :meth:`__add__`, :meth:`__rsub__`, + etc.) to indicate that the operation is not implemented with respect to + the other type; may be returned by the in-place binary special methods + (e.g. :meth:`__imul__`, :meth:`__iand__`, etc.) for the same purpose. + Its truth value is true. + +.. note:: + + When ``NotImplemented`` is returned, the interpreter will then try the + reflected operation on the other type, or some other fallback, depending + on the operator. If all attempted operations return ``NotImplemented``, the + interpreter will raise an appropriate exception. + + See + :ref:`implementing-the-arithmetic-operations` + for more details. + .. data:: Ellipsis diff --git a/Doc/library/numbers.rst b/Doc/library/numbers.rst --- a/Doc/library/numbers.rst +++ b/Doc/library/numbers.rst @@ -110,6 +110,8 @@ MyFoo.register(Real) +.. _implementing-the-arithmetic-operations: + Implementing the arithmetic operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -154,11 +154,16 @@ This type has a single value. There is a single object with this value. This object is accessed through the built-in name ``NotImplemented``. Numeric methods - and rich comparison methods may return this value if they do not implement the + and rich comparison methods should return this value if they do not implement the operation for the operands provided. (The interpreter will then try the reflected operation, or some other fallback, depending on the operator.) Its truth value is true. + See + :ref:`implementing-the-arithmetic-operations` + for more details. + + Ellipsis .. index:: object: Ellipsis -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 06:18:15 2014 From: python-checkins at python.org (ethan.furman) Date: Thu, 27 Nov 2014 05:18:15 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue22780=3A_reword_NotImplemented_docs_to_emphasise_sh?= =?utf-8?q?ould?= Message-ID: <20141127051811.116320.10028@psf.io> https://hg.python.org/cpython/rev/b6ee02acaae9 changeset: 93615:b6ee02acaae9 parent: 93612:d502b5d60e00 parent: 93614:ebb8865dcf54 user: Ethan Furman date: Wed Nov 26 21:17:53 2014 -0800 summary: Issue22780: reword NotImplemented docs to emphasise should files: Doc/library/constants.rst | 20 +++++++++++++++++--- Doc/library/numbers.rst | 2 ++ Doc/reference/datamodel.rst | 7 ++++++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Doc/library/constants.rst b/Doc/library/constants.rst --- a/Doc/library/constants.rst +++ b/Doc/library/constants.rst @@ -26,9 +26,23 @@ .. data:: NotImplemented - Special value which should be returned by the special methods - (:meth:`__eq__`, :meth:`__lt__`, :meth:`__add__`, etc.) to indicate - that the operation is not implemented with respect to the other type. + Special value which should be returned by the binary special methods + (e.g. :meth:`__eq__`, :meth:`__lt__`, :meth:`__add__`, :meth:`__rsub__`, + etc.) to indicate that the operation is not implemented with respect to + the other type; may be returned by the in-place binary special methods + (e.g. :meth:`__imul__`, :meth:`__iand__`, etc.) for the same purpose. + Its truth value is true. + +.. note:: + + When ``NotImplemented`` is returned, the interpreter will then try the + reflected operation on the other type, or some other fallback, depending + on the operator. If all attempted operations return ``NotImplemented``, the + interpreter will raise an appropriate exception. + + See + :ref:`implementing-the-arithmetic-operations` + for more details. .. data:: Ellipsis diff --git a/Doc/library/numbers.rst b/Doc/library/numbers.rst --- a/Doc/library/numbers.rst +++ b/Doc/library/numbers.rst @@ -110,6 +110,8 @@ MyFoo.register(Real) +.. _implementing-the-arithmetic-operations: + Implementing the arithmetic operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -154,11 +154,16 @@ This type has a single value. There is a single object with this value. This object is accessed through the built-in name ``NotImplemented``. Numeric methods - and rich comparison methods may return this value if they do not implement the + and rich comparison methods should return this value if they do not implement the operation for the operands provided. (The interpreter will then try the reflected operation, or some other fallback, depending on the operator.) Its truth value is true. + See + :ref:`implementing-the-arithmetic-operations` + for more details. + + Ellipsis .. index:: object: Ellipsis -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 06:57:09 2014 From: python-checkins at python.org (zach.ware) Date: Thu, 27 Nov 2014 05:57:09 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E4?= Message-ID: <20141127055708.84283.93631@psf.io> https://hg.python.org/cpython/rev/1c97f373fe49 changeset: 93617:1c97f373fe49 parent: 93615:b6ee02acaae9 parent: 93616:589c65dc528c user: Zachary Ware date: Wed Nov 26 23:56:10 2014 -0600 summary: Merge with 3.4 files: Doc/library/pydoc.rst | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Doc/library/pydoc.rst b/Doc/library/pydoc.rst --- a/Doc/library/pydoc.rst +++ b/Doc/library/pydoc.rst @@ -51,6 +51,10 @@ executed on that occasion. Use an ``if __name__ == '__main__':`` guard to only execute code when a file is invoked as a script and not just imported. +When printing output to the console, :program:`pydoc` attempts to paginate the +output for easier reading. If the :envvar:`PAGER` environment variable is set, +:program:`pydoc` will use its value as a pagination program. + Specifying a ``-w`` flag before the argument will cause HTML documentation to be written out to a file in the current directory, instead of displaying text on the console. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 06:57:09 2014 From: python-checkins at python.org (zach.ware) Date: Thu, 27 Nov 2014 05:57:09 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogcHlkb2M6IEFkZCBh?= =?utf-8?q?_note_about_setting_PAGER_to_affect_console_output_pagination?= =?utf-8?q?=2E?= Message-ID: <20141127055707.55107.68912@psf.io> https://hg.python.org/cpython/rev/589c65dc528c changeset: 93616:589c65dc528c branch: 3.4 parent: 93614:ebb8865dcf54 user: Zachary Ware date: Wed Nov 26 23:44:25 2014 -0600 summary: pydoc: Add a note about setting PAGER to affect console output pagination. Suggested by James Lowden on docs at . files: Doc/library/pydoc.rst | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Doc/library/pydoc.rst b/Doc/library/pydoc.rst --- a/Doc/library/pydoc.rst +++ b/Doc/library/pydoc.rst @@ -51,6 +51,10 @@ executed on that occasion. Use an ``if __name__ == '__main__':`` guard to only execute code when a file is invoked as a script and not just imported. +When printing output to the console, :program:`pydoc` attempts to paginate the +output for easier reading. If the :envvar:`PAGER` environment variable is set, +:program:`pydoc` will use its value as a pagination program. + Specifying a ``-w`` flag before the argument will cause HTML documentation to be written out to a file in the current directory, instead of displaying text on the console. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 06:59:20 2014 From: python-checkins at python.org (zach.ware) Date: Thu, 27 Nov 2014 05:59:20 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogcHlkb2M6IEFkZCBh?= =?utf-8?q?_note_about_setting_PAGER_to_affect_console_output_pagination?= =?utf-8?q?=2E?= Message-ID: <20141127055919.116308.76474@psf.io> https://hg.python.org/cpython/rev/ac65f90c1214 changeset: 93618:ac65f90c1214 branch: 2.7 parent: 93613:ec21b41e588b user: Zachary Ware date: Wed Nov 26 23:44:25 2014 -0600 summary: pydoc: Add a note about setting PAGER to affect console output pagination. Suggested by James Lowden on docs at . files: Doc/library/pydoc.rst | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Doc/library/pydoc.rst b/Doc/library/pydoc.rst --- a/Doc/library/pydoc.rst +++ b/Doc/library/pydoc.rst @@ -53,6 +53,10 @@ executed on that occasion. Use an ``if __name__ == '__main__':`` guard to only execute code when a file is invoked as a script and not just imported. +When printing output to the console, :program:`pydoc` attempts to paginate the +output for easier reading. If the :envvar:`PAGER` environment variable is set, +:program:`pydoc` will use its value as a pagination program. + Specifying a ``-w`` flag before the argument will cause HTML documentation to be written out to a file in the current directory, instead of displaying text on the console. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 07:07:37 2014 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 27 Nov 2014 06:07:37 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_New_section_with_contextlib_e?= =?utf-8?q?xample_=28Isaac_Schwabacher=29=2E?= Message-ID: <20141127060734.69805.43675@psf.io> https://hg.python.org/peps/rev/bb0f11810471 changeset: 5623:bb0f11810471 user: Guido van Rossum date: Wed Nov 26 22:07:29 2014 -0800 summary: New section with contextlib example (Isaac Schwabacher). Other additions by Chris, including renumbered references. files: pep-0479.txt | 105 ++++++++++++++++++++++++++++++-------- 1 files changed, 82 insertions(+), 23 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -37,12 +37,39 @@ generator to terminate silently. (When another exception is raised, a traceback is printed pinpointing the cause of the problem.) -The proposal also clears up the confusion about how to terminate a -generator: the proper way is ``return``, not ``raise StopIteration``. +This is particularly pernicious in combination with the ``yield from`` +construct of PEP 380 [1]_, as it breaks the abstraction that a +subgenerator may be factored out of a generator. That PEP notes this +limitation, but notes that "use cases for these [are] rare to non- +existent". Unfortunately while intentional use is rare, it is easy to +stumble on these cases by accident:: -Finally, the proposal reduces the difference between list + @contextlib.contextmanager + def transaction(): + begin() + try: + yield from do_it() + except: + rollback() + raise + else: + commit() + + def do_it(): + initial_preparations() + yield + finishing_touches() + +Here factoring out ``do_it`` into a subgenerator has introduced a +subtle bug: if the wrapped block raises ``StopIteration``, under the +current behavior ``do_it`` will fail but report success by returning +normally, causing the failed transaction to be committed! Similarly +problematic behavior occurs when an ``asyncio`` coroutine raises +``StopIteration``, causing it to terminate silently. + +Additionally, the proposal reduces the difference between list comprehensions and generator expressions, preventing surprises such as -the one that started this discussion [1]_. Henceforth, the following +the one that started this discussion [2]_. Henceforth, the following statements will produce the same result if either produces a result at all:: @@ -56,6 +83,10 @@ will raise an exception at this point (albeit ``RuntimeError`` in the first case and ``StopIteration`` in the second). +Finally, the proposal also clears up the confusion about how to +terminate a generator: the proper way is ``return``, not +``raise StopIteration``. + Background information ====================== @@ -77,7 +108,7 @@ If a ``StopIteration`` is about to bubble out of a generator frame, it is replaced with ``RuntimeError``, which causes the ``next()`` call (which invoked the generator) to fail, passing that exception out. -From then on it's just like any old exception. [3]_ +From then on it's just like any old exception. [4]_ This affects the third outcome listed above, without altering any other effects. Furthermore, it only affects this outcome when the @@ -119,10 +150,10 @@ This change will affect existing code that depends on ``StopIteration`` bubbling up. The pure Python reference -implementation of ``groupby`` [2]_ currently has comments "Exit on +implementation of ``groupby`` [3]_ currently has comments "Exit on ``StopIteration``" where it is expected that the exception will propagate and then be handled. This will be unusual, but not unknown, -and such constructs will fail. Other examples abound, e.g. [5]_, [6]_. +and such constructs will fail. Other examples abound, e.g. [6]_, [7]_. (Nick Coghlan comments: """If you wanted to factor out a helper function that terminated the generator you'd have to do "return @@ -235,6 +266,31 @@ to find the end marker in the inner loop, which will now raise ``RuntimeError``). +This effect of ``StopIteration`` has been used to cut a generator +expression short, creating a form of ``takewhile``:: + + def stop(): + raise StopIteration + print(list(x for x in range(10) if x < 5 or stop())) + # prints [0, 1, 2, 3, 4] + +Under the current proposal, this form of non-local flow control is +not supported, and would have to be rewritten in statement form:: + + def gen(): + for x in range(10): + if x >= 5: return + yield x + print(list(gen())) + # prints [0, 1, 2, 3, 4] + +While this is a small loss of functionality, it is functionality that +often comes at the cost of readability, and just as ``lambda`` has +restrictions compared to ``def``, so does a generator expression have +restrictions compared to a generator function. In many cases, the +transformation to full generator function will be trivially easy, and +may improve structural clarity. + Explanation of generators, iterators, and StopIteration ======================================================= @@ -330,7 +386,7 @@ return statement. The inspiration for this alternative proposal was Nick's observation -[7]_ that if an ``asyncio`` coroutine [8]_ accidentally raises +[8]_ that if an ``asyncio`` coroutine [9]_ accidentally raises ``StopIteration``, it currently terminates silently, which may present a hard-to-debug mystery to the developer. The main proposal turns such accidents into clearly distinguishable ``RuntimeError`` exceptions, @@ -367,7 +423,7 @@ Converting the exception inside next() -------------------------------------- -Mark Shannon suggested [11]_ that the problem could be solved in +Mark Shannon suggested [12]_ that the problem could be solved in ``next()`` rather than at the boundary of generator functions. By having ``next()`` catch ``StopIteration`` and raise instead ``ValueError``, all unexpected ``StopIteration`` bubbling would be @@ -384,11 +440,11 @@ ========= Unofficial and apocryphal statistics suggest that this is seldom, if -ever, a problem. [4]_ Code does exist which relies on the current -behaviour (e.g. [2]_, [5]_, [6]_), and there is the concern that this +ever, a problem. [5]_ Code does exist which relies on the current +behaviour (e.g. [3]_, [6]_, [7]_), and there is the concern that this would be unnecessary code churn to achieve little or no gain. -Steven D'Aprano started an informal survey on comp.lang.python [9]_; +Steven D'Aprano started an informal survey on comp.lang.python [10]_; at the time of writing only two responses have been received: one was in favor of changing list comprehensions to match generator expressions (!), the other was in favor of this PEP's main proposal. @@ -411,37 +467,40 @@ References ========== -.. [1] Initial mailing list comment +.. [1] PEP 380 - Syntax for Delegating to a Subgenerator + (https://www.python.org/dev/peps/pep-0380) + +.. [2] Initial mailing list comment (https://mail.python.org/pipermail/python-ideas/2014-November/029906.html) -.. [2] Pure Python implementation of groupby +.. [3] Pure Python implementation of groupby (https://docs.python.org/3/library/itertools.html#itertools.groupby) -.. [3] Proposal by GvR +.. [4] Proposal by GvR (https://mail.python.org/pipermail/python-ideas/2014-November/029953.html) -.. [4] Response by Steven D'Aprano +.. [5] Response by Steven D'Aprano (https://mail.python.org/pipermail/python-ideas/2014-November/029994.html) -.. [5] Split a sequence or generator using a predicate +.. [6] Split a sequence or generator using a predicate (http://code.activestate.com/recipes/578416-split-a-sequence-or-generator-using-a-predicate/) -.. [6] wrap unbounded generator to restrict its output +.. [7] wrap unbounded generator to restrict its output (http://code.activestate.com/recipes/66427-wrap-unbounded-generator-to-restrict-its-output/) -.. [7] Post from Nick Coghlan mentioning asyncio +.. [8] Post from Nick Coghlan mentioning asyncio (https://mail.python.org/pipermail/python-ideas/2014-November/029961.html) -.. [8] Coroutines in asyncio +.. [9] Coroutines in asyncio (https://docs.python.org/3/library/asyncio-task.html#coroutines) -.. [9] Thread on comp.lang.python started by Steven D'Aprano +.. [10] Thread on comp.lang.python started by Steven D'Aprano (https://mail.python.org/pipermail/python-list/2014-November/680757.html) -.. [10] Tracker issue with Proof-of-Concept patch +.. [11] Tracker issue with Proof-of-Concept patch (http://bugs.python.org/issue22906) -.. [11] Post from Mark Shannon with alternate proposal +.. [12] Post from Mark Shannon with alternate proposal (https://mail.python.org/pipermail/python-dev/2014-November/137129.html) Copyright -- Repository URL: https://hg.python.org/peps From solipsis at pitrou.net Thu Nov 27 10:35:11 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 27 Nov 2014 10:35:11 +0100 Subject: [Python-checkins] Daily reference leaks (c8bcede1b37a): sum=3 Message-ID: results for c8bcede1b37a on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogNSqzH_', '-x'] From python-checkins at python.org Thu Nov 27 15:54:55 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Nov 2014 14:54:55 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322609=3A_Constructors_and_update_methods_of_map?= =?utf-8?q?ping_classes_in_the?= Message-ID: <20141127145452.69793.1999@psf.io> https://hg.python.org/cpython/rev/88ab046fdd8a changeset: 93620:88ab046fdd8a parent: 93617:1c97f373fe49 parent: 93619:816c15fe5812 user: Serhiy Storchaka date: Thu Nov 27 16:35:26 2014 +0200 summary: Issue #22609: Constructors and update methods of mapping classes in the collections module now accept the self keyword argument. files: Lib/_collections_abc.py | 35 ++++++------ Lib/collections/__init__.py | 47 ++++++++++++++--- Lib/test/test_collections.py | 64 ++++++++++++++++++++++- Misc/NEWS | 3 + 4 files changed, 121 insertions(+), 28 deletions(-) diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -592,23 +592,24 @@ If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v In either case, this is followed by: for k, v in F.items(): D[k] = v ''' - if len(args) > 2: - raise TypeError("update() takes at most 2 positional " - "arguments ({} given)".format(len(args))) - elif not args: - raise TypeError("update() takes at least 1 argument (0 given)") - self = args[0] - other = args[1] if len(args) >= 2 else () - - if isinstance(other, Mapping): - for key in other: - self[key] = other[key] - elif hasattr(other, "keys"): - for key in other.keys(): - self[key] = other[key] - else: - for key, value in other: - self[key] = value + if not args: + raise TypeError("descriptor 'update' of 'MutableMapping' object " + "needs an argument") + self, *args = args + if len(args) > 1: + raise TypeError('update expected at most 1 arguments, got %d' % + len(args)) + if args: + other = args[0] + if isinstance(other, Mapping): + for key in other: + self[key] = other[key] + elif hasattr(other, "keys"): + for key in other.keys(): + self[key] = other[key] + else: + for key, value in other: + self[key] = value for key, value in kwds.items(): self[key] = value diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -55,12 +55,16 @@ # Individual links are kept alive by the hard reference in self.__map. # Those hard references disappear when a key is deleted from an OrderedDict. - def __init__(self, *args, **kwds): + def __init__(*args, **kwds): '''Initialize an ordered dictionary. The signature is the same as regular dictionaries, but keyword arguments are not recommended because their insertion order is arbitrary. ''' + if not args: + raise TypeError("descriptor '__init__' of 'OrderedDict' object " + "needs an argument") + self, *args = args if len(args) > 1: raise TypeError('expected at most 1 arguments, got %d' % len(args)) try: @@ -479,7 +483,7 @@ # http://code.activestate.com/recipes/259174/ # Knuth, TAOCP Vol. II section 4.6.3 - def __init__(self, iterable=None, **kwds): + def __init__(*args, **kwds): '''Create a new, empty Counter object. And if given, count elements from an input iterable. Or, initialize the count from another mapping of elements to their counts. @@ -490,8 +494,14 @@ >>> c = Counter(a=4, b=2) # a new counter from keyword args ''' - super().__init__() - self.update(iterable, **kwds) + if not args: + raise TypeError("descriptor '__init__' of 'Counter' object " + "needs an argument") + self, *args = args + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + super(Counter, self).__init__() + self.update(*args, **kwds) def __missing__(self, key): 'The count of elements not in the Counter is zero.' @@ -542,7 +552,7 @@ raise NotImplementedError( 'Counter.fromkeys() is undefined. Use Counter(iterable) instead.') - def update(self, iterable=None, **kwds): + def update(*args, **kwds): '''Like dict.update() but add counts instead of replacing them. Source can be an iterable, a dictionary, or another Counter instance. @@ -562,6 +572,13 @@ # contexts. Instead, we implement straight-addition. Both the inputs # and outputs are allowed to contain zero and negative counts. + if not args: + raise TypeError("descriptor 'update' of 'Counter' object " + "needs an argument") + self, *args = args + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + iterable = args[0] if args else None if iterable is not None: if isinstance(iterable, Mapping): if self: @@ -569,13 +586,13 @@ for elem, count in iterable.items(): self[elem] = count + self_get(elem, 0) else: - super().update(iterable) # fast path when counter is empty + super(Counter, self).update(iterable) # fast path when counter is empty else: _count_elements(self, iterable) if kwds: self.update(kwds) - def subtract(self, iterable=None, **kwds): + def subtract(*args, **kwds): '''Like dict.update() but subtracts counts instead of replacing them. Counts can be reduced below zero. Both the inputs and outputs are allowed to contain zero and negative counts. @@ -591,6 +608,13 @@ -1 ''' + if not args: + raise TypeError("descriptor 'subtract' of 'Counter' object " + "needs an argument") + self, *args = args + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + iterable = args[0] if args else None if iterable is not None: self_get = self.get if isinstance(iterable, Mapping): @@ -898,7 +922,14 @@ class UserDict(MutableMapping): # Start by filling-out the abstract methods - def __init__(self, dict=None, **kwargs): + def __init__(*args, **kwargs): + if not args: + raise TypeError("descriptor '__init__' of 'UserDict' object " + "needs an argument") + self, *args = args + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + dict = args[0] if args else None self.data = {} if dict is not None: self.update(dict) diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -1137,6 +1137,28 @@ self.assertEqual(c.setdefault('e', 5), 5) self.assertEqual(c['e'], 5) + def test_init(self): + self.assertEqual(list(Counter(self=42).items()), [('self', 42)]) + self.assertEqual(list(Counter(iterable=42).items()), [('iterable', 42)]) + self.assertEqual(list(Counter(iterable=None).items()), [('iterable', None)]) + self.assertRaises(TypeError, Counter, 42) + self.assertRaises(TypeError, Counter, (), ()) + self.assertRaises(TypeError, Counter.__init__) + + def test_update(self): + c = Counter() + c.update(self=42) + self.assertEqual(list(c.items()), [('self', 42)]) + c = Counter() + c.update(iterable=42) + self.assertEqual(list(c.items()), [('iterable', 42)]) + c = Counter() + c.update(iterable=None) + self.assertEqual(list(c.items()), [('iterable', None)]) + self.assertRaises(TypeError, Counter().update, 42) + self.assertRaises(TypeError, Counter().update, {}, {}) + self.assertRaises(TypeError, Counter.update) + def test_copying(self): # Check that counters are copyable, deepcopyable, picklable, and #have a repr/eval round-trip @@ -1258,6 +1280,16 @@ c.subtract('aaaabbcce') self.assertEqual(c, Counter(a=-1, b=0, c=-1, d=1, e=-1)) + c = Counter() + c.subtract(self=42) + self.assertEqual(list(c.items()), [('self', -42)]) + c = Counter() + c.subtract(iterable=42) + self.assertEqual(list(c.items()), [('iterable', -42)]) + self.assertRaises(TypeError, Counter().subtract, 42) + self.assertRaises(TypeError, Counter().subtract, {}, {}) + self.assertRaises(TypeError, Counter.subtract) + def test_unary(self): c = Counter(a=-5, b=0, c=5, d=10, e=15,g=40) self.assertEqual(dict(+c), dict(c=5, d=10, e=15, g=40)) @@ -1308,8 +1340,11 @@ c=3, e=5).items()), pairs) # mixed input # make sure no positional args conflict with possible kwdargs - self.assertEqual(inspect.getargspec(OrderedDict.__dict__['__init__']).args, - ['self']) + self.assertEqual(list(OrderedDict(self=42).items()), [('self', 42)]) + self.assertEqual(list(OrderedDict(other=42).items()), [('other', 42)]) + self.assertRaises(TypeError, OrderedDict, 42) + self.assertRaises(TypeError, OrderedDict, (), ()) + self.assertRaises(TypeError, OrderedDict.__init__) # Make sure that direct calls to __init__ do not clear previous contents d = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 44), ('e', 55)]) @@ -1354,6 +1389,10 @@ self.assertEqual(list(d.items()), [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)]) + self.assertRaises(TypeError, OrderedDict().update, 42) + self.assertRaises(TypeError, OrderedDict().update, (), ()) + self.assertRaises(TypeError, OrderedDict.update) + def test_abc(self): self.assertIsInstance(OrderedDict(), MutableMapping) self.assertTrue(issubclass(OrderedDict, MutableMapping)) @@ -1600,6 +1639,24 @@ d = self._empty_mapping() self.assertRaises(KeyError, d.popitem) +class TestUserDict(unittest.TestCase): + + def test_init(self): + self.assertEqual(list(UserDict(self=42).items()), [('self', 42)]) + self.assertEqual(list(UserDict(dict=42).items()), [('dict', 42)]) + self.assertEqual(list(UserDict(dict=None).items()), [('dict', None)]) + self.assertRaises(TypeError, UserDict, 42) + self.assertRaises(TypeError, UserDict, (), ()) + self.assertRaises(TypeError, UserDict.__init__) + + def test_update(self): + d = UserDict() + d.update(self=42) + self.assertEqual(list(d.items()), [('self', 42)]) + self.assertRaises(TypeError, UserDict().update, 42) + self.assertRaises(TypeError, UserDict().update, {}, {}) + self.assertRaises(TypeError, UserDict.update) + ################################################################################ ### Run tests @@ -1611,7 +1668,8 @@ NamedTupleDocs = doctest.DocTestSuite(module=collections) test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs, TestCollectionABCs, TestCounter, TestChainMap, - TestOrderedDict, GeneralMappingTests, SubclassMappingTests] + TestOrderedDict, GeneralMappingTests, SubclassMappingTests, + TestUserDict,] support.run_unittest(*test_classes) support.run_doctest(collections, verbose) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -191,6 +191,9 @@ Library ------- +- Issue #22609: Constructors and update methods of mapping classes in the + collections module now accept the self keyword argument. + - Issue #22940: Add readline.append_history_file. - Issue #19676: Added the "namereplace" error handler. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 15:54:54 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Nov 2014 14:54:54 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyNjA5?= =?utf-8?q?=3A_Constructors_and_update_methods_of_mapping_classes_in_the?= Message-ID: <20141127145452.69789.53068@psf.io> https://hg.python.org/cpython/rev/816c15fe5812 changeset: 93619:816c15fe5812 branch: 3.4 parent: 93616:589c65dc528c user: Serhiy Storchaka date: Thu Nov 27 16:25:51 2014 +0200 summary: Issue #22609: Constructors and update methods of mapping classes in the collections module now accept the self keyword argument. files: Lib/_collections_abc.py | 35 ++++++------ Lib/collections/__init__.py | 47 ++++++++++++++--- Lib/test/test_collections.py | 64 ++++++++++++++++++++++- Misc/NEWS | 3 + 4 files changed, 121 insertions(+), 28 deletions(-) diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -584,23 +584,24 @@ If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v In either case, this is followed by: for k, v in F.items(): D[k] = v ''' - if len(args) > 2: - raise TypeError("update() takes at most 2 positional " - "arguments ({} given)".format(len(args))) - elif not args: - raise TypeError("update() takes at least 1 argument (0 given)") - self = args[0] - other = args[1] if len(args) >= 2 else () - - if isinstance(other, Mapping): - for key in other: - self[key] = other[key] - elif hasattr(other, "keys"): - for key in other.keys(): - self[key] = other[key] - else: - for key, value in other: - self[key] = value + if not args: + raise TypeError("descriptor 'update' of 'MutableMapping' object " + "needs an argument") + self, *args = args + if len(args) > 1: + raise TypeError('update expected at most 1 arguments, got %d' % + len(args)) + if args: + other = args[0] + if isinstance(other, Mapping): + for key in other: + self[key] = other[key] + elif hasattr(other, "keys"): + for key in other.keys(): + self[key] = other[key] + else: + for key, value in other: + self[key] = value for key, value in kwds.items(): self[key] = value diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -38,12 +38,16 @@ # Individual links are kept alive by the hard reference in self.__map. # Those hard references disappear when a key is deleted from an OrderedDict. - def __init__(self, *args, **kwds): + def __init__(*args, **kwds): '''Initialize an ordered dictionary. The signature is the same as regular dictionaries, but keyword arguments are not recommended because their insertion order is arbitrary. ''' + if not args: + raise TypeError("descriptor '__init__' of 'OrderedDict' object " + "needs an argument") + self, *args = args if len(args) > 1: raise TypeError('expected at most 1 arguments, got %d' % len(args)) try: @@ -450,7 +454,7 @@ # http://code.activestate.com/recipes/259174/ # Knuth, TAOCP Vol. II section 4.6.3 - def __init__(self, iterable=None, **kwds): + def __init__(*args, **kwds): '''Create a new, empty Counter object. And if given, count elements from an input iterable. Or, initialize the count from another mapping of elements to their counts. @@ -461,8 +465,14 @@ >>> c = Counter(a=4, b=2) # a new counter from keyword args ''' - super().__init__() - self.update(iterable, **kwds) + if not args: + raise TypeError("descriptor '__init__' of 'Counter' object " + "needs an argument") + self, *args = args + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + super(Counter, self).__init__() + self.update(*args, **kwds) def __missing__(self, key): 'The count of elements not in the Counter is zero.' @@ -513,7 +523,7 @@ raise NotImplementedError( 'Counter.fromkeys() is undefined. Use Counter(iterable) instead.') - def update(self, iterable=None, **kwds): + def update(*args, **kwds): '''Like dict.update() but add counts instead of replacing them. Source can be an iterable, a dictionary, or another Counter instance. @@ -533,6 +543,13 @@ # contexts. Instead, we implement straight-addition. Both the inputs # and outputs are allowed to contain zero and negative counts. + if not args: + raise TypeError("descriptor 'update' of 'Counter' object " + "needs an argument") + self, *args = args + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + iterable = args[0] if args else None if iterable is not None: if isinstance(iterable, Mapping): if self: @@ -540,13 +557,13 @@ for elem, count in iterable.items(): self[elem] = count + self_get(elem, 0) else: - super().update(iterable) # fast path when counter is empty + super(Counter, self).update(iterable) # fast path when counter is empty else: _count_elements(self, iterable) if kwds: self.update(kwds) - def subtract(self, iterable=None, **kwds): + def subtract(*args, **kwds): '''Like dict.update() but subtracts counts instead of replacing them. Counts can be reduced below zero. Both the inputs and outputs are allowed to contain zero and negative counts. @@ -562,6 +579,13 @@ -1 ''' + if not args: + raise TypeError("descriptor 'subtract' of 'Counter' object " + "needs an argument") + self, *args = args + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + iterable = args[0] if args else None if iterable is not None: self_get = self.get if isinstance(iterable, Mapping): @@ -869,7 +893,14 @@ class UserDict(MutableMapping): # Start by filling-out the abstract methods - def __init__(self, dict=None, **kwargs): + def __init__(*args, **kwargs): + if not args: + raise TypeError("descriptor '__init__' of 'UserDict' object " + "needs an argument") + self, *args = args + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + dict = args[0] if args else None self.data = {} if dict is not None: self.update(dict) diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -1084,6 +1084,28 @@ self.assertEqual(c.setdefault('e', 5), 5) self.assertEqual(c['e'], 5) + def test_init(self): + self.assertEqual(list(Counter(self=42).items()), [('self', 42)]) + self.assertEqual(list(Counter(iterable=42).items()), [('iterable', 42)]) + self.assertEqual(list(Counter(iterable=None).items()), [('iterable', None)]) + self.assertRaises(TypeError, Counter, 42) + self.assertRaises(TypeError, Counter, (), ()) + self.assertRaises(TypeError, Counter.__init__) + + def test_update(self): + c = Counter() + c.update(self=42) + self.assertEqual(list(c.items()), [('self', 42)]) + c = Counter() + c.update(iterable=42) + self.assertEqual(list(c.items()), [('iterable', 42)]) + c = Counter() + c.update(iterable=None) + self.assertEqual(list(c.items()), [('iterable', None)]) + self.assertRaises(TypeError, Counter().update, 42) + self.assertRaises(TypeError, Counter().update, {}, {}) + self.assertRaises(TypeError, Counter.update) + def test_copying(self): # Check that counters are copyable, deepcopyable, picklable, and #have a repr/eval round-trip @@ -1205,6 +1227,16 @@ c.subtract('aaaabbcce') self.assertEqual(c, Counter(a=-1, b=0, c=-1, d=1, e=-1)) + c = Counter() + c.subtract(self=42) + self.assertEqual(list(c.items()), [('self', -42)]) + c = Counter() + c.subtract(iterable=42) + self.assertEqual(list(c.items()), [('iterable', -42)]) + self.assertRaises(TypeError, Counter().subtract, 42) + self.assertRaises(TypeError, Counter().subtract, {}, {}) + self.assertRaises(TypeError, Counter.subtract) + def test_unary(self): c = Counter(a=-5, b=0, c=5, d=10, e=15,g=40) self.assertEqual(dict(+c), dict(c=5, d=10, e=15, g=40)) @@ -1255,8 +1287,11 @@ c=3, e=5).items()), pairs) # mixed input # make sure no positional args conflict with possible kwdargs - self.assertEqual(inspect.getargspec(OrderedDict.__dict__['__init__']).args, - ['self']) + self.assertEqual(list(OrderedDict(self=42).items()), [('self', 42)]) + self.assertEqual(list(OrderedDict(other=42).items()), [('other', 42)]) + self.assertRaises(TypeError, OrderedDict, 42) + self.assertRaises(TypeError, OrderedDict, (), ()) + self.assertRaises(TypeError, OrderedDict.__init__) # Make sure that direct calls to __init__ do not clear previous contents d = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 44), ('e', 55)]) @@ -1301,6 +1336,10 @@ self.assertEqual(list(d.items()), [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)]) + self.assertRaises(TypeError, OrderedDict().update, 42) + self.assertRaises(TypeError, OrderedDict().update, (), ()) + self.assertRaises(TypeError, OrderedDict.update) + def test_abc(self): self.assertIsInstance(OrderedDict(), MutableMapping) self.assertTrue(issubclass(OrderedDict, MutableMapping)) @@ -1532,6 +1571,24 @@ d = self._empty_mapping() self.assertRaises(KeyError, d.popitem) +class TestUserDict(unittest.TestCase): + + def test_init(self): + self.assertEqual(list(UserDict(self=42).items()), [('self', 42)]) + self.assertEqual(list(UserDict(dict=42).items()), [('dict', 42)]) + self.assertEqual(list(UserDict(dict=None).items()), [('dict', None)]) + self.assertRaises(TypeError, UserDict, 42) + self.assertRaises(TypeError, UserDict, (), ()) + self.assertRaises(TypeError, UserDict.__init__) + + def test_update(self): + d = UserDict() + d.update(self=42) + self.assertEqual(list(d.items()), [('self', 42)]) + self.assertRaises(TypeError, UserDict().update, 42) + self.assertRaises(TypeError, UserDict().update, {}, {}) + self.assertRaises(TypeError, UserDict.update) + ################################################################################ ### Run tests @@ -1543,7 +1600,8 @@ NamedTupleDocs = doctest.DocTestSuite(module=collections) test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs, TestCollectionABCs, TestCounter, TestChainMap, - TestOrderedDict, GeneralMappingTests, SubclassMappingTests] + TestOrderedDict, GeneralMappingTests, SubclassMappingTests, + TestUserDict,] support.run_unittest(*test_classes) support.run_doctest(collections, verbose) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,9 @@ Library ------- +- Issue #22609: Constructors and update methods of mapping classes in the + collections module now accept the self keyword argument. + - Issue #22788: Add *context* parameter to logging.handlers.HTTPHandler. - Issue #22921: Allow SSLContext to take the *hostname* parameter even if -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 16:50:52 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Nov 2014 15:50:52 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322609=3A_Revert_changes_in_UserDict=2E_They_con?= =?utf-8?q?flicted_with_existing_tests=2E?= Message-ID: <20141127155048.84277.87297@psf.io> https://hg.python.org/cpython/rev/167d51a54de2 changeset: 93622:167d51a54de2 parent: 93620:88ab046fdd8a parent: 93621:cd1ead4feddf user: Serhiy Storchaka date: Thu Nov 27 17:46:15 2014 +0200 summary: Issue #22609: Revert changes in UserDict. They conflicted with existing tests. files: Lib/collections/__init__.py | 9 +-------- Lib/test/test_collections.py | 21 +-------------------- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -922,14 +922,7 @@ class UserDict(MutableMapping): # Start by filling-out the abstract methods - def __init__(*args, **kwargs): - if not args: - raise TypeError("descriptor '__init__' of 'UserDict' object " - "needs an argument") - self, *args = args - if len(args) > 1: - raise TypeError('expected at most 1 arguments, got %d' % len(args)) - dict = args[0] if args else None + def __init__(self, dict=None, **kwargs): self.data = {} if dict is not None: self.update(dict) diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -1639,24 +1639,6 @@ d = self._empty_mapping() self.assertRaises(KeyError, d.popitem) -class TestUserDict(unittest.TestCase): - - def test_init(self): - self.assertEqual(list(UserDict(self=42).items()), [('self', 42)]) - self.assertEqual(list(UserDict(dict=42).items()), [('dict', 42)]) - self.assertEqual(list(UserDict(dict=None).items()), [('dict', None)]) - self.assertRaises(TypeError, UserDict, 42) - self.assertRaises(TypeError, UserDict, (), ()) - self.assertRaises(TypeError, UserDict.__init__) - - def test_update(self): - d = UserDict() - d.update(self=42) - self.assertEqual(list(d.items()), [('self', 42)]) - self.assertRaises(TypeError, UserDict().update, 42) - self.assertRaises(TypeError, UserDict().update, {}, {}) - self.assertRaises(TypeError, UserDict.update) - ################################################################################ ### Run tests @@ -1668,8 +1650,7 @@ NamedTupleDocs = doctest.DocTestSuite(module=collections) test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs, TestCollectionABCs, TestCounter, TestChainMap, - TestOrderedDict, GeneralMappingTests, SubclassMappingTests, - TestUserDict,] + TestOrderedDict, GeneralMappingTests, SubclassMappingTests] support.run_unittest(*test_classes) support.run_doctest(collections, verbose) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 16:50:52 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Nov 2014 15:50:52 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyNjA5?= =?utf-8?q?=3A_Revert_changes_in_UserDict=2E_They_conflicted_with_existing?= =?utf-8?q?_tests=2E?= Message-ID: <20141127155048.69799.16536@psf.io> https://hg.python.org/cpython/rev/cd1ead4feddf changeset: 93621:cd1ead4feddf branch: 3.4 parent: 93619:816c15fe5812 user: Serhiy Storchaka date: Thu Nov 27 17:45:44 2014 +0200 summary: Issue #22609: Revert changes in UserDict. They conflicted with existing tests. files: Lib/collections/__init__.py | 9 +-------- Lib/test/test_collections.py | 21 +-------------------- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -893,14 +893,7 @@ class UserDict(MutableMapping): # Start by filling-out the abstract methods - def __init__(*args, **kwargs): - if not args: - raise TypeError("descriptor '__init__' of 'UserDict' object " - "needs an argument") - self, *args = args - if len(args) > 1: - raise TypeError('expected at most 1 arguments, got %d' % len(args)) - dict = args[0] if args else None + def __init__(self, dict=None, **kwargs): self.data = {} if dict is not None: self.update(dict) diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -1571,24 +1571,6 @@ d = self._empty_mapping() self.assertRaises(KeyError, d.popitem) -class TestUserDict(unittest.TestCase): - - def test_init(self): - self.assertEqual(list(UserDict(self=42).items()), [('self', 42)]) - self.assertEqual(list(UserDict(dict=42).items()), [('dict', 42)]) - self.assertEqual(list(UserDict(dict=None).items()), [('dict', None)]) - self.assertRaises(TypeError, UserDict, 42) - self.assertRaises(TypeError, UserDict, (), ()) - self.assertRaises(TypeError, UserDict.__init__) - - def test_update(self): - d = UserDict() - d.update(self=42) - self.assertEqual(list(d.items()), [('self', 42)]) - self.assertRaises(TypeError, UserDict().update, 42) - self.assertRaises(TypeError, UserDict().update, {}, {}) - self.assertRaises(TypeError, UserDict.update) - ################################################################################ ### Run tests @@ -1600,8 +1582,7 @@ NamedTupleDocs = doctest.DocTestSuite(module=collections) test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs, TestCollectionABCs, TestCounter, TestChainMap, - TestOrderedDict, GeneralMappingTests, SubclassMappingTests, - TestUserDict,] + TestOrderedDict, GeneralMappingTests, SubclassMappingTests] support.run_unittest(*test_classes) support.run_doctest(collections, verbose) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 18:05:28 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Nov 2014 17:05:28 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIyNjA5?= =?utf-8?q?=3A_Constructors_and_update_methods_of_mapping_classes_in_the?= Message-ID: <20141127170510.84283.88391@psf.io> https://hg.python.org/cpython/rev/3dfe4f0c626b changeset: 93623:3dfe4f0c626b branch: 2.7 parent: 93618:ac65f90c1214 user: Serhiy Storchaka date: Thu Nov 27 19:02:56 2014 +0200 summary: Issue #22609: Constructors and update methods of mapping classes in the collections module now accept the self keyword argument. files: Lib/_abcoll.py | 34 ++++++++++-------- Lib/collections.py | 38 ++++++++++++++++++-- Lib/test/test_collections.py | 43 ++++++++++++++++++++++- Misc/NEWS | 3 + 4 files changed, 95 insertions(+), 23 deletions(-) diff --git a/Lib/_abcoll.py b/Lib/_abcoll.py --- a/Lib/_abcoll.py +++ b/Lib/_abcoll.py @@ -548,23 +548,25 @@ If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v In either case, this is followed by: for k, v in F.items(): D[k] = v ''' - if len(args) > 2: - raise TypeError("update() takes at most 2 positional " - "arguments ({} given)".format(len(args))) - elif not args: - raise TypeError("update() takes at least 1 argument (0 given)") + if not args: + raise TypeError("descriptor 'update' of 'MutableMapping' object " + "needs an argument") self = args[0] - other = args[1] if len(args) >= 2 else () - - if isinstance(other, Mapping): - for key in other: - self[key] = other[key] - elif hasattr(other, "keys"): - for key in other.keys(): - self[key] = other[key] - else: - for key, value in other: - self[key] = value + args = args[1:] + if len(args) > 1: + raise TypeError('update expected at most 1 arguments, got %d' % + len(args)) + if args: + other = args[0] + if isinstance(other, Mapping): + for key in other: + self[key] = other[key] + elif hasattr(other, "keys"): + for key in other.keys(): + self[key] = other[key] + else: + for key, value in other: + self[key] = value for key, value in kwds.items(): self[key] = value diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -35,12 +35,17 @@ # The sentinel element never gets deleted (this simplifies the algorithm). # Each link is stored as a list of length three: [PREV, NEXT, KEY]. - def __init__(self, *args, **kwds): + def __init__(*args, **kwds): '''Initialize an ordered dictionary. The signature is the same as regular dictionaries, but keyword arguments are not recommended because their insertion order is arbitrary. ''' + if not args: + raise TypeError("descriptor '__init__' of 'OrderedDict' object " + "needs an argument") + self = args[0] + args = args[1:] if len(args) > 1: raise TypeError('expected at most 1 arguments, got %d' % len(args)) try: @@ -438,7 +443,7 @@ # http://code.activestate.com/recipes/259174/ # Knuth, TAOCP Vol. II section 4.6.3 - def __init__(self, iterable=None, **kwds): + def __init__(*args, **kwds): '''Create a new, empty Counter object. And if given, count elements from an input iterable. Or, initialize the count from another mapping of elements to their counts. @@ -449,8 +454,15 @@ >>> c = Counter(a=4, b=2) # a new counter from keyword args ''' + if not args: + raise TypeError("descriptor '__init__' of 'Counter' object " + "needs an argument") + self = args[0] + args = args[1:] + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) super(Counter, self).__init__() - self.update(iterable, **kwds) + self.update(*args, **kwds) def __missing__(self, key): 'The count of elements not in the Counter is zero.' @@ -501,7 +513,7 @@ raise NotImplementedError( 'Counter.fromkeys() is undefined. Use Counter(iterable) instead.') - def update(self, iterable=None, **kwds): + def update(*args, **kwds): '''Like dict.update() but add counts instead of replacing them. Source can be an iterable, a dictionary, or another Counter instance. @@ -521,6 +533,14 @@ # contexts. Instead, we implement straight-addition. Both the inputs # and outputs are allowed to contain zero and negative counts. + if not args: + raise TypeError("descriptor 'update' of 'Counter' object " + "needs an argument") + self = args[0] + args = args[1:] + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + iterable = args[0] if args else None if iterable is not None: if isinstance(iterable, Mapping): if self: @@ -536,7 +556,7 @@ if kwds: self.update(kwds) - def subtract(self, iterable=None, **kwds): + def subtract(*args, **kwds): '''Like dict.update() but subtracts counts instead of replacing them. Counts can be reduced below zero. Both the inputs and outputs are allowed to contain zero and negative counts. @@ -552,6 +572,14 @@ -1 ''' + if not args: + raise TypeError("descriptor 'subtract' of 'Counter' object " + "needs an argument") + self = args[0] + args = args[1:] + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + iterable = args[0] if args else None if iterable is not None: self_get = self.get if isinstance(iterable, Mapping): diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -905,6 +905,28 @@ self.assertEqual(c.setdefault('e', 5), 5) self.assertEqual(c['e'], 5) + def test_init(self): + self.assertEqual(list(Counter(self=42).items()), [('self', 42)]) + self.assertEqual(list(Counter(iterable=42).items()), [('iterable', 42)]) + self.assertEqual(list(Counter(iterable=None).items()), [('iterable', None)]) + self.assertRaises(TypeError, Counter, 42) + self.assertRaises(TypeError, Counter, (), ()) + self.assertRaises(TypeError, Counter.__init__) + + def test_update(self): + c = Counter() + c.update(self=42) + self.assertEqual(list(c.items()), [('self', 42)]) + c = Counter() + c.update(iterable=42) + self.assertEqual(list(c.items()), [('iterable', 42)]) + c = Counter() + c.update(iterable=None) + self.assertEqual(list(c.items()), [('iterable', None)]) + self.assertRaises(TypeError, Counter().update, 42) + self.assertRaises(TypeError, Counter().update, {}, {}) + self.assertRaises(TypeError, Counter.update) + def test_copying(self): # Check that counters are copyable, deepcopyable, picklable, and #have a repr/eval round-trip @@ -1006,6 +1028,16 @@ c.subtract('aaaabbcce') self.assertEqual(c, Counter(a=-1, b=0, c=-1, d=1, e=-1)) + c = Counter() + c.subtract(self=42) + self.assertEqual(list(c.items()), [('self', -42)]) + c = Counter() + c.subtract(iterable=42) + self.assertEqual(list(c.items()), [('iterable', -42)]) + self.assertRaises(TypeError, Counter().subtract, 42) + self.assertRaises(TypeError, Counter().subtract, {}, {}) + self.assertRaises(TypeError, Counter.subtract) + class TestOrderedDict(unittest.TestCase): def test_init(self): @@ -1019,8 +1051,11 @@ c=3, e=5).items()), pairs) # mixed input # make sure no positional args conflict with possible kwdargs - self.assertEqual(inspect.getargspec(OrderedDict.__dict__['__init__']).args, - ['self']) + self.assertEqual(list(OrderedDict(self=42).items()), [('self', 42)]) + self.assertEqual(list(OrderedDict(other=42).items()), [('other', 42)]) + self.assertRaises(TypeError, OrderedDict, 42) + self.assertRaises(TypeError, OrderedDict, (), ()) + self.assertRaises(TypeError, OrderedDict.__init__) # Make sure that direct calls to __init__ do not clear previous contents d = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 44), ('e', 55)]) @@ -1065,6 +1100,10 @@ self.assertEqual(list(d.items()), [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)]) + self.assertRaises(TypeError, OrderedDict().update, 42) + self.assertRaises(TypeError, OrderedDict().update, (), ()) + self.assertRaises(TypeError, OrderedDict.update) + def test_abc(self): self.assertIsInstance(OrderedDict(), MutableMapping) self.assertTrue(issubclass(OrderedDict, MutableMapping)) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ Library ------- +- Issue #22609: Constructors and update methods of mapping classes in the + collections module now accept the self keyword argument. + What's New in Python 2.7.9 release candidate 1? =============================================== -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 18:51:14 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Nov 2014 17:51:14 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2321514=3A_The_documentation_of_the_json_module_n?= =?utf-8?q?ow_refers_to_new_JSON_RFC?= Message-ID: <20141127175113.69789.83438@psf.io> https://hg.python.org/cpython/rev/aced2548345a changeset: 93626:aced2548345a parent: 93622:167d51a54de2 parent: 93625:89bb4384f1e1 user: Serhiy Storchaka date: Thu Nov 27 19:45:31 2014 +0200 summary: Issue #21514: The documentation of the json module now refers to new JSON RFC 7159 instead of obsoleted RFC 4627. files: Doc/library/json.rst | 111 ++++++++++++++++++++---------- Misc/NEWS | 3 + 2 files changed, 75 insertions(+), 39 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -7,9 +7,11 @@ .. sectionauthor:: Bob Ippolito `JSON (JavaScript Object Notation) `_, specified by -:rfc:`4627`, is a lightweight data interchange format based on a subset of -`JavaScript `_ syntax (`ECMA-262 3rd -edition `_). +:rfc:`7159` (which obsoletes :rfc:`4627`) and by +`ECMA-404 `_, +is a lightweight data interchange format inspired by +`JavaScript `_ object literal syntax +(although it is not a strict subset of JavaScript [#rfc-errata]_ ). :mod:`json` exposes an API familiar to users of the standard library :mod:`marshal` and :mod:`pickle` modules. @@ -467,18 +469,18 @@ mysocket.write(chunk) -Standard Compliance -------------------- +Standard Compliance and Interoperability +---------------------------------------- -The JSON format is specified by :rfc:`4627`. This section details this -module's level of compliance with the RFC. For simplicity, -:class:`JSONEncoder` and :class:`JSONDecoder` subclasses, and parameters other -than those explicitly mentioned, are not considered. +The JSON format is specified by :rfc:`7159` and by +`ECMA-404 `_. +This section details this module's level of compliance with the RFC. +For simplicity, :class:`JSONEncoder` and :class:`JSONDecoder` subclasses, and +parameters other than those explicitly mentioned, are not considered. This module does not comply with the RFC in a strict fashion, implementing some extensions that are valid JavaScript but not valid JSON. In particular: -- Top-level non-object, non-array values are accepted and output; - Infinite and NaN number values are accepted and output; - Repeated names within an object are accepted, and only the value of the last name-value pair is used. @@ -490,8 +492,8 @@ Character Encodings ^^^^^^^^^^^^^^^^^^^ -The RFC recommends that JSON be represented using either UTF-8, UTF-16, or -UTF-32, with UTF-8 being the default. +The RFC requires that JSON be represented using either UTF-8, UTF-16, or +UTF-32, with UTF-8 being the recommended default for maximum interoperability. As permitted, though not required, by the RFC, this module's serializer sets *ensure_ascii=True* by default, thus escaping the output so that the resulting @@ -499,34 +501,20 @@ Other than the *ensure_ascii* parameter, this module is defined strictly in terms of conversion between Python objects and -:class:`Unicode strings `, and thus does not otherwise address the issue -of character encodings. +:class:`Unicode strings `, and thus does not otherwise directly address +the issue of character encodings. +The RFC prohibits adding a byte order mark (BOM) to the start of a JSON text, +and this module's serializer does not add a BOM to its output. +The RFC permits, but does not require, JSON deserializers to ignore an initial +BOM in their input. This module's deserializer raises a :exc:`ValueError` +when an initial BOM is present. -Top-level Non-Object, Non-Array Values -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The RFC specifies that the top-level value of a JSON text must be either a -JSON object or array (Python :class:`dict` or :class:`list`). This module's -deserializer also accepts input texts consisting solely of a -JSON null, boolean, number, or string value:: - - >>> just_a_json_string = '"spam and eggs"' # Not by itself a valid JSON text - >>> json.loads(just_a_json_string) - 'spam and eggs' - -This module itself does not include a way to request that such input texts be -regarded as illegal. Likewise, this module's serializer also accepts single -Python :data:`None`, :class:`bool`, numeric, and :class:`str` -values as input and will generate output texts consisting solely of a top-level -JSON null, boolean, number, or string value without raising an exception:: - - >>> neither_a_list_nor_a_dict = "spam and eggs" - >>> json.dumps(neither_a_list_nor_a_dict) # The result is not a valid JSON text - '"spam and eggs"' - -This module's serializer does not itself include a way to enforce the -aforementioned constraint. +The RFC does not explicitly forbid JSON strings which contain byte sequences +that don't correspond to valid Unicode characters (e.g. unpaired UTF-16 +surrogates), but it does note that they may cause interoperability problems. +By default, this module accepts and outputs (when present in the original +:class:`str`) codepoints for such sequences. Infinite and NaN Number Values @@ -556,7 +544,7 @@ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The RFC specifies that the names within a JSON object should be unique, but -does not specify how repeated names in JSON objects should be handled. By +does not mandate how repeated names in JSON objects should be handled. By default, this module does not raise an exception; instead, it ignores all but the last name-value pair for a given name:: @@ -566,6 +554,42 @@ The *object_pairs_hook* parameter can be used to alter this behavior. + +Top-level Non-Object, Non-Array Values +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The old version of JSON specified by the obsolete :rfc:`4627` required that +the top-level value of a JSON text must be either a JSON object or array +(Python :class:`dict` or :class:`list`), and could not be a JSON null, +boolean, number, or string value. :rfc:`7159` removed that restriction, and +this module does not and has never implemented that restriction in either its +serializer or its deserializer. + +Regardless, for maximum interoperability, you may wish to voluntarily adhere +to the restriction yourself. + + +Implementation Limitations +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Some JSON deserializer implementations may set limits on: + +* the size of accepted JSON texts +* the maximum level of nesting of JSON objects and arrays +* the range and precision of JSON numbers +* the content and maximum length of JSON strings + +This module does not impose any such limits beyond those of the relevant +Python datatypes themselves or the Python interpreter itself. + +When serializing to JSON, beware any such limitations in applications that may +consume your JSON. In particular, it is common for JSON numbers to be +deserialized into IEEE 754 double precision numbers and thus subject to that +representation's range and precision limitations. This is especially relevant +when serializing Python :class:`int` values of extremely large magnitude, or +when serializing instances of "exotic" numerical types such as +:class:`decimal.Decimal`. + .. highlight:: bash .. module:: json.tool @@ -627,3 +651,12 @@ .. cmdoption:: -h, --help Show the help message. + + +.. rubric:: Footnotes + +.. [#rfc-errata] As noted in `the errata for RFC 7159 + `_, + JSON permits literal U+2028 (LINE SEPARATOR) and + U+2029 (PARAGRAPH SEPARATOR) characters in strings, whereas JavaScript + (as of ECMAScript Edition 5.1) does not. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1300,6 +1300,9 @@ Documentation ------------- +- Issue #21514: The documentation of the json module now refers to new JSON RFC + 7159 instead of obsoleted RFC 4627. + - Issue #21777: The binary sequence methods on bytes and bytearray are now documented explicitly, rather than assuming users will be able to derive the expected behaviour from the behaviour of the corresponding str methods. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 18:51:14 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Nov 2014 17:51:14 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIxNTE0?= =?utf-8?q?=3A_The_documentation_of_the_json_module_now_refers_to_new_JSON?= =?utf-8?q?_RFC?= Message-ID: <20141127175113.116320.51790@psf.io> https://hg.python.org/cpython/rev/89bb4384f1e1 changeset: 93625:89bb4384f1e1 branch: 3.4 parent: 93621:cd1ead4feddf user: Serhiy Storchaka date: Thu Nov 27 19:41:47 2014 +0200 summary: Issue #21514: The documentation of the json module now refers to new JSON RFC 7159 instead of obsoleted RFC 4627. files: Doc/library/json.rst | 111 ++++++++++++++++++++---------- Misc/NEWS | 6 + 2 files changed, 78 insertions(+), 39 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -7,9 +7,11 @@ .. sectionauthor:: Bob Ippolito `JSON (JavaScript Object Notation) `_, specified by -:rfc:`4627`, is a lightweight data interchange format based on a subset of -`JavaScript `_ syntax (`ECMA-262 3rd -edition `_). +:rfc:`7159` (which obsoletes :rfc:`4627`) and by +`ECMA-404 `_, +is a lightweight data interchange format inspired by +`JavaScript `_ object literal syntax +(although it is not a strict subset of JavaScript [#rfc-errata]_ ). :mod:`json` exposes an API familiar to users of the standard library :mod:`marshal` and :mod:`pickle` modules. @@ -465,18 +467,18 @@ mysocket.write(chunk) -Standard Compliance -------------------- +Standard Compliance and Interoperability +---------------------------------------- -The JSON format is specified by :rfc:`4627`. This section details this -module's level of compliance with the RFC. For simplicity, -:class:`JSONEncoder` and :class:`JSONDecoder` subclasses, and parameters other -than those explicitly mentioned, are not considered. +The JSON format is specified by :rfc:`7159` and by +`ECMA-404 `_. +This section details this module's level of compliance with the RFC. +For simplicity, :class:`JSONEncoder` and :class:`JSONDecoder` subclasses, and +parameters other than those explicitly mentioned, are not considered. This module does not comply with the RFC in a strict fashion, implementing some extensions that are valid JavaScript but not valid JSON. In particular: -- Top-level non-object, non-array values are accepted and output; - Infinite and NaN number values are accepted and output; - Repeated names within an object are accepted, and only the value of the last name-value pair is used. @@ -488,8 +490,8 @@ Character Encodings ^^^^^^^^^^^^^^^^^^^ -The RFC recommends that JSON be represented using either UTF-8, UTF-16, or -UTF-32, with UTF-8 being the default. +The RFC requires that JSON be represented using either UTF-8, UTF-16, or +UTF-32, with UTF-8 being the recommended default for maximum interoperability. As permitted, though not required, by the RFC, this module's serializer sets *ensure_ascii=True* by default, thus escaping the output so that the resulting @@ -497,34 +499,20 @@ Other than the *ensure_ascii* parameter, this module is defined strictly in terms of conversion between Python objects and -:class:`Unicode strings `, and thus does not otherwise address the issue -of character encodings. +:class:`Unicode strings `, and thus does not otherwise directly address +the issue of character encodings. +The RFC prohibits adding a byte order mark (BOM) to the start of a JSON text, +and this module's serializer does not add a BOM to its output. +The RFC permits, but does not require, JSON deserializers to ignore an initial +BOM in their input. This module's deserializer raises a :exc:`ValueError` +when an initial BOM is present. -Top-level Non-Object, Non-Array Values -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The RFC specifies that the top-level value of a JSON text must be either a -JSON object or array (Python :class:`dict` or :class:`list`). This module's -deserializer also accepts input texts consisting solely of a -JSON null, boolean, number, or string value:: - - >>> just_a_json_string = '"spam and eggs"' # Not by itself a valid JSON text - >>> json.loads(just_a_json_string) - 'spam and eggs' - -This module itself does not include a way to request that such input texts be -regarded as illegal. Likewise, this module's serializer also accepts single -Python :data:`None`, :class:`bool`, numeric, and :class:`str` -values as input and will generate output texts consisting solely of a top-level -JSON null, boolean, number, or string value without raising an exception:: - - >>> neither_a_list_nor_a_dict = "spam and eggs" - >>> json.dumps(neither_a_list_nor_a_dict) # The result is not a valid JSON text - '"spam and eggs"' - -This module's serializer does not itself include a way to enforce the -aforementioned constraint. +The RFC does not explicitly forbid JSON strings which contain byte sequences +that don't correspond to valid Unicode characters (e.g. unpaired UTF-16 +surrogates), but it does note that they may cause interoperability problems. +By default, this module accepts and outputs (when present in the original +:class:`str`) codepoints for such sequences. Infinite and NaN Number Values @@ -554,7 +542,7 @@ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The RFC specifies that the names within a JSON object should be unique, but -does not specify how repeated names in JSON objects should be handled. By +does not mandate how repeated names in JSON objects should be handled. By default, this module does not raise an exception; instead, it ignores all but the last name-value pair for a given name:: @@ -563,3 +551,48 @@ {'x': 3} The *object_pairs_hook* parameter can be used to alter this behavior. + + +Top-level Non-Object, Non-Array Values +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The old version of JSON specified by the obsolete :rfc:`4627` required that +the top-level value of a JSON text must be either a JSON object or array +(Python :class:`dict` or :class:`list`), and could not be a JSON null, +boolean, number, or string value. :rfc:`7159` removed that restriction, and +this module does not and has never implemented that restriction in either its +serializer or its deserializer. + +Regardless, for maximum interoperability, you may wish to voluntarily adhere +to the restriction yourself. + + +Implementation Limitations +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Some JSON deserializer implementations may set limits on: + +* the size of accepted JSON texts +* the maximum level of nesting of JSON objects and arrays +* the range and precision of JSON numbers +* the content and maximum length of JSON strings + +This module does not impose any such limits beyond those of the relevant +Python datatypes themselves or the Python interpreter itself. + +When serializing to JSON, beware any such limitations in applications that may +consume your JSON. In particular, it is common for JSON numbers to be +deserialized into IEEE 754 double precision numbers and thus subject to that +representation's range and precision limitations. This is especially relevant +when serializing Python :class:`int` values of extremely large magnitude, or +when serializing instances of "exotic" numerical types such as +:class:`decimal.Decimal`. + + +.. rubric:: Footnotes + +.. [#rfc-errata] As noted in `the errata for RFC 7159 + `_, + JSON permits literal U+2028 (LINE SEPARATOR) and + U+2029 (PARAGRAPH SEPARATOR) characters in strings, whereas JavaScript + (as of ECMAScript Edition 5.1) does not. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -175,6 +175,12 @@ - Issue #17219: Add library build dir for Python extension cross-builds. +Documentation +------------- + +- Issue #21514: The documentation of the json module now refers to new JSON RFC + 7159 instead of obsoleted RFC 4627. + Windows ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 18:51:14 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Nov 2014 17:51:14 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIxNTE0?= =?utf-8?q?=3A_The_documentation_of_the_json_module_now_refers_to_new_JSON?= =?utf-8?q?_RFC?= Message-ID: <20141127175112.116332.77812@psf.io> https://hg.python.org/cpython/rev/7e534e18a99a changeset: 93624:7e534e18a99a branch: 2.7 user: Serhiy Storchaka date: Thu Nov 27 19:41:34 2014 +0200 summary: Issue #21514: The documentation of the json module now refers to new JSON RFC 7159 instead of obsoleted RFC 4627. files: Doc/library/json.rst | 113 +++++++++++++++++++----------- Misc/NEWS | 6 + 2 files changed, 77 insertions(+), 42 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -8,9 +8,11 @@ .. versionadded:: 2.6 `JSON (JavaScript Object Notation) `_, specified by -:rfc:`4627`, is a lightweight data interchange format based on a subset of -`JavaScript `_ syntax (`ECMA-262 3rd -edition `_). +:rfc:`7159` (which obsoletes :rfc:`4627`) and by +`ECMA-404 `_, +is a lightweight data interchange format inspired by +`JavaScript `_ object literal syntax +(although it is not a strict subset of JavaScript [#rfc-errata]_ ). :mod:`json` exposes an API familiar to users of the standard library :mod:`marshal` and :mod:`pickle` modules. @@ -485,18 +487,18 @@ mysocket.write(chunk) -Standard Compliance -------------------- +Standard Compliance and Interoperability +---------------------------------------- -The JSON format is specified by :rfc:`4627`. This section details this -module's level of compliance with the RFC. For simplicity, -:class:`JSONEncoder` and :class:`JSONDecoder` subclasses, and parameters other -than those explicitly mentioned, are not considered. +The JSON format is specified by :rfc:`7159` and by +`ECMA-404 `_. +This section details this module's level of compliance with the RFC. +For simplicity, :class:`JSONEncoder` and :class:`JSONDecoder` subclasses, and +parameters other than those explicitly mentioned, are not considered. This module does not comply with the RFC in a strict fashion, implementing some extensions that are valid JavaScript but not valid JSON. In particular: -- Top-level non-object, non-array values are accepted and output; - Infinite and NaN number values are accepted and output; - Repeated names within an object are accepted, and only the value of the last name-value pair is used. @@ -508,48 +510,30 @@ Character Encodings ^^^^^^^^^^^^^^^^^^^ -The RFC recommends that JSON be represented using either UTF-8, UTF-16, or -UTF-32, with UTF-8 being the default. Accordingly, this module uses UTF-8 as -the default for its *encoding* parameter. +The RFC requires that JSON be represented using either UTF-8, UTF-16, or +UTF-32, with UTF-8 being the recommended default for maximum interoperability. +Accordingly, this module uses UTF-8 as the default for its *encoding* parameter. This module's deserializer only directly works with ASCII-compatible encodings; UTF-16, UTF-32, and other ASCII-incompatible encodings require the use of workarounds described in the documentation for the deserializer's *encoding* parameter. -The RFC also non-normatively describes a limited encoding detection technique -for JSON texts; this module's deserializer does not implement this or any other -kind of encoding detection. - As permitted, though not required, by the RFC, this module's serializer sets *ensure_ascii=True* by default, thus escaping the output so that the resulting strings only contain ASCII characters. +The RFC prohibits adding a byte order mark (BOM) to the start of a JSON text, +and this module's serializer does not add a BOM to its output. +The RFC permits, but does not require, JSON deserializers to ignore an initial +BOM in their input. This module's deserializer raises a :exc:`ValueError` +when an initial BOM is present. -Top-level Non-Object, Non-Array Values -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The RFC specifies that the top-level value of a JSON text must be either a -JSON object or array (Python :class:`dict` or :class:`list`). This module's -deserializer also accepts input texts consisting solely of a -JSON null, boolean, number, or string value:: - - >>> just_a_json_string = '"spam and eggs"' # Not by itself a valid JSON text - >>> json.loads(just_a_json_string) - u'spam and eggs' - -This module itself does not include a way to request that such input texts be -regarded as illegal. Likewise, this module's serializer also accepts single -Python :data:`None`, :class:`bool`, numeric, and :class:`str` -values as input and will generate output texts consisting solely of a top-level -JSON null, boolean, number, or string value without raising an exception:: - - >>> neither_a_list_nor_a_dict = u"spam and eggs" - >>> json.dumps(neither_a_list_nor_a_dict) # The result is not a valid JSON text - '"spam and eggs"' - -This module's serializer does not itself include a way to enforce the -aforementioned constraint. +The RFC does not explicitly forbid JSON strings which contain byte sequences +that don't correspond to valid Unicode characters (e.g. unpaired UTF-16 +surrogates), but it does note that they may cause interoperability problems. +By default, this module accepts and outputs (when present in the original +:class:`str`) codepoints for such sequences. Infinite and NaN Number Values @@ -579,7 +563,7 @@ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The RFC specifies that the names within a JSON object should be unique, but -does not specify how repeated names in JSON objects should be handled. By +does not mandate how repeated names in JSON objects should be handled. By default, this module does not raise an exception; instead, it ignores all but the last name-value pair for a given name:: @@ -588,3 +572,48 @@ {u'x': 3} The *object_pairs_hook* parameter can be used to alter this behavior. + + +Top-level Non-Object, Non-Array Values +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The old version of JSON specified by the obsolete :rfc:`4627` required that +the top-level value of a JSON text must be either a JSON object or array +(Python :class:`dict` or :class:`list`), and could not be a JSON null, +boolean, number, or string value. :rfc:`7159` removed that restriction, and +this module does not and has never implemented that restriction in either its +serializer or its deserializer. + +Regardless, for maximum interoperability, you may wish to voluntarily adhere +to the restriction yourself. + + +Implementation Limitations +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Some JSON deserializer implementations may set limits on: + +* the size of accepted JSON texts +* the maximum level of nesting of JSON objects and arrays +* the range and precision of JSON numbers +* the content and maximum length of JSON strings + +This module does not impose any such limits beyond those of the relevant +Python datatypes themselves or the Python interpreter itself. + +When serializing to JSON, beware any such limitations in applications that may +consume your JSON. In particular, it is common for JSON numbers to be +deserialized into IEEE 754 double precision numbers and thus subject to that +representation's range and precision limitations. This is especially relevant +when serializing Python :class:`int` values of extremely large magnitude, or +when serializing instances of "exotic" numerical types such as +:class:`decimal.Decimal`. + + +.. rubric:: Footnotes + +.. [#rfc-errata] As noted in `the errata for RFC 7159 + `_, + JSON permits literal U+2028 (LINE SEPARATOR) and + U+2029 (PARAGRAPH SEPARATOR) characters in strings, whereas JavaScript + (as of ECMAScript Edition 5.1) does not. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -16,6 +16,12 @@ - Issue #22609: Constructors and update methods of mapping classes in the collections module now accept the self keyword argument. +Documentation +------------- + +- Issue #21514: The documentation of the json module now refers to new JSON RFC + 7159 instead of obsoleted RFC 4627. + What's New in Python 2.7.9 release candidate 1? =============================================== -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 21:17:10 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Nov 2014 20:17:10 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyOTE1?= =?utf-8?q?=3A_SAX_parser_now_supports_files_opened_with_file_descriptor_o?= =?utf-8?q?r?= Message-ID: <20141127201700.84279.1868@psf.io> https://hg.python.org/cpython/rev/27ae1a476ef7 changeset: 93627:27ae1a476ef7 branch: 3.4 parent: 93625:89bb4384f1e1 user: Serhiy Storchaka date: Thu Nov 27 22:13:16 2014 +0200 summary: Issue #22915: SAX parser now supports files opened with file descriptor or bytes path. files: Lib/test/test_sax.py | 24 ++++++++++++++++++++++++ Lib/xml/sax/saxutils.py | 2 +- Misc/NEWS | 3 +++ 3 files changed, 28 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py --- a/Lib/test/test_sax.py +++ b/Lib/test/test_sax.py @@ -648,6 +648,30 @@ self.assertEqual(result.getvalue(), xml_test_out) + def test_expat_binary_file_bytes_name(self): + fname = os.fsencode(TEST_XMLFILE) + parser = create_parser() + result = BytesIO() + xmlgen = XMLGenerator(result) + + parser.setContentHandler(xmlgen) + with open(fname, 'rb') as f: + parser.parse(f) + + self.assertEqual(result.getvalue(), xml_test_out) + + def test_expat_binary_file_int_name(self): + parser = create_parser() + result = BytesIO() + xmlgen = XMLGenerator(result) + + parser.setContentHandler(xmlgen) + with open(TEST_XMLFILE, 'rb') as f: + with open(f.fileno(), 'rb', closefd=False) as f2: + parser.parse(f2) + + self.assertEqual(result.getvalue(), xml_test_out) + # ===== DTDHandler support class TestDTDHandler: diff --git a/Lib/xml/sax/saxutils.py b/Lib/xml/sax/saxutils.py --- a/Lib/xml/sax/saxutils.py +++ b/Lib/xml/sax/saxutils.py @@ -346,7 +346,7 @@ f = source source = xmlreader.InputSource() source.setByteStream(f) - if hasattr(f, "name"): + if hasattr(f, "name") and isinstance(f.name, str): source.setSystemId(f.name) if source.getByteStream() is None: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,9 @@ Library ------- +- Issue #22915: SAX parser now supports files opened with file descriptor or + bytes path. + - Issue #22609: Constructors and update methods of mapping classes in the collections module now accept the self keyword argument. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 21:17:10 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Nov 2014 20:17:10 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322915=3A_SAX_parser_now_supports_files_opened_w?= =?utf-8?q?ith_file_descriptor_or?= Message-ID: <20141127201700.126772.97775@psf.io> https://hg.python.org/cpython/rev/ce9881eecfb4 changeset: 93628:ce9881eecfb4 parent: 93626:aced2548345a parent: 93627:27ae1a476ef7 user: Serhiy Storchaka date: Thu Nov 27 22:14:30 2014 +0200 summary: Issue #22915: SAX parser now supports files opened with file descriptor or bytes path. files: Lib/test/test_sax.py | 24 ++++++++++++++++++++++++ Lib/xml/sax/saxutils.py | 2 +- Misc/NEWS | 3 +++ 3 files changed, 28 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py --- a/Lib/test/test_sax.py +++ b/Lib/test/test_sax.py @@ -648,6 +648,30 @@ self.assertEqual(result.getvalue(), xml_test_out) + def test_expat_binary_file_bytes_name(self): + fname = os.fsencode(TEST_XMLFILE) + parser = create_parser() + result = BytesIO() + xmlgen = XMLGenerator(result) + + parser.setContentHandler(xmlgen) + with open(fname, 'rb') as f: + parser.parse(f) + + self.assertEqual(result.getvalue(), xml_test_out) + + def test_expat_binary_file_int_name(self): + parser = create_parser() + result = BytesIO() + xmlgen = XMLGenerator(result) + + parser.setContentHandler(xmlgen) + with open(TEST_XMLFILE, 'rb') as f: + with open(f.fileno(), 'rb', closefd=False) as f2: + parser.parse(f2) + + self.assertEqual(result.getvalue(), xml_test_out) + # ===== DTDHandler support class TestDTDHandler: diff --git a/Lib/xml/sax/saxutils.py b/Lib/xml/sax/saxutils.py --- a/Lib/xml/sax/saxutils.py +++ b/Lib/xml/sax/saxutils.py @@ -346,7 +346,7 @@ f = source source = xmlreader.InputSource() source.setByteStream(f) - if hasattr(f, "name"): + if hasattr(f, "name") and isinstance(f.name, str): source.setSystemId(f.name) if source.getByteStream() is None: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -191,6 +191,9 @@ Library ------- +- Issue #22915: SAX parser now supports files opened with file descriptor or + bytes path. + - Issue #22609: Constructors and update methods of mapping classes in the collections module now accept the self keyword argument. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 23:15:45 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Nov 2014 22:15:45 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4OTA1?= =?utf-8?q?=3A_=22pydoc_-p_0=22_now_outputs_actually_used_port=2E__Based_o?= =?utf-8?q?n_patch_by?= Message-ID: <20141127221544.55107.24130@psf.io> https://hg.python.org/cpython/rev/ac7f3161aa53 changeset: 93629:ac7f3161aa53 branch: 2.7 parent: 93624:7e534e18a99a user: Serhiy Storchaka date: Thu Nov 27 23:45:37 2014 +0200 summary: Issue #18905: "pydoc -p 0" now outputs actually used port. Based on patch by Wieland Hoffmann. files: Lib/pydoc.py | 8 +++++--- Misc/NEWS | 6 ++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -17,7 +17,8 @@ of all available modules. Run "pydoc -p " to start an HTTP server on a given port on the -local machine to generate documentation web pages. +local machine to generate documentation web pages. Port number 0 can be +used to get an arbitrary unused port. For platforms without a command line, "pydoc -g" starts the HTTP server and also pops up a little window for controlling it. @@ -2098,7 +2099,6 @@ def __init__(self, port, callback): host = 'localhost' self.address = (host, port) - self.url = 'http://%s:%d/' % (host, port) self.callback = callback self.base.__init__(self, self.address, self.handler) @@ -2111,6 +2111,7 @@ def server_activate(self): self.base.server_activate(self) + self.url = 'http://%s:%d/' % (self.address[0], self.server_port) if self.callback: self.callback(self) DocServer.base = BaseHTTPServer.HTTPServer @@ -2384,7 +2385,8 @@ Search for a keyword in the synopsis lines of all available modules. %s -p - Start an HTTP server on the given port on the local machine. + Start an HTTP server on the given port on the local machine. Port + number 0 can be used to get an arbitrary unused port. %s -g Pop up a graphical interface for finding and serving documentation. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -22,6 +22,12 @@ - Issue #21514: The documentation of the json module now refers to new JSON RFC 7159 instead of obsoleted RFC 4627. +Tools/Demos +----------- + +- Issue #18905: "pydoc -p 0" now outputs actually used port. Based on patch by + Wieland Hoffmann. + What's New in Python 2.7.9 release candidate 1? =============================================== -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 23:15:45 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Nov 2014 22:15:45 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyMzE0?= =?utf-8?q?=3A_pydoc_now_works_when_the_LINES_environment_variable_is_set?= =?utf-8?q?=2E?= Message-ID: <20141127221544.126764.96834@psf.io> https://hg.python.org/cpython/rev/c6182a7e75fa changeset: 93631:c6182a7e75fa branch: 3.4 parent: 93627:27ae1a476ef7 user: Serhiy Storchaka date: Fri Nov 28 00:09:29 2014 +0200 summary: Issue #22314: pydoc now works when the LINES environment variable is set. files: Lib/pydoc.py | 10 ++++++++-- Misc/NEWS | 5 +++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1479,12 +1479,18 @@ old = tty.tcgetattr(fd) tty.setcbreak(fd) getchar = lambda: sys.stdin.read(1) - except (ImportError, AttributeError): + except (ImportError, AttributeError, io.UnsupportedOperation): tty = None getchar = lambda: sys.stdin.readline()[:-1][:1] try: - r = inc = os.environ.get('LINES', 25) - 1 + try: + h = int(os.environ.get('LINES', 0)) + except ValueError: + h = 0 + if h <= 1: + h = 25 + r = inc = h - 1 sys.stdout.write('\n'.join(lines[:inc]) + '\n') while lines[r:]: sys.stdout.write('-- more --') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -184,6 +184,11 @@ - Issue #21514: The documentation of the json module now refers to new JSON RFC 7159 instead of obsoleted RFC 4627. +Tools/Demos +----------- + +- Issue #22314: pydoc now works when the LINES environment variable is set. + Windows ------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 23:15:45 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Nov 2014 22:15:45 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIyMzE0?= =?utf-8?q?=3A_pydoc_now_works_when_the_LINES_environment_variable_is_set?= =?utf-8?q?=2E?= Message-ID: <20141127221544.55119.88976@psf.io> https://hg.python.org/cpython/rev/50808dffd0bb changeset: 93630:50808dffd0bb branch: 2.7 user: Serhiy Storchaka date: Fri Nov 28 00:09:05 2014 +0200 summary: Issue #22314: pydoc now works when the LINES environment variable is set. files: Lib/pydoc.py | 8 +++++++- Misc/NEWS | 2 ++ 2 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1446,7 +1446,13 @@ getchar = lambda: sys.stdin.readline()[:-1][:1] try: - r = inc = os.environ.get('LINES', 25) - 1 + try: + h = int(os.environ.get('LINES', 0)) + except ValueError: + h = 0 + if h <= 1: + h = 25 + r = inc = h - 1 sys.stdout.write(join(lines[:inc], '\n') + '\n') while lines[r:]: sys.stdout.write('-- more --') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,8 @@ Tools/Demos ----------- +- Issue #22314: pydoc now works when the LINES environment variable is set. + - Issue #18905: "pydoc -p 0" now outputs actually used port. Based on patch by Wieland Hoffmann. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 23:15:47 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Nov 2014 22:15:47 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2322314=3A_pydoc_now_works_when_the_LINES_environ?= =?utf-8?q?ment_variable_is_set=2E?= Message-ID: <20141127221545.126780.80304@psf.io> https://hg.python.org/cpython/rev/c8adee8a0ccb changeset: 93632:c8adee8a0ccb parent: 93628:ce9881eecfb4 parent: 93631:c6182a7e75fa user: Serhiy Storchaka date: Fri Nov 28 00:11:07 2014 +0200 summary: Issue #22314: pydoc now works when the LINES environment variable is set. files: Lib/pydoc.py | 10 ++++++++-- Misc/NEWS | 5 +++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1477,12 +1477,18 @@ old = tty.tcgetattr(fd) tty.setcbreak(fd) getchar = lambda: sys.stdin.read(1) - except (ImportError, AttributeError): + except (ImportError, AttributeError, io.UnsupportedOperation): tty = None getchar = lambda: sys.stdin.readline()[:-1][:1] try: - r = inc = os.environ.get('LINES', 25) - 1 + try: + h = int(os.environ.get('LINES', 0)) + except ValueError: + h = 0 + if h <= 1: + h = 25 + r = inc = h - 1 sys.stdout.write('\n'.join(lines[:inc]) + '\n') while lines[r:]: sys.stdout.write('-- more --') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -383,6 +383,11 @@ - Issue #17442: InteractiveInterpreter now displays the full chained traceback in its showtraceback method, to match the built in interactive interpreter. +Tools/Demos +----------- + +- Issue #22314: pydoc now works when the LINES environment variable is set. + - Issue #10510: distutils register and upload methods now use HTML standards compliant CRLF line endings. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 23:53:11 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Nov 2014 22:53:11 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2321280=3A_Fixed_a_bug_in_shutil=2Emake=5Farchive?= =?utf-8?q?=28=29_when_create_an_archive_of?= Message-ID: <20141127225311.84285.51159@psf.io> https://hg.python.org/cpython/rev/c605dcf9786f changeset: 93634:c605dcf9786f parent: 93632:c8adee8a0ccb parent: 93633:8fa9097eadcb user: Serhiy Storchaka date: Fri Nov 28 00:49:50 2014 +0200 summary: Issue #21280: Fixed a bug in shutil.make_archive() when create an archive of current directory in current directory. files: Lib/shutil.py | 4 ++-- Lib/test/test_shutil.py | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Lib/shutil.py b/Lib/shutil.py --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -617,7 +617,7 @@ archive_name = base_name + '.tar' + compress_ext.get(compress, '') archive_dir = os.path.dirname(archive_name) - if not os.path.exists(archive_dir): + if archive_dir and not os.path.exists(archive_dir): if logger is not None: logger.info("creating %s", archive_dir) if not dry_run: @@ -662,7 +662,7 @@ zip_filename = base_name + ".zip" archive_dir = os.path.dirname(base_name) - if not os.path.exists(archive_dir): + if archive_dir and not os.path.exists(archive_dir): if logger is not None: logger.info("creating %s", archive_dir) if not dry_run: 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 @@ -1132,6 +1132,21 @@ finally: unregister_archive_format('xxx') + def test_make_tarfile_in_curdir(self): + # Issue #21280 + root_dir = self.mkdtemp() + with support.change_cwd(root_dir): + self.assertEqual(make_archive('test', 'tar'), 'test.tar') + self.assertTrue(os.path.isfile('test.tar')) + + @requires_zlib + def test_make_zipfile_in_curdir(self): + # Issue #21280 + root_dir = self.mkdtemp() + with support.change_cwd(root_dir): + self.assertEqual(make_archive('test', 'zip'), 'test.zip') + self.assertTrue(os.path.isfile('test.zip')) + def test_register_archive_format(self): self.assertRaises(TypeError, register_archive_format, 'xxx', 1) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 23:53:12 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Nov 2014 22:53:12 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzIxMjgw?= =?utf-8?q?=3A_Fixed_a_bug_in_shutil=2Emake=5Farchive=28=29_when_create_an?= =?utf-8?q?_archive_of?= Message-ID: <20141127225311.55111.51849@psf.io> https://hg.python.org/cpython/rev/c7d45da654ee changeset: 93635:c7d45da654ee branch: 2.7 parent: 93630:50808dffd0bb user: Serhiy Storchaka date: Fri Nov 28 00:50:06 2014 +0200 summary: Issue #21280: Fixed a bug in shutil.make_archive() when create an archive of current directory in current directory. files: Lib/shutil.py | 4 ++-- Lib/test/test_shutil.py | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/Lib/shutil.py b/Lib/shutil.py --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -362,7 +362,7 @@ archive_name = base_name + '.tar' + compress_ext.get(compress, '') archive_dir = os.path.dirname(archive_name) - if not os.path.exists(archive_dir): + if archive_dir and not os.path.exists(archive_dir): if logger is not None: logger.info("creating %s", archive_dir) if not dry_run: @@ -426,7 +426,7 @@ zip_filename = base_name + ".zip" archive_dir = os.path.dirname(base_name) - if not os.path.exists(archive_dir): + if archive_dir and not os.path.exists(archive_dir): if logger is not None: logger.info("creating %s", archive_dir) if not dry_run: 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 @@ -581,6 +581,29 @@ finally: unregister_archive_format('xxx') + def test_make_tarfile_in_curdir(self): + # Issue #21280 + root_dir = self.mkdtemp() + saved_dir = os.getcwd() + try: + os.chdir(root_dir) + self.assertEqual(make_archive('test', 'tar'), 'test.tar') + self.assertTrue(os.path.isfile('test.tar')) + finally: + os.chdir(saved_dir) + + @unittest.skipUnless(zlib, "Requires zlib") + def test_make_zipfile_in_curdir(self): + # Issue #21280 + root_dir = self.mkdtemp() + saved_dir = os.getcwd() + try: + os.chdir(root_dir) + self.assertEqual(make_archive('test', 'zip'), 'test.zip') + self.assertTrue(os.path.isfile('test.zip')) + finally: + os.chdir(saved_dir) + def test_register_archive_format(self): self.assertRaises(TypeError, register_archive_format, 'xxx', 1) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Thu Nov 27 23:53:11 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 27 Nov 2014 22:53:11 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIxMjgw?= =?utf-8?q?=3A_Fixed_a_bug_in_shutil=2Emake=5Farchive=28=29_when_create_an?= =?utf-8?q?_archive_of?= Message-ID: <20141127225310.126784.44831@psf.io> https://hg.python.org/cpython/rev/8fa9097eadcb changeset: 93633:8fa9097eadcb branch: 3.4 parent: 93631:c6182a7e75fa user: Serhiy Storchaka date: Fri Nov 28 00:48:46 2014 +0200 summary: Issue #21280: Fixed a bug in shutil.make_archive() when create an archive of current directory in current directory. files: Lib/shutil.py | 4 ++-- Lib/test/test_shutil.py | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Lib/shutil.py b/Lib/shutil.py --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -600,7 +600,7 @@ archive_name = base_name + '.tar' + compress_ext.get(compress, '') archive_dir = os.path.dirname(archive_name) - if not os.path.exists(archive_dir): + if archive_dir and not os.path.exists(archive_dir): if logger is not None: logger.info("creating %s", archive_dir) if not dry_run: @@ -660,7 +660,7 @@ zip_filename = base_name + ".zip" archive_dir = os.path.dirname(base_name) - if not os.path.exists(archive_dir): + if archive_dir and not os.path.exists(archive_dir): if logger is not None: logger.info("creating %s", archive_dir) if not dry_run: 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 @@ -1126,6 +1126,21 @@ finally: unregister_archive_format('xxx') + def test_make_tarfile_in_curdir(self): + # Issue #21280 + root_dir = self.mkdtemp() + with support.change_cwd(root_dir): + self.assertEqual(make_archive('test', 'tar'), 'test.tar') + self.assertTrue(os.path.isfile('test.tar')) + + @requires_zlib + def test_make_zipfile_in_curdir(self): + # Issue #21280 + root_dir = self.mkdtemp() + with support.change_cwd(root_dir): + self.assertEqual(make_archive('test', 'zip'), 'test.zip') + self.assertTrue(os.path.isfile('test.zip')) + def test_register_archive_format(self): self.assertRaises(TypeError, register_archive_format, 'xxx', 1) -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 28 03:41:54 2014 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 28 Nov 2014 02:41:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_give_a_nice_me?= =?utf-8?q?ssage_when_installer_is_launched_w/o_admin_rights_=28closes_=23?= =?utf-8?q?16561=29?= Message-ID: <20141128024151.55125.76086@psf.io> https://hg.python.org/cpython/rev/caee1eabba1e changeset: 93638:caee1eabba1e branch: 3.4 parent: 93633:8fa9097eadcb user: Benjamin Peterson date: Thu Nov 27 20:39:02 2014 -0600 summary: give a nice message when installer is launched w/o admin rights (closes #16561) files: PC/bdist_wininst/install.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/PC/bdist_wininst/install.c b/PC/bdist_wininst/install.c --- a/PC/bdist_wininst/install.c +++ b/PC/bdist_wininst/install.c @@ -1774,6 +1774,16 @@ sprintf(buffer, "%s\\%s-wininst.log", dir, meta_name); logfile = fopen(buffer, "a"); + if (!logfile) { + char error[1024]; + + sprintf(error, "Can't create \"%s\" (%s).\n\n" + "Try to execute the installer as administrator.", + buffer, strerror(errno)); + MessageBox(GetFocus(), error, NULL, MB_OK | MB_ICONSTOP); + return FALSE; + } + time(<ime); now = localtime(<ime); strftime(buffer, sizeof(buffer), -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 28 03:41:54 2014 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 28 Nov 2014 02:41:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjMTY1NjEp?= Message-ID: <20141128024151.84285.17601@psf.io> https://hg.python.org/cpython/rev/ef5bbdc81796 changeset: 93639:ef5bbdc81796 parent: 93634:c605dcf9786f parent: 93638:caee1eabba1e user: Benjamin Peterson date: Thu Nov 27 20:41:36 2014 -0600 summary: merge 3.4 (#16561) files: PC/bdist_wininst/install.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/PC/bdist_wininst/install.c b/PC/bdist_wininst/install.c --- a/PC/bdist_wininst/install.c +++ b/PC/bdist_wininst/install.c @@ -1774,6 +1774,16 @@ sprintf(buffer, "%s\\%s-wininst.log", dir, meta_name); logfile = fopen(buffer, "a"); + if (!logfile) { + char error[1024]; + + sprintf(error, "Can't create \"%s\" (%s).\n\n" + "Try to execute the installer as administrator.", + buffer, strerror(errno)); + MessageBox(GetFocus(), error, NULL, MB_OK | MB_ICONSTOP); + return FALSE; + } + time(<ime); now = localtime(<ime); strftime(buffer, sizeof(buffer), -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 28 03:41:54 2014 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 28 Nov 2014 02:41:54 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf-8?q?_merge_2=2E7=2E9_release_branch?= Message-ID: <20141128024151.116316.5203@psf.io> https://hg.python.org/cpython/rev/713e5814640d changeset: 93637:713e5814640d branch: 2.7 parent: 93635:c7d45da654ee parent: 93636:1ac5aec658f6 user: Benjamin Peterson date: Thu Nov 27 20:40:35 2014 -0600 summary: merge 2.7.9 release branch files: PC/bdist_wininst/install.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/PC/bdist_wininst/install.c b/PC/bdist_wininst/install.c --- a/PC/bdist_wininst/install.c +++ b/PC/bdist_wininst/install.c @@ -1742,6 +1742,16 @@ sprintf(buffer, "%s\\%s-wininst.log", dir, meta_name); logfile = fopen(buffer, "a"); + if (!logfile) { + char error[1024]; + + sprintf(error, "Can't create \"%s\" (%s).\n\n" + "Try to execute the installer as administrator.", + buffer, strerror(errno)); + MessageBox(GetFocus(), error, NULL, MB_OK | MB_ICONSTOP); + return FALSE; + } + time(<ime); now = localtime(<ime); strftime(buffer, sizeof(buffer), -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 28 03:41:54 2014 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 28 Nov 2014 02:41:54 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_give_a_nice_me?= =?utf-8?q?ssage_when_installer_is_launched_w/o_admin_rights_=28closes_=23?= =?utf-8?q?16561=29?= Message-ID: <20141128024151.116314.73252@psf.io> https://hg.python.org/cpython/rev/1ac5aec658f6 changeset: 93636:1ac5aec658f6 branch: 2.7 parent: 93595:080dba0e66e4 user: Benjamin Peterson date: Thu Nov 27 20:39:02 2014 -0600 summary: give a nice message when installer is launched w/o admin rights (closes #16561) files: PC/bdist_wininst/install.c | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/PC/bdist_wininst/install.c b/PC/bdist_wininst/install.c --- a/PC/bdist_wininst/install.c +++ b/PC/bdist_wininst/install.c @@ -1742,6 +1742,16 @@ sprintf(buffer, "%s\\%s-wininst.log", dir, meta_name); logfile = fopen(buffer, "a"); + if (!logfile) { + char error[1024]; + + sprintf(error, "Can't create \"%s\" (%s).\n\n" + "Try to execute the installer as administrator.", + buffer, strerror(errno)); + MessageBox(GetFocus(), error, NULL, MB_OK | MB_ICONSTOP); + return FALSE; + } + time(<ime); now = localtime(<ime); strftime(buffer, sizeof(buffer), -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Fri Nov 28 10:32:01 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 28 Nov 2014 10:32:01 +0100 Subject: [Python-checkins] Daily reference leaks (c605dcf9786f): sum=58 Message-ID: results for c605dcf9786f on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 test_multiprocessing_forkserver leaked [0, 38, 0] references, sum=38 test_multiprocessing_forkserver leaked [0, 17, 0] memory blocks, sum=17 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogjYWIIn', '-x'] From python-checkins at python.org Fri Nov 28 13:16:34 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 28 Nov 2014 12:16:34 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbyBkb2M6?= =?utf-8?q?_explain_how_to_pass_keywords_to_callbacks_=28functools=2Eparti?= =?utf-8?b?YWwp?= Message-ID: <20141128121629.69779.42561@psf.io> https://hg.python.org/cpython/rev/8dacb1a21793 changeset: 93640:8dacb1a21793 branch: 3.4 parent: 93638:caee1eabba1e user: Victor Stinner date: Fri Nov 28 13:15:41 2014 +0100 summary: asyncio doc: explain how to pass keywords to callbacks (functools.partial) files: Doc/library/asyncio-eventloop.rst | 33 +++++++++++++++++++ Doc/library/asyncio-task.rst | 5 ++ 2 files changed, 38 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 @@ -67,10 +67,22 @@ This is idempotent and irreversible. No other methods should be called after this one. +.. _asyncio-pass-keywords: Calls ----- +Most :mod:`asyncio` functions don't accept keywords. If you want to pass +keywords to your callback, use :func:`functools.partial`. For example, +``loop.call_soon(functools.partial(print, "Hello", flush=True))`` will call +``print("Hello", flush=True)``. + +.. note:: + :func:`functools.partial` is better than ``lambda`` functions, because + :mod:`asyncio` can inspect :func:`functools.partial` object to display + parameters in debug mode, whereas ``lambda`` functions have a poor + representation. + .. method:: BaseEventLoop.call_soon(callback, \*args) Arrange for a callback to be called as soon as possible. @@ -83,6 +95,9 @@ An instance of :class:`asyncio.Handle` is returned. + :ref:`Use functools.partial to pass keywords to the callback + `. + .. method:: BaseEventLoop.call_soon_threadsafe(callback, \*args) Like :meth:`call_soon`, but thread safe. @@ -118,6 +133,9 @@ is called. If you want the callback to be called with some named arguments, use a closure or :func:`functools.partial`. + :ref:`Use functools.partial to pass keywords to the callback + `. + .. method:: BaseEventLoop.call_at(when, callback, *args) Arrange for the *callback* to be called at the given absolute timestamp @@ -126,6 +144,9 @@ This method's behavior is the same as :meth:`call_later`. + :ref:`Use functools.partial to pass keywords to the callback + `. + .. method:: BaseEventLoop.time() Return the current time, as a :class:`float` value, according to the @@ -334,6 +355,9 @@ Start watching the file descriptor for read availability and then call the *callback* with specified arguments. + :ref:`Use functools.partial to pass keywords to the callback + `. + .. method:: BaseEventLoop.remove_reader(fd) Stop watching the file descriptor for read availability. @@ -343,6 +367,9 @@ Start watching the file descriptor for write availability and then call the *callback* with specified arguments. + :ref:`Use functools.partial to pass keywords to the callback + `. + .. method:: BaseEventLoop.remove_writer(fd) Stop watching the file descriptor for write availability. @@ -493,6 +520,9 @@ Raise :exc:`ValueError` if the signal number is invalid or uncatchable. Raise :exc:`RuntimeError` if there is a problem setting up the handler. + :ref:`Use functools.partial to pass keywords to the callback + `. + .. method:: BaseEventLoop.remove_signal_handler(sig) Remove a handler for a signal. @@ -518,6 +548,9 @@ The *executor* argument should be an :class:`~concurrent.futures.Executor` instance. The default executor is used if *executor* is ``None``. + :ref:`Use functools.partial to pass keywords to the callback + `. + This method is a :ref:`coroutine `. .. method:: BaseEventLoop.set_default_executor(executor) 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 @@ -253,6 +253,11 @@ future is already done when this is called, the callback is scheduled with :meth:`~BaseEventLoop.call_soon`. + :ref:`Use functools.partial to pass parameters to the callback + `. For example, + ``fut.add_done_callback(functools.partial(print, "Future:", + flush=True))`` will call ``print("Future:", fut, flush=True)``. + .. method:: remove_done_callback(fn) Remove all instances of a callback from the "call when done" list. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 28 13:16:34 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 28 Nov 2014 12:16:34 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_=28Merge_3=2E4=29_asyncio_doc=3A_explain_how_to_pass_key?= =?utf-8?q?words_to_callbacks?= Message-ID: <20141128121629.84297.23955@psf.io> https://hg.python.org/cpython/rev/29645775b75c changeset: 93641:29645775b75c parent: 93639:ef5bbdc81796 parent: 93640:8dacb1a21793 user: Victor Stinner date: Fri Nov 28 13:16:03 2014 +0100 summary: (Merge 3.4) asyncio doc: explain how to pass keywords to callbacks (functools.partial) files: Doc/library/asyncio-eventloop.rst | 33 +++++++++++++++++++ Doc/library/asyncio-task.rst | 5 ++ 2 files changed, 38 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 @@ -67,10 +67,22 @@ This is idempotent and irreversible. No other methods should be called after this one. +.. _asyncio-pass-keywords: Calls ----- +Most :mod:`asyncio` functions don't accept keywords. If you want to pass +keywords to your callback, use :func:`functools.partial`. For example, +``loop.call_soon(functools.partial(print, "Hello", flush=True))`` will call +``print("Hello", flush=True)``. + +.. note:: + :func:`functools.partial` is better than ``lambda`` functions, because + :mod:`asyncio` can inspect :func:`functools.partial` object to display + parameters in debug mode, whereas ``lambda`` functions have a poor + representation. + .. method:: BaseEventLoop.call_soon(callback, \*args) Arrange for a callback to be called as soon as possible. @@ -83,6 +95,9 @@ An instance of :class:`asyncio.Handle` is returned. + :ref:`Use functools.partial to pass keywords to the callback + `. + .. method:: BaseEventLoop.call_soon_threadsafe(callback, \*args) Like :meth:`call_soon`, but thread safe. @@ -118,6 +133,9 @@ is called. If you want the callback to be called with some named arguments, use a closure or :func:`functools.partial`. + :ref:`Use functools.partial to pass keywords to the callback + `. + .. method:: BaseEventLoop.call_at(when, callback, *args) Arrange for the *callback* to be called at the given absolute timestamp @@ -126,6 +144,9 @@ This method's behavior is the same as :meth:`call_later`. + :ref:`Use functools.partial to pass keywords to the callback + `. + .. method:: BaseEventLoop.time() Return the current time, as a :class:`float` value, according to the @@ -334,6 +355,9 @@ Start watching the file descriptor for read availability and then call the *callback* with specified arguments. + :ref:`Use functools.partial to pass keywords to the callback + `. + .. method:: BaseEventLoop.remove_reader(fd) Stop watching the file descriptor for read availability. @@ -343,6 +367,9 @@ Start watching the file descriptor for write availability and then call the *callback* with specified arguments. + :ref:`Use functools.partial to pass keywords to the callback + `. + .. method:: BaseEventLoop.remove_writer(fd) Stop watching the file descriptor for write availability. @@ -493,6 +520,9 @@ Raise :exc:`ValueError` if the signal number is invalid or uncatchable. Raise :exc:`RuntimeError` if there is a problem setting up the handler. + :ref:`Use functools.partial to pass keywords to the callback + `. + .. method:: BaseEventLoop.remove_signal_handler(sig) Remove a handler for a signal. @@ -518,6 +548,9 @@ The *executor* argument should be an :class:`~concurrent.futures.Executor` instance. The default executor is used if *executor* is ``None``. + :ref:`Use functools.partial to pass keywords to the callback + `. + This method is a :ref:`coroutine `. .. method:: BaseEventLoop.set_default_executor(executor) 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 @@ -253,6 +253,11 @@ future is already done when this is called, the callback is scheduled with :meth:`~BaseEventLoop.call_soon`. + :ref:`Use functools.partial to pass parameters to the callback + `. For example, + ``fut.add_done_callback(functools.partial(print, "Future:", + flush=True))`` will call ``print("Future:", fut, flush=True)``. + .. method:: remove_done_callback(fn) Remove all instances of a callback from the "call when done" list. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 28 13:31:08 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 28 Nov 2014 12:31:08 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2321356=3A_Make_ssl?= =?utf-8?q?=2ERAND=5Fegd=28=29_optional_to_support_LibreSSL=2E_The?= Message-ID: <20141128123102.126772.53727@psf.io> https://hg.python.org/cpython/rev/6f23bc5d480e changeset: 93642:6f23bc5d480e user: Victor Stinner date: Fri Nov 28 13:28:25 2014 +0100 summary: Issue #21356: Make ssl.RAND_egd() optional to support LibreSSL. The availability of the function is checked during the compilation. Patch written by Bernard Spil. files: Lib/ssl.py | 7 ++++- Lib/test/test_ssl.py | 5 ++- Misc/NEWS | 4 +++ Modules/_ssl.c | 4 +++ configure | 42 ++++++++++++++++++++++++++++++++ configure.ac | 3 ++ pyconfig.h.in | 3 ++ 7 files changed, 65 insertions(+), 3 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -106,7 +106,12 @@ from _ssl import (VERIFY_DEFAULT, VERIFY_CRL_CHECK_LEAF, VERIFY_CRL_CHECK_CHAIN, VERIFY_X509_STRICT) from _ssl import txt2obj as _txt2obj, nid2obj as _nid2obj -from _ssl import RAND_status, RAND_egd, RAND_add, RAND_bytes, RAND_pseudo_bytes +from _ssl import RAND_status, RAND_add, RAND_bytes, RAND_pseudo_bytes +try: + from _ssl import RAND_egd +except ImportError: + # LibreSSL does not provide RAND_egd + pass def _import_symbols(prefix): for n in dir(_ssl): 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 @@ -168,8 +168,9 @@ self.assertRaises(ValueError, ssl.RAND_bytes, -5) self.assertRaises(ValueError, ssl.RAND_pseudo_bytes, -5) - self.assertRaises(TypeError, ssl.RAND_egd, 1) - self.assertRaises(TypeError, ssl.RAND_egd, 'foo', 1) + if hasattr(ssl, 'RAND_egd'): + self.assertRaises(TypeError, ssl.RAND_egd, 1) + self.assertRaises(TypeError, ssl.RAND_egd, 'foo', 1) ssl.RAND_add("this is a random string", 75.0) @unittest.skipUnless(os.name == 'posix', 'requires posix') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -191,6 +191,10 @@ Library ------- +- Issue #21356: Make ssl.RAND_egd() optional to support LibreSSL. The + availability of the function is checked during the compilation. Patch written + by Bernard Spil. + - Issue #22915: SAX parser now supports files opened with file descriptor or bytes path. diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -3713,6 +3713,7 @@ It is necessary to seed the PRNG with RAND_add() on some platforms before\n\ using the ssl() function."); +#ifdef HAVE_RAND_EGD static PyObject * PySSL_RAND_egd(PyObject *self, PyObject *args) { @@ -3740,6 +3741,7 @@ Queries the entropy gather daemon (EGD) on the socket named by 'path'.\n\ Returns number of bytes read. Raises SSLError if connection to EGD\n\ fails or if it does not provide enough data to seed PRNG."); +#endif /* HAVE_RAND_EGD */ #endif /* HAVE_OPENSSL_RAND */ @@ -4135,8 +4137,10 @@ PySSL_RAND_bytes_doc}, {"RAND_pseudo_bytes", PySSL_RAND_pseudo_bytes, METH_VARARGS, PySSL_RAND_pseudo_bytes_doc}, +#ifdef HAVE_RAND_EGD {"RAND_egd", PySSL_RAND_egd, METH_VARARGS, PySSL_RAND_egd_doc}, +#endif {"RAND_status", (PyCFunction)PySSL_RAND_status, METH_NOARGS, PySSL_RAND_status_doc}, #endif diff --git a/configure b/configure --- a/configure +++ b/configure @@ -9046,6 +9046,48 @@ fi # Dynamic linking for HP-UX +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for RAND_egd in -lcrypto" >&5 +$as_echo_n "checking for RAND_egd in -lcrypto... " >&6; } +if ${ac_cv_lib_crypto_RAND_egd+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcrypto $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char RAND_egd (); +int +main () +{ +return RAND_egd (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_crypto_RAND_egd=yes +else + ac_cv_lib_crypto_RAND_egd=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_RAND_egd" >&5 +$as_echo "$ac_cv_lib_crypto_RAND_egd" >&6; } +if test "x$ac_cv_lib_crypto_RAND_egd" = xyes; then : + +$as_echo "#define HAVE_RAND_EGD 1" >>confdefs.h + +fi + # only check for sem_init if thread support is requested if test "$with_threads" = "yes" -o -z "$with_threads"; then diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -2293,6 +2293,9 @@ AC_CHECK_LIB(sendfile, sendfile) AC_CHECK_LIB(dl, dlopen) # Dynamic linking for SunOS/Solaris and SYSV AC_CHECK_LIB(dld, shl_load) # Dynamic linking for HP-UX +AC_CHECK_LIB(crypto, RAND_egd, + AC_DEFINE(HAVE_RAND_EGD, 1, + [Define if the libcrypto has RAND_egd])) # only check for sem_init if thread support is requested if test "$with_threads" = "yes" -o -z "$with_threads"; then diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -675,6 +675,9 @@ /* Define to 1 if you have the `pwrite' function. */ #undef HAVE_PWRITE +/* Define if the libcrypto has RAND_egd */ +#undef HAVE_RAND_EGD + /* Define to 1 if you have the `readlink' function. */ #undef HAVE_READLINK -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 28 17:46:19 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 28 Nov 2014 16:46:19 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogYXN5bmNpbyBkb2M6?= =?utf-8?q?_reformat_event_loop_policy_doc?= Message-ID: <20141128164616.69805.41683@psf.io> https://hg.python.org/cpython/rev/c90fe355ac43 changeset: 93643:c90fe355ac43 branch: 3.4 parent: 93640:8dacb1a21793 user: Victor Stinner date: Fri Nov 28 13:58:28 2014 +0100 summary: asyncio doc: reformat event loop policy doc files: Doc/library/asyncio-eventloops.rst | 26 ++++++++++++----- 1 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Doc/library/asyncio-eventloops.rst b/Doc/library/asyncio-eventloops.rst --- a/Doc/library/asyncio-eventloops.rst +++ b/Doc/library/asyncio-eventloops.rst @@ -150,6 +150,7 @@ :func:`get_event_loop` and :func:`set_event_loop` provide convenient access to event loops managed by the default policy. + Event loop policy interface --------------------------- @@ -157,22 +158,31 @@ .. class:: AbstractEventLoopPolicy + Event loop policy. + .. method:: get_event_loop() - Get the event loop for the current context. Returns an event loop object - implementing the :class:`BaseEventLoop` interface, or raises an exception in case - no event loop has been set for the current context and the current policy - does not specify to create one. It should never return ``None``. + Get the event loop for the current context. + + Returns an event loop object implementing the :class:`BaseEventLoop` + interface. + + Raises an exception in case no event loop has been set for the current + context and the current policy does not specify to create one. It must + never return ``None``. .. method:: set_event_loop(loop) - Set the event loop for the current context to *loop*. + Set the event loop for the current context to *loop*. .. method:: new_event_loop() - Create and return a new event loop object according to this policy's rules. - If there's need to set this loop as the event loop for the current context, - :meth:`set_event_loop` must be called explicitly. + Create and return a new event loop object according to this policy's + rules. + + If there's need to set this loop as the event loop for the current + context, :meth:`set_event_loop` must be called explicitly. + Access to the global loop policy -------------------------------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 28 17:46:19 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 28 Nov 2014 16:46:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_=28Merge_3=2E4=29_asyncio_doc=3A_reformat_event_loop_pol?= =?utf-8?q?icy_doc?= Message-ID: <20141128164616.84285.8501@psf.io> https://hg.python.org/cpython/rev/2ab452a0c5c6 changeset: 93644:2ab452a0c5c6 parent: 93642:6f23bc5d480e parent: 93643:c90fe355ac43 user: Victor Stinner date: Fri Nov 28 13:58:53 2014 +0100 summary: (Merge 3.4) asyncio doc: reformat event loop policy doc files: Doc/library/asyncio-eventloops.rst | 26 ++++++++++++----- 1 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Doc/library/asyncio-eventloops.rst b/Doc/library/asyncio-eventloops.rst --- a/Doc/library/asyncio-eventloops.rst +++ b/Doc/library/asyncio-eventloops.rst @@ -150,6 +150,7 @@ :func:`get_event_loop` and :func:`set_event_loop` provide convenient access to event loops managed by the default policy. + Event loop policy interface --------------------------- @@ -157,22 +158,31 @@ .. class:: AbstractEventLoopPolicy + Event loop policy. + .. method:: get_event_loop() - Get the event loop for the current context. Returns an event loop object - implementing the :class:`BaseEventLoop` interface, or raises an exception in case - no event loop has been set for the current context and the current policy - does not specify to create one. It should never return ``None``. + Get the event loop for the current context. + + Returns an event loop object implementing the :class:`BaseEventLoop` + interface. + + Raises an exception in case no event loop has been set for the current + context and the current policy does not specify to create one. It must + never return ``None``. .. method:: set_event_loop(loop) - Set the event loop for the current context to *loop*. + Set the event loop for the current context to *loop*. .. method:: new_event_loop() - Create and return a new event loop object according to this policy's rules. - If there's need to set this loop as the event loop for the current context, - :meth:`set_event_loop` must be called explicitly. + Create and return a new event loop object according to this policy's + rules. + + If there's need to set this loop as the event loop for the current + context, :meth:`set_event_loop` must be called explicitly. + Access to the global loop policy -------------------------------- -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 28 17:46:19 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 28 Nov 2014 16:46:19 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogQ2xvc2VzICMyMjM0?= =?utf-8?q?8=3A_Rephrase_asyncio=2EStreamWriter=2Edrain=28=29_documentatio?= =?utf-8?q?n?= Message-ID: <20141128164616.69799.78159@psf.io> https://hg.python.org/cpython/rev/8224253ef4b7 changeset: 93645:8224253ef4b7 branch: 3.4 parent: 93643:c90fe355ac43 user: Victor Stinner date: Fri Nov 28 17:45:41 2014 +0100 summary: Closes #22348: Rephrase asyncio.StreamWriter.drain() documentation Patch written by Martin Richard. files: Doc/library/asyncio-stream.rst | 14 ++++++++++---- Misc/ACKS | 1 + 2 files changed, 11 insertions(+), 4 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 @@ -170,16 +170,22 @@ .. method:: drain() - Wait until the write buffer of the underlying transport is flushed. + Let the write buffer of the underlying transport a chance to be flushed. The intended use is to write:: w.write(data) yield from w.drain() - When the transport buffer is full (the protocol is paused), block until - the buffer is (partially) drained and the protocol is resumed. When there - is nothing to wait for, the yield-from continues immediately. + When the size of the transport buffer reaches the high-water limit (the + protocol is paused), block until the size of the buffer is drained down + to the low-water limit and the protocol is resumed. When there is nothing + to wait for, the yield-from continues immediately. + + Yielding from :meth:`drain` gives the opportunity for the loop to + schedule the write operation and flush the buffer. It should especially + be used when a possibly large amount of data is written to the transport, + and the coroutine does not yield-from between calls to :meth:`write`. This method is a :ref:`coroutine `. diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1125,6 +1125,7 @@ Tim Rice Jan Pieter Riegel Armin Rigo +Martin Richard Arc Riley Nicholas Riley Jean-Claude Rimbault -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 28 17:46:19 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 28 Nov 2014 16:46:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_=28Merge_3=2E4=29_Closes_=2322348=3A_Rephrase_asyncio=2E?= =?utf-8?q?StreamWriter=2Edrain=28=29_documentation?= Message-ID: <20141128164617.126792.42196@psf.io> https://hg.python.org/cpython/rev/1cad9e4bba40 changeset: 93646:1cad9e4bba40 parent: 93644:2ab452a0c5c6 parent: 93645:8224253ef4b7 user: Victor Stinner date: Fri Nov 28 17:46:05 2014 +0100 summary: (Merge 3.4) Closes #22348: Rephrase asyncio.StreamWriter.drain() documentation Patch written by Martin Richard. files: Doc/library/asyncio-stream.rst | 14 ++++++++++---- Misc/ACKS | 1 + 2 files changed, 11 insertions(+), 4 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 @@ -170,16 +170,22 @@ .. method:: drain() - Wait until the write buffer of the underlying transport is flushed. + Let the write buffer of the underlying transport a chance to be flushed. The intended use is to write:: w.write(data) yield from w.drain() - When the transport buffer is full (the protocol is paused), block until - the buffer is (partially) drained and the protocol is resumed. When there - is nothing to wait for, the yield-from continues immediately. + When the size of the transport buffer reaches the high-water limit (the + protocol is paused), block until the size of the buffer is drained down + to the low-water limit and the protocol is resumed. When there is nothing + to wait for, the yield-from continues immediately. + + Yielding from :meth:`drain` gives the opportunity for the loop to + schedule the write operation and flush the buffer. It should especially + be used when a possibly large amount of data is written to the transport, + and the coroutine does not yield-from between calls to :meth:`write`. This method is a :ref:`coroutine `. diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1140,6 +1140,7 @@ Tim Rice Jan Pieter Riegel Armin Rigo +Martin Richard Arc Riley Nicholas Riley Jean-Claude Rimbault -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 28 18:03:20 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 28 Nov 2014 17:03:20 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Merge_3=2E4_=28asyncio=29?= Message-ID: <20141128170259.116320.13268@psf.io> https://hg.python.org/cpython/rev/c9b03ff2ab10 changeset: 93648:c9b03ff2ab10 parent: 93646:1cad9e4bba40 parent: 93647:737355f61ba2 user: Victor Stinner date: Fri Nov 28 18:02:16 2014 +0100 summary: Merge 3.4 (asyncio) files: Lib/test/test_asyncio/test_subprocess.py | 17 +++++++---- 1 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -163,13 +163,14 @@ self.loop.run_until_complete(proc.wait()) def test_pause_reading(self): + limit = 10 + size = (limit * 2 + 1) + @asyncio.coroutine def test_pause_reading(): - limit = 100 - code = '\n'.join(( 'import sys', - 'sys.stdout.write("x" * %s)' % (limit * 2 + 1), + 'sys.stdout.write("x" * %s)' % size, 'sys.stdout.flush()', )) proc = yield from asyncio.create_subprocess_exec( @@ -181,17 +182,19 @@ stdout_transport = proc._transport.get_pipe_transport(1) stdout_transport.pause_reading = mock.Mock() - yield from proc.wait() + stdout, stderr = yield from proc.communicate() # The child process produced more than limit bytes of output, # the stream reader transport should pause the protocol to not # allocate too much memory. - return stdout_transport.pause_reading.called + return (stdout, stdout_transport) # Issue #22685: Ensure that the stream reader pauses the protocol # when the child process produces too much data - called = self.loop.run_until_complete(test_pause_reading()) - self.assertTrue(called) + stdout, transport = self.loop.run_until_complete(test_pause_reading()) + + self.assertEqual(stdout, b'x' * size) + self.assertTrue(transport.pause_reading.called) if sys.platform != 'win32': -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 28 18:03:20 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 28 Nov 2014 17:03:20 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzIyNjg1?= =?utf-8?q?=3A_Debug_test=5Fpause=5Freading=28=29_on_FreeBSD?= Message-ID: <20141128170259.116306.22361@psf.io> https://hg.python.org/cpython/rev/737355f61ba2 changeset: 93647:737355f61ba2 branch: 3.4 parent: 93645:8224253ef4b7 user: Victor Stinner date: Fri Nov 28 18:02:03 2014 +0100 summary: Issue #22685: Debug test_pause_reading() on FreeBSD files: Lib/test/test_asyncio/test_subprocess.py | 17 +++++++---- 1 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -163,13 +163,14 @@ self.loop.run_until_complete(proc.wait()) def test_pause_reading(self): + limit = 10 + size = (limit * 2 + 1) + @asyncio.coroutine def test_pause_reading(): - limit = 100 - code = '\n'.join(( 'import sys', - 'sys.stdout.write("x" * %s)' % (limit * 2 + 1), + 'sys.stdout.write("x" * %s)' % size, 'sys.stdout.flush()', )) proc = yield from asyncio.create_subprocess_exec( @@ -181,17 +182,19 @@ stdout_transport = proc._transport.get_pipe_transport(1) stdout_transport.pause_reading = mock.Mock() - yield from proc.wait() + stdout, stderr = yield from proc.communicate() # The child process produced more than limit bytes of output, # the stream reader transport should pause the protocol to not # allocate too much memory. - return stdout_transport.pause_reading.called + return (stdout, stdout_transport) # Issue #22685: Ensure that the stream reader pauses the protocol # when the child process produces too much data - called = self.loop.run_until_complete(test_pause_reading()) - self.assertTrue(called) + stdout, transport = self.loop.run_until_complete(test_pause_reading()) + + self.assertEqual(stdout, b'x' * size) + self.assertTrue(transport.pause_reading.called) if sys.platform != 'win32': -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 28 22:27:35 2014 From: python-checkins at python.org (berker.peksag) Date: Fri, 28 Nov 2014 21:27:35 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322389=3A_Add_cont?= =?utf-8?q?extlib=2Eredirect=5Fstderr=28=29=2E?= Message-ID: <20141128212731.126778.97265@psf.io> https://hg.python.org/cpython/rev/7f12c9c09fb6 changeset: 93649:7f12c9c09fb6 user: Berker Peksag date: Fri Nov 28 23:28:06 2014 +0200 summary: Issue #22389: Add contextlib.redirect_stderr(). files: Doc/library/contextlib.rst | 10 ++++ Doc/whatsnew/3.5.rst | 9 +++ Lib/contextlib.py | 40 +++++++++++----- Lib/test/test_contextlib.py | 58 +++++++++++++++--------- Misc/NEWS | 2 + 5 files changed, 85 insertions(+), 34 deletions(-) diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst --- a/Doc/library/contextlib.rst +++ b/Doc/library/contextlib.rst @@ -172,6 +172,16 @@ .. versionadded:: 3.4 +.. function:: redirect_stderr(new_target) + + Similar to :func:`~contextlib.redirect_stdout` but redirecting + :data:`sys.stderr` to another file or file-like object. + + This context manager is :ref:`reentrant `. + + .. versionadded:: 3.5 + + .. class:: ContextDecorator() A base class that enables a context manager to also be used as a decorator. diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -148,6 +148,15 @@ can now do parallel bytecode compilation. (Contributed by Claudiu Popa in :issue:`16104`.) +contextlib +---------- + +* The new :func:`contextlib.redirect_stderr` context manager(similar to + :func:`contextlib.redirect_stdout`) makes it easier for utility scripts to + handle inflexible APIs that write their output to :data:`sys.stderr` and + don't provide any options to redirect it. + (Contributed by Berker Peksag in :issue:`22389`.) + doctest ------- diff --git a/Lib/contextlib.py b/Lib/contextlib.py --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -5,7 +5,7 @@ from functools import wraps __all__ = ["contextmanager", "closing", "ContextDecorator", "ExitStack", - "redirect_stdout", "suppress"] + "redirect_stdout", "redirect_stderr", "suppress"] class ContextDecorator(object): @@ -151,8 +151,27 @@ def __exit__(self, *exc_info): self.thing.close() -class redirect_stdout: - """Context manager for temporarily redirecting stdout to another file + +class _RedirectStream: + + _stream = None + + def __init__(self, new_target): + self._new_target = new_target + # We use a list of old targets to make this CM re-entrant + self._old_targets = [] + + def __enter__(self): + self._old_targets.append(getattr(sys, self._stream)) + setattr(sys, self._stream, self._new_target) + return self._new_target + + def __exit__(self, exctype, excinst, exctb): + setattr(sys, self._stream, self._old_targets.pop()) + + +class redirect_stdout(_RedirectStream): + """Context manager for temporarily redirecting stdout to another file. # How to send help() to stderr with redirect_stdout(sys.stderr): @@ -164,18 +183,13 @@ help(pow) """ - def __init__(self, new_target): - self._new_target = new_target - # We use a list of old targets to make this CM re-entrant - self._old_targets = [] + _stream = "stdout" - def __enter__(self): - self._old_targets.append(sys.stdout) - sys.stdout = self._new_target - return self._new_target - def __exit__(self, exctype, excinst, exctb): - sys.stdout = self._old_targets.pop() +class redirect_stderr(_RedirectStream): + """Context manager for temporarily redirecting stderr to another file.""" + + _stream = "stderr" class suppress: 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 @@ -718,60 +718,76 @@ stack.push(cm) self.assertIs(stack._exit_callbacks[-1], cm) -class TestRedirectStdout(unittest.TestCase): + +class TestRedirectStream: + + redirect_stream = None + orig_stream = None @support.requires_docstrings def test_instance_docs(self): # Issue 19330: ensure context manager instances have good docstrings - cm_docstring = redirect_stdout.__doc__ - obj = redirect_stdout(None) + cm_docstring = self.redirect_stream.__doc__ + obj = self.redirect_stream(None) self.assertEqual(obj.__doc__, cm_docstring) def test_no_redirect_in_init(self): - orig_stdout = sys.stdout - redirect_stdout(None) - self.assertIs(sys.stdout, orig_stdout) + orig_stdout = getattr(sys, self.orig_stream) + self.redirect_stream(None) + self.assertIs(getattr(sys, self.orig_stream), orig_stdout) def test_redirect_to_string_io(self): f = io.StringIO() msg = "Consider an API like help(), which prints directly to stdout" - orig_stdout = sys.stdout - with redirect_stdout(f): - print(msg) - self.assertIs(sys.stdout, orig_stdout) + orig_stdout = getattr(sys, self.orig_stream) + with self.redirect_stream(f): + print(msg, file=getattr(sys, self.orig_stream)) + self.assertIs(getattr(sys, self.orig_stream), orig_stdout) s = f.getvalue().strip() self.assertEqual(s, msg) def test_enter_result_is_target(self): f = io.StringIO() - with redirect_stdout(f) as enter_result: + with self.redirect_stream(f) as enter_result: self.assertIs(enter_result, f) def test_cm_is_reusable(self): f = io.StringIO() - write_to_f = redirect_stdout(f) - orig_stdout = sys.stdout + write_to_f = self.redirect_stream(f) + orig_stdout = getattr(sys, self.orig_stream) with write_to_f: - print("Hello", end=" ") + print("Hello", end=" ", file=getattr(sys, self.orig_stream)) with write_to_f: - print("World!") - self.assertIs(sys.stdout, orig_stdout) + print("World!", file=getattr(sys, self.orig_stream)) + self.assertIs(getattr(sys, self.orig_stream), orig_stdout) s = f.getvalue() self.assertEqual(s, "Hello World!\n") def test_cm_is_reentrant(self): f = io.StringIO() - write_to_f = redirect_stdout(f) - orig_stdout = sys.stdout + write_to_f = self.redirect_stream(f) + orig_stdout = getattr(sys, self.orig_stream) with write_to_f: - print("Hello", end=" ") + print("Hello", end=" ", file=getattr(sys, self.orig_stream)) with write_to_f: - print("World!") - self.assertIs(sys.stdout, orig_stdout) + print("World!", file=getattr(sys, self.orig_stream)) + self.assertIs(getattr(sys, self.orig_stream), orig_stdout) s = f.getvalue() self.assertEqual(s, "Hello World!\n") +class TestRedirectStdout(TestRedirectStream, unittest.TestCase): + + redirect_stream = redirect_stdout + orig_stream = "stdout" + + +class TestRedirectStderr(TestRedirectStream, unittest.TestCase): + + redirect_stream = redirect_stderr + orig_stream = "stderr" + + class TestSuppress(unittest.TestCase): @support.requires_docstrings diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -191,6 +191,8 @@ Library ------- +- Issue #22389: Add contextlib.redirect_stderr(). + - Issue #21356: Make ssl.RAND_egd() optional to support LibreSSL. The availability of the function is checked during the compilation. Patch written by Bernard Spil. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 28 22:40:13 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 28 Nov 2014 21:40:13 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322685=2C_asyncio?= =?utf-8?q?=3A_mock_also_resume=5Freading_in_test=5Fpause=5Freading=28=29?= Message-ID: <20141128214007.69779.94281@psf.io> https://hg.python.org/cpython/rev/0dd91298eb17 changeset: 93650:0dd91298eb17 user: Victor Stinner date: Fri Nov 28 22:37:16 2014 +0100 summary: Issue #22685, asyncio: mock also resume_reading in test_pause_reading() files: Lib/test/test_asyncio/test_subprocess.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -181,6 +181,7 @@ loop=self.loop) stdout_transport = proc._transport.get_pipe_transport(1) stdout_transport.pause_reading = mock.Mock() + stdout_transport.resume_reading = mock.Mock() stdout, stderr = yield from proc.communicate() -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 28 22:42:19 2014 From: python-checkins at python.org (victor.stinner) Date: Fri, 28 Nov 2014 21:42:19 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322685=2C_asyncio?= =?utf-8?q?=3A_resume=5Freading=28=29_must_also_be_called_in?= Message-ID: <20141128214213.55125.33983@psf.io> https://hg.python.org/cpython/rev/276515d2ceed changeset: 93651:276515d2ceed user: Victor Stinner date: Fri Nov 28 22:42:06 2014 +0100 summary: Issue #22685, asyncio: resume_reading() must also be called in test_pause_reading() files: Lib/test/test_asyncio/test_subprocess.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -196,6 +196,7 @@ self.assertEqual(stdout, b'x' * size) self.assertTrue(transport.pause_reading.called) + self.assertTrue(transport.resume_reading.called) if sys.platform != 'win32': -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Fri Nov 28 23:52:27 2014 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 28 Nov 2014 22:52:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Minor_code_cleanup=2E?= Message-ID: <20141128225227.55105.75378@psf.io> https://hg.python.org/cpython/rev/70163e18da87 changeset: 93652:70163e18da87 user: Raymond Hettinger date: Fri Nov 28 14:52:14 2014 -0800 summary: Minor code cleanup. files: Lib/xml/etree/ElementPath.py | 5 +---- 1 files changed, 1 insertions(+), 4 deletions(-) diff --git a/Lib/xml/etree/ElementPath.py b/Lib/xml/etree/ElementPath.py --- a/Lib/xml/etree/ElementPath.py +++ b/Lib/xml/etree/ElementPath.py @@ -295,10 +295,7 @@ # Find first matching object. def find(elem, path, namespaces=None): - try: - return next(iterfind(elem, path, namespaces)) - except StopIteration: - return None + return next(iterfind(elem, path, namespaces), None) ## # Find all matching objects. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 29 00:22:50 2014 From: python-checkins at python.org (ned.deily) Date: Fri, 28 Nov 2014 23:22:50 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy40KTogSXNzdWUgIzE2MTEz?= =?utf-8?q?=3A_Also_remove_test=5Fcase=5Fsha3=5F224=5Fhuge?= Message-ID: <20141128232238.116312.74854@psf.io> https://hg.python.org/cpython/rev/21257f916668 changeset: 93653:21257f916668 branch: 3.4 parent: 93647:737355f61ba2 user: Ned Deily date: Fri Nov 28 15:21:12 2014 -0800 summary: Issue #16113: Also remove test_case_sha3_224_huge files: Lib/test/test_hashlib.py | 6 ------ 1 files changed, 0 insertions(+), 6 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 @@ -373,12 +373,6 @@ "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb"+ "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b") - @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): - self.check('sha3_224', b'A'*size, - '58ef60057c9dddb6a87477e9ace5a26f0d9db01881cf9b10a9f8c224') - def test_gil(self): # Check things work fine with an input larger than the size required # for multithreaded operation (which is hardwired to 2048). -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 29 00:22:51 2014 From: python-checkins at python.org (ned.deily) Date: Fri, 28 Nov 2014 23:22:51 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2316113=3A_Also_remove_test=5Fcase=5Fsha3=5F224?= =?utf-8?q?=5Fhuge?= Message-ID: <20141128232238.55123.93330@psf.io> https://hg.python.org/cpython/rev/bd97eab25c70 changeset: 93654:bd97eab25c70 parent: 93652:70163e18da87 parent: 93653:21257f916668 user: Ned Deily date: Fri Nov 28 15:22:15 2014 -0800 summary: Issue #16113: Also remove test_case_sha3_224_huge files: Lib/test/test_hashlib.py | 6 ------ 1 files changed, 0 insertions(+), 6 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 @@ -373,12 +373,6 @@ "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb"+ "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b") - @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): - self.check('sha3_224', b'A'*size, - '58ef60057c9dddb6a87477e9ace5a26f0d9db01881cf9b10a9f8c224') - def test_gil(self): # Check things work fine with an input larger than the size required # for multithreaded operation (which is hardwired to 2048). -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 29 02:37:14 2014 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 29 Nov 2014 01:37:14 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Elaborate_transaction=28=29_m?= =?utf-8?q?anager_example_=28Chris_A=29=2E?= Message-ID: <20141129013709.116314.23132@psf.io> https://hg.python.org/peps/rev/4803b0829533 changeset: 5624:4803b0829533 user: Guido van Rossum date: Fri Nov 28 17:26:33 2014 -0800 summary: Elaborate transaction() manager example (Chris A). files: pep-0479.txt | 31 ++++++++++++++++++++++--------- 1 files changed, 22 insertions(+), 9 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -44,26 +44,39 @@ existent". Unfortunately while intentional use is rare, it is easy to stumble on these cases by accident:: + import contextlib + @contextlib.contextmanager def transaction(): - begin() + print('begin') try: yield from do_it() except: - rollback() + print('rollback') raise else: - commit() - + print('commit') + def do_it(): - initial_preparations() - yield - finishing_touches() + print('Refactored preparations') + yield # Body of with-statement is executed here + print('Refactored finalization') + + def gene(): + for i in range(2): + with transaction(): + yield i + # return + raise StopIteration # This is wrong + print('Should not be reached') + + for i in gene(): + print('main: i =', i) Here factoring out ``do_it`` into a subgenerator has introduced a subtle bug: if the wrapped block raises ``StopIteration``, under the -current behavior ``do_it`` will fail but report success by returning -normally, causing the failed transaction to be committed! Similarly +current behavior this exception will be swallowed by the context +manager; and, worse, the finalization is silently skipped! Similarly problematic behavior occurs when an ``asyncio`` coroutine raises ``StopIteration``, causing it to terminate silently. -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Sat Nov 29 05:11:28 2014 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 29 Nov 2014 04:11:28 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Two_new_sections_=28more_moti?= =?utf-8?q?vation=2C_rejected_=40allow=5Fimplicit=5Fstop=29=2E?= Message-ID: <20141129041127.116306.58337@psf.io> https://hg.python.org/peps/rev/2cb6c16d7d2a changeset: 5625:2cb6c16d7d2a user: Guido van Rossum date: Fri Nov 28 20:11:11 2014 -0800 summary: Two new sections (more motivation, rejected @allow_implicit_stop). files: pep-0479.txt | 56 ++++++++++++++++++++++++++++++++++++++++ 1 files changed, 56 insertions(+), 0 deletions(-) diff --git a/pep-0479.txt b/pep-0479.txt --- a/pep-0479.txt +++ b/pep-0479.txt @@ -100,6 +100,16 @@ terminate a generator: the proper way is ``return``, not ``raise StopIteration``. +As an added bonus, the above changes bring generator functions much +more in line with regular functions. If you wish to take a piece of +code presented as a generator and turn it into something else, you +can usually do this fairly simply, by replacing every ``yield`` with +a call to ``print()`` or ``list.append()``; however, if there are any +bare ``next()`` calls in the code, you have to be aware of them. If +the code was originally written without relying on ``StopIteration`` +terminating the function, the transformation would be that much +easier. + Background information ====================== @@ -433,6 +443,7 @@ bubble out would still be potentially wrong, depending on the use made of the distinction between the two exception types. + Converting the exception inside next() -------------------------------------- @@ -449,6 +460,45 @@ would help this; however, all code would still need to be rewritten.) +Sub-proposal: decorator to explicitly request current behaviour +--------------------------------------------------------------- + +Nick Coghlan suggested [13]_ that the situations where the current +behaviour is desired could be supported by means of a decorator:: + + from itertools import allow_implicit_stop + + @allow_implicit_stop + def my_generator(): + ... + yield next(it) + ... + +Which would be semantically equivalent to:: + + def my_generator(): + try: + ... + yield next(it) + ... + except StopIteration + return + +but be faster, as it could be implemented by simply permitting the +``StopIteration`` to bubble up directly. + +Single-source Python 2/3 code would also benefit in a 3.7+ world, +since libraries like six and python-future could just define their own +version of "allow_implicit_stop" that referred to the new builtin in +3.5+, and was implemented as an identity function in other versions. + +However, due to the implementation complexities required, the ongoing +compatibility issues created, the subtlety of the decorator's effect, +and the fact that it would encourage the "quick-fix" solution of just +slapping the decorator onto all generators instead of properly fixing +the code in question, this sub-proposal has been rejected. [14]_ + + Criticism ========= @@ -516,6 +566,12 @@ .. [12] Post from Mark Shannon with alternate proposal (https://mail.python.org/pipermail/python-dev/2014-November/137129.html) +.. [13] Idea from Nick Coghlan + (https://mail.python.org/pipermail/python-dev/2014-November/137201.html) + +.. [14] Rejection by GvR + (https://mail.python.org/pipermail/python-dev/2014-November/137243.html) + Copyright ========= -- Repository URL: https://hg.python.org/peps From solipsis at pitrou.net Sat Nov 29 10:33:28 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 29 Nov 2014 10:33:28 +0100 Subject: [Python-checkins] Daily reference leaks (bd97eab25c70): sum=3 Message-ID: results for bd97eab25c70 on branch "default" -------------------------------------------- test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogWR_tSy', '-x'] From python-checkins at python.org Sat Nov 29 15:56:48 2014 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 29 Nov 2014 14:56:48 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?q?=29=3A_Close_issue_=2322895=3A_fix_test_failure_introduced_by_t?= =?utf-8?q?he_fix_for_issue_=2322462=2E?= Message-ID: <20141129145647.126780.56962@psf.io> https://hg.python.org/cpython/rev/4990157343c6 changeset: 93656:4990157343c6 parent: 93654:bd97eab25c70 parent: 93655:e4b986350feb user: Antoine Pitrou date: Sat Nov 29 15:56:38 2014 +0100 summary: Close issue #22895: fix test failure introduced by the fix for issue #22462. files: Lib/test/test_pyexpat.py | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py --- a/Lib/test/test_pyexpat.py +++ b/Lib/test/test_pyexpat.py @@ -3,6 +3,7 @@ from io import BytesIO import os +import sysconfig import unittest import traceback @@ -444,7 +445,8 @@ "pyexpat.c", "StartElement") self.check_traceback_entry(entries[2], "test_pyexpat.py", "StartElementHandler") - self.assertIn('call_with_frame("StartElement"', entries[1][3]) + if sysconfig.is_python_build(): + self.assertIn('call_with_frame("StartElement"', entries[1][3]) # Test Current* members: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sat Nov 29 15:56:48 2014 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 29 Nov 2014 14:56:48 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_Close_issue_?= =?utf-8?q?=2322895=3A_fix_test_failure_introduced_by_the_fix_for_issue_?= =?utf-8?q?=2322462=2E?= Message-ID: <20141129145647.116318.67899@psf.io> https://hg.python.org/cpython/rev/e4b986350feb changeset: 93655:e4b986350feb branch: 3.4 parent: 93653:21257f916668 user: Antoine Pitrou date: Sat Nov 29 15:56:07 2014 +0100 summary: Close issue #22895: fix test failure introduced by the fix for issue #22462. files: Lib/test/test_pyexpat.py | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py --- a/Lib/test/test_pyexpat.py +++ b/Lib/test/test_pyexpat.py @@ -3,6 +3,7 @@ from io import BytesIO import os +import sysconfig import unittest import traceback @@ -444,7 +445,8 @@ "pyexpat.c", "StartElement") self.check_traceback_entry(entries[2], "test_pyexpat.py", "StartElementHandler") - self.assertIn('call_with_frame("StartElement"', entries[1][3]) + if sysconfig.is_python_build(): + self.assertIn('call_with_frame("StartElement"', entries[1][3]) # Test Current* members: -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 30 00:12:25 2014 From: python-checkins at python.org (donald.stufft) Date: Sat, 29 Nov 2014 23:12:25 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Add_PEP_481_-_Migrate_Some_Su?= =?utf-8?q?pporting_Repositories_to_Git_and_Github?= Message-ID: <20141129231225.116316.27726@psf.io> https://hg.python.org/peps/rev/f394fde562b2 changeset: 5626:f394fde562b2 user: Donald Stufft date: Sat Nov 29 18:12:06 2014 -0500 summary: Add PEP 481 - Migrate Some Supporting Repositories to Git and Github files: pep-0481.txt | 284 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 284 insertions(+), 0 deletions(-) diff --git a/pep-0481.txt b/pep-0481.txt new file mode 100644 --- /dev/null +++ b/pep-0481.txt @@ -0,0 +1,284 @@ +PEP: 481 +Title: Migrate Some Supporting Repositories to Git and Github +Version: $Revision$ +Last-Modified: $Date$ +Author: Donald Stufft +Status: Draft +Type: Process +Content-Type: text/x-rst +Created: 29-Nov-2014 +Post-History: 29-Nov-2014 + + +Abstract +======== + +This PEP proposes migrating to Git and Github for certain supporting +repositories (such as the repository for Python Enhancement Proposals) in a way +that is more accessible to new contributors, and easier to manage for core +developers. This is offered as an alternative to PEP 474 which aims to achieve +the same overall benefits but while continuing to use the Mercurial DVCS and +without relying on a commerical entity. + +In particular this PEP proposes changes to the following repositories: + +* https://hg.python.org/devguide/ +* https://hg.python.org/devinabox/ +* https://hg.python.org/peps/ + + +This PEP does not propose any changes to the core development workflow for +CPython itself. + + +Rationale +========= + +As PEP 474 mentions, there are currently a number of repositories hosted on +hg.python.org which are not directly used for the development of CPython but +instead are supporting or ancillary repositories. These supporting repositories +do not typically have complex workflows or often branches at all other than the +primary integration branch. This simplicity makes them very good targets for +the "Pull Request" workflow that is commonly found on sites like Github. + +However where PEP 474 wants to continue to use Mercurial and wishes to use an +OSS and self-hosted and therefore restricts itself to only those solutions this +PEP expands the scope of that to include migrating to Git and using Github. + +The existing method of contributing to these repositories generally includes +generating a patch and either uploading them to bugs.python.org or emailing +them to peps at python.org. This process is unfriendly towards non-comitter +contributors as well as making the process harder than it needs to be for +comitters to accept the patches sent by users. In addition to the benefits +in the pull request workflow itself, this style of workflow also enables +non techincal contributors, especially those who do not know their way around +the DVCS of choice, to contribute using the web based editor. On the committer +side the Pull Requests enable them to tell, before merging, whether or not +a particular Pull Request will break anything. It also enables them to do a +simple "push button" merge which does not require them to check out the +changes locally. Another such feature that is useful in particular for docs, +is the ability to view a "prose" diff. This Github specific feature enables +a committer to view a diff of the rendered output which will hide things like +reformatting a paragraph and show you what the actual "meat" of the change +actually is. + + +Why Git? +-------- + +Looking at the variety of DVCS which are available today it becomes fairly +clear that git has gotten the vast mindshare of people who are currently using +it. The Open Hub (Previously Ohloh) statistics [#openhub-stats]_ show that +currently 37% of the repositories Open Hub is indexing is using git which is +second only to SVN (which has 48%) while Mercurial has just 2% of the indexed +repositories (beating only bazaar which has 1%). In additon to the Open Hub +statistics a look at the top 100 projects on PyPI (ordered by total download +counts) shows us that within the Python space itself there is a majority of +projects using git: + +=== ========= ========== ====== === ==== +Git Mercurial Subversion Bazaar CVS None +=== ========= ========== ====== === ==== +62 22 7 4 1 1 +=== ========= ========== ====== === ==== + + +Chosing a DVCS which has the larger mindshare will make it more likely that any +particular person who has experience with DVCS at all will be able to +meaningfully use the DVCS that we have chosen without having to learn a new +tool. + +In addition to simply making it more likely that any individual will already +know how to use git, the number of projects and people using it means that the +resources for learning the tool are likely to be more fully fleshed out and +when you run into problems the liklihood that someone else had that problem +and posted a question and recieved an answer is also far likelier. + +Thirdly by using a more popular tool you also increase your options for tooling +*around* the DVCS itself. Looking at the various options for hosting +repositories it's extremely rare to find a hosting solution (whether OSS or +commerical) that supports Mercurial but does not support Git, on the flip side +there are a number of tools which support Git but do not support Mercurial. +Therefore the popularity of git increases the flexibility of our options going +into the future for what toolchain these projects use. + +Also by moving to the more popular DVCS we increase the likelhood that the +knowledge that the person has learned in contributing to these support +repositories will transfer to projects outside of the immediate CPython project +such as to the larger Python community which is primarily using Git hosted on +Github. + +In previous years there was concern about how well supported git was on Windows +in comparison to Mercurial. However git has grown to support Windows as a first +class citizen. In addition to that, for Windows users who are not well aquanted +with the Windows command line there are GUI options as well. + +On a techincal level git and Mercurial are fairly similar, however the git +branching model is signifcantly better than Mercurial "Named Branches" for +non-comitter contributors. Mercurial does have a "Bookmarks" extension however +this isn't quite as good as git's branching model. All bookmarks live in the +same namespace so it requires individual users to ensure that they namespace +the branchnames themselves lest the risk collision. It also is an extension +which requires new users to first discover they need an extension at all and +then figure out what they need to do in order to enable that extension. Since +it is an extension it also means that in general support for them outside of +Mercurial core is going to be less than 100% in comparison to git where the +feature is built in and core to using git at all. Finally users who are not +used to Mercurial are unlikely to discover bookmarks on their own, instead they +will likely attempt to use Mercurial's "Named Branches" which, given the fact +they live "forever", are not often what a project wants their contributors to +use. + + +Why Github? +----------- + +There are a number of software projects or web services which offer +functionality similar to that of Github. These range from commerical web +services such as a Bitbucket to self-hosted OSS solutions such as Kallithea or +Gitlab. This PEP proposes that we move these repositories to Github. + +There are two primary reasons for selecting Github: Popularity and +Quality/Polish. + +Github is currently the most popular hosted repository hosting according to +Alexa where it currently has a global rank of 121. Much like for Git itself by +choosing the most popular tool we gain benefits in increasing the likelhood +that a new contributor will have already experienced the toolchain, the quality +and availablity of the help, more and better tooling being built around it, and +the knowledge transfer to other projects. A look again at the top 100 projects +by download counts on PyPI shows the following hosting locations: + +====== ========= =========== ========= =========== ========== +GitHub BitBucket Google Code Launchpad SourceForge Other/Self +====== ========= =========== ========= =========== ========== +62 18 6 4 3 7 +====== ========= =========== ========= =========== ========== + +In addition to all of those reasons, Github also has the benefit that while +many of the options have similar features when you look at them in a feature +matrix the Github version of each of those features tend to work better and be +far more polished. This is hard to quantify objectively however it is a fairly +common sentiment if you go around and ask people who are using these services +often. + +Finally a reason to choose a web service at all over something that is +self-hosted is to be able to more efficiently use volunteer time and donated +resources. Every additional service hosted on the PSF infrastruture by the +PSF infrastructure team further spreads out the amount of time that the +volunteers on that team have to spend and uses some chunk of resources that +could potentionally be used for something where there is no free or affordable +hosted solution available. + +One concern that people do have with using a hosted service is that there is a +lack of control and that at some point in the future the service may no longer +be suitable. It is the opinion of this PEP that Github does not currently and +has not in the past engaged in any attempts to lock people into their platform +and that if at some point in the future Github is no longer suitable for one +reason or another than at that point we can look at migrating away from Github +onto a different solution. In other words, we'll cross that bridge if and when +we come to it. + + +Example: Scientific Python +-------------------------- + +One of the key ideas behind the move to both git and Github is that a feature +of a DVCS, the repository hosting, and the workflow used is the social network +and size of the community using said tools. We can see this is true by looking +at an example from a sub-community of the Python community: The Scientific +Python community. They have already migrated most of the key pieces of the +SciPy stack onto Github using the Pull Request based workflow starting with +IPython and as more projects moved over it became a natural default for new +projects. + +They claim to have seen a great benefit from this move, where it enables casual +contributors to easily move between different projects within their +sub-community without having to learn a special, bespoke workflow and a +different toolchain for each project. They've found that when people can use +their limited time on actually contributing instead of learning the different +tools and workflows that not only do they contribute more to one project, that +they also expand out and contribute to other projects. This move is also +attributed to making it commonplace for members of that community to go so far +as publishing their research and educational materials on Github as well. + +This showcases the real power behind moving to a highly popular toolchain and +workflow, as each variance introduces yet another hurdle for new and casual +contributors to get past and it makes the time spent learning that workflow +less reusable with other projects. + + +Migration +========= + +Through the use of hg-git [#hg-git]_ we can easily convert a Mercurial +repository to a Git repository by simply pushing the Mercurial repository to +the Git repository. People who wish to continue to use Mercurual locally can +then use hg-git going into the future using the new Github URL, however they +will need to re-clone their repositories as using Git as the server seems to +trigger a one time change of the changeset ids. + +As none of the selected repositories have any tags, branches, or bookmarks +other than the ``default`` branch the migration will simply map the ``default`` +branch in Mercurial to the ``master`` branch in git. + +In addition since none of the selected projects have any great need of a +complex bug tracker, they will also migrate their issue handling to using the +GitHub issues. + +In addition to the migration of the repository hosting itself there are a +number of locations for each particular repository which will require updating. +The bulk of these will simply be changing commands from the hg equivilant to +the git equivilant. + +In particular this will include: + +* Updating www.python.org to generate PEPs using a git clone and link to + Github. +* Updating docs.python.org to pull from Github instead of hg.python.org for the + devguide. +* Enabling the ability to send an email to python-checkins at python.org for each + push. +* Enabling the ability to send an IRC message to #python-dev on Freenode for + each push. +* Migrate any issues for these projects to their respective bug tracker on + Github. + +This will restore these repositories to similar functionality as they currently +have. In addition to this the migration will also include enabling testing for +each pull request using Travis CI [#travisci]_ where possible to ensure that +a new PR does not break the ability to render the documentation or PEPs. + + +User Access +=========== + +Moving to Github would involve adding an additional user account that will need +to be managed, however it also offers finer grained control, allowing the +ability to grant someone access to only one particular repository instead of +the coarser grained ACLs available on hg.python.org. + + +References +========== + +.. [#openhub-stats] `Open Hub Statistics ` +.. [#hg-git] `hg-git ` +.. [#travisci] `Travis CI ` + + +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: https://hg.python.org/peps From python-checkins at python.org Sun Nov 30 01:21:28 2014 From: python-checkins at python.org (donald.stufft) Date: Sun, 30 Nov 2014 00:21:28 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Some_gramatical_fixes_and_sli?= =?utf-8?q?ght_rewordings?= Message-ID: <20141130002127.84303.84705@psf.io> https://hg.python.org/peps/rev/6c6947dbd13f changeset: 5627:6c6947dbd13f user: Donald Stufft date: Sat Nov 29 19:21:23 2014 -0500 summary: Some gramatical fixes and slight rewordings files: pep-0481.txt | 117 +++++++++++++++++++-------------------- 1 files changed, 57 insertions(+), 60 deletions(-) diff --git a/pep-0481.txt b/pep-0481.txt --- a/pep-0481.txt +++ b/pep-0481.txt @@ -41,23 +41,22 @@ primary integration branch. This simplicity makes them very good targets for the "Pull Request" workflow that is commonly found on sites like Github. -However where PEP 474 wants to continue to use Mercurial and wishes to use an -OSS and self-hosted and therefore restricts itself to only those solutions this -PEP expands the scope of that to include migrating to Git and using Github. +However whereas PEP 474 proposes to continue to use Mercurial and restricts +itself to only solutions which are OSS and self-hosted, this PEP expands the +scope of that to include migrating to Git and using Github. The existing method of contributing to these repositories generally includes generating a patch and either uploading them to bugs.python.org or emailing them to peps at python.org. This process is unfriendly towards non-comitter -contributors as well as making the process harder than it needs to be for -comitters to accept the patches sent by users. In addition to the benefits -in the pull request workflow itself, this style of workflow also enables -non techincal contributors, especially those who do not know their way around -the DVCS of choice, to contribute using the web based editor. On the committer -side the Pull Requests enable them to tell, before merging, whether or not +contributors as well as cumbersome for comitters seeking to accept the patches +sent by users. In contrast, the Pull Request workflow style enables non +techincal contributors, especially those who do not know their way around the +DVCS of choice, to contribute using the web based editor. On the committer +side, the Pull Requests enable them to tell, before merging, whether or not a particular Pull Request will break anything. It also enables them to do a simple "push button" merge which does not require them to check out the changes locally. Another such feature that is useful in particular for docs, -is the ability to view a "prose" diff. This Github specific feature enables +is the ability to view a "prose" diff. This Github-specific feature enables a committer to view a diff of the rendered output which will hide things like reformatting a paragraph and show you what the actual "meat" of the change actually is. @@ -66,15 +65,14 @@ Why Git? -------- -Looking at the variety of DVCS which are available today it becomes fairly -clear that git has gotten the vast mindshare of people who are currently using -it. The Open Hub (Previously Ohloh) statistics [#openhub-stats]_ show that -currently 37% of the repositories Open Hub is indexing is using git which is -second only to SVN (which has 48%) while Mercurial has just 2% of the indexed -repositories (beating only bazaar which has 1%). In additon to the Open Hub -statistics a look at the top 100 projects on PyPI (ordered by total download -counts) shows us that within the Python space itself there is a majority of -projects using git: +Looking at the variety of DVCS which are available today, it becomes fairly +clear that git has the largest mindshare. The Open Hub (Previously Ohloh) +statistics [#openhub-stats]_ show that currently 37% of the repositories +indexed by Open Hub are using git which is second only to SVN (which has 48%), +while Mercurial has just 2% of the indexed repositories (beating only bazaar +which has 1%). In additon to the Open Hub statistics, a look at the top 100 +projects on PyPI (ordered by total download counts) shows that within the +Python space itself, the majority of projects use git. === ========= ========== ====== === ==== Git Mercurial Subversion Bazaar CVS None @@ -85,49 +83,47 @@ Chosing a DVCS which has the larger mindshare will make it more likely that any particular person who has experience with DVCS at all will be able to -meaningfully use the DVCS that we have chosen without having to learn a new -tool. +meaningfully contribute without having to learn a new tool. In addition to simply making it more likely that any individual will already know how to use git, the number of projects and people using it means that the -resources for learning the tool are likely to be more fully fleshed out and -when you run into problems the liklihood that someone else had that problem +resources for learning the tool are likely to be more fully fleshed out. +When you run into problems, the liklihood that someone else had that problem and posted a question and recieved an answer is also far likelier. -Thirdly by using a more popular tool you also increase your options for tooling -*around* the DVCS itself. Looking at the various options for hosting -repositories it's extremely rare to find a hosting solution (whether OSS or -commerical) that supports Mercurial but does not support Git, on the flip side +Thirdly, by using a more popular tool you also increase your options for +tooling *around* the DVCS itself. Looking at the various options for hosting +repositories, it's extremely rare to find a hosting solution (whether OSS or +commerical) that supports Mercurial but does not support Git. On the flip side, there are a number of tools which support Git but do not support Mercurial. Therefore the popularity of git increases the flexibility of our options going into the future for what toolchain these projects use. -Also by moving to the more popular DVCS we increase the likelhood that the +Also, by moving to the more popular DVCS, we increase the likelhood that the knowledge that the person has learned in contributing to these support repositories will transfer to projects outside of the immediate CPython project such as to the larger Python community which is primarily using Git hosted on Github. In previous years there was concern about how well supported git was on Windows -in comparison to Mercurial. However git has grown to support Windows as a first -class citizen. In addition to that, for Windows users who are not well aquanted -with the Windows command line there are GUI options as well. +in comparison to Mercurial. However, git has grown to support Windows as a +first class citizen. In addition to that, for Windows users who are not well +aquanted with the Windows command line, there are GUI options as well. On a techincal level git and Mercurial are fairly similar, however the git branching model is signifcantly better than Mercurial "Named Branches" for -non-comitter contributors. Mercurial does have a "Bookmarks" extension however +non-comitter contributors. Mercurial does have a "Bookmarks" extension, however this isn't quite as good as git's branching model. All bookmarks live in the same namespace so it requires individual users to ensure that they namespace the branchnames themselves lest the risk collision. It also is an extension -which requires new users to first discover they need an extension at all and -then figure out what they need to do in order to enable that extension. Since -it is an extension it also means that in general support for them outside of -Mercurial core is going to be less than 100% in comparison to git where the -feature is built in and core to using git at all. Finally users who are not -used to Mercurial are unlikely to discover bookmarks on their own, instead they -will likely attempt to use Mercurial's "Named Branches" which, given the fact -they live "forever", are not often what a project wants their contributors to -use. +which requires new users to first discover they need an extension at all, and +then figure out what they need to do in order to enable that extension. Since, +in contrast to the branching feature in git, this feature is a Mercurial +extension, in general, its support outside the Mercurial core is less +extensive. Finally, users who are not used to Mercurial are unlikely to +discover bookmarks on their own, instead they will likely attempt to use +Mercurial's "Named Branches" which, given the fact they live "forever", are not +often what a project wants their contributors to use. Why Github? @@ -142,8 +138,8 @@ Quality/Polish. Github is currently the most popular hosted repository hosting according to -Alexa where it currently has a global rank of 121. Much like for Git itself by -choosing the most popular tool we gain benefits in increasing the likelhood +Alexa, where it currently has a global rank of 121. Much like for Git itself, +by choosing the most popular tool we gain benefits in increasing the likelhood that a new contributor will have already experienced the toolchain, the quality and availablity of the help, more and better tooling being built around it, and the knowledge transfer to other projects. A look again at the top 100 projects @@ -162,7 +158,7 @@ common sentiment if you go around and ask people who are using these services often. -Finally a reason to choose a web service at all over something that is +Finally, a reason to choose a web service at all over something that is self-hosted is to be able to more efficiently use volunteer time and donated resources. Every additional service hosted on the PSF infrastruture by the PSF infrastructure team further spreads out the amount of time that the @@ -175,7 +171,7 @@ be suitable. It is the opinion of this PEP that Github does not currently and has not in the past engaged in any attempts to lock people into their platform and that if at some point in the future Github is no longer suitable for one -reason or another than at that point we can look at migrating away from Github +reason or another, then at that point we can look at migrating away from Github onto a different solution. In other words, we'll cross that bridge if and when we come to it. @@ -188,24 +184,25 @@ and size of the community using said tools. We can see this is true by looking at an example from a sub-community of the Python community: The Scientific Python community. They have already migrated most of the key pieces of the -SciPy stack onto Github using the Pull Request based workflow starting with -IPython and as more projects moved over it became a natural default for new -projects. +SciPy stack onto Github using the Pull Request based workflow. This process +started with IPython, and as more projects moved over it became a natural +default for new projects in the community. -They claim to have seen a great benefit from this move, where it enables casual -contributors to easily move between different projects within their +They claim to have seen a great benefit from this move, in that it enables +casual contributors to easily move between different projects within their sub-community without having to learn a special, bespoke workflow and a different toolchain for each project. They've found that when people can use their limited time on actually contributing instead of learning the different -tools and workflows that not only do they contribute more to one project, that -they also expand out and contribute to other projects. This move is also -attributed to making it commonplace for members of that community to go so far -as publishing their research and educational materials on Github as well. +tools and workflows that, not only do they contribute more to one project, but +that they also expand out and contribute to other projects. This move has also +been attributed to the increased tendency for members of that community to go +so far as publishing their research and educational materials on Github as +well. -This showcases the real power behind moving to a highly popular toolchain and -workflow, as each variance introduces yet another hurdle for new and casual -contributors to get past and it makes the time spent learning that workflow -less reusable with other projects. +This example showcases the real power behind moving to a highly popular +toolchain and workflow, as each variance introduces yet another hurdle for new +and casual contributors to get past and it makes the time spent learning that +workflow less reusable with other projects. Migration @@ -214,7 +211,7 @@ Through the use of hg-git [#hg-git]_ we can easily convert a Mercurial repository to a Git repository by simply pushing the Mercurial repository to the Git repository. People who wish to continue to use Mercurual locally can -then use hg-git going into the future using the new Github URL, however they +then use hg-git going into the future using the new Github URL. However they will need to re-clone their repositories as using Git as the server seems to trigger a one time change of the changeset ids. @@ -222,7 +219,7 @@ other than the ``default`` branch the migration will simply map the ``default`` branch in Mercurial to the ``master`` branch in git. -In addition since none of the selected projects have any great need of a +In addition, since none of the selected projects have any great need of a complex bug tracker, they will also migrate their issue handling to using the GitHub issues. -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Sun Nov 30 04:01:32 2014 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 30 Nov 2014 03:01:32 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_8_section_on_string_quote?= =?utf-8?q?s_by_Akira_Li=2E?= Message-ID: <20141130030129.84297.25841@psf.io> https://hg.python.org/peps/rev/d3d6128fa91e changeset: 5628:d3d6128fa91e user: Guido van Rossum date: Sat Nov 29 19:01:24 2014 -0800 summary: PEP 8 section on string quotes by Akira Li. files: pep-0008.txt | 13 +++++++++++++ 1 files changed, 13 insertions(+), 0 deletions(-) diff --git a/pep-0008.txt b/pep-0008.txt --- a/pep-0008.txt +++ b/pep-0008.txt @@ -390,6 +390,19 @@ public and internal interfaces still apply. +String Quotes +============= + +In Python, single-quoted strings and double-quoted strings are the +same. This PEP do not make a recommendation for this. Pick a rule +and stick to it. When a string contains single or double quote +characters, however, use the other one to avoid backslashes in the +string. It improves readability. + +For triple-quoted strings, always use double quote characters to be +consistent with the docstring convention in PEP 257. + + Whitespace in Expressions and Statements ======================================== -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Sun Nov 30 04:02:41 2014 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 30 Nov 2014 03:02:41 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Last_patch_was_by_Akira_Kitad?= =?utf-8?q?a=2C_not_Akira_Li=2E?= Message-ID: <20141130030240.126788.48691@psf.io> https://hg.python.org/peps/rev/c9cd9f3cc044 changeset: 5629:c9cd9f3cc044 user: Guido van Rossum date: Sat Nov 29 19:02:36 2014 -0800 summary: Last patch was by Akira Kitada, not Akira Li. files: pep-0008.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0008.txt b/pep-0008.txt --- a/pep-0008.txt +++ b/pep-0008.txt @@ -397,7 +397,7 @@ same. This PEP do not make a recommendation for this. Pick a rule and stick to it. When a string contains single or double quote characters, however, use the other one to avoid backslashes in the -string. It improves readability. +string. It improves readability. For triple-quoted strings, always use double quote characters to be consistent with the docstring convention in PEP 257. -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Sun Nov 30 04:57:22 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 30 Nov 2014 03:57:22 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_add_context_pa?= =?utf-8?q?rameter_to_xmlrpclib=2EServerProxy_=28=2322960=29?= Message-ID: <20141130035722.84297.90825@psf.io> https://hg.python.org/cpython/rev/62bd574e95d5 changeset: 93657:62bd574e95d5 branch: 2.7 parent: 93636:1ac5aec658f6 user: Benjamin Peterson date: Sat Nov 29 22:55:35 2014 -0500 summary: add context parameter to xmlrpclib.ServerProxy (#22960) Patch from Alex Gaynor. files: Doc/library/xmlrpclib.rst | 11 ++++++++--- Lib/xmlrpclib.py | 10 +++++++--- Misc/NEWS | 11 +++++++++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/Doc/library/xmlrpclib.rst b/Doc/library/xmlrpclib.rst --- a/Doc/library/xmlrpclib.rst +++ b/Doc/library/xmlrpclib.rst @@ -39,7 +39,7 @@ For https URIs, :mod:`xmlrpclib` now performs all the necessary certificate and hostname checks by default -.. class:: ServerProxy(uri[, transport[, encoding[, verbose[, allow_none[, use_datetime]]]]]) +.. class:: ServerProxy(uri[, transport[, encoding[, verbose[, allow_none[, use_datetime[, context]]]]]]) A :class:`ServerProxy` instance is an object that manages communication with a remote XML-RPC server. The required first argument is a URI (Uniform Resource @@ -57,11 +57,13 @@ :class:`datetime.datetime` objects may be passed to calls. Both the HTTP and HTTPS transports support the URL syntax extension for HTTP - Basic Authentication: ``http://user:pass at host:port/path``. The ``user:pass`` + Basic Authentication: ``http://user:pass at host:port/path``. The ``user:pass`` portion will be base64-encoded as an HTTP 'Authorization' header, and sent to the remote server as part of the connection process when invoking an XML-RPC method. You only need to use this if the remote server requires a Basic - Authentication user and password. + Authentication user and password. If an HTTPS url is provided, *context* may + be :class:`ssl.SSLContext` and configures the SSL settings of the underlying + HTTPS connection. The returned instance is a proxy object with methods that can be used to invoke corresponding RPC calls on the remote server. If the remote server supports the @@ -131,6 +133,9 @@ *__dict__* attribute and don't have a base class that is marshalled in a special way. + .. versionchanged:: 2.7.9 + Added the *context* argument. + .. seealso:: diff --git a/Lib/xmlrpclib.py b/Lib/xmlrpclib.py --- a/Lib/xmlrpclib.py +++ b/Lib/xmlrpclib.py @@ -1478,6 +1478,10 @@ class SafeTransport(Transport): """Handles an HTTPS transaction to an XML-RPC server.""" + def __init__(self, use_datetime=0, context=None): + Transport.__init__(self, use_datetime=use_datetime) + self.context = context + # FIXME: mostly untested def make_connection(self, host): @@ -1493,7 +1497,7 @@ ) else: chost, self._extra_headers, x509 = self.get_host_info(host) - self._connection = host, HTTPS(chost, None, **(x509 or {})) + self._connection = host, HTTPS(chost, None, context=context, **(x509 or {})) return self._connection[1] ## @@ -1536,7 +1540,7 @@ """ def __init__(self, uri, transport=None, encoding=None, verbose=0, - allow_none=0, use_datetime=0): + allow_none=0, use_datetime=0, context=None): # establish a "logical" server connection if isinstance(uri, unicode): @@ -1553,7 +1557,7 @@ if transport is None: if type == "https": - transport = SafeTransport(use_datetime=use_datetime) + transport = SafeTransport(use_datetime=use_datetime, context=context) else: transport = Transport(use_datetime=use_datetime) self.__transport = transport diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,6 +2,17 @@ Python News +++++++++++ +What's New in Python 2.7.9? +=========================== + +*Release date: 2014-12-XX* + +Library +------- + +- Issue #22960: Add a context argument to xmlrpclib.ServerProxy. + + What's New in Python 2.7.9 release candidate 1? =============================================== -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 30 04:57:22 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 30 Nov 2014 03:57:22 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf-8?q?_merge_2=2E7=2E9_release_branch?= Message-ID: <20141130035722.84303.63657@psf.io> https://hg.python.org/cpython/rev/f55ab5c2420f changeset: 93658:f55ab5c2420f branch: 2.7 parent: 93637:713e5814640d parent: 93657:62bd574e95d5 user: Benjamin Peterson date: Sat Nov 29 22:57:15 2014 -0500 summary: merge 2.7.9 release branch files: Doc/library/xmlrpclib.rst | 11 ++++++++--- Lib/xmlrpclib.py | 10 +++++++--- Misc/NEWS | 11 +++++++++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/Doc/library/xmlrpclib.rst b/Doc/library/xmlrpclib.rst --- a/Doc/library/xmlrpclib.rst +++ b/Doc/library/xmlrpclib.rst @@ -39,7 +39,7 @@ For https URIs, :mod:`xmlrpclib` now performs all the necessary certificate and hostname checks by default -.. class:: ServerProxy(uri[, transport[, encoding[, verbose[, allow_none[, use_datetime]]]]]) +.. class:: ServerProxy(uri[, transport[, encoding[, verbose[, allow_none[, use_datetime[, context]]]]]]) A :class:`ServerProxy` instance is an object that manages communication with a remote XML-RPC server. The required first argument is a URI (Uniform Resource @@ -57,11 +57,13 @@ :class:`datetime.datetime` objects may be passed to calls. Both the HTTP and HTTPS transports support the URL syntax extension for HTTP - Basic Authentication: ``http://user:pass at host:port/path``. The ``user:pass`` + Basic Authentication: ``http://user:pass at host:port/path``. The ``user:pass`` portion will be base64-encoded as an HTTP 'Authorization' header, and sent to the remote server as part of the connection process when invoking an XML-RPC method. You only need to use this if the remote server requires a Basic - Authentication user and password. + Authentication user and password. If an HTTPS url is provided, *context* may + be :class:`ssl.SSLContext` and configures the SSL settings of the underlying + HTTPS connection. The returned instance is a proxy object with methods that can be used to invoke corresponding RPC calls on the remote server. If the remote server supports the @@ -131,6 +133,9 @@ *__dict__* attribute and don't have a base class that is marshalled in a special way. + .. versionchanged:: 2.7.9 + Added the *context* argument. + .. seealso:: diff --git a/Lib/xmlrpclib.py b/Lib/xmlrpclib.py --- a/Lib/xmlrpclib.py +++ b/Lib/xmlrpclib.py @@ -1478,6 +1478,10 @@ class SafeTransport(Transport): """Handles an HTTPS transaction to an XML-RPC server.""" + def __init__(self, use_datetime=0, context=None): + Transport.__init__(self, use_datetime=use_datetime) + self.context = context + # FIXME: mostly untested def make_connection(self, host): @@ -1493,7 +1497,7 @@ ) else: chost, self._extra_headers, x509 = self.get_host_info(host) - self._connection = host, HTTPS(chost, None, **(x509 or {})) + self._connection = host, HTTPS(chost, None, context=context, **(x509 or {})) return self._connection[1] ## @@ -1536,7 +1540,7 @@ """ def __init__(self, uri, transport=None, encoding=None, verbose=0, - allow_none=0, use_datetime=0): + allow_none=0, use_datetime=0, context=None): # establish a "logical" server connection if isinstance(uri, unicode): @@ -1553,7 +1557,7 @@ if transport is None: if type == "https": - transport = SafeTransport(use_datetime=use_datetime) + transport = SafeTransport(use_datetime=use_datetime, context=context) else: transport = Transport(use_datetime=use_datetime) self.__transport = transport diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -31,6 +31,17 @@ Wieland Hoffmann. +What's New in Python 2.7.9? +=========================== + +*Release date: 2014-12-XX* + +Library +------- + +- Issue #22960: Add a context argument to xmlrpclib.ServerProxy. + + What's New in Python 2.7.9 release candidate 1? =============================================== -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 30 05:06:26 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 30 Nov 2014 04:06:26 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_this_is_why_te?= =?utf-8?q?sts_are_great?= Message-ID: <20141130040626.84277.62484@psf.io> https://hg.python.org/cpython/rev/fee117d5c894 changeset: 93659:fee117d5c894 branch: 2.7 parent: 93657:62bd574e95d5 user: Benjamin Peterson date: Sat Nov 29 23:06:06 2014 -0500 summary: this is why tests are great files: Lib/xmlrpclib.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/xmlrpclib.py b/Lib/xmlrpclib.py --- a/Lib/xmlrpclib.py +++ b/Lib/xmlrpclib.py @@ -1497,7 +1497,7 @@ ) else: chost, self._extra_headers, x509 = self.get_host_info(host) - self._connection = host, HTTPS(chost, None, context=context, **(x509 or {})) + self._connection = host, HTTPS(chost, None, context=self.context, **(x509 or {})) return self._connection[1] ## -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 30 05:06:26 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 30 Nov 2014 04:06:26 +0000 Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMi43IC0+IDIuNyk6?= =?utf-8?q?_merge_2=2E7=2E9_release_branch?= Message-ID: <20141130040626.126782.57435@psf.io> https://hg.python.org/cpython/rev/24f86799e9d3 changeset: 93660:24f86799e9d3 branch: 2.7 parent: 93658:f55ab5c2420f parent: 93659:fee117d5c894 user: Benjamin Peterson date: Sat Nov 29 23:06:22 2014 -0500 summary: merge 2.7.9 release branch files: Lib/xmlrpclib.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/xmlrpclib.py b/Lib/xmlrpclib.py --- a/Lib/xmlrpclib.py +++ b/Lib/xmlrpclib.py @@ -1497,7 +1497,7 @@ ) else: chost, self._extra_headers, x509 = self.get_host_info(host) - self._connection = host, HTTPS(chost, None, context=context, **(x509 or {})) + self._connection = host, HTTPS(chost, None, context=self.context, **(x509 or {})) return self._connection[1] ## -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 30 05:34:34 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 30 Nov 2014 04:34:34 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_add_context_pa?= =?utf-8?q?rameter_to_xmlrpclib=2EServerProxy_=28=2322960=29?= Message-ID: <20141130043434.126770.93330@psf.io> https://hg.python.org/cpython/rev/4b00430388ad changeset: 93661:4b00430388ad branch: 3.4 parent: 93655:e4b986350feb user: Benjamin Peterson date: Sat Nov 29 23:32:57 2014 -0500 summary: add context parameter to xmlrpclib.ServerProxy (#22960) Patch by Alex Gaynor. files: Doc/library/xmlrpc.client.rst | 9 +++++++-- Lib/xmlrpc/client.py | 15 ++++++++++++--- Misc/NEWS | 2 ++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst --- a/Doc/library/xmlrpc.client.rst +++ b/Doc/library/xmlrpc.client.rst @@ -34,7 +34,7 @@ .. class:: ServerProxy(uri, transport=None, encoding=None, verbose=False, \ allow_none=False, use_datetime=False, \ - use_builtin_types=False) + use_builtin_types=False, context=None) .. versionchanged:: 3.3 The *use_builtin_types* flag was added. @@ -63,7 +63,9 @@ portion will be base64-encoded as an HTTP 'Authorization' header, and sent to the remote server as part of the connection process when invoking an XML-RPC method. You only need to use this if the remote server requires a Basic - Authentication user and password. + Authentication user and password. If an HTTPS url is provided, *context* may + be :class:`ssl.SSLContext` and configures the SSL settings of the underlying + HTTPS connection. The returned instance is a proxy object with methods that can be used to invoke corresponding RPC calls on the remote server. If the remote server supports the @@ -127,6 +129,9 @@ :class:`Server` is retained as an alias for :class:`ServerProxy` for backwards compatibility. New code should use :class:`ServerProxy`. + .. versionchanged:: 3.4.3 + Added the *context* argument. + .. seealso:: diff --git a/Lib/xmlrpc/client.py b/Lib/xmlrpc/client.py --- a/Lib/xmlrpc/client.py +++ b/Lib/xmlrpc/client.py @@ -1323,6 +1323,11 @@ class SafeTransport(Transport): """Handles an HTTPS transaction to an XML-RPC server.""" + def __init__(self, use_datetime=False, use_builtin_types=False, *, + context=None): + super().__init__(use_datetime=use_datetime, use_builtin_types=use_builtin_types) + self.context = context + # FIXME: mostly untested def make_connection(self, host): @@ -1336,7 +1341,7 @@ # host may be a string, or a (host, x509-dict) tuple chost, self._extra_headers, x509 = self.get_host_info(host) self._connection = host, http.client.HTTPSConnection(chost, - None, **(x509 or {})) + None, context=self.context, **(x509 or {})) return self._connection[1] ## @@ -1379,7 +1384,8 @@ """ def __init__(self, uri, transport=None, encoding=None, verbose=False, - allow_none=False, use_datetime=False, use_builtin_types=False): + allow_none=False, use_datetime=False, use_builtin_types=False, + *, context=None): # establish a "logical" server connection # get the url @@ -1393,10 +1399,13 @@ if transport is None: if type == "https": handler = SafeTransport + extra_kwargs = {"context": context} else: handler = Transport + extra_kwargs = {} transport = handler(use_datetime=use_datetime, - use_builtin_types=use_builtin_types) + use_builtin_types=use_builtin_types, + **extra_kwargs) self.__transport = transport self.__encoding = encoding or 'utf-8' diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,8 @@ Library ------- +- Issue #22960: Add a context argument to xmlrpclib.ServerProxy constructor. + - Issue #22915: SAX parser now supports files opened with file descriptor or bytes path. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 30 05:34:34 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 30 Nov 2014 04:34:34 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjMjI5NjAp?= Message-ID: <20141130043434.84297.47166@psf.io> https://hg.python.org/cpython/rev/2a126ce6f83e changeset: 93662:2a126ce6f83e parent: 93656:4990157343c6 parent: 93661:4b00430388ad user: Benjamin Peterson date: Sat Nov 29 23:34:30 2014 -0500 summary: merge 3.4 (#22960) files: Doc/library/xmlrpc.client.rst | 11 ++++++++--- Lib/xmlrpc/client.py | 15 ++++++++++++--- Misc/NEWS | 2 ++ 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst --- a/Doc/library/xmlrpc.client.rst +++ b/Doc/library/xmlrpc.client.rst @@ -27,14 +27,14 @@ constructed data. If you need to parse untrusted or unauthenticated data see :ref:`xml-vulnerabilities`. -.. versionchanged:: 3.4.3 +.. versionchanged:: 3.5 For https URIs, :mod:`xmlrpc.client` now performs all the necessary certificate and hostname checks by default .. class:: ServerProxy(uri, transport=None, encoding=None, verbose=False, \ allow_none=False, use_datetime=False, \ - use_builtin_types=False) + use_builtin_types=False, context=None) .. versionchanged:: 3.3 The *use_builtin_types* flag was added. @@ -63,7 +63,9 @@ portion will be base64-encoded as an HTTP 'Authorization' header, and sent to the remote server as part of the connection process when invoking an XML-RPC method. You only need to use this if the remote server requires a Basic - Authentication user and password. + Authentication user and password. If an HTTPS url is provided, *context* may + be :class:`ssl.SSLContext` and configures the SSL settings of the underlying + HTTPS connection. The returned instance is a proxy object with methods that can be used to invoke corresponding RPC calls on the remote server. If the remote server supports the @@ -127,6 +129,9 @@ :class:`Server` is retained as an alias for :class:`ServerProxy` for backwards compatibility. New code should use :class:`ServerProxy`. + .. versionchanged:: 3.5 + Added the *context* argument. + .. seealso:: diff --git a/Lib/xmlrpc/client.py b/Lib/xmlrpc/client.py --- a/Lib/xmlrpc/client.py +++ b/Lib/xmlrpc/client.py @@ -1324,6 +1324,11 @@ class SafeTransport(Transport): """Handles an HTTPS transaction to an XML-RPC server.""" + def __init__(self, use_datetime=False, use_builtin_types=False, *, + context=None): + super().__init__(use_datetime=use_datetime, use_builtin_types=use_builtin_types) + self.context = context + # FIXME: mostly untested def make_connection(self, host): @@ -1337,7 +1342,7 @@ # host may be a string, or a (host, x509-dict) tuple chost, self._extra_headers, x509 = self.get_host_info(host) self._connection = host, http.client.HTTPSConnection(chost, - None, **(x509 or {})) + None, context=self.context, **(x509 or {})) return self._connection[1] ## @@ -1380,7 +1385,8 @@ """ def __init__(self, uri, transport=None, encoding=None, verbose=False, - allow_none=False, use_datetime=False, use_builtin_types=False): + allow_none=False, use_datetime=False, use_builtin_types=False, + *, context=None): # establish a "logical" server connection # get the url @@ -1394,10 +1400,13 @@ if transport is None: if type == "https": handler = SafeTransport + extra_kwargs = {"context": context} else: handler = Transport + extra_kwargs = {} transport = handler(use_datetime=use_datetime, - use_builtin_types=use_builtin_types) + use_builtin_types=use_builtin_types, + **extra_kwargs) self.__transport = transport self.__encoding = encoding or 'utf-8' diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -191,6 +191,8 @@ Library ------- +- Issue #22960: Add a context argument to xmlrpclib.ServerProxy constructor. + - Issue #22389: Add contextlib.redirect_stderr(). - Issue #21356: Make ssl.RAND_egd() optional to support LibreSSL. The -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 30 05:38:26 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 30 Nov 2014 04:38:26 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E4=29=3A_context_is_key?= =?utf-8?q?word-only?= Message-ID: <20141130043826.126766.33157@psf.io> https://hg.python.org/cpython/rev/086a21998db2 changeset: 93663:086a21998db2 branch: 3.4 parent: 93661:4b00430388ad user: Benjamin Peterson date: Sat Nov 29 23:38:17 2014 -0500 summary: context is keyword-only files: Doc/library/xmlrpc.client.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst --- a/Doc/library/xmlrpc.client.rst +++ b/Doc/library/xmlrpc.client.rst @@ -34,7 +34,7 @@ .. class:: ServerProxy(uri, transport=None, encoding=None, verbose=False, \ allow_none=False, use_datetime=False, \ - use_builtin_types=False, context=None) + use_builtin_types=False, *, context=None) .. versionchanged:: 3.3 The *use_builtin_types* flag was added. -- Repository URL: https://hg.python.org/cpython From python-checkins at python.org Sun Nov 30 05:38:27 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 30 Nov 2014 04:38:27 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40?= Message-ID: <20141130043827.116304.71758@psf.io> https://hg.python.org/cpython/rev/13e286c718cb changeset: 93664:13e286c718cb parent: 93662:2a126ce6f83e parent: 93663:086a21998db2 user: Benjamin Peterson date: Sat Nov 29 23:38:23 2014 -0500 summary: merge 3.4 files: Doc/library/xmlrpc.client.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst --- a/Doc/library/xmlrpc.client.rst +++ b/Doc/library/xmlrpc.client.rst @@ -34,7 +34,7 @@ .. class:: ServerProxy(uri, transport=None, encoding=None, verbose=False, \ allow_none=False, use_datetime=False, \ - use_builtin_types=False, context=None) + use_builtin_types=False, *, context=None) .. versionchanged:: 3.3 The *use_builtin_types* flag was added. -- Repository URL: https://hg.python.org/cpython From solipsis at pitrou.net Sun Nov 30 10:33:26 2014 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 30 Nov 2014 10:33:26 +0100 Subject: [Python-checkins] Daily reference leaks (4990157343c6): sum=1 Message-ID: results for 4990157343c6 on branch "default" -------------------------------------------- test_collections leaked [-2, 0, 0] references, sum=-2 test_functools leaked [0, 0, 3] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog2KIkcS', '-x'] From python-checkins at python.org Sun Nov 30 17:52:06 2014 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 30 Nov 2014 16:52:06 +0000 Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E4_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy40ICgjOTE3OSk=?= Message-ID: <20141130165205.69799.64131@psf.io> https://hg.python.org/cpython/rev/f385bc6e6e09 changeset: 93666:f385bc6e6e09 parent: 93664:13e286c718cb parent: 93665:d1f7c3f45ffe user: Benjamin Peterson date: Sun Nov 30 11:51:16 2014 -0500 summary: merge 3.4 (#9179) files: Lib/re.py | 5 +-- Lib/sre_parse.py | 33 +++++++-------------------- Lib/test/test_re.py | 38 +-------------------------------- Misc/NEWS | 3 -- 4 files changed, 12 insertions(+), 67 deletions(-) diff --git a/Lib/re.py b/Lib/re.py --- a/Lib/re.py +++ b/Lib/re.py @@ -351,11 +351,10 @@ s = sre_parse.Pattern() s.flags = flags for phrase, action in lexicon: - gid = s.opengroup() p.append(sre_parse.SubPattern(s, [ - (SUBPATTERN, (gid, sre_parse.parse(phrase, flags))), + (SUBPATTERN, (len(p)+1, sre_parse.parse(phrase, flags))), ])) - s.closegroup(gid, p[-1]) + s.groups = len(p)+1 p = sre_parse.SubPattern(s, [(BRANCH, (None, p))]) self.scanner = sre_compile.compile(p) def scan(self, string): diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -68,14 +68,12 @@ # master pattern object. keeps track of global attributes def __init__(self): self.flags = 0 + self.open = [] + self.groups = 1 self.groupdict = {} - self.subpatterns = [None] # group 0 - @property - def groups(self): - return len(self.subpatterns) def opengroup(self, name=None): gid = self.groups - self.subpatterns.append(None) + self.groups = gid + 1 if self.groups > MAXGROUPS: raise error("groups number is too large") if name is not None: @@ -84,11 +82,12 @@ raise error("redefinition of group name %r as group %d; " "was group %d" % (name, gid, ogid)) self.groupdict[name] = gid + self.open.append(gid) return gid - def closegroup(self, gid, p): - self.subpatterns[gid] = p + def closegroup(self, gid): + self.open.remove(gid) def checkgroup(self, gid): - return gid < self.groups and self.subpatterns[gid] is not None + return gid < self.groups and gid not in self.open class SubPattern: # a subpattern, in intermediate form @@ -184,21 +183,7 @@ elif op in _UNITCODES: lo = lo + 1 hi = hi + 1 - elif op is GROUPREF: - i, j = self.pattern.subpatterns[av].getwidth() - lo = lo + i - hi = hi + j - elif op is GROUPREF_EXISTS: - i, j = av[1].getwidth() - if av[2] is not None: - l, h = av[2].getwidth() - i = min(i, l) - j = max(j, h) - else: - i = 0 - lo = lo + i - hi = hi + j - elif op is SUCCESS: + elif op == SUCCESS: break self.width = min(lo, MAXREPEAT - 1), min(hi, MAXREPEAT) return self.width @@ -741,7 +726,7 @@ if not sourcematch(")"): raise source.error("unbalanced parenthesis") if group is not None: - state.closegroup(group, p) + state.closegroup(group) subpatternappend((SUBPATTERN, (group, p))) else: while True: diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -589,7 +589,7 @@ self.assertEqual(re.match("a.*b", "a\n\nb", re.DOTALL).group(0), "a\n\nb") - def test_lookahead(self): + def test_non_consuming(self): self.assertEqual(re.match("(a(?=\s[^a]))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[^a]*))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[abc]))", "a b").group(1), "a") @@ -603,42 +603,6 @@ self.assertEqual(re.match(r"(a)(?!\s\1)", "a b").group(1), "a") self.assertEqual(re.match(r"(a)(?!\s(abc|a))", "a b").group(1), "a") - # Group reference. - self.assertTrue(re.match(r'(a)b(?=\1)a', 'aba')) - self.assertIsNone(re.match(r'(a)b(?=\1)c', 'abac')) - # Conditional group reference. - self.assertTrue(re.match('(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) - self.assertIsNone(re.match('(?:(a)|(x))b(?=(?(2)c|x))c', 'abc')) - self.assertTrue(re.match('(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) - self.assertIsNone(re.match('(?:(a)|(x))b(?=(?(1)b|x))c', 'abc')) - self.assertTrue(re.match('(?:(a)|(x))b(?=(?(1)c|x))c', 'abc')) - # Group used before defined. - self.assertTrue(re.match('(a)b(?=(?(2)x|c))(c)', 'abc')) - self.assertIsNone(re.match('(a)b(?=(?(2)b|x))(c)', 'abc')) - self.assertTrue(re.match('(a)b(?=(?(1)c|x))(c)', 'abc')) - - def test_lookbehind(self): - self.assertTrue(re.match('ab(?<=b)c', 'abc')) - self.assertIsNone(re.match('ab(?<=c)c', 'abc')) - self.assertIsNone(re.match('ab(? https://hg.python.org/cpython/rev/961145c548e2 changeset: 93668:961145c548e2 branch: 2.7 parent: 93660:24f86799e9d3 parent: 93667:8a3807e15a1f user: Benjamin Peterson date: Sun Nov 30 11:51:48 2014 -0500 summary: merge 2.7.9 release branch files: Lib/re.py | 5 +-- Lib/sre_parse.py | 33 +++++++-------------------- Lib/test/test_re.py | 38 +-------------------------------- Misc/NEWS | 3 -- 4 files changed, 12 insertions(+), 67 deletions(-) diff --git a/Lib/re.py b/Lib/re.py --- a/Lib/re.py +++ b/Lib/re.py @@ -312,11 +312,10 @@ s = sre_parse.Pattern() s.flags = flags for phrase, action in lexicon: - gid = s.opengroup() p.append(sre_parse.SubPattern(s, [ - (SUBPATTERN, (gid, sre_parse.parse(phrase, flags))), + (SUBPATTERN, (len(p)+1, sre_parse.parse(phrase, flags))), ])) - s.closegroup(gid, p[-1]) + s.groups = len(p)+1 p = sre_parse.SubPattern(s, [(BRANCH, (None, p))]) self.scanner = sre_compile.compile(p) def scan(self, string): diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -66,25 +66,24 @@ # master pattern object. keeps track of global attributes def __init__(self): self.flags = 0 + self.open = [] + self.groups = 1 self.groupdict = {} - self.subpatterns = [None] # group 0 - @property - def groups(self): - return len(self.subpatterns) def opengroup(self, name=None): gid = self.groups - self.subpatterns.append(None) + self.groups = gid + 1 if name is not None: ogid = self.groupdict.get(name, None) if ogid is not None: raise error, ("redefinition of group name %s as group %d; " "was group %d" % (repr(name), gid, ogid)) self.groupdict[name] = gid + self.open.append(gid) return gid - def closegroup(self, gid, p): - self.subpatterns[gid] = p + def closegroup(self, gid): + self.open.remove(gid) def checkgroup(self, gid): - return gid < self.groups and self.subpatterns[gid] is not None + return gid < self.groups and gid not in self.open class SubPattern: # a subpattern, in intermediate form @@ -179,21 +178,7 @@ elif op in UNITCODES: lo = lo + 1 hi = hi + 1 - elif op is GROUPREF: - i, j = self.pattern.subpatterns[av].getwidth() - lo = lo + i - hi = hi + j - elif op is GROUPREF_EXISTS: - i, j = av[1].getwidth() - if av[2] is not None: - l, h = av[2].getwidth() - i = min(i, l) - j = max(j, h) - else: - i = 0 - lo = lo + i - hi = hi + j - elif op is SUCCESS: + elif op == SUCCESS: break self.width = min(lo, MAXREPEAT - 1), min(hi, MAXREPEAT) return self.width @@ -672,7 +657,7 @@ if not sourcematch(")"): raise error, "unbalanced parenthesis" if group is not None: - state.closegroup(group, p) + state.closegroup(group) subpatternappend((SUBPATTERN, (group, p))) else: while 1: diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -449,7 +449,7 @@ self.assertEqual(re.match("a.*b", "a\n\nb", re.DOTALL).group(0), "a\n\nb") - def test_lookahead(self): + def test_non_consuming(self): self.assertEqual(re.match("(a(?=\s[^a]))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[^a]*))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[abc]))", "a b").group(1), "a") @@ -463,42 +463,6 @@ self.assertEqual(re.match(r"(a)(?!\s\1)", "a b").group(1), "a") self.assertEqual(re.match(r"(a)(?!\s(abc|a))", "a b").group(1), "a") - # Group reference. - self.assertTrue(re.match(r'(a)b(?=\1)a', 'aba')) - self.assertIsNone(re.match(r'(a)b(?=\1)c', 'abac')) - # Conditional group reference. - self.assertTrue(re.match('(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) - self.assertIsNone(re.match('(?:(a)|(x))b(?=(?(2)c|x))c', 'abc')) - self.assertTrue(re.match('(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) - self.assertIsNone(re.match('(?:(a)|(x))b(?=(?(1)b|x))c', 'abc')) - self.assertTrue(re.match('(?:(a)|(x))b(?=(?(1)c|x))c', 'abc')) - # Group used before defined. - self.assertTrue(re.match('(a)b(?=(?(2)x|c))(c)', 'abc')) - self.assertIsNone(re.match('(a)b(?=(?(2)b|x))(c)', 'abc')) - self.assertTrue(re.match('(a)b(?=(?(1)c|x))(c)', 'abc')) - - def test_lookbehind(self): - self.assertTrue(re.match('ab(?<=b)c', 'abc')) - self.assertIsNone(re.match('ab(?<=c)c', 'abc')) - self.assertIsNone(re.match('ab(? https://hg.python.org/cpython/rev/8a3807e15a1f changeset: 93667:8a3807e15a1f branch: 2.7 parent: 93659:fee117d5c894 user: Benjamin Peterson date: Sun Nov 30 11:47:54 2014 -0500 summary: backout fac649bf2d10 (#9179) for further consideration files: Lib/re.py | 5 +-- Lib/sre_parse.py | 33 +++++++-------------------- Lib/test/test_re.py | 38 +-------------------------------- Misc/NEWS | 3 -- 4 files changed, 12 insertions(+), 67 deletions(-) diff --git a/Lib/re.py b/Lib/re.py --- a/Lib/re.py +++ b/Lib/re.py @@ -312,11 +312,10 @@ s = sre_parse.Pattern() s.flags = flags for phrase, action in lexicon: - gid = s.opengroup() p.append(sre_parse.SubPattern(s, [ - (SUBPATTERN, (gid, sre_parse.parse(phrase, flags))), + (SUBPATTERN, (len(p)+1, sre_parse.parse(phrase, flags))), ])) - s.closegroup(gid, p[-1]) + s.groups = len(p)+1 p = sre_parse.SubPattern(s, [(BRANCH, (None, p))]) self.scanner = sre_compile.compile(p) def scan(self, string): diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -66,25 +66,24 @@ # master pattern object. keeps track of global attributes def __init__(self): self.flags = 0 + self.open = [] + self.groups = 1 self.groupdict = {} - self.subpatterns = [None] # group 0 - @property - def groups(self): - return len(self.subpatterns) def opengroup(self, name=None): gid = self.groups - self.subpatterns.append(None) + self.groups = gid + 1 if name is not None: ogid = self.groupdict.get(name, None) if ogid is not None: raise error, ("redefinition of group name %s as group %d; " "was group %d" % (repr(name), gid, ogid)) self.groupdict[name] = gid + self.open.append(gid) return gid - def closegroup(self, gid, p): - self.subpatterns[gid] = p + def closegroup(self, gid): + self.open.remove(gid) def checkgroup(self, gid): - return gid < self.groups and self.subpatterns[gid] is not None + return gid < self.groups and gid not in self.open class SubPattern: # a subpattern, in intermediate form @@ -179,21 +178,7 @@ elif op in UNITCODES: lo = lo + 1 hi = hi + 1 - elif op is GROUPREF: - i, j = self.pattern.subpatterns[av].getwidth() - lo = lo + i - hi = hi + j - elif op is GROUPREF_EXISTS: - i, j = av[1].getwidth() - if av[2] is not None: - l, h = av[2].getwidth() - i = min(i, l) - j = max(j, h) - else: - i = 0 - lo = lo + i - hi = hi + j - elif op is SUCCESS: + elif op == SUCCESS: break self.width = min(lo, MAXREPEAT - 1), min(hi, MAXREPEAT) return self.width @@ -672,7 +657,7 @@ if not sourcematch(")"): raise error, "unbalanced parenthesis" if group is not None: - state.closegroup(group, p) + state.closegroup(group) subpatternappend((SUBPATTERN, (group, p))) else: while 1: diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -449,7 +449,7 @@ self.assertEqual(re.match("a.*b", "a\n\nb", re.DOTALL).group(0), "a\n\nb") - def test_lookahead(self): + def test_non_consuming(self): self.assertEqual(re.match("(a(?=\s[^a]))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[^a]*))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[abc]))", "a b").group(1), "a") @@ -463,42 +463,6 @@ self.assertEqual(re.match(r"(a)(?!\s\1)", "a b").group(1), "a") self.assertEqual(re.match(r"(a)(?!\s(abc|a))", "a b").group(1), "a") - # Group reference. - self.assertTrue(re.match(r'(a)b(?=\1)a', 'aba')) - self.assertIsNone(re.match(r'(a)b(?=\1)c', 'abac')) - # Conditional group reference. - self.assertTrue(re.match('(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) - self.assertIsNone(re.match('(?:(a)|(x))b(?=(?(2)c|x))c', 'abc')) - self.assertTrue(re.match('(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) - self.assertIsNone(re.match('(?:(a)|(x))b(?=(?(1)b|x))c', 'abc')) - self.assertTrue(re.match('(?:(a)|(x))b(?=(?(1)c|x))c', 'abc')) - # Group used before defined. - self.assertTrue(re.match('(a)b(?=(?(2)x|c))(c)', 'abc')) - self.assertIsNone(re.match('(a)b(?=(?(2)b|x))(c)', 'abc')) - self.assertTrue(re.match('(a)b(?=(?(1)c|x))(c)', 'abc')) - - def test_lookbehind(self): - self.assertTrue(re.match('ab(?<=b)c', 'abc')) - self.assertIsNone(re.match('ab(?<=c)c', 'abc')) - self.assertIsNone(re.match('ab(? https://hg.python.org/cpython/rev/d1f7c3f45ffe changeset: 93665:d1f7c3f45ffe branch: 3.4 parent: 93663:086a21998db2 user: Benjamin Peterson date: Sun Nov 30 11:49:00 2014 -0500 summary: backout 9fcf4008b626 (#9179) for further consideration files: Lib/re.py | 5 +-- Lib/sre_parse.py | 33 +++++++-------------------- Lib/test/test_re.py | 38 +-------------------------------- Misc/NEWS | 3 -- 4 files changed, 12 insertions(+), 67 deletions(-) diff --git a/Lib/re.py b/Lib/re.py --- a/Lib/re.py +++ b/Lib/re.py @@ -352,11 +352,10 @@ s = sre_parse.Pattern() s.flags = flags for phrase, action in lexicon: - gid = s.opengroup() p.append(sre_parse.SubPattern(s, [ - (SUBPATTERN, (gid, sre_parse.parse(phrase, flags))), + (SUBPATTERN, (len(p)+1, sre_parse.parse(phrase, flags))), ])) - s.closegroup(gid, p[-1]) + s.groups = len(p)+1 p = sre_parse.SubPattern(s, [(BRANCH, (None, p))]) self.scanner = sre_compile.compile(p) def scan(self, string): diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py --- a/Lib/sre_parse.py +++ b/Lib/sre_parse.py @@ -66,25 +66,24 @@ # master pattern object. keeps track of global attributes def __init__(self): self.flags = 0 + self.open = [] + self.groups = 1 self.groupdict = {} - self.subpatterns = [None] # group 0 - @property - def groups(self): - return len(self.subpatterns) def opengroup(self, name=None): gid = self.groups - self.subpatterns.append(None) + self.groups = gid + 1 if name is not None: ogid = self.groupdict.get(name, None) if ogid is not None: raise error("redefinition of group name %s as group %d; " "was group %d" % (repr(name), gid, ogid)) self.groupdict[name] = gid + self.open.append(gid) return gid - def closegroup(self, gid, p): - self.subpatterns[gid] = p + def closegroup(self, gid): + self.open.remove(gid) def checkgroup(self, gid): - return gid < self.groups and self.subpatterns[gid] is not None + return gid < self.groups and gid not in self.open class SubPattern: # a subpattern, in intermediate form @@ -182,21 +181,7 @@ elif op in UNITCODES: lo = lo + 1 hi = hi + 1 - elif op is GROUPREF: - i, j = self.pattern.subpatterns[av].getwidth() - lo = lo + i - hi = hi + j - elif op is GROUPREF_EXISTS: - i, j = av[1].getwidth() - if av[2] is not None: - l, h = av[2].getwidth() - i = min(i, l) - j = max(j, h) - else: - i = 0 - lo = lo + i - hi = hi + j - elif op is SUCCESS: + elif op == SUCCESS: break self.width = min(lo, MAXREPEAT - 1), min(hi, MAXREPEAT) return self.width @@ -724,7 +709,7 @@ if not sourcematch(")"): raise error("unbalanced parenthesis") if group is not None: - state.closegroup(group, p) + state.closegroup(group) subpatternappend((SUBPATTERN, (group, p))) else: while 1: diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -557,7 +557,7 @@ self.assertEqual(re.match("a.*b", "a\n\nb", re.DOTALL).group(0), "a\n\nb") - def test_lookahead(self): + def test_non_consuming(self): self.assertEqual(re.match("(a(?=\s[^a]))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[^a]*))", "a b").group(1), "a") self.assertEqual(re.match("(a(?=\s[abc]))", "a b").group(1), "a") @@ -571,42 +571,6 @@ self.assertEqual(re.match(r"(a)(?!\s\1)", "a b").group(1), "a") self.assertEqual(re.match(r"(a)(?!\s(abc|a))", "a b").group(1), "a") - # Group reference. - self.assertTrue(re.match(r'(a)b(?=\1)a', 'aba')) - self.assertIsNone(re.match(r'(a)b(?=\1)c', 'abac')) - # Conditional group reference. - self.assertTrue(re.match('(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) - self.assertIsNone(re.match('(?:(a)|(x))b(?=(?(2)c|x))c', 'abc')) - self.assertTrue(re.match('(?:(a)|(x))b(?=(?(2)x|c))c', 'abc')) - self.assertIsNone(re.match('(?:(a)|(x))b(?=(?(1)b|x))c', 'abc')) - self.assertTrue(re.match('(?:(a)|(x))b(?=(?(1)c|x))c', 'abc')) - # Group used before defined. - self.assertTrue(re.match('(a)b(?=(?(2)x|c))(c)', 'abc')) - self.assertIsNone(re.match('(a)b(?=(?(2)b|x))(c)', 'abc')) - self.assertTrue(re.match('(a)b(?=(?(1)c|x))(c)', 'abc')) - - def test_lookbehind(self): - self.assertTrue(re.match('ab(?<=b)c', 'abc')) - self.assertIsNone(re.match('ab(?<=c)c', 'abc')) - self.assertIsNone(re.match('ab(? https://hg.python.org/peps/rev/baf5957cb698 changeset: 5631:baf5957cb698 parent: 5630:d31fe28e2766 parent: 5629:c9cd9f3cc044 user: Donald Stufft date: Sun Nov 30 12:27:25 2014 -0500 summary: merge files: pep-0008.txt | 13 +++++++++++++ 1 files changed, 13 insertions(+), 0 deletions(-) diff --git a/pep-0008.txt b/pep-0008.txt --- a/pep-0008.txt +++ b/pep-0008.txt @@ -390,6 +390,19 @@ public and internal interfaces still apply. +String Quotes +============= + +In Python, single-quoted strings and double-quoted strings are the +same. This PEP do not make a recommendation for this. Pick a rule +and stick to it. When a string contains single or double quote +characters, however, use the other one to avoid backslashes in the +string. It improves readability. + +For triple-quoted strings, always use double quote characters to be +consistent with the docstring convention in PEP 257. + + Whitespace in Expressions and Statements ======================================== -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Sun Nov 30 18:27:30 2014 From: python-checkins at python.org (donald.stufft) Date: Sun, 30 Nov 2014 17:27:30 +0000 Subject: [Python-checkins] =?utf-8?q?peps=3A_Add_a_read-only_mirror_and_re?= =?utf-8?q?move_the_techincal_arguments?= Message-ID: <20141130172729.69799.4306@psf.io> https://hg.python.org/peps/rev/d31fe28e2766 changeset: 5630:d31fe28e2766 parent: 5627:6c6947dbd13f user: Donald Stufft date: Sun Nov 30 12:27:06 2014 -0500 summary: Add a read-only mirror and remove the techincal arguments files: pep-0481.txt | 18 +++--------------- 1 files changed, 3 insertions(+), 15 deletions(-) diff --git a/pep-0481.txt b/pep-0481.txt --- a/pep-0481.txt +++ b/pep-0481.txt @@ -110,21 +110,6 @@ first class citizen. In addition to that, for Windows users who are not well aquanted with the Windows command line, there are GUI options as well. -On a techincal level git and Mercurial are fairly similar, however the git -branching model is signifcantly better than Mercurial "Named Branches" for -non-comitter contributors. Mercurial does have a "Bookmarks" extension, however -this isn't quite as good as git's branching model. All bookmarks live in the -same namespace so it requires individual users to ensure that they namespace -the branchnames themselves lest the risk collision. It also is an extension -which requires new users to first discover they need an extension at all, and -then figure out what they need to do in order to enable that extension. Since, -in contrast to the branching feature in git, this feature is a Mercurial -extension, in general, its support outside the Mercurial core is less -extensive. Finally, users who are not used to Mercurial are unlikely to -discover bookmarks on their own, instead they will likely attempt to use -Mercurial's "Named Branches" which, given the fact they live "forever", are not -often what a project wants their contributors to use. - Why Github? ----------- @@ -240,6 +225,9 @@ each push. * Migrate any issues for these projects to their respective bug tracker on Github. +* Use hg-git to provide a read-only mirror on hg.python.org which will enable + read-only uses of the hg.python.org instances of the specified repositories + to remain the same. This will restore these repositories to similar functionality as they currently have. In addition to this the migration will also include enabling testing for -- Repository URL: https://hg.python.org/peps From python-checkins at python.org Sun Nov 30 19:41:15 2014 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 30 Nov 2014 18:41:15 +0000 Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2322902=3A_The_=22i?= =?utf-8?q?p=22_command_is_now_used_on_Linux_to_determine_MAC_address?= Message-ID: <20141130184114.116316.59514@psf.io> https://hg.python.org/cpython/rev/64bb01bce12c changeset: 93669:64bb01bce12c parent: 93666:f385bc6e6e09 user: Serhiy Storchaka date: Sun Nov 30 20:39:04 2014 +0200 summary: Issue #22902: The "ip" command is now used on Linux to determine MAC address in uuid.getnode(). Pach by Bruno Cauet. files: Lib/test/test_uuid.py | 6 ++++++ Lib/uuid.py | 11 +++++++++-- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 19 insertions(+), 2 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 @@ -321,6 +321,12 @@ self.check_node(node, 'ifconfig') @unittest.skipUnless(os.name == 'posix', 'requires Posix') + def test_ip_getnode(self): + node = uuid._ip_getnode() + if node is not None: + self.check_node(node, 'ip') + + @unittest.skipUnless(os.name == 'posix', 'requires Posix') def test_arp_getnode(self): node = uuid._arp_getnode() if node is not None: diff --git a/Lib/uuid.py b/Lib/uuid.py --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -356,6 +356,13 @@ if mac: return mac +def _ip_getnode(): + """Get the hardware address on Unix by running ip.""" + # This works on Linux with iproute2. + mac = _find_mac('ip', 'link list', [b'link/ether'], lambda i: i+1) + if mac: + return mac + def _arp_getnode(): """Get the hardware address on Unix by running arp.""" import os, socket @@ -538,8 +545,8 @@ if sys.platform == 'win32': getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode] else: - getters = [_unixdll_getnode, _ifconfig_getnode, _arp_getnode, - _lanscan_getnode, _netstat_getnode] + getters = [_unixdll_getnode, _ifconfig_getnode, _ip_getnode, + _arp_getnode, _lanscan_getnode, _netstat_getnode] for getter in getters + [_random_getnode]: try: diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -217,6 +217,7 @@ Terry Carroll Edward Catmur Lorenzo M. Catucci +Bruno Cauet Donn Cave Charles Cazabon Jes?s Cea Avi?n diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -191,6 +191,9 @@ Library ------- +- Issue #22902: The "ip" command is now used on Linux to determine MAC address + in uuid.getnode(). Pach by Bruno Cauet. + - Issue #22960: Add a context argument to xmlrpclib.ServerProxy constructor. - Issue #22389: Add contextlib.redirect_stderr(). -- Repository URL: https://hg.python.org/cpython