From python-checkins at python.org Wed May 1 00:17:55 2013 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 1 May 2013 00:17:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3NzEy?= =?utf-8?q?=3A_Fix_test=5Fgdb_failures_on_Ubuntu_13=2E04=2E?= Message-ID: <3b0cYv6mJPz7Ln1@mail.python.org> http://hg.python.org/cpython/rev/4e58cafbebfc changeset: 83576:4e58cafbebfc branch: 3.3 parent: 83573:474f28bf67b3 user: Antoine Pitrou date: Wed May 01 00:15:44 2013 +0200 summary: Issue #17712: Fix test_gdb failures on Ubuntu 13.04. files: Lib/test/test_gdb.py | 45 +++++++++++++++++-------------- Misc/NEWS | 2 + 2 files changed, 26 insertions(+), 21 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 @@ -145,29 +145,32 @@ # Use "args" to invoke gdb, capturing stdout, stderr: out, err = run_gdb(*args, PYTHONHASHSEED='0') - # Ignore some noise on stderr due to the pending breakpoint: - err = err.replace('Function "%s" not defined.\n' % breakpoint, '') - # Ignore some other noise on stderr (http://bugs.python.org/issue8600) - err = err.replace("warning: Unable to find libthread_db matching" - " inferior's thread library, thread debugging will" - " not be available.\n", - '') - err = err.replace("warning: Cannot initialize thread debugging" - " library: Debugger service failed\n", - '') - err = err.replace('warning: Could not load shared library symbols for ' - 'linux-vdso.so.1.\n' - 'Do you need "set solib-search-path" or ' - '"set sysroot"?\n', - '') - err = err.replace('warning: Could not load shared library symbols for ' - 'linux-gate.so.1.\n' - 'Do you need "set solib-search-path" or ' - '"set sysroot"?\n', - '') + errlines = err.splitlines() + unexpected_errlines = [] + + # Ignore some benign messages on stderr. + ignore_patterns = ( + 'Function "%s" not defined.' % breakpoint, + "warning: no loadable sections found in added symbol-file" + " system-supplied DSO", + "warning: Unable to find libthread_db matching" + " inferior's thread library, thread debugging will" + " not be available.", + "warning: Cannot initialize thread debugging" + " library: Debugger service failed", + 'warning: Could not load shared library symbols for ' + 'linux-vdso.so', + 'warning: Could not load shared library symbols for ' + 'linux-gate.so', + 'Do you need "set solib-search-path" or ' + '"set sysroot"?', + ) + for line in errlines: + if not line.startswith(ignore_patterns): + unexpected_errlines.append(line) # Ensure no unexpected error messages: - self.assertEqual(err, '') + self.assertEqual(unexpected_errlines, []) return out def get_gdb_repr(self, source, diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -147,6 +147,8 @@ Tests ----- +- Issue #17712: Fix test_gdb failures on Ubuntu 13.04. + - Issue #17835: Fix test_io when the default OS pipe buffer size is larger than one million bytes. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 1 00:17:57 2013 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 1 May 2013 00:17:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317712=3A_Fix_test=5Fgdb_failures_on_Ubuntu_13?= =?utf-8?q?=2E04=2E?= Message-ID: <3b0cYx2c7Wz7Lmk@mail.python.org> http://hg.python.org/cpython/rev/4e186581fea7 changeset: 83577:4e186581fea7 parent: 83574:747cede24367 parent: 83576:4e58cafbebfc user: Antoine Pitrou date: Wed May 01 00:17:45 2013 +0200 summary: Issue #17712: Fix test_gdb failures on Ubuntu 13.04. files: Lib/test/test_gdb.py | 45 +++++++++++++++++-------------- Misc/NEWS | 2 + 2 files changed, 26 insertions(+), 21 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 @@ -145,29 +145,32 @@ # Use "args" to invoke gdb, capturing stdout, stderr: out, err = run_gdb(*args, PYTHONHASHSEED='0') - # Ignore some noise on stderr due to the pending breakpoint: - err = err.replace('Function "%s" not defined.\n' % breakpoint, '') - # Ignore some other noise on stderr (http://bugs.python.org/issue8600) - err = err.replace("warning: Unable to find libthread_db matching" - " inferior's thread library, thread debugging will" - " not be available.\n", - '') - err = err.replace("warning: Cannot initialize thread debugging" - " library: Debugger service failed\n", - '') - err = err.replace('warning: Could not load shared library symbols for ' - 'linux-vdso.so.1.\n' - 'Do you need "set solib-search-path" or ' - '"set sysroot"?\n', - '') - err = err.replace('warning: Could not load shared library symbols for ' - 'linux-gate.so.1.\n' - 'Do you need "set solib-search-path" or ' - '"set sysroot"?\n', - '') + errlines = err.splitlines() + unexpected_errlines = [] + + # Ignore some benign messages on stderr. + ignore_patterns = ( + 'Function "%s" not defined.' % breakpoint, + "warning: no loadable sections found in added symbol-file" + " system-supplied DSO", + "warning: Unable to find libthread_db matching" + " inferior's thread library, thread debugging will" + " not be available.", + "warning: Cannot initialize thread debugging" + " library: Debugger service failed", + 'warning: Could not load shared library symbols for ' + 'linux-vdso.so', + 'warning: Could not load shared library symbols for ' + 'linux-gate.so', + 'Do you need "set solib-search-path" or ' + '"set sysroot"?', + ) + for line in errlines: + if not line.startswith(ignore_patterns): + unexpected_errlines.append(line) # Ensure no unexpected error messages: - self.assertEqual(err, '') + self.assertEqual(unexpected_errlines, []) return out def get_gdb_repr(self, source, diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -176,6 +176,8 @@ Tests ----- +- Issue #17712: Fix test_gdb failures on Ubuntu 13.04. + - Issue #17835: Fix test_io when the default OS pipe buffer size is larger than one million bytes. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 1 00:21:22 2013 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 1 May 2013 00:21:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3NzEy?= =?utf-8?q?=3A_Fix_test=5Fgdb_failures_on_Ubuntu_13=2E04=2E?= Message-ID: <3b0cdt11GVz7LlH@mail.python.org> http://hg.python.org/cpython/rev/c241831a91f2 changeset: 83578:c241831a91f2 branch: 2.7 parent: 83575:1b92a0112f5d user: Antoine Pitrou date: Wed May 01 00:15:44 2013 +0200 summary: Issue #17712: Fix test_gdb failures on Ubuntu 13.04. files: Lib/test/test_gdb.py | 46 ++++++++++++++++--------------- Misc/NEWS | 2 + 2 files changed, 26 insertions(+), 22 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 @@ -142,30 +142,32 @@ # Use "args" to invoke gdb, capturing stdout, stderr: out, err = run_gdb(*args, PYTHONHASHSEED='0') - # Ignore some noise on stderr due to the pending breakpoint: - err = err.replace('Function "%s" not defined.\n' % breakpoint, '') - # Ignore some other noise on stderr (http://bugs.python.org/issue8600) - err = err.replace("warning: Unable to find libthread_db matching" - " inferior's thread library, thread debugging will" - " not be available.\n", - '') - err = err.replace("warning: Cannot initialize thread debugging" - " library: Debugger service failed\n", - '') - err = err.replace('warning: Could not load shared library symbols for ' - 'linux-vdso.so.1.\n' - 'Do you need "set solib-search-path" or ' - '"set sysroot"?\n', - '') - err = err.replace('warning: Could not load shared library symbols for ' - 'linux-gate.so.1.\n' - 'Do you need "set solib-search-path" or ' - '"set sysroot"?\n', - '') + errlines = err.splitlines() + unexpected_errlines = [] + + # Ignore some benign messages on stderr. + ignore_patterns = ( + 'Function "%s" not defined.' % breakpoint, + "warning: no loadable sections found in added symbol-file" + " system-supplied DSO", + "warning: Unable to find libthread_db matching" + " inferior's thread library, thread debugging will" + " not be available.", + "warning: Cannot initialize thread debugging" + " library: Debugger service failed", + 'warning: Could not load shared library symbols for ' + 'linux-vdso.so', + 'warning: Could not load shared library symbols for ' + 'linux-gate.so', + 'Do you need "set solib-search-path" or ' + '"set sysroot"?', + ) + for line in errlines: + if not line.startswith(ignore_patterns): + unexpected_errlines.append(line) # Ensure no unexpected error messages: - self.assertEqual(err, '') - + self.assertEqual(unexpected_errlines, []) return out def get_gdb_repr(self, source, diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -76,6 +76,8 @@ Tests ----- +- Issue #17712: Fix test_gdb failures on Ubuntu 13.04. + - Issue #17065: Use process-unique key for winreg tests to avoid failures if test is run multiple times in parallel (eg: on a buildbot host). -- Repository URL: http://hg.python.org/cpython From eliswilson at hushmail.com Wed May 1 00:31:35 2013 From: eliswilson at hushmail.com (eliswilson at hushmail.com) Date: Tue, 30 Apr 2013 18:31:35 -0400 Subject: [Python-checkins] Biggest Fake Conference in Computer Science Message-ID: <20130430223135.D9EB914DBE1@smtp.hushmail.com> Biggest Fake Conference in Computer Science We are researchers from different parts of the world and conducted a study on the world?s biggest bogus computer science conference WORLDCOMP http://sites.google.com/site/worlddump1 organized by Prof. Hamid Arabnia from University of Georgia, USA. We submitted a fake paper to WORLDCOMP 2011 and again (the same paper with a modified title) to WORLDCOMP 2012. This paper had numerous fundamental mistakes. Sample statements from that paper include: (1). Binary logic is fuzzy logic and vice versa (2). Pascal developed fuzzy logic (3). Object oriented languages do not exhibit any polymorphism or inheritance (4). TCP and IP are synonyms and are part of OSI model (5). Distributed systems deal with only one computer (6). Laptop is an example for a super computer (7). Operating system is an example for computer hardware Also, our paper did not express any conceptual meaning. However, it was accepted both the times without any modifications (and without any reviews) and we were invited to submit the final paper and a payment of $500+ fee to present the paper. We decided to use the fee for better purposes than making Prof. Hamid Arabnia richer. After that, we received few reminders from WORLDCOMP to pay the fee but we never responded. This fake paper is different from the two fake papers already published (see https://sites.google.com/site/worlddump4 for details) in WORLDCOMP. We MUST say that you should look at the above website if you have any thoughts of participating in WORLDCOMP. DBLP and other indexing agencies have stopped indexing WORLDCOMP?s proceedings since 2011 due to its fakeness. See http://www.informatik.uni-trier.de/~ley/db/conf/icai/index.html for of one of the conferences of WORLDCOMP and notice that there is no listing after 2010. See Section 2 of http://sites.google.com/site/dumpconf for comments from well-known researchers about WORLDCOMP. The status of your WORLDCOMP papers can be changed from scientific to other (i.e., junk or non-technical) at any time. Better not to have a paper than having it in WORLDCOMP and spoil the resume and peace of mind forever! Our study revealed that WORLDCOMP is money making business, using University of Georgia mask, for Prof. Hamid Arabnia. He is throwing out a small chunk of that money (around 20 dollars per paper published in WORLDCOMP?s proceedings) to his puppet (Mr. Ashu Solo or A.M.G. Solo) who publicizes WORLDCOMP and also defends it at various forums, using fake/anonymous names. The puppet uses fake names and defames other conferences to divert traffic to WORLDCOMP. He also makes anonymous phone calls and threatens the critiques of WORLDCOMP (See Item 7 of Section 5 of above website). That is, the puppet does all his best to get a maximum number of papers published at WORLDCOMP to get more money into his (and Prof. Hamid Arabnia?s) pockets. Prof. Hamid Arabnia makes a lot of tricks. For example, he appeared in a newspaper to fool the public, claiming him a victim of cyber-attack (see Item 8 in Section 5 of above website). Monte Carlo Resort (the venue of WORLDCOMP for more than 10 years, until 2012) has refused to provide the venue for WORLDCOMP?13 because of the fears of their image being tarnished due to WORLDCOMP?s fraudulent activities. That is why WORLDCOMP?13 is taking place at a different resort. WORLDCOMP will not be held after 2013. The draft paper submission deadline is over but still there are no committee members, no reviewers, and there is no conference Chairman. The only contact details available on WORLDCOMP?s website is just an email address! We ask Prof. Hamid Arabnia to publish all reviews for all the papers (after blocking identifiable details) since 2000 conference. Reveal the names and affiliations of all the reviewers (for each year) and how many papers each reviewer had reviewed on average. We also ask him to look at the Open Challenge (Section 6) at https://sites.google.com/site/moneycomp1 and respond if he has any professional values. Sorry for posting to multiple lists. Spreading the word is the only way to stop this bogus conference. Please forward this message to other mailing lists and people. We are shocked with Prof. Hamid Arabnia and his puppet?s activities at http://worldcomp-fake-bogus.blogspot.com Search Google using the keyword worldcomp fake for additional links. From eliswilson at hushmail.com Wed May 1 01:24:40 2013 From: eliswilson at hushmail.com (eliswilson at hushmail.com) Date: Tue, 30 Apr 2013 19:24:40 -0400 Subject: [Python-checkins] Biggest Fake Conference in Computer Science Message-ID: <20130430232441.0944DE6736@smtp.hushmail.com> Biggest Fake Conference in Computer Science We are researchers from different parts of the world and conducted a study on the world?s biggest bogus computer science conference WORLDCOMP http://sites.google.com/site/worlddump1 organized by Prof. Hamid Arabnia from University of Georgia, USA. We submitted a fake paper to WORLDCOMP 2011 and again (the same paper with a modified title) to WORLDCOMP 2012. This paper had numerous fundamental mistakes. Sample statements from that paper include: (1). Binary logic is fuzzy logic and vice versa (2). Pascal developed fuzzy logic (3). Object oriented languages do not exhibit any polymorphism or inheritance (4). TCP and IP are synonyms and are part of OSI model (5). Distributed systems deal with only one computer (6). Laptop is an example for a super computer (7). Operating system is an example for computer hardware Also, our paper did not express any conceptual meaning. However, it was accepted both the times without any modifications (and without any reviews) and we were invited to submit the final paper and a payment of $500+ fee to present the paper. We decided to use the fee for better purposes than making Prof. Hamid Arabnia richer. After that, we received few reminders from WORLDCOMP to pay the fee but we never responded. This fake paper is different from the two fake papers already published (see https://sites.google.com/site/worlddump4 for details) in WORLDCOMP. We MUST say that you should look at the above website if you have any thoughts of participating in WORLDCOMP. DBLP and other indexing agencies have stopped indexing WORLDCOMP?s proceedings since 2011 due to its fakeness. See http://www.informatik.uni-trier.de/~ley/db/conf/icai/index.html for of one of the conferences of WORLDCOMP and notice that there is no listing after 2010. See Section 2 of http://sites.google.com/site/dumpconf for comments from well-known researchers about WORLDCOMP. The status of your WORLDCOMP papers can be changed from scientific to other (i.e., junk or non-technical) at any time. Better not to have a paper than having it in WORLDCOMP and spoil the resume and peace of mind forever! Our study revealed that WORLDCOMP is money making business, using University of Georgia mask, for Prof. Hamid Arabnia. He is throwing out a small chunk of that money (around 20 dollars per paper published in WORLDCOMP?s proceedings) to his puppet (Mr. Ashu Solo or A.M.G. Solo) who publicizes WORLDCOMP and also defends it at various forums, using fake/anonymous names. The puppet uses fake names and defames other conferences to divert traffic to WORLDCOMP. He also makes anonymous phone calls and threatens the critiques of WORLDCOMP (See Item 7 of Section 5 of above website). That is, the puppet does all his best to get a maximum number of papers published at WORLDCOMP to get more money into his (and Prof. Hamid Arabnia?s) pockets. Prof. Hamid Arabnia makes a lot of tricks. For example, he appeared in a newspaper to fool the public, claiming him a victim of cyber-attack (see Item 8 in Section 5 of above website). Monte Carlo Resort (the venue of WORLDCOMP for more than 10 years, until 2012) has refused to provide the venue for WORLDCOMP?13 because of the fears of their image being tarnished due to WORLDCOMP?s fraudulent activities. That is why WORLDCOMP?13 is taking place at a different resort. WORLDCOMP will not be held after 2013. The draft paper submission deadline is over but still there are no committee members, no reviewers, and there is no conference Chairman. The only contact details available on WORLDCOMP?s website is just an email address! We ask Prof. Hamid Arabnia to publish all reviews for all the papers (after blocking identifiable details) since 2000 conference. Reveal the names and affiliations of all the reviewers (for each year) and how many papers each reviewer had reviewed on average. We also ask him to look at the Open Challenge (Section 6) at https://sites.google.com/site/moneycomp1 and respond if he has any professional values. Sorry for posting to multiple lists. Spreading the word is the only way to stop this bogus conference. Please forward this message to other mailing lists and people. We are shocked with Prof. Hamid Arabnia and his puppet?s activities at http://worldcomp-fake-bogus.blogspot.com Search Google using the keyword worldcomp fake for additional links. From solipsis at pitrou.net Wed May 1 05:53:23 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 01 May 2013 05:53:23 +0200 Subject: [Python-checkins] Daily reference leaks (4e186581fea7): sum=2 Message-ID: results for 4e186581fea7 on branch "default" -------------------------------------------- test_unittest leaked [-1, 2, 1] memory blocks, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogFCAAGj', '-x'] From python-checkins at python.org Wed May 1 13:13:21 2013 From: python-checkins at python.org (ezio.melotti) Date: Wed, 1 May 2013 13:13:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE2NTE4OiBmaXgg?= =?utf-8?q?links_in_glossary_entry=2E?= Message-ID: <3b0xmd2gDMz7Ljn@mail.python.org> http://hg.python.org/cpython/rev/d1aa8a9eba44 changeset: 83579:d1aa8a9eba44 branch: 2.7 user: Ezio Melotti date: Wed May 01 14:13:05 2013 +0300 summary: #16518: fix links in glossary entry. files: Doc/glossary.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -78,8 +78,8 @@ `_, Python's creator. bytes-like object - An object that supports the :ref:`bufferobjects`, like :class:`bytes` or - :class:`bytearray`. + An object that supports the :ref:`buffer protocol `, + like :class:`str` or :class:`bytearray`. bytecode Python source code is compiled into bytecode, the internal representation -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 1 13:58:25 2013 From: python-checkins at python.org (ezio.melotti) Date: Wed, 1 May 2013 13:58:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbjogIzExMDc4OiB0ZXN0X19fYWxs?= =?utf-8?q?=5F=5F_now_checks_for_duplicates_in_=5F=5Fall=5F=5F=2E__Initial?= =?utf-8?q?_patch_by_R=2E?= Message-ID: <3b0ymd1lHTz7Ljn@mail.python.org> http://hg.python.org/cpython/rev/3f1bcfbed022 changeset: 83580:3f1bcfbed022 parent: 83577:4e186581fea7 user: Ezio Melotti date: Wed May 01 14:58:09 2013 +0300 summary: #11078: test___all__ now checks for duplicates in __all__. Initial patch by R. David Murray. files: Lib/test/test___all__.py | 25 ++++++++++++++----------- Misc/NEWS | 3 +++ 2 files changed, 17 insertions(+), 11 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 @@ -29,17 +29,20 @@ if not hasattr(sys.modules[modname], "__all__"): raise NoAll(modname) names = {} - try: - exec("from %s import *" % modname, names) - except Exception as e: - # Include the module name in the exception string - self.fail("__all__ failure in {}: {}: {}".format( - modname, e.__class__.__name__, e)) - if "__builtins__" in names: - del names["__builtins__"] - keys = set(names) - all = set(sys.modules[modname].__all__) - self.assertEqual(keys, all) + with self.subTest(module=modname): + try: + exec("from %s import *" % modname, names) + except Exception as e: + # Include the module name in the exception string + self.fail("__all__ failure in {}: {}: {}".format( + modname, e.__class__.__name__, e)) + if "__builtins__" in names: + del names["__builtins__"] + keys = set(names) + all_list = sys.modules[modname].__all__ + all_set = set(all_list) + self.assertCountEqual(all_set, all_list, "in module {}".format(modname)) + self.assertEqual(keys, all_set, "in module {}".format(modname)) def walk_modules(self, basedir, modpath): for fn in sorted(os.listdir(basedir)): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -176,6 +176,9 @@ Tests ----- +- Issue #11078: test___all__ now checks for duplicates in __all__. + Initial patch by R. David Murray. + - Issue #17712: Fix test_gdb failures on Ubuntu 13.04. - Issue #17835: Fix test_io when the default OS pipe buffer size is larger -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 1 15:09:50 2013 From: python-checkins at python.org (ezio.melotti) Date: Wed, 1 May 2013 15:09:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbjogIzE0Njc5OiBhZGQgYW4gX19h?= =?utf-8?q?ll=5F=5F_=28that_contains_only_HTMLParser=29_to_html=2Eparser?= =?utf-8?q?=2E?= Message-ID: <3b10M21WK6z7Ljj@mail.python.org> http://hg.python.org/cpython/rev/1f7ce8af3356 changeset: 83581:1f7ce8af3356 user: Ezio Melotti date: Wed May 01 16:09:34 2013 +0300 summary: #14679: add an __all__ (that contains only HTMLParser) to html.parser. files: Lib/html/parser.py | 2 ++ Misc/NEWS | 2 ++ 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/html/parser.py b/Lib/html/parser.py --- a/Lib/html/parser.py +++ b/Lib/html/parser.py @@ -12,6 +12,8 @@ import re import warnings +__all__ = ['HTMLParser'] + # Regular expressions used for parsing interesting_normal = re.compile('[&<]') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #14679: add an __all__ (that contains only HTMLParser) to html.parser. + - Issue #17853: Ensure locals of a class that shadow free variables always win over the closures. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 1 15:13:58 2013 From: python-checkins at python.org (ezio.melotti) Date: Wed, 1 May 2013 15:13:58 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Move_NEWS_entry_to_the_rig?= =?utf-8?q?ht_section=2E?= Message-ID: <3b10Rp6wdgzSPZ@mail.python.org> http://hg.python.org/cpython/rev/9af3f6af9a71 changeset: 83582:9af3f6af9a71 user: Ezio Melotti date: Wed May 01 16:13:45 2013 +0300 summary: Move NEWS entry to the right section. files: Misc/NEWS | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,8 +10,6 @@ Core and Builtins ----------------- -- Issue #14679: add an __all__ (that contains only HTMLParser) to html.parser. - - Issue #17853: Ensure locals of a class that shadow free variables always win over the closures. @@ -62,6 +60,8 @@ Library ------- +- Issue #14679: add an __all__ (that contains only HTMLParser) to html.parser. + - Issue #17358: Modules loaded by imp.load_source() and load_compiled() (and by extention load_module()) now have a better chance of working when reloaded. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 1 15:16:32 2013 From: python-checkins at python.org (charles-francois.natali) Date: Wed, 1 May 2013 15:16:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3NTI5?= =?utf-8?q?=3A_Fix_os=2Esendfile=28=29_documentation_regarding_the_type_of?= =?utf-8?q?_file?= Message-ID: <3b10Vm4dPhzSPZ@mail.python.org> http://hg.python.org/cpython/rev/4f45f9cde9b4 changeset: 83583:4f45f9cde9b4 branch: 3.3 parent: 83576:4e58cafbebfc user: Charles-Francois Natali date: Wed May 01 15:12:20 2013 +0200 summary: Issue #17529: Fix os.sendfile() documentation regarding the type of file descriptor supported. files: Doc/library/os.rst | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -999,9 +999,8 @@ On Mac OS X and FreeBSD, a value of 0 for *nbytes* specifies to send until the end of *in* is reached. - On Solaris, *out* may be the file descriptor of a regular file or the file - descriptor of a socket. On all other platforms, *out* must be the file - descriptor of an open socket. + All platforms support sockets as *out* file descriptor, and some platforms + allow other types (e.g. regular file, pipe) as well. Availability: Unix. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 1 15:16:33 2013 From: python-checkins at python.org (charles-francois.natali) Date: Wed, 1 May 2013 15:16:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317529=3A_Fix_os=2Esendfile=28=29_documentation_?= =?utf-8?q?regarding_the_type_of_file?= Message-ID: <3b10Vn6tg9z7Llb@mail.python.org> http://hg.python.org/cpython/rev/538055b28ba6 changeset: 83584:538055b28ba6 parent: 83580:3f1bcfbed022 parent: 83583:4f45f9cde9b4 user: Charles-Francois Natali date: Wed May 01 15:13:12 2013 +0200 summary: Issue #17529: Fix os.sendfile() documentation regarding the type of file descriptor supported. files: Doc/library/os.rst | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -999,9 +999,8 @@ On Mac OS X and FreeBSD, a value of 0 for *nbytes* specifies to send until the end of *in* is reached. - On Solaris, *out* may be the file descriptor of a regular file or the file - descriptor of a socket. On all other platforms, *out* must be the file - descriptor of an open socket. + All platforms support sockets as *out* file descriptor, and some platforms + allow other types (e.g. regular file, pipe) as well. Availability: Unix. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 1 15:16:35 2013 From: python-checkins at python.org (charles-francois.natali) Date: Wed, 1 May 2013 15:16:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?b?KTogTWVyZ2Uu?= Message-ID: <3b10Vq20lFzR6J@mail.python.org> http://hg.python.org/cpython/rev/9ea84f006892 changeset: 83585:9ea84f006892 parent: 83584:538055b28ba6 parent: 83582:9af3f6af9a71 user: Charles-Francois Natali date: Wed May 01 15:15:50 2013 +0200 summary: Merge. files: Lib/html/parser.py | 2 ++ Misc/NEWS | 2 ++ 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/html/parser.py b/Lib/html/parser.py --- a/Lib/html/parser.py +++ b/Lib/html/parser.py @@ -12,6 +12,8 @@ import re import warnings +__all__ = ['HTMLParser'] + # Regular expressions used for parsing interesting_normal = re.compile('[&<]') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -60,6 +60,8 @@ Library ------- +- Issue #14679: add an __all__ (that contains only HTMLParser) to html.parser. + - Issue #17358: Modules loaded by imp.load_source() and load_compiled() (and by extention load_module()) now have a better chance of working when reloaded. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 1 15:20:16 2013 From: python-checkins at python.org (ezio.melotti) Date: Wed, 1 May 2013 15:20:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE3ODAyOiBGaXgg?= =?utf-8?q?an_UnboundLocalError_in_html=2Eparser=2E__Initial_tests_by_Thom?= =?utf-8?q?as?= Message-ID: <3b10b42Mdbz7LkG@mail.python.org> http://hg.python.org/cpython/rev/9cb90c1a1a46 changeset: 83586:9cb90c1a1a46 branch: 3.3 parent: 83583:4f45f9cde9b4 user: Ezio Melotti date: Wed May 01 16:18:25 2013 +0300 summary: #17802: Fix an UnboundLocalError in html.parser. Initial tests by Thomas Barlow. files: Lib/html/parser.py | 1 + Lib/test/test_htmlparser.py | 14 ++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 18 insertions(+), 0 deletions(-) diff --git a/Lib/html/parser.py b/Lib/html/parser.py --- a/Lib/html/parser.py +++ b/Lib/html/parser.py @@ -249,6 +249,7 @@ if self.strict: self.error("EOF in middle of entity or char ref") else: + k = match.end() if k <= i: k = n i = self.updatepos(i, i + 1) diff --git a/Lib/test/test_htmlparser.py b/Lib/test/test_htmlparser.py --- a/Lib/test/test_htmlparser.py +++ b/Lib/test/test_htmlparser.py @@ -535,6 +535,20 @@ ] self._run_check(html, expected) + def test_EOF_in_charref(self): + # see #17802 + # This test checks that the UnboundLocalError reported in the issue + # is not raised, however I'm not sure the returned values are correct. + # Maybe HTMLParser should use self.unescape for these + data = [ + ('a&', [('data', 'a&')]), + ('a&b', [('data', 'ab')]), + ('a&b ', [('data', 'a'), ('entityref', 'b'), ('data', ' ')]), + ('a&b;', [('data', 'a'), ('entityref', 'b')]), + ] + for html, expected in data: + self._run_check(html, expected) + def test_unescape_function(self): p = self.get_collector() self.assertEqual(p.unescape('&#bad;'),'&#bad;') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -44,6 +44,9 @@ Library ------- +- Issue #17802: Fix an UnboundLocalError in html.parser. Initial tests by + Thomas Barlow. + - Issue #17192: Restore the patch for Issue #11729 which was ommitted in 3.3.1 when updating the bundled version of libffi used by ctypes. Update many libffi files that were missed in 3.3.1's update to libffi-3.0.13. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 1 15:20:17 2013 From: python-checkins at python.org (ezio.melotti) Date: Wed, 1 May 2013 15:20:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzE3ODAyOiBtZXJnZSB3aXRoIDMuMy4=?= Message-ID: <3b10b54pSNz7Lkp@mail.python.org> http://hg.python.org/cpython/rev/20be90a3a714 changeset: 83587:20be90a3a714 parent: 83585:9ea84f006892 parent: 83586:9cb90c1a1a46 user: Ezio Melotti date: Wed May 01 16:20:00 2013 +0300 summary: #17802: merge with 3.3. files: Lib/html/parser.py | 1 + Lib/test/test_htmlparser.py | 14 ++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 18 insertions(+), 0 deletions(-) diff --git a/Lib/html/parser.py b/Lib/html/parser.py --- a/Lib/html/parser.py +++ b/Lib/html/parser.py @@ -251,6 +251,7 @@ if self.strict: self.error("EOF in middle of entity or char ref") else: + k = match.end() if k <= i: k = n i = self.updatepos(i, i + 1) diff --git a/Lib/test/test_htmlparser.py b/Lib/test/test_htmlparser.py --- a/Lib/test/test_htmlparser.py +++ b/Lib/test/test_htmlparser.py @@ -535,6 +535,20 @@ ] self._run_check(html, expected) + def test_EOF_in_charref(self): + # see #17802 + # This test checks that the UnboundLocalError reported in the issue + # is not raised, however I'm not sure the returned values are correct. + # Maybe HTMLParser should use self.unescape for these + data = [ + ('a&', [('data', 'a&')]), + ('a&b', [('data', 'ab')]), + ('a&b ', [('data', 'a'), ('entityref', 'b'), ('data', ' ')]), + ('a&b;', [('data', 'a'), ('entityref', 'b')]), + ] + for html, expected in data: + self._run_check(html, expected) + def test_unescape_function(self): p = self.get_collector() self.assertEqual(p.unescape('&#bad;'),'&#bad;') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -62,6 +62,9 @@ - Issue #14679: add an __all__ (that contains only HTMLParser) to html.parser. +- Issue #17802: Fix an UnboundLocalError in html.parser. Initial tests by + Thomas Barlow. + - Issue #17358: Modules loaded by imp.load_source() and load_compiled() (and by extention load_module()) now have a better chance of working when reloaded. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 1 20:52:16 2013 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 1 May 2013 20:52:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2313721=3A_SSLSocke?= =?utf-8?q?t=2Egetpeercert=28=29_and_SSLSocket=2Edo=5Fhandshake=28=29_now_?= =?utf-8?q?raise_an?= Message-ID: <3b17y855vZz7Ll3@mail.python.org> http://hg.python.org/cpython/rev/e6b962fa44bb changeset: 83588:e6b962fa44bb user: Antoine Pitrou date: Wed May 01 20:52:07 2013 +0200 summary: Issue #13721: SSLSocket.getpeercert() and SSLSocket.do_handshake() now raise an OSError with ENOTCONN, instead of an AttributeError, when the SSLSocket is not connected. files: Lib/ssl.py | 34 ++++++++++++++++++++----------- Lib/test/test_ssl.py | 15 ++++++++++++++ Misc/NEWS | 4 +++ 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -299,7 +299,6 @@ self.server_hostname = server_hostname self.do_handshake_on_connect = do_handshake_on_connect self.suppress_ragged_eofs = suppress_ragged_eofs - connected = False if sock is not None: socket.__init__(self, family=sock.family, @@ -307,20 +306,22 @@ proto=sock.proto, fileno=sock.fileno()) self.settimeout(sock.gettimeout()) - # see if it's connected - try: - sock.getpeername() - except OSError as e: - if e.errno != errno.ENOTCONN: - raise - else: - connected = True sock.detach() elif fileno is not None: socket.__init__(self, fileno=fileno) else: socket.__init__(self, family=family, type=type, proto=proto) + # See if we are connected + try: + self.getpeername() + except OSError as e: + if e.errno != errno.ENOTCONN: + raise + connected = False + else: + connected = True + self._closed = False self._sslobj = None self._connected = connected @@ -339,6 +340,7 @@ except OSError as x: self.close() raise x + @property def context(self): return self._context @@ -356,6 +358,14 @@ # raise an exception here if you wish to check for spurious closes pass + def _check_connected(self): + if not self._connected: + # getpeername() will raise ENOTCONN if the socket is really + # not connected; note that we can be connected even without + # _connected being set, e.g. if connect() first returned + # EAGAIN. + self.getpeername() + def read(self, len=0, buffer=None): """Read up to LEN bytes and return them. Return zero-length string on EOF.""" @@ -390,6 +400,7 @@ certificate was provided, but not validated.""" self._checkClosed() + self._check_connected() return self._sslobj.peer_certificate(binary_form) def selected_npn_protocol(self): @@ -538,12 +549,11 @@ def _real_close(self): self._sslobj = None - # self._closed = True socket._real_close(self) def do_handshake(self, block=False): """Perform a TLS/SSL handshake.""" - + self._check_connected() timeout = self.gettimeout() try: if timeout == 0.0 and block: @@ -567,9 +577,9 @@ rc = None socket.connect(self, addr) if not rc: + self._connected = True if self.do_handshake_on_connect: self.do_handshake() - self._connected = True return rc except OSError: self._sslobj = None 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 @@ -17,6 +17,7 @@ import weakref import platform import functools +from unittest import mock ssl = support.import_module("ssl") @@ -1931,6 +1932,20 @@ self.assertIsInstance(remote, ssl.SSLSocket) self.assertEqual(peer, client_addr) + def test_getpeercert_enotconn(self): + context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + with context.wrap_socket(socket.socket()) as sock: + with self.assertRaises(OSError) as cm: + sock.getpeercert() + self.assertEqual(cm.exception.errno, errno.ENOTCONN) + + def test_do_handshake_enotconn(self): + context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + with context.wrap_socket(socket.socket()) as sock: + with self.assertRaises(OSError) as cm: + sock.do_handshake() + self.assertEqual(cm.exception.errno, errno.ENOTCONN) + def test_default_ciphers(self): context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) try: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -60,6 +60,10 @@ Library ------- +- Issue #13721: SSLSocket.getpeercert() and SSLSocket.do_handshake() now + raise an OSError with ENOTCONN, instead of an AttributeError, when the + SSLSocket is not connected. + - Issue #14679: add an __all__ (that contains only HTMLParser) to html.parser. - Issue #17802: Fix an UnboundLocalError in html.parser. Initial tests by -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu May 2 05:53:14 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 02 May 2013 05:53:14 +0200 Subject: [Python-checkins] Daily reference leaks (e6b962fa44bb): sum=1 Message-ID: results for e6b962fa44bb on branch "default" -------------------------------------------- test_unittest leaked [-1, 2, 0] memory blocks, sum=1 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogf5H8ZR', '-x'] From python-checkins at python.org Thu May 2 14:50:37 2013 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 2 May 2013 14:50:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIyAxNzIyIC0gQWRk?= =?utf-8?q?_a_note_on_urllib_helper_functions_like_splittype=2C_splithost_?= =?utf-8?q?etc=2E?= Message-ID: <3b1btP3blRz7Lk0@mail.python.org> http://hg.python.org/cpython/rev/c3656dca65e7 changeset: 83589:c3656dca65e7 branch: 2.7 parent: 83579:d1aa8a9eba44 user: Senthil Kumaran date: Thu May 02 05:50:21 2013 -0700 summary: # 1722 - Add a note on urllib helper functions like splittype, splithost etc. files: Doc/library/urllib.rst | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Doc/library/urllib.rst b/Doc/library/urllib.rst --- a/Doc/library/urllib.rst +++ b/Doc/library/urllib.rst @@ -280,6 +280,13 @@ find it, looks for proxy information from Mac OSX System Configuration for Mac OS X and Windows Systems Registry for Windows. +.. note:: + urllib also exposes certain utility functions like splittype, splithost and + others parsing url into various components. But it is recommended to use + :mod:`urlparse` for parsing urls than using these functions directly. + Python 3 does not expose these helper functions from :mod:`urllib.parse` + module. + URL Opener objects ------------------ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 2 14:52:21 2013 From: python-checkins at python.org (eli.bendersky) Date: Thu, 2 May 2013 14:52:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Overhaul_PEP_435_to_describe_?= =?utf-8?q?the_current_state_of_decisions=2C_which_deviates?= Message-ID: <3b1bwP3k0bzSDs@mail.python.org> http://hg.python.org/peps/rev/f924a0a3da3b changeset: 4869:f924a0a3da3b user: Eli Bendersky date: Thu May 02 05:51:33 2013 -0700 summary: Overhaul PEP 435 to describe the current state of decisions, which deviates from flufl.enum: 1. type(Color.red) == Color 2. All attrs of an enum that are not dunders and are not descriptors become enumeration values 3. Given class Color(Enum), it's only valid to subclass Color if Color defines no enumeration values 4. As a corollary to (3), class IntEnum(int, Enum) is also part of the stdlib (and serves as an example for others) Other issues that were contended recently but seem to have gotten resolved: A. __call__ for by-value access, explicit getattr() for by-name access. __getitem__ is removed from Enum B. __int__ is removed from Enum. It's present by definition in IntEnum NOTE: this is still an early draft that is in the process of being reviewed, so please treat it accordingly. files: pep-0435.txt | 459 +++++++++++++++++--------------------- 1 files changed, 204 insertions(+), 255 deletions(-) diff --git a/pep-0435.txt b/pep-0435.txt --- a/pep-0435.txt +++ b/pep-0435.txt @@ -3,22 +3,20 @@ Version: $Revision$ Last-Modified: $Date$ Author: Barry Warsaw , - Eli Bendersky + Eli Bendersky , + Ethan Furman Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 2013-02-23 Python-Version: 3.4 -Post-History: 2013-02-23 +Post-History: 2013-02-23, 2013-05-02 Abstract ======== This PEP proposes adding an enumeration type to the Python standard library. -Specifically, it proposes moving the existing ``flufl.enum`` package by Barry -Warsaw into the standard library. Much of this PEP is based on the "using" -[1]_ document from the documentation of ``flufl.enum``. An enumeration is a set of symbolic names bound to unique, constant values. Within an enumeration, the values can be compared by identity, and the @@ -28,7 +26,7 @@ Decision ======== -TODO: update decision here once pronouncement is made. +TODO: update decision here once pronouncement is made. [1]_ Status of discussions @@ -55,9 +53,11 @@ replacing existing standard library constants (such as ``socket.AF_INET``) with enumerations. -This PEP is an attempt to formalize this decision as well as discuss a number -of variations that were proposed and can be considered for inclusion. - +Further discussion in late April 2013 led to the conclusion that enumeration +members should belong to the type of their enum: ``type(Color.red) == Color``. +Guido has pronounced a decision on this issue [5]_, as well as related issues +of not allowing to subclass enums [6]_, unless they define no enumeration +members [7]_. Motivation ========== @@ -97,229 +97,151 @@ Enumerations are created using the class syntax, which makes them easy to read and write. An alternative creation method is described in `Convenience API`_. -To define an enumeration, derive from the ``Enum`` class and add attributes -with assignment to their integer values:: +To define an enumeration, subclass ``Enum`` as follows:: >>> from enum import Enum - >>> class Colors(Enum): + >>> class Color(Enum): ... red = 1 ... green = 2 ... blue = 3 -Enumeration values have nice, human readable string representations:: +**A note on nomenclature**: we call ``Color`` an *enumeration* (or *enum*) +and ``Color.red``, ``Color.green`` are *enumeration members* (or +*enum members*). Enumeration members also have *values* (the value of +``Color.red`` is ``1``, etc.) - >>> print(Colors.red) - Colors.red +Enumeration members have human readable string representations:: -...while their repr has more information:: + >>> print(Color.red) + Color.red - >>> print(repr(Colors.red)) - +...while their ``repr`` has more information:: -You can get the enumeration class object from an enumeration value:: + >>> print(repr(Color.red)) + Color.red [value=1] - >>> cls = Colors.red.enum - >>> print(cls.__name__) - Colors +The *type* of an enumeration member is the enumeration it belongs to:: + + >>> type(Color.red) + + >>> isinstance(Color.green, Color) + True + >>> Enums also have a property that contains just their item name:: - >>> print(Colors.red.name) + >>> print(Color.red.name) red - >>> print(Colors.green.name) - green - >>> print(Colors.blue.name) - blue -The str and repr of the enumeration class also provides useful information:: +Enumerations support iteration, in definition order:: - >>> print(Colors) - - >>> print(repr(Colors)) - + >>> class Shake(Enum): + ... vanilla = 7 + ... chocolate = 4 + ... cookies = 9 + ... mint = 3 + ... + >>> for shake in Shake: + ... print(shake) + ... + Shake.vanilla + Shake.chocolate + Shake.cookies + Shake.mint -The ``Enum`` class supports iteration. Iteration order is undefined:: - - >>> from operator import attrgetter - >>> by_value = attrgetter('value') - >>> class FiveColors(Enum): - ... pink = 4 - ... cyan = 5 - ... green = 2 - ... blue = 3 - ... red = 1 - >>> [v.name for v in sorted(FiveColors, by_value)] - ['red', 'green', 'blue', 'pink', 'cyan'] - -Iteration order over `IntEnum`_ enumerations are guaranteed to be -sorted by value. - - >>> class Toppings(IntEnum): - ... anchovies = 4 - ... black_olives = 8 - ... cheese = 2 - ... dried_tomatoes = 16 - ... eggplant = 1 - - >>> for value in Toppings: - ... print(value.name, '=', value.value) - eggplant = 1 - cheese = 2 - anchovies = 4 - black_olives = 8 - dried_tomatoes = 16 - -Enumeration values are hashable, so they can be used in dictionaries and sets:: +Enumeration members are hashable, so they can be used in dictionaries and sets:: >>> apples = {} - >>> apples[Colors.red] = 'red delicious' - >>> apples[Colors.green] = 'granny smith' + >>> apples[Color.red] = 'red delicious' + >>> apples[Color.green] = 'granny smith' >>> apples - {: 'granny smith', : 'red delicious'} + {Color.red [value=1]: 'red delicious', Color.green [value=2]: 'granny smith'} -Programmatic access to enum values ----------------------------------- +Programmatic access to enumeration members +------------------------------------------ -Sometimes it's useful to access values in enumerations programmatically (i.e. -situations where ``Colors.red`` won't do because the exact color is not known -at program-writing time). ``Enum`` allows such access by value:: +Sometimes it's useful to access members in enumerations programmatically (i.e. +situations where ``Color.red`` won't do because the exact color is not known +at program-writing time). ``Enum`` allows such access:: - >>> Colors[1] - - >>> Colors[2] - + >>> Color(1) + Color.red [value=1] + >>> Color(3) + Color.blue [value=3] -For consistency, an ``EnumValue`` can be used in the same access pattern:: - - >>> Colors[Colors.red] - - >>> Colors[Colors.green] - - -If you want to access enum values by *name*, ``Enum`` works as expected with +If you want to access enum members by *name*, ``Enum`` works as expected with ``getattr``:: - >>> getattr(Colors, 'red') - - >>> getattr(Colors, 'green') - + >>> getattr(Color, 'red') + Color.red [value=1] + >>> getattr(Color, 'green') + Color.green [value=2] + +Duplicating enum members and values +----------------------------------- + +Having two enum members with the same name is invalid:: + + >>> class Shape(Enum): + ... square = 2 + ... square = 3 + ... + Traceback (most recent call last): + ... + TypeError: Attempted to reuse key: square + +However, two enum members are allowed to have the same value. By-value lookup +will then access the *earliest defined* member:: + + >>> class Shape(Enum): + ... square = 2 + ... diamond = 1 + ... circle = 3 + ... alias_for_square = 2 + ... + >>> Shape.square + Shape.square [value=2] + >>> Shape.alias_for_square + Shape.square [value=2] + >>> Shape(2) + Shape.square [value=2] Comparisons ----------- -Enumeration values are compared by identity:: +Enumeration members are compared by identity:: - >>> Colors.red is Colors.red + >>> Color.red is Color.red True - >>> Colors.blue is Colors.blue + >>> Color.red is Color.blue + False + >>> Color.red is not Color.blue True - >>> Colors.red is not Colors.blue - True - >>> Colors.blue is Colors.red - False Ordered comparisons between enumeration values are *not* supported. Enums are not integers (but see `IntEnum`_ below):: - >>> Colors.red < Colors.blue + >>> Color.red < Color.blue Traceback (most recent call last): - ... - NotImplementedError - >>> Colors.red <= Colors.blue - Traceback (most recent call last): - ... - NotImplementedError - >>> Colors.blue > Colors.green - Traceback (most recent call last): - ... - NotImplementedError - >>> Colors.blue >= Colors.green - Traceback (most recent call last): - ... - NotImplementedError + File "", line 1, in + TypeError: unorderable types: Color() < Color() Equality comparisons are defined though:: - >>> Colors.blue == Colors.blue - True - >>> Colors.green != Colors.blue + >>> Color.blue == Color.red + False + >>> Color.blue == Color.blue True -Comparisons against non-enumeration values will always compare not equal:: +Comparisons against non-enumeration values will always compare not equal +(again, ``IntEnum`` was explicitly designed to behave differently, see +below):: - >>> Colors.green == 2 - False - >>> Colors.blue == 3 - False - >>> Colors.green != 3 - True - >>> Colors.green == 'green' + >>> Color.blue == 2 False - -Extending enumerations by subclassing -------------------------------------- - -You can extend previously defined Enums by subclassing:: - - >>> class MoreColors(Colors): - ... pink = 4 - ... cyan = 5 - -When extended in this way, the base enumeration's values are identical to the -same named values in the derived class:: - - >>> Colors.red is MoreColors.red - True - >>> Colors.blue is MoreColors.blue - True - -However, these are not doing comparisons against the integer -equivalent values, because if you define an enumeration with similar -item names and integer values, they will not be identical:: - - >>> class OtherColors(Enum): - ... red = 1 - ... blue = 2 - ... yellow = 3 - >>> Colors.red is OtherColors.red - False - >>> Colors.blue is not OtherColors.blue - True - -Because ``Colors`` and ``OtherColors`` are unrelated enumerations, -their values are not equal, and thus they may exist in the same set, -or as distinct keys in the same dictionary:: - - >>> Colors.red == OtherColors.red - False - >>> len(set((Colors.red, OtherColors.red))) - 2 - -You may not define two enumeration values with the same integer value:: - - >>> class Bad(Enum): - ... cartman = 1 - ... stan = 2 - ... kyle = 3 - ... kenny = 3 # Oops! - ... butters = 4 - Traceback (most recent call last): - ... - ValueError: Conflicting enums with value '3': 'kenny' and 'kyle' - -You also may not duplicate values in derived enumerations:: - - >>> class BadColors(Colors): - ... yellow = 4 - ... chartreuse = 2 # Oops! - Traceback (most recent call last): - ... - ValueError: Conflicting enums with value '2': 'green' and 'chartreuse' - - -Enumeration values ------------------- +Allowed members and attributs of enumerations +--------------------------------------------- The examples above use integers for enumeration values. Using integers is short and handy (and provided by default by the `Convenience API`_), but not @@ -330,9 +252,9 @@ >>> class SpecialId(Enum): ... selector = '$IM($N)' ... adaptor = '~$IM' - ... + ... >>> SpecialId.selector - + SpecialId.selector [value='$IM($N)'] >>> SpecialId.selector.value '$IM($N)' >>> a = SpecialId.adaptor @@ -342,8 +264,6 @@ True >>> print(a) SpecialId.adaptor - >>> print(a.value) - ~$IM Here ``Enum`` is used to provide readable (and syntactically valid!) names for some special values, as well as group them together. @@ -353,14 +273,73 @@ enumerations aren't important and enumerations are just used for their naming and comparison properties. +Enumerations are Python classes, and can have methods and special methods as +usual. If we have this enumeration:: + + class Mood(Enum): + funky = 1 + happy = 3 + + def describe(self): + # self is the member here + return self.name, self.value + + def __str__(self): + return 'my custom str! {0}'.format(self.value) + + @classmethod + def favorite_mood(cls): + # cls here is the enumeration + return cls.happy + +Then:: + + >>> Mood.favorite_mood() + Mood.happy [value=3] + >>> Mood.happy.describe() + ('happy', 3) + >>> str(Mood.funky) + 'my custom str! 1' + +The rules for what is allowed are as follows: all attributes defined within an +enumeration will become members of this enumeration, with the exception of +*__dunder__* names and descriptors; methods are descriptors too. + +Restricted subclassing of enumerations +-------------------------------------- + +Subclassing an enumeration is allowed only if the enumeration does not define +any members. So this is forbidden:: + + >>> class MoreColor(Color): + ... pink = 17 + ... + TypeError: Cannot subclass enumerations + +But this is allowed:: + + >>> class Foo(Enum): + ... def some_behavior(self): + ... pass + ... + >>> class Bar(Foo): + ... happy = 1 + ... sad = 2 + ... + +The rationale for this decision was given by Guido in [6]_. Allowing to +subclass enums that define members would lead to a violation of some +important invariants of types and instances. On the other hand, it +makes sense to allow sharing some common behavior between a group of +enumerations, and subclassing empty enumerations is also used to implement +``IntEnum``. IntEnum ------- -A variation of ``Enum`` is proposed where the enumeration values also -subclasses ``int`` - ``IntEnum``. These values can be compared to -integers; by extension, enumerations of different types can also be -compared to each other:: +A variation of ``Enum`` is proposed which is also a subclass of ``int``. +Members of an ``IntEnum`` can be compared to integers; by extension, +integer enumerations of different types can also be compared to each other:: >>> from enum import IntEnum >>> class Shape(IntEnum): @@ -384,11 +363,11 @@ ... circle = 1 ... square = 2 ... - >>> class Colors(Enum): + >>> class Color(Enum): ... red = 1 ... green = 2 ... - >>> Shape.circle == Colors.red + >>> Shape.circle == Color.red False ``IntEnum`` values behave like integers in other ways you'd expect:: @@ -425,21 +404,23 @@ The ``Enum`` class is callable, providing the following convenience API:: - >>> Animals = Enum('Animals', 'ant bee cat dog') - >>> Animals - - >>> Animals.ant - - >>> Animals.ant.value + >>> Animal = Enum('Animal', 'ant bee cat dog') + >>> Animal + + >>> Animal.ant + Animal.ant [value=1] + >>> Animal.ant.value 1 + >>> list(Animal) + [Animal.ant [value=1], Animal.bee [value=2], Animal.cat [value=3], Animal.dog [value=4]] The semantics of this API resemble ``namedtuple``. The first argument of the call to ``Enum`` is the name of the enumeration. The second argument is -a source of enumeration value names. It can be a whitespace-separated string +a source of enumeration member names. It can be a whitespace-separated string of names, a sequence of names or a sequence of 2-tuples with key/value pairs. The last option enables assigning arbitrary values to enumerations; the others auto-assign increasing integers starting with 1. A new class derived from -``Enum`` is returned. In other words, the above assignment to ``Animals`` is +``Enum`` is returned. In other words, the above assignment to ``Animal`` is equivalent to:: >>> class Animals(Enum): @@ -448,26 +429,22 @@ ... cat = 3 ... dog = 4 -Examples of alternative name/value specifications:: - - >>> Enum('Animals', ['ant', 'bee', 'cat', 'dog']) - - >>> Enum('Animals', (('ant', 'one'), ('bee', 'two'), ('cat', 'three'), ('dog', 'four'))) - - -The second argument can also be a dictionary mapping names to values:: - - >>> levels = dict(debug=10, info=20, warning=30, severe=40) - >>> Enum('Levels', levels) - - - Proposed variations =================== Some variations were proposed during the discussions in the mailing list. Here's some of the more popular ones. +flufl.enum +---------- + +``flufl.enum`` was the reference implementation upon which this PEP was +originally based. Eventually, it was decided against the inclusion of +``flufl.enum`` because its design separated enumeration members from +enumerations, so the former are not instances of the latter. Its design +also explicitly permits subclassing enumerations for extending them with +more members (due to the member/enum separation, the type invariants are not +violated in ``flufl.enum`` with such a scheme). Not having to specify values for enums -------------------------------------- @@ -487,7 +464,6 @@ definition of such enums baffling when first seen. Besides, explicit is better than implicit. - Using special names or forms to auto-assign enum values ------------------------------------------------------- @@ -519,7 +495,6 @@ Cons: actually longer to type in many simple cases. The argument of explicit vs. implicit applies here as well. - Use-cases in the standard library ================================= @@ -553,51 +528,24 @@ about a lot of networking code (especially implementation of protocols) and can be seen in test protocols written with the Tulip library as well. - -Differences from PEP 354 -======================== - -Unlike PEP 354, enumeration values are not defined as a sequence of strings, -but as attributes of a class. This design was chosen because it was felt that -class syntax is more readable. - -Unlike PEP 354, enumeration values require an explicit integer value. This -difference recognizes that enumerations often represent real-world values, or -must interoperate with external real-world systems. For example, to store an -enumeration in a database, it is better to convert it to an integer on the way -in and back to an enumeration on the way out. Providing an integer value also -provides an explicit ordering. However, there is no automatic conversion to -and from the integer values, because explicit is better than implicit. - -Unlike PEP 354, this implementation does use a metaclass to define the -enumeration's syntax, and allows for extended base-enumerations so that the -common values in derived classes are identical (a singleton model). While PEP -354 dismisses this approach for its complexity, in practice any perceived -complexity, though minimal, is hidden from users of the enumeration. - -Unlike PEP 354, enumeration values should only be tested by identity -comparison. This is to emphasize the fact that enumeration values are -singletons, much like ``None``. - - Acknowledgments =============== -This PEP describes the ``flufl.enum`` package by Barry Warsaw. ``flufl.enum`` -is based on an example by Jeremy Hylton. It has been modified and extended -by Barry Warsaw for use in the GNU Mailman [5]_ project. Ben Finney is the -author of the earlier enumeration PEP 354. - +This PEP was initially proposing including the ``flufl.enum`` package [8]_ +by Barry Warsaw into the stdlib, and is inspired in large parts by it. +Ben Finney is the author of the earlier enumeration PEP 354. References ========== -.. [1] http://pythonhosted.org/flufl.enum/docs/using.html +.. [1] Placeholder for pronouncement .. [2] http://www.python.org/dev/peps/pep-0354/ .. [3] http://mail.python.org/pipermail/python-ideas/2013-January/019003.html .. [4] http://mail.python.org/pipermail/python-ideas/2013-February/019373.html -.. [5] http://www.list.org - +.. [5] http://mail.python.org/pipermail/python-dev/2013-April/125687.html +.. [6] http://mail.python.org/pipermail/python-dev/2013-April/125716.html +.. [7] http://mail.python.org/pipermail/python-dev/2013-May/125859.html +.. [8] http://pythonhosted.org/flufl.enum/ Copyright ========= @@ -608,7 +556,8 @@ Todo ==== - * Mark PEP 354 "superseded by" this one, if accepted +* Mark PEP 354 "superseded by" this one, if accepted +* The last revision where flufl.enum was the approach is cb3c18a080a3 .. Local Variables: -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu May 2 19:44:26 2013 From: python-checkins at python.org (alexandre.vassalotti) Date: Thu, 2 May 2013 19:44:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2317892=3A_Fix_the?= =?utf-8?q?_name_of_=5FPyObject=5FCallMethodObjIdArgs?= Message-ID: <3b1kPQ0H8CzSS9@mail.python.org> http://hg.python.org/cpython/rev/8a364deb0225 changeset: 83590:8a364deb0225 parent: 83588:e6b962fa44bb user: Alexandre Vassalotti date: Thu May 02 10:44:04 2013 -0700 summary: Closes #17892: Fix the name of _PyObject_CallMethodObjIdArgs files: Include/abstract.h | 3 +-- Objects/abstract.c | 2 +- Python/import.c | 8 ++++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Include/abstract.h b/Include/abstract.h --- a/Include/abstract.h +++ b/Include/abstract.h @@ -339,11 +339,10 @@ PyAPI_FUNC(PyObject *) PyObject_CallMethodObjArgs(PyObject *o, PyObject *method, ...); - PyAPI_FUNC(PyObject *) _PyObject_CallMethodObjIdArgs(PyObject *o, + PyAPI_FUNC(PyObject *) _PyObject_CallMethodIdObjArgs(PyObject *o, struct _Py_Identifier *method, ...); - /* Call the method named m of object o with a variable number of C arguments. The C arguments are provided as PyObject * diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2343,7 +2343,7 @@ } PyObject * -_PyObject_CallMethodObjIdArgs(PyObject *callable, +_PyObject_CallMethodIdObjArgs(PyObject *callable, struct _Py_Identifier *name, ...) { PyObject *args, *tmp; diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -704,7 +704,7 @@ "no interpreter!"); } - pathobj = _PyObject_CallMethodObjIdArgs(interp->importlib, + pathobj = _PyObject_CallMethodIdObjArgs(interp->importlib, &PyId__get_sourcefile, cpathobj, NULL); if (pathobj == NULL) @@ -1441,7 +1441,7 @@ } if (initializing > 0) { /* _bootstrap._lock_unlock_module() releases the import lock */ - value = _PyObject_CallMethodObjIdArgs(interp->importlib, + value = _PyObject_CallMethodIdObjArgs(interp->importlib, &PyId__lock_unlock_module, abs_name, NULL); if (value == NULL) @@ -1459,7 +1459,7 @@ } else { /* _bootstrap._find_and_load() releases the import lock */ - mod = _PyObject_CallMethodObjIdArgs(interp->importlib, + mod = _PyObject_CallMethodIdObjArgs(interp->importlib, &PyId__find_and_load, abs_name, builtins_import, NULL); if (mod == NULL) { @@ -1528,7 +1528,7 @@ } } else { - final_mod = _PyObject_CallMethodObjIdArgs(interp->importlib, + final_mod = _PyObject_CallMethodIdObjArgs(interp->importlib, &PyId__handle_fromlist, mod, fromlist, builtins_import, NULL); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 3 00:34:13 2013 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 3 May 2013 00:34:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?cGVwczogQWRkIHRpbWUoKSwgY2FsbF9hdCgp?= =?utf-8?q?=2E_Remove_call=5Frepeatedly=28=29=2E_Get_rid_of_add=5F*=5Fhand?= =?utf-8?b?bGVyKCk=?= Message-ID: <3b1rqn1Pt1z7Lkl@mail.python.org> http://hg.python.org/peps/rev/26947623fc5d changeset: 4870:26947623fc5d user: Guido van Rossum date: Thu May 02 14:11:08 2013 -0700 summary: Add time(), call_at(). Remove call_repeatedly(). Get rid of add_*_handler() return value. files: pep-3156.txt | 80 +++++++++++++++++++++------------------ 1 files changed, 43 insertions(+), 37 deletions(-) diff --git a/pep-3156.txt b/pep-3156.txt --- a/pep-3156.txt +++ b/pep-3156.txt @@ -252,13 +252,12 @@ implementation may choose not to implement the internet/socket methods, and still conform to the other methods.) -- Resource management: ``close()``. +- Miscellaneous: ``close()``, ``time()``. - Starting and stopping: ``run_forever()``, ``run_until_complete()``, ``stop()``, ``is_running()``. -- Basic callbacks: ``call_soon()``, ``call_later()``, - ``call_repeatedly()``. +- Basic callbacks: ``call_soon()``, ``call_later()``, ``call_at()``. - Thread interaction: ``call_soon_threadsafe()``, ``wrap_future()``, ``run_in_executor()``, @@ -303,8 +302,8 @@ Required Event Loop Methods --------------------------- -Resource Management -''''''''''''''''''' +Miscellaneous +''''''''''''' - ``close()``. Closes the event loop, releasing any resources it may hold, such as the file descriptor used by ``epoll()`` or @@ -313,6 +312,12 @@ again. It may be called multiple times; subsequent calls are no-ops. +- ``time()``. Returns the current time according to the event loop's + clock. This may be ``time.time()`` or ``time.monotonic()`` or some + other system-specific clock, but it must return a float expressing + the time in units of approximately one second since some epoch. + (No clock is perfect -- see PEP 418.) + Starting and Stopping ''''''''''''''''''''' @@ -362,17 +367,27 @@ ``callback(*args)`` to be called approximately ``delay`` seconds in the future, once, unless cancelled. Returns a Handle representing the callback, whose ``cancel()`` method can be used to cancel the - callback. If ``delay`` is <= 0, this acts like ``call_soon()`` - instead. Otherwise, callbacks scheduled for exactly the same time - will be called in an undefined order. + callback. Callbacks scheduled in the past or at exactly the same + time will be called in an undefined order. -- ``call_repeatedly(interval, callback, **args)``. Like - ``call_later()`` but calls the callback repeatedly, every (approximately) - ``interval`` seconds, until the Handle returned is cancelled or - the callback raises an exception. The first call is in - approximately ``interval`` seconds. If for whatever reason the - callback happens later than scheduled, subsequent callbacks will be - delayed for (at least) the same amount. The ``interval`` must be > 0. +- ``call_at(when, callback, *args)``. This is like ``call_later()``, + but the time is expressed as an absolute time. There is a simple + equivalency: ``loop.call_later(delay, callback, *args)`` is the same + as ``loop.call_at(loop.time() + delay, callback, *args)``. + +Note: A previous version of this PEP defined a method named +``call_repeatedly()``, which promised to call a callback at regular +intervals. This has been withdrawn because the design of such a +function is overspecified. On the one hand, a simple timer loop can +easily be emulated using a callback that reschedules itself using +``call_later()``; it is also easy to write coroutine containing a loop +and a ``sleep()`` call (a toplevel function in the module, see below). +On the other hand, due to the complexities of accurate timekeeping +there are many traps and pitfalls here for the unaware (see PEP 418), +and different use cases require different behavior in edge cases. It +is impossible to offer an API for this purpose that is bullet-proof in +all cases, so it is deemed better to let application designers decide +for themselves what kind of timer loop to implement. Thread interaction '''''''''''''''''' @@ -656,12 +671,9 @@ - ``add_reader(fd, callback, *args)``. Arrange for ``callback(*args)`` to be called whenever file descriptor ``fd`` is - deemed ready for reading. Returns a Handle object which can be used - to cancel the callback. (However, it is strongly preferred to use - ``remove_reader()`` instead.) Calling ``add_reader()`` again for - the same file descriptor implies a call to ``remove_reader()`` for - the same file descriptor. (TBD: Since cancelling the Handle is not - recommended, perhaps we should return None instead?) + deemed ready for reading. Calling ``add_reader()`` again for the + same file descriptor implies a call to ``remove_reader()`` for the + same file descriptor. - ``add_writer(fd, callback, *args)``. Like ``add_reader()``, but registers the callback for writing instead of for reading. @@ -669,8 +681,7 @@ - ``remove_reader(fd)``. Cancels the current read callback for file descriptor ``fd``, if one is set. If no callback is currently set for the file descriptor, this is a no-op and returns ``False``. - Otherwise, it removes the callback arrangement, cancels the - corresponding Handle, and returns ``True``. + Otherwise, it removes the callback arrangement and returns ``True``. - ``remove_writer(fd)``. This is to ``add_writer()`` as ``remove_reader()`` is to ``add_reader()``. @@ -704,11 +715,7 @@ '''''''''''''''' - ``add_signal_handler(sig, callback, *args). Whenever signal ``sig`` - is received, arrange for ``callback(*args)`` to be called. Returns - a Handle which can be used to cancel the signal callback. - (Cancelling the handle causes ``remove_signal_handler()`` to be - called the next time the signal arrives. Explicitly calling - ``remove_signal_handler()`` is preferred.) + is received, arrange for ``callback(*args)`` to be called. Specifying another callback for the same signal replaces the previous handler (only one handler can be active per signal). The ``sig`` must be a valid sigal number defined in the ``signal`` @@ -777,11 +784,12 @@ Handles ------- -The various methods for registering callbacks (e.g. ``call_soon()`` -and ``add_reader()``) all return an object representing the -registration that can be used to cancel the callback. This object is -called a Handle (although its class name is not necessarily -``Handle``). Handles are opaque and have only one public method: +The various methods for registering one-off callbacks +(``call_soon()``, ``call_later()`` and ``call_at()``) all return an +object representing the registration that can be used to cancel the +callback. This object is called a Handle (although its class name is +not necessarily ``Handle``). Handles are opaque and have only one +public method: - ``cancel()``. Cancel the callback. @@ -1354,10 +1362,6 @@ Open Issues =========== -- A ``time()`` method that returns the time according to the function - used by the scheduler (e.g. ``time.monotonic()`` in Tulip's case)? - What's the use case? - - A fuller public API for Handle? What's the use case? - Should we require all event loops to implement ``sock_recv()`` and @@ -1410,6 +1414,8 @@ - PEP 3153, while rejected, has a good write-up explaining the need to separate transports and protocols. +- PEP 418 discusses the issues of timekeeping. + - Tulip repo: http://code.google.com/p/tulip/ - Nick Coghlan wrote a nice blog post with some background, thoughts -- Repository URL: http://hg.python.org/peps From ncoghlan at gmail.com Fri May 3 00:57:43 2013 From: ncoghlan at gmail.com (Nick Coghlan) Date: Fri, 3 May 2013 08:57:43 +1000 Subject: [Python-checkins] peps: Add time(), call_at(). Remove call_repeatedly(). Get rid of add_*_handler() In-Reply-To: <3b1rqn1Pt1z7Lkl@mail.python.org> References: <3b1rqn1Pt1z7Lkl@mail.python.org> Message-ID: On 3 May 2013 08:34, "guido.van.rossum" wrote: > > http://hg.python.org/peps/rev/26947623fc5d > changeset: 4870:26947623fc5d > user: Guido van Rossum > date: Thu May 02 14:11:08 2013 -0700 > summary: > Add time(), call_at(). Remove call_repeatedly(). Get rid of add_*_handler() return value. > > files: > pep-3156.txt | 80 +++++++++++++++++++++------------------ > 1 files changed, 43 insertions(+), 37 deletions(-) > > > diff --git a/pep-3156.txt b/pep-3156.txt > --- a/pep-3156.txt > +++ b/pep-3156.txt > @@ -252,13 +252,12 @@ > implementation may choose not to implement the internet/socket > methods, and still conform to the other methods.) > > -- Resource management: ``close()``. > +- Miscellaneous: ``close()``, ``time()``. > > - Starting and stopping: ``run_forever()``, ``run_until_complete()``, > ``stop()``, ``is_running()``. > > -- Basic callbacks: ``call_soon()``, ``call_later()``, > - ``call_repeatedly()``. > +- Basic callbacks: ``call_soon()``, ``call_later()``, ``call_at()``. > > - Thread interaction: ``call_soon_threadsafe()``, > ``wrap_future()``, ``run_in_executor()``, > @@ -303,8 +302,8 @@ > Required Event Loop Methods > --------------------------- > > -Resource Management > -''''''''''''''''''' > +Miscellaneous > +''''''''''''' > > - ``close()``. Closes the event loop, releasing any resources it may > hold, such as the file descriptor used by ``epoll()`` or > @@ -313,6 +312,12 @@ > again. It may be called multiple times; subsequent calls are > no-ops. > > +- ``time()``. Returns the current time according to the event loop's > + clock. This may be ``time.time()`` or ``time.monotonic()`` or some > + other system-specific clock, but it must return a float expressing > + the time in units of approximately one second since some epoch. > + (No clock is perfect -- see PEP 418.) Should the PEP allow event loops that use decimal.Decimal? > + > Starting and Stopping > ''''''''''''''''''''' > > @@ -362,17 +367,27 @@ > ``callback(*args)`` to be called approximately ``delay`` seconds in > the future, once, unless cancelled. Returns a Handle representing > the callback, whose ``cancel()`` method can be used to cancel the > - callback. If ``delay`` is <= 0, this acts like ``call_soon()`` > - instead. Otherwise, callbacks scheduled for exactly the same time > - will be called in an undefined order. > + callback. Callbacks scheduled in the past or at exactly the same > + time will be called in an undefined order. > > -- ``call_repeatedly(interval, callback, **args)``. Like > - ``call_later()`` but calls the callback repeatedly, every (approximately) > - ``interval`` seconds, until the Handle returned is cancelled or > - the callback raises an exception. The first call is in > - approximately ``interval`` seconds. If for whatever reason the > - callback happens later than scheduled, subsequent callbacks will be > - delayed for (at least) the same amount. The ``interval`` must be > 0. > +- ``call_at(when, callback, *args)``. This is like ``call_later()``, > + but the time is expressed as an absolute time. There is a simple > + equivalency: ``loop.call_later(delay, callback, *args)`` is the same > + as ``loop.call_at(loop.time() + delay, callback, *args)``. It may be worth explicitly noting the time scales where floating point's dynamic range starts to significantly limit granularity. Cheers, Nick. > + > +Note: A previous version of this PEP defined a method named > +``call_repeatedly()``, which promised to call a callback at regular > +intervals. This has been withdrawn because the design of such a > +function is overspecified. On the one hand, a simple timer loop can > +easily be emulated using a callback that reschedules itself using > +``call_later()``; it is also easy to write coroutine containing a loop > +and a ``sleep()`` call (a toplevel function in the module, see below). > +On the other hand, due to the complexities of accurate timekeeping > +there are many traps and pitfalls here for the unaware (see PEP 418), > +and different use cases require different behavior in edge cases. It > +is impossible to offer an API for this purpose that is bullet-proof in > +all cases, so it is deemed better to let application designers decide > +for themselves what kind of timer loop to implement. > > Thread interaction > '''''''''''''''''' > @@ -656,12 +671,9 @@ > > - ``add_reader(fd, callback, *args)``. Arrange for > ``callback(*args)`` to be called whenever file descriptor ``fd`` is > - deemed ready for reading. Returns a Handle object which can be used > - to cancel the callback. (However, it is strongly preferred to use > - ``remove_reader()`` instead.) Calling ``add_reader()`` again for > - the same file descriptor implies a call to ``remove_reader()`` for > - the same file descriptor. (TBD: Since cancelling the Handle is not > - recommended, perhaps we should return None instead?) > + deemed ready for reading. Calling ``add_reader()`` again for the > + same file descriptor implies a call to ``remove_reader()`` for the > + same file descriptor. > > - ``add_writer(fd, callback, *args)``. Like ``add_reader()``, > but registers the callback for writing instead of for reading. > @@ -669,8 +681,7 @@ > - ``remove_reader(fd)``. Cancels the current read callback for file > descriptor ``fd``, if one is set. If no callback is currently set > for the file descriptor, this is a no-op and returns ``False``. > - Otherwise, it removes the callback arrangement, cancels the > - corresponding Handle, and returns ``True``. > + Otherwise, it removes the callback arrangement and returns ``True``. > > - ``remove_writer(fd)``. This is to ``add_writer()`` as > ``remove_reader()`` is to ``add_reader()``. > @@ -704,11 +715,7 @@ > '''''''''''''''' > > - ``add_signal_handler(sig, callback, *args). Whenever signal ``sig`` > - is received, arrange for ``callback(*args)`` to be called. Returns > - a Handle which can be used to cancel the signal callback. > - (Cancelling the handle causes ``remove_signal_handler()`` to be > - called the next time the signal arrives. Explicitly calling > - ``remove_signal_handler()`` is preferred.) > + is received, arrange for ``callback(*args)`` to be called. > Specifying another callback for the same signal replaces the > previous handler (only one handler can be active per signal). The > ``sig`` must be a valid sigal number defined in the ``signal`` > @@ -777,11 +784,12 @@ > Handles > ------- > > -The various methods for registering callbacks (e.g. ``call_soon()`` > -and ``add_reader()``) all return an object representing the > -registration that can be used to cancel the callback. This object is > -called a Handle (although its class name is not necessarily > -``Handle``). Handles are opaque and have only one public method: > +The various methods for registering one-off callbacks > +(``call_soon()``, ``call_later()`` and ``call_at()``) all return an > +object representing the registration that can be used to cancel the > +callback. This object is called a Handle (although its class name is > +not necessarily ``Handle``). Handles are opaque and have only one > +public method: > > - ``cancel()``. Cancel the callback. > > @@ -1354,10 +1362,6 @@ > Open Issues > =========== > > -- A ``time()`` method that returns the time according to the function > - used by the scheduler (e.g. ``time.monotonic()`` in Tulip's case)? > - What's the use case? > - > - A fuller public API for Handle? What's the use case? > > - Should we require all event loops to implement ``sock_recv()`` and > @@ -1410,6 +1414,8 @@ > - PEP 3153, while rejected, has a good write-up explaining the need > to separate transports and protocols. > > +- PEP 418 discusses the issues of timekeeping. > + > - Tulip repo: http://code.google.com/p/tulip/ > > - Nick Coghlan wrote a nice blog post with some background, thoughts > > -- > Repository URL: http://hg.python.org/peps > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > -------------- next part -------------- An HTML attachment was scrubbed... URL: From python-checkins at python.org Fri May 3 01:35:38 2013 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 3 May 2013 01:35:38 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Small_corrections=2E?= Message-ID: <3b1tBf5Bjmz7LlS@mail.python.org> http://hg.python.org/peps/rev/7347527b5474 changeset: 4871:7347527b5474 user: Guido van Rossum date: Thu May 02 16:35:23 2013 -0700 summary: Small corrections. files: pep-3156.txt | 37 ++++++++++++++++++++----------------- 1 files changed, 20 insertions(+), 17 deletions(-) diff --git a/pep-3156.txt b/pep-3156.txt --- a/pep-3156.txt +++ b/pep-3156.txt @@ -360,8 +360,10 @@ ''''''''''''''' - ``call_soon(callback, *args)``. This schedules a callback to be - called as soon as possible. It guarantees that callbacks are called - in the order in which they were scheduled. + called as soon as possible. Returns a Handle representing the + callback, whose ``cancel()`` method can be used to cancel the + callback. It guarantees that callbacks are called in the order in + which they were scheduled. - ``call_later(delay, callback, *args)``. Arrange for ``callback(*args)`` to be called approximately ``delay`` seconds in @@ -371,9 +373,10 @@ time will be called in an undefined order. - ``call_at(when, callback, *args)``. This is like ``call_later()``, - but the time is expressed as an absolute time. There is a simple - equivalency: ``loop.call_later(delay, callback, *args)`` is the same - as ``loop.call_at(loop.time() + delay, callback, *args)``. + but the time is expressed as an absolute time. Returns a similar + Handle. There is a simple equivalency: ``loop.call_later(delay, + callback, *args)`` is the same as ``loop.call_at(loop.time() + + delay, callback, *args)``. Note: A previous version of this PEP defined a method named ``call_repeatedly()``, which promised to call a callback at regular @@ -785,11 +788,11 @@ ------- The various methods for registering one-off callbacks -(``call_soon()``, ``call_later()`` and ``call_at()``) all return an -object representing the registration that can be used to cancel the -callback. This object is called a Handle (although its class name is -not necessarily ``Handle``). Handles are opaque and have only one -public method: +(``call_soon()``, ``call_later()``, ``call_at()`` and +``call_soon_threadsafe()``) all return an object representing the +registration that can be used to cancel the callback. This object is +called a Handle (although its class name is not necessarily +``Handle``). Handles are opaque and have only one public method: - ``cancel()``. Cancel the callback. @@ -834,10 +837,10 @@ Difference with PEP 3148: The callback is never called immediately, and always in the context of the caller. (Typically, a context is a thread.) You can think of this as calling the callback through - ``call_soon()``. Note that the callback (unlike all other callbacks - defined in this PEP, and ignoring the convention from the section - "Callback Style" below) is always called with a single argument, the - Future object, and should not be a Handle object. + ``call_soon()``. Note that in order to match PEP 3148, the callback + (unlike all other callbacks defined in this PEP, and ignoring the + convention from the section "Callback Style" below) is always called + with a single argument, the Future object. - ``set_result(result)``. The Future must not be done (nor cancelled) already. This makes the Future done and schedules the callbacks. @@ -1312,9 +1315,9 @@ Cancelling a task that's not done yet prevents its coroutine from completing. In this case a ``CancelledError`` exception is thrown -into the coroutine that it may catch to further handle cancellation. -If the exception is not caught, the generator will be properly -finalized anyway, as described in PEP 342. +into the coroutine, which it may catch to propagate cancellation to +other Futures. If the exception is not caught, the generator will be +properly finalized anyway, as described in PEP 342. Tasks are also useful for interoperating between coroutines and callback-based frameworks like Twisted. After converting a coroutine -- Repository URL: http://hg.python.org/peps From solipsis at pitrou.net Fri May 3 06:03:02 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 03 May 2013 06:03:02 +0200 Subject: [Python-checkins] Daily reference leaks (8a364deb0225): sum=2 Message-ID: results for 8a364deb0225 on branch "default" -------------------------------------------- test_unittest leaked [-1, 1, 2] memory blocks, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/refloghLGWl4', '-x'] From python-checkins at python.org Fri May 3 09:59:33 2013 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 3 May 2013 09:59:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1NTM1?= =?utf-8?q?=3A__Fix_regression_in_pickling_of_named_tuples=2E?= Message-ID: <3b25N56nzVz7LkP@mail.python.org> http://hg.python.org/cpython/rev/18303391b981 changeset: 83591:18303391b981 branch: 2.7 parent: 83589:c3656dca65e7 user: Raymond Hettinger date: Fri May 03 00:59:20 2013 -0700 summary: Issue #15535: Fix regression in pickling of named tuples. files: Doc/library/collections.rst | 4 +--- Lib/collections.py | 2 -- Lib/test/test_collections.py | 2 +- Misc/NEWS | 3 +++ 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -628,9 +628,7 @@ 'Return a new OrderedDict which maps field names to their values' return OrderedDict(zip(self._fields, self)) - __dict__ = property(_asdict) - - def _replace(_self, **kwds): + def _replace(_self, **kwds): 'Return a new Point object replacing specified fields with new values' result = _self._make(map(kwds.pop, ('x', 'y'), _self)) if kwds: diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -259,8 +259,6 @@ 'Return a new OrderedDict which maps field names to their values' return OrderedDict(zip(self._fields, self)) - __dict__ = property(_asdict) - def _replace(_self, **kwds): 'Return a new {typename} object replacing specified fields with new values' result = _self._make(map(kwds.pop, {field_names!r}, _self)) diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -78,12 +78,12 @@ self.assertRaises(TypeError, eval, 'Point(XXX=1, y=2)', locals()) # wrong keyword argument self.assertRaises(TypeError, eval, 'Point(x=1)', locals()) # missing keyword argument self.assertEqual(repr(p), 'Point(x=11, y=22)') + self.assertNotIn('__dict__', dir(p)) # verify instance has no dict self.assertNotIn('__weakref__', dir(p)) self.assertEqual(p, Point._make([11, 22])) # test _make classmethod self.assertEqual(p._fields, ('x', 'y')) # test _fields attribute self.assertEqual(p._replace(x=1), (1, 22)) # test _replace method self.assertEqual(p._asdict(), dict(x=11, y=22)) # test _asdict method - self.assertEqual(vars(p), p._asdict()) # verify that vars() works try: p._replace(x=1, error=2) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -17,6 +17,9 @@ Core and Builtins ----------------- +- Issue #15535: Fixed regression in the pickling of named tuples by + removing the __dict__ property introduced in 2.7.4. + - Issue #17857: Prevent build failures with pre-3.5.0 versions of sqlite3, such as was shipped with Centos 5 and Mac OS X 10.4. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 3 11:41:58 2013 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 3 May 2013 11:41:58 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE1NTM1?= =?utf-8?q?=3A__Fix_pickling_of_named_tuples=2E?= Message-ID: <3b27fG6gBtz7Lkt@mail.python.org> http://hg.python.org/cpython/rev/65cd71abebc8 changeset: 83592:65cd71abebc8 branch: 3.3 parent: 83586:9cb90c1a1a46 user: Raymond Hettinger date: Fri May 03 02:24:15 2013 -0700 summary: Issue #15535: Fix pickling of named tuples. files: Lib/collections/__init__.py | 4 ++++ Lib/test/test_collections.py | 1 + Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 9 insertions(+), 0 deletions(-) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -281,6 +281,10 @@ 'Return self as a plain tuple. Used by copy and pickle.' return tuple(self) + def __getstate__(self): + 'Exclude the OrderedDict from pickling' + return None + {field_defs} ''' 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 @@ -273,6 +273,7 @@ q = loads(dumps(p, protocol)) self.assertEqual(p, q) self.assertEqual(p._fields, q._fields) + self.assertNotIn(b'OrderedDict', dumps(p, protocol)) def test_copy(self): p = TestNT(x=10, y=20, z=30) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -811,6 +811,7 @@ Jason Michalski Franck Michea Tom Middleton +Thomas Miedema Stan Mihai Stefan Mihaila Aristotelis Mikropoulos diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -47,6 +47,9 @@ - Issue #17802: Fix an UnboundLocalError in html.parser. Initial tests by Thomas Barlow. +- Issue #15535: Fix namedtuple pickles which were picking up the OrderedDict + instead of just the underlying tuple. + - Issue #17192: Restore the patch for Issue #11729 which was ommitted in 3.3.1 when updating the bundled version of libffi used by ctypes. Update many libffi files that were missed in 3.3.1's update to libffi-3.0.13. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 3 11:42:00 2013 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 3 May 2013 11:42:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3b27fJ1wVKz7LkP@mail.python.org> http://hg.python.org/cpython/rev/09c6faf1877c changeset: 83593:09c6faf1877c parent: 83590:8a364deb0225 parent: 83592:65cd71abebc8 user: Raymond Hettinger date: Fri May 03 02:41:02 2013 -0700 summary: merge files: Lib/collections/__init__.py | 4 ++++ Lib/test/test_collections.py | 1 + Misc/ACKS | 1 + 3 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -281,6 +281,10 @@ 'Return self as a plain tuple. Used by copy and pickle.' return tuple(self) + def __getstate__(self): + 'Exclude the OrderedDict from pickling' + return None + {field_defs} ''' 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 @@ -305,6 +305,7 @@ q = loads(dumps(p, protocol)) self.assertEqual(p, q) self.assertEqual(p._fields, q._fields) + self.assertNotIn(b'OrderedDict', dumps(p, protocol)) def test_copy(self): p = TestNT(x=10, y=20, z=30) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -829,6 +829,7 @@ Jason Michalski Franck Michea Tom Middleton +Thomas Miedema Stan Mihai Stefan Mihaila Aristotelis Mikropoulos -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 3 16:47:28 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 3 May 2013 16:47:28 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE1OTAy?= =?utf-8?q?=3A_Fix_imp=2Eload=5Fmodule=28=29_to_accept_None_as_a_file_when?= Message-ID: <3b2GQm1Mssz7Lk8@mail.python.org> http://hg.python.org/cpython/rev/c0a21617dbee changeset: 83594:c0a21617dbee branch: 3.3 parent: 83592:65cd71abebc8 user: Brett Cannon date: Fri May 03 10:37:08 2013 -0400 summary: Issue #15902: Fix imp.load_module() to accept None as a file when trying to load an extension module. While at it, also add a proper unittest.skipIf() guard to another test involving imp.load_dynamic(). files: Lib/imp.py | 8 ++++++-- Lib/test/test_imp.py | 15 +++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Lib/imp.py b/Lib/imp.py --- a/Lib/imp.py +++ b/Lib/imp.py @@ -168,7 +168,7 @@ warnings.simplefilter('ignore') if mode and (not mode.startswith(('r', 'U')) or '+' in mode): raise ValueError('invalid file open mode {!r}'.format(mode)) - elif file is None and type_ in {PY_SOURCE, PY_COMPILED, C_EXTENSION}: + elif file is None and type_ in {PY_SOURCE, PY_COMPILED}: msg = 'file object required for import (type code {})'.format(type_) raise ValueError(msg) elif type_ == PY_SOURCE: @@ -176,7 +176,11 @@ elif type_ == PY_COMPILED: return load_compiled(name, filename, file) elif type_ == C_EXTENSION and load_dynamic is not None: - return load_dynamic(name, filename, file) + if file is None: + with open(filename, 'rb') as opened_file: + return load_dynamic(name, filename, opened_file) + else: + return load_dynamic(name, filename, file) elif type_ == PKG_DIRECTORY: return load_package(name, filename) elif type_ == C_BUILTIN: diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -208,6 +208,8 @@ self.assertIsNot(orig_getenv, new_os.getenv) @support.cpython_only + @unittest.skipIf(not hasattr(imp, 'load_dynamic'), + 'imp.load_dynamic() required') def test_issue15828_load_extensions(self): # Issue 15828 picked up that the adapter between the old imp API # and importlib couldn't handle C extensions @@ -230,6 +232,19 @@ self.assertIn(path, err.exception.path) self.assertEqual(name, err.exception.name) + @support.cpython_only + @unittest.skipIf(not hasattr(imp, 'load_dynamic'), + 'imp.load_dynamic() required') + def test_load_module_extension_file_is_None(self): + # When loading an extension module and the file is None, open one + # on the behalf of imp.load_dynamic(). + # Issue #15902 + name = '_heapq' + found = imp.find_module(name) + assert found[2][2] == imp.C_EXTENSION + found[0].close() + imp.load_module(name, None, *found[1:]) + class ReloadTests(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -44,6 +44,9 @@ Library ------- +- Issue #15902: Fix imp.load_module() accepting None as a file when loading an + extension module. + - Issue #17802: Fix an UnboundLocalError in html.parser. Initial tests by Thomas Barlow. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 3 16:47:29 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 3 May 2013 16:47:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzE1OTAyOiBtZXJnZSB3LyAzLjM=?= Message-ID: <3b2GQn43pjz7Ll7@mail.python.org> http://hg.python.org/cpython/rev/322c556260d5 changeset: 83595:322c556260d5 parent: 83593:09c6faf1877c parent: 83594:c0a21617dbee user: Brett Cannon date: Fri May 03 10:47:17 2013 -0400 summary: #15902: merge w/ 3.3 files: Lib/imp.py | 8 ++++++-- Lib/test/test_imp.py | 15 +++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Lib/imp.py b/Lib/imp.py --- a/Lib/imp.py +++ b/Lib/imp.py @@ -168,7 +168,7 @@ warnings.simplefilter('ignore') if mode and (not mode.startswith(('r', 'U')) or '+' in mode): raise ValueError('invalid file open mode {!r}'.format(mode)) - elif file is None and type_ in {PY_SOURCE, PY_COMPILED, C_EXTENSION}: + elif file is None and type_ in {PY_SOURCE, PY_COMPILED}: msg = 'file object required for import (type code {})'.format(type_) raise ValueError(msg) elif type_ == PY_SOURCE: @@ -176,7 +176,11 @@ elif type_ == PY_COMPILED: return load_compiled(name, filename, file) elif type_ == C_EXTENSION and load_dynamic is not None: - return load_dynamic(name, filename, file) + if file is None: + with open(filename, 'rb') as opened_file: + return load_dynamic(name, filename, opened_file) + else: + return load_dynamic(name, filename, file) elif type_ == PKG_DIRECTORY: return load_package(name, filename) elif type_ == C_BUILTIN: diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -208,6 +208,8 @@ self.assertIsNot(orig_getenv, new_os.getenv) @support.cpython_only + @unittest.skipIf(not hasattr(imp, 'load_dynamic'), + 'imp.load_dynamic() required') def test_issue15828_load_extensions(self): # Issue 15828 picked up that the adapter between the old imp API # and importlib couldn't handle C extensions @@ -244,6 +246,19 @@ self.assertIn(path, err.exception.path) self.assertEqual(name, err.exception.name) + @support.cpython_only + @unittest.skipIf(not hasattr(imp, 'load_dynamic'), + 'imp.load_dynamic() required') + def test_load_module_extension_file_is_None(self): + # When loading an extension module and the file is None, open one + # on the behalf of imp.load_dynamic(). + # Issue #15902 + name = '_heapq' + found = imp.find_module(name) + assert found[2][2] == imp.C_EXTENSION + found[0].close() + imp.load_module(name, None, *found[1:]) + class ReloadTests(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -60,6 +60,9 @@ Library ------- + - Issue #15902: Fix imp.load_module() accepting None as a file when loading an + extension module. + - Issue #13721: SSLSocket.getpeercert() and SSLSocket.do_handshake() now raise an OSError with ENOTCONN, instead of an AttributeError, when the SSLSocket is not connected. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 3 16:57:15 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 3 May 2013 16:57:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Guard_more_tests_in_test?= =?utf-8?q?=5Fimp_requiring_imp=2Eload=5Fdynamic=28=29_to_exist=2E?= Message-ID: <3b2Gf34yy4zPYS@mail.python.org> http://hg.python.org/cpython/rev/acb289da963b changeset: 83596:acb289da963b user: Brett Cannon date: Fri May 03 10:54:23 2013 -0400 summary: Guard more tests in test_imp requiring imp.load_dynamic() to exist. files: Lib/test/test_imp.py | 19 +++++++++++++------ 1 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -8,6 +8,15 @@ import unittest import warnings + +def requires_load_dynamic(meth): + """Decorator to skip a test if not running under CPython or lacking + imp.load_dynamic().""" + meth = support.cpython_only(meth) + return unittest.skipIf(not hasattr(imp, 'load_dynamic'), + 'imp.load_dynamic() required')(meth) + + class LockTests(unittest.TestCase): """Very basic test of import lock functions.""" @@ -207,9 +216,7 @@ self.assertIs(orig_path, new_os.path) self.assertIsNot(orig_getenv, new_os.getenv) - @support.cpython_only - @unittest.skipIf(not hasattr(imp, 'load_dynamic'), - 'imp.load_dynamic() required') + @requires_load_dynamic def test_issue15828_load_extensions(self): # Issue 15828 picked up that the adapter between the old imp API # and importlib couldn't handle C extensions @@ -221,6 +228,7 @@ mod = imp.load_module(example, *x) self.assertEqual(mod.__name__, example) + @requires_load_dynamic def test_issue16421_multiple_modules_in_one_dll(self): # Issue 16421: loading several modules from the same compiled file fails m = '_testimportmultiple' @@ -235,6 +243,7 @@ with self.assertRaises(ImportError): imp.load_dynamic('nonexistent', pathname) + @requires_load_dynamic def test_load_dynamic_ImportError_path(self): # Issue #1559549 added `name` and `path` attributes to ImportError # in order to provide better detail. Issue #10854 implemented those @@ -246,9 +255,7 @@ self.assertIn(path, err.exception.path) self.assertEqual(name, err.exception.name) - @support.cpython_only - @unittest.skipIf(not hasattr(imp, 'load_dynamic'), - 'imp.load_dynamic() required') + @requires_load_dynamic def test_load_module_extension_file_is_None(self): # When loading an extension module and the file is None, open one # on the behalf of imp.load_dynamic(). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 3 16:57:16 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 3 May 2013 16:57:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Move_test=5Fimp_over_to_un?= =?utf-8?q?ittest=2Emain=28=29?= Message-ID: <3b2Gf473kFzQ1s@mail.python.org> http://hg.python.org/cpython/rev/78c60e2eb3f3 changeset: 83597:78c60e2eb3f3 user: Brett Cannon date: Fri May 03 10:56:19 2013 -0400 summary: Move test_imp over to unittest.main() files: Lib/test/test_imp.py | 22 ++++++---------------- 1 files changed, 6 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -1,3 +1,7 @@ +try: + import _thread +except ImportError: + _thread = None import imp import importlib import os @@ -17,6 +21,7 @@ 'imp.load_dynamic() required')(meth) + at unittest.skipIf(_thread is None, '_thread module is required') class LockTests(unittest.TestCase): """Very basic test of import lock functions.""" @@ -446,20 +451,5 @@ os.rmdir(name) -def test_main(): - tests = [ - ImportTests, - PEP3147Tests, - ReloadTests, - NullImporterTests, - ] - try: - import _thread - except ImportError: - pass - else: - tests.append(LockTests) - support.run_unittest(*tests) - if __name__ == "__main__": - test_main() + unittest.main() \ No newline at end of file -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 3 16:57:18 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 3 May 2013 16:57:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_add_trailing_newline_to_fi?= =?utf-8?q?le?= Message-ID: <3b2Gf622DbzQ4P@mail.python.org> http://hg.python.org/cpython/rev/56ca8eb5207a changeset: 83598:56ca8eb5207a user: Brett Cannon date: Fri May 03 10:57:08 2013 -0400 summary: add trailing newline to file files: Lib/test/test_imp.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -452,4 +452,4 @@ if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 3 19:07:30 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 3 May 2013 19:07:30 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?benchmarks=3A_=2315834=3A_Make_2to3_s?= =?utf-8?q?o_it_can_actually_be_proper_translated=2E?= Message-ID: <3b2KXL4JzSzSh0@mail.python.org> http://hg.python.org/benchmarks/rev/66f168b468c3 changeset: 203:66f168b468c3 user: Brett Cannon date: Fri May 03 13:03:51 2013 -0400 summary: #15834: Make 2to3 so it can actually be proper translated. Error only showed itself when you didn't run a fast pass for the benchmark. files: lib/2to3/lib2to3/fixes/fix_operator.py | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/lib/2to3/lib2to3/fixes/fix_operator.py b/lib/2to3/lib2to3/fixes/fix_operator.py --- a/lib/2to3/lib2to3/fixes/fix_operator.py +++ b/lib/2to3/lib2to3/fixes/fix_operator.py @@ -85,7 +85,9 @@ return Call(Name(u"isinstance"), args, prefix=node.prefix) def _check_method(self, node, results): - method = getattr(self, "_" + results["method"][0].value.encode("ascii")) + # Issue #15834: don't encode to ASCII as that breaks in translation to + # Python 3. + method = getattr(self, "_" + str(results["method"][0].value)) if callable(method): if "module" in results: return method -- Repository URL: http://hg.python.org/benchmarks From python-checkins at python.org Fri May 3 19:07:31 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 3 May 2013 19:07:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?benchmarks=3A_Switch_to_using_Python_?= =?utf-8?q?3_for_translation_since_if_you_are_building_the?= Message-ID: <3b2KXM75nDzT0X@mail.python.org> http://hg.python.org/benchmarks/rev/dccd52b95a71 changeset: 204:dccd52b95a71 user: Brett Cannon date: Fri May 03 13:04:25 2013 -0400 summary: Switch to using Python 3 for translation since if you are building the benchmarks for Python 3 you will actually have it (unlike Python 2.6). files: make_perf3.sh | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/make_perf3.sh b/make_perf3.sh --- a/make_perf3.sh +++ b/make_perf3.sh @@ -8,7 +8,7 @@ # mkdir py3benchmarks; # cd py3benchmarks # ../py2benchmarks/make_perf3.sh ../py2benchmarks -# python3.1 perf.py -b py3k old_py3k new_py3k +# python3 perf.py -b py3k old_py3k new_py3k set -e @@ -23,10 +23,10 @@ exit 1 fi -py2_6=${PYTHON:-python2.6} +py3=${PYTHON:-python3} # Update the files in place. -CONVERT="${py2_6} ${srcdir}/lib/2to3/2to3 --write --nobackups --no-diffs" +CONVERT="${py3} -m lib2to3 --write --nobackups --no-diffs" rm -rf perf.py* lib performance -- Repository URL: http://hg.python.org/benchmarks From solipsis at pitrou.net Sat May 4 06:02:44 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 04 May 2013 06:02:44 +0200 Subject: [Python-checkins] Daily reference leaks (56ca8eb5207a): sum=0 Message-ID: results for 56ca8eb5207a on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogt8dt_5', '-x'] From python-checkins at python.org Sat May 4 14:16:53 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 4 May 2013 14:16:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE2MzE2?= =?utf-8?q?=3A_mimetypes_now_recognizes_the_=2Exz_and_=2Etxz_=28=2Etar=2Ex?= =?utf-8?q?z=29_extensions=2E?= Message-ID: <3b2q2Y6sjnzNn9@mail.python.org> http://hg.python.org/cpython/rev/26068bfec70e changeset: 83599:26068bfec70e branch: 2.7 parent: 83591:18303391b981 user: Serhiy Storchaka date: Sat May 04 15:11:46 2013 +0300 summary: Issue #16316: mimetypes now recognizes the .xz and .txz (.tar.xz) extensions. files: Lib/mimetypes.py | 2 ++ Lib/test/test_mimetypes.py | 2 ++ Misc/NEWS | 2 ++ 3 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py --- a/Lib/mimetypes.py +++ b/Lib/mimetypes.py @@ -386,12 +386,14 @@ '.taz': '.tar.gz', '.tz': '.tar.gz', '.tbz2': '.tar.bz2', + '.txz': '.tar.xz', } encodings_map = { '.gz': 'gzip', '.Z': 'compress', '.bz2': 'bzip2', + '.xz': 'xz', } # Before adding new types, make sure they are either registered with IANA, diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py --- a/Lib/test/test_mimetypes.py +++ b/Lib/test/test_mimetypes.py @@ -21,6 +21,8 @@ eq(self.db.guess_type("foo.tgz"), ("application/x-tar", "gzip")) eq(self.db.guess_type("foo.tar.gz"), ("application/x-tar", "gzip")) eq(self.db.guess_type("foo.tar.Z"), ("application/x-tar", "compress")) + eq(self.db.guess_type("foo.tar.bz2"), ("application/x-tar", "bzip2")) + eq(self.db.guess_type("foo.tar.xz"), ("application/x-tar", "xz")) def test_data_urls(self): eq = self.assertEqual diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,8 @@ Library ------- +- Issue #16316: mimetypes now recognizes the .xz and .txz (.tar.xz) extensions. + - Issue #17192: Restore the patch for Issue #10309 which was ommitted in 2.7.4 when updating the bundled version of libffi used by ctypes. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 14:16:55 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 4 May 2013 14:16:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE2MzE2?= =?utf-8?q?=3A_mimetypes_now_recognizes_the_=2Exz_and_=2Etxz_=28=2Etar=2Ex?= =?utf-8?q?z=29_extensions=2E?= Message-ID: <3b2q2b282Pz7LkX@mail.python.org> http://hg.python.org/cpython/rev/d04259af01ff changeset: 83600:d04259af01ff branch: 3.3 parent: 83594:c0a21617dbee user: Serhiy Storchaka date: Sat May 04 15:12:55 2013 +0300 summary: Issue #16316: mimetypes now recognizes the .xz and .txz (.tar.xz) extensions. files: Lib/mimetypes.py | 2 ++ Lib/test/test_mimetypes.py | 2 ++ Misc/NEWS | 2 ++ 3 files changed, 6 insertions(+), 0 deletions(-) diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py --- a/Lib/mimetypes.py +++ b/Lib/mimetypes.py @@ -378,12 +378,14 @@ '.taz': '.tar.gz', '.tz': '.tar.gz', '.tbz2': '.tar.bz2', + '.txz': '.tar.xz', } encodings_map = { '.gz': 'gzip', '.Z': 'compress', '.bz2': 'bzip2', + '.xz': 'xz', } # Before adding new types, make sure they are either registered with IANA, diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py --- a/Lib/test/test_mimetypes.py +++ b/Lib/test/test_mimetypes.py @@ -22,6 +22,8 @@ eq(self.db.guess_type("foo.tgz"), ("application/x-tar", "gzip")) eq(self.db.guess_type("foo.tar.gz"), ("application/x-tar", "gzip")) eq(self.db.guess_type("foo.tar.Z"), ("application/x-tar", "compress")) + eq(self.db.guess_type("foo.tar.bz2"), ("application/x-tar", "bzip2")) + eq(self.db.guess_type("foo.tar.xz"), ("application/x-tar", "xz")) def test_data_urls(self): eq = self.assertEqual diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -44,6 +44,8 @@ Library ------- +- Issue #16316: mimetypes now recognizes the .xz and .txz (.tar.xz) extensions. + - Issue #15902: Fix imp.load_module() accepting None as a file when loading an extension module. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 14:16:56 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Sat, 4 May 2013 14:16:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Null_merge_=28already_committed_in_changeset_a3ba5fe9bfd?= =?utf-8?q?3=29?= Message-ID: <3b2q2c4QVgz7Ll0@mail.python.org> http://hg.python.org/cpython/rev/ed0c30b4c082 changeset: 83601:ed0c30b4c082 parent: 83598:56ca8eb5207a parent: 83600:d04259af01ff user: Serhiy Storchaka date: Sat May 04 15:16:16 2013 +0300 summary: Null merge (already committed in changeset a3ba5fe9bfd3) files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 15:29:26 2013 From: python-checkins at python.org (eli.bendersky) Date: Sat, 4 May 2013 15:29:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Update_PEP_435_with_latest_de?= =?utf-8?q?cisions_and_add_some_clarifications=3A?= Message-ID: <3b2rfG3Nm1z7LjQ@mail.python.org> http://hg.python.org/peps/rev/0357c81c8e6c changeset: 4872:0357c81c8e6c user: Eli Bendersky date: Sat May 04 06:28:32 2013 -0700 summary: Update PEP 435 with latest decisions and add some clarifications: 1. getitem syntax come-back 2. Define iteration in presence of aliases 3. __aliases__ 4. s/Convenience/Functional/ API 5. Don't say enums created with the functional API can't be pickled, but provide the usual precaution from the doc of pickle files: pep-0435.txt | 156 ++++++++++++++++++++++---------------- 1 files changed, 90 insertions(+), 66 deletions(-) diff --git a/pep-0435.txt b/pep-0435.txt --- a/pep-0435.txt +++ b/pep-0435.txt @@ -96,7 +96,7 @@ ---------------- Enumerations are created using the class syntax, which makes them easy to read -and write. An alternative creation method is described in `Convenience API`_. +and write. An alternative creation method is described in `Functional API`_. To define an enumeration, subclass ``Enum`` as follows:: >>> from enum import Enum @@ -118,7 +118,7 @@ ...while their ``repr`` has more information:: >>> print(repr(Color.red)) - Color.red [value=1] + The *type* of an enumeration member is the enumeration it belongs to:: @@ -126,7 +126,7 @@ >>> isinstance(Color.green, Color) True - >>> + >>> Enums also have a property that contains just their item name:: @@ -140,10 +140,10 @@ ... chocolate = 4 ... cookies = 9 ... mint = 3 - ... + ... >>> for shake in Shake: ... print(shake) - ... + ... Shake.vanilla Shake.chocolate Shake.cookies @@ -155,7 +155,8 @@ >>> apples[Color.red] = 'red delicious' >>> apples[Color.green] = 'granny smith' >>> apples - {Color.red [value=1]: 'red delicious', Color.green [value=2]: 'granny smith'} + {: 'red delicious', : 'granny smith'} + Programmatic access to enumeration members ------------------------------------------ @@ -165,17 +166,17 @@ at program-writing time). ``Enum`` allows such access:: >>> Color(1) - Color.red [value=1] + >>> Color(3) - Color.blue [value=3] + -If you want to access enum members by *name*, ``Enum`` works as expected with -``getattr``:: +If you want to access enum members by *name*, use item access:: - >>> getattr(Color, 'red') - Color.red [value=1] - >>> getattr(Color, 'green') - Color.green [value=2] + >>> Color['red'] + + >>> Color['green'] + + Duplicating enum members and values ----------------------------------- @@ -185,26 +186,39 @@ >>> class Shape(Enum): ... square = 2 ... square = 3 - ... + ... Traceback (most recent call last): ... TypeError: Attempted to reuse key: square -However, two enum members are allowed to have the same value. By-value lookup -will then access the *earliest defined* member:: +However, two enum members are allowed to have the same value. Given two members +A and B with the same value (and A defined first), B is an alias to A. By-value +lookup of the value of A and B will return A. >>> class Shape(Enum): ... square = 2 ... diamond = 1 ... circle = 3 ... alias_for_square = 2 - ... + ... >>> Shape.square - Shape.square [value=2] + >>> Shape.alias_for_square - Shape.square [value=2] + >>> Shape(2) - Shape.square [value=2] + + +Iterating over the members of an enum does not provide the aliases:: + + >>> list(Shape) + [, , ] + +If access to aliases is required for some reason, use the special attribute +``__aliases__``:: + + >>> Shape.__aliases__ + ['alias_for_square'] + Comparisons ----------- @@ -240,38 +254,15 @@ >>> Color.blue == 2 False -Allowed members and attributs of enumerations ---------------------------------------------- + +Allowed members and attributes of enumerations +---------------------------------------------- The examples above use integers for enumeration values. Using integers is -short and handy (and provided by default by the `Convenience API`_), but not +short and handy (and provided by default by the `Functional API`_), but not strictly enforced. In the vast majority of use-cases, one doesn't care what the actual value of an enumeration is. But if the value *is* important, -enumerations can have arbitrary values. The following example uses strings:: - - >>> class SpecialId(Enum): - ... selector = '$IM($N)' - ... adaptor = '~$IM' - ... - >>> SpecialId.selector - SpecialId.selector [value='$IM($N)'] - >>> SpecialId.selector.value - '$IM($N)' - >>> a = SpecialId.adaptor - >>> a == '~$IM' - False - >>> a == SpecialId.adaptor - True - >>> print(a) - SpecialId.adaptor - -Here ``Enum`` is used to provide readable (and syntactically valid!) names for -some special values, as well as group them together. - -While ``Enum`` supports this flexibility, one should only use it in -very special cases. Code will be most readable when actual values of -enumerations aren't important and enumerations are just used for their -naming and comparison properties. +enumerations can have arbitrary values. Enumerations are Python classes, and can have methods and special methods as usual. If we have this enumeration:: @@ -295,7 +286,7 @@ Then:: >>> Mood.favorite_mood() - Mood.happy [value=3] + >>> Mood.happy.describe() ('happy', 3) >>> str(Mood.funky) @@ -305,6 +296,7 @@ enumeration will become members of this enumeration, with the exception of *__dunder__* names and descriptors; methods are descriptors too. + Restricted subclassing of enumerations -------------------------------------- @@ -313,19 +305,19 @@ >>> class MoreColor(Color): ... pink = 17 - ... - TypeError: Cannot subclass enumerations + ... + TypeError: Cannot extend enumerations But this is allowed:: >>> class Foo(Enum): ... def some_behavior(self): ... pass - ... + ... >>> class Bar(Foo): ... happy = 1 ... sad = 2 - ... + ... The rationale for this decision was given by Guido in [6]_. Allowing to subclass enums that define members would lead to a violation of some @@ -334,6 +326,7 @@ enumerations, and subclassing empty enumerations is also used to implement ``IntEnum``. + IntEnum ------- @@ -388,31 +381,41 @@ with code that still expects integers. -Pickling --------- +Other derived enumerations +-------------------------- -Enumerations created with the class syntax can also be pickled and unpickled:: +``IntEnum`` will be part of the ``enum`` module. However, it would be very +simple to implement independently:: - >>> from enum.tests.fruit import Fruit - >>> from pickle import dumps, loads - >>> Fruit.tomato is loads(dumps(Fruit.tomato)) - True + class IntEnum(int, Enum): + pass +This demonstrates how similar derived enumerations can be defined, for example +a ``StrEnum`` that mixes in ``str`` instead of ``int``. -Convenience API ---------------- +Some rules: -The ``Enum`` class is callable, providing the following convenience API:: +1. When subclassing Enum, mixing types must appear before Enum itself in the + sequence of bases. +2. While Enum can have members of any type, once you mix in an additional + type, all the members must have values of that type, e.g. ``int`` above. + This restriction does not apply to behavior-only mixins. + + +Functional API +-------------- + +The ``Enum`` class is callable, providing the following functional API:: >>> Animal = Enum('Animal', 'ant bee cat dog') >>> Animal >>> Animal.ant - Animal.ant [value=1] + >>> Animal.ant.value 1 >>> list(Animal) - [Animal.ant [value=1], Animal.bee [value=2], Animal.cat [value=3], Animal.dog [value=4]] + [, , , ] The semantics of this API resemble ``namedtuple``. The first argument of the call to ``Enum`` is the name of the enumeration. The second argument is @@ -429,12 +432,29 @@ ... cat = 3 ... dog = 4 + +Pickling +-------- + +Enumerations be pickled and unpickled:: + + >>> from enum.tests.fruit import Fruit + >>> from pickle import dumps, loads + >>> Fruit.tomato is loads(dumps(Fruit.tomato)) + True + +The usual restrictions for pickling apply: picklable enums must be defined in +the top level of a module, to be importable from that module when unpickling +occurs. + + Proposed variations =================== Some variations were proposed during the discussions in the mailing list. Here's some of the more popular ones. + flufl.enum ---------- @@ -446,6 +466,7 @@ more members (due to the member/enum separation, the type invariants are not violated in ``flufl.enum`` with such a scheme). + Not having to specify values for enums -------------------------------------- @@ -495,6 +516,7 @@ Cons: actually longer to type in many simple cases. The argument of explicit vs. implicit applies here as well. + Use-cases in the standard library ================================= @@ -528,6 +550,7 @@ about a lot of networking code (especially implementation of protocols) and can be seen in test protocols written with the Tulip library as well. + Acknowledgments =============== @@ -535,6 +558,7 @@ by Barry Warsaw into the stdlib, and is inspired in large parts by it. Ben Finney is the author of the earlier enumeration PEP 354. + References ========== -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat May 4 16:48:06 2013 From: python-checkins at python.org (ezio.melotti) Date: Sat, 4 May 2013 16:48:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzc4NTU6IEFkZCB0?= =?utf-8?q?ests_for_ctypes/winreg_for_issues_found_in_IronPython=2E__Initi?= =?utf-8?q?al?= Message-ID: <3b2tP26Y1mzR1R@mail.python.org> http://hg.python.org/cpython/rev/5f82b68c1f28 changeset: 83602:5f82b68c1f28 branch: 3.3 parent: 83600:d04259af01ff user: Ezio Melotti date: Sat May 04 17:46:23 2013 +0300 summary: #7855: Add tests for ctypes/winreg for issues found in IronPython. Initial patch by Dino Viehland. files: Lib/ctypes/test/__init__.py | 2 +- Lib/ctypes/test/test_wintypes.py | 43 ++++++++++++++++++++ Lib/test/test_winreg.py | 3 + Misc/ACKS | 1 + Misc/NEWS | 3 + 5 files changed, 51 insertions(+), 1 deletions(-) diff --git a/Lib/ctypes/test/__init__.py b/Lib/ctypes/test/__init__.py --- a/Lib/ctypes/test/__init__.py +++ b/Lib/ctypes/test/__init__.py @@ -62,7 +62,7 @@ continue try: mod = __import__(modname, globals(), locals(), ['*']) - except ResourceDenied as detail: + except (ResourceDenied, unittest.SkipTest) as detail: skipped.append(modname) if verbosity > 1: print("Skipped %s: %s" % (modname, detail), file=sys.stderr) diff --git a/Lib/ctypes/test/test_wintypes.py b/Lib/ctypes/test/test_wintypes.py new file mode 100644 --- /dev/null +++ b/Lib/ctypes/test/test_wintypes.py @@ -0,0 +1,43 @@ +import sys +import unittest + +if not sys.platform.startswith('win'): + raise unittest.SkipTest('Windows-only test') + +from ctypes import * +from ctypes import wintypes + +class WinTypesTest(unittest.TestCase): + def test_variant_bool(self): + # reads 16-bits from memory, anything non-zero is True + for true_value in (1, 32767, 32768, 65535, 65537): + true = POINTER(c_int16)(c_int16(true_value)) + value = cast(true, POINTER(wintypes.VARIANT_BOOL)) + self.assertEqual(repr(value.contents), 'VARIANT_BOOL(True)') + + vb = wintypes.VARIANT_BOOL() + self.assertIs(vb.value, False) + vb.value = True + self.assertIs(vb.value, True) + vb.value = true_value + self.assertIs(vb.value, True) + + for false_value in (0, 65536, 262144, 2**33): + false = POINTER(c_int16)(c_int16(false_value)) + value = cast(false, POINTER(wintypes.VARIANT_BOOL)) + self.assertEqual(repr(value.contents), 'VARIANT_BOOL(False)') + + # allow any bool conversion on assignment to value + for set_value in (65536, 262144, 2**33): + vb = wintypes.VARIANT_BOOL() + vb.value = set_value + self.assertIs(vb.value, True) + + vb = wintypes.VARIANT_BOOL() + vb.value = [2, 3] + self.assertIs(vb.value, True) + vb.value = [] + self.assertIs(vb.value, False) + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -457,6 +457,9 @@ DeleteKeyEx(HKEY_CURRENT_USER, test_reflect_key_name, KEY_WOW64_32KEY, 0) + def test_exception_numbers(self): + with self.assertRaises(FileNotFoundError) as ctx: + QueryValue(HKEY_CLASSES_ROOT, 'some_value_that_does_not_exist') def test_main(): support.run_unittest(LocalWinregTests, RemoteWinregTests, diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1259,6 +1259,7 @@ Al Vezza Jacques A. Vidrine John Viega +Dino Viehland Kannan Vijayan Kurt Vile Norman Vine diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -158,6 +158,9 @@ Tests ----- +- Issue #7855: Add tests for ctypes/winreg for issues found in IronPython. + Initial patch by Dino Viehland. + - Issue #17712: Fix test_gdb failures on Ubuntu 13.04. - Issue #17835: Fix test_io when the default OS pipe buffer size is larger -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 16:48:08 2013 From: python-checkins at python.org (ezio.melotti) Date: Sat, 4 May 2013 16:48:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzc4NTU6IG1lcmdlIHdpdGggMy4zLg==?= Message-ID: <3b2tP41trpz7LlG@mail.python.org> http://hg.python.org/cpython/rev/df655ebf74d7 changeset: 83603:df655ebf74d7 parent: 83601:ed0c30b4c082 parent: 83602:5f82b68c1f28 user: Ezio Melotti date: Sat May 04 17:47:54 2013 +0300 summary: #7855: merge with 3.3. files: Lib/ctypes/test/__init__.py | 2 +- Lib/ctypes/test/test_wintypes.py | 43 ++++++++++++++++++++ Lib/test/test_winreg.py | 3 + Misc/ACKS | 1 + Misc/NEWS | 3 + 5 files changed, 51 insertions(+), 1 deletions(-) diff --git a/Lib/ctypes/test/__init__.py b/Lib/ctypes/test/__init__.py --- a/Lib/ctypes/test/__init__.py +++ b/Lib/ctypes/test/__init__.py @@ -62,7 +62,7 @@ continue try: mod = __import__(modname, globals(), locals(), ['*']) - except ResourceDenied as detail: + except (ResourceDenied, unittest.SkipTest) as detail: skipped.append(modname) if verbosity > 1: print("Skipped %s: %s" % (modname, detail), file=sys.stderr) diff --git a/Lib/ctypes/test/test_wintypes.py b/Lib/ctypes/test/test_wintypes.py new file mode 100644 --- /dev/null +++ b/Lib/ctypes/test/test_wintypes.py @@ -0,0 +1,43 @@ +import sys +import unittest + +if not sys.platform.startswith('win'): + raise unittest.SkipTest('Windows-only test') + +from ctypes import * +from ctypes import wintypes + +class WinTypesTest(unittest.TestCase): + def test_variant_bool(self): + # reads 16-bits from memory, anything non-zero is True + for true_value in (1, 32767, 32768, 65535, 65537): + true = POINTER(c_int16)(c_int16(true_value)) + value = cast(true, POINTER(wintypes.VARIANT_BOOL)) + self.assertEqual(repr(value.contents), 'VARIANT_BOOL(True)') + + vb = wintypes.VARIANT_BOOL() + self.assertIs(vb.value, False) + vb.value = True + self.assertIs(vb.value, True) + vb.value = true_value + self.assertIs(vb.value, True) + + for false_value in (0, 65536, 262144, 2**33): + false = POINTER(c_int16)(c_int16(false_value)) + value = cast(false, POINTER(wintypes.VARIANT_BOOL)) + self.assertEqual(repr(value.contents), 'VARIANT_BOOL(False)') + + # allow any bool conversion on assignment to value + for set_value in (65536, 262144, 2**33): + vb = wintypes.VARIANT_BOOL() + vb.value = set_value + self.assertIs(vb.value, True) + + vb = wintypes.VARIANT_BOOL() + vb.value = [2, 3] + self.assertIs(vb.value, True) + vb.value = [] + self.assertIs(vb.value, False) + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -457,6 +457,9 @@ DeleteKeyEx(HKEY_CURRENT_USER, test_reflect_key_name, KEY_WOW64_32KEY, 0) + def test_exception_numbers(self): + with self.assertRaises(FileNotFoundError) as ctx: + QueryValue(HKEY_CLASSES_ROOT, 'some_value_that_does_not_exist') def test_main(): support.run_unittest(LocalWinregTests, RemoteWinregTests, diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1287,6 +1287,7 @@ Al Vezza Jacques A. Vidrine John Viega +Dino Viehland Kannan Vijayan Kurt Vile Norman Vine diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -188,6 +188,9 @@ Tests ----- +- Issue #7855: Add tests for ctypes/winreg for issues found in IronPython. + Initial patch by Dino Viehland. + - Issue #11078: test___all__ now checks for duplicates in __all__. Initial patch by R. David Murray. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 16:59:15 2013 From: python-checkins at python.org (ezio.melotti) Date: Sat, 4 May 2013 16:59:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzc4NTU6IEFkZCB0?= =?utf-8?q?ests_for_ctypes/winreg_for_issues_found_in_IronPython=2E__Initi?= =?utf-8?q?al?= Message-ID: <3b2tdv42RmzQxV@mail.python.org> http://hg.python.org/cpython/rev/e71406d8ed5d changeset: 83604:e71406d8ed5d branch: 2.7 parent: 83599:26068bfec70e user: Ezio Melotti date: Sat May 04 17:59:03 2013 +0300 summary: #7855: Add tests for ctypes/winreg for issues found in IronPython. Initial patch by Dino Viehland. files: Lib/ctypes/test/__init__.py | 2 +- Lib/ctypes/test/test_wintypes.py | 43 ++++++++++++++++++++ Lib/test/test_winreg.py | 5 ++ Misc/ACKS | 1 + Misc/NEWS | 3 + 5 files changed, 53 insertions(+), 1 deletions(-) diff --git a/Lib/ctypes/test/__init__.py b/Lib/ctypes/test/__init__.py --- a/Lib/ctypes/test/__init__.py +++ b/Lib/ctypes/test/__init__.py @@ -62,7 +62,7 @@ continue try: mod = __import__(modname, globals(), locals(), ['*']) - except ResourceDenied, detail: + except (ResourceDenied, unittest.SkipTest) as detail: skipped.append(modname) if verbosity > 1: print >> sys.stderr, "Skipped %s: %s" % (modname, detail) diff --git a/Lib/ctypes/test/test_wintypes.py b/Lib/ctypes/test/test_wintypes.py new file mode 100644 --- /dev/null +++ b/Lib/ctypes/test/test_wintypes.py @@ -0,0 +1,43 @@ +import sys +import unittest + +if not sys.platform.startswith('win'): + raise unittest.SkipTest('Windows-only test') + +from ctypes import * +from ctypes import wintypes + +class WinTypesTest(unittest.TestCase): + def test_variant_bool(self): + # reads 16-bits from memory, anything non-zero is True + for true_value in (1, 32767, 32768, 65535, 65537): + true = POINTER(c_int16)(c_int16(true_value)) + value = cast(true, POINTER(wintypes.VARIANT_BOOL)) + self.assertEqual(repr(value.contents), 'VARIANT_BOOL(True)') + + vb = wintypes.VARIANT_BOOL() + self.assertIs(vb.value, False) + vb.value = True + self.assertIs(vb.value, True) + vb.value = true_value + self.assertIs(vb.value, True) + + for false_value in (0, 65536, 262144, 2**33): + false = POINTER(c_int16)(c_int16(false_value)) + value = cast(false, POINTER(wintypes.VARIANT_BOOL)) + self.assertEqual(repr(value.contents), 'VARIANT_BOOL(False)') + + # allow any bool conversion on assignment to value + for set_value in (65536, 262144, 2**33): + vb = wintypes.VARIANT_BOOL() + vb.value = set_value + self.assertIs(vb.value, True) + + vb = wintypes.VARIANT_BOOL() + vb.value = [2, 3] + self.assertIs(vb.value, True) + vb.value = [] + self.assertIs(vb.value, False) + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -442,6 +442,11 @@ DeleteKeyEx(HKEY_CURRENT_USER, test_reflect_key_name, KEY_WOW64_32KEY, 0) + def test_exception_numbers(self): + with self.assertRaises(WindowsError) as ctx: + QueryValue(HKEY_CLASSES_ROOT, 'some_value_that_does_not_exist') + + self.assertEqual(ctx.exception.errno, 2) def test_main(): test_support.run_unittest(LocalWinregTests, RemoteWinregTests, diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1050,6 +1050,7 @@ Al Vezza Jacques A. Vidrine John Viega +Dino Viehland Kannan Vijayan Kurt Vile Norman Vine diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -81,6 +81,9 @@ Tests ----- +- Issue #7855: Add tests for ctypes/winreg for issues found in IronPython. + Initial patch by Dino Viehland. + - Issue #17712: Fix test_gdb failures on Ubuntu 13.04. - Issue #17065: Use process-unique key for winreg tests to avoid failures if -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 17:07:31 2013 From: python-checkins at python.org (ezio.melotti) Date: Sat, 4 May 2013 17:07:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE2NTE4OiB1c2Ug?= =?utf-8?q?=22bytes-like_object=22_throughout_the_docs=2E?= Message-ID: <3b2tqR6Ddgz7Lk8@mail.python.org> http://hg.python.org/cpython/rev/003e4eb92683 changeset: 83605:003e4eb92683 branch: 3.3 parent: 83602:5f82b68c1f28 user: Ezio Melotti date: Sat May 04 18:06:34 2013 +0300 summary: #16518: use "bytes-like object" throughout the docs. files: Doc/c-api/arg.rst | 13 ++++++------- Doc/c-api/bytearray.rst | 2 +- Doc/library/array.rst | 6 +++--- Doc/library/binascii.rst | 5 +++-- Doc/library/hashlib.rst | 6 +++--- Doc/library/hmac.rst | 3 +-- Doc/library/multiprocessing.rst | 5 ++--- Doc/library/stdtypes.rst | 12 +++++------- 8 files changed, 24 insertions(+), 28 deletions(-) diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -70,8 +70,7 @@ as *converter*. ``s*`` (:class:`str`, :class:`bytes`, :class:`bytearray` or buffer compatible object) [Py_buffer] - This format accepts Unicode objects as well as objects supporting the - buffer protocol. + This format accepts Unicode objects as well as :term:`bytes-like object`\ s. It fills a :c:type:`Py_buffer` structure provided by the caller. In this case the resulting C string may contain embedded NUL bytes. Unicode objects are converted to C strings using ``'utf-8'`` encoding. @@ -101,14 +100,14 @@ contain embedded NUL bytes; if it does, a :exc:`TypeError` exception is raised. -``y*`` (:class:`bytes`, :class:`bytearray` or buffer compatible object) [Py_buffer] - This variant on ``s*`` doesn't accept Unicode objects, only objects - supporting the buffer protocol. **This is the recommended way to accept +``y*`` (:class:`bytes`, :class:`bytearray` or :term:`bytes-like object`) [Py_buffer] + This variant on ``s*`` doesn't accept Unicode objects, only + :term:`bytes-like object`\ s. **This is the recommended way to accept binary data.** ``y#`` (:class:`bytes`) [const char \*, int] - This variant on ``s#`` doesn't accept Unicode objects, only bytes-like - objects. + This variant on ``s#`` doesn't accept Unicode objects, only :term:`bytes-like + object`\ s. ``S`` (:class:`bytes`) [PyBytesObject \*] Requires that the Python object is a :class:`bytes` object, without diff --git a/Doc/c-api/bytearray.rst b/Doc/c-api/bytearray.rst --- a/Doc/c-api/bytearray.rst +++ b/Doc/c-api/bytearray.rst @@ -40,7 +40,7 @@ .. c:function:: PyObject* PyByteArray_FromObject(PyObject *o) Return a new bytearray object from any object, *o*, that implements the - buffer protocol. + :ref:`buffer protocol `. .. XXX expand about the buffer protocol, at least somewhere diff --git a/Doc/library/array.rst b/Doc/library/array.rst --- a/Doc/library/array.rst +++ b/Doc/library/array.rst @@ -73,8 +73,8 @@ .. class:: array(typecode[, initializer]) A new array whose items are restricted by *typecode*, and initialized - from the optional *initializer* value, which must be a list, object - supporting the buffer interface, or iterable over elements of the + from the optional *initializer* value, which must be a list, a + :term:`bytes-like object`, or iterable over elements of the appropriate type. If given a list or string, the initializer is passed to the new array's @@ -91,7 +91,7 @@ concatenation, and multiplication. When using slice assignment, the assigned value must be an array object with the same type code; in all other cases, :exc:`TypeError` is raised. Array objects also implement the buffer interface, -and may be used wherever buffer objects are supported. +and may be used wherever :term:`bytes-like object`\ s are supported. The following data items and methods are also supported: diff --git a/Doc/library/binascii.rst b/Doc/library/binascii.rst --- a/Doc/library/binascii.rst +++ b/Doc/library/binascii.rst @@ -21,8 +21,9 @@ .. note:: ``a2b_*`` functions accept Unicode strings containing only ASCII characters. - Other functions only accept bytes and bytes-compatible objects (such as - bytearray objects and other objects implementing the buffer API). + Other functions only accept :term:`bytes-like object`\ s (such as + :class:`bytes`, :class:`bytearray` and other objects that support the buffer + protocol). .. versionchanged:: 3.3 ASCII-only unicode strings are now accepted by the ``a2b_*`` functions. diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst --- a/Doc/library/hashlib.rst +++ b/Doc/library/hashlib.rst @@ -32,9 +32,9 @@ There is one constructor method named for each type of :dfn:`hash`. All return a hash object with the same simple interface. For example: use :func:`sha1` to -create a SHA1 hash object. You can now feed this object with objects conforming -to the buffer interface (normally :class:`bytes` objects) using the -:meth:`update` method. At any point you can ask it for the :dfn:`digest` of the +create a SHA1 hash object. You can now feed this object with :term:`bytes-like +object`\ s (normally :class:`bytes`) using the :meth:`update` method. +At any point you can ask it for the :dfn:`digest` of the concatenation of the data fed to it so far using the :meth:`digest` or :meth:`hexdigest` methods. diff --git a/Doc/library/hmac.rst b/Doc/library/hmac.rst --- a/Doc/library/hmac.rst +++ b/Doc/library/hmac.rst @@ -74,8 +74,7 @@ timing analysis by avoiding content-based short circuiting behaviour, making it appropriate for cryptography. *a* and *b* must both be of the same type: either :class:`str` (ASCII only, as e.g. returned by - :meth:`HMAC.hexdigest`), or any type that supports the buffer protocol - (e.g. :class:`bytes`). + :meth:`HMAC.hexdigest`), or a :term:`bytes-like object`. .. note:: diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -800,8 +800,7 @@ .. method:: send_bytes(buffer[, offset[, size]]) - Send byte data from an object supporting the buffer interface as a - complete message. + Send byte data from a :term:`bytes-like object` as a complete message. If *offset* is given then data is read from that position in *buffer*. If *size* is given then that many bytes will be read from buffer. Very large @@ -832,7 +831,7 @@ :exc:`EOFError` if there is nothing left to receive and the other end was closed. - *buffer* must be an object satisfying the writable buffer interface. If + *buffer* must be a writable :term:`bytes-like object`. If *offset* is given then the message will be written into the buffer from that position. Offset must be a non-negative integer less than the length of *buffer* (in bytes). diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -519,9 +519,8 @@ >>> int.from_bytes([255, 0, 0], byteorder='big') 16711680 - The argument *bytes* must either support the buffer protocol or be an - iterable producing bytes. :class:`bytes` and :class:`bytearray` are - examples of built-in objects that support the buffer protocol. + The argument *bytes* must either be a :term:`bytes-like object` or an + iterable producing bytes. The *byteorder* argument determines the byte order used to represent the integer. If *byteorder* is ``"big"``, the most significant byte is at the @@ -1417,10 +1416,9 @@ single: bytes; str (built-in class) If at least one of *encoding* or *errors* is given, *object* should be a - :class:`bytes` or :class:`bytearray` object, or more generally any object - that supports the :ref:`buffer protocol `. In this case, if - *object* is a :class:`bytes` (or :class:`bytearray`) object, then - ``str(bytes, encoding, errors)`` is equivalent to + :term:`bytes-like object` (e.g. :class:`bytes` or :class:`bytearray`). In + this case, if *object* is a :class:`bytes` (or :class:`bytearray`) object, + then ``str(bytes, encoding, errors)`` is equivalent to :meth:`bytes.decode(encoding, errors) `. Otherwise, the bytes object underlying the buffer object is obtained before calling :meth:`bytes.decode`. See :ref:`binaryseq` and -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 17:07:33 2013 From: python-checkins at python.org (ezio.melotti) Date: Sat, 4 May 2013 17:07:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzE2NTE4OiBtZXJnZSB3aXRoIDMuMy4=?= Message-ID: <3b2tqT2nLsz7Llk@mail.python.org> http://hg.python.org/cpython/rev/d4912244cce6 changeset: 83606:d4912244cce6 parent: 83603:df655ebf74d7 parent: 83605:003e4eb92683 user: Ezio Melotti date: Sat May 04 18:07:12 2013 +0300 summary: #16518: merge with 3.3. files: Doc/c-api/arg.rst | 13 ++++++------- Doc/c-api/bytearray.rst | 2 +- Doc/library/array.rst | 6 +++--- Doc/library/binascii.rst | 5 +++-- Doc/library/hashlib.rst | 6 +++--- Doc/library/hmac.rst | 3 +-- Doc/library/multiprocessing.rst | 5 ++--- Doc/library/stdtypes.rst | 12 +++++------- 8 files changed, 24 insertions(+), 28 deletions(-) diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -70,8 +70,7 @@ as *converter*. ``s*`` (:class:`str`, :class:`bytes`, :class:`bytearray` or buffer compatible object) [Py_buffer] - This format accepts Unicode objects as well as objects supporting the - buffer protocol. + This format accepts Unicode objects as well as :term:`bytes-like object`\ s. It fills a :c:type:`Py_buffer` structure provided by the caller. In this case the resulting C string may contain embedded NUL bytes. Unicode objects are converted to C strings using ``'utf-8'`` encoding. @@ -101,14 +100,14 @@ contain embedded NUL bytes; if it does, a :exc:`TypeError` exception is raised. -``y*`` (:class:`bytes`, :class:`bytearray` or buffer compatible object) [Py_buffer] - This variant on ``s*`` doesn't accept Unicode objects, only objects - supporting the buffer protocol. **This is the recommended way to accept +``y*`` (:class:`bytes`, :class:`bytearray` or :term:`bytes-like object`) [Py_buffer] + This variant on ``s*`` doesn't accept Unicode objects, only + :term:`bytes-like object`\ s. **This is the recommended way to accept binary data.** ``y#`` (:class:`bytes`) [const char \*, int] - This variant on ``s#`` doesn't accept Unicode objects, only bytes-like - objects. + This variant on ``s#`` doesn't accept Unicode objects, only :term:`bytes-like + object`\ s. ``S`` (:class:`bytes`) [PyBytesObject \*] Requires that the Python object is a :class:`bytes` object, without diff --git a/Doc/c-api/bytearray.rst b/Doc/c-api/bytearray.rst --- a/Doc/c-api/bytearray.rst +++ b/Doc/c-api/bytearray.rst @@ -40,7 +40,7 @@ .. c:function:: PyObject* PyByteArray_FromObject(PyObject *o) Return a new bytearray object from any object, *o*, that implements the - buffer protocol. + :ref:`buffer protocol `. .. XXX expand about the buffer protocol, at least somewhere diff --git a/Doc/library/array.rst b/Doc/library/array.rst --- a/Doc/library/array.rst +++ b/Doc/library/array.rst @@ -73,8 +73,8 @@ .. class:: array(typecode[, initializer]) A new array whose items are restricted by *typecode*, and initialized - from the optional *initializer* value, which must be a list, object - supporting the buffer interface, or iterable over elements of the + from the optional *initializer* value, which must be a list, a + :term:`bytes-like object`, or iterable over elements of the appropriate type. If given a list or string, the initializer is passed to the new array's @@ -91,7 +91,7 @@ concatenation, and multiplication. When using slice assignment, the assigned value must be an array object with the same type code; in all other cases, :exc:`TypeError` is raised. Array objects also implement the buffer interface, -and may be used wherever buffer objects are supported. +and may be used wherever :term:`bytes-like object`\ s are supported. The following data items and methods are also supported: diff --git a/Doc/library/binascii.rst b/Doc/library/binascii.rst --- a/Doc/library/binascii.rst +++ b/Doc/library/binascii.rst @@ -21,8 +21,9 @@ .. note:: ``a2b_*`` functions accept Unicode strings containing only ASCII characters. - Other functions only accept bytes and bytes-compatible objects (such as - bytearray objects and other objects implementing the buffer API). + Other functions only accept :term:`bytes-like object`\ s (such as + :class:`bytes`, :class:`bytearray` and other objects that support the buffer + protocol). .. versionchanged:: 3.3 ASCII-only unicode strings are now accepted by the ``a2b_*`` functions. diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst --- a/Doc/library/hashlib.rst +++ b/Doc/library/hashlib.rst @@ -32,9 +32,9 @@ There is one constructor method named for each type of :dfn:`hash`. All return a hash object with the same simple interface. For example: use :func:`sha1` to -create a SHA1 hash object. You can now feed this object with objects conforming -to the buffer interface (normally :class:`bytes` objects) using the -:meth:`update` method. At any point you can ask it for the :dfn:`digest` of the +create a SHA1 hash object. You can now feed this object with :term:`bytes-like +object`\ s (normally :class:`bytes`) using the :meth:`update` method. +At any point you can ask it for the :dfn:`digest` of the concatenation of the data fed to it so far using the :meth:`digest` or :meth:`hexdigest` methods. diff --git a/Doc/library/hmac.rst b/Doc/library/hmac.rst --- a/Doc/library/hmac.rst +++ b/Doc/library/hmac.rst @@ -74,8 +74,7 @@ timing analysis by avoiding content-based short circuiting behaviour, making it appropriate for cryptography. *a* and *b* must both be of the same type: either :class:`str` (ASCII only, as e.g. returned by - :meth:`HMAC.hexdigest`), or any type that supports the buffer protocol - (e.g. :class:`bytes`). + :meth:`HMAC.hexdigest`), or a :term:`bytes-like object`. .. note:: diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -800,8 +800,7 @@ .. method:: send_bytes(buffer[, offset[, size]]) - Send byte data from an object supporting the buffer interface as a - complete message. + Send byte data from a :term:`bytes-like object` as a complete message. If *offset* is given then data is read from that position in *buffer*. If *size* is given then that many bytes will be read from buffer. Very large @@ -832,7 +831,7 @@ :exc:`EOFError` if there is nothing left to receive and the other end was closed. - *buffer* must be an object satisfying the writable buffer interface. If + *buffer* must be a writable :term:`bytes-like object`. If *offset* is given then the message will be written into the buffer from that position. Offset must be a non-negative integer less than the length of *buffer* (in bytes). diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -519,9 +519,8 @@ >>> int.from_bytes([255, 0, 0], byteorder='big') 16711680 - The argument *bytes* must either support the buffer protocol or be an - iterable producing bytes. :class:`bytes` and :class:`bytearray` are - examples of built-in objects that support the buffer protocol. + The argument *bytes* must either be a :term:`bytes-like object` or an + iterable producing bytes. The *byteorder* argument determines the byte order used to represent the integer. If *byteorder* is ``"big"``, the most significant byte is at the @@ -1417,10 +1416,9 @@ single: bytes; str (built-in class) If at least one of *encoding* or *errors* is given, *object* should be a - :class:`bytes` or :class:`bytearray` object, or more generally any object - that supports the :ref:`buffer protocol `. In this case, if - *object* is a :class:`bytes` (or :class:`bytearray`) object, then - ``str(bytes, encoding, errors)`` is equivalent to + :term:`bytes-like object` (e.g. :class:`bytes` or :class:`bytearray`). In + this case, if *object* is a :class:`bytes` (or :class:`bytearray`) object, + then ``str(bytes, encoding, errors)`` is equivalent to :meth:`bytes.decode(encoding, errors) `. Otherwise, the bytes object underlying the buffer object is obtained before calling :meth:`bytes.decode`. See :ref:`binaryseq` and -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 19:57:10 2013 From: python-checkins at python.org (brett.cannon) Date: Sat, 4 May 2013 19:57:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_=2317115=2C17116=3A_Have_m?= =?utf-8?q?odules_initialize_the_=5F=5Fpackage=5F=5F_and_=5F=5Floader=5F?= =?utf-8?q?=5F?= Message-ID: <3b2ybB24YVz7Ljl@mail.python.org> http://hg.python.org/cpython/rev/e39a8f8ceb9f changeset: 83607:e39a8f8ceb9f user: Brett Cannon date: Sat May 04 13:56:58 2013 -0400 summary: #17115,17116: Have modules initialize the __package__ and __loader__ attributes to None. The long-term goal is for people to be able to rely on these attributes existing and checking for None to see if they have been set. Since import itself sets these attributes when a loader does not the only instances when the attributes are None are from someone overloading __import__() and not using a loader or someone creating a module from scratch. This patch also unifies module initialization. Before you could have different attributes with default values depending on how the module object was created. Now the only way to not get the same default set of attributes is to circumvent initialization by calling ModuleType.__new__() directly. files: Doc/c-api/module.rst | 11 +- Doc/library/importlib.rst | 2 +- Doc/reference/import.rst | 4 +- Doc/whatsnew/3.4.rst | 5 + Lib/ctypes/test/__init__.py | 2 +- Lib/doctest.py | 2 +- Lib/importlib/_bootstrap.py | 2 +- Lib/inspect.py | 2 +- Lib/test/test_descr.py | 4 +- Lib/test/test_importlib/test_api.py | 14 +- Lib/test/test_module.py | 28 +- Misc/NEWS | 3 + Objects/moduleobject.c | 39 +- Python/importlib.h | 363 ++++++++------- Python/pythonrun.c | 3 +- 15 files changed, 264 insertions(+), 220 deletions(-) diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -35,13 +35,20 @@ single: __name__ (module attribute) single: __doc__ (module attribute) single: __file__ (module attribute) + single: __package__ (module attribute) + single: __loader__ (module attribute) Return a new module object with the :attr:`__name__` attribute set to *name*. - Only the module's :attr:`__doc__` and :attr:`__name__` attributes are filled in; - the caller is responsible for providing a :attr:`__file__` attribute. + The module's :attr:`__name__`, :attr:`__doc__`, :attr:`__package__`, and + :attr:`__loader__` attributes are filled in (all but :attr:`__name__` are set + to ``None``); the caller is responsible for providing a :attr:`__file__` + attribute. .. versionadded:: 3.3 + .. versionchanged:: 3.4 + :attr:`__package__` and :attr:`__loader__` are set to ``None``. + .. c:function:: PyObject* PyModule_New(const char *name) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -827,7 +827,7 @@ decorator as it subsumes this functionality. .. versionchanged:: 3.4 - Set ``__loader__`` if set to ``None`` as well if the attribute does not + Set ``__loader__`` if set to ``None``, as if the attribute does not exist. diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -423,8 +423,8 @@ * If the module has a ``__file__`` attribute, this is used as part of the module's repr. - * If the module has no ``__file__`` but does have a ``__loader__``, then the - loader's repr is used as part of the module's repr. + * If the module has no ``__file__`` but does have a ``__loader__`` that is not + ``None``, then the loader's repr is used as part of the module's repr. * Otherwise, just use the module's ``__name__`` in the repr. 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 @@ -231,3 +231,8 @@ :exc:`NotImplementedError` blindly. This will only affect code calling :func:`super` and falling through all the way to the ABCs. For compatibility, catch both :exc:`NotImplementedError` or the appropriate exception as needed. + +* The module type now initializes the :attr:`__package__` and :attr:`__loader__` + attributes to ``None`` by default. To determine if these attributes were set + in a backwards-compatible fashion, use e.g. + ``getattr(module, '__loader__', None) is not None``. \ No newline at end of file diff --git a/Lib/ctypes/test/__init__.py b/Lib/ctypes/test/__init__.py --- a/Lib/ctypes/test/__init__.py +++ b/Lib/ctypes/test/__init__.py @@ -37,7 +37,7 @@ def find_package_modules(package, mask): import fnmatch - if (hasattr(package, "__loader__") and + if (package.__loader__ is not None and hasattr(package.__loader__, '_files')): path = package.__name__.replace(".", os.path.sep) mask = os.path.join(path, mask) diff --git a/Lib/doctest.py b/Lib/doctest.py --- a/Lib/doctest.py +++ b/Lib/doctest.py @@ -215,7 +215,7 @@ if module_relative: package = _normalize_module(package, 3) filename = _module_relative_path(package, filename) - if hasattr(package, '__loader__'): + if getattr(package, '__loader__', None) is not None: if hasattr(package.__loader__, 'get_data'): file_contents = package.__loader__.get_data(filename) file_contents = file_contents.decode(encoding) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -1726,7 +1726,7 @@ module_type = type(sys) for name, module in sys.modules.items(): if isinstance(module, module_type): - if not hasattr(module, '__loader__'): + if getattr(module, '__loader__', None) is None: if name in sys.builtin_module_names: module.__loader__ = BuiltinImporter elif _imp.is_frozen(name): diff --git a/Lib/inspect.py b/Lib/inspect.py --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -476,7 +476,7 @@ if os.path.exists(filename): return filename # only return a non-existent filename if the module has a PEP 302 loader - if hasattr(getmodule(object, filename), '__loader__'): + if getattr(getmodule(object, filename), '__loader__', None) is not None: return filename # or it is in the linecache if filename in linecache.cache: diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -2250,7 +2250,9 @@ minstance = M("m") minstance.b = 2 minstance.a = 1 - names = [x for x in dir(minstance) if x not in ["__name__", "__doc__"]] + default_attributes = ['__name__', '__doc__', '__package__', + '__loader__'] + names = [x for x in dir(minstance) if x not in default_attributes] self.assertEqual(names, ['a', 'b']) class M2(M): diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py --- a/Lib/test/test_importlib/test_api.py +++ b/Lib/test/test_importlib/test_api.py @@ -197,14 +197,12 @@ # Issue #17098: all modules should have __loader__ defined. for name, module in sys.modules.items(): if isinstance(module, types.ModuleType): - if name in sys.builtin_module_names: - self.assertIn(module.__loader__, - (importlib.machinery.BuiltinImporter, - importlib._bootstrap.BuiltinImporter)) - elif imp.is_frozen(name): - self.assertIn(module.__loader__, - (importlib.machinery.FrozenImporter, - importlib._bootstrap.FrozenImporter)) + self.assertTrue(hasattr(module, '__loader__'), + '{!r} lacks a __loader__ attribute'.format(name)) + if importlib.machinery.BuiltinImporter.find_module(name): + self.assertIsNot(module.__loader__, None) + elif importlib.machinery.FrozenImporter.find_module(name): + self.assertIsNot(module.__loader__, None) if __name__ == '__main__': diff --git a/Lib/test/test_module.py b/Lib/test/test_module.py --- a/Lib/test/test_module.py +++ b/Lib/test/test_module.py @@ -33,7 +33,10 @@ foo = ModuleType("foo") self.assertEqual(foo.__name__, "foo") self.assertEqual(foo.__doc__, None) - self.assertEqual(foo.__dict__, {"__name__": "foo", "__doc__": None}) + self.assertIs(foo.__loader__, None) + self.assertIs(foo.__package__, None) + self.assertEqual(foo.__dict__, {"__name__": "foo", "__doc__": None, + "__loader__": None, "__package__": None}) def test_ascii_docstring(self): # ASCII docstring @@ -41,7 +44,8 @@ self.assertEqual(foo.__name__, "foo") self.assertEqual(foo.__doc__, "foodoc") self.assertEqual(foo.__dict__, - {"__name__": "foo", "__doc__": "foodoc"}) + {"__name__": "foo", "__doc__": "foodoc", + "__loader__": None, "__package__": None}) def test_unicode_docstring(self): # Unicode docstring @@ -49,7 +53,8 @@ self.assertEqual(foo.__name__, "foo") self.assertEqual(foo.__doc__, "foodoc\u1234") self.assertEqual(foo.__dict__, - {"__name__": "foo", "__doc__": "foodoc\u1234"}) + {"__name__": "foo", "__doc__": "foodoc\u1234", + "__loader__": None, "__package__": None}) def test_reinit(self): # Reinitialization should not replace the __dict__ @@ -61,7 +66,8 @@ self.assertEqual(foo.__doc__, "foodoc") self.assertEqual(foo.bar, 42) self.assertEqual(foo.__dict__, - {"__name__": "foo", "__doc__": "foodoc", "bar": 42}) + {"__name__": "foo", "__doc__": "foodoc", "bar": 42, + "__loader__": None, "__package__": None}) self.assertTrue(foo.__dict__ is d) @unittest.expectedFailure @@ -110,13 +116,19 @@ m.__file__ = '/tmp/foo.py' self.assertEqual(repr(m), "") + def test_module_repr_with_loader_as_None(self): + m = ModuleType('foo') + assert m.__loader__ is None + self.assertEqual(repr(m), "") + def test_module_repr_with_bare_loader_but_no_name(self): m = ModuleType('foo') del m.__name__ # Yes, a class not an instance. m.__loader__ = BareLoader + loader_repr = repr(BareLoader) self.assertEqual( - repr(m), ")>") + repr(m), "".format(loader_repr)) def test_module_repr_with_full_loader_but_no_name(self): # m.__loader__.module_repr() will fail because the module has no @@ -126,15 +138,17 @@ del m.__name__ # Yes, a class not an instance. m.__loader__ = FullLoader + loader_repr = repr(FullLoader) self.assertEqual( - repr(m), ")>") + repr(m), "".format(loader_repr)) def test_module_repr_with_bare_loader(self): m = ModuleType('foo') # Yes, a class not an instance. m.__loader__ = BareLoader + module_repr = repr(BareLoader) self.assertEqual( - repr(m), ")>") + repr(m), "".format(module_repr)) def test_module_repr_with_full_loader(self): m = ModuleType('foo') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #17115,17116: Module initialization now includes setting __package__ and + __loader__ attributes to None. + - Issue #17853: Ensure locals of a class that shadow free variables always win over the closures. diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -26,6 +26,27 @@ }; +static int +module_init_dict(PyObject *md_dict, PyObject *name, PyObject *doc) +{ + if (md_dict == NULL) + return -1; + if (doc == NULL) + doc = Py_None; + + if (PyDict_SetItemString(md_dict, "__name__", name) != 0) + return -1; + if (PyDict_SetItemString(md_dict, "__doc__", doc) != 0) + return -1; + if (PyDict_SetItemString(md_dict, "__package__", Py_None) != 0) + return -1; + if (PyDict_SetItemString(md_dict, "__loader__", Py_None) != 0) + return -1; + + return 0; +} + + PyObject * PyModule_NewObject(PyObject *name) { @@ -36,13 +57,7 @@ m->md_def = NULL; m->md_state = NULL; m->md_dict = PyDict_New(); - if (m->md_dict == NULL) - goto fail; - if (PyDict_SetItemString(m->md_dict, "__name__", name) != 0) - goto fail; - if (PyDict_SetItemString(m->md_dict, "__doc__", Py_None) != 0) - goto fail; - if (PyDict_SetItemString(m->md_dict, "__package__", Py_None) != 0) + if (module_init_dict(m->md_dict, name, NULL) != 0) goto fail; PyObject_GC_Track(m); return (PyObject *)m; @@ -347,9 +362,7 @@ return -1; m->md_dict = dict; } - if (PyDict_SetItemString(dict, "__name__", name) < 0) - return -1; - if (PyDict_SetItemString(dict, "__doc__", doc) < 0) + if (module_init_dict(dict, name, doc) < 0) return -1; return 0; } @@ -380,7 +393,7 @@ if (m->md_dict != NULL) { loader = PyDict_GetItemString(m->md_dict, "__loader__"); } - if (loader != NULL) { + if (loader != NULL && loader != Py_None) { repr = PyObject_CallMethod(loader, "module_repr", "(O)", (PyObject *)m, NULL); if (repr == NULL) { @@ -404,10 +417,10 @@ filename = PyModule_GetFilenameObject((PyObject *)m); if (filename == NULL) { PyErr_Clear(); - /* There's no m.__file__, so if there was an __loader__, use that in + /* There's no m.__file__, so if there was a __loader__, use that in * the repr, otherwise, the only thing you can use is m.__name__ */ - if (loader == NULL) { + if (loader == NULL || loader == Py_None) { repr = PyUnicode_FromFormat("", name); } else { diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -866,7 +866,8 @@ * be set if __main__ gets further initialized later in the startup * process. */ - if (PyDict_GetItemString(d, "__loader__") == NULL) { + PyObject *loader = PyDict_GetItemString(d, "__loader__"); + if (loader == NULL || loader == Py_None) { PyObject *loader = PyObject_GetAttrString(interp->importlib, "BuiltinImporter"); if (loader == NULL) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 20:04:53 2013 From: python-checkins at python.org (brett.cannon) Date: Sat, 4 May 2013 20:04:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Add_a_warning_to_PEP_302_that?= =?utf-8?q?_it_should_not_longer_be_used_as_a?= Message-ID: <3b2ym558fkz7LjQ@mail.python.org> http://hg.python.org/peps/rev/af43643e51da changeset: 4873:af43643e51da user: Brett Cannon date: Sat May 04 14:04:46 2013 -0400 summary: Add a warning to PEP 302 that it should not longer be used as a reference. files: pep-0302.txt | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/pep-0302.txt b/pep-0302.txt --- a/pep-0302.txt +++ b/pep-0302.txt @@ -11,6 +11,11 @@ Python-Version: 2.3 Post-History: 19-Dec-2002 +.. warning:: + The language reference for import [10]_ and importlib documentation + [11]_ now supercede this PEP. This document is no longer updated + and provided for historical purposes only. + Abstract ======== @@ -553,6 +558,12 @@ .. [9] New import hooks + Import from Zip files http://bugs.python.org/issue652586 +.. [10] Language reference for imports + http://docs.python.org/3/reference/import.html + +.. [11] importlib documentation + http://docs.python.org/3/library/importlib.html#module-importlib + Copyright ========= -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat May 4 20:08:44 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 4 May 2013 20:08:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=235845=3A_Enable_ta?= =?utf-8?q?b-completion_in_the_interactive_interpreter_by_default=2C?= Message-ID: <3b2yrX5nDpz7Ljl@mail.python.org> http://hg.python.org/cpython/rev/d5ef330bac50 changeset: 83608:d5ef330bac50 user: Antoine Pitrou date: Sat May 04 20:08:35 2013 +0200 summary: Issue #5845: Enable tab-completion in the interactive interpreter by default, thanks to a new sys.__interactivehook__. (original patch by ?ric Araujo) files: Doc/library/readline.rst | 20 +- Doc/library/rlcompleter.rst | 16 +- Doc/library/site.rst | 20 ++- Doc/library/sys.rst | 10 + Doc/tutorial/interactive.rst | 153 ++-------------------- Doc/using/cmdline.rst | 9 +- Lib/site.py | 42 ++++++- Misc/NEWS | 10 +- Modules/main.c | 28 ++++ 9 files changed, 143 insertions(+), 165 deletions(-) diff --git a/Doc/library/readline.rst b/Doc/library/readline.rst --- a/Doc/library/readline.rst +++ b/Doc/library/readline.rst @@ -190,28 +190,32 @@ The following example demonstrates how to use the :mod:`readline` module's history reading and writing functions to automatically load and save a history -file named :file:`.pyhist` from the user's home directory. The code below would -normally be executed automatically during interactive sessions from the user's -:envvar:`PYTHONSTARTUP` file. :: +file named :file:`.python_history` from the user's home directory. The code +below would normally be executed automatically during interactive sessions +from the user's :envvar:`PYTHONSTARTUP` file. :: + import atexit import os import readline - histfile = os.path.join(os.path.expanduser("~"), ".pyhist") + + histfile = os.path.join(os.path.expanduser("~"), ".python_history") try: readline.read_history_file(histfile) except FileNotFoundError: pass - import atexit + atexit.register(readline.write_history_file, histfile) - del os, histfile + +This code is actually automatically run when Python is run in +:ref:`interactive mode ` (see :ref:`rlcompleter-config`). The following example extends the :class:`code.InteractiveConsole` class to support history save/restore. :: + import atexit import code + import os import readline - import atexit - import os class HistoryConsole(code.InteractiveConsole): def __init__(self, locals=None, filename="", diff --git a/Doc/library/rlcompleter.rst b/Doc/library/rlcompleter.rst --- a/Doc/library/rlcompleter.rst +++ b/Doc/library/rlcompleter.rst @@ -27,18 +27,10 @@ readline.__name__ readline.parse_and_bind( >>> readline. -The :mod:`rlcompleter` module is designed for use with Python's interactive -mode. A user can add the following lines to his or her initialization file -(identified by the :envvar:`PYTHONSTARTUP` environment variable) to get -automatic :kbd:`Tab` completion:: - - try: - import readline - except ImportError: - print("Module readline not available.") - else: - import rlcompleter - readline.parse_and_bind("tab: complete") +The :mod:`rlcompleter` module is designed for use with Python's +:ref:`interactive mode `. Unless Python is run with the +:option:`-S` option, the module is automatically imported and configured +(see :ref:`rlcompleter-config`). On platforms without :mod:`readline`, the :class:`Completer` class defined by this module can still be used for custom purposes. diff --git a/Doc/library/site.rst b/Doc/library/site.rst --- a/Doc/library/site.rst +++ b/Doc/library/site.rst @@ -111,6 +111,23 @@ :mod:`sitecustomize` and :mod:`usercustomize` is still attempted. +.. _rlcompleter-config: + +Readline configuration +---------------------- + +On systems that support :mod:`readline`, this module will also import and +configure the :mod:`rlcompleter` module, if Python is started in +:ref:`interactive mode ` and without the :option:`-S` option. +The default behavior is enable tab-completion and to use +:file:`~/.python_history` as the history save file. To disable it, override +the :data:`sys.__interactivehook__` attribute in your :mod:`sitecustomize` +or :mod:`usercustomize` module or your :envvar:`PYTHONSTARTUP` file. + + +Module contents +--------------- + .. data:: PREFIXES A list of prefixes for site-packages directories. @@ -153,8 +170,7 @@ Adds all the standard site-specific directories to the module search path. This function is called automatically when this module is imported, - unless the :program:`python` interpreter was started with the :option:`-S` - flag. + unless the Python interpreter was started with the :option:`-S` flag. .. versionchanged:: 3.3 This function used to be called unconditionnally. diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -679,6 +679,16 @@ .. versionadded:: 3.1 +.. data:: __interactivehook__ + + When present, this function is automatically called (with no arguments) + when the interpreter is launched in :ref:`interactive mode `. + This is done after the :envvar:`PYTHONSTARTUP` file is read, so that you + can set this hook there. + + .. versionadded:: 3.4 + + .. function:: intern(string) Enter *string* in the table of "interned" strings and return the interned string diff --git a/Doc/tutorial/interactive.rst b/Doc/tutorial/interactive.rst --- a/Doc/tutorial/interactive.rst +++ b/Doc/tutorial/interactive.rst @@ -7,140 +7,27 @@ Some versions of the Python interpreter support editing of the current input line and history substitution, similar to facilities found in the Korn shell and the GNU Bash shell. This is implemented using the `GNU Readline`_ library, -which supports Emacs-style and vi-style editing. This library has its own -documentation which I won't duplicate here; however, the basics are easily -explained. The interactive editing and history described here are optionally -available in the Unix and Cygwin versions of the interpreter. - -This chapter does *not* document the editing facilities of Mark Hammond's -PythonWin package or the Tk-based environment, IDLE, distributed with Python. -The command line history recall which operates within DOS boxes on NT and some -other DOS and Windows flavors is yet another beast. - - -.. _tut-lineediting: - -Line Editing -============ - -If supported, input line editing is active whenever the interpreter prints a -primary or secondary prompt. The current line can be edited using the -conventional Emacs control characters. The most important of these are: -:kbd:`C-A` (Control-A) moves the cursor to the beginning of the line, :kbd:`C-E` -to the end, :kbd:`C-B` moves it one position to the left, :kbd:`C-F` to the -right. Backspace erases the character to the left of the cursor, :kbd:`C-D` the -character to its right. :kbd:`C-K` kills (erases) the rest of the line to the -right of the cursor, :kbd:`C-Y` yanks back the last killed string. -:kbd:`C-underscore` undoes the last change you made; it can be repeated for -cumulative effect. - - -.. _tut-history: - -History Substitution -==================== - -History substitution works as follows. All non-empty input lines issued are -saved in a history buffer, and when a new prompt is given you are positioned on -a new line at the bottom of this buffer. :kbd:`C-P` moves one line up (back) in -the history buffer, :kbd:`C-N` moves one down. Any line in the history buffer -can be edited; an asterisk appears in front of the prompt to mark a line as -modified. Pressing the :kbd:`Return` key passes the current line to the -interpreter. :kbd:`C-R` starts an incremental reverse search; :kbd:`C-S` starts -a forward search. +which supports various styles of editing. This library has its own +documentation which we won't duplicate here. .. _tut-keybindings: -Key Bindings -============ +Tab Completion and History Editing +================================== -The key bindings and some other parameters of the Readline library can be -customized by placing commands in an initialization file called -:file:`~/.inputrc`. Key bindings have the form :: - - key-name: function-name - -or :: - - "string": function-name - -and options can be set with :: - - set option-name value - -For example:: - - # I prefer vi-style editing: - set editing-mode vi - - # Edit using a single line: - set horizontal-scroll-mode On - - # Rebind some keys: - Meta-h: backward-kill-word - "\C-u": universal-argument - "\C-x\C-r": re-read-init-file - -Note that the default binding for :kbd:`Tab` in Python is to insert a :kbd:`Tab` -character instead of Readline's default filename completion function. If you -insist, you can override this by putting :: - - Tab: complete - -in your :file:`~/.inputrc`. (Of course, this makes it harder to type indented -continuation lines if you're accustomed to using :kbd:`Tab` for that purpose.) - -.. index:: - module: rlcompleter - module: readline - -Automatic completion of variable and module names is optionally available. To -enable it in the interpreter's interactive mode, add the following to your -startup file: [#]_ :: - - import rlcompleter, readline - readline.parse_and_bind('tab: complete') - -This binds the :kbd:`Tab` key to the completion function, so hitting the -:kbd:`Tab` key twice suggests completions; it looks at Python statement names, -the current local variables, and the available module names. For dotted -expressions such as ``string.a``, it will evaluate the expression up to the -final ``'.'`` and then suggest completions from the attributes of the resulting -object. Note that this may execute application-defined code if an object with a -:meth:`__getattr__` method is part of the expression. - -A more capable startup file might look like this example. Note that this -deletes the names it creates once they are no longer needed; this is done since -the startup file is executed in the same namespace as the interactive commands, -and removing the names avoids creating side effects in the interactive -environment. You may find it convenient to keep some of the imported modules, -such as :mod:`os`, which turn out to be needed in most sessions with the -interpreter. :: - - # Add auto-completion and a stored history file of commands to your Python - # interactive interpreter. Requires Python 2.0+, readline. Autocomplete is - # bound to the Esc key by default (you can change it - see readline docs). - # - # Store the file in ~/.pystartup, and set an environment variable to point - # to it: "export PYTHONSTARTUP=~/.pystartup" in bash. - - import atexit - import os - import readline - import rlcompleter - - historyPath = os.path.expanduser("~/.pyhistory") - - def save_history(historyPath=historyPath): - import readline - readline.write_history_file(historyPath) - - if os.path.exists(historyPath): - readline.read_history_file(historyPath) - - atexit.register(save_history) - del os, atexit, readline, rlcompleter, save_history, historyPath +Completion of variable and module names is +:ref:`automatically enabled ` at interpreter startup so +that the :kbd:`Tab` key invokes the completion function; it looks at +Python statement names, the current local variables, and the available +module names. For dotted expressions such as ``string.a``, it will evaluate +the expression up to the final ``'.'`` and then suggest completions from +the attributes of the resulting object. Note that this may execute +application-defined code if an object with a :meth:`__getattr__` method +is part of the expression. The default configuration also saves your +history into a file named :file:`.python_history` in your user directory. +The history will be available again during the next interactive interpreter +session. .. _tut-commentary: @@ -162,14 +49,6 @@ bpython_. -.. rubric:: Footnotes - -.. [#] Python will execute the contents of a file identified by the - :envvar:`PYTHONSTARTUP` environment variable when you start an interactive - interpreter. To customize Python even for non-interactive mode, see - :ref:`tut-customize`. - - .. _GNU Readline: http://tiswww.case.edu/php/chet/readline/rltop.html .. _IPython: http://ipython.scipy.org/ .. _bpython: http://www.bpython-interpreter.org/ diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -147,7 +147,12 @@ If no interface option is given, :option:`-i` is implied, ``sys.argv[0]`` is an empty string (``""``) and the current directory will be added to the -start of :data:`sys.path`. +start of :data:`sys.path`. Also, tab-completion and history editing is +automatically enabled, if available on your platform (see +:ref:`rlcompleter-config`). + +.. versionchanged:: 3.4 + Automatic enabling of tab-completion and history editing. .. seealso:: :ref:`tut-invoking` @@ -438,7 +443,7 @@ is executed in the same namespace where interactive commands are executed so that objects defined or imported in it can be used without qualification in the interactive session. You can also change the prompts :data:`sys.ps1` and - :data:`sys.ps2` in this file. + :data:`sys.ps2` and the hook :data:`sys.__interactivehook__` in this file. .. envvar:: PYTHONY2K diff --git a/Lib/site.py b/Lib/site.py --- a/Lib/site.py +++ b/Lib/site.py @@ -58,11 +58,14 @@ because bar.pth comes alphabetically before foo.pth; and spam is omitted because it is not mentioned in either path configuration file. -After these path manipulations, an attempt is made to import a module +The readline module is also automatically configured to enable +completion for systems that support it. This can be overriden in +sitecustomize, usercustomize or PYTHONSTARTUP. + +After these operations, an attempt is made to import a module named sitecustomize, which can perform arbitrary additional site-specific customizations. If this import fails with an ImportError exception, it is silently ignored. - """ import sys @@ -452,6 +455,40 @@ def sethelper(): builtins.help = _Helper() +def enablerlcompleter(): + """Enable default readline configuration on interactive prompts, by + registering a sys.__interactivehook__. + + If the readline module can be imported, the hook will set the Tab key + as completion key and register ~/.python_history as history file. + This can be overriden in the sitecustomize or usercustomize module, + or in a PYTHONSTARTUP file. + """ + def register_readline(): + import atexit + try: + import readline + import rlcompleter + except ImportError: + return + + # Reading the initialization (config) file may not be enough to set a + # completion key, so we set one first and then read the file + if 'libedit' in getattr(readline, '__doc__', ''): + readline.parse_and_bind('bind ^I rl_complete') + else: + readline.parse_and_bind('tab: complete') + readline.read_init_file() + + history = os.path.join(os.path.expanduser('~'), '.python_history') + try: + readline.read_history_file(history) + except IOError: + pass + atexit.register(readline.write_history_file, history) + + sys.__interactivehook__ = register_readline + def aliasmbcs(): """On Windows, some default encodings are not provided by Python, while they are always available as "mbcs" in each locale. Make @@ -571,6 +608,7 @@ setquit() setcopyright() sethelper() + enablerlcompleter() aliasmbcs() execsitecustomize() if ENABLE_USER_SITE: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #5845: Enable tab-completion in the interactive interpreter by + default, thanks to a new sys.__interactivehook__. + - Issue #17115,17116: Module initialization now includes setting __package__ and __loader__ attributes to None. @@ -63,8 +66,8 @@ Library ------- - - Issue #15902: Fix imp.load_module() accepting None as a file when loading an - extension module. +- Issue #15902: Fix imp.load_module() accepting None as a file when loading an + extension module. - Issue #13721: SSLSocket.getpeercert() and SSLSocket.do_handshake() now raise an OSError with ENOTCONN, instead of an AttributeError, when the @@ -5001,6 +5004,9 @@ - Issue #11635: Don't use polling in worker threads and processes launched by concurrent.futures. +- Issue #5845: Automatically read readline configuration to enable completion + in interactive mode. + - Issue #6811: Allow importlib to change a code object's co_filename attribute to match the path to where the source code currently is, not where the code object originally came from. diff --git a/Modules/main.c b/Modules/main.c --- a/Modules/main.c +++ b/Modules/main.c @@ -160,6 +160,32 @@ } } +static void RunInteractiveHook(void) +{ + PyObject *sys, *hook, *result; + sys = PyImport_ImportModule("sys"); + if (sys == NULL) + goto error; + hook = PyObject_GetAttrString(sys, "__interactivehook__"); + Py_DECREF(sys); + if (hook == NULL) + PyErr_Clear(); + else { + result = PyObject_CallObject(hook, NULL); + Py_DECREF(hook); + if (result == NULL) + goto error; + else + Py_DECREF(result); + } + return; + +error: + PySys_WriteStderr("Failed calling sys.__interactivehook__\n"); + PyErr_Print(); + PyErr_Clear(); +} + static int RunModule(wchar_t *modname, int set_argv0) { @@ -690,6 +716,7 @@ if (filename == NULL && stdin_is_interactive) { Py_InspectFlag = 0; /* do exit on SystemExit */ RunStartupFile(&cf); + RunInteractiveHook(); } /* XXX */ @@ -755,6 +782,7 @@ if (Py_InspectFlag && stdin_is_interactive && (filename != NULL || command != NULL || module != NULL)) { Py_InspectFlag = 0; + RunInteractiveHook(); /* XXX */ sts = PyRun_AnyFileFlags(stdin, "", &cf) != 0; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 20:19:03 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 4 May 2013 20:19:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Elaborate_on_b?= =?utf-8?q?ytes-like_objects=2E?= Message-ID: <3b2z4R3fmSz7LlN@mail.python.org> http://hg.python.org/cpython/rev/6bd2446f129a changeset: 83609:6bd2446f129a branch: 3.3 parent: 83605:003e4eb92683 user: Antoine Pitrou date: Sat May 04 20:18:34 2013 +0200 summary: Elaborate on bytes-like objects. files: Doc/glossary.rst | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -79,8 +79,12 @@ `_, Python's creator. bytes-like object - An object that supports the :ref:`bufferobjects`, like :class:`bytes` or - :class:`bytearray`. + An object that supports the :ref:`bufferobjects`, like :class:`bytes`, + :class:`bytearray` or :class:`memoryview`. Bytes-like objects can + be used for various operations that expect binary data, such as + compression, saving to a binary file or sending over a socket. + Some operations need the binary data to be mutable, in which case + not all bytes-like objects can apply. bytecode Python source code is compiled into bytecode, the internal representation -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 20:19:04 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 4 May 2013 20:19:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Elaborate_on_bytes-like_objects=2E?= Message-ID: <3b2z4S5tRfz7LlN@mail.python.org> http://hg.python.org/cpython/rev/193f25352e1c changeset: 83610:193f25352e1c parent: 83608:d5ef330bac50 parent: 83609:6bd2446f129a user: Antoine Pitrou date: Sat May 04 20:18:53 2013 +0200 summary: Elaborate on bytes-like objects. files: Doc/glossary.rst | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -79,8 +79,12 @@ `_, Python's creator. bytes-like object - An object that supports the :ref:`bufferobjects`, like :class:`bytes` or - :class:`bytearray`. + An object that supports the :ref:`bufferobjects`, like :class:`bytes`, + :class:`bytearray` or :class:`memoryview`. Bytes-like objects can + be used for various operations that expect binary data, such as + compression, saving to a binary file or sending over a socket. + Some operations need the binary data to be mutable, in which case + not all bytes-like objects can apply. bytecode Python source code is compiled into bytecode, the internal representation -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 20:24:56 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 4 May 2013 20:24:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Elaborate_on_b?= =?utf-8?q?ytes-like_objects=2E?= Message-ID: <3b2zCD0nTMzRlj@mail.python.org> http://hg.python.org/cpython/rev/74e1c50498f8 changeset: 83611:74e1c50498f8 branch: 2.7 parent: 83604:e71406d8ed5d user: Antoine Pitrou date: Sat May 04 20:18:34 2013 +0200 summary: Elaborate on bytes-like objects. files: Doc/glossary.rst | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -79,7 +79,11 @@ bytes-like object An object that supports the :ref:`buffer protocol `, - like :class:`str` or :class:`bytearray`. + like :class:`str`, :class:`bytearray` or :class:`memoryview`. + Bytes-like objects can be used for various operations that expect + binary data, such as compression, saving to a binary file or sending + over a socket. Some operations need the binary data to be mutable, + in which case not all bytes-like objects can apply. bytecode Python source code is compiled into bytecode, the internal representation -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 20:46:34 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 4 May 2013 20:46:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3NDA4?= =?utf-8?q?=3A_Avoid_using_an_obsolete_instance_of_the_copyreg_module_when?= =?utf-8?q?_the?= Message-ID: <3b2zhB6Rr6z7Lk8@mail.python.org> http://hg.python.org/cpython/rev/8c1385205a35 changeset: 83612:8c1385205a35 branch: 3.3 parent: 83609:6bd2446f129a user: Antoine Pitrou date: Sat May 04 20:45:02 2013 +0200 summary: Issue #17408: Avoid using an obsolete instance of the copyreg module when the interpreter is shutdown and then started again. files: Include/pythonrun.h | 1 + Misc/NEWS | 3 +++ Objects/typeobject.c | 26 +++++++++++++++++++------- Python/pythonrun.c | 4 +--- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Include/pythonrun.h b/Include/pythonrun.h --- a/Include/pythonrun.h +++ b/Include/pythonrun.h @@ -219,6 +219,7 @@ PyAPI_FUNC(void) PyOS_FiniInterrupts(void); PyAPI_FUNC(void) _PyGC_Fini(void); PyAPI_FUNC(void) PySlice_Fini(void); +PyAPI_FUNC(void) _PyType_Fini(void); PyAPI_DATA(PyThreadState *) _Py_Finalizing; #endif diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ Core and Builtins ----------------- +- Issue #17408: Avoid using an obsolete instance of the copyreg module when + the interpreter is shutdown and then started again. + - Issue #17863: In the interactive console, don't loop forever if the encoding can't be fetched from stdin. diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -7,6 +7,10 @@ #include +/* Cached lookup of the copyreg module, for faster __reduce__ calls */ + +static PyObject *cached_copyreg_module = NULL; + /* Support type attribute cache */ /* The cache can keep references to the names alive for longer than @@ -69,6 +73,15 @@ } void +_PyType_Fini(void) +{ + PyType_ClearCache(); + /* Need to forget our obsolete instance of the copyreg module at + * interpreter shutdown (issue #17408). */ + Py_CLEAR(cached_copyreg_module); +} + +void PyType_Modified(PyTypeObject *type) { /* Invalidate any cached data for the specified type and all @@ -3339,19 +3352,18 @@ import_copyreg(void) { static PyObject *copyreg_str; - static PyObject *mod_copyreg = NULL; if (!copyreg_str) { copyreg_str = PyUnicode_InternFromString("copyreg"); if (copyreg_str == NULL) return NULL; } - if (!mod_copyreg) { - mod_copyreg = PyImport_Import(copyreg_str); - } - - Py_XINCREF(mod_copyreg); - return mod_copyreg; + if (!cached_copyreg_module) { + cached_copyreg_module = PyImport_Import(copyreg_str); + } + + Py_XINCREF(cached_copyreg_module); + return cached_copyreg_module; } static PyObject * diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -506,9 +506,6 @@ /* Disable signal handling */ PyOS_FiniInterrupts(); - /* Clear type lookup cache */ - PyType_ClearCache(); - /* 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 @@ -614,6 +611,7 @@ PyFloat_Fini(); PyDict_Fini(); PySlice_Fini(); + _PyType_Fini(); /* Cleanup Unicode implementation */ _PyUnicode_Fini(); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 20:46:36 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 4 May 2013 20:46:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317408=3A_Avoid_using_an_obsolete_instance_of_th?= =?utf-8?q?e_copyreg_module_when_the?= Message-ID: <3b2zhD1t0yz7LjR@mail.python.org> http://hg.python.org/cpython/rev/0b34fd75b937 changeset: 83613:0b34fd75b937 parent: 83610:193f25352e1c parent: 83612:8c1385205a35 user: Antoine Pitrou date: Sat May 04 20:46:19 2013 +0200 summary: Issue #17408: Avoid using an obsolete instance of the copyreg module when the interpreter is shutdown and then started again. files: Include/pythonrun.h | 1 + Misc/NEWS | 3 +++ Objects/typeobject.c | 26 +++++++++++++++++++------- Python/pythonrun.c | 4 +--- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Include/pythonrun.h b/Include/pythonrun.h --- a/Include/pythonrun.h +++ b/Include/pythonrun.h @@ -219,6 +219,7 @@ PyAPI_FUNC(void) PyOS_FiniInterrupts(void); PyAPI_FUNC(void) _PyGC_Fini(void); PyAPI_FUNC(void) PySlice_Fini(void); +PyAPI_FUNC(void) _PyType_Fini(void); PyAPI_DATA(PyThreadState *) _Py_Finalizing; #endif diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #17408: Avoid using an obsolete instance of the copyreg module when + the interpreter is shutdown and then started again. + - Issue #5845: Enable tab-completion in the interactive interpreter by default, thanks to a new sys.__interactivehook__. diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -7,6 +7,10 @@ #include +/* Cached lookup of the copyreg module, for faster __reduce__ calls */ + +static PyObject *cached_copyreg_module = NULL; + /* Support type attribute cache */ /* The cache can keep references to the names alive for longer than @@ -69,6 +73,15 @@ } void +_PyType_Fini(void) +{ + PyType_ClearCache(); + /* Need to forget our obsolete instance of the copyreg module at + * interpreter shutdown (issue #17408). */ + Py_CLEAR(cached_copyreg_module); +} + +void PyType_Modified(PyTypeObject *type) { /* Invalidate any cached data for the specified type and all @@ -3339,19 +3352,18 @@ import_copyreg(void) { static PyObject *copyreg_str; - static PyObject *mod_copyreg = NULL; if (!copyreg_str) { copyreg_str = PyUnicode_InternFromString("copyreg"); if (copyreg_str == NULL) return NULL; } - if (!mod_copyreg) { - mod_copyreg = PyImport_Import(copyreg_str); - } - - Py_XINCREF(mod_copyreg); - return mod_copyreg; + if (!cached_copyreg_module) { + cached_copyreg_module = PyImport_Import(copyreg_str); + } + + Py_XINCREF(cached_copyreg_module); + return cached_copyreg_module; } static PyObject * diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -524,9 +524,6 @@ /* Disable signal handling */ PyOS_FiniInterrupts(); - /* Clear type lookup cache */ - PyType_ClearCache(); - /* 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 @@ -632,6 +629,7 @@ PyFloat_Fini(); PyDict_Fini(); PySlice_Fini(); + _PyType_Fini(); /* Cleanup Unicode implementation */ _PyUnicode_Fini(); -- Repository URL: http://hg.python.org/cpython From brett at python.org Sat May 4 20:49:16 2013 From: brett at python.org (Brett Cannon) Date: Sat, 4 May 2013 14:49:16 -0400 Subject: [Python-checkins] cpython: #17115, 17116: Have modules initialize the __package__ and __loader__ In-Reply-To: <3b2ybB24YVz7Ljl@mail.python.org> References: <3b2ybB24YVz7Ljl@mail.python.org> Message-ID: FYI, I'm aware this broke some buildbots and will have a look today to figure out why. On Sat, May 4, 2013 at 1:57 PM, brett.cannon wrote: > http://hg.python.org/cpython/rev/e39a8f8ceb9f > changeset: 83607:e39a8f8ceb9f > user: Brett Cannon > date: Sat May 04 13:56:58 2013 -0400 > summary: > #17115,17116: Have modules initialize the __package__ and __loader__ > attributes to None. > > The long-term goal is for people to be able to rely on these > attributes existing and checking for None to see if they have been > set. Since import itself sets these attributes when a loader does not > the only instances when the attributes are None are from someone > overloading __import__() and not using a loader or someone creating a > module from scratch. > > This patch also unifies module initialization. Before you could have > different attributes with default values depending on how the module > object was created. Now the only way to not get the same default set > of attributes is to circumvent initialization by calling > ModuleType.__new__() directly. > > files: > Doc/c-api/module.rst | 11 +- > Doc/library/importlib.rst | 2 +- > Doc/reference/import.rst | 4 +- > Doc/whatsnew/3.4.rst | 5 + > Lib/ctypes/test/__init__.py | 2 +- > Lib/doctest.py | 2 +- > Lib/importlib/_bootstrap.py | 2 +- > Lib/inspect.py | 2 +- > Lib/test/test_descr.py | 4 +- > Lib/test/test_importlib/test_api.py | 14 +- > Lib/test/test_module.py | 28 +- > Misc/NEWS | 3 + > Objects/moduleobject.c | 39 +- > Python/importlib.h | 363 ++++++++------- > Python/pythonrun.c | 3 +- > 15 files changed, 264 insertions(+), 220 deletions(-) > > > diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst > --- a/Doc/c-api/module.rst > +++ b/Doc/c-api/module.rst > @@ -35,13 +35,20 @@ > single: __name__ (module attribute) > single: __doc__ (module attribute) > single: __file__ (module attribute) > + single: __package__ (module attribute) > + single: __loader__ (module attribute) > > Return a new module object with the :attr:`__name__` attribute set to *name*. > - Only the module's :attr:`__doc__` and :attr:`__name__` attributes are filled in; > - the caller is responsible for providing a :attr:`__file__` attribute. > + The module's :attr:`__name__`, :attr:`__doc__`, :attr:`__package__`, and > + :attr:`__loader__` attributes are filled in (all but :attr:`__name__` are set > + to ``None``); the caller is responsible for providing a :attr:`__file__` > + attribute. > > .. versionadded:: 3.3 > > + .. versionchanged:: 3.4 > + :attr:`__package__` and :attr:`__loader__` are set to ``None``. > + > > .. c:function:: PyObject* PyModule_New(const char *name) > > diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst > --- a/Doc/library/importlib.rst > +++ b/Doc/library/importlib.rst > @@ -827,7 +827,7 @@ > decorator as it subsumes this functionality. > > .. versionchanged:: 3.4 > - Set ``__loader__`` if set to ``None`` as well if the attribute does not > + Set ``__loader__`` if set to ``None``, as if the attribute does not > exist. > > > diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst > --- a/Doc/reference/import.rst > +++ b/Doc/reference/import.rst > @@ -423,8 +423,8 @@ > * If the module has a ``__file__`` attribute, this is used as part of the > module's repr. > > - * If the module has no ``__file__`` but does have a ``__loader__``, then the > - loader's repr is used as part of the module's repr. > + * If the module has no ``__file__`` but does have a ``__loader__`` that is not > + ``None``, then the loader's repr is used as part of the module's repr. > > * Otherwise, just use the module's ``__name__`` in the repr. > > 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 > @@ -231,3 +231,8 @@ > :exc:`NotImplementedError` blindly. This will only affect code calling > :func:`super` and falling through all the way to the ABCs. For compatibility, > catch both :exc:`NotImplementedError` or the appropriate exception as needed. > + > +* The module type now initializes the :attr:`__package__` and :attr:`__loader__` > + attributes to ``None`` by default. To determine if these attributes were set > + in a backwards-compatible fashion, use e.g. > + ``getattr(module, '__loader__', None) is not None``. > \ No newline at end of file > diff --git a/Lib/ctypes/test/__init__.py b/Lib/ctypes/test/__init__.py > --- a/Lib/ctypes/test/__init__.py > +++ b/Lib/ctypes/test/__init__.py > @@ -37,7 +37,7 @@ > > def find_package_modules(package, mask): > import fnmatch > - if (hasattr(package, "__loader__") and > + if (package.__loader__ is not None and > hasattr(package.__loader__, '_files')): > path = package.__name__.replace(".", os.path.sep) > mask = os.path.join(path, mask) > diff --git a/Lib/doctest.py b/Lib/doctest.py > --- a/Lib/doctest.py > +++ b/Lib/doctest.py > @@ -215,7 +215,7 @@ > if module_relative: > package = _normalize_module(package, 3) > filename = _module_relative_path(package, filename) > - if hasattr(package, '__loader__'): > + if getattr(package, '__loader__', None) is not None: > if hasattr(package.__loader__, 'get_data'): > file_contents = package.__loader__.get_data(filename) > file_contents = file_contents.decode(encoding) > diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py > --- a/Lib/importlib/_bootstrap.py > +++ b/Lib/importlib/_bootstrap.py > @@ -1726,7 +1726,7 @@ > module_type = type(sys) > for name, module in sys.modules.items(): > if isinstance(module, module_type): > - if not hasattr(module, '__loader__'): > + if getattr(module, '__loader__', None) is None: > if name in sys.builtin_module_names: > module.__loader__ = BuiltinImporter > elif _imp.is_frozen(name): > diff --git a/Lib/inspect.py b/Lib/inspect.py > --- a/Lib/inspect.py > +++ b/Lib/inspect.py > @@ -476,7 +476,7 @@ > if os.path.exists(filename): > return filename > # only return a non-existent filename if the module has a PEP 302 loader > - if hasattr(getmodule(object, filename), '__loader__'): > + if getattr(getmodule(object, filename), '__loader__', None) is not None: > return filename > # or it is in the linecache > if filename in linecache.cache: > diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py > --- a/Lib/test/test_descr.py > +++ b/Lib/test/test_descr.py > @@ -2250,7 +2250,9 @@ > minstance = M("m") > minstance.b = 2 > minstance.a = 1 > - names = [x for x in dir(minstance) if x not in ["__name__", "__doc__"]] > + default_attributes = ['__name__', '__doc__', '__package__', > + '__loader__'] > + names = [x for x in dir(minstance) if x not in default_attributes] > self.assertEqual(names, ['a', 'b']) > > class M2(M): > diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py > --- a/Lib/test/test_importlib/test_api.py > +++ b/Lib/test/test_importlib/test_api.py > @@ -197,14 +197,12 @@ > # Issue #17098: all modules should have __loader__ defined. > for name, module in sys.modules.items(): > if isinstance(module, types.ModuleType): > - if name in sys.builtin_module_names: > - self.assertIn(module.__loader__, > - (importlib.machinery.BuiltinImporter, > - importlib._bootstrap.BuiltinImporter)) > - elif imp.is_frozen(name): > - self.assertIn(module.__loader__, > - (importlib.machinery.FrozenImporter, > - importlib._bootstrap.FrozenImporter)) > + self.assertTrue(hasattr(module, '__loader__'), > + '{!r} lacks a __loader__ attribute'.format(name)) > + if importlib.machinery.BuiltinImporter.find_module(name): > + self.assertIsNot(module.__loader__, None) > + elif importlib.machinery.FrozenImporter.find_module(name): > + self.assertIsNot(module.__loader__, None) > > > if __name__ == '__main__': > diff --git a/Lib/test/test_module.py b/Lib/test/test_module.py > --- a/Lib/test/test_module.py > +++ b/Lib/test/test_module.py > @@ -33,7 +33,10 @@ > foo = ModuleType("foo") > self.assertEqual(foo.__name__, "foo") > self.assertEqual(foo.__doc__, None) > - self.assertEqual(foo.__dict__, {"__name__": "foo", "__doc__": None}) > + self.assertIs(foo.__loader__, None) > + self.assertIs(foo.__package__, None) > + self.assertEqual(foo.__dict__, {"__name__": "foo", "__doc__": None, > + "__loader__": None, "__package__": None}) > > def test_ascii_docstring(self): > # ASCII docstring > @@ -41,7 +44,8 @@ > self.assertEqual(foo.__name__, "foo") > self.assertEqual(foo.__doc__, "foodoc") > self.assertEqual(foo.__dict__, > - {"__name__": "foo", "__doc__": "foodoc"}) > + {"__name__": "foo", "__doc__": "foodoc", > + "__loader__": None, "__package__": None}) > > def test_unicode_docstring(self): > # Unicode docstring > @@ -49,7 +53,8 @@ > self.assertEqual(foo.__name__, "foo") > self.assertEqual(foo.__doc__, "foodoc\u1234") > self.assertEqual(foo.__dict__, > - {"__name__": "foo", "__doc__": "foodoc\u1234"}) > + {"__name__": "foo", "__doc__": "foodoc\u1234", > + "__loader__": None, "__package__": None}) > > def test_reinit(self): > # Reinitialization should not replace the __dict__ > @@ -61,7 +66,8 @@ > self.assertEqual(foo.__doc__, "foodoc") > self.assertEqual(foo.bar, 42) > self.assertEqual(foo.__dict__, > - {"__name__": "foo", "__doc__": "foodoc", "bar": 42}) > + {"__name__": "foo", "__doc__": "foodoc", "bar": 42, > + "__loader__": None, "__package__": None}) > self.assertTrue(foo.__dict__ is d) > > @unittest.expectedFailure > @@ -110,13 +116,19 @@ > m.__file__ = '/tmp/foo.py' > self.assertEqual(repr(m), "") > > + def test_module_repr_with_loader_as_None(self): > + m = ModuleType('foo') > + assert m.__loader__ is None > + self.assertEqual(repr(m), "") > + > def test_module_repr_with_bare_loader_but_no_name(self): > m = ModuleType('foo') > del m.__name__ > # Yes, a class not an instance. > m.__loader__ = BareLoader > + loader_repr = repr(BareLoader) > self.assertEqual( > - repr(m), ")>") > + repr(m), "".format(loader_repr)) > > def test_module_repr_with_full_loader_but_no_name(self): > # m.__loader__.module_repr() will fail because the module has no > @@ -126,15 +138,17 @@ > del m.__name__ > # Yes, a class not an instance. > m.__loader__ = FullLoader > + loader_repr = repr(FullLoader) > self.assertEqual( > - repr(m), ")>") > + repr(m), "".format(loader_repr)) > > def test_module_repr_with_bare_loader(self): > m = ModuleType('foo') > # Yes, a class not an instance. > m.__loader__ = BareLoader > + module_repr = repr(BareLoader) > self.assertEqual( > - repr(m), ")>") > + repr(m), "".format(module_repr)) > > def test_module_repr_with_full_loader(self): > m = ModuleType('foo') > diff --git a/Misc/NEWS b/Misc/NEWS > --- a/Misc/NEWS > +++ b/Misc/NEWS > @@ -10,6 +10,9 @@ > Core and Builtins > ----------------- > > +- Issue #17115,17116: Module initialization now includes setting __package__ and > + __loader__ attributes to None. > + > - Issue #17853: Ensure locals of a class that shadow free variables always win > over the closures. > > diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c > --- a/Objects/moduleobject.c > +++ b/Objects/moduleobject.c > @@ -26,6 +26,27 @@ > }; > > > +static int > +module_init_dict(PyObject *md_dict, PyObject *name, PyObject *doc) > +{ > + if (md_dict == NULL) > + return -1; > + if (doc == NULL) > + doc = Py_None; > + > + if (PyDict_SetItemString(md_dict, "__name__", name) != 0) > + return -1; > + if (PyDict_SetItemString(md_dict, "__doc__", doc) != 0) > + return -1; > + if (PyDict_SetItemString(md_dict, "__package__", Py_None) != 0) > + return -1; > + if (PyDict_SetItemString(md_dict, "__loader__", Py_None) != 0) > + return -1; > + > + return 0; > +} > + > + > PyObject * > PyModule_NewObject(PyObject *name) > { > @@ -36,13 +57,7 @@ > m->md_def = NULL; > m->md_state = NULL; > m->md_dict = PyDict_New(); > - if (m->md_dict == NULL) > - goto fail; > - if (PyDict_SetItemString(m->md_dict, "__name__", name) != 0) > - goto fail; > - if (PyDict_SetItemString(m->md_dict, "__doc__", Py_None) != 0) > - goto fail; > - if (PyDict_SetItemString(m->md_dict, "__package__", Py_None) != 0) > + if (module_init_dict(m->md_dict, name, NULL) != 0) > goto fail; > PyObject_GC_Track(m); > return (PyObject *)m; > @@ -347,9 +362,7 @@ > return -1; > m->md_dict = dict; > } > - if (PyDict_SetItemString(dict, "__name__", name) < 0) > - return -1; > - if (PyDict_SetItemString(dict, "__doc__", doc) < 0) > + if (module_init_dict(dict, name, doc) < 0) > return -1; > return 0; > } > @@ -380,7 +393,7 @@ > if (m->md_dict != NULL) { > loader = PyDict_GetItemString(m->md_dict, "__loader__"); > } > - if (loader != NULL) { > + if (loader != NULL && loader != Py_None) { > repr = PyObject_CallMethod(loader, "module_repr", "(O)", > (PyObject *)m, NULL); > if (repr == NULL) { > @@ -404,10 +417,10 @@ > filename = PyModule_GetFilenameObject((PyObject *)m); > if (filename == NULL) { > PyErr_Clear(); > - /* There's no m.__file__, so if there was an __loader__, use that in > + /* There's no m.__file__, so if there was a __loader__, use that in > * the repr, otherwise, the only thing you can use is m.__name__ > */ > - if (loader == NULL) { > + if (loader == NULL || loader == Py_None) { > repr = PyUnicode_FromFormat("", name); > } > else { > diff --git a/Python/importlib.h b/Python/importlib.h > --- a/Python/importlib.h > +++ b/Python/importlib.h > [stripped] > diff --git a/Python/pythonrun.c b/Python/pythonrun.c > --- a/Python/pythonrun.c > +++ b/Python/pythonrun.c > @@ -866,7 +866,8 @@ > * be set if __main__ gets further initialized later in the startup > * process. > */ > - if (PyDict_GetItemString(d, "__loader__") == NULL) { > + PyObject *loader = PyDict_GetItemString(d, "__loader__"); > + if (loader == NULL || loader == Py_None) { > PyObject *loader = PyObject_GetAttrString(interp->importlib, > "BuiltinImporter"); > if (loader == NULL) { > > -- > Repository URL: http://hg.python.org/cpython > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > From python-checkins at python.org Sat May 4 23:21:21 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 4 May 2013 23:21:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE0MTcz?= =?utf-8?q?=3A_Avoid_crashing_when_reading_a_signal_handler_during_interpr?= =?utf-8?q?eter?= Message-ID: <3b336n5SQDzP7r@mail.python.org> http://hg.python.org/cpython/rev/0201d8fa8bd0 changeset: 83614:0201d8fa8bd0 branch: 2.7 parent: 83611:74e1c50498f8 user: Antoine Pitrou date: Sat May 04 23:16:59 2013 +0200 summary: Issue #14173: Avoid crashing when reading a signal handler during interpreter shutdown. files: Misc/NEWS | 3 +++ Modules/signalmodule.c | 14 +++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,9 @@ Library ------- +- Issue #14173: Avoid crashing when reading a signal handler during + interpreter shutdown. + - Issue #16316: mimetypes now recognizes the .xz and .txz (.tar.xz) extensions. - Issue #17192: Restore the patch for Issue #10309 which was ommitted diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -321,7 +321,10 @@ Handlers[sig_num].tripped = 0; Py_INCREF(obj); Handlers[sig_num].func = obj; - return old_handler; + if (old_handler != NULL) + return old_handler; + else + Py_RETURN_NONE; } PyDoc_STRVAR(signal_doc, @@ -349,8 +352,13 @@ return NULL; } old_handler = Handlers[sig_num].func; - Py_INCREF(old_handler); - return old_handler; + if (old_handler != NULL) { + Py_INCREF(old_handler); + return old_handler; + } + else { + Py_RETURN_NONE; + } } PyDoc_STRVAR(getsignal_doc, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 23:21:23 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 4 May 2013 23:21:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE0MTcz?= =?utf-8?q?=3A_Avoid_crashing_when_reading_a_signal_handler_during_interpr?= =?utf-8?q?eter?= Message-ID: <3b336q0kwfz7Lkm@mail.python.org> http://hg.python.org/cpython/rev/0dfd5c7d953d changeset: 83615:0dfd5c7d953d branch: 3.3 parent: 83612:8c1385205a35 user: Antoine Pitrou date: Sat May 04 23:16:59 2013 +0200 summary: Issue #14173: Avoid crashing when reading a signal handler during interpreter shutdown. files: Misc/NEWS | 3 +++ Modules/signalmodule.c | 14 +++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -47,6 +47,9 @@ Library ------- +- Issue #14173: Avoid crashing when reading a signal handler during + interpreter shutdown. + - Issue #16316: mimetypes now recognizes the .xz and .txz (.tar.xz) extensions. - Issue #15902: Fix imp.load_module() accepting None as a file when loading an diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -344,7 +344,10 @@ Handlers[sig_num].tripped = 0; Py_INCREF(obj); Handlers[sig_num].func = obj; - return old_handler; + if (old_handler != NULL) + return old_handler; + else + Py_RETURN_NONE; } PyDoc_STRVAR(signal_doc, @@ -372,8 +375,13 @@ return NULL; } old_handler = Handlers[sig_num].func; - Py_INCREF(old_handler); - return old_handler; + if (old_handler != NULL) { + Py_INCREF(old_handler); + return old_handler; + } + else { + Py_RETURN_NONE; + } } PyDoc_STRVAR(getsignal_doc, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 23:21:24 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 4 May 2013 23:21:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2314173=3A_Avoid_crashing_when_reading_a_signal_h?= =?utf-8?q?andler_during_interpreter?= Message-ID: <3b336r31t5z7LlG@mail.python.org> http://hg.python.org/cpython/rev/753bcce45854 changeset: 83616:753bcce45854 parent: 83613:0b34fd75b937 parent: 83615:0dfd5c7d953d user: Antoine Pitrou date: Sat May 04 23:21:09 2013 +0200 summary: Issue #14173: Avoid crashing when reading a signal handler during interpreter shutdown. files: Misc/NEWS | 3 +++ Modules/signalmodule.c | 14 +++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -69,6 +69,9 @@ Library ------- +- Issue #14173: Avoid crashing when reading a signal handler during + interpreter shutdown. + - Issue #15902: Fix imp.load_module() accepting None as a file when loading an extension module. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -339,7 +339,10 @@ Handlers[sig_num].tripped = 0; Py_INCREF(obj); Handlers[sig_num].func = obj; - return old_handler; + if (old_handler != NULL) + return old_handler; + else + Py_RETURN_NONE; } PyDoc_STRVAR(signal_doc, @@ -367,8 +370,13 @@ return NULL; } old_handler = Handlers[sig_num].func; - Py_INCREF(old_handler); - return old_handler; + if (old_handler != NULL) { + Py_INCREF(old_handler); + return old_handler; + } + else { + Py_RETURN_NONE; + } } PyDoc_STRVAR(getsignal_doc, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 23:29:44 2013 From: python-checkins at python.org (brett.cannon) Date: Sat, 4 May 2013 23:29:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_=2317115=3A_Remove_what_ap?= =?utf-8?q?pears_to_be_a_useless_chunk_of_code_which_broke?= Message-ID: <3b33JS3WnCz7LjS@mail.python.org> http://hg.python.org/cpython/rev/bb023c3426bc changeset: 83617:bb023c3426bc parent: 83613:0b34fd75b937 user: Brett Cannon date: Sat May 04 17:27:59 2013 -0400 summary: #17115: Remove what appears to be a useless chunk of code which broke other tests. files: Lib/test/test_pydoc.py | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -26,10 +26,6 @@ except ImportError: threading = None -# Just in case sys.modules["test"] has the optional attribute __loader__. -if hasattr(pydoc_mod, "__loader__"): - del pydoc_mod.__loader__ - if test.support.HAVE_DOCSTRINGS: expected_data_docstrings = ( 'dictionary for instance variables (if defined)', -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 23:29:45 2013 From: python-checkins at python.org (brett.cannon) Date: Sat, 4 May 2013 23:29:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3b33JT5l75z7LkP@mail.python.org> http://hg.python.org/cpython/rev/fa0e2f04fcc0 changeset: 83618:fa0e2f04fcc0 parent: 83617:bb023c3426bc parent: 83616:753bcce45854 user: Brett Cannon date: Sat May 04 17:29:36 2013 -0400 summary: merge files: Misc/NEWS | 3 +++ Modules/signalmodule.c | 14 +++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -69,6 +69,9 @@ Library ------- +- Issue #14173: Avoid crashing when reading a signal handler during + interpreter shutdown. + - Issue #15902: Fix imp.load_module() accepting None as a file when loading an extension module. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -339,7 +339,10 @@ Handlers[sig_num].tripped = 0; Py_INCREF(obj); Handlers[sig_num].func = obj; - return old_handler; + if (old_handler != NULL) + return old_handler; + else + Py_RETURN_NONE; } PyDoc_STRVAR(signal_doc, @@ -367,8 +370,13 @@ return NULL; } old_handler = Handlers[sig_num].func; - Py_INCREF(old_handler); - return old_handler; + if (old_handler != NULL) { + Py_INCREF(old_handler); + return old_handler; + } + else { + Py_RETURN_NONE; + } } PyDoc_STRVAR(getsignal_doc, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 23:37:18 2013 From: python-checkins at python.org (brett.cannon) Date: Sat, 4 May 2013 23:37:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_=2317115=3A_I_hate_you_MS_?= =?utf-8?q?for_not_supporting_C99=2E?= Message-ID: <3b33TB0b2vz7LjR@mail.python.org> http://hg.python.org/cpython/rev/97b7bd87c44c changeset: 83619:97b7bd87c44c user: Brett Cannon date: Sat May 04 17:37:09 2013 -0400 summary: #17115: I hate you MS for not supporting C99. files: Python/pythonrun.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -843,7 +843,7 @@ static void initmain(PyInterpreterState *interp) { - PyObject *m, *d; + PyObject *m, *d, *loader; m = PyImport_AddModule("__main__"); if (m == NULL) Py_FatalError("can't create __main__ module"); @@ -864,7 +864,7 @@ * be set if __main__ gets further initialized later in the startup * process. */ - PyObject *loader = PyDict_GetItemString(d, "__loader__"); + loader = PyDict_GetItemString(d, "__loader__"); if (loader == NULL || loader == Py_None) { PyObject *loader = PyObject_GetAttrString(interp->importlib, "BuiltinImporter"); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 4 23:38:50 2013 From: python-checkins at python.org (eli.bendersky) Date: Sat, 4 May 2013 23:38:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_reword_complicated_sentence?= Message-ID: <3b33Vy2WWMz7LjR@mail.python.org> http://hg.python.org/peps/rev/f79a03811517 changeset: 4874:f79a03811517 user: Eli Bendersky date: Sat May 04 14:37:56 2013 -0700 summary: reword complicated sentence files: pep-0435.txt | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pep-0435.txt b/pep-0435.txt --- a/pep-0435.txt +++ b/pep-0435.txt @@ -372,10 +372,10 @@ >>> [i for i in range(Shape.square)] [0, 1] -For the vast majority of code, ``Enum`` is strongly recommended. -Since ``IntEnum`` breaks some semantic promises of an enumeration (by +For the vast majority of code, ``Enum`` is strongly recommended, +since ``IntEnum`` breaks some semantic promises of an enumeration (by being comparable to integers, and thus by transitivity to other -unrelated enumerations), it should be used only in special cases where +unrelated enumerations). It should be used only in special cases where there's no other choice; for example, when integer constants are replaced with enumerations and backwards compatibility is required with code that still expects integers. -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat May 4 23:55:04 2013 From: python-checkins at python.org (brett.cannon) Date: Sat, 4 May 2013 23:55:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Change_a_test_assertion_to?= =?utf-8?q?_a_conditional_so_the_test_will_pass_on?= Message-ID: <3b33sh5mqTzPr9@mail.python.org> http://hg.python.org/cpython/rev/5932f4578354 changeset: 83620:5932f4578354 user: Brett Cannon date: Sat May 04 17:54:57 2013 -0400 summary: Change a test assertion to a conditional so the test will pass on Windows. files: Lib/test/test_imp.py | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -265,10 +265,11 @@ # When loading an extension module and the file is None, open one # on the behalf of imp.load_dynamic(). # Issue #15902 - name = '_heapq' + name = '_testimportmultiple' found = imp.find_module(name) - assert found[2][2] == imp.C_EXTENSION found[0].close() + if found[2][2] != imp.C_EXTENSION: + return imp.load_module(name, None, *found[1:]) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 5 00:11:39 2013 From: python-checkins at python.org (brett.cannon) Date: Sun, 5 May 2013 00:11:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Fix_a_test_to_?= =?utf-8?q?not_use_an_assertion_for_something_that_could_be?= Message-ID: <3b34Dq2zY5zQrN@mail.python.org> http://hg.python.org/cpython/rev/996a937cdf81 changeset: 83621:996a937cdf81 branch: 3.3 parent: 83615:0dfd5c7d953d user: Brett Cannon date: Sat May 04 18:11:12 2013 -0400 summary: Fix a test to not use an assertion for something that could be legitimately false. files: Lib/test/test_imp.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -241,8 +241,9 @@ # Issue #15902 name = '_heapq' found = imp.find_module(name) - assert found[2][2] == imp.C_EXTENSION found[0].close() + if found[2][2] != imp.C_EXTENSION: + return imp.load_module(name, None, *found[1:]) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 5 00:11:40 2013 From: python-checkins at python.org (brett.cannon) Date: Sun, 5 May 2013 00:11:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2Ugdy8gMy4z?= Message-ID: <3b34Dr55S2zQrN@mail.python.org> http://hg.python.org/cpython/rev/bf325cd5cc94 changeset: 83622:bf325cd5cc94 parent: 83620:5932f4578354 parent: 83621:996a937cdf81 user: Brett Cannon date: Sat May 04 18:11:30 2013 -0400 summary: merge w/ 3.3 files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 5 02:46:09 2013 From: python-checkins at python.org (eli.bendersky) Date: Sun, 5 May 2013 02:46:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Fix_typo?= Message-ID: <3b37g573RJz7LjS@mail.python.org> http://hg.python.org/peps/rev/23071c1d4497 changeset: 4875:23071c1d4497 user: Eli Bendersky date: Sat May 04 17:45:15 2013 -0700 summary: Fix typo files: pep-0435.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0435.txt b/pep-0435.txt --- a/pep-0435.txt +++ b/pep-0435.txt @@ -168,7 +168,7 @@ >>> Color(1) >>> Color(3) - + If you want to access enum members by *name*, use item access:: -- Repository URL: http://hg.python.org/peps From solipsis at pitrou.net Sun May 5 06:02:20 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 05 May 2013 06:02:20 +0200 Subject: [Python-checkins] Daily reference leaks (bf325cd5cc94): sum=1 Message-ID: results for bf325cd5cc94 on branch "default" -------------------------------------------- test_multiprocessing leaked [0, -1, 2] memory blocks, sum=1 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogzlUl5l', '-x'] From python-checkins at python.org Sun May 5 08:16:19 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 5 May 2013 08:16:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Fix_crash_caus?= =?utf-8?q?ed_by_8c1385205a35?= Message-ID: <3b3H035xPYzQQB@mail.python.org> http://hg.python.org/cpython/rev/7de9852cdc0e changeset: 83623:7de9852cdc0e branch: 3.3 parent: 83621:996a937cdf81 user: Antoine Pitrou date: Sun May 05 08:12:42 2013 +0200 summary: Fix crash caused by 8c1385205a35 (thanks Arfrever for reporting). files: Python/pythonrun.c | 14 ++++++++------ 1 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -558,6 +558,9 @@ /* Destroy the database used by _PyImport_{Fixup,Find}Extension */ _PyImport_Fini(); + /* Cleanup typeobject.c's internal caches. */ + _PyType_Fini(); + /* unload faulthandler module */ _PyFaulthandler_Fini(); @@ -578,7 +581,7 @@ _Py_PrintReferences(stderr); #endif /* Py_TRACE_REFS */ - /* Clear interpreter state */ + /* Clear interpreter state and all thread states. */ PyInterpreterState_Clear(interp); /* Now we decref the exception classes. After this point nothing @@ -594,10 +597,6 @@ _PyGILState_Fini(); #endif /* WITH_THREAD */ - /* Delete current thread */ - PyThreadState_Swap(NULL); - PyInterpreterState_Delete(interp); - /* Sundry finalizers */ PyMethod_Fini(); PyFrame_Fini(); @@ -611,11 +610,14 @@ PyFloat_Fini(); PyDict_Fini(); PySlice_Fini(); - _PyType_Fini(); /* Cleanup Unicode implementation */ _PyUnicode_Fini(); + /* Delete current thread. After this, many C API calls become crashy. */ + PyThreadState_Swap(NULL); + PyInterpreterState_Delete(interp); + /* reset file system default encoding */ if (!Py_HasFileSystemDefaultEncoding && Py_FileSystemDefaultEncoding) { free((char*)Py_FileSystemDefaultEncoding); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 5 08:16:21 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 5 May 2013 08:16:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Fix_crash_caused_by_8c1385205a35?= Message-ID: <3b3H0517YjzSCd@mail.python.org> http://hg.python.org/cpython/rev/6f4627a65c0a changeset: 83624:6f4627a65c0a parent: 83622:bf325cd5cc94 parent: 83623:7de9852cdc0e user: Antoine Pitrou date: Sun May 05 08:14:53 2013 +0200 summary: Fix crash caused by 8c1385205a35 (thanks Arfrever for reporting). files: Python/pythonrun.c | 14 ++++++++------ 1 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -576,6 +576,9 @@ /* Destroy the database used by _PyImport_{Fixup,Find}Extension */ _PyImport_Fini(); + /* Cleanup typeobject.c's internal caches. */ + _PyType_Fini(); + /* unload faulthandler module */ _PyFaulthandler_Fini(); @@ -596,7 +599,7 @@ _Py_PrintReferences(stderr); #endif /* Py_TRACE_REFS */ - /* Clear interpreter state */ + /* Clear interpreter state and all thread states. */ PyInterpreterState_Clear(interp); /* Now we decref the exception classes. After this point nothing @@ -612,10 +615,6 @@ _PyGILState_Fini(); #endif /* WITH_THREAD */ - /* Delete current thread */ - PyThreadState_Swap(NULL); - PyInterpreterState_Delete(interp); - /* Sundry finalizers */ PyMethod_Fini(); PyFrame_Fini(); @@ -629,11 +628,14 @@ PyFloat_Fini(); PyDict_Fini(); PySlice_Fini(); - _PyType_Fini(); /* Cleanup Unicode implementation */ _PyUnicode_Fini(); + /* Delete current thread. After this, many C API calls become crashy. */ + PyThreadState_Swap(NULL); + PyInterpreterState_Delete(interp); + /* reset file system default encoding */ if (!Py_HasFileSystemDefaultEncoding && Py_FileSystemDefaultEncoding) { free((char*)Py_FileSystemDefaultEncoding); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 5 18:36:33 2013 From: python-checkins at python.org (roger.serwy) Date: Sun, 5 May 2013 18:36:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE3Nzk4OiBBbGxv?= =?utf-8?q?w_IDLE_to_edit_new_files_when_specified_on_command_line=2E?= Message-ID: <3b3Xlj4jqvz7Ljq@mail.python.org> http://hg.python.org/cpython/rev/c8cdc2400643 changeset: 83625:c8cdc2400643 branch: 3.3 parent: 83623:7de9852cdc0e user: Roger Serwy date: Sun May 05 11:34:21 2013 -0500 summary: #17798: Allow IDLE to edit new files when specified on command line. files: Lib/idlelib/EditorWindow.py | 2 ++ Misc/NEWS | 2 ++ 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -321,6 +321,8 @@ per.insertfilter(color) else: io.set_filename(filename) + self.good_load = True + self.ResetColorizer() self.saved_change_hook() self.update_recent_files_list() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -135,6 +135,8 @@ IDLE ---- +- Issue #17798: Allow IDLE to edit new files when specified on command line. + - Issue #14735: Update IDLE docs to omit "Control-z on Windows". - Issue #17585: Fixed IDLE regression. Now closes when using exit() or quit(). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 5 18:36:34 2013 From: python-checkins at python.org (roger.serwy) Date: Sun, 5 May 2013 18:36:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzE3Nzk4OiBtZXJnZSB3aXRoIDMuMy4=?= Message-ID: <3b3Xlk72RYz7Lkp@mail.python.org> http://hg.python.org/cpython/rev/a64a3da996ed changeset: 83626:a64a3da996ed parent: 83624:6f4627a65c0a parent: 83625:c8cdc2400643 user: Roger Serwy date: Sun May 05 11:35:15 2013 -0500 summary: #17798: merge with 3.3. files: Lib/idlelib/EditorWindow.py | 2 ++ Misc/NEWS | 2 ++ 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -321,6 +321,8 @@ per.insertfilter(color) else: io.set_filename(filename) + self.good_load = True + self.ResetColorizer() self.saved_change_hook() self.update_recent_files_list() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -249,6 +249,8 @@ IDLE ---- +- Issue #17798: Allow IDLE to edit new files when specified on command line. + - Issue #14735: Update IDLE docs to omit "Control-z on Windows". -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 5 21:36:19 2013 From: python-checkins at python.org (ezio.melotti) Date: Sun, 5 May 2013 21:36:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE3ODgzOiBGaXgg?= =?utf-8?q?buildbot_testing_of_Tkinter_on_Windows=2E__Patch_by_Zachary_War?= =?utf-8?q?e=2E?= Message-ID: <3b3cl73q8Gz7Lkr@mail.python.org> http://hg.python.org/cpython/rev/3c58fa7dc7f1 changeset: 83627:3c58fa7dc7f1 branch: 2.7 parent: 83614:0201d8fa8bd0 user: Ezio Melotti date: Sun May 05 22:36:09 2013 +0300 summary: #17883: Fix buildbot testing of Tkinter on Windows. Patch by Zachary Ware. files: Misc/NEWS | 3 +++ PCbuild/rt.bat | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -84,6 +84,9 @@ Tests ----- +- Issue #17883: Fix buildbot testing of Tkinter on Windows. + Patch by Zachary Ware. + - Issue #7855: Add tests for ctypes/winreg for issues found in IronPython. Initial patch by Dino Viehland. diff --git a/PCbuild/rt.bat b/PCbuild/rt.bat --- a/PCbuild/rt.bat +++ b/PCbuild/rt.bat @@ -30,7 +30,7 @@ set suffix= set qmode= set dashO= -set tcltk= +set tcltk=tcltk :CheckOpts if "%1"=="-O" (set dashO=-O) & shift & goto CheckOpts @@ -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%;..\..\%tcltk%\bin +PATH %PATH%;%~dp0..\..\%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 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 5 23:03:02 2013 From: python-checkins at python.org (richard.oudkerk) Date: Sun, 5 May 2013 23:03:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315528=3A_Add_weak?= =?utf-8?q?ref=2Efinalize_to_support_finalization_using?= Message-ID: <3b3fgB0Xk8z7Ljy@mail.python.org> http://hg.python.org/cpython/rev/2e446e87ac5b changeset: 83628:2e446e87ac5b parent: 83626:a64a3da996ed user: Richard Oudkerk date: Sun May 05 20:59:04 2013 +0100 summary: Issue #15528: Add weakref.finalize to support finalization using weakref callbacks. files: Doc/library/weakref.rst | 215 ++++++++++++++++++++++++++- Lib/test/test_weakref.py | 152 ++++++++++++++++++- Lib/weakref.py | 137 +++++++++++++++++- Misc/NEWS | 3 + 4 files changed, 500 insertions(+), 7 deletions(-) diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -51,10 +51,15 @@ but keeps weak references to its elements, just like a :class:`WeakKeyDictionary` does. -Most programs should find that using one of these weak container types is all -they need -- it's not usually necessary to create your own weak references -directly. The low-level machinery used by the weak dictionary implementations -is exposed by the :mod:`weakref` module for the benefit of advanced uses. +:class:`finalize` provides a straight forward way to register a +cleanup function to be called when an object is garbage collected. +This is simpler to use than setting up a callback function on a raw +weak reference. + +Most programs should find that using one of these weak container types +or :class:`finalize` is all they need -- it's not usually necessary to +create your own weak references directly. The low-level machinery is +exposed by the :mod:`weakref` module for the benefit of advanced uses. Not all objects can be weakly referenced; those objects which can include class instances, functions written in Python (but not in C), instance methods, sets, @@ -117,7 +122,16 @@ weakref. If there is no callback or if the referent of the weakref is no longer alive then this attribute will have value ``None``. - .. versionadded:: 3.4 + .. note:: + + Like :meth:`__del__` methods, weak reference callbacks can be + called during interpreter shutdown when module globals have been + overwritten with :const:`None`. This can make writing robust + weak reference callbacks a challenge. Callbacks registered + using :class:`finalize` do not have to worry about this issue + because they will not be run after module teardown has begun. + + .. versionchanged:: 3.4 Added the :attr:`__callback__` attribute. @@ -229,6 +243,66 @@ .. versionadded:: 3.4 +.. class:: finalize(obj, func, *args, **kwargs) + + Return a callable finalizer object which will be called when *obj* + is garbage collected. A finalizer is *alive* until it is called + (either explicitly or at garbage collection), and after that it is + *dead*. Calling a live finalizer returns the result of evaluating + ``func(*arg, **kwargs)``, whereas calling a dead finalizer returns + :const:`None`. + + Exceptions raised by finalizer callbacks during garbage collection + will be shown on the standard error output, but cannot be + propagated. They are handled in the same way as exceptions raised + from an object's :meth:`__del__` method or a weak reference's + callback. + + When the program exits, each remaining live finalizer is called + unless its :attr:`atexit` attribute has been set to false. They + are called in reverse order of creation. + + A finalizer will never invoke its callback during the later part of + the interpreter shutdown when module globals are liable to have + been replaced by :const:`None`. + + .. method:: __call__() + + If *self* is alive then mark it as dead and return the result of + calling ``func(*args, **kwargs)``. If *self* is dead then return + :const:`None`. + + .. method:: detach() + + If *self* is alive then mark it as dead and return the tuple + ``(obj, func, args, kwargs)``. If *self* is dead then return + :const:`None`. + + .. method:: peek() + + If *self* is alive then return the tuple ``(obj, func, args, + kwargs)``. If *self* is dead then return :const:`None`. + + .. attribute:: alive + + Property which is true if the finalizer is alive, false otherwise. + + .. attribute:: atexit + + A writable boolean property which by default is true. When the + program exits, it calls all remaining live finalizers for which + :attr:`.atexit` is true. They are called in reverse order of + creation. + + .. note:: + + It is important to ensure that *func*, *args* and *kwargs* do + not own any references to *obj*, either directly or indirectly, + since otherwise *obj* will never be garbage collected. In + particular, *func* should not be a bound method of *obj*. + + .. versionadded:: 3.4 + .. data:: ReferenceType @@ -365,3 +439,134 @@ def id2obj(oid): return _id2obj_dict[oid] + +.. _finalize-examples: + +Finalizer Objects +----------------- + +Often one uses :class:`finalize` to register a callback without +bothering to keep the returned finalizer object. For instance + + >>> import weakref + >>> class Object: + ... pass + ... + >>> kenny = Object() + >>> weakref.finalize(kenny, print, "You killed Kenny!") #doctest:+ELLIPSIS + + >>> del kenny + You killed Kenny! + +The finalizer can be called directly as well. However the finalizer +will invoke the callback at most once. + + >>> def callback(x, y, z): + ... print("CALLBACK") + ... return x + y + z + ... + >>> obj = Object() + >>> f = weakref.finalize(obj, callback, 1, 2, z=3) + >>> assert f.alive + >>> assert f() == 6 + CALLBACK + >>> assert not f.alive + >>> f() # callback not called because finalizer dead + >>> del obj # callback not called because finalizer dead + +You can unregister a finalizer using its :meth:`~finalize.detach` +method. This kills the finalizer and returns the arguments passed to +the constructor when it was created. + + >>> obj = Object() + >>> f = weakref.finalize(obj, callback, 1, 2, z=3) + >>> f.detach() #doctest:+ELLIPSIS + (<__main__.Object object ...>, , (1, 2), {'z': 3}) + >>> newobj, func, args, kwargs = _ + >>> assert not f.alive + >>> assert newobj is obj + >>> assert func(*args, **kwargs) == 6 + CALLBACK + +Unless you set the :attr:`~finalize.atexit` attribute to +:const:`False`, a finalizer will be called when the program exit if it +is still alive. For instance + + >>> obj = Object() + >>> weakref.finalize(obj, print, "obj dead or exiting") #doctest:+ELLIPSIS + + >>> exit() #doctest:+SKIP + obj dead or exiting + + +Comparing finalizers with :meth:`__del__` methods +------------------------------------------------- + +Suppose we want to create a class whose instances represent temporary +directories. The directories should be deleted with their contents +when the first of the following events occurs: + +* the object is garbage collected, +* the object's :meth:`remove` method is called, or +* the program exits. + +We might try to implement the class using a :meth:`__del__` method as +follows:: + + class TempDir: + def __init__(self): + self.name = tempfile.mkdtemp() + + def remove(self): + if self.name is not None: + shutil.rmtree(self.name) + self.name = None + + @property + def removed(self): + return self.name is None + + def __del__(self): + self.remove() + +This solution has a couple of serious problems: + +* There is no guarantee that the object will be garbage collected + before the program exists, so the directory might be left. This is + because reference cycles containing an object with a :meth:`__del__` + method can never be collected. And even if the :class:`TempDir` + object is not itself part of a reference cycle, it may still be kept + alive by some unkown uncollectable reference cycle. + +* The :meth:`__del__` method may be called at shutdown after the + :mod:`shutil` module has been cleaned up, in which case + :attr:`shutil.rmtree` will have been replaced by :const:`None`. + This will cause the :meth:`__del__` method to fail and the directory + will not be removed. + +Using finalizers we can avoid these problems:: + + class TempDir: + def __init__(self): + self.name = tempfile.mkdtemp() + self._finalizer = weakref.finalize(self, shutil.rmtree, self.name) + + def remove(self): + self._finalizer() + + @property + def removed(self): + return not self._finalizer.alive + +Defined like this, even if a :class:`TempDir` object is part of a +reference cycle, that reference cycle can still be garbage collected. +If the object never gets garbage collected the finalizer will still be +called at exit. + +.. note:: + + If you create a finalizer object in a daemonic thread just as the + the program exits then there is the possibility that the finalizer + does not get called at exit. However, in a daemonic thread + :func:`atexit.register`, ``try: ... finally: ...`` and ``with: ...`` + do not guarantee that cleanup occurs either. diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -7,11 +7,15 @@ import contextlib import copy -from test import support +from test import support, script_helper # Used in ReferencesTestCase.test_ref_created_during_del() . ref_from_del = None +# Used by FinalizeTestCase as a global that may be replaced by None +# when the interpreter shuts down. +_global_var = 'foobar' + class C: def method(self): pass @@ -1551,6 +1555,151 @@ def _reference(self): return self.__ref.copy() + +class FinalizeTestCase(unittest.TestCase): + + class A: + pass + + def _collect_if_necessary(self): + # we create no ref-cycles so in CPython no gc should be needed + if sys.implementation.name != 'cpython': + support.gc_collect() + + def test_finalize(self): + def add(x,y,z): + res.append(x + y + z) + return x + y + z + + a = self.A() + + res = [] + f = weakref.finalize(a, add, 67, 43, z=89) + self.assertEqual(f.alive, True) + self.assertEqual(f.peek(), (a, add, (67,43), {'z':89})) + self.assertEqual(f(), 199) + self.assertEqual(f(), None) + self.assertEqual(f(), None) + self.assertEqual(f.peek(), None) + self.assertEqual(f.detach(), None) + self.assertEqual(f.alive, False) + self.assertEqual(res, [199]) + + res = [] + f = weakref.finalize(a, add, 67, 43, 89) + self.assertEqual(f.peek(), (a, add, (67,43,89), {})) + self.assertEqual(f.detach(), (a, add, (67,43,89), {})) + self.assertEqual(f(), None) + self.assertEqual(f(), None) + self.assertEqual(f.peek(), None) + self.assertEqual(f.detach(), None) + self.assertEqual(f.alive, False) + self.assertEqual(res, []) + + res = [] + f = weakref.finalize(a, add, x=67, y=43, z=89) + del a + self._collect_if_necessary() + self.assertEqual(f(), None) + self.assertEqual(f(), None) + self.assertEqual(f.peek(), None) + self.assertEqual(f.detach(), None) + self.assertEqual(f.alive, False) + self.assertEqual(res, [199]) + + def test_order(self): + a = self.A() + res = [] + + f1 = weakref.finalize(a, res.append, 'f1') + f2 = weakref.finalize(a, res.append, 'f2') + f3 = weakref.finalize(a, res.append, 'f3') + f4 = weakref.finalize(a, res.append, 'f4') + f5 = weakref.finalize(a, res.append, 'f5') + + # make sure finalizers can keep themselves alive + del f1, f4 + + self.assertTrue(f2.alive) + self.assertTrue(f3.alive) + self.assertTrue(f5.alive) + + self.assertTrue(f5.detach()) + self.assertFalse(f5.alive) + + f5() # nothing because previously unregistered + res.append('A') + f3() # => res.append('f3') + self.assertFalse(f3.alive) + res.append('B') + f3() # nothing because previously called + res.append('C') + del a + self._collect_if_necessary() + # => res.append('f4') + # => res.append('f2') + # => res.append('f1') + self.assertFalse(f2.alive) + res.append('D') + f2() # nothing because previously called by gc + + expected = ['A', 'f3', 'B', 'C', 'f4', 'f2', 'f1', 'D'] + self.assertEqual(res, expected) + + def test_all_freed(self): + # we want a weakrefable subclass of weakref.finalize + class MyFinalizer(weakref.finalize): + pass + + a = self.A() + res = [] + def callback(): + res.append(123) + f = MyFinalizer(a, callback) + + wr_callback = weakref.ref(callback) + wr_f = weakref.ref(f) + del callback, f + + self.assertIsNotNone(wr_callback()) + self.assertIsNotNone(wr_f()) + + del a + self._collect_if_necessary() + + self.assertIsNone(wr_callback()) + self.assertIsNone(wr_f()) + self.assertEqual(res, [123]) + + @classmethod + def run_in_child(cls): + def error(): + # Create an atexit finalizer from inside a finalizer called + # at exit. This should be the next to be run. + g1 = weakref.finalize(cls, print, 'g1') + print('f3 error') + 1/0 + + # cls should stay alive till atexit callbacks run + f1 = weakref.finalize(cls, print, 'f1', _global_var) + f2 = weakref.finalize(cls, print, 'f2', _global_var) + f3 = weakref.finalize(cls, error) + f4 = weakref.finalize(cls, print, 'f4', _global_var) + + assert f1.atexit == True + f2.atexit = False + assert f3.atexit == True + assert f4.atexit == True + + def test_atexit(self): + prog = ('from test.test_weakref import FinalizeTestCase;'+ + 'FinalizeTestCase.run_in_child()') + rc, out, err = script_helper.assert_python_ok('-c', prog) + out = out.decode('ascii').splitlines() + self.assertEqual(out, ['f4 foobar', 'f3 error', 'g1', 'f1 foobar']) + self.assertTrue(b'ZeroDivisionError' in err) + + libreftest = """ Doctest for examples in the library reference: weakref.rst >>> import weakref @@ -1644,6 +1793,7 @@ WeakValueDictionaryTestCase, WeakKeyDictionaryTestCase, SubclassableWeakrefTestCase, + FinalizeTestCase, ) support.run_doctest(sys.modules[__name__]) diff --git a/Lib/weakref.py b/Lib/weakref.py --- a/Lib/weakref.py +++ b/Lib/weakref.py @@ -21,13 +21,16 @@ from _weakrefset import WeakSet, _IterationGuard import collections # Import after _weakref to avoid circular import. +import sys +import atexit +import itertools ProxyTypes = (ProxyType, CallableProxyType) __all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs", "WeakKeyDictionary", "ReferenceType", "ProxyType", "CallableProxyType", "ProxyTypes", "WeakValueDictionary", - "WeakSet", "WeakMethod"] + "WeakSet", "WeakMethod", "finalize"] class WeakMethod(ref): @@ -436,3 +439,135 @@ d[ref(key, self._remove)] = value if len(kwargs): self.update(kwargs) + + +class finalize: + """Class for finalization of weakrefable objects + + finalize(obj, func, *args, **kwargs) returns a callable finalizer + object which will be called when obj is garbage collected. The + first time the finalizer is called it evaluates func(*arg, **kwargs) + and returns the result. After this the finalizer is dead, and + calling it just returns None. + + When the program exits any remaining finalizers for which the + atexit attribute is true will be run in reverse order of creation. + By default atexit is true. + """ + + # Finalizer objects don't have any state of their own. They are + # just used as keys to lookup _Info objects in the registry. This + # ensures that they cannot be part of a ref-cycle. + + __slots__ = () + _registry = {} + _shutdown = False + _index_iter = itertools.count() + _dirty = False + + class _Info: + __slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index") + + def __init__(self, obj, func, *args, **kwargs): + info = self._Info() + info.weakref = ref(obj, self) + info.func = func + info.args = args + info.kwargs = kwargs or None + info.atexit = True + info.index = next(self._index_iter) + self._registry[self] = info + finalize._dirty = True + + def __call__(self, _=None): + """If alive then mark as dead and return func(*args, **kwargs); + otherwise return None""" + info = self._registry.pop(self, None) + if info and not self._shutdown: + return info.func(*info.args, **(info.kwargs or {})) + + def detach(self): + """If alive then mark as dead and return (obj, func, args, kwargs); + otherwise return None""" + info = self._registry.get(self) + obj = info and info.weakref() + if obj is not None and self._registry.pop(self, None): + return (obj, info.func, info.args, info.kwargs or {}) + + def peek(self): + """If alive then return (obj, func, args, kwargs); + otherwise return None""" + info = self._registry.get(self) + obj = info and info.weakref() + if obj is not None: + return (obj, info.func, info.args, info.kwargs or {}) + + @property + def alive(self): + """Whether finalizer is alive""" + return self in self._registry + + @property + def atexit(self): + """Whether finalizer should be called at exit""" + info = self._registry.get(self) + return bool(info) and info.atexit + + @atexit.setter + def atexit(self, value): + info = self._registry.get(self) + if info: + info.atexit = bool(value) + + def __repr__(self): + info = self._registry.get(self) + obj = info and info.weakref() + if obj is None: + return '<%s object at %#x; dead>' % (type(self).__name__, id(self)) + else: + return '<%s object at %#x; for %r at %#x>' % \ + (type(self).__name__, id(self), type(obj).__name__, id(obj)) + + @classmethod + def _select_for_exit(cls): + # Return live finalizers marked for exit, oldest first + L = [(f,i) for (f,i) in cls._registry.items() if i.atexit] + L.sort(key=lambda item:item[1].index) + return [f for (f,i) in L] + + @classmethod + def _exitfunc(cls): + # At shutdown invoke finalizers for which atexit is true. + # This is called once all other non-daemonic threads have been + # joined. + reenable_gc = False + try: + if cls._registry: + import gc + if gc.isenabled(): + reenable_gc = True + gc.disable() + pending = None + while True: + if pending is None or finalize._dirty: + pending = cls._select_for_exit() + finalize._dirty = False + if not pending: + break + f = pending.pop() + try: + # gc is disabled, so (assuming no daemonic + # threads) the following is the only line in + # this function which might trigger creation + # of a new finalizer + f() + except Exception: + sys.excepthook(*sys.exc_info()) + assert f not in cls._registry + finally: + # prevent any more finalizers from executing during shutdown + finalize._shutdown = True + if reenable_gc: + gc.enable() + +atexit.register(finalize._exitfunc) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -69,6 +69,9 @@ Library ------- +- Issue #15528: Add weakref.finalize to support finalization using + weakref callbacks. + - Issue #14173: Avoid crashing when reading a signal handler during interpreter shutdown. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 5 23:14:41 2013 From: python-checkins at python.org (richard.oudkerk) Date: Sun, 5 May 2013 23:14:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Backout_2e446e87ac5b=3B_it?= =?utf-8?q?_breaks_the_unix_buildbots=2E?= Message-ID: <3b3fwd6Cnbz7Lk4@mail.python.org> http://hg.python.org/cpython/rev/dad96fd5c8a4 changeset: 83629:dad96fd5c8a4 user: Richard Oudkerk date: Sun May 05 22:12:34 2013 +0100 summary: Backout 2e446e87ac5b; it breaks the unix buildbots. files: Doc/library/weakref.rst | 215 +-------------------------- Lib/test/test_weakref.py | 152 +------------------ Lib/weakref.py | 137 +----------------- Misc/NEWS | 3 - 4 files changed, 7 insertions(+), 500 deletions(-) diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -51,15 +51,10 @@ but keeps weak references to its elements, just like a :class:`WeakKeyDictionary` does. -:class:`finalize` provides a straight forward way to register a -cleanup function to be called when an object is garbage collected. -This is simpler to use than setting up a callback function on a raw -weak reference. - -Most programs should find that using one of these weak container types -or :class:`finalize` is all they need -- it's not usually necessary to -create your own weak references directly. The low-level machinery is -exposed by the :mod:`weakref` module for the benefit of advanced uses. +Most programs should find that using one of these weak container types is all +they need -- it's not usually necessary to create your own weak references +directly. The low-level machinery used by the weak dictionary implementations +is exposed by the :mod:`weakref` module for the benefit of advanced uses. Not all objects can be weakly referenced; those objects which can include class instances, functions written in Python (but not in C), instance methods, sets, @@ -122,16 +117,7 @@ weakref. If there is no callback or if the referent of the weakref is no longer alive then this attribute will have value ``None``. - .. note:: - - Like :meth:`__del__` methods, weak reference callbacks can be - called during interpreter shutdown when module globals have been - overwritten with :const:`None`. This can make writing robust - weak reference callbacks a challenge. Callbacks registered - using :class:`finalize` do not have to worry about this issue - because they will not be run after module teardown has begun. - - .. versionchanged:: 3.4 + .. versionadded:: 3.4 Added the :attr:`__callback__` attribute. @@ -243,66 +229,6 @@ .. versionadded:: 3.4 -.. class:: finalize(obj, func, *args, **kwargs) - - Return a callable finalizer object which will be called when *obj* - is garbage collected. A finalizer is *alive* until it is called - (either explicitly or at garbage collection), and after that it is - *dead*. Calling a live finalizer returns the result of evaluating - ``func(*arg, **kwargs)``, whereas calling a dead finalizer returns - :const:`None`. - - Exceptions raised by finalizer callbacks during garbage collection - will be shown on the standard error output, but cannot be - propagated. They are handled in the same way as exceptions raised - from an object's :meth:`__del__` method or a weak reference's - callback. - - When the program exits, each remaining live finalizer is called - unless its :attr:`atexit` attribute has been set to false. They - are called in reverse order of creation. - - A finalizer will never invoke its callback during the later part of - the interpreter shutdown when module globals are liable to have - been replaced by :const:`None`. - - .. method:: __call__() - - If *self* is alive then mark it as dead and return the result of - calling ``func(*args, **kwargs)``. If *self* is dead then return - :const:`None`. - - .. method:: detach() - - If *self* is alive then mark it as dead and return the tuple - ``(obj, func, args, kwargs)``. If *self* is dead then return - :const:`None`. - - .. method:: peek() - - If *self* is alive then return the tuple ``(obj, func, args, - kwargs)``. If *self* is dead then return :const:`None`. - - .. attribute:: alive - - Property which is true if the finalizer is alive, false otherwise. - - .. attribute:: atexit - - A writable boolean property which by default is true. When the - program exits, it calls all remaining live finalizers for which - :attr:`.atexit` is true. They are called in reverse order of - creation. - - .. note:: - - It is important to ensure that *func*, *args* and *kwargs* do - not own any references to *obj*, either directly or indirectly, - since otherwise *obj* will never be garbage collected. In - particular, *func* should not be a bound method of *obj*. - - .. versionadded:: 3.4 - .. data:: ReferenceType @@ -439,134 +365,3 @@ def id2obj(oid): return _id2obj_dict[oid] - -.. _finalize-examples: - -Finalizer Objects ------------------ - -Often one uses :class:`finalize` to register a callback without -bothering to keep the returned finalizer object. For instance - - >>> import weakref - >>> class Object: - ... pass - ... - >>> kenny = Object() - >>> weakref.finalize(kenny, print, "You killed Kenny!") #doctest:+ELLIPSIS - - >>> del kenny - You killed Kenny! - -The finalizer can be called directly as well. However the finalizer -will invoke the callback at most once. - - >>> def callback(x, y, z): - ... print("CALLBACK") - ... return x + y + z - ... - >>> obj = Object() - >>> f = weakref.finalize(obj, callback, 1, 2, z=3) - >>> assert f.alive - >>> assert f() == 6 - CALLBACK - >>> assert not f.alive - >>> f() # callback not called because finalizer dead - >>> del obj # callback not called because finalizer dead - -You can unregister a finalizer using its :meth:`~finalize.detach` -method. This kills the finalizer and returns the arguments passed to -the constructor when it was created. - - >>> obj = Object() - >>> f = weakref.finalize(obj, callback, 1, 2, z=3) - >>> f.detach() #doctest:+ELLIPSIS - (<__main__.Object object ...>, , (1, 2), {'z': 3}) - >>> newobj, func, args, kwargs = _ - >>> assert not f.alive - >>> assert newobj is obj - >>> assert func(*args, **kwargs) == 6 - CALLBACK - -Unless you set the :attr:`~finalize.atexit` attribute to -:const:`False`, a finalizer will be called when the program exit if it -is still alive. For instance - - >>> obj = Object() - >>> weakref.finalize(obj, print, "obj dead or exiting") #doctest:+ELLIPSIS - - >>> exit() #doctest:+SKIP - obj dead or exiting - - -Comparing finalizers with :meth:`__del__` methods -------------------------------------------------- - -Suppose we want to create a class whose instances represent temporary -directories. The directories should be deleted with their contents -when the first of the following events occurs: - -* the object is garbage collected, -* the object's :meth:`remove` method is called, or -* the program exits. - -We might try to implement the class using a :meth:`__del__` method as -follows:: - - class TempDir: - def __init__(self): - self.name = tempfile.mkdtemp() - - def remove(self): - if self.name is not None: - shutil.rmtree(self.name) - self.name = None - - @property - def removed(self): - return self.name is None - - def __del__(self): - self.remove() - -This solution has a couple of serious problems: - -* There is no guarantee that the object will be garbage collected - before the program exists, so the directory might be left. This is - because reference cycles containing an object with a :meth:`__del__` - method can never be collected. And even if the :class:`TempDir` - object is not itself part of a reference cycle, it may still be kept - alive by some unkown uncollectable reference cycle. - -* The :meth:`__del__` method may be called at shutdown after the - :mod:`shutil` module has been cleaned up, in which case - :attr:`shutil.rmtree` will have been replaced by :const:`None`. - This will cause the :meth:`__del__` method to fail and the directory - will not be removed. - -Using finalizers we can avoid these problems:: - - class TempDir: - def __init__(self): - self.name = tempfile.mkdtemp() - self._finalizer = weakref.finalize(self, shutil.rmtree, self.name) - - def remove(self): - self._finalizer() - - @property - def removed(self): - return not self._finalizer.alive - -Defined like this, even if a :class:`TempDir` object is part of a -reference cycle, that reference cycle can still be garbage collected. -If the object never gets garbage collected the finalizer will still be -called at exit. - -.. note:: - - If you create a finalizer object in a daemonic thread just as the - the program exits then there is the possibility that the finalizer - does not get called at exit. However, in a daemonic thread - :func:`atexit.register`, ``try: ... finally: ...`` and ``with: ...`` - do not guarantee that cleanup occurs either. diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -7,15 +7,11 @@ import contextlib import copy -from test import support, script_helper +from test import support # Used in ReferencesTestCase.test_ref_created_during_del() . ref_from_del = None -# Used by FinalizeTestCase as a global that may be replaced by None -# when the interpreter shuts down. -_global_var = 'foobar' - class C: def method(self): pass @@ -1555,151 +1551,6 @@ def _reference(self): return self.__ref.copy() - -class FinalizeTestCase(unittest.TestCase): - - class A: - pass - - def _collect_if_necessary(self): - # we create no ref-cycles so in CPython no gc should be needed - if sys.implementation.name != 'cpython': - support.gc_collect() - - def test_finalize(self): - def add(x,y,z): - res.append(x + y + z) - return x + y + z - - a = self.A() - - res = [] - f = weakref.finalize(a, add, 67, 43, z=89) - self.assertEqual(f.alive, True) - self.assertEqual(f.peek(), (a, add, (67,43), {'z':89})) - self.assertEqual(f(), 199) - self.assertEqual(f(), None) - self.assertEqual(f(), None) - self.assertEqual(f.peek(), None) - self.assertEqual(f.detach(), None) - self.assertEqual(f.alive, False) - self.assertEqual(res, [199]) - - res = [] - f = weakref.finalize(a, add, 67, 43, 89) - self.assertEqual(f.peek(), (a, add, (67,43,89), {})) - self.assertEqual(f.detach(), (a, add, (67,43,89), {})) - self.assertEqual(f(), None) - self.assertEqual(f(), None) - self.assertEqual(f.peek(), None) - self.assertEqual(f.detach(), None) - self.assertEqual(f.alive, False) - self.assertEqual(res, []) - - res = [] - f = weakref.finalize(a, add, x=67, y=43, z=89) - del a - self._collect_if_necessary() - self.assertEqual(f(), None) - self.assertEqual(f(), None) - self.assertEqual(f.peek(), None) - self.assertEqual(f.detach(), None) - self.assertEqual(f.alive, False) - self.assertEqual(res, [199]) - - def test_order(self): - a = self.A() - res = [] - - f1 = weakref.finalize(a, res.append, 'f1') - f2 = weakref.finalize(a, res.append, 'f2') - f3 = weakref.finalize(a, res.append, 'f3') - f4 = weakref.finalize(a, res.append, 'f4') - f5 = weakref.finalize(a, res.append, 'f5') - - # make sure finalizers can keep themselves alive - del f1, f4 - - self.assertTrue(f2.alive) - self.assertTrue(f3.alive) - self.assertTrue(f5.alive) - - self.assertTrue(f5.detach()) - self.assertFalse(f5.alive) - - f5() # nothing because previously unregistered - res.append('A') - f3() # => res.append('f3') - self.assertFalse(f3.alive) - res.append('B') - f3() # nothing because previously called - res.append('C') - del a - self._collect_if_necessary() - # => res.append('f4') - # => res.append('f2') - # => res.append('f1') - self.assertFalse(f2.alive) - res.append('D') - f2() # nothing because previously called by gc - - expected = ['A', 'f3', 'B', 'C', 'f4', 'f2', 'f1', 'D'] - self.assertEqual(res, expected) - - def test_all_freed(self): - # we want a weakrefable subclass of weakref.finalize - class MyFinalizer(weakref.finalize): - pass - - a = self.A() - res = [] - def callback(): - res.append(123) - f = MyFinalizer(a, callback) - - wr_callback = weakref.ref(callback) - wr_f = weakref.ref(f) - del callback, f - - self.assertIsNotNone(wr_callback()) - self.assertIsNotNone(wr_f()) - - del a - self._collect_if_necessary() - - self.assertIsNone(wr_callback()) - self.assertIsNone(wr_f()) - self.assertEqual(res, [123]) - - @classmethod - def run_in_child(cls): - def error(): - # Create an atexit finalizer from inside a finalizer called - # at exit. This should be the next to be run. - g1 = weakref.finalize(cls, print, 'g1') - print('f3 error') - 1/0 - - # cls should stay alive till atexit callbacks run - f1 = weakref.finalize(cls, print, 'f1', _global_var) - f2 = weakref.finalize(cls, print, 'f2', _global_var) - f3 = weakref.finalize(cls, error) - f4 = weakref.finalize(cls, print, 'f4', _global_var) - - assert f1.atexit == True - f2.atexit = False - assert f3.atexit == True - assert f4.atexit == True - - def test_atexit(self): - prog = ('from test.test_weakref import FinalizeTestCase;'+ - 'FinalizeTestCase.run_in_child()') - rc, out, err = script_helper.assert_python_ok('-c', prog) - out = out.decode('ascii').splitlines() - self.assertEqual(out, ['f4 foobar', 'f3 error', 'g1', 'f1 foobar']) - self.assertTrue(b'ZeroDivisionError' in err) - - libreftest = """ Doctest for examples in the library reference: weakref.rst >>> import weakref @@ -1793,7 +1644,6 @@ WeakValueDictionaryTestCase, WeakKeyDictionaryTestCase, SubclassableWeakrefTestCase, - FinalizeTestCase, ) support.run_doctest(sys.modules[__name__]) diff --git a/Lib/weakref.py b/Lib/weakref.py --- a/Lib/weakref.py +++ b/Lib/weakref.py @@ -21,16 +21,13 @@ from _weakrefset import WeakSet, _IterationGuard import collections # Import after _weakref to avoid circular import. -import sys -import atexit -import itertools ProxyTypes = (ProxyType, CallableProxyType) __all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs", "WeakKeyDictionary", "ReferenceType", "ProxyType", "CallableProxyType", "ProxyTypes", "WeakValueDictionary", - "WeakSet", "WeakMethod", "finalize"] + "WeakSet", "WeakMethod"] class WeakMethod(ref): @@ -439,135 +436,3 @@ d[ref(key, self._remove)] = value if len(kwargs): self.update(kwargs) - - -class finalize: - """Class for finalization of weakrefable objects - - finalize(obj, func, *args, **kwargs) returns a callable finalizer - object which will be called when obj is garbage collected. The - first time the finalizer is called it evaluates func(*arg, **kwargs) - and returns the result. After this the finalizer is dead, and - calling it just returns None. - - When the program exits any remaining finalizers for which the - atexit attribute is true will be run in reverse order of creation. - By default atexit is true. - """ - - # Finalizer objects don't have any state of their own. They are - # just used as keys to lookup _Info objects in the registry. This - # ensures that they cannot be part of a ref-cycle. - - __slots__ = () - _registry = {} - _shutdown = False - _index_iter = itertools.count() - _dirty = False - - class _Info: - __slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index") - - def __init__(self, obj, func, *args, **kwargs): - info = self._Info() - info.weakref = ref(obj, self) - info.func = func - info.args = args - info.kwargs = kwargs or None - info.atexit = True - info.index = next(self._index_iter) - self._registry[self] = info - finalize._dirty = True - - def __call__(self, _=None): - """If alive then mark as dead and return func(*args, **kwargs); - otherwise return None""" - info = self._registry.pop(self, None) - if info and not self._shutdown: - return info.func(*info.args, **(info.kwargs or {})) - - def detach(self): - """If alive then mark as dead and return (obj, func, args, kwargs); - otherwise return None""" - info = self._registry.get(self) - obj = info and info.weakref() - if obj is not None and self._registry.pop(self, None): - return (obj, info.func, info.args, info.kwargs or {}) - - def peek(self): - """If alive then return (obj, func, args, kwargs); - otherwise return None""" - info = self._registry.get(self) - obj = info and info.weakref() - if obj is not None: - return (obj, info.func, info.args, info.kwargs or {}) - - @property - def alive(self): - """Whether finalizer is alive""" - return self in self._registry - - @property - def atexit(self): - """Whether finalizer should be called at exit""" - info = self._registry.get(self) - return bool(info) and info.atexit - - @atexit.setter - def atexit(self, value): - info = self._registry.get(self) - if info: - info.atexit = bool(value) - - def __repr__(self): - info = self._registry.get(self) - obj = info and info.weakref() - if obj is None: - return '<%s object at %#x; dead>' % (type(self).__name__, id(self)) - else: - return '<%s object at %#x; for %r at %#x>' % \ - (type(self).__name__, id(self), type(obj).__name__, id(obj)) - - @classmethod - def _select_for_exit(cls): - # Return live finalizers marked for exit, oldest first - L = [(f,i) for (f,i) in cls._registry.items() if i.atexit] - L.sort(key=lambda item:item[1].index) - return [f for (f,i) in L] - - @classmethod - def _exitfunc(cls): - # At shutdown invoke finalizers for which atexit is true. - # This is called once all other non-daemonic threads have been - # joined. - reenable_gc = False - try: - if cls._registry: - import gc - if gc.isenabled(): - reenable_gc = True - gc.disable() - pending = None - while True: - if pending is None or finalize._dirty: - pending = cls._select_for_exit() - finalize._dirty = False - if not pending: - break - f = pending.pop() - try: - # gc is disabled, so (assuming no daemonic - # threads) the following is the only line in - # this function which might trigger creation - # of a new finalizer - f() - except Exception: - sys.excepthook(*sys.exc_info()) - assert f not in cls._registry - finally: - # prevent any more finalizers from executing during shutdown - finalize._shutdown = True - if reenable_gc: - gc.enable() - -atexit.register(finalize._exitfunc) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -69,9 +69,6 @@ Library ------- -- Issue #15528: Add weakref.finalize to support finalization using - weakref callbacks. - - Issue #14173: Avoid crashing when reading a signal handler during interpreter shutdown. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 5 23:47:19 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 5 May 2013 23:47:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2317094=3A_Clear_st?= =?utf-8?q?ale_thread_states_after_fork=28=29=2E?= Message-ID: <3b3gfH0Kg9zPf5@mail.python.org> http://hg.python.org/cpython/rev/847692b9902a changeset: 83630:847692b9902a user: Antoine Pitrou date: Sun May 05 23:47:09 2013 +0200 summary: Issue #17094: Clear stale thread states after fork(). Note that this is a potentially disruptive change since it may release some system resources which would otherwise remain perpetually alive (e.g. database connections kept in thread-local storage). files: Include/pystate.h | 1 + Lib/test/test_threading.py | 25 +++++++++++++ Misc/NEWS | 5 ++ Python/ceval.c | 18 +++++---- Python/pystate.c | 47 ++++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 8 deletions(-) diff --git a/Include/pystate.h b/Include/pystate.h --- a/Include/pystate.h +++ b/Include/pystate.h @@ -139,6 +139,7 @@ PyAPI_FUNC(void) _PyThreadState_Init(PyThreadState *); PyAPI_FUNC(void) PyThreadState_Clear(PyThreadState *); PyAPI_FUNC(void) PyThreadState_Delete(PyThreadState *); +PyAPI_FUNC(void) _PyThreadState_DeleteExcept(PyThreadState *tstate); #ifdef WITH_THREAD PyAPI_FUNC(void) PyThreadState_DeleteCurrent(void); PyAPI_FUNC(void) _PyGILState_Reinit(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 @@ -728,6 +728,31 @@ for t in threads: t.join() + @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") + def test_clear_threads_states_after_fork(self): + # Issue #17094: check that threads states are cleared after fork() + + # start a bunch of threads + threads = [] + for i in range(16): + t = threading.Thread(target=lambda : time.sleep(0.3)) + threads.append(t) + t.start() + + pid = os.fork() + if pid == 0: + # check that threads states have been cleared + if len(sys._current_frames()) == 1: + os._exit(0) + else: + os._exit(1) + else: + _, status = os.waitpid(pid, 0) + self.assertEqual(0, status) + + for t in threads: + t.join() + class ThreadingExceptionTests(BaseTestCase): # A RuntimeError should be raised if Thread.start() is called diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ Core and Builtins ----------------- +- Issue #17094: Clear stale thread states after fork(). Note that this + is a potentially disruptive change since it may release some system + resources which would otherwise remain perpetually alive (e.g. database + connections kept in thread-local storage). + - Issue #17408: Avoid using an obsolete instance of the copyreg module when the interpreter is shutdown and then started again. diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -362,29 +362,28 @@ drop_gil(tstate); } -/* This function is called from PyOS_AfterFork to ensure that newly - created child processes don't hold locks referring to threads which - are not running in the child process. (This could also be done using - pthread_atfork mechanism, at least for the pthreads implementation.) */ +/* This function is called from PyOS_AfterFork to destroy all threads which are + * not running in the child process, and clear internal locks which might be + * held by those threads. (This could also be done using pthread_atfork + * mechanism, at least for the pthreads implementation.) */ void PyEval_ReInitThreads(void) { _Py_IDENTIFIER(_after_fork); PyObject *threading, *result; - PyThreadState *tstate = PyThreadState_GET(); + PyThreadState *current_tstate = PyThreadState_GET(); if (!gil_created()) return; recreate_gil(); pending_lock = PyThread_allocate_lock(); - take_gil(tstate); + take_gil(current_tstate); main_thread = PyThread_get_thread_ident(); /* Update the threading module with the new state. */ - tstate = PyThreadState_GET(); - threading = PyMapping_GetItemString(tstate->interp->modules, + threading = PyMapping_GetItemString(current_tstate->interp->modules, "threading"); if (threading == NULL) { /* threading not imported */ @@ -397,6 +396,9 @@ else Py_DECREF(result); Py_DECREF(threading); + + /* Destroy all threads except the current one */ + _PyThreadState_DeleteExcept(current_tstate); } #else diff --git a/Python/pystate.c b/Python/pystate.c --- a/Python/pystate.c +++ b/Python/pystate.c @@ -414,6 +414,53 @@ #endif /* WITH_THREAD */ +/* + * Delete all thread states except the one passed as argument. + * Note that, if there is a current thread state, it *must* be the one + * passed as argument. Also, this won't touch any other interpreters + * than the current one, since we don't know which thread state should + * be kept in those other interpreteres. + */ +void +_PyThreadState_DeleteExcept(PyThreadState *tstate) +{ + PyInterpreterState *interp = tstate->interp; + PyThreadState *p, *next, *garbage; + HEAD_LOCK(); + /* Remove all thread states, except tstate, from the linked list of + thread states. This will allow calling PyThreadState_Clear() + without holding the lock. + XXX This would be simpler with a doubly-linked list. */ + garbage = interp->tstate_head; + interp->tstate_head = tstate; + if (garbage == tstate) { + garbage = garbage->next; + tstate->next = NULL; + } + else { + for (p = garbage; p; p = p->next) { + if (p->next == tstate) { + p->next = tstate->next; + tstate->next = NULL; + break; + } + } + } + if (tstate->next != NULL) + Py_FatalError("_PyThreadState_DeleteExcept: tstate not found " + "in interpreter thread states"); + HEAD_UNLOCK(); + /* Clear and deallocate all stale thread states. Even if this + executes Python code, we should be safe since it executes + in the current thread, not one of the stale threads. */ + for (p = garbage; p; p = next) { + next = p->next; + PyThreadState_Clear(p); + free(p); + } +} + + PyThreadState * PyThreadState_Get(void) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 00:12:10 2013 From: python-checkins at python.org (richard.oudkerk) Date: Mon, 6 May 2013 00:12:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315528=3A_Add_weak?= =?utf-8?q?ref=2Efinalize_to_support_finalization_using?= Message-ID: <3b3hBy3qkyzQKd@mail.python.org> http://hg.python.org/cpython/rev/186cf551dae5 changeset: 83631:186cf551dae5 user: Richard Oudkerk date: Sun May 05 23:05:00 2013 +0100 summary: Issue #15528: Add weakref.finalize to support finalization using weakref callbacks. This is 2e446e87ac5b except that collections/__init__.py has been modified to import proxy from _weakref instead of weakref. This eliminates an import cycle which seems to cause a problem on Unix but not Windows. files: Doc/library/weakref.rst | 215 +++++++++++++++++++++++- Lib/collections/__init__.py | 2 +- Lib/test/test_weakref.py | 152 ++++++++++++++++- Lib/weakref.py | 137 +++++++++++++++- Misc/NEWS | 3 + 5 files changed, 501 insertions(+), 8 deletions(-) diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst --- a/Doc/library/weakref.rst +++ b/Doc/library/weakref.rst @@ -51,10 +51,15 @@ but keeps weak references to its elements, just like a :class:`WeakKeyDictionary` does. -Most programs should find that using one of these weak container types is all -they need -- it's not usually necessary to create your own weak references -directly. The low-level machinery used by the weak dictionary implementations -is exposed by the :mod:`weakref` module for the benefit of advanced uses. +:class:`finalize` provides a straight forward way to register a +cleanup function to be called when an object is garbage collected. +This is simpler to use than setting up a callback function on a raw +weak reference. + +Most programs should find that using one of these weak container types +or :class:`finalize` is all they need -- it's not usually necessary to +create your own weak references directly. The low-level machinery is +exposed by the :mod:`weakref` module for the benefit of advanced uses. Not all objects can be weakly referenced; those objects which can include class instances, functions written in Python (but not in C), instance methods, sets, @@ -117,7 +122,16 @@ weakref. If there is no callback or if the referent of the weakref is no longer alive then this attribute will have value ``None``. - .. versionadded:: 3.4 + .. note:: + + Like :meth:`__del__` methods, weak reference callbacks can be + called during interpreter shutdown when module globals have been + overwritten with :const:`None`. This can make writing robust + weak reference callbacks a challenge. Callbacks registered + using :class:`finalize` do not have to worry about this issue + because they will not be run after module teardown has begun. + + .. versionchanged:: 3.4 Added the :attr:`__callback__` attribute. @@ -229,6 +243,66 @@ .. versionadded:: 3.4 +.. class:: finalize(obj, func, *args, **kwargs) + + Return a callable finalizer object which will be called when *obj* + is garbage collected. A finalizer is *alive* until it is called + (either explicitly or at garbage collection), and after that it is + *dead*. Calling a live finalizer returns the result of evaluating + ``func(*arg, **kwargs)``, whereas calling a dead finalizer returns + :const:`None`. + + Exceptions raised by finalizer callbacks during garbage collection + will be shown on the standard error output, but cannot be + propagated. They are handled in the same way as exceptions raised + from an object's :meth:`__del__` method or a weak reference's + callback. + + When the program exits, each remaining live finalizer is called + unless its :attr:`atexit` attribute has been set to false. They + are called in reverse order of creation. + + A finalizer will never invoke its callback during the later part of + the interpreter shutdown when module globals are liable to have + been replaced by :const:`None`. + + .. method:: __call__() + + If *self* is alive then mark it as dead and return the result of + calling ``func(*args, **kwargs)``. If *self* is dead then return + :const:`None`. + + .. method:: detach() + + If *self* is alive then mark it as dead and return the tuple + ``(obj, func, args, kwargs)``. If *self* is dead then return + :const:`None`. + + .. method:: peek() + + If *self* is alive then return the tuple ``(obj, func, args, + kwargs)``. If *self* is dead then return :const:`None`. + + .. attribute:: alive + + Property which is true if the finalizer is alive, false otherwise. + + .. attribute:: atexit + + A writable boolean property which by default is true. When the + program exits, it calls all remaining live finalizers for which + :attr:`.atexit` is true. They are called in reverse order of + creation. + + .. note:: + + It is important to ensure that *func*, *args* and *kwargs* do + not own any references to *obj*, either directly or indirectly, + since otherwise *obj* will never be garbage collected. In + particular, *func* should not be a bound method of *obj*. + + .. versionadded:: 3.4 + .. data:: ReferenceType @@ -365,3 +439,134 @@ def id2obj(oid): return _id2obj_dict[oid] + +.. _finalize-examples: + +Finalizer Objects +----------------- + +Often one uses :class:`finalize` to register a callback without +bothering to keep the returned finalizer object. For instance + + >>> import weakref + >>> class Object: + ... pass + ... + >>> kenny = Object() + >>> weakref.finalize(kenny, print, "You killed Kenny!") #doctest:+ELLIPSIS + + >>> del kenny + You killed Kenny! + +The finalizer can be called directly as well. However the finalizer +will invoke the callback at most once. + + >>> def callback(x, y, z): + ... print("CALLBACK") + ... return x + y + z + ... + >>> obj = Object() + >>> f = weakref.finalize(obj, callback, 1, 2, z=3) + >>> assert f.alive + >>> assert f() == 6 + CALLBACK + >>> assert not f.alive + >>> f() # callback not called because finalizer dead + >>> del obj # callback not called because finalizer dead + +You can unregister a finalizer using its :meth:`~finalize.detach` +method. This kills the finalizer and returns the arguments passed to +the constructor when it was created. + + >>> obj = Object() + >>> f = weakref.finalize(obj, callback, 1, 2, z=3) + >>> f.detach() #doctest:+ELLIPSIS + (<__main__.Object object ...>, , (1, 2), {'z': 3}) + >>> newobj, func, args, kwargs = _ + >>> assert not f.alive + >>> assert newobj is obj + >>> assert func(*args, **kwargs) == 6 + CALLBACK + +Unless you set the :attr:`~finalize.atexit` attribute to +:const:`False`, a finalizer will be called when the program exit if it +is still alive. For instance + + >>> obj = Object() + >>> weakref.finalize(obj, print, "obj dead or exiting") #doctest:+ELLIPSIS + + >>> exit() #doctest:+SKIP + obj dead or exiting + + +Comparing finalizers with :meth:`__del__` methods +------------------------------------------------- + +Suppose we want to create a class whose instances represent temporary +directories. The directories should be deleted with their contents +when the first of the following events occurs: + +* the object is garbage collected, +* the object's :meth:`remove` method is called, or +* the program exits. + +We might try to implement the class using a :meth:`__del__` method as +follows:: + + class TempDir: + def __init__(self): + self.name = tempfile.mkdtemp() + + def remove(self): + if self.name is not None: + shutil.rmtree(self.name) + self.name = None + + @property + def removed(self): + return self.name is None + + def __del__(self): + self.remove() + +This solution has a couple of serious problems: + +* There is no guarantee that the object will be garbage collected + before the program exists, so the directory might be left. This is + because reference cycles containing an object with a :meth:`__del__` + method can never be collected. And even if the :class:`TempDir` + object is not itself part of a reference cycle, it may still be kept + alive by some unkown uncollectable reference cycle. + +* The :meth:`__del__` method may be called at shutdown after the + :mod:`shutil` module has been cleaned up, in which case + :attr:`shutil.rmtree` will have been replaced by :const:`None`. + This will cause the :meth:`__del__` method to fail and the directory + will not be removed. + +Using finalizers we can avoid these problems:: + + class TempDir: + def __init__(self): + self.name = tempfile.mkdtemp() + self._finalizer = weakref.finalize(self, shutil.rmtree, self.name) + + def remove(self): + self._finalizer() + + @property + def removed(self): + return not self._finalizer.alive + +Defined like this, even if a :class:`TempDir` object is part of a +reference cycle, that reference cycle can still be garbage collected. +If the object never gets garbage collected the finalizer will still be +called at exit. + +.. note:: + + If you create a finalizer object in a daemonic thread just as the + the program exits then there is the possibility that the finalizer + does not get called at exit. However, in a daemonic thread + :func:`atexit.register`, ``try: ... finally: ...`` and ``with: ...`` + do not guarantee that cleanup occurs either. diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -12,7 +12,7 @@ from keyword import iskeyword as _iskeyword import sys as _sys import heapq as _heapq -from weakref import proxy as _proxy +from _weakref import proxy as _proxy from itertools import repeat as _repeat, chain as _chain, starmap as _starmap from reprlib import recursive_repr as _recursive_repr diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -7,11 +7,15 @@ import contextlib import copy -from test import support +from test import support, script_helper # Used in ReferencesTestCase.test_ref_created_during_del() . ref_from_del = None +# Used by FinalizeTestCase as a global that may be replaced by None +# when the interpreter shuts down. +_global_var = 'foobar' + class C: def method(self): pass @@ -1551,6 +1555,151 @@ def _reference(self): return self.__ref.copy() + +class FinalizeTestCase(unittest.TestCase): + + class A: + pass + + def _collect_if_necessary(self): + # we create no ref-cycles so in CPython no gc should be needed + if sys.implementation.name != 'cpython': + support.gc_collect() + + def test_finalize(self): + def add(x,y,z): + res.append(x + y + z) + return x + y + z + + a = self.A() + + res = [] + f = weakref.finalize(a, add, 67, 43, z=89) + self.assertEqual(f.alive, True) + self.assertEqual(f.peek(), (a, add, (67,43), {'z':89})) + self.assertEqual(f(), 199) + self.assertEqual(f(), None) + self.assertEqual(f(), None) + self.assertEqual(f.peek(), None) + self.assertEqual(f.detach(), None) + self.assertEqual(f.alive, False) + self.assertEqual(res, [199]) + + res = [] + f = weakref.finalize(a, add, 67, 43, 89) + self.assertEqual(f.peek(), (a, add, (67,43,89), {})) + self.assertEqual(f.detach(), (a, add, (67,43,89), {})) + self.assertEqual(f(), None) + self.assertEqual(f(), None) + self.assertEqual(f.peek(), None) + self.assertEqual(f.detach(), None) + self.assertEqual(f.alive, False) + self.assertEqual(res, []) + + res = [] + f = weakref.finalize(a, add, x=67, y=43, z=89) + del a + self._collect_if_necessary() + self.assertEqual(f(), None) + self.assertEqual(f(), None) + self.assertEqual(f.peek(), None) + self.assertEqual(f.detach(), None) + self.assertEqual(f.alive, False) + self.assertEqual(res, [199]) + + def test_order(self): + a = self.A() + res = [] + + f1 = weakref.finalize(a, res.append, 'f1') + f2 = weakref.finalize(a, res.append, 'f2') + f3 = weakref.finalize(a, res.append, 'f3') + f4 = weakref.finalize(a, res.append, 'f4') + f5 = weakref.finalize(a, res.append, 'f5') + + # make sure finalizers can keep themselves alive + del f1, f4 + + self.assertTrue(f2.alive) + self.assertTrue(f3.alive) + self.assertTrue(f5.alive) + + self.assertTrue(f5.detach()) + self.assertFalse(f5.alive) + + f5() # nothing because previously unregistered + res.append('A') + f3() # => res.append('f3') + self.assertFalse(f3.alive) + res.append('B') + f3() # nothing because previously called + res.append('C') + del a + self._collect_if_necessary() + # => res.append('f4') + # => res.append('f2') + # => res.append('f1') + self.assertFalse(f2.alive) + res.append('D') + f2() # nothing because previously called by gc + + expected = ['A', 'f3', 'B', 'C', 'f4', 'f2', 'f1', 'D'] + self.assertEqual(res, expected) + + def test_all_freed(self): + # we want a weakrefable subclass of weakref.finalize + class MyFinalizer(weakref.finalize): + pass + + a = self.A() + res = [] + def callback(): + res.append(123) + f = MyFinalizer(a, callback) + + wr_callback = weakref.ref(callback) + wr_f = weakref.ref(f) + del callback, f + + self.assertIsNotNone(wr_callback()) + self.assertIsNotNone(wr_f()) + + del a + self._collect_if_necessary() + + self.assertIsNone(wr_callback()) + self.assertIsNone(wr_f()) + self.assertEqual(res, [123]) + + @classmethod + def run_in_child(cls): + def error(): + # Create an atexit finalizer from inside a finalizer called + # at exit. This should be the next to be run. + g1 = weakref.finalize(cls, print, 'g1') + print('f3 error') + 1/0 + + # cls should stay alive till atexit callbacks run + f1 = weakref.finalize(cls, print, 'f1', _global_var) + f2 = weakref.finalize(cls, print, 'f2', _global_var) + f3 = weakref.finalize(cls, error) + f4 = weakref.finalize(cls, print, 'f4', _global_var) + + assert f1.atexit == True + f2.atexit = False + assert f3.atexit == True + assert f4.atexit == True + + def test_atexit(self): + prog = ('from test.test_weakref import FinalizeTestCase;'+ + 'FinalizeTestCase.run_in_child()') + rc, out, err = script_helper.assert_python_ok('-c', prog) + out = out.decode('ascii').splitlines() + self.assertEqual(out, ['f4 foobar', 'f3 error', 'g1', 'f1 foobar']) + self.assertTrue(b'ZeroDivisionError' in err) + + libreftest = """ Doctest for examples in the library reference: weakref.rst >>> import weakref @@ -1644,6 +1793,7 @@ WeakValueDictionaryTestCase, WeakKeyDictionaryTestCase, SubclassableWeakrefTestCase, + FinalizeTestCase, ) support.run_doctest(sys.modules[__name__]) diff --git a/Lib/weakref.py b/Lib/weakref.py --- a/Lib/weakref.py +++ b/Lib/weakref.py @@ -21,13 +21,16 @@ from _weakrefset import WeakSet, _IterationGuard import collections # Import after _weakref to avoid circular import. +import sys +import itertools +import atexit ProxyTypes = (ProxyType, CallableProxyType) __all__ = ["ref", "proxy", "getweakrefcount", "getweakrefs", "WeakKeyDictionary", "ReferenceType", "ProxyType", "CallableProxyType", "ProxyTypes", "WeakValueDictionary", - "WeakSet", "WeakMethod"] + "WeakSet", "WeakMethod", "finalize"] class WeakMethod(ref): @@ -436,3 +439,135 @@ d[ref(key, self._remove)] = value if len(kwargs): self.update(kwargs) + + +class finalize: + """Class for finalization of weakrefable objects + + finalize(obj, func, *args, **kwargs) returns a callable finalizer + object which will be called when obj is garbage collected. The + first time the finalizer is called it evaluates func(*arg, **kwargs) + and returns the result. After this the finalizer is dead, and + calling it just returns None. + + When the program exits any remaining finalizers for which the + atexit attribute is true will be run in reverse order of creation. + By default atexit is true. + """ + + # Finalizer objects don't have any state of their own. They are + # just used as keys to lookup _Info objects in the registry. This + # ensures that they cannot be part of a ref-cycle. + + __slots__ = () + _registry = {} + _shutdown = False + _index_iter = itertools.count() + _dirty = False + + class _Info: + __slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index") + + def __init__(self, obj, func, *args, **kwargs): + info = self._Info() + info.weakref = ref(obj, self) + info.func = func + info.args = args + info.kwargs = kwargs or None + info.atexit = True + info.index = next(self._index_iter) + self._registry[self] = info + finalize._dirty = True + + def __call__(self, _=None): + """If alive then mark as dead and return func(*args, **kwargs); + otherwise return None""" + info = self._registry.pop(self, None) + if info and not self._shutdown: + return info.func(*info.args, **(info.kwargs or {})) + + def detach(self): + """If alive then mark as dead and return (obj, func, args, kwargs); + otherwise return None""" + info = self._registry.get(self) + obj = info and info.weakref() + if obj is not None and self._registry.pop(self, None): + return (obj, info.func, info.args, info.kwargs or {}) + + def peek(self): + """If alive then return (obj, func, args, kwargs); + otherwise return None""" + info = self._registry.get(self) + obj = info and info.weakref() + if obj is not None: + return (obj, info.func, info.args, info.kwargs or {}) + + @property + def alive(self): + """Whether finalizer is alive""" + return self in self._registry + + @property + def atexit(self): + """Whether finalizer should be called at exit""" + info = self._registry.get(self) + return bool(info) and info.atexit + + @atexit.setter + def atexit(self, value): + info = self._registry.get(self) + if info: + info.atexit = bool(value) + + def __repr__(self): + info = self._registry.get(self) + obj = info and info.weakref() + if obj is None: + return '<%s object at %#x; dead>' % (type(self).__name__, id(self)) + else: + return '<%s object at %#x; for %r at %#x>' % \ + (type(self).__name__, id(self), type(obj).__name__, id(obj)) + + @classmethod + def _select_for_exit(cls): + # Return live finalizers marked for exit, oldest first + L = [(f,i) for (f,i) in cls._registry.items() if i.atexit] + L.sort(key=lambda item:item[1].index) + return [f for (f,i) in L] + + @classmethod + def _exitfunc(cls): + # At shutdown invoke finalizers for which atexit is true. + # This is called once all other non-daemonic threads have been + # joined. + reenable_gc = False + try: + if cls._registry: + import gc + if gc.isenabled(): + reenable_gc = True + gc.disable() + pending = None + while True: + if pending is None or finalize._dirty: + pending = cls._select_for_exit() + finalize._dirty = False + if not pending: + break + f = pending.pop() + try: + # gc is disabled, so (assuming no daemonic + # threads) the following is the only line in + # this function which might trigger creation + # of a new finalizer + f() + except Exception: + sys.excepthook(*sys.exc_info()) + assert f not in cls._registry + finally: + # prevent any more finalizers from executing during shutdown + finalize._shutdown = True + if reenable_gc: + gc.enable() + +atexit.register(finalize._exitfunc) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -74,6 +74,9 @@ Library ------- +- Issue #15528: Add weakref.finalize to support finalization using + weakref callbacks. + - Issue #14173: Avoid crashing when reading a signal handler during interpreter shutdown. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 04:45:55 2013 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 6 May 2013 04:45:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgMTc4NjI6?= =?utf-8?q?__Improve_the_signature_of_itertools_grouper=28=29_recipe=2E?= Message-ID: <3b3pGq6lNKzQZ8@mail.python.org> http://hg.python.org/cpython/rev/763d260414d1 changeset: 83632:763d260414d1 branch: 2.7 parent: 83627:3c58fa7dc7f1 user: Raymond Hettinger date: Sun May 05 19:45:42 2013 -0700 summary: Issue 17862: Improve the signature of itertools grouper() recipe. Putting *n* after the *iterable* matches the signature of other itertools and recipes. Also, it reads better. Suggested by Ezio Melotti. files: Doc/library/itertools.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -732,9 +732,9 @@ next(b, None) return izip(a, b) - def grouper(n, iterable, fillvalue=None): + def grouper(iterable, n, fillvalue=None): "Collect data into fixed-length chunks or blocks" - # grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx + # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx args = [iter(iterable)] * n return izip_longest(fillvalue=fillvalue, *args) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 04:54:34 2013 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 6 May 2013 04:54:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgMTc4NjI6?= =?utf-8?q?__Improve_the_signature_of_itertools_grouper=28=29_recipe=2E?= Message-ID: <3b3pSp1wp9zNlw@mail.python.org> http://hg.python.org/cpython/rev/6383d0c8140d changeset: 83633:6383d0c8140d branch: 3.3 parent: 83625:c8cdc2400643 user: Raymond Hettinger date: Sun May 05 19:53:41 2013 -0700 summary: Issue 17862: Improve the signature of itertools grouper() recipe. Putting *n* after the *iterable* matches the signature of other itertools and recipes. Also, it reads better. Suggested by Ezio Melotti. files: Doc/library/itertools.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -705,9 +705,9 @@ next(b, None) return zip(a, b) - def grouper(n, iterable, fillvalue=None): + def grouper(iterable, n, fillvalue=None): "Collect data into fixed-length chunks or blocks" - # grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" + # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx" args = [iter(iterable)] * n return zip_longest(*args, fillvalue=fillvalue) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 04:54:35 2013 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 6 May 2013 04:54:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3b3pSq47DyzPk2@mail.python.org> http://hg.python.org/cpython/rev/f95144242466 changeset: 83634:f95144242466 parent: 83631:186cf551dae5 parent: 83633:6383d0c8140d user: Raymond Hettinger date: Sun May 05 19:54:04 2013 -0700 summary: merge files: Doc/library/itertools.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -705,9 +705,9 @@ next(b, None) return zip(a, b) - def grouper(n, iterable, fillvalue=None): + def grouper(iterable, n, fillvalue=None): "Collect data into fixed-length chunks or blocks" - # grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" + # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx" args = [iter(iterable)] * n return zip_longest(*args, fillvalue=fillvalue) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 05:15:35 2013 From: python-checkins at python.org (roger.serwy) Date: Mon, 6 May 2013 05:15:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzEzNDk1OiBBdm9p?= =?utf-8?q?d_loading_the_color_delegator_twice_in_IDLE=2E?= Message-ID: <3b3px32YwHzRPL@mail.python.org> http://hg.python.org/cpython/rev/fef7f212fe76 changeset: 83635:fef7f212fe76 branch: 3.3 parent: 83633:6383d0c8140d user: Roger Serwy date: Sun May 05 22:15:44 2013 -0500 summary: #13495: Avoid loading the color delegator twice in IDLE. files: Lib/idlelib/EditorWindow.py | 3 --- Lib/idlelib/PyShell.py | 2 -- Misc/NEWS | 2 ++ 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -316,9 +316,6 @@ self.good_load = True is_py_src = self.ispythonsource(filename) self.set_indentation_params(is_py_src) - if is_py_src: - self.color = color = self.ColorDelegator() - per.insertfilter(color) else: io.set_filename(filename) self.good_load = True diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -858,8 +858,6 @@ text.bind("<>", self.open_stack_viewer) text.bind("<>", self.toggle_debugger) text.bind("<>", self.toggle_jit_stack_viewer) - self.color = color = self.ColorDelegator() - self.per.insertfilter(color) if use_subprocess: text.bind("<>", self.view_restart_mark) text.bind("<>", self.restart_shell) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -135,6 +135,8 @@ IDLE ---- +- Issue #13495: Avoid loading the color delegator twice in IDLE. + - Issue #17798: Allow IDLE to edit new files when specified on command line. - Issue #14735: Update IDLE docs to omit "Control-z on Windows". -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 05:15:36 2013 From: python-checkins at python.org (roger.serwy) Date: Mon, 6 May 2013 05:15:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzEzNDk1OiBtZXJnZSB3aXRoIDMuMy4=?= Message-ID: <3b3px45p5GzRBC@mail.python.org> http://hg.python.org/cpython/rev/588fcf36c975 changeset: 83636:588fcf36c975 parent: 83634:f95144242466 parent: 83635:fef7f212fe76 user: Roger Serwy date: Sun May 05 22:16:03 2013 -0500 summary: #13495: merge with 3.3. files: Lib/idlelib/EditorWindow.py | 3 --- Lib/idlelib/PyShell.py | 2 -- Misc/NEWS | 2 ++ 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -316,9 +316,6 @@ self.good_load = True is_py_src = self.ispythonsource(filename) self.set_indentation_params(is_py_src) - if is_py_src: - self.color = color = self.ColorDelegator() - per.insertfilter(color) else: io.set_filename(filename) self.good_load = True diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -858,8 +858,6 @@ text.bind("<>", self.open_stack_viewer) text.bind("<>", self.toggle_debugger) text.bind("<>", self.toggle_jit_stack_viewer) - self.color = color = self.ColorDelegator() - self.per.insertfilter(color) if use_subprocess: text.bind("<>", self.view_restart_mark) text.bind("<>", self.restart_shell) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -257,6 +257,8 @@ IDLE ---- +- Issue #13495: Avoid loading the color delegator twice in IDLE. + - Issue #17798: Allow IDLE to edit new files when specified on command line. - Issue #14735: Update IDLE docs to omit "Control-z on Windows". -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 05:22:40 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 6 May 2013 05:22:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUxNzg4Mzog?= =?utf-8?q?Update_to_assertIn_to_see_why_test_fails_on_one_buildbot=2E?= Message-ID: <3b3q5D4xktz7Ll2@mail.python.org> http://hg.python.org/cpython/rev/b1abc5800e2b changeset: 83637:b1abc5800e2b branch: 2.7 parent: 83632:763d260414d1 user: Terry Jan Reedy date: Sun May 05 23:22:19 2013 -0400 summary: Issue17883: Update to assertIn to see why test fails on one buildbot. files: Lib/test/test_tcl.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -148,7 +148,7 @@ env.unset("TCL_LIBRARY") f = os.popen('%s -c "import Tkinter; print Tkinter"' % (unc_name,)) - self.assertTrue('Tkinter.py' in f.read()) + self.assertIn('Tkinter.py', f.read()) # exit code must be zero self.assertEqual(f.close(), None) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon May 6 06:05:34 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 06 May 2013 06:05:34 +0200 Subject: [Python-checkins] Daily reference leaks (186cf551dae5): sum=37 Message-ID: results for 186cf551dae5 on branch "default" -------------------------------------------- test_unittest leaked [-1, 2, 0] memory blocks, sum=1 test_multiprocessing leaked [0, 22, 0] references, sum=22 test_multiprocessing leaked [0, 11, 3] memory blocks, sum=14 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogg5wwIg', '-x'] From python-checkins at python.org Mon May 6 12:46:51 2013 From: python-checkins at python.org (richard.oudkerk) Date: Mon, 6 May 2013 12:46:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2313813=3A_Embed_st?= =?utf-8?q?ringification_of_remote_traceback_in_local?= Message-ID: <3b40xl3HR2z7LjW@mail.python.org> http://hg.python.org/cpython/rev/c4f92b597074 changeset: 83638:c4f92b597074 parent: 83636:588fcf36c975 user: Richard Oudkerk date: Mon May 06 11:38:25 2013 +0100 summary: Issue #13813: Embed stringification of remote traceback in local traceback raised when pool task raises an exception. files: Lib/multiprocessing/pool.py | 25 +++++++++++++++++ Lib/test/test_multiprocessing.py | 29 ++++++++++++++++++++ Misc/NEWS | 3 ++ 3 files changed, 57 insertions(+), 0 deletions(-) diff --git a/Lib/multiprocessing/pool.py b/Lib/multiprocessing/pool.py --- a/Lib/multiprocessing/pool.py +++ b/Lib/multiprocessing/pool.py @@ -18,6 +18,7 @@ import itertools import collections import time +import traceback from multiprocessing import Process, cpu_count, TimeoutError from multiprocessing.util import Finalize, debug @@ -43,6 +44,29 @@ return list(itertools.starmap(args[0], args[1])) # +# Hack to embed stringification of remote traceback in local traceback +# + +class RemoteTraceback(Exception): + def __init__(self, tb): + self.tb = tb + def __str__(self): + return self.tb + +class ExceptionWithTraceback: + def __init__(self, exc, tb): + tb = traceback.format_exception(type(exc), exc, tb) + tb = ''.join(tb) + self.exc = exc + self.tb = '\n"""\n%s"""' % tb + def __reduce__(self): + return rebuild_exc, (self.exc, self.tb) + +def rebuild_exc(exc, tb): + exc.__cause__ = RemoteTraceback(tb) + return exc + +# # Code run by worker processes # @@ -90,6 +114,7 @@ try: result = (True, func(*args, **kwds)) except Exception as e: + e = ExceptionWithTraceback(e, e.__traceback__) result = (False, e) try: put((job, i, result)) diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -1757,6 +1757,35 @@ self.assertEqual(r.get(), expected) self.assertRaises(ValueError, p.map_async, sqr, L) + @classmethod + def _test_traceback(cls): + raise RuntimeError(123) # some comment + + def test_traceback(self): + # We want ensure that the traceback from the child process is + # contained in the traceback raised in the main process. + if self.TYPE == 'processes': + with self.Pool(1) as p: + try: + p.apply(self._test_traceback) + except Exception as e: + exc = e + else: + raise AssertionError('expected RuntimeError') + self.assertIs(type(exc), RuntimeError) + self.assertEqual(exc.args, (123,)) + cause = exc.__cause__ + self.assertIs(type(cause), multiprocessing.pool.RemoteTraceback) + self.assertIn('raise RuntimeError(123) # some comment', cause.tb) + + with test.support.captured_stderr() as f1: + try: + raise exc + except RuntimeError: + sys.excepthook(*sys.exc_info()) + self.assertIn('raise RuntimeError(123) # some comment', + f1.getvalue()) + def raising(): raise KeyError("key") diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -74,6 +74,9 @@ Library ------- +- Issue #13813: Embed stringification of remote traceback in local + traceback raised when pool task raises an exception. + - Issue #15528: Add weakref.finalize to support finalization using weakref callbacks. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 13:15:20 2013 From: python-checkins at python.org (richard.oudkerk) Date: Mon, 6 May 2013 13:15:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3ODA1?= =?utf-8?q?=3A_Add_AsyncResult_alias_for_ApplyResult?= Message-ID: <3b41Zc0Tfxz7LmN@mail.python.org> http://hg.python.org/cpython/rev/2684176519ef changeset: 83639:2684176519ef branch: 2.7 parent: 83637:b1abc5800e2b user: Richard Oudkerk date: Mon May 06 12:04:28 2013 +0100 summary: Issue #17805: Add AsyncResult alias for ApplyResult files: Lib/multiprocessing/pool.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Lib/multiprocessing/pool.py b/Lib/multiprocessing/pool.py --- a/Lib/multiprocessing/pool.py +++ b/Lib/multiprocessing/pool.py @@ -565,6 +565,8 @@ self._cond.release() del self._cache[self._job] +AsyncResult = ApplyResult # create alias -- see #17805 + # # Class whose instances are returned by `Pool.map_async()` # -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 13:15:21 2013 From: python-checkins at python.org (richard.oudkerk) Date: Mon, 6 May 2013 13:15:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3ODA1?= =?utf-8?q?=3A_Add_AsyncResult_alias_for_ApplyResult?= Message-ID: <3b41Zd2kGzz7LmG@mail.python.org> http://hg.python.org/cpython/rev/bb4bb2db6106 changeset: 83640:bb4bb2db6106 branch: 3.3 parent: 83635:fef7f212fe76 user: Richard Oudkerk date: Mon May 06 12:10:04 2013 +0100 summary: Issue #17805: Add AsyncResult alias for ApplyResult files: Lib/multiprocessing/pool.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Lib/multiprocessing/pool.py b/Lib/multiprocessing/pool.py --- a/Lib/multiprocessing/pool.py +++ b/Lib/multiprocessing/pool.py @@ -572,6 +572,8 @@ self._event.set() del self._cache[self._job] +AsyncResult = ApplyResult # create alias -- see #17805 + # # Class whose instances are returned by `Pool.map_async()` # -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 13:15:22 2013 From: python-checkins at python.org (richard.oudkerk) Date: Mon, 6 May 2013 13:15:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge?= Message-ID: <3b41Zf52vcz7Lkt@mail.python.org> http://hg.python.org/cpython/rev/cdf53fd5eb2f changeset: 83641:cdf53fd5eb2f parent: 83638:c4f92b597074 parent: 83640:bb4bb2db6106 user: Richard Oudkerk date: Mon May 06 12:13:50 2013 +0100 summary: Merge files: Lib/multiprocessing/pool.py | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Lib/multiprocessing/pool.py b/Lib/multiprocessing/pool.py --- a/Lib/multiprocessing/pool.py +++ b/Lib/multiprocessing/pool.py @@ -597,6 +597,8 @@ self._event.set() del self._cache[self._job] +AsyncResult = ApplyResult # create alias -- see #17805 + # # Class whose instances are returned by `Pool.map_async()` # -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 13:25:59 2013 From: python-checkins at python.org (richard.oudkerk) Date: Mon, 6 May 2013 13:25:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Correct_issue_number_for_c?= =?utf-8?q?4f92b597074_in_Misc/NEWS_from_=2313813_to_=2313831?= Message-ID: <3b41pv0vGJz7Lk5@mail.python.org> http://hg.python.org/cpython/rev/a2928dd2fde4 changeset: 83642:a2928dd2fde4 user: Richard Oudkerk date: Mon May 06 12:24:30 2013 +0100 summary: Correct issue number for c4f92b597074 in Misc/NEWS from #13813 to #13831 files: Misc/NEWS | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -74,7 +74,7 @@ Library ------- -- Issue #13813: Embed stringification of remote traceback in local +- Issue #13831: Embed stringification of remote traceback in local traceback raised when pool task raises an exception. - Issue #15528: Add weakref.finalize to support finalization using -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 15:39:48 2013 From: python-checkins at python.org (mark.dickinson) Date: Mon, 6 May 2013 15:39:48 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=235845=3A_avoid_an_?= =?utf-8?q?exception_at_startup_on_OS_X_if_no_=2Eeditrc_file_exists=2E?= Message-ID: <3b44nJ24xDzNHP@mail.python.org> http://hg.python.org/cpython/rev/82e92da929eb changeset: 83643:82e92da929eb user: Mark Dickinson date: Mon May 06 15:39:31 2013 +0200 summary: Issue #5845: avoid an exception at startup on OS X if no .editrc file exists. files: Lib/site.py | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Lib/site.py b/Lib/site.py --- a/Lib/site.py +++ b/Lib/site.py @@ -478,7 +478,15 @@ readline.parse_and_bind('bind ^I rl_complete') else: readline.parse_and_bind('tab: complete') - readline.read_init_file() + + try: + readline.read_init_file() + except OSError: + # An OSError here could have many causes, but the most likely one + # is that there's no .inputrc file (or .editrc file in the case of + # Mac OS X + libedit) in the expected location. In that case, we + # want to ignore the exception. + pass history = os.path.join(os.path.expanduser('~'), '.python_history') try: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 15:59:49 2013 From: python-checkins at python.org (nick.coghlan) Date: Mon, 6 May 2013 15:59:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2311816=3A_multiple?= =?utf-8?q?_improvements_to_the_dis_module?= Message-ID: <3b45DP41NszNgv@mail.python.org> http://hg.python.org/cpython/rev/f65b867ce817 changeset: 83644:f65b867ce817 user: Nick Coghlan date: Mon May 06 23:59:20 2013 +1000 summary: Issue #11816: multiple improvements to the dis module * get_instructions generator * ability to redirect output to a file * Bytecode and Instruction abstractions Patch by Nick Coghlan, Ryan Kelly and Thomas Kluyver. files: Doc/library/dis.rst | 269 +++++++++++++++++++----- Doc/whatsnew/3.4.rst | 15 + Lib/dis.py | 341 +++++++++++++++++++++--------- Lib/test/test_dis.py | 339 +++++++++++++++++++++++++++--- Misc/NEWS | 4 + 5 files changed, 775 insertions(+), 193 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -26,7 +26,8 @@ def myfunc(alist): return len(alist) -the following command can be used to get the disassembly of :func:`myfunc`:: +the following command can be used to display the disassembly of +:func:`myfunc`:: >>> dis.dis(myfunc) 2 0 LOAD_GLOBAL 0 (len) @@ -36,8 +37,62 @@ (The "2" is a line number). -The :mod:`dis` module defines the following functions and constants: +Bytecode analysis +----------------- +The bytecode analysis API allows pieces of Python code to be wrapped in a +:class:`Bytecode` object that provides easy access to details of the +compiled code. + +.. class:: Bytecode + + The bytecode operations of a piece of code + + This is a convenient wrapper around many of the functions listed below. + Instantiate it with a function, method, string of code, or a code object + (as returned by :func:`compile`). + + Iterating over this yields the bytecode operations as :class:`Instruction` + instances. + + .. data:: codeobj + + The compiled code object. + + .. method:: display_code(*, file=None) + + Print a formatted view of the bytecode operations, like :func:`dis`. + + .. method:: info() + + Return a formatted multi-line string with detailed information about the + code object, like :func:`code_info`. + + .. method:: show_info(*, file=None) + + Print the information about the code object as returned by :meth:`info`. + + .. versionadded:: 3.4 + +Example:: + + >>> bytecode = dis.Bytecode(myfunc) + >>> for instr in bytecode: + ... print(instr.opname) + ... + LOAD_GLOBAL + LOAD_FAST + CALL_FUNCTION + RETURN_VALUE + + +Analysis functions +------------------ + +The :mod:`dis` module also defines the following analysis functions that +convert the input directly to the desired output. They can be useful if +only a single operation is being performed, so the intermediate analysis +object isn't useful: .. function:: code_info(x) @@ -51,17 +106,21 @@ .. versionadded:: 3.2 -.. function:: show_code(x) +.. function:: show_code(x, *, file=None) Print detailed code object information for the supplied function, method, source code string or code object to stdout. - This is a convenient shorthand for ``print(code_info(x))``, intended for - interactive exploration at the interpreter prompt. + This is a convenient shorthand for ``print(code_info(x), file=file)``, + intended for interactive exploration at the interpreter prompt. .. versionadded:: 3.2 -.. function:: dis(x=None) + .. versionchanged:: 3.4 + Added ``file`` parameter + + +.. function:: dis(x=None, *, file=None) Disassemble the *x* object. *x* can denote either a module, a class, a method, a function, a code object, a string of source code or a byte sequence @@ -72,16 +131,28 @@ disassembled. If no object is provided, this function disassembles the last traceback. + The disassembly is written as text to the supplied ``file`` argument if + provided and to ``sys.stdout`` otherwise. -.. function:: distb(tb=None) + .. versionchanged:: 3.4 + Added ``file`` parameter + + +.. function:: distb(tb=None, *, file=None) Disassemble the top-of-stack function of a traceback, using the last traceback if none was passed. The instruction causing the exception is indicated. + The disassembly is written as text to the supplied ``file`` argument if + provided and to ``sys.stdout`` otherwise. -.. function:: disassemble(code, lasti=-1) - disco(code, lasti=-1) + .. versionchanged:: 3.4 + Added ``file`` parameter + + +.. function:: disassemble(code, lasti=-1, *, file=None) + disco(code, lasti=-1, *, file=None) Disassemble a code object, indicating the last instruction if *lasti* was provided. The output is divided in the following columns: @@ -97,6 +168,26 @@ 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 + provided and to ``sys.stdout`` otherwise. + + .. versionchanged:: 3.4 + Added ``file`` parameter + + +.. function:: get_instructions(x, *, line_offset=0) + + Return an iterator over the instructions in the supplied function, method, + source code string or code object. + + The iterator generates a series of :class:`Instruction` named tuples + giving the details of each operation in the supplied code. + + The given *line_offset* is added to the ``starts_line`` attribute of any + instructions that start a new line. + + .. versionadded:: 3.4 + .. function:: findlinestarts(code) @@ -110,62 +201,61 @@ Detect all offsets in the code object *code* which are jump targets, and return a list of these offsets. - -.. data:: opname - - Sequence of operation names, indexable using the bytecode. - - -.. data:: opmap - - Dictionary mapping operation names to bytecodes. - - -.. data:: cmp_op - - Sequence of all compare operation names. - - -.. data:: hasconst - - Sequence of bytecodes that have a constant parameter. - - -.. data:: hasfree - - Sequence of bytecodes that access a free variable. - - -.. data:: hasname - - Sequence of bytecodes that access an attribute by name. - - -.. data:: hasjrel - - Sequence of bytecodes that have a relative jump target. - - -.. data:: hasjabs - - Sequence of bytecodes that have an absolute jump target. - - -.. data:: haslocal - - Sequence of bytecodes that access a local variable. - - -.. data:: hascompare - - Sequence of bytecodes of Boolean operations. - - .. _bytecodes: Python Bytecode Instructions ---------------------------- +The :func:`get_instructions` function and :class:`Bytecode` class provide +details of bytecode instructions as :class:`Instruction` instances: + +.. class:: Instruction + + Details for a bytecode operation + + .. data:: opcode + + numeric code for operation, corresponding to the opcode values listed + below and the bytecode values in the :ref:`opcode_collections`. + + + .. data:: opname + + human readable name for operation + + + .. data:: arg + + numeric argument to operation (if any), otherwise None + + + .. data:: argval + + resolved arg value (if known), otherwise same as arg + + + .. data:: argrepr + + human readable description of operation argument + + + .. data:: offset + + start index of operation within bytecode sequence + + + .. data:: starts_line + + line started by this opcode (if any), otherwise None + + + .. data:: is_jump_target + + True if other code jumps to here, otherwise False + + .. versionadded:: 3.4 + + The Python compiler currently generates the following bytecode instructions. @@ -820,3 +910,62 @@ which don't take arguments ``< HAVE_ARGUMENT`` and those which do ``>= HAVE_ARGUMENT``. +.. _opcode_collections: + +Opcode collections +------------------ + +These collections are provided for automatic introspection of bytecode +instructions: + +.. data:: opname + + Sequence of operation names, indexable using the bytecode. + + +.. data:: opmap + + Dictionary mapping operation names to bytecodes. + + +.. data:: cmp_op + + Sequence of all compare operation names. + + +.. data:: hasconst + + Sequence of bytecodes that have a constant parameter. + + +.. data:: hasfree + + Sequence of bytecodes that access a free variable (note that 'free' in + this context refers to names in the current scope that are referenced by + inner scopes or names in outer scopes that are referenced from this scope. + It does *not* include references to global or builtin scopes). + + +.. data:: hasname + + Sequence of bytecodes that access an attribute by name. + + +.. data:: hasjrel + + Sequence of bytecodes that have a relative jump target. + + +.. data:: hasjabs + + Sequence of bytecodes that have an absolute jump target. + + +.. data:: haslocal + + Sequence of bytecodes that access a local variable. + + +.. data:: hascompare + + Sequence of bytecodes of Boolean operations. 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 @@ -152,6 +152,21 @@ ================ +dis +--- + +The :mod:`dis` module is now built around an :class:`Instruction` class that +provides details of individual bytecode operations and a +:func:`get_instructions` iterator that emits the Instruction stream for a +given piece of Python code. The various display tools in the :mod:`dis` +module have been updated to be based on these new components. + +The new :class:`dis.Bytecode` class provides an object-oriented API for +inspecting bytecode, both in human-readable form and for iterating over +instructions. + +(Contributed by Nick Coghlan, Ryan Kelly and Thomas Kluyver in :issue:`11816`) + doctest ------- diff --git a/Lib/dis.py b/Lib/dis.py --- a/Lib/dis.py +++ b/Lib/dis.py @@ -2,12 +2,14 @@ import sys import types +import collections from opcode import * from opcode import __all__ as _opcodes_all __all__ = ["code_info", "dis", "disassemble", "distb", "disco", - "findlinestarts", "findlabels", "show_code"] + _opcodes_all + "findlinestarts", "findlabels", "show_code", + "get_instructions", "Instruction", "Bytecode"] + _opcodes_all del _opcodes_all _have_code = (types.MethodType, types.FunctionType, types.CodeType, type) @@ -25,7 +27,7 @@ c = compile(source, name, 'exec') return c -def dis(x=None): +def dis(x=None, *, file=None): """Disassemble classes, methods, functions, or code. With no argument, disassemble the last traceback. @@ -42,23 +44,23 @@ items = sorted(x.__dict__.items()) for name, x1 in items: if isinstance(x1, _have_code): - print("Disassembly of %s:" % name) + print("Disassembly of %s:" % name, file=file) try: dis(x1) except TypeError as msg: - print("Sorry:", msg) - print() + print("Sorry:", msg, file=file) + print(file=file) elif hasattr(x, 'co_code'): # Code object - disassemble(x) + disassemble(x, file=file) elif isinstance(x, (bytes, bytearray)): # Raw bytecode - _disassemble_bytes(x) + _disassemble_bytes(x, file=file) elif isinstance(x, str): # Source code - _disassemble_str(x) + _disassemble_str(x, file=file) else: raise TypeError("don't know how to disassemble %s objects" % type(x).__name__) -def distb(tb=None): +def distb(tb=None, *, file=None): """Disassemble a traceback (default: last traceback).""" if tb is None: try: @@ -66,7 +68,7 @@ except AttributeError: raise RuntimeError("no last traceback to disassemble") while tb.tb_next: tb = tb.tb_next - disassemble(tb.tb_frame.f_code, tb.tb_lasti) + disassemble(tb.tb_frame.f_code, tb.tb_lasti, file=file) # The inspect module interrogates this dictionary to build its # list of CO_* constants. It is also used by pretty_flags to @@ -95,19 +97,22 @@ names.append(hex(flags)) return ", ".join(names) -def code_info(x): - """Formatted details of methods, functions, or code.""" +def _get_code_object(x): + """Helper to handle methods, functions, strings and raw code objects""" if hasattr(x, '__func__'): # Method x = x.__func__ if hasattr(x, '__code__'): # Function x = x.__code__ if isinstance(x, str): # Source code - x = _try_compile(x, "") + x = _try_compile(x, "") if hasattr(x, 'co_code'): # Code object - return _format_code_info(x) - else: - raise TypeError("don't know how to disassemble %s objects" % - type(x).__name__) + return x + raise TypeError("don't know how to disassemble %s objects" % + type(x).__name__) + +def code_info(x): + """Formatted details of methods, functions, or code.""" + return _format_code_info(_get_code_object(x)) def _format_code_info(co): lines = [] @@ -140,106 +145,196 @@ lines.append("%4d: %s" % i_n) return "\n".join(lines) -def show_code(co): +def show_code(co, *, file=None): """Print details of methods, functions, or code to stdout.""" - print(code_info(co)) + print(code_info(co), file=file) -def disassemble(co, lasti=-1): - """Disassemble a code object.""" - code = co.co_code +_Instruction = collections.namedtuple("_Instruction", + "opname opcode arg argval argrepr offset starts_line is_jump_target") + +class Instruction(_Instruction): + """Details for a bytecode operation + + Defined fields: + opname - human readable name for operation + opcode - numeric code for operation + arg - numeric argument to operation (if any), otherwise None + argval - resolved arg value (if known), otherwise same as arg + argrepr - human readable description of operation argument + offset - start index of operation within bytecode sequence + starts_line - line started by this opcode (if any), otherwise None + is_jump_target - True if other code jumps to here, otherwise False + """ + + def _disassemble(self, lineno_width=3, mark_as_current=False): + """Format instruction details for inclusion in disassembly output + + *lineno_width* sets the width of the line number field (0 omits it) + *mark_as_current* inserts a '-->' marker arrow as part of the line + """ + fields = [] + # Column: Source code line number + if lineno_width: + if self.starts_line is not None: + lineno_fmt = "%%%dd" % lineno_width + fields.append(lineno_fmt % self.starts_line) + else: + fields.append(' ' * lineno_width) + # Column: Current instruction indicator + if mark_as_current: + fields.append('-->') + else: + fields.append(' ') + # Column: Jump target marker + if self.is_jump_target: + fields.append('>>') + else: + fields.append(' ') + # Column: Instruction offset from start of code sequence + fields.append(repr(self.offset).rjust(4)) + # Column: Opcode name + fields.append(self.opname.ljust(20)) + # Column: Opcode argument + if self.arg is not None: + fields.append(repr(self.arg).rjust(5)) + # Column: Opcode argument details + if self.argrepr: + fields.append('(' + self.argrepr + ')') + return ' '.join(fields) + + +def get_instructions(x, *, line_offset=0): + """Iterator for the opcodes in methods, functions or code + + Generates a series of Instruction named tuples giving the details of + each operations in the supplied code. + + The given line offset is added to the 'starts_line' attribute of any + instructions that start a new line. + """ + co = _get_code_object(x) + cell_names = co.co_cellvars + co.co_freevars + linestarts = dict(findlinestarts(co)) + return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names, + co.co_consts, cell_names, linestarts, + line_offset) + +def _get_const_info(const_index, const_list): + """Helper to get optional details about const references + + Returns the dereferenced constant and its repr if the constant + list is defined. + Otherwise returns the constant index and its repr(). + """ + argval = const_index + if const_list is not None: + argval = const_list[const_index] + return argval, repr(argval) + +def _get_name_info(name_index, name_list): + """Helper to get optional details about named references + + Returns the dereferenced name as both value and repr if the name + list is defined. + Otherwise returns the name index and its repr(). + """ + argval = name_index + if name_list is not None: + argval = name_list[name_index] + argrepr = argval + else: + argrepr = repr(argval) + return argval, argrepr + + +def _get_instructions_bytes(code, varnames=None, names=None, constants=None, + cells=None, linestarts=None, line_offset=0): + """Iterate over the instructions in a bytecode string. + + Generates a sequence of Instruction namedtuples giving the details of each + opcode. Additional information about the code's runtime environment + (e.g. variable names, constants) can be specified using optional + arguments. + + """ labels = findlabels(code) - linestarts = dict(findlinestarts(co)) - n = len(code) - i = 0 extended_arg = 0 + starts_line = None free = None - while i < n: - op = code[i] - if i in linestarts: - if i > 0: - print() - print("%3d" % linestarts[i], end=' ') - else: - print(' ', end=' ') - - if i == lasti: print('-->', end=' ') - else: print(' ', end=' ') - if i in labels: print('>>', end=' ') - else: print(' ', end=' ') - print(repr(i).rjust(4), end=' ') - print(opname[op].ljust(20), end=' ') - i = i+1 - if op >= HAVE_ARGUMENT: - oparg = code[i] + code[i+1]*256 + extended_arg - extended_arg = 0 - i = i+2 - if op == EXTENDED_ARG: - extended_arg = oparg*65536 - print(repr(oparg).rjust(5), end=' ') - if op in hasconst: - print('(' + repr(co.co_consts[oparg]) + ')', end=' ') - elif op in hasname: - print('(' + co.co_names[oparg] + ')', end=' ') - elif op in hasjrel: - print('(to ' + repr(i + oparg) + ')', end=' ') - elif op in haslocal: - print('(' + co.co_varnames[oparg] + ')', end=' ') - elif op in hascompare: - print('(' + cmp_op[oparg] + ')', end=' ') - elif op in hasfree: - if free is None: - free = co.co_cellvars + co.co_freevars - print('(' + free[oparg] + ')', end=' ') - elif op in hasnargs: - print('(%d positional, %d keyword pair)' - % (code[i-2], code[i-1]), end=' ') - print() - -def _disassemble_bytes(code, lasti=-1, varnames=None, names=None, - constants=None): - labels = findlabels(code) + # enumerate() is not an option, since we sometimes process + # multiple elements on a single pass through the loop n = len(code) i = 0 while i < n: op = code[i] - if i == lasti: print('-->', end=' ') - else: print(' ', end=' ') - if i in labels: print('>>', end=' ') - else: print(' ', end=' ') - print(repr(i).rjust(4), end=' ') - print(opname[op].ljust(15), end=' ') + offset = i + if linestarts is not None: + starts_line = linestarts.get(i, None) + if starts_line is not None: + starts_line += line_offset + is_jump_target = i in labels i = i+1 + arg = None + argval = None + argrepr = '' if op >= HAVE_ARGUMENT: - oparg = code[i] + code[i+1]*256 + arg = code[i] + code[i+1]*256 + extended_arg + extended_arg = 0 i = i+2 - print(repr(oparg).rjust(5), end=' ') + if op == EXTENDED_ARG: + extended_arg = arg*65536 + # Set argval to the dereferenced value of the argument when + # availabe, and argrepr to the string representation of argval. + # _disassemble_bytes needs the string repr of the + # raw name index for LOAD_GLOBAL, LOAD_CONST, etc. + argval = arg if op in hasconst: - if constants: - print('(' + repr(constants[oparg]) + ')', end=' ') - else: - print('(%d)'%oparg, end=' ') + argval, argrepr = _get_const_info(arg, constants) elif op in hasname: - if names is not None: - print('(' + names[oparg] + ')', end=' ') - else: - print('(%d)'%oparg, end=' ') + argval, argrepr = _get_name_info(arg, names) elif op in hasjrel: - print('(to ' + repr(i + oparg) + ')', end=' ') + argval = i + arg + argrepr = "to " + repr(argval) elif op in haslocal: - if varnames: - print('(' + varnames[oparg] + ')', end=' ') - else: - print('(%d)' % oparg, end=' ') + argval, argrepr = _get_name_info(arg, varnames) elif op in hascompare: - print('(' + cmp_op[oparg] + ')', end=' ') + argval = cmp_op[arg] + argrepr = argval + elif op in hasfree: + argval, argrepr = _get_name_info(arg, cells) elif op in hasnargs: - print('(%d positional, %d keyword pair)' - % (code[i-2], code[i-1]), end=' ') - print() + argrepr = "%d positional, %d keyword pair" % (code[i-2], code[i-1]) + yield Instruction(opname[op], op, + arg, argval, argrepr, + offset, starts_line, is_jump_target) -def _disassemble_str(source): +def disassemble(co, lasti=-1, *, file=None): + """Disassemble a code object.""" + cell_names = co.co_cellvars + co.co_freevars + linestarts = dict(findlinestarts(co)) + _disassemble_bytes(co.co_code, lasti, co.co_varnames, co.co_names, + co.co_consts, cell_names, linestarts, file=file) + +def _disassemble_bytes(code, lasti=-1, varnames=None, names=None, + constants=None, cells=None, linestarts=None, + *, file=None): + # Omit the line number column entirely if we have no line number info + show_lineno = linestarts is not None + # TODO?: Adjust width upwards if max(linestarts.values()) >= 1000? + lineno_width = 3 if show_lineno else 0 + for instr in _get_instructions_bytes(code, varnames, names, + constants, cells, linestarts): + new_source_line = (show_lineno and + instr.starts_line is not None and + instr.offset > 0) + if new_source_line: + print(file=file) + is_current_instr = instr.offset == lasti + print(instr._disassemble(lineno_width, is_current_instr), file=file) + +def _disassemble_str(source, *, file=None): """Compile the source string, then disassemble the code object.""" - disassemble(_try_compile(source, '')) + disassemble(_try_compile(source, ''), file=file) disco = disassemble # XXX For backwards compatibility @@ -250,19 +345,21 @@ """ labels = [] + # enumerate() is not an option, since we sometimes process + # multiple elements on a single pass through the loop n = len(code) i = 0 while i < n: op = code[i] i = i+1 if op >= HAVE_ARGUMENT: - oparg = code[i] + code[i+1]*256 + arg = code[i] + code[i+1]*256 i = i+2 label = -1 if op in hasjrel: - label = i+oparg + label = i+arg elif op in hasjabs: - label = oparg + label = arg if label >= 0: if label not in labels: labels.append(label) @@ -290,6 +387,50 @@ if lineno != lastlineno: yield (addr, lineno) +class Bytecode: + """The bytecode operations of a piece of code + + Instantiate this with a function, method, string of code, or a code object + (as returned by compile()). + + Iterating over this yields the bytecode operations as Instruction instances. + """ + def __init__(self, x): + self.codeobj = _get_code_object(x) + self.cell_names = self.codeobj.co_cellvars + self.codeobj.co_freevars + self.linestarts = dict(findlinestarts(self.codeobj)) + self.line_offset = 0 + self.original_object = x + + def __iter__(self): + co = self.codeobj + return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names, + co.co_consts, self.cell_names, + self.linestarts, self.line_offset) + + def __repr__(self): + return "{}({!r})".format(self.__class__.__name__, self.original_object) + + def info(self): + """Return formatted information about the code object.""" + return _format_code_info(self.codeobj) + + def show_info(self, *, file=None): + """Print the information about the code object as returned by info().""" + print(self.info(), file=file) + + def display_code(self, *, file=None): + """Print a formatted view of the bytecode operations. + """ + co = self.codeobj + return _disassemble_bytes(co.co_code, varnames=co.co_varnames, + names=co.co_names, constants=co.co_consts, + cells=self.cell_names, + linestarts=self.linestarts, + file=file + ) + + def _test(): """Simple test program to disassemble a file.""" if sys.argv[1:]: diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1,11 +1,13 @@ # Minimal tests for dis module from test.support import run_unittest, captured_stdout +from test.bytecode_helper import BytecodeTestCase import difflib import unittest import sys import dis import io +import types class _C: def __init__(self, x): @@ -22,12 +24,12 @@ """ % (_C.__init__.__code__.co_firstlineno + 1,) dis_c_instance_method_bytes = """\ - 0 LOAD_FAST 1 (1) - 3 LOAD_CONST 1 (1) - 6 COMPARE_OP 2 (==) - 9 LOAD_FAST 0 (0) - 12 STORE_ATTR 0 (0) - 15 LOAD_CONST 0 (0) + 0 LOAD_FAST 1 (1) + 3 LOAD_CONST 1 (1) + 6 COMPARE_OP 2 (==) + 9 LOAD_FAST 0 (0) + 12 STORE_ATTR 0 (0) + 15 LOAD_CONST 0 (0) 18 RETURN_VALUE """ @@ -48,11 +50,11 @@ dis_f_co_code = """\ - 0 LOAD_GLOBAL 0 (0) - 3 LOAD_FAST 0 (0) - 6 CALL_FUNCTION 1 (1 positional, 0 keyword pair) + 0 LOAD_GLOBAL 0 (0) + 3 LOAD_FAST 0 (0) + 6 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 9 POP_TOP - 10 LOAD_CONST 1 (1) + 10 LOAD_CONST 1 (1) 13 RETURN_VALUE """ @@ -298,29 +300,16 @@ Argument count: 1 Kw-only arguments: 0 Number of locals: 1 -Stack size: 4 +Stack size: 3 Flags: OPTIMIZED, NEWLOCALS, NOFREE Constants: 0: %r - 1: '__func__' - 2: '__code__' - 3: '' - 4: 'co_code' - 5: "don't know how to disassemble %%s objects" -%sNames: - 0: hasattr - 1: __func__ - 2: __code__ - 3: isinstance - 4: str - 5: _try_compile - 6: _format_code_info - 7: TypeError - 8: type - 9: __name__ +Names: + 0: _format_code_info + 1: _get_code_object Variable names: - 0: x""" % (('Formatted details of methods, functions, or code.', ' 6: None\n') - if sys.flags.optimize < 2 else (None, '')) + 0: x""" % (('Formatted details of methods, functions, or code.',) + if sys.flags.optimize < 2 else (None,)) @staticmethod def tricky(x, y, z=True, *args, c, d, e=[], **kwds): @@ -384,7 +373,7 @@ code_info_expr_str = """\ Name: -Filename: +Filename: Argument count: 0 Kw-only arguments: 0 Number of locals: 0 @@ -397,7 +386,7 @@ code_info_simple_stmt_str = """\ Name: -Filename: +Filename: Argument count: 0 Kw-only arguments: 0 Number of locals: 0 @@ -411,7 +400,7 @@ code_info_compound_stmt_str = """\ Name: -Filename: +Filename: Argument count: 0 Kw-only arguments: 0 Number of locals: 0 @@ -445,6 +434,9 @@ with captured_stdout() as output: dis.show_code(x) self.assertRegex(output.getvalue(), expected+"\n") + output = io.StringIO() + dis.show_code(x, file=output) + self.assertRegex(output.getvalue(), expected) def test_code_info_object(self): self.assertRaises(TypeError, dis.code_info, object()) @@ -453,8 +445,289 @@ self.assertEqual(dis.pretty_flags(0), '0x0') +# Fodder for instruction introspection tests +# Editing any of these may require recalculating the expected output +def outer(a=1, b=2): + def f(c=3, d=4): + def inner(e=5, f=6): + print(a, b, c, d, e, f) + print(a, b, c, d) + return inner + print(a, b, '', 1, [], {}, "Hello world!") + return f + +def jumpy(): + # This won't actually run (but that's OK, we only disassemble it) + for i in range(10): + print(i) + if i < 4: + continue + if i > 6: + break + else: + print("I can haz else clause?") + while i: + print(i) + i -= 1 + if i > 6: + continue + if i < 4: + break + else: + print("Who let lolcatz into this test suite?") + try: + 1 / 0 + except ZeroDivisionError: + print("Here we go, here we go, here we go...") + else: + with i as dodgy: + print("Never reach this") + finally: + print("OK, now we're done") + +# End fodder for opinfo generation tests +expected_outer_offset = 1 - outer.__code__.co_firstlineno +expected_jumpy_offset = 1 - jumpy.__code__.co_firstlineno +code_object_f = outer.__code__.co_consts[3] +code_object_inner = code_object_f.co_consts[3] + +# The following lines are useful to regenerate the expected results after +# either the fodder is modified or the bytecode generation changes +# After regeneration, update the references to code_object_f and +# code_object_inner before rerunning the tests + +#_instructions = dis.get_instructions(outer, line_offset=expected_outer_offset) +#print('expected_opinfo_outer = [\n ', + #',\n '.join(map(str, _instructions)), ',\n]', sep='') +#_instructions = dis.get_instructions(outer(), line_offset=expected_outer_offset) +#print('expected_opinfo_f = [\n ', + #',\n '.join(map(str, _instructions)), ',\n]', sep='') +#_instructions = dis.get_instructions(outer()(), line_offset=expected_outer_offset) +#print('expected_opinfo_inner = [\n ', + #',\n '.join(map(str, _instructions)), ',\n]', sep='') +#_instructions = dis.get_instructions(jumpy, line_offset=expected_jumpy_offset) +#print('expected_opinfo_jumpy = [\n ', + #',\n '.join(map(str, _instructions)), ',\n]', sep='') + + +Instruction = dis.Instruction +expected_opinfo_outer = [ + Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=3, argrepr='3', offset=0, starts_line=2, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=3, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='a', argrepr='a', offset=6, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='b', argrepr='b', offset=9, starts_line=None, is_jump_target=False), + Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=12, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_f, argrepr=repr(code_object_f), offset=15, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer..f', argrepr="'outer..f'", offset=18, starts_line=None, is_jump_target=False), + Instruction(opname='MAKE_CLOSURE', opcode=134, arg=2, argval=2, argrepr='', offset=21, starts_line=None, is_jump_target=False), + Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=24, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=27, starts_line=7, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='a', argrepr='a', offset=30, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='b', argrepr='b', offset=33, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval='', argrepr="''", offset=36, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval=1, argrepr='1', offset=39, starts_line=None, is_jump_target=False), + Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=42, starts_line=None, is_jump_target=False), + Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=45, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval='Hello world!', argrepr="'Hello world!'", offset=48, starts_line=None, is_jump_target=False), + Instruction(opname='CALL_FUNCTION', opcode=131, arg=7, argval=7, argrepr='7 positional, 0 keyword pair', offset=51, starts_line=None, is_jump_target=False), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=54, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=55, starts_line=8, is_jump_target=False), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=58, starts_line=None, is_jump_target=False), +] + +expected_opinfo_f = [ + Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=5, argrepr='5', offset=0, starts_line=3, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=6, argrepr='6', offset=3, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CLOSURE', opcode=135, arg=2, argval='a', argrepr='a', offset=6, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CLOSURE', opcode=135, arg=3, argval='b', argrepr='b', offset=9, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='c', argrepr='c', offset=12, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='d', argrepr='d', offset=15, starts_line=None, is_jump_target=False), + Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=18, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_inner, argrepr=repr(code_object_inner), offset=21, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer..f..inner', argrepr="'outer..f..inner'", offset=24, starts_line=None, is_jump_target=False), + Instruction(opname='MAKE_CLOSURE', opcode=134, arg=2, argval=2, argrepr='', offset=27, starts_line=None, is_jump_target=False), + Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=30, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=33, starts_line=5, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='a', argrepr='a', offset=36, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='b', argrepr='b', offset=39, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='c', argrepr='c', offset=42, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='d', argrepr='d', offset=45, starts_line=None, is_jump_target=False), + Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='4 positional, 0 keyword pair', offset=48, starts_line=None, is_jump_target=False), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=51, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=52, starts_line=6, is_jump_target=False), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=55, starts_line=None, is_jump_target=False), +] + +expected_opinfo_inner = [ + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=0, starts_line=4, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='a', argrepr='a', offset=3, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='b', argrepr='b', offset=6, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='c', argrepr='c', offset=9, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='d', argrepr='d', offset=12, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=15, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=18, starts_line=None, is_jump_target=False), + Instruction(opname='CALL_FUNCTION', opcode=131, arg=6, argval=6, argrepr='6 positional, 0 keyword pair', offset=21, starts_line=None, is_jump_target=False), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=24, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=25, starts_line=None, is_jump_target=False), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=28, starts_line=None, is_jump_target=False), +] + +expected_opinfo_jumpy = [ + Instruction(opname='SETUP_LOOP', opcode=120, arg=74, argval=77, argrepr='to 77', offset=0, starts_line=3, is_jump_target=False), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='range', argrepr='range', offset=3, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=6, starts_line=None, is_jump_target=False), + Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=9, starts_line=None, is_jump_target=False), + Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=12, starts_line=None, is_jump_target=False), + Instruction(opname='FOR_ITER', opcode=93, arg=50, argval=66, argrepr='to 66', offset=13, starts_line=None, is_jump_target=True), + Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=16, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=19, starts_line=4, is_jump_target=False), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=22, starts_line=None, is_jump_target=False), + Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=25, starts_line=None, is_jump_target=False), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=28, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=29, starts_line=5, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=32, starts_line=None, is_jump_target=False), + Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=35, starts_line=None, is_jump_target=False), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=47, argval=47, argrepr='', offset=38, starts_line=None, is_jump_target=False), + Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=13, argval=13, argrepr='', offset=41, starts_line=6, is_jump_target=False), + Instruction(opname='JUMP_FORWARD', opcode=110, arg=0, argval=47, argrepr='to 47', offset=44, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=47, starts_line=7, is_jump_target=True), + Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=50, starts_line=None, is_jump_target=False), + Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=53, starts_line=None, is_jump_target=False), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=13, argval=13, argrepr='', offset=56, starts_line=None, is_jump_target=False), + Instruction(opname='BREAK_LOOP', opcode=80, arg=None, argval=None, argrepr='', offset=59, starts_line=8, is_jump_target=False), + Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=13, argval=13, argrepr='', offset=60, starts_line=None, is_jump_target=False), + Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=13, argval=13, argrepr='', offset=63, starts_line=None, is_jump_target=False), + Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=66, starts_line=None, is_jump_target=True), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=67, starts_line=10, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=70, starts_line=None, is_jump_target=False), + Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=73, starts_line=None, is_jump_target=False), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=76, starts_line=None, is_jump_target=False), + Instruction(opname='SETUP_LOOP', opcode=120, arg=74, argval=154, argrepr='to 154', offset=77, starts_line=11, is_jump_target=True), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=80, starts_line=None, is_jump_target=True), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=143, argval=143, argrepr='', offset=83, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=86, starts_line=12, is_jump_target=False), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=89, starts_line=None, is_jump_target=False), + Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=92, starts_line=None, is_jump_target=False), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=95, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=96, starts_line=13, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=99, starts_line=None, is_jump_target=False), + Instruction(opname='INPLACE_SUBTRACT', opcode=56, arg=None, argval=None, argrepr='', offset=102, starts_line=None, is_jump_target=False), + Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=103, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=106, starts_line=14, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=109, starts_line=None, is_jump_target=False), + Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=112, starts_line=None, is_jump_target=False), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=124, argval=124, argrepr='', offset=115, starts_line=None, is_jump_target=False), + Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=80, argval=80, argrepr='', offset=118, starts_line=15, is_jump_target=False), + Instruction(opname='JUMP_FORWARD', opcode=110, arg=0, argval=124, argrepr='to 124', offset=121, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=124, starts_line=16, is_jump_target=True), + Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=127, starts_line=None, is_jump_target=False), + Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=130, starts_line=None, is_jump_target=False), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=80, argval=80, argrepr='', offset=133, starts_line=None, is_jump_target=False), + Instruction(opname='BREAK_LOOP', opcode=80, arg=None, argval=None, argrepr='', offset=136, starts_line=17, is_jump_target=False), + Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=80, argval=80, argrepr='', offset=137, starts_line=None, is_jump_target=False), + Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=80, argval=80, argrepr='', offset=140, starts_line=None, is_jump_target=False), + Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=143, starts_line=None, is_jump_target=True), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=144, starts_line=19, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=147, starts_line=None, is_jump_target=False), + Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=150, starts_line=None, is_jump_target=False), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=153, starts_line=None, is_jump_target=False), + Instruction(opname='SETUP_FINALLY', opcode=122, arg=72, argval=229, argrepr='to 229', offset=154, starts_line=20, is_jump_target=True), + Instruction(opname='SETUP_EXCEPT', opcode=121, arg=12, argval=172, argrepr='to 172', offset=157, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=160, starts_line=21, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=163, starts_line=None, is_jump_target=False), + Instruction(opname='BINARY_TRUE_DIVIDE', opcode=27, arg=None, argval=None, argrepr='', offset=166, starts_line=None, is_jump_target=False), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=167, starts_line=None, is_jump_target=False), + Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=168, starts_line=None, is_jump_target=False), + Instruction(opname='JUMP_FORWARD', opcode=110, arg=28, argval=200, argrepr='to 200', offset=169, starts_line=None, is_jump_target=False), + Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=172, starts_line=22, is_jump_target=True), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=2, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=173, starts_line=None, is_jump_target=False), + Instruction(opname='COMPARE_OP', opcode=107, arg=10, argval='exception match', argrepr='exception match', offset=176, starts_line=None, is_jump_target=False), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=199, argval=199, argrepr='', offset=179, starts_line=None, is_jump_target=False), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=182, starts_line=None, is_jump_target=False), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=183, starts_line=None, is_jump_target=False), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=184, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=185, starts_line=23, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=188, starts_line=None, is_jump_target=False), + Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=191, starts_line=None, is_jump_target=False), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=194, starts_line=None, is_jump_target=False), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=195, starts_line=None, is_jump_target=False), + Instruction(opname='JUMP_FORWARD', opcode=110, arg=26, argval=225, argrepr='to 225', offset=196, starts_line=None, is_jump_target=False), + Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=199, starts_line=None, is_jump_target=True), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=200, starts_line=25, is_jump_target=True), + Instruction(opname='SETUP_WITH', opcode=143, arg=17, argval=223, argrepr='to 223', offset=203, starts_line=None, is_jump_target=False), + Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=206, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=209, starts_line=26, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=212, starts_line=None, is_jump_target=False), + Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=215, starts_line=None, is_jump_target=False), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=218, starts_line=None, is_jump_target=False), + Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=219, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=220, starts_line=None, is_jump_target=False), + Instruction(opname='WITH_CLEANUP', opcode=81, arg=None, argval=None, argrepr='', offset=223, starts_line=None, is_jump_target=True), + Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=224, starts_line=None, is_jump_target=False), + Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=225, starts_line=None, is_jump_target=True), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=226, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=229, starts_line=28, is_jump_target=True), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=232, starts_line=None, is_jump_target=False), + Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=235, starts_line=None, is_jump_target=False), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=238, starts_line=None, is_jump_target=False), + Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=239, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=240, starts_line=None, is_jump_target=False), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=243, starts_line=None, is_jump_target=False), +] + +class InstructionTests(BytecodeTestCase): + def test_outer(self): + self.assertBytecodeExactlyMatches(outer, expected_opinfo_outer, + line_offset=expected_outer_offset) + + def test_nested(self): + with captured_stdout(): + f = outer() + self.assertBytecodeExactlyMatches(f, expected_opinfo_f, + line_offset=expected_outer_offset) + + def test_doubly_nested(self): + with captured_stdout(): + inner = outer()() + self.assertBytecodeExactlyMatches(inner, expected_opinfo_inner, + line_offset=expected_outer_offset) + + def test_jumpy(self): + self.assertBytecodeExactlyMatches(jumpy, expected_opinfo_jumpy, + line_offset=expected_jumpy_offset) + +class BytecodeTests(unittest.TestCase): + def test_instantiation(self): + # Test with function, method, code string and code object + for obj in [_f, _C(1).__init__, "a=1", _f.__code__]: + b = dis.Bytecode(obj) + self.assertIsInstance(b.codeobj, types.CodeType) + + self.assertRaises(TypeError, dis.Bytecode, object()) + + def test_iteration(self): + b = dis.Bytecode(_f) + for instr in b: + self.assertIsInstance(instr, dis.Instruction) + + assert len(list(b)) > 0 # Iterating should yield at least 1 instruction + + def test_info(self): + self.maxDiff = 1000 + for x, expected in CodeInfoTests.test_pairs: + b = dis.Bytecode(x) + self.assertRegex(b.info(), expected) + + def test_display_code(self): + b = dis.Bytecode(_f) + output = io.StringIO() + b.display_code(file=output) + result = [line.rstrip() for line in output.getvalue().splitlines()] + self.assertEqual(result, dis_f.splitlines()) + + def test_main(): - run_unittest(DisTests, CodeInfoTests) + run_unittest(DisTests, CodeInfoTests, InstructionTests, BytecodeTests) if __name__ == "__main__": test_main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -74,6 +74,10 @@ Library ------- +- Issue #11816: multiple improvements to the dis module: get_instructions + generator, ability to redirect output to a file, Bytecode and Instruction + abstractions. Patch by Nick Coghlan, Ryan Kelly and Thomas Kluyver. + - Issue #13831: Embed stringification of remote traceback in local traceback raised when pool task raises an exception. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 16:03:14 2013 From: python-checkins at python.org (nick.coghlan) Date: Mon, 6 May 2013 16:03:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2311816=3A_switch_t?= =?utf-8?q?est=5Fpeepholer_to_bytecode=5Fhelper?= Message-ID: <3b45JL1VRWzNbN@mail.python.org> http://hg.python.org/cpython/rev/d3fee4c64654 changeset: 83645:d3fee4c64654 user: Nick Coghlan date: Tue May 07 00:03:00 2013 +1000 summary: Issue #11816: switch test_peepholer to bytecode_helper files: Lib/test/test_peepholer.py | 295 +++++++++++------------- 1 files changed, 139 insertions(+), 156 deletions(-) diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -5,44 +5,28 @@ import unittest from math import copysign -def disassemble(func): - f = StringIO() - tmp = sys.stdout - sys.stdout = f - try: - dis.dis(func) - finally: - sys.stdout = tmp - result = f.getvalue() - f.close() - return result +from test.bytecode_helper import BytecodeTestCase -def dis_single(line): - return disassemble(compile(line, '', 'single')) - - -class TestTranforms(unittest.TestCase): +class TestTranforms(BytecodeTestCase): def test_unot(self): # UNARY_NOT POP_JUMP_IF_FALSE --> POP_JUMP_IF_TRUE' def unot(x): if not x == 2: del x - asm = disassemble(unot) - for elem in ('UNARY_NOT', 'POP_JUMP_IF_FALSE'): - self.assertNotIn(elem, asm) - for elem in ('POP_JUMP_IF_TRUE',): - self.assertIn(elem, asm) + self.assertNotInBytecode(unot, 'UNARY_NOT') + self.assertNotInBytecode(unot, 'POP_JUMP_IF_FALSE') + self.assertInBytecode(unot, 'POP_JUMP_IF_TRUE') def test_elim_inversion_of_is_or_in(self): - for line, elem in ( - ('not a is b', '(is not)',), - ('not a in b', '(not in)',), - ('not a is not b', '(is)',), - ('not a not in b', '(in)',), + for line, cmp_op in ( + ('not a is b', 'is not',), + ('not a in b', 'not in',), + ('not a is not b', 'is',), + ('not a not in b', 'in',), ): - asm = dis_single(line) - self.assertIn(elem, asm) + code = compile(line, '', 'single') + self.assertInBytecode(code, 'COMPARE_OP', cmp_op) def test_global_as_constant(self): # LOAD_GLOBAL None/True/False --> LOAD_CONST None/True/False @@ -56,17 +40,14 @@ def h(x): False return x - for func, name in ((f, 'None'), (g, 'True'), (h, 'False')): - asm = disassemble(func) - for elem in ('LOAD_GLOBAL',): - self.assertNotIn(elem, asm) - for elem in ('LOAD_CONST', '('+name+')'): - self.assertIn(elem, asm) + for func, elem in ((f, None), (g, True), (h, False)): + self.assertNotInBytecode(func, 'LOAD_GLOBAL') + self.assertInBytecode(func, 'LOAD_CONST', elem) def f(): 'Adding a docstring made this test fail in Py2.5.0' return None - self.assertIn('LOAD_CONST', disassemble(f)) - self.assertNotIn('LOAD_GLOBAL', disassemble(f)) + self.assertNotInBytecode(f, 'LOAD_GLOBAL') + self.assertInBytecode(f, 'LOAD_CONST', None) def test_while_one(self): # Skip over: LOAD_CONST trueconst POP_JUMP_IF_FALSE xx @@ -74,11 +55,10 @@ while 1: pass return list - asm = disassemble(f) for elem in ('LOAD_CONST', 'POP_JUMP_IF_FALSE'): - self.assertNotIn(elem, asm) + self.assertNotInBytecode(f, elem) for elem in ('JUMP_ABSOLUTE',): - self.assertIn(elem, asm) + self.assertInBytecode(f, elem) def test_pack_unpack(self): for line, elem in ( @@ -86,28 +66,30 @@ ('a, b = a, b', 'ROT_TWO',), ('a, b, c = a, b, c', 'ROT_THREE',), ): - asm = dis_single(line) - self.assertIn(elem, asm) - self.assertNotIn('BUILD_TUPLE', asm) - self.assertNotIn('UNPACK_TUPLE', asm) + code = compile(line,'','single') + self.assertInBytecode(code, elem) + self.assertNotInBytecode(code, 'BUILD_TUPLE') + self.assertNotInBytecode(code, 'UNPACK_TUPLE') def test_folding_of_tuples_of_constants(self): for line, elem in ( - ('a = 1,2,3', '((1, 2, 3))'), - ('("a","b","c")', "(('a', 'b', 'c'))"), - ('a,b,c = 1,2,3', '((1, 2, 3))'), - ('(None, 1, None)', '((None, 1, None))'), - ('((1, 2), 3, 4)', '(((1, 2), 3, 4))'), + ('a = 1,2,3', (1, 2, 3)), + ('("a","b","c")', ('a', 'b', 'c')), + ('a,b,c = 1,2,3', (1, 2, 3)), + ('(None, 1, None)', (None, 1, None)), + ('((1, 2), 3, 4)', ((1, 2), 3, 4)), ): - asm = dis_single(line) - self.assertIn(elem, asm) - self.assertNotIn('BUILD_TUPLE', asm) + code = compile(line,'','single') + self.assertInBytecode(code, 'LOAD_CONST', elem) + self.assertNotInBytecode(code, 'BUILD_TUPLE') # Long tuples should be folded too. - asm = dis_single(repr(tuple(range(10000)))) + code = compile(repr(tuple(range(10000))),'','single') + self.assertNotInBytecode(code, 'BUILD_TUPLE') # One LOAD_CONST for the tuple, one for the None return value - self.assertEqual(asm.count('LOAD_CONST'), 2) - self.assertNotIn('BUILD_TUPLE', asm) + load_consts = [instr for instr in dis.get_instructions(code) + if instr.opname == 'LOAD_CONST'] + self.assertEqual(len(load_consts), 2) # Bug 1053819: Tuple of constants misidentified when presented with: # . . . opcode_with_arg 100 unary_opcode BUILD_TUPLE 1 . . . @@ -129,14 +111,14 @@ def test_folding_of_lists_of_constants(self): for line, elem in ( # in/not in constants with BUILD_LIST should be folded to a tuple: - ('a in [1,2,3]', '(1, 2, 3)'), - ('a not in ["a","b","c"]', "(('a', 'b', 'c'))"), - ('a in [None, 1, None]', '((None, 1, None))'), - ('a not in [(1, 2), 3, 4]', '(((1, 2), 3, 4))'), + ('a in [1,2,3]', (1, 2, 3)), + ('a not in ["a","b","c"]', ('a', 'b', 'c')), + ('a in [None, 1, None]', (None, 1, None)), + ('a not in [(1, 2), 3, 4]', ((1, 2), 3, 4)), ): - asm = dis_single(line) - self.assertIn(elem, asm) - self.assertNotIn('BUILD_LIST', asm) + code = compile(line, '', 'single') + self.assertInBytecode(code, 'LOAD_CONST', elem) + self.assertNotInBytecode(code, 'BUILD_LIST') def test_folding_of_sets_of_constants(self): for line, elem in ( @@ -147,18 +129,9 @@ ('a not in {(1, 2), 3, 4}', frozenset({(1, 2), 3, 4})), ('a in {1, 2, 3, 3, 2, 1}', frozenset({1, 2, 3})), ): - asm = dis_single(line) - self.assertNotIn('BUILD_SET', asm) - - # Verify that the frozenset 'elem' is in the disassembly - # The ordering of the elements in repr( frozenset ) isn't - # guaranteed, so we jump through some hoops to ensure that we have - # the frozenset we expect: - self.assertIn('frozenset', asm) - # Extract the frozenset literal from the disassembly: - m = re.match(r'.*(frozenset\({.*}\)).*', asm, re.DOTALL) - self.assertTrue(m) - self.assertEqual(eval(m.group(1)), elem) + code = compile(line, '', 'single') + self.assertNotInBytecode(code, 'BUILD_SET') + self.assertInBytecode(code, 'LOAD_CONST', elem) # Ensure that the resulting code actually works: def f(a): @@ -176,98 +149,103 @@ def test_folding_of_binops_on_constants(self): for line, elem in ( - ('a = 2+3+4', '(9)'), # chained fold - ('"@"*4', "('@@@@')"), # check string ops - ('a="abc" + "def"', "('abcdef')"), # check string ops - ('a = 3**4', '(81)'), # binary power - ('a = 3*4', '(12)'), # binary multiply - ('a = 13//4', '(3)'), # binary floor divide - ('a = 14%4', '(2)'), # binary modulo - ('a = 2+3', '(5)'), # binary add - ('a = 13-4', '(9)'), # binary subtract - ('a = (12,13)[1]', '(13)'), # binary subscr - ('a = 13 << 2', '(52)'), # binary lshift - ('a = 13 >> 2', '(3)'), # binary rshift - ('a = 13 & 7', '(5)'), # binary and - ('a = 13 ^ 7', '(10)'), # binary xor - ('a = 13 | 7', '(15)'), # binary or + ('a = 2+3+4', 9), # chained fold + ('"@"*4', '@@@@'), # check string ops + ('a="abc" + "def"', 'abcdef'), # check string ops + ('a = 3**4', 81), # binary power + ('a = 3*4', 12), # binary multiply + ('a = 13//4', 3), # binary floor divide + ('a = 14%4', 2), # binary modulo + ('a = 2+3', 5), # binary add + ('a = 13-4', 9), # binary subtract + ('a = (12,13)[1]', 13), # binary subscr + ('a = 13 << 2', 52), # binary lshift + ('a = 13 >> 2', 3), # binary rshift + ('a = 13 & 7', 5), # binary and + ('a = 13 ^ 7', 10), # binary xor + ('a = 13 | 7', 15), # binary or ): - asm = dis_single(line) - self.assertIn(elem, asm, asm) - self.assertNotIn('BINARY_', asm) + code = compile(line, '', 'single') + self.assertInBytecode(code, 'LOAD_CONST', elem) + for instr in dis.get_instructions(code): + self.assertFalse(instr.opname.startswith('BINARY_')) # Verify that unfoldables are skipped - asm = dis_single('a=2+"b"') - self.assertIn('(2)', asm) - self.assertIn("('b')", asm) + code = compile('a=2+"b"', '', 'single') + self.assertInBytecode(code, 'LOAD_CONST', 2) + self.assertInBytecode(code, 'LOAD_CONST', 'b') # Verify that large sequences do not result from folding - asm = dis_single('a="x"*1000') - self.assertIn('(1000)', asm) + code = compile('a="x"*1000', '', 'single') + self.assertInBytecode(code, 'LOAD_CONST', 1000) def test_binary_subscr_on_unicode(self): # valid code get optimized - asm = dis_single('"foo"[0]') - self.assertIn("('f')", asm) - self.assertNotIn('BINARY_SUBSCR', asm) - asm = dis_single('"\u0061\uffff"[1]') - self.assertIn("('\\uffff')", asm) - self.assertNotIn('BINARY_SUBSCR', asm) - asm = dis_single('"\U00012345abcdef"[3]') - self.assertIn("('c')", asm) - self.assertNotIn('BINARY_SUBSCR', asm) + code = compile('"foo"[0]', '', 'single') + self.assertInBytecode(code, 'LOAD_CONST', 'f') + self.assertNotInBytecode(code, 'BINARY_SUBSCR') + code = compile('"\u0061\uffff"[1]', '', 'single') + self.assertInBytecode(code, 'LOAD_CONST', '\uffff') + self.assertNotInBytecode(code,'BINARY_SUBSCR') + + # With PEP 393, non-BMP char get optimized + code = compile('"\U00012345"[0]', '', 'single') + self.assertInBytecode(code, 'LOAD_CONST', '\U00012345') + self.assertNotInBytecode(code, 'BINARY_SUBSCR') # invalid code doesn't get optimized # out of range - asm = dis_single('"fuu"[10]') - self.assertIn('BINARY_SUBSCR', asm) + code = compile('"fuu"[10]', '', 'single') + self.assertInBytecode(code, 'BINARY_SUBSCR') def test_folding_of_unaryops_on_constants(self): for line, elem in ( - ('-0.5', '(-0.5)'), # unary negative - ('-0.0', '(-0.0)'), # -0.0 - ('-(1.0-1.0)','(-0.0)'), # -0.0 after folding - ('-0', '(0)'), # -0 - ('~-2', '(1)'), # unary invert - ('+1', '(1)'), # unary positive + ('-0.5', -0.5), # unary negative + ('-0.0', -0.0), # -0.0 + ('-(1.0-1.0)', -0.0), # -0.0 after folding + ('-0', 0), # -0 + ('~-2', 1), # unary invert + ('+1', 1), # unary positive ): - asm = dis_single(line) - self.assertIn(elem, asm, asm) - self.assertNotIn('UNARY_', asm) + code = compile(line, '', 'single') + self.assertInBytecode(code, 'LOAD_CONST', elem) + for instr in dis.get_instructions(code): + self.assertFalse(instr.opname.startswith('UNARY_')) # Check that -0.0 works after marshaling def negzero(): return -(1.0-1.0) - self.assertNotIn('UNARY_', disassemble(negzero)) - self.assertTrue(copysign(1.0, negzero()) < 0) + for instr in dis.get_instructions(code): + self.assertFalse(instr.opname.startswith('UNARY_')) # Verify that unfoldables are skipped - for line, elem in ( - ('-"abc"', "('abc')"), # unary negative - ('~"abc"', "('abc')"), # unary invert + for line, elem, opname in ( + ('-"abc"', 'abc', 'UNARY_NEGATIVE'), + ('~"abc"', 'abc', 'UNARY_INVERT'), ): - asm = dis_single(line) - self.assertIn(elem, asm, asm) - self.assertIn('UNARY_', asm) + code = compile(line, '', 'single') + self.assertInBytecode(code, 'LOAD_CONST', elem) + self.assertInBytecode(code, opname) def test_elim_extra_return(self): # RETURN LOAD_CONST None RETURN --> RETURN def f(x): return x - asm = disassemble(f) - self.assertNotIn('LOAD_CONST', asm) - self.assertNotIn('(None)', asm) - self.assertEqual(asm.split().count('RETURN_VALUE'), 1) + self.assertNotInBytecode(f, 'LOAD_CONST', None) + returns = [instr for instr in dis.get_instructions(f) + if instr.opname == 'RETURN_VALUE'] + self.assertEqual(len(returns), 1) def test_elim_jump_to_return(self): # JUMP_FORWARD to RETURN --> RETURN def f(cond, true_value, false_value): return true_value if cond else false_value - asm = disassemble(f) - self.assertNotIn('JUMP_FORWARD', asm) - self.assertNotIn('JUMP_ABSOLUTE', asm) - self.assertEqual(asm.split().count('RETURN_VALUE'), 2) + self.assertNotInBytecode(f, 'JUMP_FORWARD') + self.assertNotInBytecode(f, 'JUMP_ABSOLUTE') + returns = [instr for instr in dis.get_instructions(f) + if instr.opname == 'RETURN_VALUE'] + self.assertEqual(len(returns), 2) def test_elim_jump_after_return1(self): # Eliminate dead code: jumps immediately after returns can't be reached @@ -280,48 +258,53 @@ if cond1: return 4 return 5 return 6 - asm = disassemble(f) - self.assertNotIn('JUMP_FORWARD', asm) - self.assertNotIn('JUMP_ABSOLUTE', asm) - self.assertEqual(asm.split().count('RETURN_VALUE'), 6) + self.assertNotInBytecode(f, 'JUMP_FORWARD') + self.assertNotInBytecode(f, 'JUMP_ABSOLUTE') + returns = [instr for instr in dis.get_instructions(f) + if instr.opname == 'RETURN_VALUE'] + self.assertEqual(len(returns), 6) def test_elim_jump_after_return2(self): # Eliminate dead code: jumps immediately after returns can't be reached def f(cond1, cond2): while 1: if cond1: return 4 - asm = disassemble(f) - self.assertNotIn('JUMP_FORWARD', asm) + self.assertNotInBytecode(f, 'JUMP_FORWARD') # There should be one jump for the while loop. - self.assertEqual(asm.split().count('JUMP_ABSOLUTE'), 1) - self.assertEqual(asm.split().count('RETURN_VALUE'), 2) + returns = [instr for instr in dis.get_instructions(f) + if instr.opname == 'JUMP_ABSOLUTE'] + self.assertEqual(len(returns), 1) + returns = [instr for instr in dis.get_instructions(f) + if instr.opname == 'RETURN_VALUE'] + self.assertEqual(len(returns), 2) def test_make_function_doesnt_bail(self): def f(): def g()->1+1: pass return g - asm = disassemble(f) - self.assertNotIn('BINARY_ADD', asm) + self.assertNotInBytecode(f, 'BINARY_ADD') def test_constant_folding(self): # Issue #11244: aggressive constant folding. exprs = [ - "3 * -5", - "-3 * 5", - "2 * (3 * 4)", - "(2 * 3) * 4", - "(-1, 2, 3)", - "(1, -2, 3)", - "(1, 2, -3)", - "(1, 2, -3) * 6", - "lambda x: x in {(3 * -5) + (-1 - 6), (1, -2, 3) * 2, None}", + '3 * -5', + '-3 * 5', + '2 * (3 * 4)', + '(2 * 3) * 4', + '(-1, 2, 3)', + '(1, -2, 3)', + '(1, 2, -3)', + '(1, 2, -3) * 6', + 'lambda x: x in {(3 * -5) + (-1 - 6), (1, -2, 3) * 2, None}', ] for e in exprs: - asm = dis_single(e) - self.assertNotIn('UNARY_', asm, e) - self.assertNotIn('BINARY_', asm, e) - self.assertNotIn('BUILD_', asm, e) + code = compile(e, '', 'single') + for instr in dis.get_instructions(code): + self.assertFalse(instr.opname.startswith('UNARY_')) + self.assertFalse(instr.opname.startswith('BINARY_')) + self.assertFalse(instr.opname.startswith('BUILD_')) + class TestBuglets(unittest.TestCase): @@ -343,7 +326,7 @@ support.run_unittest(*test_classes) # verify reference counting - if verbose and hasattr(sys, "gettotalrefcount"): + if verbose and hasattr(sys, 'gettotalrefcount'): import gc counts = [None] * 5 for i in range(len(counts)): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 18:59:27 2013 From: python-checkins at python.org (r.david.murray) Date: Mon, 6 May 2013 18:59:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE0MTg3OiBBZGQg?= =?utf-8?q?glossary_entry_for_=27function_annotations=27=2E?= Message-ID: <3b49Cg3qpZzNbN@mail.python.org> http://hg.python.org/cpython/rev/e2a805281d26 changeset: 83646:e2a805281d26 branch: 3.3 parent: 83640:bb4bb2db6106 user: R David Murray date: Mon May 06 12:58:16 2013 -0400 summary: #14187: Add glossary entry for 'function annotations'. Patch by Chris Rebert. files: Doc/glossary.rst | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -252,6 +252,16 @@ the execution of the body. See also :term:`parameter`, :term:`method`, and the :ref:`function` section. + function annotation + An arbitrary metadata value associated with a function parameter or return + value. Its syntax is explained in section :ref:`function`. Annotations + may be accessed via the :attr:`__annotations__` special attribute of a + function object. + + Python itself does not assign any particular meaning to function + annotations. They are intended to be interpreted by third-party libraries + or tools. See :pep:`3107`, which describes some of their potential uses. + __future__ A pseudo-module which programmers can use to enable new language features which are not compatible with the current interpreter. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 18:59:28 2013 From: python-checkins at python.org (r.david.murray) Date: Mon, 6 May 2013 18:59:28 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_=2314187=3A_Add_glossary_entry_for_=27function_ann?= =?utf-8?q?otations=27=2E?= Message-ID: <3b49Ch64GQzNgv@mail.python.org> http://hg.python.org/cpython/rev/3e1c45f5c585 changeset: 83647:3e1c45f5c585 parent: 83645:d3fee4c64654 parent: 83646:e2a805281d26 user: R David Murray date: Mon May 06 12:58:41 2013 -0400 summary: Merge #14187: Add glossary entry for 'function annotations'. Patch by Chris Rebert. files: Doc/glossary.rst | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -252,6 +252,16 @@ the execution of the body. See also :term:`parameter`, :term:`method`, and the :ref:`function` section. + function annotation + An arbitrary metadata value associated with a function parameter or return + value. Its syntax is explained in section :ref:`function`. Annotations + may be accessed via the :attr:`__annotations__` special attribute of a + function object. + + Python itself does not assign any particular meaning to function + annotations. They are intended to be interpreted by third-party libraries + or tools. See :pep:`3107`, which describes some of their potential uses. + __future__ A pseudo-module which programmers can use to enable new language features which are not compatible with the current interpreter. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 20:51:42 2013 From: python-checkins at python.org (david.malcolm) Date: Mon, 6 May 2013 20:51:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE3ODMzOiBmaXgg?= =?utf-8?q?test=5Fgdb_failures_seen_on_PPC64_Linux_in_test=5Fthreads?= Message-ID: <3b4CjB0R0JzPq8@mail.python.org> http://hg.python.org/cpython/rev/f4a6b731905a changeset: 83648:f4a6b731905a branch: 3.3 parent: 83646:e2a805281d26 user: David Malcolm date: Mon May 06 14:47:15 2013 -0400 summary: #17833: fix test_gdb failures seen on PPC64 Linux in test_threads (test.test_gdb.PyBtTests) files: Misc/NEWS | 3 +++ Tools/gdb/libpython.py | 2 +- 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -168,6 +168,9 @@ Tests ----- +- Issue #17833: Fix test_gdb failures seen on machines where debug symbols + for glibc are available (seen on PPC64 Linux). + - Issue #7855: Add tests for ctypes/winreg for issues found in IronPython. Initial patch by Dino Viehland. diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -1460,7 +1460,7 @@ # This assumes the _POSIX_THREADS version of Python/ceval_gil.h: name = self._gdbframe.name() if name: - return name.startswith('pthread_cond_timedwait') + return 'pthread_cond_timedwait' in name def is_gc_collect(self): '''Is this frame "collect" within the garbage-collector?''' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 20:51:43 2013 From: python-checkins at python.org (david.malcolm) Date: Mon, 6 May 2013 20:51:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_=2317833=3A_merge_with_3=2E3?= Message-ID: <3b4CjC2ht7zPq8@mail.python.org> http://hg.python.org/cpython/rev/6d971b172389 changeset: 83649:6d971b172389 parent: 83647:3e1c45f5c585 parent: 83648:f4a6b731905a user: David Malcolm date: Mon May 06 14:51:13 2013 -0400 summary: #17833: merge with 3.3 files: Misc/NEWS | 3 +++ Tools/gdb/libpython.py | 2 +- 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -215,6 +215,9 @@ Tests ----- +- Issue #17833: Fix test_gdb failures seen on machines where debug symbols + for glibc are available (seen on PPC64 Linux). + - Issue #7855: Add tests for ctypes/winreg for issues found in IronPython. Initial patch by Dino Viehland. diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -1462,7 +1462,7 @@ # This assumes the _POSIX_THREADS version of Python/ceval_gil.h: name = self._gdbframe.name() if name: - return name.startswith('pthread_cond_timedwait') + return 'pthread_cond_timedwait' in name def is_gc_collect(self): '''Is this frame "collect" within the garbage-collector?''' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 21:17:21 2013 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 6 May 2013 21:17:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=231545463=3A_Global?= =?utf-8?q?_variables_caught_in_reference_cycles_are_now?= Message-ID: <3b4DGn3GwBzPtG@mail.python.org> http://hg.python.org/cpython/rev/f0833e6ff2d2 changeset: 83650:f0833e6ff2d2 user: Antoine Pitrou date: Mon May 06 21:15:57 2013 +0200 summary: Issue #1545463: Global variables caught in reference cycles are now garbage-collected at shutdown. files: Include/pythonrun.h | 1 + Lib/test/test_gc.py | 36 +++++++++++++++++++++++++++++++++ Misc/NEWS | 3 ++ Modules/gcmodule.c | 8 ++++++- Python/import.c | 8 +++++++ Python/pythonrun.c | 5 +--- 6 files changed, 56 insertions(+), 5 deletions(-) diff --git a/Include/pythonrun.h b/Include/pythonrun.h --- a/Include/pythonrun.h +++ b/Include/pythonrun.h @@ -217,6 +217,7 @@ 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); diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py --- a/Lib/test/test_gc.py +++ b/Lib/test/test_gc.py @@ -1,6 +1,8 @@ import unittest from test.support import (verbose, refcount_test, run_unittest, strip_python_stderr) +from test.script_helper import assert_python_ok, make_script, temp_dir + import sys import time import gc @@ -610,6 +612,40 @@ stderr = run_command(code % "gc.DEBUG_SAVEALL") self.assertNotIn(b"uncollectable objects at shutdown", stderr) + def test_gc_main_module_at_shutdown(self): + # Create a reference cycle through the __main__ module and check + # it gets collected at interpreter shutdown. + code = """if 1: + import weakref + class C: + def __del__(self): + print('__del__ called') + l = [C()] + l.append(l) + """ + rc, out, err = assert_python_ok('-c', code) + self.assertEqual(out.strip(), b'__del__ called') + + def test_gc_ordinary_module_at_shutdown(self): + # Same as above, but with a non-__main__ module. + with temp_dir() as script_dir: + module = """if 1: + import weakref + class C: + def __del__(self): + print('__del__ called') + l = [C()] + l.append(l) + """ + code = """if 1: + import sys + sys.path.insert(0, %r) + import gctest + """ % (script_dir,) + make_script(script_dir, 'gctest', module) + rc, out, err = assert_python_ok('-c', code) + self.assertEqual(out.strip(), b'__del__ called') + def test_get_stats(self): stats = gc.get_stats() self.assertEqual(len(stats), 3) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #1545463: Global variables caught in reference cycles are now + garbage-collected at shutdown. + - Issue #17094: Clear stale thread states after fork(). Note that this is a potentially disruptive change since it may release some system resources which would otherwise remain perpetually alive (e.g. database diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1544,8 +1544,9 @@ return n; } + void -_PyGC_Fini(void) +_PyGC_DumpShutdownStats(void) { if (!(debug & DEBUG_SAVEALL) && garbage != NULL && PyList_GET_SIZE(garbage) > 0) { @@ -1574,6 +1575,11 @@ Py_XDECREF(bytes); } } +} + +void +_PyGC_Fini(void) +{ Py_CLEAR(callbacks); } diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -403,6 +403,14 @@ } } + /* Collect garbage remaining after deleting the modules. Mostly + reference cycles created by classes. */ + PyGC_Collect(); + + /* Dump GC stats before it's too late, since it uses the warnings + machinery. */ + _PyGC_DumpShutdownStats(); + /* Next, delete sys and builtins (in that order) */ value = PyDict_GetItemString(modules, "sys"); if (value != NULL && PyModule_Check(value)) { diff --git a/Python/pythonrun.c b/Python/pythonrun.c --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -544,10 +544,6 @@ while (PyGC_Collect() > 0) /* nothing */; #endif - /* We run this while most interpreter state is still alive, so that - debug information can be printed out */ - _PyGC_Fini(); - /* Destroy all modules */ PyImport_Cleanup(); @@ -628,6 +624,7 @@ PyFloat_Fini(); PyDict_Fini(); PySlice_Fini(); + _PyGC_Fini(); /* Cleanup Unicode implementation */ _PyUnicode_Fini(); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 21:26:51 2013 From: python-checkins at python.org (charles-francois.natali) Date: Mon, 6 May 2013 21:26:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzEyMTgx?= =?utf-8?q?=3A_select_module=3A_Fix_struct_kevent_definition_on_OpenBSD_64?= =?utf-8?q?-bit?= Message-ID: <3b4DTl4v5lzMp1@mail.python.org> http://hg.python.org/cpython/rev/c6c2b216bd14 changeset: 83651:c6c2b216bd14 branch: 2.7 parent: 83639:2684176519ef user: Charles-Francois Natali date: Mon May 06 21:21:57 2013 +0200 summary: Issue #12181: select module: Fix struct kevent definition on OpenBSD 64-bit platforms. Patch by Federico Schwindt. files: Misc/NEWS | 3 ++ Modules/selectmodule.c | 35 ++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,9 @@ Library ------- +- Issue #12181: select module: Fix struct kevent definition on OpenBSD 64-bit + platforms. Patch by Federico Schwindt. + - Issue #14173: Avoid crashing when reading a signal handler during interpreter shutdown. diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -1203,6 +1203,23 @@ # error uintptr_t does not match int, long, or long long! #endif +/* + * kevent is not standard and its members vary across BSDs. + */ +#if !defined(__OpenBSD__) +# define IDENT_TYPE T_UINTPTRT +# define IDENT_CAST Py_intptr_t +# define DATA_TYPE T_INTPTRT +# define DATA_FMT_UNIT INTPTRT_FMT_UNIT +# define IDENT_AsType PyLong_AsUintptr_t +#else +# define IDENT_TYPE T_UINT +# define IDENT_CAST int +# define DATA_TYPE T_INT +# define DATA_FMT_UNIT "i" +# define IDENT_AsType PyLong_AsUnsignedLong +#endif + /* Unfortunately, we can't store python objects in udata, because * kevents in the kernel can be removed without warning, which would * forever lose the refcount on the object stored with it. @@ -1210,11 +1227,11 @@ #define KQ_OFF(x) offsetof(kqueue_event_Object, x) static struct PyMemberDef kqueue_event_members[] = { - {"ident", T_UINTPTRT, KQ_OFF(e.ident)}, + {"ident", IDENT_TYPE, KQ_OFF(e.ident)}, {"filter", T_SHORT, KQ_OFF(e.filter)}, {"flags", T_USHORT, KQ_OFF(e.flags)}, {"fflags", T_UINT, KQ_OFF(e.fflags)}, - {"data", T_INTPTRT, KQ_OFF(e.data)}, + {"data", DATA_TYPE, KQ_OFF(e.data)}, {"udata", T_UINTPTRT, KQ_OFF(e.udata)}, {NULL} /* Sentinel */ }; @@ -1240,7 +1257,7 @@ PyObject *pfd; static char *kwlist[] = {"ident", "filter", "flags", "fflags", "data", "udata", NULL}; - static char *fmt = "O|hhi" INTPTRT_FMT_UNIT UINTPTRT_FMT_UNIT ":kevent"; + static char *fmt = "O|hhi" DATA_FMT_UNIT UINTPTRT_FMT_UNIT ":kevent"; EV_SET(&(self->e), 0, EVFILT_READ, EV_ADD, 0, 0, 0); /* defaults */ @@ -1250,8 +1267,12 @@ return -1; } - if (PyLong_Check(pfd)) { - self->e.ident = PyLong_AsUintptr_t(pfd); + if (PyLong_Check(pfd) +#if IDENT_TYPE == T_UINT + && PyLong_AsUnsignedLong(pfd) <= UINT_MAX +#endif + ) { + self->e.ident = IDENT_AsType(pfd); } else { self->e.ident = PyObject_AsFileDescriptor(pfd); @@ -1279,10 +1300,10 @@ Py_TYPE(s)->tp_name, Py_TYPE(o)->tp_name); return NULL; } - if (((result = s->e.ident - o->e.ident) == 0) && + if (((result = (IDENT_CAST)(s->e.ident - o->e.ident)) == 0) && ((result = s->e.filter - o->e.filter) == 0) && ((result = s->e.flags - o->e.flags) == 0) && - ((result = s->e.fflags - o->e.fflags) == 0) && + ((result = (int)(s->e.fflags - o->e.fflags)) == 0) && ((result = s->e.data - o->e.data) == 0) && ((result = s->e.udata - o->e.udata) == 0) ) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 21:26:53 2013 From: python-checkins at python.org (charles-francois.natali) Date: Mon, 6 May 2013 21:26:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzEyMTgx?= =?utf-8?q?=3A_select_module=3A_Fix_struct_kevent_definition_on_OpenBSD_64?= =?utf-8?q?-bit?= Message-ID: <3b4DTn0DpqzPhP@mail.python.org> http://hg.python.org/cpython/rev/f6c50b437de6 changeset: 83652:f6c50b437de6 branch: 3.3 parent: 83648:f4a6b731905a user: Charles-Francois Natali date: Mon May 06 21:24:31 2013 +0200 summary: Issue #12181: select module: Fix struct kevent definition on OpenBSD 64-bit platforms. Patch by Federico Schwindt. files: Misc/NEWS | 3 ++ Modules/selectmodule.c | 35 ++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -47,6 +47,9 @@ Library ------- +- Issue #12181: select module: Fix struct kevent definition on OpenBSD 64-bit + platforms. Patch by Federico Schwindt. + - Issue #14173: Avoid crashing when reading a signal handler during interpreter shutdown. diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -1571,6 +1571,23 @@ # error uintptr_t does not match int, long, or long long! #endif +/* + * kevent is not standard and its members vary across BSDs. + */ +#if !defined(__OpenBSD__) +# define IDENT_TYPE T_UINTPTRT +# define IDENT_CAST Py_intptr_t +# define DATA_TYPE T_INTPTRT +# define DATA_FMT_UNIT INTPTRT_FMT_UNIT +# define IDENT_AsType PyLong_AsUintptr_t +#else +# define IDENT_TYPE T_UINT +# define IDENT_CAST int +# define DATA_TYPE T_INT +# define DATA_FMT_UNIT "i" +# define IDENT_AsType PyLong_AsUnsignedLong +#endif + /* Unfortunately, we can't store python objects in udata, because * kevents in the kernel can be removed without warning, which would * forever lose the refcount on the object stored with it. @@ -1578,11 +1595,11 @@ #define KQ_OFF(x) offsetof(kqueue_event_Object, x) static struct PyMemberDef kqueue_event_members[] = { - {"ident", T_UINTPTRT, KQ_OFF(e.ident)}, + {"ident", IDENT_TYPE, KQ_OFF(e.ident)}, {"filter", T_SHORT, KQ_OFF(e.filter)}, {"flags", T_USHORT, KQ_OFF(e.flags)}, {"fflags", T_UINT, KQ_OFF(e.fflags)}, - {"data", T_INTPTRT, KQ_OFF(e.data)}, + {"data", DATA_TYPE, KQ_OFF(e.data)}, {"udata", T_UINTPTRT, KQ_OFF(e.udata)}, {NULL} /* Sentinel */ }; @@ -1608,7 +1625,7 @@ PyObject *pfd; static char *kwlist[] = {"ident", "filter", "flags", "fflags", "data", "udata", NULL}; - static char *fmt = "O|hhi" INTPTRT_FMT_UNIT UINTPTRT_FMT_UNIT ":kevent"; + static char *fmt = "O|hhi" DATA_FMT_UNIT UINTPTRT_FMT_UNIT ":kevent"; EV_SET(&(self->e), 0, EVFILT_READ, EV_ADD, 0, 0, 0); /* defaults */ @@ -1618,8 +1635,12 @@ return -1; } - if (PyLong_Check(pfd)) { - self->e.ident = PyLong_AsUintptr_t(pfd); + if (PyLong_Check(pfd) +#if IDENT_TYPE == T_UINT + && PyLong_AsUnsignedLong(pfd) <= UINT_MAX +#endif + ) { + self->e.ident = IDENT_AsType(pfd); } else { self->e.ident = PyObject_AsFileDescriptor(pfd); @@ -1647,10 +1668,10 @@ Py_TYPE(s)->tp_name, Py_TYPE(o)->tp_name); return NULL; } - if (((result = s->e.ident - o->e.ident) == 0) && + if (((result = (IDENT_CAST)(s->e.ident - o->e.ident)) == 0) && ((result = s->e.filter - o->e.filter) == 0) && ((result = s->e.flags - o->e.flags) == 0) && - ((result = s->e.fflags - o->e.fflags) == 0) && + ((result = (int)(s->e.fflags - o->e.fflags)) == 0) && ((result = s->e.data - o->e.data) == 0) && ((result = s->e.udata - o->e.udata) == 0) ) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 21:26:54 2013 From: python-checkins at python.org (charles-francois.natali) Date: Mon, 6 May 2013 21:26:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2312181=3A_select_module=3A_Fix_struct_kevent_def?= =?utf-8?q?inition_on_OpenBSD_64-bit?= Message-ID: <3b4DTp3lhYzQ3m@mail.python.org> http://hg.python.org/cpython/rev/557599a32821 changeset: 83653:557599a32821 parent: 83650:f0833e6ff2d2 parent: 83652:f6c50b437de6 user: Charles-Francois Natali date: Mon May 06 21:26:05 2013 +0200 summary: Issue #12181: select module: Fix struct kevent definition on OpenBSD 64-bit platforms. Patch by Federico Schwindt. files: Misc/NEWS | 3 ++ Modules/selectmodule.c | 35 ++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -77,6 +77,9 @@ Library ------- +- Issue #12181: select module: Fix struct kevent definition on OpenBSD 64-bit + platforms. Patch by Federico Schwindt. + - Issue #11816: multiple improvements to the dis module: get_instructions generator, ability to redirect output to a file, Bytecode and Instruction abstractions. Patch by Nick Coghlan, Ryan Kelly and Thomas Kluyver. diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -1588,6 +1588,23 @@ # error uintptr_t does not match int, long, or long long! #endif +/* + * kevent is not standard and its members vary across BSDs. + */ +#if !defined(__OpenBSD__) +# define IDENT_TYPE T_UINTPTRT +# define IDENT_CAST Py_intptr_t +# define DATA_TYPE T_INTPTRT +# define DATA_FMT_UNIT INTPTRT_FMT_UNIT +# define IDENT_AsType PyLong_AsUintptr_t +#else +# define IDENT_TYPE T_UINT +# define IDENT_CAST int +# define DATA_TYPE T_INT +# define DATA_FMT_UNIT "i" +# define IDENT_AsType PyLong_AsUnsignedLong +#endif + /* Unfortunately, we can't store python objects in udata, because * kevents in the kernel can be removed without warning, which would * forever lose the refcount on the object stored with it. @@ -1595,11 +1612,11 @@ #define KQ_OFF(x) offsetof(kqueue_event_Object, x) static struct PyMemberDef kqueue_event_members[] = { - {"ident", T_UINTPTRT, KQ_OFF(e.ident)}, + {"ident", IDENT_TYPE, KQ_OFF(e.ident)}, {"filter", T_SHORT, KQ_OFF(e.filter)}, {"flags", T_USHORT, KQ_OFF(e.flags)}, {"fflags", T_UINT, KQ_OFF(e.fflags)}, - {"data", T_INTPTRT, KQ_OFF(e.data)}, + {"data", DATA_TYPE, KQ_OFF(e.data)}, {"udata", T_UINTPTRT, KQ_OFF(e.udata)}, {NULL} /* Sentinel */ }; @@ -1625,7 +1642,7 @@ PyObject *pfd; static char *kwlist[] = {"ident", "filter", "flags", "fflags", "data", "udata", NULL}; - static char *fmt = "O|hhi" INTPTRT_FMT_UNIT UINTPTRT_FMT_UNIT ":kevent"; + static char *fmt = "O|hhi" DATA_FMT_UNIT UINTPTRT_FMT_UNIT ":kevent"; EV_SET(&(self->e), 0, EVFILT_READ, EV_ADD, 0, 0, 0); /* defaults */ @@ -1635,8 +1652,12 @@ return -1; } - if (PyLong_Check(pfd)) { - self->e.ident = PyLong_AsUintptr_t(pfd); + if (PyLong_Check(pfd) +#if IDENT_TYPE == T_UINT + && PyLong_AsUnsignedLong(pfd) <= UINT_MAX +#endif + ) { + self->e.ident = IDENT_AsType(pfd); } else { self->e.ident = PyObject_AsFileDescriptor(pfd); @@ -1664,10 +1685,10 @@ Py_TYPE(s)->tp_name, Py_TYPE(o)->tp_name); return NULL; } - if (((result = s->e.ident - o->e.ident) == 0) && + if (((result = (IDENT_CAST)(s->e.ident - o->e.ident)) == 0) && ((result = s->e.filter - o->e.filter) == 0) && ((result = s->e.flags - o->e.flags) == 0) && - ((result = s->e.fflags - o->e.fflags) == 0) && + ((result = (int)(s->e.fflags - o->e.fflags)) == 0) && ((result = s->e.data - o->e.data) == 0) && ((result = s->e.udata - o->e.udata) == 0) ) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 21:51:13 2013 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 6 May 2013 21:51:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3Mjg5?= =?utf-8?q?=3A_The_readline_module_now_plays_nicer_with_external_modules_o?= =?utf-8?q?r?= Message-ID: <3b4F1s38GbzQGS@mail.python.org> http://hg.python.org/cpython/rev/55c7295aca6c changeset: 83654:55c7295aca6c branch: 2.7 parent: 83651:c6c2b216bd14 user: Antoine Pitrou date: Mon May 06 21:51:03 2013 +0200 summary: Issue #17289: The readline module now plays nicer with external modules or applications changing the rl_completer_word_break_characters global variable. Initial patch by Bradley Froehle. files: Misc/NEWS | 4 ++++ Modules/readline.c | 27 +++++++++++++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,10 @@ Library ------- +- Issue #17289: The readline module now plays nicer with external modules + or applications changing the rl_completer_word_break_characters global + variable. Initial patch by Bradley Froehle. + - Issue #12181: select module: Fix struct kevent definition on OpenBSD 64-bit platforms. Patch by Federico Schwindt. diff --git a/Modules/readline.c b/Modules/readline.c --- a/Modules/readline.c +++ b/Modules/readline.c @@ -69,6 +69,10 @@ int num_matches, int max_length); +/* Memory allocated for rl_completer_word_break_characters + (see issue #17289 for the motivation). */ +static char *completer_word_break_characters; + /* Exported function to send one line to readline's init file parser */ static PyObject * @@ -344,12 +348,20 @@ { char *break_chars; - if(!PyArg_ParseTuple(args, "s:set_completer_delims", &break_chars)) { + if (!PyArg_ParseTuple(args, "s:set_completer_delims", &break_chars)) { return NULL; } - free((void*)rl_completer_word_break_characters); - rl_completer_word_break_characters = strdup(break_chars); - Py_RETURN_NONE; + /* Keep a reference to the allocated memory in the module state in case + some other module modifies rl_completer_word_break_characters + (see issue #17289). */ + free(completer_word_break_characters); + completer_word_break_characters = strdup(break_chars); + if (completer_word_break_characters) { + rl_completer_word_break_characters = completer_word_break_characters; + Py_RETURN_NONE; + } + else + return PyErr_NoMemory(); } PyDoc_STRVAR(doc_set_completer_delims, @@ -893,7 +905,8 @@ /* Set our completion function */ rl_attempted_completion_function = (CPPFunction *)flex_complete; /* Set Python word break characters */ - rl_completer_word_break_characters = + completer_word_break_characters = + rl_completer_word_break_characters = strdup(" \t\n`~!@#$%^&*()-=+[{]}\\|;:'\",<>/?"); /* All nonalphanums except '.' */ @@ -906,7 +919,7 @@ */ #ifdef __APPLE__ if (using_libedit_emulation) - rl_read_init_file(NULL); + rl_read_init_file(NULL); else #endif /* __APPLE__ */ rl_initialize(); @@ -1137,8 +1150,6 @@ if (m == NULL) return; - - PyOS_ReadlineFunctionPointer = call_readline; setup_readline(); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 21:54:16 2013 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 6 May 2013 21:54:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3Mjg5?= =?utf-8?q?=3A_The_readline_module_now_plays_nicer_with_external_modules_o?= =?utf-8?q?r?= Message-ID: <3b4F5N4PZxzQHY@mail.python.org> http://hg.python.org/cpython/rev/df0afd3ebb70 changeset: 83655:df0afd3ebb70 branch: 3.3 parent: 83652:f6c50b437de6 user: Antoine Pitrou date: Mon May 06 21:51:03 2013 +0200 summary: Issue #17289: The readline module now plays nicer with external modules or applications changing the rl_completer_word_break_characters global variable. Initial patch by Bradley Froehle. files: Misc/NEWS | 4 ++++ Modules/readline.c | 25 ++++++++++++++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -47,6 +47,10 @@ Library ------- +- Issue #17289: The readline module now plays nicer with external modules + or applications changing the rl_completer_word_break_characters global + variable. Initial patch by Bradley Froehle. + - Issue #12181: select module: Fix struct kevent definition on OpenBSD 64-bit platforms. Patch by Federico Schwindt. diff --git a/Modules/readline.c b/Modules/readline.c --- a/Modules/readline.c +++ b/Modules/readline.c @@ -70,6 +70,10 @@ int num_matches, int max_length); #endif +/* Memory allocated for rl_completer_word_break_characters + (see issue #17289 for the motivation). */ +static char *completer_word_break_characters; + /* Exported function to send one line to readline's init file parser */ static PyObject * @@ -368,12 +372,20 @@ { char *break_chars; - if(!PyArg_ParseTuple(args, "s:set_completer_delims", &break_chars)) { + if (!PyArg_ParseTuple(args, "s:set_completer_delims", &break_chars)) { return NULL; } - free((void*)rl_completer_word_break_characters); - rl_completer_word_break_characters = strdup(break_chars); - Py_RETURN_NONE; + /* Keep a reference to the allocated memory in the module state in case + some other module modifies rl_completer_word_break_characters + (see issue #17289). */ + free(completer_word_break_characters); + completer_word_break_characters = strdup(break_chars); + if (completer_word_break_characters) { + rl_completer_word_break_characters = completer_word_break_characters; + Py_RETURN_NONE; + } + else + return PyErr_NoMemory(); } PyDoc_STRVAR(doc_set_completer_delims, @@ -918,7 +930,8 @@ /* Set our completion function */ rl_attempted_completion_function = (CPPFunction *)flex_complete; /* Set Python word break characters */ - rl_completer_word_break_characters = + completer_word_break_characters = + rl_completer_word_break_characters = strdup(" \t\n`~!@#$%^&*()-=+[{]}\\|;:'\",<>/?"); /* All nonalphanums except '.' */ @@ -1174,8 +1187,6 @@ if (m == NULL) return NULL; - - PyOS_ReadlineFunctionPointer = call_readline; setup_readline(); return m; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 21:54:18 2013 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 6 May 2013 21:54:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317289=3A_The_readline_module_now_plays_nicer_wi?= =?utf-8?q?th_external_modules_or?= Message-ID: <3b4F5Q0GSRzQXy@mail.python.org> http://hg.python.org/cpython/rev/0f65426009e2 changeset: 83656:0f65426009e2 parent: 83653:557599a32821 parent: 83655:df0afd3ebb70 user: Antoine Pitrou date: Mon May 06 21:54:07 2013 +0200 summary: Issue #17289: The readline module now plays nicer with external modules or applications changing the rl_completer_word_break_characters global variable. Initial patch by Bradley Froehle. files: Misc/NEWS | 4 ++++ Modules/readline.c | 25 ++++++++++++++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -77,6 +77,10 @@ Library ------- +- Issue #17289: The readline module now plays nicer with external modules + or applications changing the rl_completer_word_break_characters global + variable. Initial patch by Bradley Froehle. + - Issue #12181: select module: Fix struct kevent definition on OpenBSD 64-bit platforms. Patch by Federico Schwindt. diff --git a/Modules/readline.c b/Modules/readline.c --- a/Modules/readline.c +++ b/Modules/readline.c @@ -70,6 +70,10 @@ int num_matches, int max_length); #endif +/* Memory allocated for rl_completer_word_break_characters + (see issue #17289 for the motivation). */ +static char *completer_word_break_characters; + /* Exported function to send one line to readline's init file parser */ static PyObject * @@ -368,12 +372,20 @@ { char *break_chars; - if(!PyArg_ParseTuple(args, "s:set_completer_delims", &break_chars)) { + if (!PyArg_ParseTuple(args, "s:set_completer_delims", &break_chars)) { return NULL; } - free((void*)rl_completer_word_break_characters); - rl_completer_word_break_characters = strdup(break_chars); - Py_RETURN_NONE; + /* Keep a reference to the allocated memory in the module state in case + some other module modifies rl_completer_word_break_characters + (see issue #17289). */ + free(completer_word_break_characters); + completer_word_break_characters = strdup(break_chars); + if (completer_word_break_characters) { + rl_completer_word_break_characters = completer_word_break_characters; + Py_RETURN_NONE; + } + else + return PyErr_NoMemory(); } PyDoc_STRVAR(doc_set_completer_delims, @@ -914,7 +926,8 @@ /* Set our completion function */ rl_attempted_completion_function = (CPPFunction *)flex_complete; /* Set Python word break characters */ - rl_completer_word_break_characters = + completer_word_break_characters = + rl_completer_word_break_characters = strdup(" \t\n`~!@#$%^&*()-=+[{]}\\|;:'\",<>/?"); /* All nonalphanums except '.' */ @@ -1170,8 +1183,6 @@ if (m == NULL) return NULL; - - PyOS_ReadlineFunctionPointer = call_readline; setup_readline(); return m; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 22:15:44 2013 From: python-checkins at python.org (barry.warsaw) Date: Mon, 6 May 2013 22:15:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_A_few_PEP_435_clarifications?= =?utf-8?q?=2E?= Message-ID: <3b4FZ85PTFzMR5@mail.python.org> http://hg.python.org/peps/rev/1af9bc06972a changeset: 4876:1af9bc06972a user: Barry Warsaw date: Mon May 06 16:15:38 2013 -0400 summary: A few PEP 435 clarifications. files: pep-0435.txt | 29 +++++++++++++++++++---------- 1 files changed, 19 insertions(+), 10 deletions(-) diff --git a/pep-0435.txt b/pep-0435.txt --- a/pep-0435.txt +++ b/pep-0435.txt @@ -213,8 +213,8 @@ >>> list(Shape) [, , ] -If access to aliases is required for some reason, use the special attribute -``__aliases__``:: +The special attribute ``__aliases__`` contains a list of all enum +member aliases, by name:: >>> Shape.__aliases__ ['alias_for_square'] @@ -244,6 +244,8 @@ >>> Color.blue == Color.red False + >>> Color.blue != Color.red + True >>> Color.blue == Color.blue True @@ -294,7 +296,7 @@ The rules for what is allowed are as follows: all attributes defined within an enumeration will become members of this enumeration, with the exception of -*__dunder__* names and descriptors; methods are descriptors too. +*__dunder__* names and descriptors [9]_; methods are descriptors too. Restricted subclassing of enumerations @@ -418,13 +420,19 @@ [, , , ] The semantics of this API resemble ``namedtuple``. The first argument of -the call to ``Enum`` is the name of the enumeration. The second argument is -a source of enumeration member names. It can be a whitespace-separated string -of names, a sequence of names or a sequence of 2-tuples with key/value pairs. -The last option enables assigning arbitrary values to enumerations; the others -auto-assign increasing integers starting with 1. A new class derived from -``Enum`` is returned. In other words, the above assignment to ``Animal`` is -equivalent to:: +the call to ``Enum`` is the name of the enumeration. This argument +can be the short name of the enum or a dotted-name including the +module path to better support pickling. E.g.:: + + >>> Animals = Enum('animals.Animals', 'ant bee cat dog') + +The second argument is the *source* of enumeration member names. It can be a +whitespace-separated string of names, a sequence of names, a sequence of +2-tuples with key/value pairs, or a mapping (e.g. dictionary) of names to +values. The last two options enable assigning arbitrary values to +enumerations; the others auto-assign increasing integers starting with 1. A +new class derived from ``Enum`` is returned. In other words, the above +assignment to ``Animal`` is equivalent to:: >>> class Animals(Enum): ... ant = 1 @@ -570,6 +578,7 @@ .. [6] http://mail.python.org/pipermail/python-dev/2013-April/125716.html .. [7] http://mail.python.org/pipermail/python-dev/2013-May/125859.html .. [8] http://pythonhosted.org/flufl.enum/ +.. [9] http://docs.python.org/3/howto/descriptor.html Copyright ========= -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon May 6 22:19:57 2013 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 6 May 2013 22:19:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3OTE4?= =?utf-8?q?=3A_When_using_SSLSocket=2Eaccept=28=29=2C_if_the_SSL_handshake?= =?utf-8?q?_failed_on_the?= Message-ID: <3b4Fg16Kx0zR3P@mail.python.org> http://hg.python.org/cpython/rev/85e5a93e534e changeset: 83657:85e5a93e534e branch: 2.7 parent: 83654:55c7295aca6c user: Antoine Pitrou date: Mon May 06 22:19:48 2013 +0200 summary: Issue #17918: When using SSLSocket.accept(), if the SSL handshake failed on the new socket, the socket would linger indefinitely. Thanks to Peter Saveliev for reporting. files: Lib/ssl.py | 26 +++++++++++++++----------- Misc/NEWS | 4 ++++ 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -344,17 +344,21 @@ SSL channel, and the address of the remote client.""" newsock, addr = socket.accept(self) - return (SSLSocket(newsock, - keyfile=self.keyfile, - certfile=self.certfile, - server_side=True, - cert_reqs=self.cert_reqs, - ssl_version=self.ssl_version, - ca_certs=self.ca_certs, - ciphers=self.ciphers, - do_handshake_on_connect=self.do_handshake_on_connect, - suppress_ragged_eofs=self.suppress_ragged_eofs), - addr) + try: + return (SSLSocket(newsock, + keyfile=self.keyfile, + certfile=self.certfile, + server_side=True, + cert_reqs=self.cert_reqs, + ssl_version=self.ssl_version, + ca_certs=self.ca_certs, + ciphers=self.ciphers, + do_handshake_on_connect=self.do_handshake_on_connect, + suppress_ragged_eofs=self.suppress_ragged_eofs), + addr) + except socket_error as e: + newsock.close() + raise e def makefile(self, mode='r', bufsize=-1): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,10 @@ Library ------- +- Issue #17918: When using SSLSocket.accept(), if the SSL handshake failed + on the new socket, the socket would linger indefinitely. Thanks to + Peter Saveliev for reporting. + - Issue #17289: The readline module now plays nicer with external modules or applications changing the rl_completer_word_break_characters global variable. Initial patch by Bradley Froehle. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 6 23:23:35 2013 From: python-checkins at python.org (victor.stinner) Date: Mon, 6 May 2013 23:23:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=237330=3A_Implement?= =?utf-8?q?_width_and_precision_=28ex=3A_=22=255=2E3s=22=29_for_the_format?= =?utf-8?q?_string?= Message-ID: <3b4H4R5j5nzR0w@mail.python.org> http://hg.python.org/cpython/rev/9e0f1c3bf9b6 changeset: 83658:9e0f1c3bf9b6 parent: 83656:0f65426009e2 user: Victor Stinner date: Mon May 06 23:11:54 2013 +0200 summary: Issue #7330: Implement width and precision (ex: "%5.3s") for the format string of PyUnicode_FromFormat() function, original patch written by Ysj Ray. files: Doc/c-api/unicode.rst | 11 + Lib/test/test_unicode.py | 221 ++++++++++++++++++++------ Misc/NEWS | 3 + Objects/unicodeobject.c | 159 +++++++++++++----- 4 files changed, 296 insertions(+), 98 deletions(-) diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -526,12 +526,23 @@ The `"%lld"` and `"%llu"` format specifiers are only available when :const:`HAVE_LONG_LONG` is defined. + .. note:: + The width formatter unit is number of characters rather than bytes. + The precision formatter unit is number of bytes for ``"%s"`` and + ``"%V"`` (if the ``PyObject*`` argument is NULL), and a number of + characters for ``"%A"``, ``"%U"``, ``"%S"``, ``"%R"`` and ``"%V"`` + (if the ``PyObject*`` argument is not NULL). + .. versionchanged:: 3.2 Support for ``"%lld"`` and ``"%llu"`` added. .. versionchanged:: 3.3 Support for ``"%li"``, ``"%lli"`` and ``"%zi"`` added. + .. versionchanged:: 3.4 + Support width and precision formatter for ``"%s"``, ``"%A"``, ``"%U"``, + ``"%V"``, ``"%S"``, ``"%R"`` added. + .. c:function:: PyObject* PyUnicode_FromFormatV(const char *format, va_list vargs) 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 @@ -2007,9 +2007,13 @@ for arg in args) return _PyUnicode_FromFormat(format, *cargs) + def check_format(expected, format, *args): + text = PyUnicode_FromFormat(format, *args) + self.assertEqual(expected, text) + # ascii format, non-ascii argument - text = PyUnicode_FromFormat(b'ascii\x7f=%U', 'unicode\xe9') - self.assertEqual(text, 'ascii\x7f=unicode\xe9') + check_format('ascii\x7f=unicode\xe9', + b'ascii\x7f=%U', 'unicode\xe9') # non-ascii format, ascii argument: ensure that PyUnicode_FromFormatV() # raises an error @@ -2019,83 +2023,200 @@ PyUnicode_FromFormat, b'unicode\xe9=%s', 'ascii') # test "%c" - self.assertEqual(PyUnicode_FromFormat(b'%c', c_int(0xabcd)), '\uabcd') - self.assertEqual(PyUnicode_FromFormat(b'%c', c_int(0x10ffff)), '\U0010ffff') + check_format('\uabcd', + b'%c', c_int(0xabcd)) + check_format('\U0010ffff', + b'%c', c_int(0x10ffff)) # test "%" - self.assertEqual(PyUnicode_FromFormat(b'%'), '%') - self.assertEqual(PyUnicode_FromFormat(b'%%'), '%') - self.assertEqual(PyUnicode_FromFormat(b'%%s'), '%s') - self.assertEqual(PyUnicode_FromFormat(b'[%%]'), '[%]') - self.assertEqual(PyUnicode_FromFormat(b'%%%s', b'abc'), '%abc') + check_format('%', + b'%') + check_format('%', + b'%%') + check_format('%s', + b'%%s') + check_format('[%]', + b'[%%]') + check_format('%abc', + b'%%%s', b'abc') + + # truncated string + check_format('abc', + b'%.3s', b'abcdef') + check_format('abc[\ufffd', + b'%.5s', 'abc[\u20ac]'.encode('utf8')) + check_format("'\\u20acABC'", + b'%A', '\u20acABC') + check_format("'\\u20", + b'%.5A', '\u20acABCDEF') + check_format("'\u20acABC'", + b'%R', '\u20acABC') + check_format("'\u20acA", + b'%.3R', '\u20acABCDEF') + check_format('\u20acAB', + b'%.3S', '\u20acABCDEF') + check_format('\u20acAB', + b'%.3U', '\u20acABCDEF') + check_format('\u20acAB', + b'%.3V', '\u20acABCDEF', None) + check_format('abc[\ufffd', + b'%.5V', None, 'abc[\u20ac]'.encode('utf8')) + + # following tests comes from #7330 + # test width modifier and precision modifier with %S + check_format("repr= abc", + b'repr=%5S', 'abc') + check_format("repr=ab", + b'repr=%.2S', 'abc') + check_format("repr= ab", + b'repr=%5.2S', 'abc') + + # test width modifier and precision modifier with %R + check_format("repr= 'abc'", + b'repr=%8R', 'abc') + check_format("repr='ab", + b'repr=%.3R', 'abc') + check_format("repr= 'ab", + b'repr=%5.3R', 'abc') + + # test width modifier and precision modifier with %A + check_format("repr= 'abc'", + b'repr=%8A', 'abc') + check_format("repr='ab", + b'repr=%.3A', 'abc') + check_format("repr= 'ab", + b'repr=%5.3A', 'abc') + + # test width modifier and precision modifier with %s + check_format("repr= abc", + b'repr=%5s', b'abc') + check_format("repr=ab", + b'repr=%.2s', b'abc') + check_format("repr= ab", + b'repr=%5.2s', b'abc') + + # test width modifier and precision modifier with %U + check_format("repr= abc", + b'repr=%5U', 'abc') + check_format("repr=ab", + b'repr=%.2U', 'abc') + check_format("repr= ab", + b'repr=%5.2U', 'abc') + + # test width modifier and precision modifier with %V + check_format("repr= abc", + b'repr=%5V', 'abc', b'123') + check_format("repr=ab", + b'repr=%.2V', 'abc', b'123') + check_format("repr= ab", + b'repr=%5.2V', 'abc', b'123') + check_format("repr= 123", + b'repr=%5V', None, b'123') + check_format("repr=12", + b'repr=%.2V', None, b'123') + check_format("repr= 12", + b'repr=%5.2V', None, b'123') # test integer formats (%i, %d, %u) - self.assertEqual(PyUnicode_FromFormat(b'%03i', c_int(10)), '010') - self.assertEqual(PyUnicode_FromFormat(b'%0.4i', c_int(10)), '0010') - self.assertEqual(PyUnicode_FromFormat(b'%i', c_int(-123)), '-123') - self.assertEqual(PyUnicode_FromFormat(b'%li', c_long(-123)), '-123') - self.assertEqual(PyUnicode_FromFormat(b'%lli', c_longlong(-123)), '-123') - self.assertEqual(PyUnicode_FromFormat(b'%zi', c_ssize_t(-123)), '-123') + check_format('010', + b'%03i', c_int(10)) + check_format('0010', + b'%0.4i', c_int(10)) + check_format('-123', + b'%i', c_int(-123)) + check_format('-123', + b'%li', c_long(-123)) + check_format('-123', + b'%lli', c_longlong(-123)) + check_format('-123', + b'%zi', c_ssize_t(-123)) - self.assertEqual(PyUnicode_FromFormat(b'%d', c_int(-123)), '-123') - self.assertEqual(PyUnicode_FromFormat(b'%ld', c_long(-123)), '-123') - self.assertEqual(PyUnicode_FromFormat(b'%lld', c_longlong(-123)), '-123') - self.assertEqual(PyUnicode_FromFormat(b'%zd', c_ssize_t(-123)), '-123') + check_format('-123', + b'%d', c_int(-123)) + check_format('-123', + b'%ld', c_long(-123)) + check_format('-123', + b'%lld', c_longlong(-123)) + check_format('-123', + b'%zd', c_ssize_t(-123)) - self.assertEqual(PyUnicode_FromFormat(b'%u', c_uint(123)), '123') - self.assertEqual(PyUnicode_FromFormat(b'%lu', c_ulong(123)), '123') - self.assertEqual(PyUnicode_FromFormat(b'%llu', c_ulonglong(123)), '123') - self.assertEqual(PyUnicode_FromFormat(b'%zu', c_size_t(123)), '123') + check_format('123', + b'%u', c_uint(123)) + check_format('123', + b'%lu', c_ulong(123)) + check_format('123', + b'%llu', c_ulonglong(123)) + check_format('123', + b'%zu', c_size_t(123)) # test long output min_longlong = -(2 ** (8 * sizeof(c_longlong) - 1)) max_longlong = -min_longlong - 1 - self.assertEqual(PyUnicode_FromFormat(b'%lld', c_longlong(min_longlong)), str(min_longlong)) - self.assertEqual(PyUnicode_FromFormat(b'%lld', c_longlong(max_longlong)), str(max_longlong)) + check_format(str(min_longlong), + b'%lld', c_longlong(min_longlong)) + check_format(str(max_longlong), + b'%lld', c_longlong(max_longlong)) max_ulonglong = 2 ** (8 * sizeof(c_ulonglong)) - 1 - self.assertEqual(PyUnicode_FromFormat(b'%llu', c_ulonglong(max_ulonglong)), str(max_ulonglong)) + check_format(str(max_ulonglong), + b'%llu', c_ulonglong(max_ulonglong)) PyUnicode_FromFormat(b'%p', c_void_p(-1)) # test padding (width and/or precision) - self.assertEqual(PyUnicode_FromFormat(b'%010i', c_int(123)), '123'.rjust(10, '0')) - self.assertEqual(PyUnicode_FromFormat(b'%100i', c_int(123)), '123'.rjust(100)) - self.assertEqual(PyUnicode_FromFormat(b'%.100i', c_int(123)), '123'.rjust(100, '0')) - self.assertEqual(PyUnicode_FromFormat(b'%100.80i', c_int(123)), '123'.rjust(80, '0').rjust(100)) + check_format('123'.rjust(10, '0'), + b'%010i', c_int(123)) + check_format('123'.rjust(100), + b'%100i', c_int(123)) + check_format('123'.rjust(100, '0'), + b'%.100i', c_int(123)) + check_format('123'.rjust(80, '0').rjust(100), + b'%100.80i', c_int(123)) - self.assertEqual(PyUnicode_FromFormat(b'%010u', c_uint(123)), '123'.rjust(10, '0')) - self.assertEqual(PyUnicode_FromFormat(b'%100u', c_uint(123)), '123'.rjust(100)) - self.assertEqual(PyUnicode_FromFormat(b'%.100u', c_uint(123)), '123'.rjust(100, '0')) - self.assertEqual(PyUnicode_FromFormat(b'%100.80u', c_uint(123)), '123'.rjust(80, '0').rjust(100)) + check_format('123'.rjust(10, '0'), + b'%010u', c_uint(123)) + check_format('123'.rjust(100), + b'%100u', c_uint(123)) + check_format('123'.rjust(100, '0'), + b'%.100u', c_uint(123)) + check_format('123'.rjust(80, '0').rjust(100), + b'%100.80u', c_uint(123)) - self.assertEqual(PyUnicode_FromFormat(b'%010x', c_int(0x123)), '123'.rjust(10, '0')) - self.assertEqual(PyUnicode_FromFormat(b'%100x', c_int(0x123)), '123'.rjust(100)) - self.assertEqual(PyUnicode_FromFormat(b'%.100x', c_int(0x123)), '123'.rjust(100, '0')) - self.assertEqual(PyUnicode_FromFormat(b'%100.80x', c_int(0x123)), '123'.rjust(80, '0').rjust(100)) + check_format('123'.rjust(10, '0'), + b'%010x', c_int(0x123)) + check_format('123'.rjust(100), + b'%100x', c_int(0x123)) + check_format('123'.rjust(100, '0'), + b'%.100x', c_int(0x123)) + check_format('123'.rjust(80, '0').rjust(100), + b'%100.80x', c_int(0x123)) # test %A - text = PyUnicode_FromFormat(b'%%A:%A', 'abc\xe9\uabcd\U0010ffff') - self.assertEqual(text, r"%A:'abc\xe9\uabcd\U0010ffff'") + check_format(r"%A:'abc\xe9\uabcd\U0010ffff'", + b'%%A:%A', 'abc\xe9\uabcd\U0010ffff') # test %V - text = PyUnicode_FromFormat(b'repr=%V', 'abc', b'xyz') - self.assertEqual(text, 'repr=abc') + check_format('repr=abc', + b'repr=%V', 'abc', b'xyz') # Test string decode from parameter of %s using utf-8. # b'\xe4\xba\xba\xe6\xb0\x91' is utf-8 encoded byte sequence of # '\u4eba\u6c11' - text = PyUnicode_FromFormat(b'repr=%V', None, b'\xe4\xba\xba\xe6\xb0\x91') - self.assertEqual(text, 'repr=\u4eba\u6c11') + check_format('repr=\u4eba\u6c11', + b'repr=%V', None, b'\xe4\xba\xba\xe6\xb0\x91') #Test replace error handler. - text = PyUnicode_FromFormat(b'repr=%V', None, b'abc\xff') - self.assertEqual(text, 'repr=abc\ufffd') + check_format('repr=abc\ufffd', + b'repr=%V', None, b'abc\xff') # not supported: copy the raw format string. these tests are just here # to check for crashs and should not be considered as specifications - self.assertEqual(PyUnicode_FromFormat(b'%1%s', b'abc'), '%s') - self.assertEqual(PyUnicode_FromFormat(b'%1abc'), '%1abc') - self.assertEqual(PyUnicode_FromFormat(b'%+i', c_int(10)), '%+i') - self.assertEqual(PyUnicode_FromFormat(b'%.%s', b'abc'), '%.%s') + check_format('%s', + b'%1%s', b'abc') + check_format('%1abc', + b'%1abc') + check_format('%+i', + b'%+i', c_int(10)) + check_format('%.%s', + b'%.%s', b'abc') # Test PyUnicode_AsWideChar() def test_aswidechar(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #7330: Implement width and precision (ex: "%5.3s") for the format + string of PyUnicode_FromFormat() function, original patch written by Ysj Ray. + - Issue #1545463: Global variables caught in reference cycles are now garbage-collected at shutdown. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -2346,6 +2346,67 @@ plus 1 for the sign. 53/22 is an upper bound for log10(256). */ #define MAX_LONG_LONG_CHARS (2 + (SIZEOF_LONG_LONG*53-1) / 22) +static int +unicode_fromformat_write_str(_PyUnicodeWriter *writer, PyObject *str, + Py_ssize_t width, Py_ssize_t precision) +{ + Py_ssize_t length, fill, arglen; + Py_UCS4 maxchar; + + if (PyUnicode_READY(str) == -1) + return -1; + + length = PyUnicode_GET_LENGTH(str); + if ((precision == -1 || precision >= length) + && width <= length) + return _PyUnicodeWriter_WriteStr(writer, str); + + if (precision != -1) + length = Py_MIN(precision, length); + + arglen = Py_MAX(length, width); + if (PyUnicode_MAX_CHAR_VALUE(str) > writer->maxchar) + maxchar = _PyUnicode_FindMaxChar(str, 0, length); + else + maxchar = writer->maxchar; + + if (_PyUnicodeWriter_Prepare(writer, arglen, maxchar) == -1) + return -1; + + if (width > length) { + fill = width - length; + if (PyUnicode_Fill(writer->buffer, writer->pos, fill, ' ') == -1) + return -1; + writer->pos += fill; + } + + _PyUnicode_FastCopyCharacters(writer->buffer, writer->pos, + str, 0, length); + writer->pos += length; + return 0; +} + +static int +unicode_fromformat_write_cstr(_PyUnicodeWriter *writer, const char *str, + Py_ssize_t width, Py_ssize_t precision) +{ + /* UTF-8 */ + Py_ssize_t length; + PyObject *unicode; + int res; + + length = strlen(str); + if (precision != -1) + length = Py_MIN(length, precision); + unicode = PyUnicode_DecodeUTF8Stateful(str, length, "replace", NULL); + if (unicode == NULL) + return -1; + + res = unicode_fromformat_write_str(writer, unicode, width, -1); + Py_DECREF(unicode); + return res; +} + static const char* unicode_fromformat_arg(_PyUnicodeWriter *writer, const char *f, va_list *vargs) @@ -2353,12 +2414,12 @@ const char *p; Py_ssize_t len; int zeropad; - int width; - int precision; + Py_ssize_t width; + Py_ssize_t precision; int longflag; int longlongflag; int size_tflag; - int fill; + Py_ssize_t fill; p = f; f++; @@ -2369,27 +2430,35 @@ } /* parse the width.precision part, e.g. "%2.5s" => width=2, precision=5 */ - width = 0; - while (Py_ISDIGIT((unsigned)*f)) { - if (width > (INT_MAX - ((int)*f - '0')) / 10) { - PyErr_SetString(PyExc_ValueError, - "width too big"); - return NULL; - } - width = (width*10) + (*f - '0'); + width = -1; + if (Py_ISDIGIT((unsigned)*f)) { + width = *f - '0'; f++; - } - precision = 0; + while (Py_ISDIGIT((unsigned)*f)) { + if (width > (PY_SSIZE_T_MAX - ((int)*f - '0')) / 10) { + PyErr_SetString(PyExc_ValueError, + "width too big"); + return NULL; + } + width = (width * 10) + (*f - '0'); + f++; + } + } + precision = -1; if (*f == '.') { f++; - while (Py_ISDIGIT((unsigned)*f)) { - if (precision > (INT_MAX - ((int)*f - '0')) / 10) { - PyErr_SetString(PyExc_ValueError, - "precision too big"); - return NULL; - } - precision = (precision*10) + (*f - '0'); + if (Py_ISDIGIT((unsigned)*f)) { + precision = (*f - '0'); f++; + while (Py_ISDIGIT((unsigned)*f)) { + if (precision > (PY_SSIZE_T_MAX - ((int)*f - '0')) / 10) { + PyErr_SetString(PyExc_ValueError, + "precision too big"); + return NULL; + } + precision = (precision * 10) + (*f - '0'); + f++; + } } if (*f == '%') { /* "%.3%s" => f points to "3" */ @@ -2449,6 +2518,7 @@ /* 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); @@ -2494,26 +2564,29 @@ if (precision < len) precision = len; + + arglen = Py_MAX(precision, width); + assert(ucs1lib_find_max_char((Py_UCS1*)buffer, (Py_UCS1*)buffer + len) <= 127); + if (_PyUnicodeWriter_Prepare(writer, arglen, 127) == -1) + return NULL; + if (width > precision) { Py_UCS4 fillchar; fill = width - precision; fillchar = zeropad?'0':' '; - if (_PyUnicodeWriter_Prepare(writer, fill, fillchar) == -1) - return NULL; if (PyUnicode_Fill(writer->buffer, writer->pos, fill, fillchar) == -1) return NULL; writer->pos += fill; } if (precision > len) { fill = precision - len; - if (_PyUnicodeWriter_Prepare(writer, fill, '0') == -1) - return NULL; if (PyUnicode_Fill(writer->buffer, writer->pos, fill, '0') == -1) return NULL; writer->pos += fill; } - if (_PyUnicodeWriter_WriteCstr(writer, buffer, len) == -1) - return NULL; + + unicode_write_cstr(writer->buffer, writer->pos, buffer, len); + writer->pos += len; break; } @@ -2535,8 +2608,11 @@ len += 2; } - if (_PyUnicodeWriter_WriteCstr(writer, number, len) == -1) + assert(ucs1lib_find_max_char((Py_UCS1*)number, (Py_UCS1*)number + len) <= 127); + if (_PyUnicodeWriter_Prepare(writer, len, 127) == -1) return NULL; + unicode_write_cstr(writer->buffer, writer->pos, number, len); + writer->pos += len; break; } @@ -2544,14 +2620,8 @@ { /* UTF-8 */ const char *s = va_arg(*vargs, const char*); - PyObject *str = PyUnicode_DecodeUTF8Stateful(s, strlen(s), "replace", NULL); - if (!str) + if (unicode_fromformat_write_cstr(writer, s, width, precision) < 0) return NULL; - if (_PyUnicodeWriter_WriteStr(writer, str) == -1) { - Py_DECREF(str); - return NULL; - } - Py_DECREF(str); break; } @@ -2560,7 +2630,7 @@ PyObject *obj = va_arg(*vargs, PyObject *); assert(obj && _PyUnicode_CHECK(obj)); - if (_PyUnicodeWriter_WriteStr(writer, obj) == -1) + if (unicode_fromformat_write_str(writer, obj, width, precision) == -1) return NULL; break; } @@ -2569,22 +2639,15 @@ { PyObject *obj = va_arg(*vargs, PyObject *); const char *str = va_arg(*vargs, const char *); - PyObject *str_obj; - assert(obj || str); if (obj) { assert(_PyUnicode_CHECK(obj)); - if (_PyUnicodeWriter_WriteStr(writer, obj) == -1) + if (unicode_fromformat_write_str(writer, obj, width, precision) == -1) return NULL; } else { - str_obj = PyUnicode_DecodeUTF8Stateful(str, strlen(str), "replace", NULL); - if (!str_obj) + assert(str != NULL); + if (unicode_fromformat_write_cstr(writer, str, width, precision) < 0) return NULL; - if (_PyUnicodeWriter_WriteStr(writer, str_obj) == -1) { - Py_DECREF(str_obj); - return NULL; - } - Py_DECREF(str_obj); } break; } @@ -2597,7 +2660,7 @@ str = PyObject_Str(obj); if (!str) return NULL; - if (_PyUnicodeWriter_WriteStr(writer, str) == -1) { + if (unicode_fromformat_write_str(writer, str, width, precision) == -1) { Py_DECREF(str); return NULL; } @@ -2613,7 +2676,7 @@ repr = PyObject_Repr(obj); if (!repr) return NULL; - if (_PyUnicodeWriter_WriteStr(writer, repr) == -1) { + if (unicode_fromformat_write_str(writer, repr, width, precision) == -1) { Py_DECREF(repr); return NULL; } @@ -2629,7 +2692,7 @@ ascii = PyObject_ASCII(obj); if (!ascii) return NULL; - if (_PyUnicodeWriter_WriteStr(writer, ascii) == -1) { + if (unicode_fromformat_write_str(writer, ascii, width, precision) == -1) { Py_DECREF(ascii); return NULL; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 7 00:28:39 2013 From: python-checkins at python.org (nick.coghlan) Date: Tue, 7 May 2013 00:28:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2311816=3A_Add_miss?= =?utf-8?q?ing_test_helper?= Message-ID: <3b4JWW5s3LzRL7@mail.python.org> http://hg.python.org/cpython/rev/84d1a0e32d3b changeset: 83659:84d1a0e32d3b user: Nick Coghlan date: Tue May 07 08:28:21 2013 +1000 summary: Issue #11816: Add missing test helper This is why I should really use hg import rather than patch, but old habits die hard... files: Lib/test/bytecode_helper.py | 72 +++++++++++++++++++++++++ 1 files changed, 72 insertions(+), 0 deletions(-) diff --git a/Lib/test/bytecode_helper.py b/Lib/test/bytecode_helper.py new file mode 100644 --- /dev/null +++ b/Lib/test/bytecode_helper.py @@ -0,0 +1,72 @@ +"""bytecode_helper - support tools for testing correct bytecode generation""" + +import unittest +import dis +import io + +_UNSPECIFIED = object() + +class BytecodeTestCase(unittest.TestCase): + """Custom assertion methods for inspecting bytecode.""" + + def get_disassembly_as_string(self, co): + s = io.StringIO() + dis.dis(co, file=s) + return s.getvalue() + + def assertInstructionMatches(self, instr, expected, *, line_offset=0): + # Deliberately test opname first, since that gives a more + # meaningful error message than testing opcode + self.assertEqual(instr.opname, expected.opname) + self.assertEqual(instr.opcode, expected.opcode) + self.assertEqual(instr.arg, expected.arg) + self.assertEqual(instr.argval, expected.argval) + self.assertEqual(instr.argrepr, expected.argrepr) + self.assertEqual(instr.offset, expected.offset) + if expected.starts_line is None: + self.assertIsNone(instr.starts_line) + else: + self.assertEqual(instr.starts_line, + expected.starts_line + line_offset) + self.assertEqual(instr.is_jump_target, expected.is_jump_target) + + + def assertBytecodeExactlyMatches(self, x, expected, *, line_offset=0): + """Throws AssertionError if any discrepancy is found in bytecode + + *x* is the object to be introspected + *expected* is a list of dis.Instruction objects + + Set *line_offset* as appropriate to adjust for the location of the + object to be disassembled within the test file. If the expected list + assumes the first line is line 1, then an appropriate offset would be + ``1 - f.__code__.co_firstlineno``. + """ + actual = dis.get_instructions(x, line_offset=line_offset) + self.assertEqual(list(actual), expected) + + def assertInBytecode(self, x, opname, argval=_UNSPECIFIED): + """Returns instr if op is found, otherwise throws AssertionError""" + for instr in dis.get_instructions(x): + if instr.opname == opname: + if argval is _UNSPECIFIED or instr.argval == argval: + return instr + disassembly = self.get_disassembly_as_string(x) + if argval is _UNSPECIFIED: + msg = '%s not found in bytecode:\n%s' % (opname, disassembly) + else: + msg = '(%s,%r) not found in bytecode:\n%s' + msg = msg % (opname, argval, disassembly) + self.fail(msg) + + def assertNotInBytecode(self, x, opname, argval=_UNSPECIFIED): + """Throws AssertionError if op is found""" + for instr in dis.get_instructions(x): + if instr.opname == opname: + disassembly = self.get_disassembly_as_string(co) + if opargval is _UNSPECIFIED: + msg = '%s occurs in bytecode:\n%s' % (opname, disassembly) + elif instr.argval == argval: + msg = '(%s,%r) occurs in bytecode:\n%s' + msg = msg % (opname, argval, disassembly) + self.fail(msg) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 7 01:02:39 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 7 May 2013 01:02:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_uninitialized_value_in?= =?utf-8?q?_charmap=5Fdecode=5Fmapping=28=29?= Message-ID: <3b4KGl32fyzQ3P@mail.python.org> http://hg.python.org/cpython/rev/1c1f60ccf305 changeset: 83660:1c1f60ccf305 user: Victor Stinner date: Tue May 07 01:01:31 2013 +0200 summary: Fix uninitialized value in charmap_decode_mapping() files: Objects/unicodeobject.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -7459,7 +7459,7 @@ Py_ssize_t startinpos, endinpos; PyObject *errorHandler = NULL, *exc = NULL; unsigned char ch; - PyObject *key, *item; + PyObject *key, *item = NULL; e = s + size; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 7 03:21:19 2013 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 7 May 2013 03:21:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgMTc5MjA6?= =?utf-8?q?__Fix-up_terminology_in_the_set_documentation?= Message-ID: <3b4NLl4G70zRpW@mail.python.org> http://hg.python.org/cpython/rev/a285ce18bd55 changeset: 83661:a285ce18bd55 branch: 2.7 parent: 83657:85e5a93e534e user: Raymond Hettinger date: Mon May 06 18:21:10 2013 -0700 summary: Issue 17920: Fix-up terminology in the set documentation files: Doc/library/stdtypes.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -1849,8 +1849,8 @@ based on their members. For example, ``set('abc') == frozenset('abc')`` returns ``True`` and so does ``set('abc') in set([frozenset('abc')])``. - The subset and equality comparisons do not generalize to a complete ordering - function. For example, any two disjoint sets are not equal and are not + The subset and equality comparisons do not generalize to a total ordering + function. For example, any two non-empty disjoint sets are not equal and are not subsets of each other, so *all* of the following return ``False``: ``ab``. Accordingly, sets do not implement the :meth:`__cmp__` method. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 7 03:23:22 2013 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 7 May 2013 03:23:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgMTc5MjA6?= =?utf-8?q?__Fix-up_terminology_in_the_set_documentation?= Message-ID: <3b4NP66Db1zT25@mail.python.org> http://hg.python.org/cpython/rev/6ec04c5dae6e changeset: 83662:6ec04c5dae6e branch: 3.3 parent: 83655:df0afd3ebb70 user: Raymond Hettinger date: Mon May 06 18:22:43 2013 -0700 summary: Issue 17920: Fix-up terminology in the set documentation files: Doc/library/stdtypes.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2909,8 +2909,8 @@ based on their members. For example, ``set('abc') == frozenset('abc')`` returns ``True`` and so does ``set('abc') in set([frozenset('abc')])``. - The subset and equality comparisons do not generalize to a complete ordering - function. For example, any two disjoint sets are not equal and are not + The subset and equality comparisons do not generalize to a total ordering + function. For example, any two nonempty disjoint sets are not equal and are not subsets of each other, so *all* of the following return ``False``: ``ab``. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 7 03:23:24 2013 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 7 May 2013 03:23:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3b4NP81MPgzRGC@mail.python.org> http://hg.python.org/cpython/rev/e163c13b941c changeset: 83663:e163c13b941c parent: 83660:1c1f60ccf305 parent: 83662:6ec04c5dae6e user: Raymond Hettinger date: Mon May 06 18:23:10 2013 -0700 summary: merge files: Doc/library/stdtypes.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2909,8 +2909,8 @@ based on their members. For example, ``set('abc') == frozenset('abc')`` returns ``True`` and so does ``set('abc') in set([frozenset('abc')])``. - The subset and equality comparisons do not generalize to a complete ordering - function. For example, any two disjoint sets are not equal and are not + The subset and equality comparisons do not generalize to a total ordering + function. For example, any two nonempty disjoint sets are not equal and are not subsets of each other, so *all* of the following return ``False``: ``ab``. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue May 7 06:02:20 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 07 May 2013 06:02:20 +0200 Subject: [Python-checkins] Daily reference leaks (e163c13b941c): sum=12 Message-ID: results for e163c13b941c on branch "default" -------------------------------------------- test_support leaked [-1, 1, 0] references, sum=0 test_support leaked [-1, 3, 2] memory blocks, sum=4 test_concurrent_futures leaked [2, 1, 1] memory blocks, sum=4 test_multiprocessing leaked [1, 1, 2] memory blocks, sum=4 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogbcoWXw', '-x'] From python-checkins at python.org Tue May 7 08:35:01 2013 From: python-checkins at python.org (ezio.melotti) Date: Tue, 7 May 2013 08:35:01 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE3ODMzOiBhZGQg?= =?utf-8?q?debug_output_to_investigate_buildbot_failure=2E?= Message-ID: <3b4WJj6M9qzRJ6@mail.python.org> http://hg.python.org/cpython/rev/63f2941477d3 changeset: 83664:63f2941477d3 branch: 2.7 parent: 83661:a285ce18bd55 user: Ezio Melotti date: Tue May 07 09:34:49 2013 +0300 summary: #17833: add debug output to investigate buildbot failure. files: Lib/test/test_tcl.py | 18 ++++++++++++++---- 1 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -4,6 +4,7 @@ import sys import os from test import test_support +from subprocess import Popen, PIPE # Skip this test if the _tkinter module wasn't built. _tkinter = test_support.import_module('_tkinter') @@ -146,11 +147,20 @@ with test_support.EnvironmentVarGuard() as env: env.unset("TCL_LIBRARY") - f = os.popen('%s -c "import Tkinter; print Tkinter"' % (unc_name,)) + cmd = '%s -c "import Tkinter; print Tkinter"' % (unc_name,) - self.assertIn('Tkinter.py', f.read()) - # exit code must be zero - self.assertEqual(f.close(), None) + p = Popen(cmd, stdout=PIPE, stderr=PIPE) + out_data, err_data = p.communicate() + + msg = '\n\n'.join(['"Tkinter.py" not in output', + 'Command:', cmd, + 'stdout:', out_data, + 'stderr:', err_data]) + + self.assertIn('Tkinter.py', out_data, msg) + + self.assertEqual(p.wait(), 0, 'Non-zero exit code') + def test_passing_values(self): def passValue(value): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 7 08:47:18 2013 From: python-checkins at python.org (ezio.melotti) Date: Tue, 7 May 2013 08:47:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE3ODcxOiBmaXgg?= =?utf-8?q?unittest=2ETextTestRunner_signature_in_the_docs=2E__Patch_by_Yo?= =?utf-8?q?gesh?= Message-ID: <3b4WZt6vLLzQsm@mail.python.org> http://hg.python.org/cpython/rev/5dd076d441ec changeset: 83665:5dd076d441ec branch: 3.3 parent: 83662:6ec04c5dae6e user: Ezio Melotti date: Tue May 07 09:46:30 2013 +0300 summary: #17871: fix unittest.TextTestRunner signature in the docs. Patch by Yogesh Chaudhari. files: Doc/library/unittest.rst | 3 ++- Misc/ACKS | 1 + 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1746,7 +1746,8 @@ instead of repeatedly creating new instances. -.. class:: TextTestRunner(stream=None, descriptions=True, verbosity=1, runnerclass=None, warnings=None) +.. class:: TextTestRunner(stream=None, descriptions=True, verbosity=1, failfast=False, \ + buffer=False, resultclass=None, warnings=None) A basic test runner implementation that outputs results to a stream. If *stream* is ``None``, the default, :data:`sys.stderr` is used as the output stream. This class diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -204,6 +204,7 @@ Brad Chapman Greg Chapman Mitch Chapman +Yogesh Chaudhari David Chaum Nicolas Chauvat Jerry Chen -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 7 08:47:20 2013 From: python-checkins at python.org (ezio.melotti) Date: Tue, 7 May 2013 08:47:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzE3ODcxOiBtZXJnZSB3aXRoIDMuMy4=?= Message-ID: <3b4WZw27JbzR3P@mail.python.org> http://hg.python.org/cpython/rev/15ed67602ddf changeset: 83666:15ed67602ddf parent: 83663:e163c13b941c parent: 83665:5dd076d441ec user: Ezio Melotti date: Tue May 07 09:47:08 2013 +0300 summary: #17871: merge with 3.3. files: Doc/library/unittest.rst | 3 ++- Misc/ACKS | 1 + 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1850,7 +1850,8 @@ instead of repeatedly creating new instances. -.. class:: TextTestRunner(stream=None, descriptions=True, verbosity=1, runnerclass=None, warnings=None) +.. class:: TextTestRunner(stream=None, descriptions=True, verbosity=1, failfast=False, \ + buffer=False, resultclass=None, warnings=None) A basic test runner implementation that outputs results to a stream. If *stream* is ``None``, the default, :data:`sys.stderr` is used as the output stream. This class diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -208,6 +208,7 @@ Brad Chapman Greg Chapman Mitch Chapman +Yogesh Chaudhari David Chaum Nicolas Chauvat Jerry Chen -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 7 10:14:39 2013 From: python-checkins at python.org (ezio.melotti) Date: Tue, 7 May 2013 10:14:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE3NzE0OiBkb2N1?= =?utf-8?q?ment_that_the_base64_codec_adds_a_trailing_newline=2E?= Message-ID: <3b4YWg15wkzQ1v@mail.python.org> http://hg.python.org/cpython/rev/8b764c3521fa changeset: 83667:8b764c3521fa branch: 2.7 parent: 83664:63f2941477d3 user: Ezio Melotti date: Tue May 07 11:14:27 2013 +0300 summary: #17714: document that the base64 codec adds a trailing newline. files: Doc/library/codecs.rst | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -1113,7 +1113,9 @@ | Codec | Aliases | Operand type | Purpose | +====================+===========================+================+===========================+ | base64_codec | base64, base-64 | byte string | Convert operand to MIME | -| | | | base64 | +| | | | base64 (the result always | +| | | | includes a trailing | +| | | | ``'\n'``) | +--------------------+---------------------------+----------------+---------------------------+ | bz2_codec | bz2 | byte string | Compress the operand | | | | | using bz2 | -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 7 10:21:34 2013 From: python-checkins at python.org (ezio.melotti) Date: Tue, 7 May 2013 10:21:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE3NzE0OiBkb2N1?= =?utf-8?q?ment_that_the_base64_codec_adds_a_trailing_newline=2E?= Message-ID: <3b4Ygf17DKzRHD@mail.python.org> http://hg.python.org/cpython/rev/cbb23e40e0d7 changeset: 83668:cbb23e40e0d7 branch: 3.3 parent: 83665:5dd076d441ec user: Ezio Melotti date: Tue May 07 11:14:27 2013 +0300 summary: #17714: document that the base64 codec adds a trailing newline. files: Doc/library/codecs.rst | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -1194,7 +1194,9 @@ | Codec | Aliases | Purpose | +====================+===========================+===========================+ | base64_codec | base64, base-64 | Convert operand to MIME | -| | | base64 | +| | | base64 (the result always | +| | | includes a trailing | +| | | ``'\n'``) | +--------------------+---------------------------+---------------------------+ | bz2_codec | bz2 | Compress the operand | | | | using bz2 | -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 7 10:21:35 2013 From: python-checkins at python.org (ezio.melotti) Date: Tue, 7 May 2013 10:21:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzE3NzE0OiBtZXJnZSB3aXRoIDMuMy4=?= Message-ID: <3b4Ygg46SNzSPF@mail.python.org> http://hg.python.org/cpython/rev/b3e1be1493a5 changeset: 83669:b3e1be1493a5 parent: 83666:15ed67602ddf parent: 83668:cbb23e40e0d7 user: Ezio Melotti date: Tue May 07 11:21:21 2013 +0300 summary: #17714: merge with 3.3. files: Doc/library/codecs.rst | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -1194,7 +1194,9 @@ | Codec | Aliases | Purpose | +====================+===========================+===========================+ | base64_codec | base64, base-64 | Convert operand to MIME | -| | | base64 | +| | | base64 (the result always | +| | | includes a trailing | +| | | ``'\n'``) | +--------------------+---------------------------+---------------------------+ | bz2_codec | bz2 | Compress the operand | | | | using bz2 | -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 7 11:52:30 2013 From: python-checkins at python.org (vinay.sajip) Date: Tue, 7 May 2013 11:52:30 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Skip_failing_test_pending_?= =?utf-8?q?investigation=2E?= Message-ID: <3b4bhZ0tmtzQvx@mail.python.org> http://hg.python.org/cpython/rev/15fd07c89941 changeset: 83670:15fd07c89941 user: Vinay Sajip date: Tue May 07 10:52:18 2013 +0100 summary: Skip failing test pending investigation. files: Lib/test/test_logging.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3964,6 +3964,7 @@ finally: rh.close() + @unittest.skipIf(True, 'Temporarily skipped while failures investigated.') def test_compute_rollover_weekly_attime(self): currentTime = int(time.time()) today = currentTime - currentTime % 86400 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 7 15:26:19 2013 From: python-checkins at python.org (richard.oudkerk) Date: Tue, 7 May 2013 15:26:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbjogRml4IG9zLl9fYWxsX18gdG8g?= =?utf-8?q?is_passes_test=5F=5F=5Fall=5F=5F?= Message-ID: <3b4hRH5DNrzQsm@mail.python.org> http://hg.python.org/cpython/rev/4f82b6cfee46 changeset: 83671:4f82b6cfee46 user: Richard Oudkerk date: Tue May 07 14:23:42 2013 +0100 summary: Fix os.__all__ to is passes test___all__ files: Lib/os.py | 14 ++++++++------ 1 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Lib/os.py b/Lib/os.py --- a/Lib/os.py +++ b/Lib/os.py @@ -686,19 +686,16 @@ self[key] = value return self[key] +# if putenv or unsetenv exist they should already be in __all__ try: _putenv = putenv except NameError: _putenv = lambda key, value: None -else: - __all__.append("putenv") try: _unsetenv = unsetenv except NameError: _unsetenv = lambda key: _putenv(key, "") -else: - __all__.append("unsetenv") def _createenviron(): if name == 'nt': @@ -883,6 +880,10 @@ otherwise return -SIG, where SIG is the signal that killed it. """ return _spawnvef(mode, file, args, env, execvpe) + + __all__.extend(["spawnv", "spawnve", "spawnvp", "spawnvpe"]) + + if _exists("spawnv"): # These aren't supplied by the basic Windows code # but can be easily implemented in Python @@ -908,7 +909,7 @@ return spawnve(mode, file, args[:-1], env) - __all__.extend(["spawnv", "spawnve", "spawnl", "spawnle",]) + __all__.extend(["spawnl", "spawnle"]) if _exists("spawnvp"): @@ -936,7 +937,8 @@ return spawnvpe(mode, file, args[:-1], env) - __all__.extend(["spawnvp", "spawnvpe", "spawnlp", "spawnlpe",]) + __all__.extend(["spawnlp", "spawnlpe"]) + import copyreg as _copyreg -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 7 15:38:35 2013 From: python-checkins at python.org (richard.oudkerk) Date: Tue, 7 May 2013 15:38:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Correction_for_4f82b6cfee4?= =?utf-8?q?6=2E?= Message-ID: <3b4hjR4q6XzPDQ@mail.python.org> http://hg.python.org/cpython/rev/32067784f198 changeset: 83672:32067784f198 user: Richard Oudkerk date: Tue May 07 14:36:51 2013 +0100 summary: Correction for 4f82b6cfee46. files: Lib/os.py | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/Lib/os.py b/Lib/os.py --- a/Lib/os.py +++ b/Lib/os.py @@ -686,16 +686,21 @@ self[key] = value return self[key] -# if putenv or unsetenv exist they should already be in __all__ try: _putenv = putenv except NameError: _putenv = lambda key, value: None +else: + if "putenv" not in __all__: + __all__.append("putenv") try: _unsetenv = unsetenv except NameError: _unsetenv = lambda key: _putenv(key, "") +else: + if "unsetenv" not in __all__: + __all__.append("unsetenv") def _createenviron(): if name == 'nt': -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 7 23:51:34 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 7 May 2013 23:51:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_a_compiler_warning=3A_?= =?utf-8?q?in_and_out_are_unused_in_=5FPy=5Fchar2wchar=28=29_if?= Message-ID: <3b4vfG05tPzS7Z@mail.python.org> http://hg.python.org/cpython/rev/2ea629da4f54 changeset: 83673:2ea629da4f54 user: Victor Stinner date: Tue May 07 23:48:56 2013 +0200 summary: Fix a compiler warning: in and out are unused in _Py_char2wchar() if HAVE_MBRTOWC is not defined files: Python/fileutils.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/fileutils.c b/Python/fileutils.c --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -254,9 +254,9 @@ wchar_t *res; size_t argsize; size_t count; +#ifdef HAVE_MBRTOWC unsigned char *in; wchar_t *out; -#ifdef HAVE_MBRTOWC mbstate_t mbs; #endif -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 7 23:51:35 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 7 May 2013 23:51:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_audioop=3A_explicit_cast_t?= =?utf-8?q?o_fix_a_compiler_warning?= Message-ID: <3b4vfH2H40zS7Z@mail.python.org> http://hg.python.org/cpython/rev/41cf9f488225 changeset: 83674:41cf9f488225 user: Victor Stinner date: Tue May 07 23:49:15 2013 +0200 summary: audioop: explicit cast to fix a compiler warning files: Modules/audioop.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/audioop.c b/Modules/audioop.c --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -37,7 +37,7 @@ val = maxval; else if (val < minval + 1) val = minval; - return val; + return (int)val; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 7 23:51:36 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 7 May 2013 23:51:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_a_compiler_warning=3A_?= =?utf-8?q?use_unsigned_int_type_instead_of_enum_PyUnicode=5FKind_to?= Message-ID: <3b4vfJ4V9bz7LjX@mail.python.org> http://hg.python.org/cpython/rev/4ce2a4e75ad3 changeset: 83675:4ce2a4e75ad3 user: Victor Stinner date: Tue May 07 23:50:03 2013 +0200 summary: Fix a compiler warning: use unsigned int type instead of enum PyUnicode_Kind to compare two Unicode kinds files: Python/formatter_unicode.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/formatter_unicode.c b/Python/formatter_unicode.c --- a/Python/formatter_unicode.c +++ b/Python/formatter_unicode.c @@ -556,7 +556,7 @@ { /* Used to keep track of digits, decimal, and remainder. */ Py_ssize_t d_pos = d_start; - const enum PyUnicode_Kind kind = writer->kind; + const unsigned int kind = writer->kind; const void *data = writer->data; Py_ssize_t r; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 7 23:51:37 2013 From: python-checkins at python.org (victor.stinner) Date: Tue, 7 May 2013 23:51:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_zlib=3A_Explicit_cast_to_f?= =?utf-8?q?ix_a_compiler_warning?= Message-ID: <3b4vfK6dyDz7LjW@mail.python.org> http://hg.python.org/cpython/rev/8d1bdf8405a0 changeset: 83676:8d1bdf8405a0 user: Victor Stinner date: Tue May 07 23:50:21 2013 +0200 summary: zlib: Explicit cast to fix a compiler warning files: Modules/zlibmodule.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -573,7 +573,7 @@ Py_ssize_t old_size = PyBytes_GET_SIZE(self->unused_data); Py_ssize_t new_size; PyObject *new_data; - if (self->zst.avail_in > PY_SSIZE_T_MAX - old_size) { + if ((Py_ssize_t)self->zst.avail_in > PY_SSIZE_T_MAX - old_size) { PyErr_NoMemory(); return -1; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 8 00:43:19 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 8 May 2013 00:43:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_compiler_warnings=3A_e?= =?utf-8?q?xplicit_cast_to_int_in_sha256/sha512_modules?= Message-ID: <3b4wnz3sjsz7Ljv@mail.python.org> http://hg.python.org/cpython/rev/cfc5fbfbd32a changeset: 83677:cfc5fbfbd32a user: Victor Stinner date: Wed May 08 00:00:44 2013 +0200 summary: Fix compiler warnings: explicit cast to int in sha256/sha512 modules files: Modules/sha256module.c | 4 ++-- Modules/sha512module.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/sha256module.c b/Modules/sha256module.c --- a/Modules/sha256module.c +++ b/Modules/sha256module.c @@ -274,7 +274,7 @@ memcpy(((SHA_BYTE *) sha_info->data) + sha_info->local, buffer, i); count -= i; buffer += i; - sha_info->local += i; + sha_info->local += (int)i; if (sha_info->local == SHA_BLOCKSIZE) { sha_transform(sha_info); } @@ -289,7 +289,7 @@ sha_transform(sha_info); } memcpy(sha_info->data, buffer, count); - sha_info->local = count; + sha_info->local = (int)count; } /* finish computing the SHA digest */ diff --git a/Modules/sha512module.c b/Modules/sha512module.c --- a/Modules/sha512module.c +++ b/Modules/sha512module.c @@ -300,7 +300,7 @@ memcpy(((SHA_BYTE *) sha_info->data) + sha_info->local, buffer, i); count -= i; buffer += i; - sha_info->local += i; + sha_info->local += (int)i; if (sha_info->local == SHA_BLOCKSIZE) { sha512_transform(sha_info); } @@ -315,7 +315,7 @@ sha512_transform(sha_info); } memcpy(sha_info->data, buffer, count); - sha_info->local = count; + sha_info->local = (int)count; } /* finish computing the SHA digest */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 8 00:44:25 2013 From: python-checkins at python.org (victor.stinner) Date: Wed, 8 May 2013 00:44:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Use_Py=5Fintptr=5Ft_to_sto?= =?utf-8?q?re_the_difference_between_two_pointers=2C_instead_of_int?= Message-ID: <3b4wqF5hkfzSCd@mail.python.org> http://hg.python.org/cpython/rev/8e1caaf567c4 changeset: 83678:8e1caaf567c4 user: Victor Stinner date: Wed May 08 00:44:15 2013 +0200 summary: Use Py_intptr_t to store the difference between two pointers, instead of int Fix a compiler warning on Windows 64-bit files: Objects/descrobject.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Objects/descrobject.c b/Objects/descrobject.c --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1009,7 +1009,7 @@ static PyObject * wrapper_richcompare(PyObject *a, PyObject *b, int op) { - int result; + Py_intptr_t result; PyObject *v; PyWrapperDescrObject *a_descr, *b_descr; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 8 01:51:46 2013 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 8 May 2013 01:51:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3OTI2?= =?utf-8?q?=3A_Fix_dbm=2E=5F=5Fcontains=5F=5F_on_64-bit_big-endian_machine?= =?utf-8?q?s=2E?= Message-ID: <3b4yJy5qTcz7Ljj@mail.python.org> http://hg.python.org/cpython/rev/53da3bad8554 changeset: 83679:53da3bad8554 branch: 2.7 parent: 83667:8b764c3521fa user: Antoine Pitrou date: Wed May 08 01:51:37 2013 +0200 summary: Issue #17926: Fix dbm.__contains__ on 64-bit big-endian machines. files: Misc/NEWS | 2 ++ Modules/dbmmodule.c | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -34,6 +34,8 @@ Library ------- +- Issue #17926: Fix dbm.__contains__ on 64-bit big-endian machines. + - Issue #17918: When using SSLSocket.accept(), if the SSL handshake failed on the new socket, the socket would linger indefinitely. Thanks to Peter Saveliev for reporting. diff --git a/Modules/dbmmodule.c b/Modules/dbmmodule.c --- a/Modules/dbmmodule.c +++ b/Modules/dbmmodule.c @@ -168,11 +168,13 @@ dbm_contains(register dbmobject *dp, PyObject *v) { datum key, val; + char *ptr; + Py_ssize_t size; - if (PyString_AsStringAndSize(v, (char **)&key.dptr, - (Py_ssize_t *)&key.dsize)) { + if (PyString_AsStringAndSize(v, &ptr, &size)) return -1; - } + key.dptr = ptr; + key.dsize = size; /* Expand check_dbmobject_open to return -1 */ if (dp->di_dbm == NULL) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 8 02:07:22 2013 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 8 May 2013 02:07:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3OTI4?= =?utf-8?q?=3A_Fix_test=5Fstructmembers_on_64-bit_big-endian_machines=2E?= Message-ID: <3b4yfy6MdWzR9k@mail.python.org> http://hg.python.org/cpython/rev/a199ec80c679 changeset: 83680:a199ec80c679 branch: 2.7 user: Antoine Pitrou date: Wed May 08 02:07:13 2013 +0200 summary: Issue #17928: Fix test_structmembers on 64-bit big-endian machines. (_testcapi isn't Py_ssize_t-clean, the "s#" code should use an int for length) files: Misc/NEWS | 2 ++ Modules/_testcapimodule.c | 2 +- 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -97,6 +97,8 @@ Tests ----- +- Issue #17928: Fix test_structmembers on 64-bit big-endian machines. + - Issue #17883: Fix buildbot testing of Tkinter on Windows. Patch by Zachary Ware. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1813,7 +1813,7 @@ ; test_structmembers *ob; const char *s = NULL; - Py_ssize_t string_len = 0; + int string_len = 0; ob = PyObject_New(test_structmembers, type); if (ob == NULL) return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 8 03:23:19 2013 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 8 May 2013 03:23:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Fix_NEWS_order?= Message-ID: <3b50Lb0pcYz7LkR@mail.python.org> http://hg.python.org/cpython/rev/98856b41b6a6 changeset: 83681:98856b41b6a6 branch: 2.7 user: Antoine Pitrou date: Wed May 08 03:23:10 2013 +0200 summary: Fix NEWS order files: Misc/NEWS | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -6,14 +6,6 @@ *Release date: XXXX-XX-XX* -Build ------ - -- Issue #17682: Add the _io module to Modules/Setup.dist (commented out). - -- Issue #17086: Search the include and library directories provided by the - compiler. - Core and Builtins ----------------- @@ -94,6 +86,14 @@ - Issue #17526: fix an IndexError raised while passing code without filename to inspect.findsource(). Initial patch by Tyler Doyle. +Build +----- + +- Issue #17682: Add the _io module to Modules/Setup.dist (commented out). + +- Issue #17086: Search the include and library directories provided by the + compiler. + Tests ----- -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed May 8 06:06:35 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 08 May 2013 06:06:35 +0200 Subject: [Python-checkins] Daily reference leaks (8e1caaf567c4): sum=2 Message-ID: results for 8e1caaf567c4 on branch "default" -------------------------------------------- test_support leaked [0, -1, 1] references, sum=0 test_support leaked [0, -1, 3] memory blocks, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogJjqd9q', '-x'] From python-checkins at python.org Wed May 8 09:57:06 2013 From: python-checkins at python.org (ezio.melotti) Date: Wed, 8 May 2013 09:57:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE2NTIzOiBpbXBy?= =?utf-8?q?ove_attrgetter/itemgetter/methodcaller_documentation=2E?= Message-ID: <3b594y1FQRz7Lk0@mail.python.org> http://hg.python.org/cpython/rev/6f2412f12bfd changeset: 83682:6f2412f12bfd branch: 3.3 parent: 83668:cbb23e40e0d7 user: Ezio Melotti date: Wed May 08 10:53:11 2013 +0300 summary: #16523: improve attrgetter/itemgetter/methodcaller documentation. files: Doc/library/operator.rst | 47 +++++++++++++++++++-------- Modules/operator.c | 14 ++++---- 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/Doc/library/operator.rst b/Doc/library/operator.rst --- a/Doc/library/operator.rst +++ b/Doc/library/operator.rst @@ -241,13 +241,22 @@ expect a function argument. -.. function:: attrgetter(attr[, args...]) +.. function:: attrgetter(attr) + attrgetter(*attrs) - Return a callable object that fetches *attr* from its operand. If more than one - attribute is requested, returns a tuple of attributes. After, - ``f = attrgetter('name')``, the call ``f(b)`` returns ``b.name``. After, - ``f = attrgetter('name', 'date')``, the call ``f(b)`` returns ``(b.name, - b.date)``. Equivalent to:: + Return a callable object that fetches *attr* from its operand. + If more than one attribute is requested, returns a tuple of attributes. + The attribute names can also contain dots. For example: + + * After ``f = attrgetter('name')``, the call ``f(b)`` returns ``b.name``. + + * After ``f = attrgetter('name', 'date')``, the call ``f(b)`` returns + ``(b.name, b.date)``. + + * After ``f = attrgetter('name.first', 'name.last')``, the call ``f(b)`` + returns ``(r.name.first, r.name.last)``. + + Equivalent to:: def attrgetter(*items): if any(not isinstance(item, str) for item in items): @@ -267,14 +276,19 @@ return obj - The attribute names can also contain dots; after ``f = attrgetter('date.month')``, - the call ``f(b)`` returns ``b.date.month``. - -.. function:: itemgetter(item[, args...]) +.. function:: itemgetter(item) + itemgetter(*items) Return a callable object that fetches *item* from its operand using the operand's :meth:`__getitem__` method. If multiple items are specified, - returns a tuple of lookup values. Equivalent to:: + returns a tuple of lookup values. For example: + + * After ``f = itemgetter(2)``, the call ``f(r)`` returns ``r[2]``. + + * After ``g = itemgetter(2, 5, 3)``, the call ``g(r)`` returns + ``(r[2], r[5], r[3])``. + + Equivalent to:: def itemgetter(*items): if len(items) == 1: @@ -313,9 +327,14 @@ Return a callable object that calls the method *name* on its operand. If additional arguments and/or keyword arguments are given, they will be given - to the method as well. After ``f = methodcaller('name')``, the call ``f(b)`` - returns ``b.name()``. After ``f = methodcaller('name', 'foo', bar=1)``, the - call ``f(b)`` returns ``b.name('foo', bar=1)``. Equivalent to:: + to the method as well. For example: + + * After ``f = methodcaller('name')``, the call ``f(b)`` returns ``b.name()``. + + * After ``f = methodcaller('name', 'foo', bar=1)``, the call ``f(b)`` + returns ``b.name('foo', bar=1)``. + + Equivalent to:: def methodcaller(name, *args, **kwargs): def caller(obj): diff --git a/Modules/operator.c b/Modules/operator.c --- a/Modules/operator.c +++ b/Modules/operator.c @@ -460,8 +460,8 @@ "itemgetter(item, ...) --> itemgetter object\n\ \n\ Return a callable object that fetches the given item(s) from its operand.\n\ -After, f=itemgetter(2), the call f(r) returns r[2].\n\ -After, g=itemgetter(2,5,3), the call g(r) returns (r[2], r[5], r[3])"); +After f = itemgetter(2), the call f(r) returns r[2].\n\ +After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3])"); static PyTypeObject itemgetter_type = { PyVarObject_HEAD_INIT(NULL, 0) @@ -712,9 +712,9 @@ "attrgetter(attr, ...) --> attrgetter object\n\ \n\ Return a callable object that fetches the given attribute(s) from its operand.\n\ -After, f=attrgetter('name'), the call f(r) returns r.name.\n\ -After, g=attrgetter('name', 'date'), the call g(r) returns (r.name, r.date).\n\ -After, h=attrgetter('name.first', 'name.last'), the call h(r) returns\n\ +After f = attrgetter('name'), the call f(r) returns r.name.\n\ +After g = attrgetter('name', 'date'), the call g(r) returns (r.name, r.date).\n\ +After h = attrgetter('name.first', 'name.last'), the call h(r) returns\n\ (r.name.first, r.name.last)."); static PyTypeObject attrgetter_type = { @@ -844,8 +844,8 @@ "methodcaller(name, ...) --> methodcaller object\n\ \n\ Return a callable object that calls the given method on its operand.\n\ -After, f = methodcaller('name'), the call f(r) returns r.name().\n\ -After, g = methodcaller('name', 'date', foo=1), the call g(r) returns\n\ +After f = methodcaller('name'), the call f(r) returns r.name().\n\ +After g = methodcaller('name', 'date', foo=1), the call g(r) returns\n\ r.name('date', foo=1)."); static PyTypeObject methodcaller_type = { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 8 09:57:07 2013 From: python-checkins at python.org (ezio.melotti) Date: Wed, 8 May 2013 09:57:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzE2NTIzOiBtZXJnZSB3aXRoIDMuMy4=?= Message-ID: <3b594z4Y5Rz7LlN@mail.python.org> http://hg.python.org/cpython/rev/c2000ce25fe8 changeset: 83683:c2000ce25fe8 parent: 83678:8e1caaf567c4 parent: 83682:6f2412f12bfd user: Ezio Melotti date: Wed May 08 10:56:32 2013 +0300 summary: #16523: merge with 3.3. files: Doc/library/operator.rst | 47 +++++++++++++++++++-------- Lib/operator.py | 10 ++-- Modules/_operator.c | 10 ++-- 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/Doc/library/operator.rst b/Doc/library/operator.rst --- a/Doc/library/operator.rst +++ b/Doc/library/operator.rst @@ -249,13 +249,22 @@ expect a function argument. -.. function:: attrgetter(attr[, args...]) +.. function:: attrgetter(attr) + attrgetter(*attrs) - Return a callable object that fetches *attr* from its operand. If more than one - attribute is requested, returns a tuple of attributes. After, - ``f = attrgetter('name')``, the call ``f(b)`` returns ``b.name``. After, - ``f = attrgetter('name', 'date')``, the call ``f(b)`` returns ``(b.name, - b.date)``. Equivalent to:: + Return a callable object that fetches *attr* from its operand. + If more than one attribute is requested, returns a tuple of attributes. + The attribute names can also contain dots. For example: + + * After ``f = attrgetter('name')``, the call ``f(b)`` returns ``b.name``. + + * After ``f = attrgetter('name', 'date')``, the call ``f(b)`` returns + ``(b.name, b.date)``. + + * After ``f = attrgetter('name.first', 'name.last')``, the call ``f(b)`` + returns ``(r.name.first, r.name.last)``. + + Equivalent to:: def attrgetter(*items): if any(not isinstance(item, str) for item in items): @@ -275,14 +284,19 @@ return obj - The attribute names can also contain dots; after ``f = attrgetter('date.month')``, - the call ``f(b)`` returns ``b.date.month``. - -.. function:: itemgetter(item[, args...]) +.. function:: itemgetter(item) + itemgetter(*items) Return a callable object that fetches *item* from its operand using the operand's :meth:`__getitem__` method. If multiple items are specified, - returns a tuple of lookup values. Equivalent to:: + returns a tuple of lookup values. For example: + + * After ``f = itemgetter(2)``, the call ``f(r)`` returns ``r[2]``. + + * After ``g = itemgetter(2, 5, 3)``, the call ``g(r)`` returns + ``(r[2], r[5], r[3])``. + + Equivalent to:: def itemgetter(*items): if len(items) == 1: @@ -321,9 +335,14 @@ Return a callable object that calls the method *name* on its operand. If additional arguments and/or keyword arguments are given, they will be given - to the method as well. After ``f = methodcaller('name')``, the call ``f(b)`` - returns ``b.name()``. After ``f = methodcaller('name', 'foo', bar=1)``, the - call ``f(b)`` returns ``b.name('foo', bar=1)``. Equivalent to:: + to the method as well. For example: + + * After ``f = methodcaller('name')``, the call ``f(b)`` returns ``b.name()``. + + * After ``f = methodcaller('name', 'foo', bar=1)``, the call ``f(b)`` + returns ``b.name('foo', bar=1)``. + + Equivalent to:: def methodcaller(name, *args, **kwargs): def caller(obj): diff --git a/Lib/operator.py b/Lib/operator.py --- a/Lib/operator.py +++ b/Lib/operator.py @@ -223,9 +223,9 @@ class attrgetter: """ Return a callable object that fetches the given attribute(s) from its operand. - After f=attrgetter('name'), the call f(r) returns r.name. - After g=attrgetter('name', 'date'), the call g(r) returns (r.name, r.date). - After h=attrgetter('name.first', 'name.last'), the call h(r) returns + After f = attrgetter('name'), the call f(r) returns r.name. + After g = attrgetter('name', 'date'), the call g(r) returns (r.name, r.date). + After h = attrgetter('name.first', 'name.last'), the call h(r) returns (r.name.first, r.name.last). """ def __init__(self, attr, *attrs): @@ -250,8 +250,8 @@ class itemgetter: """ Return a callable object that fetches the given item(s) from its operand. - After f=itemgetter(2), the call f(r) returns r[2]. - After g=itemgetter(2,5,3), the call g(r) returns (r[2], r[5], r[3]) + After f = itemgetter(2), the call f(r) returns r[2]. + After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3]) """ def __init__(self, item, *items): if not items: diff --git a/Modules/_operator.c b/Modules/_operator.c --- a/Modules/_operator.c +++ b/Modules/_operator.c @@ -485,8 +485,8 @@ "itemgetter(item, ...) --> itemgetter object\n\ \n\ Return a callable object that fetches the given item(s) from its operand.\n\ -After f=itemgetter(2), the call f(r) returns r[2].\n\ -After g=itemgetter(2,5,3), the call g(r) returns (r[2], r[5], r[3])"); +After f = itemgetter(2), the call f(r) returns r[2].\n\ +After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3])"); static PyTypeObject itemgetter_type = { PyVarObject_HEAD_INIT(NULL, 0) @@ -737,9 +737,9 @@ "attrgetter(attr, ...) --> attrgetter object\n\ \n\ Return a callable object that fetches the given attribute(s) from its operand.\n\ -After f=attrgetter('name'), the call f(r) returns r.name.\n\ -After g=attrgetter('name', 'date'), the call g(r) returns (r.name, r.date).\n\ -After h=attrgetter('name.first', 'name.last'), the call h(r) returns\n\ +After f = attrgetter('name'), the call f(r) returns r.name.\n\ +After g = attrgetter('name', 'date'), the call g(r) returns (r.name, r.date).\n\ +After h = attrgetter('name.first', 'name.last'), the call h(r) returns\n\ (r.name.first, r.name.last)."); static PyTypeObject attrgetter_type = { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 8 09:57:09 2013 From: python-checkins at python.org (ezio.melotti) Date: Wed, 8 May 2013 09:57:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE2NTIzOiBpbXBy?= =?utf-8?q?ove_attrgetter/itemgetter/methodcaller_documentation=2E?= Message-ID: <3b59510v09z7Ll9@mail.python.org> http://hg.python.org/cpython/rev/5885c02120f0 changeset: 83684:5885c02120f0 branch: 2.7 parent: 83681:98856b41b6a6 user: Ezio Melotti date: Wed May 08 10:53:11 2013 +0300 summary: #16523: improve attrgetter/itemgetter/methodcaller documentation. files: Doc/library/operator.rst | 47 +++++++++++++++++++-------- Modules/operator.c | 14 ++++---- 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/Doc/library/operator.rst b/Doc/library/operator.rst --- a/Doc/library/operator.rst +++ b/Doc/library/operator.rst @@ -490,13 +490,22 @@ expect a function argument. -.. function:: attrgetter(attr[, args...]) +.. function:: attrgetter(attr) + attrgetter(*attrs) - Return a callable object that fetches *attr* from its operand. If more than one - attribute is requested, returns a tuple of attributes. After, - ``f = attrgetter('name')``, the call ``f(b)`` returns ``b.name``. After, - ``f = attrgetter('name', 'date')``, the call ``f(b)`` returns ``(b.name, - b.date)``. Equivalent to:: + Return a callable object that fetches *attr* from its operand. + If more than one attribute is requested, returns a tuple of attributes. + The attribute names can also contain dots. For example: + + * After ``f = attrgetter('name')``, the call ``f(b)`` returns ``b.name``. + + * After ``f = attrgetter('name', 'date')``, the call ``f(b)`` returns + ``(b.name, b.date)``. + + * After ``f = attrgetter('name.first', 'name.last')``, the call ``f(b)`` + returns ``(r.name.first, r.name.last)``. + + Equivalent to:: def attrgetter(*items): if len(items) == 1: @@ -514,8 +523,8 @@ return obj - The attribute names can also contain dots; after ``f = attrgetter('date.month')``, - the call ``f(b)`` returns ``b.date.month``. +.. function:: itemgetter(item) + itemgetter(*items) .. versionadded:: 2.4 @@ -526,11 +535,16 @@ Added support for dotted attributes. -.. function:: itemgetter(item[, args...]) - Return a callable object that fetches *item* from its operand using the operand's :meth:`__getitem__` method. If multiple items are specified, - returns a tuple of lookup values. Equivalent to:: + returns a tuple of lookup values. For example: + + * After ``f = itemgetter(2)``, the call ``f(r)`` returns ``r[2]``. + + * After ``g = itemgetter(2, 5, 3)``, the call ``g(r)`` returns + ``(r[2], r[5], r[3])``. + + Equivalent to:: def itemgetter(*items): if len(items) == 1: @@ -573,9 +587,14 @@ Return a callable object that calls the method *name* on its operand. If additional arguments and/or keyword arguments are given, they will be given - to the method as well. After ``f = methodcaller('name')``, the call ``f(b)`` - returns ``b.name()``. After ``f = methodcaller('name', 'foo', bar=1)``, the - call ``f(b)`` returns ``b.name('foo', bar=1)``. Equivalent to:: + to the method as well. For example: + + * After ``f = methodcaller('name')``, the call ``f(b)`` returns ``b.name()``. + + * After ``f = methodcaller('name', 'foo', bar=1)``, the call ``f(b)`` + returns ``b.name('foo', bar=1)``. + + Equivalent to:: def methodcaller(name, *args, **kwargs): def caller(obj): diff --git a/Modules/operator.c b/Modules/operator.c --- a/Modules/operator.c +++ b/Modules/operator.c @@ -412,8 +412,8 @@ "itemgetter(item, ...) --> itemgetter object\n\ \n\ Return a callable object that fetches the given item(s) from its operand.\n\ -After, f=itemgetter(2), the call f(r) returns r[2].\n\ -After, g=itemgetter(2,5,3), the call g(r) returns (r[2], r[5], r[3])"); +After f = itemgetter(2), the call f(r) returns r[2].\n\ +After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3])"); static PyTypeObject itemgetter_type = { PyVarObject_HEAD_INIT(NULL, 0) @@ -592,9 +592,9 @@ "attrgetter(attr, ...) --> attrgetter object\n\ \n\ Return a callable object that fetches the given attribute(s) from its operand.\n\ -After, f=attrgetter('name'), the call f(r) returns r.name.\n\ -After, g=attrgetter('name', 'date'), the call g(r) returns (r.name, r.date).\n\ -After, h=attrgetter('name.first', 'name.last'), the call h(r) returns\n\ +After f = attrgetter('name'), the call f(r) returns r.name.\n\ +After g = attrgetter('name', 'date'), the call g(r) returns (r.name, r.date).\n\ +After h = attrgetter('name.first', 'name.last'), the call h(r) returns\n\ (r.name.first, r.name.last)."); static PyTypeObject attrgetter_type = { @@ -724,8 +724,8 @@ "methodcaller(name, ...) --> methodcaller object\n\ \n\ Return a callable object that calls the given method on its operand.\n\ -After, f = methodcaller('name'), the call f(r) returns r.name().\n\ -After, g = methodcaller('name', 'date', foo=1), the call g(r) returns\n\ +After f = methodcaller('name'), the call f(r) returns r.name().\n\ +After g = methodcaller('name', 'date', foo=1), the call g(r) returns\n\ r.name('date', foo=1)."); static PyTypeObject methodcaller_type = { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 8 10:16:55 2013 From: python-checkins at python.org (ezio.melotti) Date: Wed, 8 May 2013 10:16:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE3ODc3OiBza2lw?= =?utf-8?q?_test_if_the_Olson=27s_TZ_database_is_missing=2E?= Message-ID: <3b59Wq6F0qzQgD@mail.python.org> http://hg.python.org/cpython/rev/f7b552020d44 changeset: 83685:f7b552020d44 branch: 3.3 parent: 83682:6f2412f12bfd user: Ezio Melotti date: Wed May 08 11:16:02 2013 +0300 summary: #17877: skip test if the Olson's TZ database is missing. files: Lib/test/test_email/test_utils.py | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_email/test_utils.py b/Lib/test/test_email/test_utils.py --- a/Lib/test/test_email/test_utils.py +++ b/Lib/test/test_email/test_utils.py @@ -4,6 +4,7 @@ import time import unittest import sys +import os.path class DateTimeTests(unittest.TestCase): @@ -123,6 +124,9 @@ # XXX: Need a more robust test for Olson's tzdata @unittest.skipIf(sys.platform.startswith('win'), "Windows does not use Olson's TZ database") + @unittest.skipUnless(os.path.exists('/usr/share/zoneinfo') or + os.path.exists('/usr/lib/zoneinfo'), + "Can't find the Olson's TZ database") @test.support.run_with_tz('Europe/Kiev') def test_variable_tzname(self): t0 = datetime.datetime(1984, 1, 1, tzinfo=datetime.timezone.utc) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 8 10:16:57 2013 From: python-checkins at python.org (ezio.melotti) Date: Wed, 8 May 2013 10:16:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzE3ODc3OiBtZXJnZSB3aXRoIDMuMy4=?= Message-ID: <3b59Ws1Gdbz7LkG@mail.python.org> http://hg.python.org/cpython/rev/492eba054e59 changeset: 83686:492eba054e59 parent: 83683:c2000ce25fe8 parent: 83685:f7b552020d44 user: Ezio Melotti date: Wed May 08 11:16:33 2013 +0300 summary: #17877: merge with 3.3. files: Lib/test/test_email/test_utils.py | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_email/test_utils.py b/Lib/test/test_email/test_utils.py --- a/Lib/test/test_email/test_utils.py +++ b/Lib/test/test_email/test_utils.py @@ -4,6 +4,7 @@ import time import unittest import sys +import os.path class DateTimeTests(unittest.TestCase): @@ -123,6 +124,9 @@ # XXX: Need a more robust test for Olson's tzdata @unittest.skipIf(sys.platform.startswith('win'), "Windows does not use Olson's TZ database") + @unittest.skipUnless(os.path.exists('/usr/share/zoneinfo') or + os.path.exists('/usr/lib/zoneinfo'), + "Can't find the Olson's TZ database") @test.support.run_with_tz('Europe/Kiev') def test_variable_tzname(self): t0 = datetime.datetime(1984, 1, 1, tzinfo=datetime.timezone.utc) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 8 13:23:35 2013 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 8 May 2013 13:23:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=231545463=3A_At_shu?= =?utf-8?q?tdown=2C_defer_finalization_of_codec_modules_so_that_stderr?= Message-ID: <3b5FgC2Zt4z7Ljx@mail.python.org> http://hg.python.org/cpython/rev/8a5bebea9fec changeset: 83687:8a5bebea9fec user: Antoine Pitrou date: Wed May 08 13:23:25 2013 +0200 summary: Issue #1545463: At shutdown, defer finalization of codec modules so that stderr remains usable. (should fix Windows buildbot failures on test_gc) files: Include/warnings.h | 6 +++ Misc/NEWS | 3 + Modules/gcmodule.c | 10 ++++- Python/_warnings.c | 47 +++++++++++++++++++++++++++- Python/import.c | 55 +++++++++++++++++++++------------ 5 files changed, 96 insertions(+), 25 deletions(-) diff --git a/Include/warnings.h b/Include/warnings.h --- a/Include/warnings.h +++ b/Include/warnings.h @@ -25,6 +25,12 @@ const char *module, /* UTF-8 encoded string */ PyObject *registry); +PyAPI_FUNC(int) +PyErr_WarnExplicitFormat(PyObject *category, + const char *filename, int lineno, + const char *module, PyObject *registry, + const char *format, ...); + /* DEPRECATED: Use PyErr_WarnEx() instead. */ #ifndef Py_LIMITED_API #define PyErr_Warn(category, msg) PyErr_WarnEx(category, msg, 1) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #1545463: At shutdown, defer finalization of codec modules so + that stderr remains usable. + - Issue #7330: Implement width and precision (ex: "%5.3s") for the format string of PyUnicode_FromFormat() function, original patch written by Ysj Ray. diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1557,8 +1557,12 @@ else message = "gc: %zd uncollectable objects at " \ "shutdown; use gc.set_debug(gc.DEBUG_UNCOLLECTABLE) to list them"; - if (PyErr_WarnFormat(PyExc_ResourceWarning, 0, message, - PyList_GET_SIZE(garbage)) < 0) + /* PyErr_WarnFormat does too many things and we are at shutdown, + the warnings module's dependencies (e.g. linecache) may be gone + already. */ + if (PyErr_WarnExplicitFormat(PyExc_ResourceWarning, "gc", 0, + "gc", NULL, message, + PyList_GET_SIZE(garbage))) PyErr_WriteUnraisable(NULL); if (debug & DEBUG_UNCOLLECTABLE) { PyObject *repr = NULL, *bytes = NULL; @@ -1567,7 +1571,7 @@ PyErr_WriteUnraisable(garbage); else { PySys_WriteStderr( - " %s\n", + " %s\n", PyBytes_AS_STRING(bytes) ); } diff --git a/Python/_warnings.c b/Python/_warnings.c --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -800,8 +800,8 @@ goto exit; if (module_str != NULL) { module = PyUnicode_FromString(module_str); - if (module == NULL) - goto exit; + if (module == NULL) + goto exit; } if (category == NULL) @@ -820,6 +820,49 @@ return ret; } +int +PyErr_WarnExplicitFormat(PyObject *category, + const char *filename_str, int lineno, + const char *module_str, PyObject *registry, + const char *format, ...) +{ + PyObject *message; + PyObject *module = NULL; + PyObject *filename = PyUnicode_DecodeFSDefault(filename_str); + int ret = -1; + va_list vargs; + + if (filename == NULL) + goto exit; + if (module_str != NULL) { + module = PyUnicode_FromString(module_str); + if (module == NULL) + goto exit; + } + +#ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, format); +#else + va_start(vargs); +#endif + message = PyUnicode_FromFormatV(format, vargs); + if (message != NULL) { + PyObject *res; + res = warn_explicit(category, message, filename, lineno, + module, registry, NULL); + Py_DECREF(message); + if (res != NULL) { + Py_DECREF(res); + ret = 0; + } + } + va_end(vargs); +exit: + Py_XDECREF(module); + Py_XDECREF(filename); + return ret; +} + PyDoc_STRVAR(warn_doc, "Issue a warning, or maybe ignore it or raise an exception."); diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -295,6 +295,30 @@ NULL }; +static int +is_essential_module(PyObject *name) +{ + Py_ssize_t name_len; + char *name_str = PyUnicode_AsUTF8AndSize(name, &name_len); + + if (name_str == NULL) { + PyErr_Clear(); + return 0; + } + if (strcmp(name_str, "builtins") == 0) + return 1; + if (strcmp(name_str, "sys") == 0) + return 1; + /* These are all needed for stderr to still function */ + if (strcmp(name_str, "codecs") == 0) + return 1; + if (strcmp(name_str, "_codecs") == 0) + return 1; + if (strncmp(name_str, "encodings.", 10) == 0) + return 1; + return 0; +} + /* Un-initialize things, as good as we can */ @@ -374,9 +398,7 @@ if (value->ob_refcnt != 1) continue; if (PyUnicode_Check(key) && PyModule_Check(value)) { - if (PyUnicode_CompareWithASCIIString(key, "builtins") == 0) - continue; - if (PyUnicode_CompareWithASCIIString(key, "sys") == 0) + if (is_essential_module(key)) continue; if (Py_VerboseFlag) PySys_FormatStderr( @@ -392,9 +414,7 @@ pos = 0; while (PyDict_Next(modules, &pos, &key, &value)) { if (PyUnicode_Check(key) && PyModule_Check(value)) { - if (PyUnicode_CompareWithASCIIString(key, "builtins") == 0) - continue; - if (PyUnicode_CompareWithASCIIString(key, "sys") == 0) + if (is_essential_module(key)) continue; if (Py_VerboseFlag) PySys_FormatStderr("# cleanup[2] %U\n", key); @@ -411,20 +431,15 @@ machinery. */ _PyGC_DumpShutdownStats(); - /* Next, delete sys and builtins (in that order) */ - value = PyDict_GetItemString(modules, "sys"); - if (value != NULL && PyModule_Check(value)) { - if (Py_VerboseFlag) - PySys_WriteStderr("# cleanup sys\n"); - _PyModule_Clear(value); - PyDict_SetItemString(modules, "sys", Py_None); - } - value = PyDict_GetItemString(modules, "builtins"); - if (value != NULL && PyModule_Check(value)) { - if (Py_VerboseFlag) - PySys_WriteStderr("# cleanup builtins\n"); - _PyModule_Clear(value); - PyDict_SetItemString(modules, "builtins", Py_None); + /* Next, delete all remaining modules */ + pos = 0; + while (PyDict_Next(modules, &pos, &key, &value)) { + if (PyUnicode_Check(key) && PyModule_Check(value)) { + if (Py_VerboseFlag) + PySys_FormatStderr("# cleanup[3] %U\n", key); + _PyModule_Clear(value); + PyDict_SetItem(modules, key, Py_None); + } } /* Finally, clear and delete the modules directory */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 8 18:12:47 2013 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 8 May 2013 18:12:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2317807=3A_Generato?= =?utf-8?q?rs_can_now_be_finalized_even_when_they_are_part_of_a?= Message-ID: <3b5N4v2zCyz7LjR@mail.python.org> http://hg.python.org/cpython/rev/c89febab4648 changeset: 83688:c89febab4648 user: Antoine Pitrou date: Wed May 08 18:12:35 2013 +0200 summary: Issue #17807: Generators can now be finalized even when they are part of a reference cycle. files: Include/frameobject.h | 9 + Include/genobject.h | 1 + Lib/test/test_generators.py | 53 +++++ Lib/test/test_sys.py | 2 +- Misc/NEWS | 3 + Modules/gcmodule.c | 5 +- Objects/frameobject.c | 254 ++++++++++++++++++++++- Objects/genobject.c | 253 +++-------------------- 8 files changed, 335 insertions(+), 245 deletions(-) diff --git a/Include/frameobject.h b/Include/frameobject.h --- a/Include/frameobject.h +++ b/Include/frameobject.h @@ -36,6 +36,8 @@ non-generator frames. See the save_exc_state and swap_exc_state functions in ceval.c for details of their use. */ PyObject *f_exc_type, *f_exc_value, *f_exc_traceback; + /* Borrowed referenced to a generator, or NULL */ + PyObject *f_gen; PyThreadState *f_tstate; int f_lasti; /* Last instruction if called */ @@ -84,6 +86,13 @@ /* Return the line of code the frame is currently executing. */ PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *); +/* Generator support */ +PyAPI_FUNC(PyObject *) _PyFrame_YieldingFrom(PyFrameObject *); +PyAPI_FUNC(PyObject *) _PyFrame_GeneratorSend(PyFrameObject *, PyObject *, int exc); +PyAPI_FUNC(PyObject *) _PyFrame_Finalize(PyFrameObject *); +PyAPI_FUNC(int) _PyFrame_CloseIterator(PyObject *); + + #ifdef __cplusplus } #endif diff --git a/Include/genobject.h b/Include/genobject.h --- a/Include/genobject.h +++ b/Include/genobject.h @@ -33,6 +33,7 @@ #define PyGen_CheckExact(op) (Py_TYPE(op) == &PyGen_Type) PyAPI_FUNC(PyObject *) PyGen_New(struct _frame *); +/* Deprecated, kept for backwards compatibility. */ PyAPI_FUNC(int) PyGen_NeedsFinalizing(PyGenObject *); PyAPI_FUNC(int) _PyGen_FetchStopIterationValue(PyObject **); PyObject *_PyGen_Send(PyGenObject *, PyObject *); diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -1,3 +1,55 @@ +import gc +import sys +import unittest +import weakref + +from test import support + + +class FinalizationTest(unittest.TestCase): + + def test_frame_resurrect(self): + # A generator frame can be resurrected by a generator's finalization. + def gen(): + nonlocal frame + try: + yield + finally: + frame = sys._getframe() + + g = gen() + wr = weakref.ref(g) + next(g) + del g + support.gc_collect() + self.assertIs(wr(), None) + self.assertTrue(frame) + del frame + support.gc_collect() + + def test_refcycle(self): + # A generator caught in a refcycle gets finalized anyway. + old_garbage = gc.garbage[:] + finalized = False + def gen(): + nonlocal finalized + try: + g = yield + yield 1 + finally: + finalized = True + + g = gen() + next(g) + g.send(g) + self.assertGreater(sys.getrefcount(g), 2) + self.assertFalse(finalized) + del g + support.gc_collect() + self.assertTrue(finalized) + self.assertEqual(gc.garbage, old_garbage) + + tutorial_tests = """ Let's try a simple generator: @@ -1880,6 +1932,7 @@ # so this works as expected in both ways of running regrtest. def test_main(verbose=None): from test import support, test_generators + support.run_unittest(__name__) support.run_doctest(test_generators, verbose) # This part isn't needed for regrtest, but for running the test directly. 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 @@ -764,7 +764,7 @@ nfrees = len(x.f_code.co_freevars) extras = x.f_code.co_stacksize + x.f_code.co_nlocals +\ ncells + nfrees - 1 - check(x, vsize('12P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) + check(x, vsize('13P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) # function def func(): pass check(func, size('12P')) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #17807: Generators can now be finalized even when they are part of + a reference cycle. + - Issue #1545463: At shutdown, defer finalization of codec modules so that stderr remains usable. diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -524,10 +524,7 @@ static int has_finalizer(PyObject *op) { - if (PyGen_CheckExact(op)) - return PyGen_NeedsFinalizing((PyGenObject *)op); - else - return op->ob_type->tp_del != NULL; + return op->ob_type->tp_del != NULL; } /* Move the objects in unreachable with __del__ methods into `finalizers`. diff --git a/Objects/frameobject.c b/Objects/frameobject.c --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -31,6 +31,195 @@ return f->f_locals; } +/* + * Generator support. + */ + +PyObject * +_PyFrame_YieldingFrom(PyFrameObject *f) +{ + PyObject *yf = NULL; + + if (f && f->f_stacktop) { + PyObject *bytecode = f->f_code->co_code; + unsigned char *code = (unsigned char *)PyBytes_AS_STRING(bytecode); + + if (code[f->f_lasti + 1] != YIELD_FROM) + return NULL; + yf = f->f_stacktop[-1]; + Py_INCREF(yf); + } + return yf; +} + +PyObject * +_PyFrame_GeneratorSend(PyFrameObject *f, PyObject *arg, int exc) +{ + PyThreadState *tstate = PyThreadState_GET(); + PyObject *result; + PyGenObject *gen = (PyGenObject *) f->f_gen; + + assert(gen == NULL || PyGen_CheckExact(gen)); + if (gen && gen->gi_running) { + PyErr_SetString(PyExc_ValueError, + "generator already executing"); + return NULL; + } + if (f->f_stacktop == NULL) { + /* Only set exception if send() called, not throw() or next() */ + if (arg && !exc) + PyErr_SetNone(PyExc_StopIteration); + return NULL; + } + + if (f->f_lasti == -1) { + if (arg && arg != Py_None) { + PyErr_SetString(PyExc_TypeError, + "can't send non-None value to a " + "just-started generator"); + return NULL; + } + } else { + /* Push arg onto the frame's value stack */ + result = arg ? arg : Py_None; + Py_INCREF(result); + *(f->f_stacktop++) = result; + } + + /* Generators always return to their most recent caller, not + * necessarily their creator. */ + Py_XINCREF(tstate->frame); + assert(f->f_back == NULL); + f->f_back = tstate->frame; + + if (gen) { + Py_INCREF(gen); + gen->gi_running = 1; + } + result = PyEval_EvalFrameEx(f, exc); + if (gen) { + gen->gi_running = 0; + /* In case running the frame has lost all external references + * to gen, we must be careful not to hold on an invalid object. */ + if (Py_REFCNT(gen) == 1) + Py_CLEAR(gen); + else + Py_DECREF(gen); + } + + /* Don't keep the reference to f_back any longer than necessary. It + * may keep a chain of frames alive or it could create a reference + * cycle. */ + assert(f->f_back == tstate->frame); + Py_CLEAR(f->f_back); + + /* If the generator just returned (as opposed to yielding), signal + * that the generator is exhausted. */ + if (result && f->f_stacktop == NULL) { + if (result == Py_None) { + /* Delay exception instantiation if we can */ + PyErr_SetNone(PyExc_StopIteration); + } else { + PyObject *e = PyObject_CallFunctionObjArgs( + PyExc_StopIteration, result, NULL); + if (e != NULL) { + PyErr_SetObject(PyExc_StopIteration, e); + Py_DECREF(e); + } + } + Py_CLEAR(result); + } + + if (f->f_stacktop == NULL) { + /* generator can't be rerun, so release the frame */ + /* first clean reference cycle through stored exception traceback */ + PyObject *t, *v, *tb; + t = f->f_exc_type; + v = f->f_exc_value; + tb = f->f_exc_traceback; + f->f_exc_type = NULL; + f->f_exc_value = NULL; + f->f_exc_traceback = NULL; + Py_XDECREF(t); + Py_XDECREF(v); + Py_XDECREF(tb); + if (gen) { + f->f_gen = NULL; + Py_CLEAR(gen->gi_frame); + } + } + + return result; +} + +int +_PyFrame_CloseIterator(PyObject *yf) +{ + PyObject *retval = NULL; + _Py_IDENTIFIER(close); + + if (PyGen_CheckExact(yf)) { + PyFrameObject *f = ((PyGenObject *) yf)->gi_frame; + assert(f != NULL); + retval = _PyFrame_Finalize(f); + if (retval == NULL) + return -1; + } else { + PyObject *meth = _PyObject_GetAttrId(yf, &PyId_close); + if (meth == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + PyErr_WriteUnraisable(yf); + PyErr_Clear(); + } else { + retval = PyObject_CallFunction(meth, ""); + Py_DECREF(meth); + if (retval == NULL) + return -1; + } + } + Py_XDECREF(retval); + return 0; +} + +PyObject * +_PyFrame_Finalize(PyFrameObject *f) +{ + int err = 0; + PyObject *retval; + PyGenObject *gen = (PyGenObject *) f->f_gen; + PyObject *yf = _PyFrame_YieldingFrom(f); + + assert(gen == NULL || PyGen_CheckExact(gen)); + if (yf) { + if (gen) + gen->gi_running = 1; + err = _PyFrame_CloseIterator(yf); + if (gen) + gen->gi_running = 0; + Py_DECREF(yf); + } + if (err == 0) + PyErr_SetNone(PyExc_GeneratorExit); + retval = _PyFrame_GeneratorSend(f, Py_None, 1); + if (retval) { + Py_DECREF(retval); + PyErr_SetString(PyExc_RuntimeError, + "generator ignored GeneratorExit"); + return NULL; + } + if (PyErr_ExceptionMatches(PyExc_StopIteration) + || PyErr_ExceptionMatches(PyExc_GeneratorExit)) { + PyErr_Clear(); /* ignore these errors */ + Py_INCREF(Py_None); + return Py_None; + } + return NULL; +} + +/* + * Line number support. + */ + int PyFrame_GetLineNumber(PyFrameObject *f) { @@ -420,32 +609,43 @@ #define PyFrame_MAXFREELIST 200 static void +frame_clear(PyFrameObject *f); + +static void frame_dealloc(PyFrameObject *f) { - PyObject **p, **valuestack; PyCodeObject *co; + Py_REFCNT(f)++; + frame_clear(f); + Py_REFCNT(f)--; + if (Py_REFCNT(f) > 0) { + /* Frame resurrected! */ + Py_ssize_t refcnt = Py_REFCNT(f); + _Py_NewReference((PyObject *) f); + Py_REFCNT(f) = refcnt; + /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so + * we need to undo that. */ + _Py_DEC_REFTOTAL; + /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object + * chain, so no more to do there. + * If COUNT_ALLOCS, the original decref bumped tp_frees, and + * _Py_NewReference bumped tp_allocs: both of those need to be + * undone. + */ +#ifdef COUNT_ALLOCS + --(Py_TYPE(self)->tp_frees); + --(Py_TYPE(self)->tp_allocs); +#endif + } + PyObject_GC_UnTrack(f); Py_TRASHCAN_SAFE_BEGIN(f) - /* Kill all local variables */ - valuestack = f->f_valuestack; - for (p = f->f_localsplus; p < valuestack; p++) - Py_CLEAR(*p); - - /* Free stack */ - if (f->f_stacktop != NULL) { - for (p = valuestack; p < f->f_stacktop; p++) - Py_XDECREF(*p); - } Py_XDECREF(f->f_back); Py_DECREF(f->f_builtins); Py_DECREF(f->f_globals); Py_CLEAR(f->f_locals); - Py_CLEAR(f->f_trace); - Py_CLEAR(f->f_exc_type); - Py_CLEAR(f->f_exc_value); - Py_CLEAR(f->f_exc_traceback); co = f->f_code; if (co->co_zombieframe == NULL) @@ -497,12 +697,25 @@ { PyObject **fastlocals, **p, **oldtop; Py_ssize_t i, slots; + PyObject *retval; - /* Before anything else, make sure that this frame is clearly marked - * as being defunct! Else, e.g., a generator reachable from this - * frame may also point to this frame, believe itself to still be - * active, and try cleaning up this frame again. - */ + if (f->f_back == NULL) { + PyObject *t, *v, *tb; + PyErr_Fetch(&t, &v, &tb); + /* Note that this can finalize a suspended generator frame even + * if the generator object was disposed of (i.e. if f_gen is NULL). + */ + retval = _PyFrame_Finalize(f); + if (retval == NULL) { + if (PyErr_Occurred()) + PyErr_WriteUnraisable((PyObject *) f); + } + else + Py_DECREF(retval); + PyErr_Restore(t, v, tb); + } + + /* Make sure the frame is now clearly marked as being defunct */ oldtop = f->f_stacktop; f->f_stacktop = NULL; @@ -713,6 +926,7 @@ f->f_lasti = -1; f->f_lineno = code->co_firstlineno; f->f_iblock = 0; + f->f_gen = NULL; _PyObject_GC_TRACK(f); return f; diff --git a/Objects/genobject.c b/Objects/genobject.c --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -19,112 +19,50 @@ gen_dealloc(PyGenObject *gen) { PyObject *self = (PyObject *) gen; + PyFrameObject *f = gen->gi_frame; _PyObject_GC_UNTRACK(gen); if (gen->gi_weakreflist != NULL) PyObject_ClearWeakRefs(self); - _PyObject_GC_TRACK(self); - - if (gen->gi_frame != NULL && gen->gi_frame->f_stacktop != NULL) { - /* Generator is paused, so we need to close */ - Py_TYPE(gen)->tp_del(self); - if (self->ob_refcnt > 0) - return; /* resurrected. :( */ + gen->gi_frame = NULL; + if (f) { + /* Close the generator by finalizing the frame */ + PyObject *retval, *t, *v, *tb; + PyErr_Fetch(&t, &v, &tb); + f->f_gen = NULL; + retval = _PyFrame_Finalize(f); + if (retval) + Py_DECREF(retval); + else if (PyErr_Occurred()) + PyErr_WriteUnraisable((PyObject *) gen); + Py_DECREF(f); + PyErr_Restore(t, v, tb); } - - _PyObject_GC_UNTRACK(self); - Py_CLEAR(gen->gi_frame); Py_CLEAR(gen->gi_code); PyObject_GC_Del(gen); } - static PyObject * gen_send_ex(PyGenObject *gen, PyObject *arg, int exc) { - PyThreadState *tstate = PyThreadState_GET(); PyFrameObject *f = gen->gi_frame; - PyObject *result; + /* For compatibility, we check gi_running before f == NULL */ if (gen->gi_running) { PyErr_SetString(PyExc_ValueError, "generator already executing"); return NULL; } - if (f == NULL || f->f_stacktop == NULL) { - /* Only set exception if called from send() */ + if (f == NULL) { + /* Only set exception if send() called, not throw() or next() */ if (arg && !exc) PyErr_SetNone(PyExc_StopIteration); return NULL; } - if (f->f_lasti == -1) { - if (arg && arg != Py_None) { - PyErr_SetString(PyExc_TypeError, - "can't send non-None value to a " - "just-started generator"); - return NULL; - } - } else { - /* Push arg onto the frame's value stack */ - result = arg ? arg : Py_None; - Py_INCREF(result); - *(f->f_stacktop++) = result; - } - - /* Generators always return to their most recent caller, not - * necessarily their creator. */ - Py_XINCREF(tstate->frame); - assert(f->f_back == NULL); - f->f_back = tstate->frame; - - gen->gi_running = 1; - result = PyEval_EvalFrameEx(f, exc); - gen->gi_running = 0; - - /* Don't keep the reference to f_back any longer than necessary. It - * may keep a chain of frames alive or it could create a reference - * cycle. */ - assert(f->f_back == tstate->frame); - Py_CLEAR(f->f_back); - - /* If the generator just returned (as opposed to yielding), signal - * that the generator is exhausted. */ - if (result && f->f_stacktop == NULL) { - if (result == Py_None) { - /* Delay exception instantiation if we can */ - PyErr_SetNone(PyExc_StopIteration); - } else { - PyObject *e = PyObject_CallFunctionObjArgs( - PyExc_StopIteration, result, NULL); - if (e != NULL) { - PyErr_SetObject(PyExc_StopIteration, e); - Py_DECREF(e); - } - } - Py_CLEAR(result); - } - - if (!result || f->f_stacktop == NULL) { - /* generator can't be rerun, so release the frame */ - /* first clean reference cycle through stored exception traceback */ - PyObject *t, *v, *tb; - t = f->f_exc_type; - v = f->f_exc_value; - tb = f->f_exc_traceback; - f->f_exc_type = NULL; - f->f_exc_value = NULL; - f->f_exc_traceback = NULL; - Py_XDECREF(t); - Py_XDECREF(v); - Py_XDECREF(tb); - gen->gi_frame = NULL; - Py_DECREF(f); - } - - return result; + return _PyFrame_GeneratorSend(f, arg, exc); } PyDoc_STRVAR(send_doc, @@ -145,146 +83,33 @@ * close a subiterator being delegated to by yield-from. */ -static int -gen_close_iter(PyObject *yf) -{ - PyObject *retval = NULL; - _Py_IDENTIFIER(close); - - if (PyGen_CheckExact(yf)) { - retval = gen_close((PyGenObject *)yf, NULL); - if (retval == NULL) - return -1; - } else { - PyObject *meth = _PyObject_GetAttrId(yf, &PyId_close); - if (meth == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - PyErr_WriteUnraisable(yf); - PyErr_Clear(); - } else { - retval = PyObject_CallFunction(meth, ""); - Py_DECREF(meth); - if (retval == NULL) - return -1; - } - } - Py_XDECREF(retval); - return 0; -} - static PyObject * gen_yf(PyGenObject *gen) { - PyObject *yf = NULL; PyFrameObject *f = gen->gi_frame; - - if (f && f->f_stacktop) { - PyObject *bytecode = f->f_code->co_code; - unsigned char *code = (unsigned char *)PyBytes_AS_STRING(bytecode); - - if (code[f->f_lasti + 1] != YIELD_FROM) - return NULL; - yf = f->f_stacktop[-1]; - Py_INCREF(yf); - } - - return yf; + if (f) + return _PyFrame_YieldingFrom(f); + else + return NULL; } static PyObject * gen_close(PyGenObject *gen, PyObject *args) { - PyObject *retval; - PyObject *yf = gen_yf(gen); - int err = 0; + PyFrameObject *f = gen->gi_frame; - if (yf) { - gen->gi_running = 1; - err = gen_close_iter(yf); - gen->gi_running = 0; - Py_DECREF(yf); - } - if (err == 0) - PyErr_SetNone(PyExc_GeneratorExit); - retval = gen_send_ex(gen, Py_None, 1); - if (retval) { - Py_DECREF(retval); - PyErr_SetString(PyExc_RuntimeError, - "generator ignored GeneratorExit"); + /* For compatibility, we check gi_running before f == NULL */ + if (gen->gi_running) { + PyErr_SetString(PyExc_ValueError, + "generator already executing"); return NULL; } - if (PyErr_ExceptionMatches(PyExc_StopIteration) - || PyErr_ExceptionMatches(PyExc_GeneratorExit)) { - PyErr_Clear(); /* ignore these errors */ - Py_INCREF(Py_None); - return Py_None; - } - return NULL; + if (f == NULL) + Py_RETURN_NONE; + + return _PyFrame_Finalize(f); } -static void -gen_del(PyObject *self) -{ - PyObject *res; - PyObject *error_type, *error_value, *error_traceback; - PyGenObject *gen = (PyGenObject *)self; - - if (gen->gi_frame == NULL || gen->gi_frame->f_stacktop == NULL) - /* Generator isn't paused, so no need to close */ - return; - - /* Temporarily resurrect the object. */ - assert(self->ob_refcnt == 0); - self->ob_refcnt = 1; - - /* Save the current exception, if any. */ - PyErr_Fetch(&error_type, &error_value, &error_traceback); - - res = gen_close(gen, NULL); - - if (res == NULL) - PyErr_WriteUnraisable(self); - else - Py_DECREF(res); - - /* Restore the saved exception. */ - PyErr_Restore(error_type, error_value, error_traceback); - - /* Undo the temporary resurrection; can't use DECREF here, it would - * cause a recursive call. - */ - assert(self->ob_refcnt > 0); - if (--self->ob_refcnt == 0) - return; /* this is the normal path out */ - - /* close() resurrected it! Make it look like the original Py_DECREF - * never happened. - */ - { - Py_ssize_t refcnt = self->ob_refcnt; - _Py_NewReference(self); - self->ob_refcnt = refcnt; - } - assert(PyType_IS_GC(Py_TYPE(self)) && - _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED); - - /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so - * we need to undo that. */ - _Py_DEC_REFTOTAL; - /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object - * chain, so no more to do there. - * If COUNT_ALLOCS, the original decref bumped tp_frees, and - * _Py_NewReference bumped tp_allocs: both of those need to be - * undone. - */ -#ifdef COUNT_ALLOCS - --(Py_TYPE(self)->tp_frees); - --(Py_TYPE(self)->tp_allocs); -#endif -} - - - PyDoc_STRVAR(throw_doc, "throw(typ[,val[,tb]]) -> raise exception in generator,\n\ return next yielded value or raise StopIteration."); @@ -306,7 +131,7 @@ int err; if (PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit)) { gen->gi_running = 1; - err = gen_close_iter(yf); + err = _PyFrame_CloseIterator(yf); gen->gi_running = 0; Py_DECREF(yf); if (err < 0) @@ -544,7 +369,6 @@ 0, /* tp_cache */ 0, /* tp_subclasses */ 0, /* tp_weaklist */ - gen_del, /* tp_del */ }; PyObject * @@ -556,6 +380,7 @@ return NULL; } gen->gi_frame = f; + f->f_gen = (PyObject *) gen; Py_INCREF(f->f_code); gen->gi_code = (PyObject *)(f->f_code); gen->gi_running = 0; @@ -567,17 +392,5 @@ int PyGen_NeedsFinalizing(PyGenObject *gen) { - int i; - PyFrameObject *f = gen->gi_frame; - - if (f == NULL || f->f_stacktop == NULL) - return 0; /* no frame or empty blockstack == no finalization */ - - /* Any block type besides a loop requires cleanup. */ - for (i = 0; i < f->f_iblock; i++) - if (f->f_blockstack[i].b_type != SETUP_LOOP) - return 1; - - /* No blocks except loops, it's safe to skip finalization. */ return 0; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 8 20:53:25 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 8 May 2013 20:53:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3NjU2?= =?utf-8?q?=3A_Skip_test=5Fextract=5Funicode=5Ffilenames_if_the_FS_encodin?= =?utf-8?q?g?= Message-ID: <3b5RfF5yZnzRFf@mail.python.org> http://hg.python.org/cpython/rev/8952fa2c475f changeset: 83689:8952fa2c475f branch: 2.7 parent: 83684:5885c02120f0 user: Serhiy Storchaka date: Wed May 08 21:52:31 2013 +0300 summary: Issue #17656: Skip test_extract_unicode_filenames if the FS encoding doesn't support non-ASCII filenames. files: Lib/test/test_zipfile.py | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -18,7 +18,14 @@ from random import randint, random from unittest import skipUnless -from test.test_support import TESTFN, TESTFN_UNICODE, run_unittest, findfile, unlink +from test.test_support import TESTFN, TESTFN_UNICODE, TESTFN_ENCODING, \ + run_unittest, findfile, unlink +try: + TESTFN_UNICODE.encode(TESTFN_ENCODING) +except (UnicodeError, TypeError): + # Either the file system encoding is None, or the file name + # cannot be encoded in the file system encoding. + TESTFN_UNICODE = None TESTFN2 = TESTFN + "2" TESTFNDIR = TESTFN + "d" @@ -424,6 +431,7 @@ with open(filename, 'rb') as f: self.assertEqual(f.read(), content) + @skipUnless(TESTFN_UNICODE, "No Unicode filesystem semantics on this platform.") def test_extract_unicode_filenames(self): fnames = [u'foo.txt', os.path.basename(TESTFN_UNICODE)] content = 'Test for unicode filename' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 8 21:10:31 2013 From: python-checkins at python.org (charles-francois.natali) Date: Wed, 8 May 2013 21:10:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2317912=3A_Use_a_do?= =?utf-8?q?ubly_linked-list_for_thread_states=2E?= Message-ID: <3b5S1z4qdWzRBT@mail.python.org> http://hg.python.org/cpython/rev/375d4fed4cf2 changeset: 83690:375d4fed4cf2 parent: 83688:c89febab4648 user: Charles-Francois Natali date: Wed May 08 21:09:52 2013 +0200 summary: Issue #17912: Use a doubly linked-list for thread states. files: Include/pystate.h | 1 + Python/pystate.c | 58 ++++++++++------------------------ 2 files changed, 18 insertions(+), 41 deletions(-) diff --git a/Include/pystate.h b/Include/pystate.h --- a/Include/pystate.h +++ b/Include/pystate.h @@ -69,6 +69,7 @@ typedef struct _ts { /* See Python/ceval.c for comments explaining most fields */ + struct _ts *prev; struct _ts *next; PyInterpreterState *interp; diff --git a/Python/pystate.c b/Python/pystate.c --- a/Python/pystate.c +++ b/Python/pystate.c @@ -213,7 +213,10 @@ _PyThreadState_Init(tstate); HEAD_LOCK(); + tstate->prev = NULL; tstate->next = interp->tstate_head; + if (tstate->next) + tstate->next->prev = tstate; interp->tstate_head = tstate; HEAD_UNLOCK(); } @@ -349,35 +352,18 @@ tstate_delete_common(PyThreadState *tstate) { PyInterpreterState *interp; - PyThreadState **p; - PyThreadState *prev_p = NULL; if (tstate == NULL) Py_FatalError("PyThreadState_Delete: NULL tstate"); interp = tstate->interp; if (interp == NULL) Py_FatalError("PyThreadState_Delete: NULL interp"); HEAD_LOCK(); - for (p = &interp->tstate_head; ; p = &(*p)->next) { - if (*p == NULL) - Py_FatalError( - "PyThreadState_Delete: invalid tstate"); - if (*p == tstate) - break; - /* Sanity check. These states should never happen but if - * they do we must abort. Otherwise we'll end up spinning in - * in a tight loop with the lock held. A similar check is done - * in thread.c find_key(). */ - if (*p == prev_p) - Py_FatalError( - "PyThreadState_Delete: small circular list(!)" - " and tstate not found."); - prev_p = *p; - if ((*p)->next == interp->tstate_head) - Py_FatalError( - "PyThreadState_Delete: circular list(!) and" - " tstate not found."); - } - *p = tstate->next; + if (tstate->prev) + tstate->prev->next = tstate->next; + else + interp->tstate_head = tstate->next; + if (tstate->next) + tstate->next->prev = tstate->prev; HEAD_UNLOCK(); free(tstate); } @@ -429,26 +415,16 @@ HEAD_LOCK(); /* Remove all thread states, except tstate, from the linked list of thread states. This will allow calling PyThreadState_Clear() - without holding the lock. - XXX This would be simpler with a doubly-linked list. */ + without holding the lock. */ garbage = interp->tstate_head; + if (garbage == tstate) + garbage = tstate->next; + if (tstate->prev) + tstate->prev->next = tstate->next; + if (tstate->next) + tstate->next->prev = tstate->prev; + tstate->prev = tstate->next = NULL; interp->tstate_head = tstate; - if (garbage == tstate) { - garbage = garbage->next; - tstate->next = NULL; - } - else { - for (p = garbage; p; p = p->next) { - if (p->next == tstate) { - p->next = tstate->next; - tstate->next = NULL; - break; - } - } - } - if (tstate->next != NULL) - Py_FatalError("_PyThreadState_DeleteExcept: tstate not found " - "in interpreter thread states"); HEAD_UNLOCK(); /* Clear and deallocate all stale thread states. Even if this executes Python code, we should be safe since it executes -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 9 05:37:44 2013 From: python-checkins at python.org (eli.bendersky) Date: Thu, 9 May 2013 05:37:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?cGVwczogRGVzY3JpYmUgX19tZW1iZXJzX18g?= =?utf-8?q?instead_of_=5F=5Faliases=5F=5F=2E_+a_few_additional_touch-ups?= Message-ID: <3b5gHD6SK5z7LlL@mail.python.org> http://hg.python.org/peps/rev/54ec32489684 changeset: 4877:54ec32489684 user: Eli Bendersky date: Wed May 08 20:32:27 2013 -0700 summary: Describe __members__ instead of __aliases__. +a few additional touch-ups files: pep-0435.txt | 31 ++++++++++++++++++++++--------- 1 files changed, 22 insertions(+), 9 deletions(-) diff --git a/pep-0435.txt b/pep-0435.txt --- a/pep-0435.txt +++ b/pep-0435.txt @@ -59,16 +59,17 @@ of not allowing to subclass enums [6]_, unless they define no enumeration members [7]_. + Motivation ========== *[Based partly on the Motivation stated in PEP 354]* The properties of an enumeration are useful for defining an immutable, related -set of constant values that have a defined sequence but no inherent semantic -meaning. Classic examples are days of the week (Sunday through Saturday) and -school assessment grades ('A' through 'D', and 'F'). Other examples include -error status values and states within a defined process. +set of constant values that may or may not have a semantic meaning. Classic +examples are days of the week (Sunday through Saturday) and school assessment +grades ('A' through 'D', and 'F'). Other examples include error status values +and states within a defined process. It is possible to simply define a sequence of values of some other basic type, such as ``int`` or ``str``, to represent discrete arbitrary values. However, @@ -193,7 +194,8 @@ However, two enum members are allowed to have the same value. Given two members A and B with the same value (and A defined first), B is an alias to A. By-value -lookup of the value of A and B will return A. +lookup of the value of A and B will return A. By-name lookup of B will also +return A:: >>> class Shape(Enum): ... square = 2 @@ -213,13 +215,24 @@ >>> list(Shape) [, , ] -The special attribute ``__aliases__`` contains a list of all enum -member aliases, by name:: +The special attribute ``__members__`` is an ordered dictionary mapping names +to members. It includes all names defined in the enumeration, including the +aliases:: - >>> Shape.__aliases__ + >>> for name, member in Shape.__members__.items(): + ... name, member + ... + ('square', ) + ('diamond', ) + ('circle', ) + ('alias_for_square', ) + +The ``__members__`` attribute can be used for detailed programmatic access to +the enumeration members. For example, finding all the aliases:: + + >>> [name for name, member in Shape.__members__.items() if member.name != name] ['alias_for_square'] - Comparisons ----------- -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu May 9 05:37:46 2013 From: python-checkins at python.org (eli.bendersky) Date: Thu, 9 May 2013 05:37:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_update_todo_items?= Message-ID: <3b5gHG2YjSzRV8@mail.python.org> http://hg.python.org/peps/rev/47865eee9202 changeset: 4878:47865eee9202 user: Eli Bendersky date: Wed May 08 20:36:39 2013 -0700 summary: update todo items files: pep-0435.txt | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/pep-0435.txt b/pep-0435.txt --- a/pep-0435.txt +++ b/pep-0435.txt @@ -603,7 +603,8 @@ ==== * Mark PEP 354 "superseded by" this one, if accepted -* The last revision where flufl.enum was the approach is cb3c18a080a3 +* In docs: describe the detailed extension API (i.e. __new__). Also describe + the problem with pickling of functional API in more detail. .. Local Variables: -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu May 9 05:43:04 2013 From: python-checkins at python.org (terry.reedy) Date: Thu, 9 May 2013 05:43:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgMTY1ODQ6?= =?utf-8?q?_in_filecomp=2E=5Fcmp=2C_catch_IOError_as_well_as_os=2Eerror=2E?= Message-ID: <3b5gPN4djDz7LlL@mail.python.org> http://hg.python.org/cpython/rev/1823cf6e1084 changeset: 83691:1823cf6e1084 branch: 2.7 parent: 83689:8952fa2c475f user: Terry Jan Reedy date: Wed May 08 23:42:41 2013 -0400 summary: Issue 16584: in filecomp._cmp, catch IOError as well as os.error. Patch by Till Maas. files: Lib/filecmp.py | 2 +- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 3 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Lib/filecmp.py b/Lib/filecmp.py --- a/Lib/filecmp.py +++ b/Lib/filecmp.py @@ -268,7 +268,7 @@ def _cmp(a, b, sh, abs=abs, cmp=cmp): try: return not abs(cmp(a, b, sh)) - except os.error: + except (os.error, IOError): return 2 diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -626,6 +626,7 @@ Jim Lynch Mikael Lyngvig Martin von L?wis +Till Maas Jeff MacDonald John Machin Andrew I MacIntyre diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -26,6 +26,9 @@ Library ------- +- Issue 16584: in filecomp._cmp, catch IOError as well as os.error. + Patch by Till Maas. + - Issue #17926: Fix dbm.__contains__ on 64-bit big-endian machines. - Issue #17918: When using SSLSocket.accept(), if the SSL handshake failed -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu May 9 06:07:20 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 09 May 2013 06:07:20 +0200 Subject: [Python-checkins] Daily reference leaks (375d4fed4cf2): sum=4 Message-ID: results for 375d4fed4cf2 on branch "default" -------------------------------------------- test_unittest leaked [-1, 1, 2] memory blocks, sum=2 test_concurrent_futures leaked [-2, 3, 1] memory blocks, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog38VugR', '-x'] From python-checkins at python.org Thu May 9 13:39:32 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 9 May 2013 13:39:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE2NjAx?= =?utf-8?q?=3A_Restarting_iteration_over_tarfile_no_more_continues_from_wh?= =?utf-8?q?ere?= Message-ID: <3b5sz81qqYzLq6@mail.python.org> http://hg.python.org/cpython/rev/9b86fb6f5bc9 changeset: 83692:9b86fb6f5bc9 branch: 2.7 user: Serhiy Storchaka date: Thu May 09 14:22:05 2013 +0300 summary: Issue #16601: Restarting iteration over tarfile no more continues from where it left off. Patch by Michael Birtwell. files: Lib/tarfile.py | 12 +++++++----- Lib/test/test_tarfile.py | 8 ++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -2462,16 +2462,18 @@ # Fix for SF #1100429: Under rare circumstances it can # happen that getmembers() is called during iteration, # which will cause TarIter to stop prematurely. - if not self.tarfile._loaded: + + if self.index == 0 and self.tarfile.firstmember is not None: + tarinfo = self.tarfile.next() + elif self.index < len(self.tarfile.members): + tarinfo = self.tarfile.members[self.index] + elif not self.tarfile._loaded: tarinfo = self.tarfile.next() if not tarinfo: self.tarfile._loaded = True raise StopIteration else: - try: - tarinfo = self.tarfile.members[self.index] - except IndexError: - raise StopIteration + raise StopIteration self.index += 1 return tarinfo diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -345,6 +345,14 @@ finally: os.remove(empty) + def test_parallel_iteration(self): + # Issue #16601: Restarting iteration over tarfile continued + # from where it left off. + with tarfile.open(self.tarname) as tar: + for m1, m2 in zip(tar, tar): + self.assertEqual(m1.offset, m2.offset) + self.assertEqual(m1.name, m2.name) + class StreamReadTest(CommonReadTest): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -96,6 +96,7 @@ David Binger Dominic Binks Philippe Biondi +Michael Birtwell Stuart Bishop Roy Bixler Jonathan Black diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -26,6 +26,9 @@ Library ------- +- Issue #16601: Restarting iteration over tarfile no more continues from where + it left off. Patch by Michael Birtwell. + - Issue 16584: in filecomp._cmp, catch IOError as well as os.error. Patch by Till Maas. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 9 13:39:33 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 9 May 2013 13:39:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE2NjAx?= =?utf-8?q?=3A_Restarting_iteration_over_tarfile_no_more_continues_from_wh?= =?utf-8?q?ere?= Message-ID: <3b5sz94Qs5zQx7@mail.python.org> http://hg.python.org/cpython/rev/9ed127d8ad61 changeset: 83693:9ed127d8ad61 branch: 3.3 parent: 83685:f7b552020d44 user: Serhiy Storchaka date: Thu May 09 14:22:26 2013 +0300 summary: Issue #16601: Restarting iteration over tarfile no more continues from where it left off. Patch by Michael Birtwell. files: Lib/tarfile.py | 12 +++++++----- Lib/test/test_tarfile.py | 8 ++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -2398,16 +2398,18 @@ # Fix for SF #1100429: Under rare circumstances it can # happen that getmembers() is called during iteration, # which will cause TarIter to stop prematurely. - if not self.tarfile._loaded: + + if self.index == 0 and self.tarfile.firstmember is not None: + tarinfo = self.tarfile.next() + elif self.index < len(self.tarfile.members): + tarinfo = self.tarfile.members[self.index] + elif not self.tarfile._loaded: tarinfo = self.tarfile.next() if not tarinfo: self.tarfile._loaded = True raise StopIteration else: - try: - tarinfo = self.tarfile.members[self.index] - except IndexError: - raise StopIteration + raise StopIteration self.index += 1 return tarinfo diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -415,6 +415,14 @@ finally: support.unlink(empty) + def test_parallel_iteration(self): + # Issue #16601: Restarting iteration over tarfile continued + # from where it left off. + with tarfile.open(self.tarname) as tar: + for m1, m2 in zip(tar, tar): + self.assertEqual(m1.offset, m2.offset) + self.assertEqual(m1.get_info(), m2.get_info()) + class StreamReadTest(CommonReadTest): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -117,6 +117,7 @@ David Binger Dominic Binks Philippe Biondi +Michael Birtwell Stuart Bishop Roy Bixler Jonathan Black diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -47,6 +47,9 @@ Library ------- +- Issue #16601: Restarting iteration over tarfile no more continues from where + it left off. Patch by Michael Birtwell. + - Issue #17289: The readline module now plays nicer with external modules or applications changing the rl_completer_word_break_characters global variable. Initial patch by Bradley Froehle. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 9 13:39:35 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Thu, 9 May 2013 13:39:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2316601=3A_Restarting_iteration_over_tarfile_no_m?= =?utf-8?q?ore_continues_from_where?= Message-ID: <3b5szC05vdz7LjY@mail.python.org> http://hg.python.org/cpython/rev/1c6a1427353b changeset: 83694:1c6a1427353b parent: 83690:375d4fed4cf2 parent: 83693:9ed127d8ad61 user: Serhiy Storchaka date: Thu May 09 14:36:58 2013 +0300 summary: Issue #16601: Restarting iteration over tarfile no more continues from where it left off. Patch by Michael Birtwell. files: Lib/tarfile.py | 12 +++++++----- Lib/test/test_tarfile.py | 8 ++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -2397,16 +2397,18 @@ # Fix for SF #1100429: Under rare circumstances it can # happen that getmembers() is called during iteration, # which will cause TarIter to stop prematurely. - if not self.tarfile._loaded: + + if self.index == 0 and self.tarfile.firstmember is not None: + tarinfo = self.tarfile.next() + elif self.index < len(self.tarfile.members): + tarinfo = self.tarfile.members[self.index] + elif not self.tarfile._loaded: tarinfo = self.tarfile.next() if not tarinfo: self.tarfile._loaded = True raise StopIteration else: - try: - tarinfo = self.tarfile.members[self.index] - except IndexError: - raise StopIteration + raise StopIteration self.index += 1 return tarinfo diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -415,6 +415,14 @@ finally: support.unlink(empty) + def test_parallel_iteration(self): + # Issue #16601: Restarting iteration over tarfile continued + # from where it left off. + with tarfile.open(self.tarname) as tar: + for m1, m2 in zip(tar, tar): + self.assertEqual(m1.offset, m2.offset) + self.assertEqual(m1.get_info(), m2.get_info()) + class StreamReadTest(CommonReadTest): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -118,6 +118,7 @@ David Binger Dominic Binks Philippe Biondi +Michael Birtwell Stuart Bishop Roy Bixler Daniel Black diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -86,6 +86,9 @@ Library ------- +- Issue #16601: Restarting iteration over tarfile no more continues from where + it left off. Patch by Michael Birtwell. + - Issue #17289: The readline module now plays nicer with external modules or applications changing the rl_completer_word_break_characters global variable. Initial patch by Bradley Froehle. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 9 14:25:25 2013 From: python-checkins at python.org (ezio.melotti) Date: Thu, 9 May 2013 14:25:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE3ODA5OiBmaXgg?= =?utf-8?q?a_test_failure_in_test=5Fexpanduser_when_=24HOME_has_a_trailing?= =?utf-8?b?IC8u?= Message-ID: <3b5v050S8yzR8T@mail.python.org> http://hg.python.org/cpython/rev/dee0a2dea11e changeset: 83695:dee0a2dea11e branch: 3.3 parent: 83693:9ed127d8ad61 user: Ezio Melotti date: Thu May 09 15:19:45 2013 +0300 summary: #17809: fix a test failure in test_expanduser when $HOME has a trailing /. Patch by Kubilay Kocak. files: Lib/test/test_posixpath.py | 3 ++- Misc/ACKS | 1 + 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py --- a/Lib/test/test_posixpath.py +++ b/Lib/test/test_posixpath.py @@ -318,7 +318,8 @@ # expanduser should fall back to using the password database del env['HOME'] home = pwd.getpwuid(os.getuid()).pw_dir - self.assertEqual(posixpath.expanduser("~"), home) + # $HOME can end with a trailing /, so strip it (see #17809) + self.assertEqual(posixpath.expanduser("~"), home.rstrip("/")) def test_normpath(self): self.assertEqual(posixpath.normpath(""), ".") diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -648,6 +648,7 @@ Lenny Kneler Pat Knight Jeff Knupp +Kubilay Kocak Greg Kochanski Damon Kohler Marko Kohtala -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 9 14:25:26 2013 From: python-checkins at python.org (ezio.melotti) Date: Thu, 9 May 2013 14:25:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzE3ODA5OiBtZXJnZSB3aXRoIDMuMy4=?= Message-ID: <3b5v062g6dz7Ljh@mail.python.org> http://hg.python.org/cpython/rev/489f075430de changeset: 83696:489f075430de parent: 83694:1c6a1427353b parent: 83695:dee0a2dea11e user: Ezio Melotti date: Thu May 09 15:24:30 2013 +0300 summary: #17809: merge with 3.3. files: Lib/test/test_posixpath.py | 3 ++- Misc/ACKS | 1 + 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py --- a/Lib/test/test_posixpath.py +++ b/Lib/test/test_posixpath.py @@ -261,7 +261,8 @@ # expanduser should fall back to using the password database del env['HOME'] home = pwd.getpwuid(os.getuid()).pw_dir - self.assertEqual(posixpath.expanduser("~"), home) + # $HOME can end with a trailing /, so strip it (see #17809) + self.assertEqual(posixpath.expanduser("~"), home.rstrip("/")) def test_normpath(self): self.assertEqual(posixpath.normpath(""), ".") diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -660,6 +660,7 @@ Lenny Kneler Pat Knight Jeff Knupp +Kubilay Kocak Greg Kochanski Damon Kohler Marko Kohtala -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 9 14:34:21 2013 From: python-checkins at python.org (ezio.melotti) Date: Thu, 9 May 2013 14:34:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE3OTM4OiByZW1v?= =?utf-8?q?ve_duplicate_paragraphs=2E?= Message-ID: <3b5vBP05FkzR0J@mail.python.org> http://hg.python.org/cpython/rev/844c6442a39e changeset: 83697:844c6442a39e branch: 3.3 parent: 83695:dee0a2dea11e user: Ezio Melotti date: Thu May 09 15:33:53 2013 +0300 summary: #17938: remove duplicate paragraphs. files: Doc/reference/simple_stmts.rst | 16 ---------------- 1 files changed, 0 insertions(+), 16 deletions(-) diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -737,22 +737,6 @@ to avoid accidentally exporting items that are not part of the API (such as library modules which were imported and used within the module). -The :keyword:`from` form with ``*`` may only occur in a module scope. -Attempting to use it in class or function definitions will raise a -:exc:`SyntaxError`. - -.. index:: single: __all__ (optional module attribute) - -The *public names* defined by a module are determined by checking the module's -namespace for a variable named ``__all__``; if defined, it must be a sequence -of strings which are names defined or imported by that module. The names -given in ``__all__`` are all considered public and are required to exist. If -``__all__`` is not defined, the set of public names includes all names found -in the module's namespace which do not begin with an underscore character -(``'_'``). ``__all__`` should contain the entire public API. It is intended -to avoid accidentally exporting items that are not part of the API (such as -library modules which were imported and used within the module). - The :keyword:`from` form with ``*`` may only occur in a module scope. The wild card form of import --- ``import *`` --- is only allowed at the module level. Attempting to use it in class or function definitions will raise a -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 9 14:34:22 2013 From: python-checkins at python.org (ezio.melotti) Date: Thu, 9 May 2013 14:34:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzE3OTM4OiBtZXJnZSB3aXRoIDMuMy4=?= Message-ID: <3b5vBQ2L3JzR0J@mail.python.org> http://hg.python.org/cpython/rev/ebc296bf23d1 changeset: 83698:ebc296bf23d1 parent: 83696:489f075430de parent: 83697:844c6442a39e user: Ezio Melotti date: Thu May 09 15:34:09 2013 +0300 summary: #17938: merge with 3.3. files: Doc/reference/simple_stmts.rst | 16 ---------------- 1 files changed, 0 insertions(+), 16 deletions(-) diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -737,22 +737,6 @@ to avoid accidentally exporting items that are not part of the API (such as library modules which were imported and used within the module). -The :keyword:`from` form with ``*`` may only occur in a module scope. -Attempting to use it in class or function definitions will raise a -:exc:`SyntaxError`. - -.. index:: single: __all__ (optional module attribute) - -The *public names* defined by a module are determined by checking the module's -namespace for a variable named ``__all__``; if defined, it must be a sequence -of strings which are names defined or imported by that module. The names -given in ``__all__`` are all considered public and are required to exist. If -``__all__`` is not defined, the set of public names includes all names found -in the module's namespace which do not begin with an underscore character -(``'_'``). ``__all__`` should contain the entire public API. It is intended -to avoid accidentally exporting items that are not part of the API (such as -library modules which were imported and used within the module). - The :keyword:`from` form with ``*`` may only occur in a module scope. The wild card form of import --- ``import *`` --- is only allowed at the module level. Attempting to use it in class or function definitions will raise a -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 10 00:39:54 2013 From: python-checkins at python.org (barry.warsaw) Date: Fri, 10 May 2013 00:39:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_-_The_functional_API_gets_a_k?= =?utf-8?q?eyword-only_=60module=60_argument=2E?= Message-ID: <3b68d60qq6z7LkR@mail.python.org> http://hg.python.org/peps/rev/575129af919e changeset: 4879:575129af919e user: Barry Warsaw date: Thu May 09 18:39:44 2013 -0400 summary: - The functional API gets a keyword-only `module` argument. - Spell it 'mix-in' - Clarify "behavior only" files: pep-0435.txt | 17 +++++++++-------- 1 files changed, 9 insertions(+), 8 deletions(-) diff --git a/pep-0435.txt b/pep-0435.txt --- a/pep-0435.txt +++ b/pep-0435.txt @@ -410,11 +410,12 @@ Some rules: -1. When subclassing Enum, mixing types must appear before Enum itself in the - sequence of bases. +1. When subclassing Enum, mix-in types must appear before Enum itself in the + sequence of bases, as in the ``IntEnum`` example above. 2. While Enum can have members of any type, once you mix in an additional type, all the members must have values of that type, e.g. ``int`` above. - This restriction does not apply to behavior-only mixins. + This restriction does not apply to mix-ins which only add methods + and don't specify another data type such as ``int`` or ``str``. Functional API @@ -432,12 +433,12 @@ >>> list(Animal) [, , , ] -The semantics of this API resemble ``namedtuple``. The first argument of -the call to ``Enum`` is the name of the enumeration. This argument -can be the short name of the enum or a dotted-name including the -module path to better support pickling. E.g.:: +The semantics of this API resemble ``namedtuple``. The first argument +of the call to ``Enum`` is the name of the enumeration. To support +pickling of these enums, the module name can be specified using the +``module`` keyword-only argument. E.g.:: - >>> Animals = Enum('animals.Animals', 'ant bee cat dog') + >>> Animals = Enum('Animals', 'ant bee cat dog', module=__name__) The second argument is the *source* of enumeration member names. It can be a whitespace-separated string of names, a sequence of names, a sequence of -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri May 10 01:59:09 2013 From: python-checkins at python.org (barry.warsaw) Date: Fri, 10 May 2013 01:59:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_435_is_accepted_by_Guido?= =?utf-8?q?=2E?= Message-ID: <3b6BNY2JHFz7LlW@mail.python.org> http://hg.python.org/peps/rev/856453fa2637 changeset: 4880:856453fa2637 user: Barry Warsaw date: Thu May 09 19:59:04 2013 -0400 summary: PEP 435 is accepted by Guido. files: pep-0435.txt | 9 ++------- 1 files changed, 2 insertions(+), 7 deletions(-) diff --git a/pep-0435.txt b/pep-0435.txt --- a/pep-0435.txt +++ b/pep-0435.txt @@ -5,12 +5,13 @@ Author: Barry Warsaw , Eli Bendersky , Ethan Furman -Status: Draft +Status: Accepted Type: Standards Track Content-Type: text/x-rst Created: 2013-02-23 Python-Version: 3.4 Post-History: 2013-02-23, 2013-05-02 +Resolution: http://mail.python.org/pipermail/python-dev/2013-May/126112.html Abstract @@ -23,12 +24,6 @@ enumeration itself can be iterated over. -Decision -======== - -TODO: update decision here once pronouncement is made. [1]_ - - Status of discussions ===================== -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri May 10 02:14:50 2013 From: python-checkins at python.org (andrew.kuchling) Date: Fri, 10 May 2013 02:14:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE3NzAwOiB1cGRh?= =?utf-8?q?te_the_curses_HOWTO_for_3=2Ex?= Message-ID: <3b6Bkf2Lnhz7LjP@mail.python.org> http://hg.python.org/cpython/rev/1fa70b797973 changeset: 83699:1fa70b797973 branch: 3.3 parent: 83697:844c6442a39e user: Andrew Kuchling date: Thu May 09 20:05:20 2013 -0400 summary: #17700: update the curses HOWTO for 3.x files: Doc/howto/curses.rst | 454 +++++++++++++++++++----------- 1 files changed, 283 insertions(+), 171 deletions(-) diff --git a/Doc/howto/curses.rst b/Doc/howto/curses.rst --- a/Doc/howto/curses.rst +++ b/Doc/howto/curses.rst @@ -5,39 +5,43 @@ ********************************** :Author: A.M. Kuchling, Eric S. Raymond -:Release: 2.03 +:Release: 2.04 .. topic:: Abstract - This document describes how to write text-mode programs with Python 2.x, using - the :mod:`curses` extension module to control the display. + This document describes how to use the :mod:`curses` extension + module to control text-mode displays. What is curses? =============== The curses library supplies a terminal-independent screen-painting and -keyboard-handling facility for text-based terminals; such terminals include -VT100s, the Linux console, and the simulated terminal provided by X11 programs -such as xterm and rxvt. Display terminals support various control codes to -perform common operations such as moving the cursor, scrolling the screen, and -erasing areas. Different terminals use widely differing codes, and often have -their own minor quirks. +keyboard-handling facility for text-based terminals; such terminals +include VT100s, the Linux console, and the simulated terminal provided +by various programs. Display terminals support various control codes +to perform common operations such as moving the cursor, scrolling the +screen, and erasing areas. Different terminals use widely differing +codes, and often have their own minor quirks. -In a world of X displays, one might ask "why bother"? It's true that -character-cell display terminals are an obsolete technology, but there are -niches in which being able to do fancy things with them are still valuable. One -is on small-footprint or embedded Unixes that don't carry an X server. Another -is for tools like OS installers and kernel configurators that may have to run -before X is available. +In a world of graphical displays, one might ask "why bother"? It's +true that character-cell display terminals are an obsolete technology, +but there are niches in which being able to do fancy things with them +are still valuable. One niche is on small-footprint or embedded +Unixes that don't run an X server. Another is tools such as OS +installers and kernel configurators that may have to run before any +graphical support is available. -The curses library hides all the details of different terminals, and provides -the programmer with an abstraction of a display, containing multiple -non-overlapping windows. The contents of a window can be changed in various -ways-- adding text, erasing it, changing its appearance--and the curses library -will automagically figure out what control codes need to be sent to the terminal -to produce the right output. +The curses library provides fairly basic functionality, providing the +programmer with an abstraction of a display containing multiple +non-overlapping windows of text. The contents of a window can be +changed in various ways---adding text, erasing it, changing its +appearance---and the curses library will figure out what control codes +need to be sent to the terminal to produce the right output. curses +doesn't provide many user-interface concepts such as buttons, checkboxes, +or dialogs; if you need such features, consider a user interface library such as +`Urwid `_. The curses library was originally written for BSD Unix; the later System V versions of Unix from AT&T added many enhancements and new functions. BSD curses @@ -49,10 +53,13 @@ versions of curses carried by some proprietary Unixes may not support everything, though. -No one has made a Windows port of the curses module. On a Windows platform, try -the Console module written by Fredrik Lundh. The Console module provides -cursor-addressable text output, plus full support for mouse and keyboard input, -and is available from http://effbot.org/zone/console-index.htm. +The Windows version of Python doesn't include the :mod:`curses` +module. A ported version called `UniCurses +`_ is available. You could +also try `the Console module `_ +written by Fredrik Lundh, which doesn't +use the same API as curses but provides cursor-addressable text output +and full support for mouse and keyboard input. The Python curses module @@ -61,11 +68,12 @@ Thy Python module is a fairly simple wrapper over the C functions provided by curses; if you're already familiar with curses programming in C, it's really easy to transfer that knowledge to Python. The biggest difference is that the -Python interface makes things simpler, by merging different C functions such as -:func:`addstr`, :func:`mvaddstr`, :func:`mvwaddstr`, into a single -:meth:`addstr` method. You'll see this covered in more detail later. +Python interface makes things simpler by merging different C functions such as +:c:func:`addstr`, :c:func:`mvaddstr`, and :c:func:`mvwaddstr` into a single +:meth:`~curses.window.addstr` method. You'll see this covered in more +detail later. -This HOWTO is simply an introduction to writing text-mode programs with curses +This HOWTO is an introduction to writing text-mode programs with curses and Python. It doesn't attempt to be a complete guide to the curses API; for that, see the Python library guide's section on ncurses, and the C manual pages for ncurses. It will, however, give you the basic ideas. @@ -74,25 +82,27 @@ Starting and ending a curses application ======================================== -Before doing anything, curses must be initialized. This is done by calling the -:func:`initscr` function, which will determine the terminal type, send any -required setup codes to the terminal, and create various internal data -structures. If successful, :func:`initscr` returns a window object representing -the entire screen; this is usually called ``stdscr``, after the name of the +Before doing anything, curses must be initialized. This is done by +calling the :func:`~curses.initscr` function, which will determine the +terminal type, send any required setup codes to the terminal, and +create various internal data structures. If successful, +:func:`initscr` returns a window object representing the entire +screen; this is usually called ``stdscr`` after the name of the corresponding C variable. :: import curses stdscr = curses.initscr() -Usually curses applications turn off automatic echoing of keys to the screen, in -order to be able to read keys and only display them under certain circumstances. -This requires calling the :func:`noecho` function. :: +Usually curses applications turn off automatic echoing of keys to the +screen, in order to be able to read keys and only display them under +certain circumstances. This requires calling the +:func:`~curses.noecho` function. :: curses.noecho() -Applications will also commonly need to react to keys instantly, without -requiring the Enter key to be pressed; this is called cbreak mode, as opposed to -the usual buffered input mode. :: +Applications will also commonly need to react to keys instantly, +without requiring the Enter key to be pressed; this is called cbreak +mode, as opposed to the usual buffered input mode. :: curses.cbreak() @@ -103,12 +113,14 @@ :const:`curses.KEY_LEFT`. To get curses to do the job, you'll have to enable keypad mode. :: - stdscr.keypad(1) + stdscr.keypad(True) Terminating a curses application is much easier than starting one. You'll need -to call :: +to call:: - curses.nocbreak(); stdscr.keypad(0); curses.echo() + curses.nocbreak() + stdscr.keypad(False) + curses.echo() to reverse the curses-friendly terminal settings. Then call the :func:`endwin` function to restore the terminal to its original operating mode. :: @@ -122,102 +134,147 @@ you type them, for example, which makes using the shell difficult. In Python you can avoid these complications and make debugging much easier by -importing the module :mod:`curses.wrapper`. It supplies a :func:`wrapper` -function that takes a callable. It does the initializations described above, -and also initializes colors if color support is present. It then runs your -provided callable and finally deinitializes appropriately. The callable is -called inside a try-catch clause which catches exceptions, performs curses -deinitialization, and then passes the exception upwards. Thus, your terminal -won't be left in a funny state on exception. +importing the :func:`curses.wrapper` function and using it like this:: + + from curses import wrapper + + def main(stdscr): + # Clear screen + stdscr.clear() + + # This raises ZeroDivisionError when i == 10. + for i in range(0, 10): + v = i-10 + stdscr.addstr(i, 0, '10 divided by {} is {}'.format(v, 10/v)) + + stdscr.refresh() + stdscr.getkey() + + wrapper(main) + +The :func:`wrapper` function takes a callable object and does the +initializations described above, also initializing colors if color +support is present. :func:`wrapper` then runs your provided callable. +Once the callable returns, :func:`wrapper` will restore the original +state of the terminal. The callable is called inside a +:keyword:`try`...\ :keyword:`except` that catches exceptions, restores +the state of the terminal, and then re-raises the exception. Therefore +your terminal won't be left in a funny state on exception and you'll be +able to read the exception's message and traceback. Windows and Pads ================ Windows are the basic abstraction in curses. A window object represents a -rectangular area of the screen, and supports various methods to display text, +rectangular area of the screen, and supports methods to display text, erase it, allow the user to input strings, and so forth. -The ``stdscr`` object returned by the :func:`initscr` function is a window -object that covers the entire screen. Many programs may need only this single -window, but you might wish to divide the screen into smaller windows, in order -to redraw or clear them separately. The :func:`newwin` function creates a new -window of a given size, returning the new window object. :: +The ``stdscr`` object returned by the :func:`initscr` function is a +window object that covers the entire screen. Many programs may need +only this single window, but you might wish to divide the screen into +smaller windows, in order to redraw or clear them separately. The +:func:`~curses.newwin` function creates a new window of a given size, +returning the new window object. :: begin_x = 20 ; begin_y = 7 height = 5 ; width = 40 win = curses.newwin(height, width, begin_y, begin_x) -A word about the coordinate system used in curses: coordinates are always passed -in the order *y,x*, and the top-left corner of a window is coordinate (0,0). -This breaks a common convention for handling coordinates, where the *x* -coordinate usually comes first. This is an unfortunate difference from most -other computer applications, but it's been part of curses since it was first -written, and it's too late to change things now. +Note that the coordinate system used in curses is unusual. +Coordinates are always passed in the order *y,x*, and the top-left +corner of a window is coordinate (0,0). This breaks the normal +convention for handling coordinates where the *x* coordinate comes +first. This is an unfortunate difference from most other computer +applications, but it's been part of curses since it was first written, +and it's too late to change things now. -When you call a method to display or erase text, the effect doesn't immediately -show up on the display. This is because curses was originally written with slow -300-baud terminal connections in mind; with these terminals, minimizing the time -required to redraw the screen is very important. This lets curses accumulate -changes to the screen, and display them in the most efficient manner. For -example, if your program displays some characters in a window, and then clears -the window, there's no need to send the original characters because they'd never -be visible. +Your application can determine the size of the screen by using the +:data:`curses.LINES` and :data:`curses.COLS` variables to obtain the *y* and +*x* sizes. Legal coordinates will then extend from ``(0,0)`` to +``(curses.LINES - 1, curses.COLS - 1)``. -Accordingly, curses requires that you explicitly tell it to redraw windows, -using the :func:`refresh` method of window objects. In practice, this doesn't +When you call a method to display or erase text, the effect doesn't +immediately show up on the display. Instead you must call the +:meth:`~curses.window.refresh` method of window objects to update the +screen. + +This is because curses was originally written with slow 300-baud +terminal connections in mind; with these terminals, minimizing the +time required to redraw the screen was very important. Instead curses +accumulates changes to the screen and displays them in the most +efficient manner when you call :meth:`refresh`. For example, if your +program displays some text in a window and then clears the window, +there's no need to send the original text because they're never +visible. + +In practice, explicitly telling curses to redraw a window doesn't really complicate programming with curses much. Most programs go into a flurry of activity, and then pause waiting for a keypress or some other action on the part of the user. All you have to do is to be sure that the screen has been -redrawn before pausing to wait for user input, by simply calling -``stdscr.refresh()`` or the :func:`refresh` method of some other relevant +redrawn before pausing to wait for user input, by first calling +``stdscr.refresh()`` or the :meth:`refresh` method of some other relevant window. A pad is a special case of a window; it can be larger than the actual display -screen, and only a portion of it displayed at a time. Creating a pad simply +screen, and only a portion of the pad displayed at a time. Creating a pad requires the pad's height and width, while refreshing a pad requires giving the coordinates of the on-screen area where a subsection of the pad will be -displayed. :: +displayed. :: pad = curses.newpad(100, 100) - # These loops fill the pad with letters; this is + # These loops fill the pad with letters; addch() is # explained in the next section - for y in range(0, 100): - for x in range(0, 100): - try: pad.addch(y,x, ord('a') + (x*x+y*y) % 26 ) - except curses.error: pass + for y in range(0, 99): + for x in range(0, 99): + pad.addch(y,x, ord('a') + (x*x+y*y) % 26 ) - # Displays a section of the pad in the middle of the screen + # Displays a section of the pad in the middle of the screen. + # (0,0) : coordinate of upper-left corner of pad area to display. + # (5,5) : coordinate of upper-left corner of window area to be filled + # with pad content. + # (20, 75) : coordinate of lower-right corner of window area to be + # : filled with pad content. pad.refresh( 0,0, 5,5, 20,75) -The :func:`refresh` call displays a section of the pad in the rectangle +The :meth:`refresh` call displays a section of the pad in the rectangle extending from coordinate (5,5) to coordinate (20,75) on the screen; the upper left corner of the displayed section is coordinate (0,0) on the pad. Beyond that difference, pads are exactly like ordinary windows and support the same methods. -If you have multiple windows and pads on screen there is a more efficient way to -go, which will prevent annoying screen flicker at refresh time. Use the -:meth:`noutrefresh` method of each window to update the data structure -representing the desired state of the screen; then change the physical screen to -match the desired state in one go with the function :func:`doupdate`. The -normal :meth:`refresh` method calls :func:`doupdate` as its last act. +If you have multiple windows and pads on screen there is a more +efficient way to update the screen and prevent annoying screen flicker +as each part of the screen gets updated. :meth:`refresh` actually +does two things: + +1) Calls the :meth:`~curses.window.noutrefresh` method of each window + to update an underlying data structure representing the desired + state of the screen. +2) Calls the function :func:`~curses.doupdate` function to change the + physical screen to match the desired state recorded in the data structure. + +Instead you can call :meth:`noutrefresh` on a number of windows to +update the data structure, and then call :func:`doupdate` to update +the screen. Displaying Text =============== -From a C programmer's point of view, curses may sometimes look like a twisty -maze of functions, all subtly different. For example, :func:`addstr` displays a -string at the current cursor location in the ``stdscr`` window, while -:func:`mvaddstr` moves to a given y,x coordinate first before displaying the -string. :func:`waddstr` is just like :func:`addstr`, but allows specifying a -window to use, instead of using ``stdscr`` by default. :func:`mvwaddstr` follows -similarly. +From a C programmer's point of view, curses may sometimes look like a +twisty maze of functions, all subtly different. For example, +:c:func:`addstr` displays a string at the current cursor location in +the ``stdscr`` window, while :c:func:`mvaddstr` moves to a given y,x +coordinate first before displaying the string. :c:func:`waddstr` is just +like :func:`addstr`, but allows specifying a window to use instead of +using ``stdscr`` by default. :c:func:`mvwaddstr` allows specifying both +a window and a coordinate. -Fortunately the Python interface hides all these details; ``stdscr`` is a window -object like any other, and methods like :func:`addstr` accept multiple argument -forms. Usually there are four different forms. +Fortunately the Python interface hides all these details. ``stdscr`` +is a window object like any other, and methods such as :meth:`addstr` +accept multiple argument forms. Usually there are four different +forms. +---------------------------------+-----------------------------------------------+ | Form | Description | @@ -236,17 +293,26 @@ | | display *str* or *ch*, using attribute *attr* | +---------------------------------+-----------------------------------------------+ -Attributes allow displaying text in highlighted forms, such as in boldface, +Attributes allow displaying text in highlighted forms such as boldface, underline, reverse code, or in color. They'll be explained in more detail in the next subsection. -The :func:`addstr` function takes a Python string as the value to be displayed, -while the :func:`addch` functions take a character, which can be either a Python -string of length 1 or an integer. If it's a string, you're limited to -displaying characters between 0 and 255. SVr4 curses provides constants for -extension characters; these constants are integers greater than 255. For -example, :const:`ACS_PLMINUS` is a +/- symbol, and :const:`ACS_ULCORNER` is the -upper left corner of a box (handy for drawing borders). + +The :meth:`~curses.window.addstr` method takes a Python string or +bytestring as the value to be displayed. The contents of bytestrings +are sent to the terminal as-is. Strings are encoded to bytes using +the value of the window's :attr:`encoding` attribute; this defaults to +the default system encoding as returned by +:func:`locale.getpreferredencoding`. + +The :meth:`~curses.window.addch` methods take a character, which can be +either a string of length 1, a bytestring of length 1, or an integer. + +Constants are provided for extension characters; these constants are +integers greater than 255. For example, :const:`ACS_PLMINUS` is a +/- +symbol, and :const:`ACS_ULCORNER` is the upper left corner of a box +(handy for drawing borders). You can also use the appropriate Unicode +character. Windows remember where the cursor was left after the last operation, so if you leave out the *y,x* coordinates, the string or character will be displayed @@ -256,10 +322,11 @@ won't be distracting; it can be confusing to have the cursor blinking at some apparently random location. -If your application doesn't need a blinking cursor at all, you can call -``curs_set(0)`` to make it invisible. Equivalently, and for compatibility with -older curses versions, there's a ``leaveok(bool)`` function. When *bool* is -true, the curses library will attempt to suppress the flashing cursor, and you +If your application doesn't need a blinking cursor at all, you can +call ``curs_set(False)`` to make it invisible. For compatibility +with older curses versions, there's a ``leaveok(bool)`` function +that's a synonym for :func:`curs_set`. When *bool* is true, the +curses library will attempt to suppress the flashing cursor, and you won't need to worry about leaving it in odd locations. @@ -267,15 +334,16 @@ -------------------- Characters can be displayed in different ways. Status lines in a text-based -application are commonly shown in reverse video; a text viewer may need to +application are commonly shown in reverse video, or a text viewer may need to highlight certain words. curses supports this by allowing you to specify an attribute for each cell on the screen. -An attribute is an integer, each bit representing a different attribute. You can -try to display text with multiple attribute bits set, but curses doesn't -guarantee that all the possible combinations are available, or that they're all -visually distinct. That depends on the ability of the terminal being used, so -it's safest to stick to the most commonly available attributes, listed here. +An attribute is an integer, each bit representing a different +attribute. You can try to display text with multiple attribute bits +set, but curses doesn't guarantee that all the possible combinations +are available, or that they're all visually distinct. That depends on +the ability of the terminal being used, so it's safest to stick to the +most commonly available attributes, listed here. +----------------------+--------------------------------------+ | Attribute | Description | @@ -306,7 +374,7 @@ To use color, you must call the :func:`start_color` function soon after calling :func:`initscr`, to initialize the default color set (the -:func:`curses.wrapper.wrapper` function does this automatically). Once that's +:func:`curses.wrapper` function does this automatically). Once that's done, the :func:`has_colors` function returns TRUE if the terminal in use can actually display color. (Note: curses uses the American spelling 'color', instead of the Canadian/British spelling 'colour'. If you're used to the @@ -325,15 +393,16 @@ stdscr.refresh() As I said before, a color pair consists of a foreground and background color. -:func:`start_color` initializes 8 basic colors when it activates color mode. -They are: 0:black, 1:red, 2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and -7:white. The curses module defines named constants for each of these colors: -:const:`curses.COLOR_BLACK`, :const:`curses.COLOR_RED`, and so forth. - The ``init_pair(n, f, b)`` function changes the definition of color pair *n*, to foreground color f and background color b. Color pair 0 is hard-wired to white on black, and cannot be changed. +Colors are numbered, and :func:`start_color` initializes 8 basic +colors when it activates color mode. They are: 0:black, 1:red, +2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The :mod:`curses` +module defines named constants for each of these colors: +:const:`curses.COLOR_BLACK`, :const:`curses.COLOR_RED`, and so forth. + Let's put all this together. To change color 1 to red text on a white background, you would call:: @@ -350,87 +419,130 @@ blue or any other color you like. Unfortunately, the Linux console doesn't support this, so I'm unable to try it out, and can't provide any examples. You can check if your terminal can do this by calling :func:`can_change_color`, -which returns TRUE if the capability is there. If you're lucky enough to have +which returns True if the capability is there. If you're lucky enough to have such a talented terminal, consult your system's man pages for more information. User Input ========== -The curses library itself offers only very simple input mechanisms. Python's -support adds a text-input widget that makes up some of the lack. +The C curses library offers only very simple input mechanisms. Python's +:mod:`curses` module adds a basic text-input widget. (Other libraries +such as `Urwid `_ have more extensive +collections of widgets.) -The most common way to get input to a window is to use its :meth:`getch` method. -:meth:`getch` pauses and waits for the user to hit a key, displaying it if -:func:`echo` has been called earlier. You can optionally specify a coordinate -to which the cursor should be moved before pausing. +There are two methods for getting input from a window: -It's possible to change this behavior with the method :meth:`nodelay`. After -``nodelay(1)``, :meth:`getch` for the window becomes non-blocking and returns -``curses.ERR`` (a value of -1) when no input is ready. There's also a -:func:`halfdelay` function, which can be used to (in effect) set a timer on each -:meth:`getch`; if no input becomes available within a specified -delay (measured in tenths of a second), curses raises an exception. +* :meth:`~curses.window.getch` refreshes the screen and then waits for + the user to hit a key, displaying the key if :func:`echo` has been + called earlier. You can optionally specify a coordinate to which + the cursor should be moved before pausing. + +* :meth:`~curses.window.getkey` does the same thing but converts the + integer to a string. Individual characters are returned as + 1-character strings, and special keys such as function keys return + longer strings containing a key name such as ``KEY_UP`` or ``^G``. + +It's possible to not wait for the user using the +:meth:`~curses.window.nodelay` window method. After ``nodelay(True)``, +:meth:`getch` and :meth:`getkey` for the window become +non-blocking. To signal that no input is ready, :meth:`getch` returns +``curses.ERR`` (a value of -1) and :meth:`getkey` raises an exception. +There's also a :func:`~curses.halfdelay` function, which can be used to (in +effect) set a timer on each :meth:`getch`; if no input becomes +available within a specified delay (measured in tenths of a second), +curses raises an exception. The :meth:`getch` method returns an integer; if it's between 0 and 255, it represents the ASCII code of the key pressed. Values greater than 255 are special keys such as Page Up, Home, or the cursor keys. You can compare the value returned to constants such as :const:`curses.KEY_PPAGE`, -:const:`curses.KEY_HOME`, or :const:`curses.KEY_LEFT`. Usually the main loop of -your program will look something like this:: +:const:`curses.KEY_HOME`, or :const:`curses.KEY_LEFT`. The main loop of +your program may look something like this:: while True: c = stdscr.getch() - if c == ord('p'): PrintDocument() - elif c == ord('q'): break # Exit the while() - elif c == curses.KEY_HOME: x = y = 0 + if c == ord('p'): + PrintDocument() + elif c == ord('q'): + break # Exit the while loop + elif c == curses.KEY_HOME: + x = y = 0 The :mod:`curses.ascii` module supplies ASCII class membership functions that -take either integer or 1-character-string arguments; these may be useful in -writing more readable tests for your command interpreters. It also supplies +take either integer or 1-character string arguments; these may be useful in +writing more readable tests for such loops. It also supplies conversion functions that take either integer or 1-character-string arguments and return the same type. For example, :func:`curses.ascii.ctrl` returns the control character corresponding to its argument. -There's also a method to retrieve an entire string, :const:`getstr()`. It isn't -used very often, because its functionality is quite limited; the only editing -keys available are the backspace key and the Enter key, which terminates the -string. It can optionally be limited to a fixed number of characters. :: +There's also a method to retrieve an entire string, +:meth:`~curses.window.getstr`. It isn't used very often, because its +functionality is quite limited; the only editing keys available are +the backspace key and the Enter key, which terminates the string. It +can optionally be limited to a fixed number of characters. :: curses.echo() # Enable echoing of characters # Get a 15-character string, with the cursor on the top line s = stdscr.getstr(0,0, 15) -The Python :mod:`curses.textpad` module supplies something better. With it, you -can turn a window into a text box that supports an Emacs-like set of -keybindings. Various methods of :class:`Textbox` class support editing with -input validation and gathering the edit results either with or without trailing -spaces. See the library documentation on :mod:`curses.textpad` for the -details. +The :mod:`curses.textpad` module supplies a text box that supports an +Emacs-like set of keybindings. Various methods of the +:class:`~curses.textpad.Textbox` class support editing with input +validation and gathering the edit results either with or without +trailing spaces. Here's an example:: + + import curses + from curses.textpad import Textbox, rectangle + + def main(stdscr): + stdscr.addstr(0, 0, "Enter IM message: (hit Ctrl-G to send)") + + editwin = curses.newwin(5,30, 2,1) + rectangle(stdscr, 1,0, 1+5+1, 1+30+1) + stdscr.refresh() + + box = Textbox(editwin) + + # Let the user edit until Ctrl-G is struck. + box.edit() + + # Get resulting contents + message = box.gather() + +See the library documentation on :mod:`curses.textpad` for more details. For More Information ==================== -This HOWTO didn't cover some advanced topics, such as screen-scraping or -capturing mouse events from an xterm instance. But the Python library page for -the curses modules is now pretty complete. You should browse it next. +This HOWTO doesn't cover some advanced topics, such as reading the +contents of the screen or capturing mouse events from an xterm +instance, but the Python library page for the :mod:`curses` module is now +reasonably complete. You should browse it next. -If you're in doubt about the detailed behavior of any of the ncurses entry -points, consult the manual pages for your curses implementation, whether it's -ncurses or a proprietary Unix vendor's. The manual pages will document any -quirks, and provide complete lists of all the functions, attributes, and -:const:`ACS_\*` characters available to you. +If you're in doubt about the detailed behavior of the curses +functions, consult the manual pages for your curses implementation, +whether it's ncurses or a proprietary Unix vendor's. The manual pages +will document any quirks, and provide complete lists of all the +functions, attributes, and :const:`ACS_\*` characters available to +you. -Because the curses API is so large, some functions aren't supported in the -Python interface, not because they're difficult to implement, but because no one -has needed them yet. Feel free to add them and then submit a patch. Also, we -don't yet have support for the menu library associated with -ncurses; feel free to add that. +Because the curses API is so large, some functions aren't supported in +the Python interface. Often this isn't because they're difficult to +implement, but because no one has needed them yet. Also, Python +doesn't yet support the menu library associated with ncurses. +Patches adding support for these would be welcome; see +`the Python Developer's Guide `_ to +learn more about submitting patches to Python. -If you write an interesting little program, feel free to contribute it as -another demo. We can always use more of them! - -The ncurses FAQ: http://invisible-island.net/ncurses/ncurses.faq.html - +* `Writing Programs with NCURSES `_: + a lengthy tutorial for C programmers. +* `The ncurses man page `_ +* `The ncurses FAQ `_ +* `"Use curses... don't swear" `_: + video of a PyCon 2013 talk on controlling terminals using curses or Urwid. +* `"Console Applications with Urwid" `_: + video of a PyCon CA 2012 talk demonstrating some applications written using + Urwid. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 10 02:14:52 2013 From: python-checkins at python.org (andrew.kuchling) Date: Fri, 10 May 2013 02:14:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_=2317700=3A_merge_with_3=2E3?= Message-ID: <3b6Bkh1DzTz7Lm1@mail.python.org> http://hg.python.org/cpython/rev/70f530161b9b changeset: 83700:70f530161b9b parent: 83698:ebc296bf23d1 parent: 83699:1fa70b797973 user: Andrew Kuchling date: Thu May 09 20:14:01 2013 -0400 summary: #17700: merge with 3.3 files: Doc/howto/curses.rst | 454 +++++++++++++++++++----------- 1 files changed, 283 insertions(+), 171 deletions(-) diff --git a/Doc/howto/curses.rst b/Doc/howto/curses.rst --- a/Doc/howto/curses.rst +++ b/Doc/howto/curses.rst @@ -5,39 +5,43 @@ ********************************** :Author: A.M. Kuchling, Eric S. Raymond -:Release: 2.03 +:Release: 2.04 .. topic:: Abstract - This document describes how to write text-mode programs with Python 2.x, using - the :mod:`curses` extension module to control the display. + This document describes how to use the :mod:`curses` extension + module to control text-mode displays. What is curses? =============== The curses library supplies a terminal-independent screen-painting and -keyboard-handling facility for text-based terminals; such terminals include -VT100s, the Linux console, and the simulated terminal provided by X11 programs -such as xterm and rxvt. Display terminals support various control codes to -perform common operations such as moving the cursor, scrolling the screen, and -erasing areas. Different terminals use widely differing codes, and often have -their own minor quirks. +keyboard-handling facility for text-based terminals; such terminals +include VT100s, the Linux console, and the simulated terminal provided +by various programs. Display terminals support various control codes +to perform common operations such as moving the cursor, scrolling the +screen, and erasing areas. Different terminals use widely differing +codes, and often have their own minor quirks. -In a world of X displays, one might ask "why bother"? It's true that -character-cell display terminals are an obsolete technology, but there are -niches in which being able to do fancy things with them are still valuable. One -is on small-footprint or embedded Unixes that don't carry an X server. Another -is for tools like OS installers and kernel configurators that may have to run -before X is available. +In a world of graphical displays, one might ask "why bother"? It's +true that character-cell display terminals are an obsolete technology, +but there are niches in which being able to do fancy things with them +are still valuable. One niche is on small-footprint or embedded +Unixes that don't run an X server. Another is tools such as OS +installers and kernel configurators that may have to run before any +graphical support is available. -The curses library hides all the details of different terminals, and provides -the programmer with an abstraction of a display, containing multiple -non-overlapping windows. The contents of a window can be changed in various -ways-- adding text, erasing it, changing its appearance--and the curses library -will automagically figure out what control codes need to be sent to the terminal -to produce the right output. +The curses library provides fairly basic functionality, providing the +programmer with an abstraction of a display containing multiple +non-overlapping windows of text. The contents of a window can be +changed in various ways---adding text, erasing it, changing its +appearance---and the curses library will figure out what control codes +need to be sent to the terminal to produce the right output. curses +doesn't provide many user-interface concepts such as buttons, checkboxes, +or dialogs; if you need such features, consider a user interface library such as +`Urwid `_. The curses library was originally written for BSD Unix; the later System V versions of Unix from AT&T added many enhancements and new functions. BSD curses @@ -49,10 +53,13 @@ versions of curses carried by some proprietary Unixes may not support everything, though. -No one has made a Windows port of the curses module. On a Windows platform, try -the Console module written by Fredrik Lundh. The Console module provides -cursor-addressable text output, plus full support for mouse and keyboard input, -and is available from http://effbot.org/zone/console-index.htm. +The Windows version of Python doesn't include the :mod:`curses` +module. A ported version called `UniCurses +`_ is available. You could +also try `the Console module `_ +written by Fredrik Lundh, which doesn't +use the same API as curses but provides cursor-addressable text output +and full support for mouse and keyboard input. The Python curses module @@ -61,11 +68,12 @@ Thy Python module is a fairly simple wrapper over the C functions provided by curses; if you're already familiar with curses programming in C, it's really easy to transfer that knowledge to Python. The biggest difference is that the -Python interface makes things simpler, by merging different C functions such as -:func:`addstr`, :func:`mvaddstr`, :func:`mvwaddstr`, into a single -:meth:`addstr` method. You'll see this covered in more detail later. +Python interface makes things simpler by merging different C functions such as +:c:func:`addstr`, :c:func:`mvaddstr`, and :c:func:`mvwaddstr` into a single +:meth:`~curses.window.addstr` method. You'll see this covered in more +detail later. -This HOWTO is simply an introduction to writing text-mode programs with curses +This HOWTO is an introduction to writing text-mode programs with curses and Python. It doesn't attempt to be a complete guide to the curses API; for that, see the Python library guide's section on ncurses, and the C manual pages for ncurses. It will, however, give you the basic ideas. @@ -74,25 +82,27 @@ Starting and ending a curses application ======================================== -Before doing anything, curses must be initialized. This is done by calling the -:func:`initscr` function, which will determine the terminal type, send any -required setup codes to the terminal, and create various internal data -structures. If successful, :func:`initscr` returns a window object representing -the entire screen; this is usually called ``stdscr``, after the name of the +Before doing anything, curses must be initialized. This is done by +calling the :func:`~curses.initscr` function, which will determine the +terminal type, send any required setup codes to the terminal, and +create various internal data structures. If successful, +:func:`initscr` returns a window object representing the entire +screen; this is usually called ``stdscr`` after the name of the corresponding C variable. :: import curses stdscr = curses.initscr() -Usually curses applications turn off automatic echoing of keys to the screen, in -order to be able to read keys and only display them under certain circumstances. -This requires calling the :func:`noecho` function. :: +Usually curses applications turn off automatic echoing of keys to the +screen, in order to be able to read keys and only display them under +certain circumstances. This requires calling the +:func:`~curses.noecho` function. :: curses.noecho() -Applications will also commonly need to react to keys instantly, without -requiring the Enter key to be pressed; this is called cbreak mode, as opposed to -the usual buffered input mode. :: +Applications will also commonly need to react to keys instantly, +without requiring the Enter key to be pressed; this is called cbreak +mode, as opposed to the usual buffered input mode. :: curses.cbreak() @@ -103,12 +113,14 @@ :const:`curses.KEY_LEFT`. To get curses to do the job, you'll have to enable keypad mode. :: - stdscr.keypad(1) + stdscr.keypad(True) Terminating a curses application is much easier than starting one. You'll need -to call :: +to call:: - curses.nocbreak(); stdscr.keypad(0); curses.echo() + curses.nocbreak() + stdscr.keypad(False) + curses.echo() to reverse the curses-friendly terminal settings. Then call the :func:`endwin` function to restore the terminal to its original operating mode. :: @@ -122,102 +134,147 @@ you type them, for example, which makes using the shell difficult. In Python you can avoid these complications and make debugging much easier by -importing the module :mod:`curses.wrapper`. It supplies a :func:`wrapper` -function that takes a callable. It does the initializations described above, -and also initializes colors if color support is present. It then runs your -provided callable and finally deinitializes appropriately. The callable is -called inside a try-catch clause which catches exceptions, performs curses -deinitialization, and then passes the exception upwards. Thus, your terminal -won't be left in a funny state on exception. +importing the :func:`curses.wrapper` function and using it like this:: + + from curses import wrapper + + def main(stdscr): + # Clear screen + stdscr.clear() + + # This raises ZeroDivisionError when i == 10. + for i in range(0, 10): + v = i-10 + stdscr.addstr(i, 0, '10 divided by {} is {}'.format(v, 10/v)) + + stdscr.refresh() + stdscr.getkey() + + wrapper(main) + +The :func:`wrapper` function takes a callable object and does the +initializations described above, also initializing colors if color +support is present. :func:`wrapper` then runs your provided callable. +Once the callable returns, :func:`wrapper` will restore the original +state of the terminal. The callable is called inside a +:keyword:`try`...\ :keyword:`except` that catches exceptions, restores +the state of the terminal, and then re-raises the exception. Therefore +your terminal won't be left in a funny state on exception and you'll be +able to read the exception's message and traceback. Windows and Pads ================ Windows are the basic abstraction in curses. A window object represents a -rectangular area of the screen, and supports various methods to display text, +rectangular area of the screen, and supports methods to display text, erase it, allow the user to input strings, and so forth. -The ``stdscr`` object returned by the :func:`initscr` function is a window -object that covers the entire screen. Many programs may need only this single -window, but you might wish to divide the screen into smaller windows, in order -to redraw or clear them separately. The :func:`newwin` function creates a new -window of a given size, returning the new window object. :: +The ``stdscr`` object returned by the :func:`initscr` function is a +window object that covers the entire screen. Many programs may need +only this single window, but you might wish to divide the screen into +smaller windows, in order to redraw or clear them separately. The +:func:`~curses.newwin` function creates a new window of a given size, +returning the new window object. :: begin_x = 20 ; begin_y = 7 height = 5 ; width = 40 win = curses.newwin(height, width, begin_y, begin_x) -A word about the coordinate system used in curses: coordinates are always passed -in the order *y,x*, and the top-left corner of a window is coordinate (0,0). -This breaks a common convention for handling coordinates, where the *x* -coordinate usually comes first. This is an unfortunate difference from most -other computer applications, but it's been part of curses since it was first -written, and it's too late to change things now. +Note that the coordinate system used in curses is unusual. +Coordinates are always passed in the order *y,x*, and the top-left +corner of a window is coordinate (0,0). This breaks the normal +convention for handling coordinates where the *x* coordinate comes +first. This is an unfortunate difference from most other computer +applications, but it's been part of curses since it was first written, +and it's too late to change things now. -When you call a method to display or erase text, the effect doesn't immediately -show up on the display. This is because curses was originally written with slow -300-baud terminal connections in mind; with these terminals, minimizing the time -required to redraw the screen is very important. This lets curses accumulate -changes to the screen, and display them in the most efficient manner. For -example, if your program displays some characters in a window, and then clears -the window, there's no need to send the original characters because they'd never -be visible. +Your application can determine the size of the screen by using the +:data:`curses.LINES` and :data:`curses.COLS` variables to obtain the *y* and +*x* sizes. Legal coordinates will then extend from ``(0,0)`` to +``(curses.LINES - 1, curses.COLS - 1)``. -Accordingly, curses requires that you explicitly tell it to redraw windows, -using the :func:`refresh` method of window objects. In practice, this doesn't +When you call a method to display or erase text, the effect doesn't +immediately show up on the display. Instead you must call the +:meth:`~curses.window.refresh` method of window objects to update the +screen. + +This is because curses was originally written with slow 300-baud +terminal connections in mind; with these terminals, minimizing the +time required to redraw the screen was very important. Instead curses +accumulates changes to the screen and displays them in the most +efficient manner when you call :meth:`refresh`. For example, if your +program displays some text in a window and then clears the window, +there's no need to send the original text because they're never +visible. + +In practice, explicitly telling curses to redraw a window doesn't really complicate programming with curses much. Most programs go into a flurry of activity, and then pause waiting for a keypress or some other action on the part of the user. All you have to do is to be sure that the screen has been -redrawn before pausing to wait for user input, by simply calling -``stdscr.refresh()`` or the :func:`refresh` method of some other relevant +redrawn before pausing to wait for user input, by first calling +``stdscr.refresh()`` or the :meth:`refresh` method of some other relevant window. A pad is a special case of a window; it can be larger than the actual display -screen, and only a portion of it displayed at a time. Creating a pad simply +screen, and only a portion of the pad displayed at a time. Creating a pad requires the pad's height and width, while refreshing a pad requires giving the coordinates of the on-screen area where a subsection of the pad will be -displayed. :: +displayed. :: pad = curses.newpad(100, 100) - # These loops fill the pad with letters; this is + # These loops fill the pad with letters; addch() is # explained in the next section - for y in range(0, 100): - for x in range(0, 100): - try: pad.addch(y,x, ord('a') + (x*x+y*y) % 26 ) - except curses.error: pass + for y in range(0, 99): + for x in range(0, 99): + pad.addch(y,x, ord('a') + (x*x+y*y) % 26 ) - # Displays a section of the pad in the middle of the screen + # Displays a section of the pad in the middle of the screen. + # (0,0) : coordinate of upper-left corner of pad area to display. + # (5,5) : coordinate of upper-left corner of window area to be filled + # with pad content. + # (20, 75) : coordinate of lower-right corner of window area to be + # : filled with pad content. pad.refresh( 0,0, 5,5, 20,75) -The :func:`refresh` call displays a section of the pad in the rectangle +The :meth:`refresh` call displays a section of the pad in the rectangle extending from coordinate (5,5) to coordinate (20,75) on the screen; the upper left corner of the displayed section is coordinate (0,0) on the pad. Beyond that difference, pads are exactly like ordinary windows and support the same methods. -If you have multiple windows and pads on screen there is a more efficient way to -go, which will prevent annoying screen flicker at refresh time. Use the -:meth:`noutrefresh` method of each window to update the data structure -representing the desired state of the screen; then change the physical screen to -match the desired state in one go with the function :func:`doupdate`. The -normal :meth:`refresh` method calls :func:`doupdate` as its last act. +If you have multiple windows and pads on screen there is a more +efficient way to update the screen and prevent annoying screen flicker +as each part of the screen gets updated. :meth:`refresh` actually +does two things: + +1) Calls the :meth:`~curses.window.noutrefresh` method of each window + to update an underlying data structure representing the desired + state of the screen. +2) Calls the function :func:`~curses.doupdate` function to change the + physical screen to match the desired state recorded in the data structure. + +Instead you can call :meth:`noutrefresh` on a number of windows to +update the data structure, and then call :func:`doupdate` to update +the screen. Displaying Text =============== -From a C programmer's point of view, curses may sometimes look like a twisty -maze of functions, all subtly different. For example, :func:`addstr` displays a -string at the current cursor location in the ``stdscr`` window, while -:func:`mvaddstr` moves to a given y,x coordinate first before displaying the -string. :func:`waddstr` is just like :func:`addstr`, but allows specifying a -window to use, instead of using ``stdscr`` by default. :func:`mvwaddstr` follows -similarly. +From a C programmer's point of view, curses may sometimes look like a +twisty maze of functions, all subtly different. For example, +:c:func:`addstr` displays a string at the current cursor location in +the ``stdscr`` window, while :c:func:`mvaddstr` moves to a given y,x +coordinate first before displaying the string. :c:func:`waddstr` is just +like :func:`addstr`, but allows specifying a window to use instead of +using ``stdscr`` by default. :c:func:`mvwaddstr` allows specifying both +a window and a coordinate. -Fortunately the Python interface hides all these details; ``stdscr`` is a window -object like any other, and methods like :func:`addstr` accept multiple argument -forms. Usually there are four different forms. +Fortunately the Python interface hides all these details. ``stdscr`` +is a window object like any other, and methods such as :meth:`addstr` +accept multiple argument forms. Usually there are four different +forms. +---------------------------------+-----------------------------------------------+ | Form | Description | @@ -236,17 +293,26 @@ | | display *str* or *ch*, using attribute *attr* | +---------------------------------+-----------------------------------------------+ -Attributes allow displaying text in highlighted forms, such as in boldface, +Attributes allow displaying text in highlighted forms such as boldface, underline, reverse code, or in color. They'll be explained in more detail in the next subsection. -The :func:`addstr` function takes a Python string as the value to be displayed, -while the :func:`addch` functions take a character, which can be either a Python -string of length 1 or an integer. If it's a string, you're limited to -displaying characters between 0 and 255. SVr4 curses provides constants for -extension characters; these constants are integers greater than 255. For -example, :const:`ACS_PLMINUS` is a +/- symbol, and :const:`ACS_ULCORNER` is the -upper left corner of a box (handy for drawing borders). + +The :meth:`~curses.window.addstr` method takes a Python string or +bytestring as the value to be displayed. The contents of bytestrings +are sent to the terminal as-is. Strings are encoded to bytes using +the value of the window's :attr:`encoding` attribute; this defaults to +the default system encoding as returned by +:func:`locale.getpreferredencoding`. + +The :meth:`~curses.window.addch` methods take a character, which can be +either a string of length 1, a bytestring of length 1, or an integer. + +Constants are provided for extension characters; these constants are +integers greater than 255. For example, :const:`ACS_PLMINUS` is a +/- +symbol, and :const:`ACS_ULCORNER` is the upper left corner of a box +(handy for drawing borders). You can also use the appropriate Unicode +character. Windows remember where the cursor was left after the last operation, so if you leave out the *y,x* coordinates, the string or character will be displayed @@ -256,10 +322,11 @@ won't be distracting; it can be confusing to have the cursor blinking at some apparently random location. -If your application doesn't need a blinking cursor at all, you can call -``curs_set(0)`` to make it invisible. Equivalently, and for compatibility with -older curses versions, there's a ``leaveok(bool)`` function. When *bool* is -true, the curses library will attempt to suppress the flashing cursor, and you +If your application doesn't need a blinking cursor at all, you can +call ``curs_set(False)`` to make it invisible. For compatibility +with older curses versions, there's a ``leaveok(bool)`` function +that's a synonym for :func:`curs_set`. When *bool* is true, the +curses library will attempt to suppress the flashing cursor, and you won't need to worry about leaving it in odd locations. @@ -267,15 +334,16 @@ -------------------- Characters can be displayed in different ways. Status lines in a text-based -application are commonly shown in reverse video; a text viewer may need to +application are commonly shown in reverse video, or a text viewer may need to highlight certain words. curses supports this by allowing you to specify an attribute for each cell on the screen. -An attribute is an integer, each bit representing a different attribute. You can -try to display text with multiple attribute bits set, but curses doesn't -guarantee that all the possible combinations are available, or that they're all -visually distinct. That depends on the ability of the terminal being used, so -it's safest to stick to the most commonly available attributes, listed here. +An attribute is an integer, each bit representing a different +attribute. You can try to display text with multiple attribute bits +set, but curses doesn't guarantee that all the possible combinations +are available, or that they're all visually distinct. That depends on +the ability of the terminal being used, so it's safest to stick to the +most commonly available attributes, listed here. +----------------------+--------------------------------------+ | Attribute | Description | @@ -306,7 +374,7 @@ To use color, you must call the :func:`start_color` function soon after calling :func:`initscr`, to initialize the default color set (the -:func:`curses.wrapper.wrapper` function does this automatically). Once that's +:func:`curses.wrapper` function does this automatically). Once that's done, the :func:`has_colors` function returns TRUE if the terminal in use can actually display color. (Note: curses uses the American spelling 'color', instead of the Canadian/British spelling 'colour'. If you're used to the @@ -325,15 +393,16 @@ stdscr.refresh() As I said before, a color pair consists of a foreground and background color. -:func:`start_color` initializes 8 basic colors when it activates color mode. -They are: 0:black, 1:red, 2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and -7:white. The curses module defines named constants for each of these colors: -:const:`curses.COLOR_BLACK`, :const:`curses.COLOR_RED`, and so forth. - The ``init_pair(n, f, b)`` function changes the definition of color pair *n*, to foreground color f and background color b. Color pair 0 is hard-wired to white on black, and cannot be changed. +Colors are numbered, and :func:`start_color` initializes 8 basic +colors when it activates color mode. They are: 0:black, 1:red, +2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The :mod:`curses` +module defines named constants for each of these colors: +:const:`curses.COLOR_BLACK`, :const:`curses.COLOR_RED`, and so forth. + Let's put all this together. To change color 1 to red text on a white background, you would call:: @@ -350,87 +419,130 @@ blue or any other color you like. Unfortunately, the Linux console doesn't support this, so I'm unable to try it out, and can't provide any examples. You can check if your terminal can do this by calling :func:`can_change_color`, -which returns TRUE if the capability is there. If you're lucky enough to have +which returns True if the capability is there. If you're lucky enough to have such a talented terminal, consult your system's man pages for more information. User Input ========== -The curses library itself offers only very simple input mechanisms. Python's -support adds a text-input widget that makes up some of the lack. +The C curses library offers only very simple input mechanisms. Python's +:mod:`curses` module adds a basic text-input widget. (Other libraries +such as `Urwid `_ have more extensive +collections of widgets.) -The most common way to get input to a window is to use its :meth:`getch` method. -:meth:`getch` pauses and waits for the user to hit a key, displaying it if -:func:`echo` has been called earlier. You can optionally specify a coordinate -to which the cursor should be moved before pausing. +There are two methods for getting input from a window: -It's possible to change this behavior with the method :meth:`nodelay`. After -``nodelay(1)``, :meth:`getch` for the window becomes non-blocking and returns -``curses.ERR`` (a value of -1) when no input is ready. There's also a -:func:`halfdelay` function, which can be used to (in effect) set a timer on each -:meth:`getch`; if no input becomes available within a specified -delay (measured in tenths of a second), curses raises an exception. +* :meth:`~curses.window.getch` refreshes the screen and then waits for + the user to hit a key, displaying the key if :func:`echo` has been + called earlier. You can optionally specify a coordinate to which + the cursor should be moved before pausing. + +* :meth:`~curses.window.getkey` does the same thing but converts the + integer to a string. Individual characters are returned as + 1-character strings, and special keys such as function keys return + longer strings containing a key name such as ``KEY_UP`` or ``^G``. + +It's possible to not wait for the user using the +:meth:`~curses.window.nodelay` window method. After ``nodelay(True)``, +:meth:`getch` and :meth:`getkey` for the window become +non-blocking. To signal that no input is ready, :meth:`getch` returns +``curses.ERR`` (a value of -1) and :meth:`getkey` raises an exception. +There's also a :func:`~curses.halfdelay` function, which can be used to (in +effect) set a timer on each :meth:`getch`; if no input becomes +available within a specified delay (measured in tenths of a second), +curses raises an exception. The :meth:`getch` method returns an integer; if it's between 0 and 255, it represents the ASCII code of the key pressed. Values greater than 255 are special keys such as Page Up, Home, or the cursor keys. You can compare the value returned to constants such as :const:`curses.KEY_PPAGE`, -:const:`curses.KEY_HOME`, or :const:`curses.KEY_LEFT`. Usually the main loop of -your program will look something like this:: +:const:`curses.KEY_HOME`, or :const:`curses.KEY_LEFT`. The main loop of +your program may look something like this:: while True: c = stdscr.getch() - if c == ord('p'): PrintDocument() - elif c == ord('q'): break # Exit the while() - elif c == curses.KEY_HOME: x = y = 0 + if c == ord('p'): + PrintDocument() + elif c == ord('q'): + break # Exit the while loop + elif c == curses.KEY_HOME: + x = y = 0 The :mod:`curses.ascii` module supplies ASCII class membership functions that -take either integer or 1-character-string arguments; these may be useful in -writing more readable tests for your command interpreters. It also supplies +take either integer or 1-character string arguments; these may be useful in +writing more readable tests for such loops. It also supplies conversion functions that take either integer or 1-character-string arguments and return the same type. For example, :func:`curses.ascii.ctrl` returns the control character corresponding to its argument. -There's also a method to retrieve an entire string, :const:`getstr()`. It isn't -used very often, because its functionality is quite limited; the only editing -keys available are the backspace key and the Enter key, which terminates the -string. It can optionally be limited to a fixed number of characters. :: +There's also a method to retrieve an entire string, +:meth:`~curses.window.getstr`. It isn't used very often, because its +functionality is quite limited; the only editing keys available are +the backspace key and the Enter key, which terminates the string. It +can optionally be limited to a fixed number of characters. :: curses.echo() # Enable echoing of characters # Get a 15-character string, with the cursor on the top line s = stdscr.getstr(0,0, 15) -The Python :mod:`curses.textpad` module supplies something better. With it, you -can turn a window into a text box that supports an Emacs-like set of -keybindings. Various methods of :class:`Textbox` class support editing with -input validation and gathering the edit results either with or without trailing -spaces. See the library documentation on :mod:`curses.textpad` for the -details. +The :mod:`curses.textpad` module supplies a text box that supports an +Emacs-like set of keybindings. Various methods of the +:class:`~curses.textpad.Textbox` class support editing with input +validation and gathering the edit results either with or without +trailing spaces. Here's an example:: + + import curses + from curses.textpad import Textbox, rectangle + + def main(stdscr): + stdscr.addstr(0, 0, "Enter IM message: (hit Ctrl-G to send)") + + editwin = curses.newwin(5,30, 2,1) + rectangle(stdscr, 1,0, 1+5+1, 1+30+1) + stdscr.refresh() + + box = Textbox(editwin) + + # Let the user edit until Ctrl-G is struck. + box.edit() + + # Get resulting contents + message = box.gather() + +See the library documentation on :mod:`curses.textpad` for more details. For More Information ==================== -This HOWTO didn't cover some advanced topics, such as screen-scraping or -capturing mouse events from an xterm instance. But the Python library page for -the curses modules is now pretty complete. You should browse it next. +This HOWTO doesn't cover some advanced topics, such as reading the +contents of the screen or capturing mouse events from an xterm +instance, but the Python library page for the :mod:`curses` module is now +reasonably complete. You should browse it next. -If you're in doubt about the detailed behavior of any of the ncurses entry -points, consult the manual pages for your curses implementation, whether it's -ncurses or a proprietary Unix vendor's. The manual pages will document any -quirks, and provide complete lists of all the functions, attributes, and -:const:`ACS_\*` characters available to you. +If you're in doubt about the detailed behavior of the curses +functions, consult the manual pages for your curses implementation, +whether it's ncurses or a proprietary Unix vendor's. The manual pages +will document any quirks, and provide complete lists of all the +functions, attributes, and :const:`ACS_\*` characters available to +you. -Because the curses API is so large, some functions aren't supported in the -Python interface, not because they're difficult to implement, but because no one -has needed them yet. Feel free to add them and then submit a patch. Also, we -don't yet have support for the menu library associated with -ncurses; feel free to add that. +Because the curses API is so large, some functions aren't supported in +the Python interface. Often this isn't because they're difficult to +implement, but because no one has needed them yet. Also, Python +doesn't yet support the menu library associated with ncurses. +Patches adding support for these would be welcome; see +`the Python Developer's Guide `_ to +learn more about submitting patches to Python. -If you write an interesting little program, feel free to contribute it as -another demo. We can always use more of them! - -The ncurses FAQ: http://invisible-island.net/ncurses/ncurses.faq.html - +* `Writing Programs with NCURSES `_: + a lengthy tutorial for C programmers. +* `The ncurses man page `_ +* `The ncurses FAQ `_ +* `"Use curses... don't swear" `_: + video of a PyCon 2013 talk on controlling terminals using curses or Urwid. +* `"Console Applications with Urwid" `_: + video of a PyCon CA 2012 talk demonstrating some applications written using + Urwid. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 10 02:55:46 2013 From: python-checkins at python.org (andrew.kuchling) Date: Fri, 10 May 2013 02:55:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE0ODc4OiBhZGQg?= =?utf-8?q?cross-reference_to_the_yield_statement=2E?= Message-ID: <3b6Cdt6F9hz7Lls@mail.python.org> http://hg.python.org/cpython/rev/7b8c0bf8fcb8 changeset: 83701:7b8c0bf8fcb8 branch: 2.7 parent: 83692:9b86fb6f5bc9 user: Andrew Kuchling date: Thu May 09 20:55:22 2013 -0400 summary: #14878: add cross-reference to the yield statement. (Backported from 3.x by Jan Duzinkiewicz.) files: Doc/reference/simple_stmts.rst | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -511,6 +511,9 @@ :meth:`close` method will be called, allowing any pending :keyword:`finally` clauses to execute. +For full details of :keyword:`yield` semantics, refer to the :ref:`yieldexpr` +section. + .. note:: In Python 2.2, the :keyword:`yield` statement was only allowed when the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 10 04:22:28 2013 From: python-checkins at python.org (ezio.melotti) Date: Fri, 10 May 2013 04:22:28 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE3ODQxOiByZW1v?= =?utf-8?q?ve_missing_codecs_aliases_from_the_documentation=2E__Patch_by_T?= =?utf-8?q?homas?= Message-ID: <3b6FYw5nrZzR2w@mail.python.org> http://hg.python.org/cpython/rev/ead47bc3a763 changeset: 83702:ead47bc3a763 branch: 3.3 parent: 83699:1fa70b797973 user: Ezio Melotti date: Fri May 10 05:21:35 2013 +0300 summary: #17841: remove missing codecs aliases from the documentation. Patch by Thomas Fenzl. files: Doc/library/codecs.rst | 66 +++++++++++++++--------------- Misc/ACKS | 1 + 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -1188,44 +1188,44 @@ The following codecs provide bytes-to-bytes mappings. -.. tabularcolumns:: |l|p{0.3\linewidth}|p{0.3\linewidth}| +.. tabularcolumns:: |l|L| -+--------------------+---------------------------+---------------------------+ -| Codec | Aliases | Purpose | -+====================+===========================+===========================+ -| base64_codec | base64, base-64 | Convert operand to MIME | -| | | base64 (the result always | -| | | includes a trailing | -| | | ``'\n'``) | -+--------------------+---------------------------+---------------------------+ -| bz2_codec | bz2 | Compress the operand | -| | | using bz2 | -+--------------------+---------------------------+---------------------------+ -| hex_codec | hex | Convert operand to | -| | | hexadecimal | -| | | representation, with two | -| | | digits per byte | -+--------------------+---------------------------+---------------------------+ -| quopri_codec | quopri, quoted-printable, | Convert operand to MIME | -| | quotedprintable | quoted printable | -+--------------------+---------------------------+---------------------------+ -| uu_codec | uu | Convert the operand using | -| | | uuencode | -+--------------------+---------------------------+---------------------------+ -| zlib_codec | zip, zlib | Compress the operand | -| | | using gzip | -+--------------------+---------------------------+---------------------------+ ++--------------------+---------------------------+ +| Codec | Purpose | ++====================+===========================+ +| base64_codec | Convert operand to MIME | +| | base64 (the result always | +| | includes a trailing | +| | ``'\n'``) | ++--------------------+---------------------------+ +| bz2_codec | Compress the operand | +| | using bz2 | ++--------------------+---------------------------+ +| hex_codec | Convert operand to | +| | hexadecimal | +| | representation, with two | +| | digits per byte | ++--------------------+---------------------------+ +| quopri_codec | Convert operand to MIME | +| | quoted printable | ++--------------------+---------------------------+ +| uu_codec | Convert the operand using | +| | uuencode | ++--------------------+---------------------------+ +| zlib_codec | Compress the operand | +| | using gzip | ++--------------------+---------------------------+ The following codecs provide string-to-string mappings. -.. tabularcolumns:: |l|p{0.3\linewidth}|p{0.3\linewidth}| +.. tabularcolumns:: |l|L| -+--------------------+---------------------------+---------------------------+ -| Codec | Aliases | Purpose | -+====================+===========================+===========================+ -| rot_13 | rot13 | Returns the Caesar-cypher | -| | | encryption of the operand | -+--------------------+---------------------------+---------------------------+ ++--------------------+---------------------------+ +| Codec | Purpose | ++====================+===========================+ +| rot_13 | Returns the Caesar-cypher | +| | encryption of the operand | ++--------------------+---------------------------+ .. versionadded:: 3.2 bytes-to-bytes and string-to-string codecs. diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -365,6 +365,7 @@ Troy J. Farrell Mark Favas Boris Feld +Thomas Fenzl Niels Ferguson Sebastian Fernandez Florian Festi -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 10 04:22:30 2013 From: python-checkins at python.org (ezio.melotti) Date: Fri, 10 May 2013 04:22:30 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzE3ODQxOiBtZXJnZSB3aXRoIDMuMy4=?= Message-ID: <3b6FYy1zcNzRMk@mail.python.org> http://hg.python.org/cpython/rev/eafff38a56cc changeset: 83703:eafff38a56cc parent: 83700:70f530161b9b parent: 83702:ead47bc3a763 user: Ezio Melotti date: Fri May 10 05:22:14 2013 +0300 summary: #17841: merge with 3.3. files: Doc/library/codecs.rst | 66 +++++++++++++++--------------- 1 files changed, 33 insertions(+), 33 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -1188,44 +1188,44 @@ The following codecs provide bytes-to-bytes mappings. -.. tabularcolumns:: |l|p{0.3\linewidth}|p{0.3\linewidth}| +.. tabularcolumns:: |l|L| -+--------------------+---------------------------+---------------------------+ -| Codec | Aliases | Purpose | -+====================+===========================+===========================+ -| base64_codec | base64, base-64 | Convert operand to MIME | -| | | base64 (the result always | -| | | includes a trailing | -| | | ``'\n'``) | -+--------------------+---------------------------+---------------------------+ -| bz2_codec | bz2 | Compress the operand | -| | | using bz2 | -+--------------------+---------------------------+---------------------------+ -| hex_codec | hex | Convert operand to | -| | | hexadecimal | -| | | representation, with two | -| | | digits per byte | -+--------------------+---------------------------+---------------------------+ -| quopri_codec | quopri, quoted-printable, | Convert operand to MIME | -| | quotedprintable | quoted printable | -+--------------------+---------------------------+---------------------------+ -| uu_codec | uu | Convert the operand using | -| | | uuencode | -+--------------------+---------------------------+---------------------------+ -| zlib_codec | zip, zlib | Compress the operand | -| | | using gzip | -+--------------------+---------------------------+---------------------------+ ++--------------------+---------------------------+ +| Codec | Purpose | ++====================+===========================+ +| base64_codec | Convert operand to MIME | +| | base64 (the result always | +| | includes a trailing | +| | ``'\n'``) | ++--------------------+---------------------------+ +| bz2_codec | Compress the operand | +| | using bz2 | ++--------------------+---------------------------+ +| hex_codec | Convert operand to | +| | hexadecimal | +| | representation, with two | +| | digits per byte | ++--------------------+---------------------------+ +| quopri_codec | Convert operand to MIME | +| | quoted printable | ++--------------------+---------------------------+ +| uu_codec | Convert the operand using | +| | uuencode | ++--------------------+---------------------------+ +| zlib_codec | Compress the operand | +| | using gzip | ++--------------------+---------------------------+ The following codecs provide string-to-string mappings. -.. tabularcolumns:: |l|p{0.3\linewidth}|p{0.3\linewidth}| +.. tabularcolumns:: |l|L| -+--------------------+---------------------------+---------------------------+ -| Codec | Aliases | Purpose | -+====================+===========================+===========================+ -| rot_13 | rot13 | Returns the Caesar-cypher | -| | | encryption of the operand | -+--------------------+---------------------------+---------------------------+ ++--------------------+---------------------------+ +| Codec | Purpose | ++====================+===========================+ +| rot_13 | Returns the Caesar-cypher | +| | encryption of the operand | ++--------------------+---------------------------+ .. versionadded:: 3.2 bytes-to-bytes and string-to-string codecs. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri May 10 06:10:43 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 10 May 2013 06:10:43 +0200 Subject: [Python-checkins] Daily reference leaks (70f530161b9b): sum=0 Message-ID: results for 70f530161b9b on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogDWQvM9', '-x'] From python-checkins at python.org Fri May 10 14:46:28 2013 From: python-checkins at python.org (eli.bendersky) Date: Fri, 10 May 2013 14:46:28 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Updated_PEP_435_with_some_in-?= =?utf-8?q?line_motivations=2C_and_some_general_cleanup=2E?= Message-ID: <3b6WPw5c8SzRQP@mail.python.org> http://hg.python.org/peps/rev/bd3de993d6e2 changeset: 4881:bd3de993d6e2 user: Eli Bendersky date: Fri May 10 05:45:20 2013 -0700 summary: Updated PEP 435 with some in-line motivations, and some general cleanup. Marked PEP 354 as superseded by PEP 435. files: pep-0354.txt | 5 ++++- pep-0435.txt | 31 +++++++++++++++++++------------ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/pep-0354.txt b/pep-0354.txt --- a/pep-0354.txt +++ b/pep-0354.txt @@ -3,12 +3,13 @@ Version: $Revision$ Last-Modified: $Date$ Author: Ben Finney -Status: Rejected +Status: Superseded Type: Standards Track Content-Type: text/x-rst Created: 20-Dec-2005 Python-Version: 2.6 Post-History: 20-Dec-2005 +Superseded-By: 435 Rejection Notice @@ -21,6 +22,8 @@ those who need enumerations, there are cookbook recipes and PyPI packages that meet these needs. +*Note: this PEP was superseded by PEP 435, which has been accepted in +May 2013.* Abstract ======== diff --git a/pep-0435.txt b/pep-0435.txt --- a/pep-0435.txt +++ b/pep-0435.txt @@ -54,6 +54,8 @@ of not allowing to subclass enums [6]_, unless they define no enumeration members [7]_. +The PEP was accepted by Guido on May 10th, 2013 [1]_. + Motivation ========== @@ -216,7 +218,7 @@ >>> for name, member in Shape.__members__.items(): ... name, member - ... + ... ('square', ) ('diamond', ) ('circle', ) @@ -579,29 +581,34 @@ References ========== -.. [1] Placeholder for pronouncement +.. [1] http://mail.python.org/pipermail/python-dev/2013-May/126112.html .. [2] http://www.python.org/dev/peps/pep-0354/ .. [3] http://mail.python.org/pipermail/python-ideas/2013-January/019003.html .. [4] http://mail.python.org/pipermail/python-ideas/2013-February/019373.html -.. [5] http://mail.python.org/pipermail/python-dev/2013-April/125687.html -.. [6] http://mail.python.org/pipermail/python-dev/2013-April/125716.html -.. [7] http://mail.python.org/pipermail/python-dev/2013-May/125859.html +.. [5] To make enums behave similarly to Python classes like bool, and + behave in a more intuitive way. It would be surprising if the type of + ``Color.red`` would not be ``Color``. (Discussion in + http://mail.python.org/pipermail/python-dev/2013-April/125687.html) +.. [6] Subclassing enums and adding new members creates an unresolvable + situation; on one hand ``MoreColor.red`` and ``Color.red`` should + not be the same object, and on the other ``isinstance`` checks become + confusing if they are not. The discussion also links to Stack Overflow + discussions that make additional arguments. + (http://mail.python.org/pipermail/python-dev/2013-April/125716.html) +.. [7] It may be useful to have a class defining some behavior (methods, with + no actual enumeration members) mixed into an enum, and this would not + create the problem discussed in [6]_. (Discussion in + http://mail.python.org/pipermail/python-dev/2013-May/125859.html) .. [8] http://pythonhosted.org/flufl.enum/ .. [9] http://docs.python.org/3/howto/descriptor.html + Copyright ========= This document has been placed in the public domain. -Todo -==== - -* Mark PEP 354 "superseded by" this one, if accepted -* In docs: describe the detailed extension API (i.e. __new__). Also describe - the problem with pickling of functional API in more detail. - .. Local Variables: mode: indented-text -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri May 10 17:36:29 2013 From: python-checkins at python.org (barry.warsaw) Date: Fri, 10 May 2013 17:36:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_I_was_confused?= =?utf-8?q?_before=2E__It=27s_correct_to_not_call_=2Eclose=28=29_inside_th?= =?utf-8?q?e_with?= Message-ID: <3b6bB52RZwzRWZ@mail.python.org> http://hg.python.org/cpython/rev/3b935ac07f65 changeset: 83704:3b935ac07f65 branch: 3.3 parent: 83702:ead47bc3a763 user: Barry Warsaw date: Fri May 10 11:35:38 2013 -0400 summary: I was confused before. It's correct to not call .close() inside the with statement, but add a comment that clarifies the purpose of the code. files: Doc/library/contextlib.rst | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst --- a/Doc/library/contextlib.rst +++ b/Doc/library/contextlib.rst @@ -259,11 +259,12 @@ with ExitStack() as stack: files = [stack.enter_context(open(fname)) for fname in filenames] - close_files = stack.pop_all().close() + # Hold onto the close method, but don't call it yet. + close_files = stack.pop_all().close # If opening any file fails, all previously opened files will be # closed automatically. If all files are opened successfully, # they will remain open even after the with statement ends. - # close_files() can then be invoked explicitly to close them all + # close_files() can then be invoked explicitly to close them all. .. method:: close() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 10 17:36:30 2013 From: python-checkins at python.org (barry.warsaw) Date: Fri, 10 May 2013 17:36:30 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy4z?= Message-ID: <3b6bB64hFczRFR@mail.python.org> http://hg.python.org/cpython/rev/1bed56c3d010 changeset: 83705:1bed56c3d010 parent: 83703:eafff38a56cc parent: 83704:3b935ac07f65 user: Barry Warsaw date: Fri May 10 11:36:23 2013 -0400 summary: Merge 3.3 files: Doc/library/contextlib.rst | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst --- a/Doc/library/contextlib.rst +++ b/Doc/library/contextlib.rst @@ -279,11 +279,12 @@ with ExitStack() as stack: files = [stack.enter_context(open(fname)) for fname in filenames] - close_files = stack.pop_all().close() + # Hold onto the close method, but don't call it yet. + close_files = stack.pop_all().close # If opening any file fails, all previously opened files will be # closed automatically. If all files are opened successfully, # they will remain open even after the with statement ends. - # close_files() can then be invoked explicitly to close them all + # close_files() can then be invoked explicitly to close them all. .. method:: close() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 10 17:48:04 2013 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 10 May 2013 17:48:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_=2317927=3A_Keep_frame_fro?= =?utf-8?q?m_referencing_cell-ified_arguments=2E?= Message-ID: <3b6bRS3x43zSRl@mail.python.org> http://hg.python.org/cpython/rev/d331e14cae42 changeset: 83706:d331e14cae42 user: Guido van Rossum date: Fri May 10 08:47:42 2013 -0700 summary: #17927: Keep frame from referencing cell-ified arguments. files: Lib/test/test_scope.py | 41 +++++++++++++++++++++++++++++- Misc/NEWS | 3 ++ Objects/typeobject.c | 4 ++ Python/ceval.c | 16 ++++++++-- 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_scope.py b/Lib/test/test_scope.py --- a/Lib/test/test_scope.py +++ b/Lib/test/test_scope.py @@ -1,3 +1,4 @@ +import gc import unittest from test.support import check_syntax_error, cpython_only, run_unittest @@ -713,7 +714,6 @@ def b(): global a - def testClassNamespaceOverridesClosure(self): # See #17853. x = 42 @@ -727,6 +727,45 @@ self.assertFalse(hasattr(X, "x")) self.assertEqual(x, 42) + @cpython_only + def testCellLeak(self): + # Issue 17927. + # + # The issue was that if self was part of a cycle involving the + # frame of a method call, *and* the method contained a nested + # function referencing self, thereby forcing 'self' into a + # cell, setting self to None would not be enough to break the + # frame -- the frame had another reference to the instance, + # which could not be cleared by the code running in the frame + # (though it will be cleared when the frame is collected). + # Without the lambda, setting self to None is enough to break + # the cycle. + logs = [] + class Canary: + def __del__(self): + logs.append('canary') + class Base: + def dig(self): + pass + class Tester(Base): + def __init__(self): + self.canary = Canary() + def dig(self): + if 0: + lambda: self + try: + 1/0 + except Exception as exc: + self.exc = exc + super().dig() + self = None # Break the cycle + tester = Tester() + tester.dig() + del tester + logs.append('collect') + gc.collect() + self.assertEqual(logs, ['canary', 'collect']) + def test_main(): run_unittest(ScopeTests) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #17927: Frame objects kept arguments alive if they had been + copied into a cell, even if the cell was cleared. + - Issue #17807: Generators can now be finalized even when they are part of a reference cycle. diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6510,6 +6510,10 @@ return -1; } obj = f->f_localsplus[0]; + if (obj != NULL && PyCell_Check(obj)) { + /* It might be a cell. See cell var initialization in ceval.c. */ + obj = PyCell_GET(obj); + } if (obj == NULL) { PyErr_SetString(PyExc_RuntimeError, "super(): arg[0] deleted"); diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3519,12 +3519,20 @@ int arg; /* Possibly account for the cell variable being an argument. */ if (co->co_cell2arg != NULL && - (arg = co->co_cell2arg[i]) != CO_CELL_NOT_AN_ARG) + (arg = co->co_cell2arg[i]) != CO_CELL_NOT_AN_ARG) { c = PyCell_New(GETLOCAL(arg)); - else + if (c == NULL) + goto fail; + /* Reference the cell from the argument slot, for super(). + See typeobject.c. */ + Py_INCREF(c); + SETLOCAL(arg, c); + } + else { c = PyCell_New(NULL); - if (c == NULL) - goto fail; + if (c == NULL) + goto fail; + } SETLOCAL(co->co_nlocals + i, c); } for (i = 0; i < PyTuple_GET_SIZE(co->co_freevars); ++i) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 10 18:28:32 2013 From: python-checkins at python.org (barry.warsaw) Date: Fri, 10 May 2013 18:28:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Guido_explicitly_rejects_PEP_?= =?utf-8?q?3142=2E?= Message-ID: <3b6cL804DpzSQw@mail.python.org> http://hg.python.org/peps/rev/f1428462ba69 changeset: 4882:f1428462ba69 parent: 4880:856453fa2637 user: Barry Warsaw date: Fri May 10 12:27:55 2013 -0400 summary: Guido explicitly rejects PEP 3142. files: pep-3142.txt | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/pep-3142.txt b/pep-3142.txt --- a/pep-3142.txt +++ b/pep-3142.txt @@ -3,12 +3,13 @@ Version: $Revision$ Last-Modified: $Date$ Author: Gerald Britton -Status: Draft +Status: Rejected Type: Standards Track Content-Type: text/plain Created: 12-Jan-2009 Python-Version: 3.0 Post-History: +Resolution: http://mail.python.org/pipermail/python-dev/2013-May/126136.html Abstract -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri May 10 18:28:33 2013 From: python-checkins at python.org (barry.warsaw) Date: Fri, 10 May 2013 18:28:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps_=28merge_default_-=3E_default=29?= =?utf-8?q?=3A_trunk_merge?= Message-ID: <3b6cL927WvzRFn@mail.python.org> http://hg.python.org/peps/rev/921df87329b5 changeset: 4883:921df87329b5 parent: 4882:f1428462ba69 parent: 4881:bd3de993d6e2 user: Barry Warsaw date: Fri May 10 12:28:27 2013 -0400 summary: trunk merge files: pep-0354.txt | 5 ++++- pep-0435.txt | 31 +++++++++++++++++++------------ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/pep-0354.txt b/pep-0354.txt --- a/pep-0354.txt +++ b/pep-0354.txt @@ -3,12 +3,13 @@ Version: $Revision$ Last-Modified: $Date$ Author: Ben Finney -Status: Rejected +Status: Superseded Type: Standards Track Content-Type: text/x-rst Created: 20-Dec-2005 Python-Version: 2.6 Post-History: 20-Dec-2005 +Superseded-By: 435 Rejection Notice @@ -21,6 +22,8 @@ those who need enumerations, there are cookbook recipes and PyPI packages that meet these needs. +*Note: this PEP was superseded by PEP 435, which has been accepted in +May 2013.* Abstract ======== diff --git a/pep-0435.txt b/pep-0435.txt --- a/pep-0435.txt +++ b/pep-0435.txt @@ -54,6 +54,8 @@ of not allowing to subclass enums [6]_, unless they define no enumeration members [7]_. +The PEP was accepted by Guido on May 10th, 2013 [1]_. + Motivation ========== @@ -216,7 +218,7 @@ >>> for name, member in Shape.__members__.items(): ... name, member - ... + ... ('square', ) ('diamond', ) ('circle', ) @@ -579,29 +581,34 @@ References ========== -.. [1] Placeholder for pronouncement +.. [1] http://mail.python.org/pipermail/python-dev/2013-May/126112.html .. [2] http://www.python.org/dev/peps/pep-0354/ .. [3] http://mail.python.org/pipermail/python-ideas/2013-January/019003.html .. [4] http://mail.python.org/pipermail/python-ideas/2013-February/019373.html -.. [5] http://mail.python.org/pipermail/python-dev/2013-April/125687.html -.. [6] http://mail.python.org/pipermail/python-dev/2013-April/125716.html -.. [7] http://mail.python.org/pipermail/python-dev/2013-May/125859.html +.. [5] To make enums behave similarly to Python classes like bool, and + behave in a more intuitive way. It would be surprising if the type of + ``Color.red`` would not be ``Color``. (Discussion in + http://mail.python.org/pipermail/python-dev/2013-April/125687.html) +.. [6] Subclassing enums and adding new members creates an unresolvable + situation; on one hand ``MoreColor.red`` and ``Color.red`` should + not be the same object, and on the other ``isinstance`` checks become + confusing if they are not. The discussion also links to Stack Overflow + discussions that make additional arguments. + (http://mail.python.org/pipermail/python-dev/2013-April/125716.html) +.. [7] It may be useful to have a class defining some behavior (methods, with + no actual enumeration members) mixed into an enum, and this would not + create the problem discussed in [6]_. (Discussion in + http://mail.python.org/pipermail/python-dev/2013-May/125859.html) .. [8] http://pythonhosted.org/flufl.enum/ .. [9] http://docs.python.org/3/howto/descriptor.html + Copyright ========= This document has been placed in the public domain. -Todo -==== - -* Mark PEP 354 "superseded by" this one, if accepted -* In docs: describe the detailed extension API (i.e. __new__). Also describe - the problem with pickling of functional API in more detail. - .. Local Variables: mode: indented-text -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri May 10 18:57:16 2013 From: python-checkins at python.org (ezio.melotti) Date: Fri, 10 May 2013 18:57:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE3OTQ5OiBmaXgg?= =?utf-8?q?merge_glitch_in_itemgetter_signature=2E__Patch_by_Martijn_Piete?= =?utf-8?b?cnMu?= Message-ID: <3b6czJ6wJCzRF0@mail.python.org> http://hg.python.org/cpython/rev/9c93a631e95a changeset: 83707:9c93a631e95a branch: 2.7 parent: 83701:7b8c0bf8fcb8 user: Ezio Melotti date: Fri May 10 19:57:04 2013 +0300 summary: #17949: fix merge glitch in itemgetter signature. Patch by Martijn Pieters. files: Doc/library/operator.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/operator.rst b/Doc/library/operator.rst --- a/Doc/library/operator.rst +++ b/Doc/library/operator.rst @@ -523,9 +523,6 @@ return obj -.. function:: itemgetter(item) - itemgetter(*items) - .. versionadded:: 2.4 .. versionchanged:: 2.5 @@ -535,6 +532,9 @@ Added support for dotted attributes. +.. function:: itemgetter(item) + itemgetter(*items) + Return a callable object that fetches *item* from its operand using the operand's :meth:`__getitem__` method. If multiple items are specified, returns a tuple of lookup values. For example: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 11 01:09:56 2013 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 11 May 2013 01:09:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Move_wrap=5Ffuture=28=29_out_?= =?utf-8?q?of_EventLoop=2E__Document_local=5Faddr=2E?= Message-ID: <3b6nFJ5MdZzPmd@mail.python.org> http://hg.python.org/peps/rev/9d1025fa57a2 changeset: 4884:9d1025fa57a2 user: Guido van Rossum date: Fri May 10 16:09:48 2013 -0700 summary: Move wrap_future() out of EventLoop. Document local_addr. files: pep-3156.txt | 22 +++++++++++++++++----- 1 files changed, 17 insertions(+), 5 deletions(-) diff --git a/pep-3156.txt b/pep-3156.txt --- a/pep-3156.txt +++ b/pep-3156.txt @@ -406,10 +406,6 @@ signal-safe; if you want to handle signals, use ``add_signal_handler()`` described below. -- ``wrap_future(future)``. This takes a PEP 3148 Future (i.e., an - instance of ``concurrent.futures.Future``) and returns a Future - compatible with the event loop (i.e., a ``tulip.Future`` instance). - - ``run_in_executor(executor, callback, *args)``. Arrange to call ``callback(*args)`` in an executor (see PEP 3148). Returns a Future whose result on success is the return value of that call. This is @@ -424,6 +420,9 @@ ``Executor`` instance or ``None``, in order to reset the default executor. +See also the ``wrap_future()`` function described in the section about +Futures. + Internet name lookups ''''''''''''''''''''' @@ -518,6 +517,12 @@ arguments. If this is given, host and port must be omitted; otherwise, host and port are required. + - ``local_addr``: If given, a ``(host, port)`` tuple used to bind + the socket to locally. This is rarely needed but on multi-homed + servers you occasionally need to force a connection to come from a + specific address. This is how you would do that. The host and + port are looked up using ``getaddrinfo()``. + - ``start_serving(protocol_factory, host, port, **kwds)``. Enters a serving loop that accepts connections. This is a Task that completes once the serving loop is set up to serve. The return @@ -892,12 +897,19 @@ ``concurrent.futures.Future``, e.g. by adding an ``__iter__()`` method to the latter that works with ``yield from``. To prevent accidentally blocking the event loop by calling e.g. ``result()`` on a Future -that's not don yet, the blocking operation may detect that an event +that's not done yet, the blocking operation may detect that an event loop is active in the current thread and raise an exception instead. However the current PEP strives to have no dependencies beyond Python 3.3, so changes to ``concurrent.futures.Future`` are off the table for now. +There is one public function related to Futures. It is: + +- ``wrap_future(future)``. This takes a PEP 3148 Future (i.e., an + instance of ``concurrent.futures.Future``) and returns a Future + compatible with the event loop (i.e., a ``tulip.Future`` instance). + + Transports ---------- -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat May 11 04:57:59 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 11 May 2013 04:57:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2316694=3A__Add_sou?= =?utf-8?q?rce_code_link_for_operator=2Epy?= Message-ID: <3b6tJR2SnMzRGm@mail.python.org> http://hg.python.org/cpython/rev/4b3238923b01 changeset: 83708:4b3238923b01 parent: 83706:d331e14cae42 user: Raymond Hettinger date: Fri May 10 19:57:44 2013 -0700 summary: Issue #16694: Add source code link for operator.py files: Doc/library/operator.rst | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Doc/library/operator.rst b/Doc/library/operator.rst --- a/Doc/library/operator.rst +++ b/Doc/library/operator.rst @@ -11,6 +11,9 @@ import operator from operator import itemgetter, iadd +**Source code:** :source:`Lib/operator.py` + +-------------- The :mod:`operator` module exports a set of efficient functions corresponding to the intrinsic operators of Python. For example, ``operator.add(x, y)`` is -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat May 11 06:05:14 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 11 May 2013 06:05:14 +0200 Subject: [Python-checkins] Daily reference leaks (d331e14cae42): sum=0 Message-ID: results for d331e14cae42 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogz1lAk6', '-x'] From python-checkins at python.org Sat May 11 15:59:52 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 11 May 2013 15:59:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3MjM3?= =?utf-8?q?=3A_Fix_crash_in_the_ASCII_decoder_on_m68k=2E?= Message-ID: <3b79081PgwzSsc@mail.python.org> http://hg.python.org/cpython/rev/0f8022ac88ad changeset: 83709:0f8022ac88ad branch: 3.3 parent: 83704:3b935ac07f65 user: Antoine Pitrou date: Sat May 11 15:58:34 2013 +0200 summary: Issue #17237: Fix crash in the ASCII decoder on m68k. files: Misc/NEWS | 2 ++ Objects/unicodeobject.c | 9 +++++++++ 2 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,8 @@ Core and Builtins ----------------- +- Issue #17237: Fix crash in the ASCII decoder on m68k. + - Issue #17408: Avoid using an obsolete instance of the copyreg module when the interpreter is shutdown and then started again. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -4661,6 +4661,14 @@ const char *p = start; const char *aligned_end = (const char *) _Py_ALIGN_DOWN(end, SIZEOF_LONG); + /* + * Issue #17237: m68k is a bit different from most architectures in + * that objects do not use "natural alignment" - for example, int and + * long are only aligned at 2-byte boundaries. Therefore the assert() + * won't work; also, tests have shown that skipping the "optimised + * version" will even speed up m68k. + */ +#if !defined(__m68k__) #if SIZEOF_LONG <= SIZEOF_VOID_P assert(_Py_IS_ALIGNED(dest, SIZEOF_LONG)); if (_Py_IS_ALIGNED(p, SIZEOF_LONG)) { @@ -4686,6 +4694,7 @@ return p - start; } #endif +#endif while (p < end) { /* Fast path, see in STRINGLIB(utf8_decode) in stringlib/codecs.h for an explanation. */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 11 15:59:53 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 11 May 2013 15:59:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317237=3A_Fix_crash_in_the_ASCII_decoder_on_m68k?= =?utf-8?q?=2E?= Message-ID: <3b79093xbMzSsc@mail.python.org> http://hg.python.org/cpython/rev/201ae2d02328 changeset: 83710:201ae2d02328 parent: 83708:4b3238923b01 parent: 83709:0f8022ac88ad user: Antoine Pitrou date: Sat May 11 15:59:37 2013 +0200 summary: Issue #17237: Fix crash in the ASCII decoder on m68k. files: Misc/NEWS | 2 ++ Objects/unicodeobject.c | 9 +++++++++ 2 files changed, 11 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #17237: Fix crash in the ASCII decoder on m68k. + - Issue #17927: Frame objects kept arguments alive if they had been copied into a cell, even if the cell was cleared. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -4647,6 +4647,14 @@ const char *p = start; const char *aligned_end = (const char *) _Py_ALIGN_DOWN(end, SIZEOF_LONG); + /* + * Issue #17237: m68k is a bit different from most architectures in + * that objects do not use "natural alignment" - for example, int and + * long are only aligned at 2-byte boundaries. Therefore the assert() + * won't work; also, tests have shown that skipping the "optimised + * version" will even speed up m68k. + */ +#if !defined(__m68k__) #if SIZEOF_LONG <= SIZEOF_VOID_P assert(_Py_IS_ALIGNED(dest, SIZEOF_LONG)); if (_Py_IS_ALIGNED(p, SIZEOF_LONG)) { @@ -4672,6 +4680,7 @@ return p - start; } #endif +#endif while (p < end) { /* Fast path, see in STRINGLIB(utf8_decode) in stringlib/codecs.h for an explanation. */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 11 16:53:31 2013 From: python-checkins at python.org (brett.cannon) Date: Sat, 11 May 2013 16:53:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_Record_giving_Ethan_Furma?= =?utf-8?q?n_commit_privileges=2E?= Message-ID: <3b7BB30wQ6zSrM@mail.python.org> http://hg.python.org/devguide/rev/0a4785786b8f changeset: 619:0a4785786b8f user: Brett Cannon date: Sat May 11 10:53:26 2013 -0400 summary: Record giving Ethan Furman commit privileges. files: developers.rst | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/developers.rst b/developers.rst --- a/developers.rst +++ b/developers.rst @@ -24,6 +24,9 @@ Permissions History ------------------- +- Ethan Furman was given prush privileges on May 11 2013 by BAC, for PEP 435 + work, on the recommendation of Eli Bendersky. + - Roger Serwy was given push privileges on Mar 21 2013 by GFB, for IDLE contributions, on recommendation by Ned Deily. -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat May 11 19:20:13 2013 From: python-checkins at python.org (eli.bendersky) Date: Sat, 11 May 2013 19:20:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Some_clarifications_about_pic?= =?utf-8?q?kling_of_Enums?= Message-ID: <3b7FRK38lLzRgr@mail.python.org> http://hg.python.org/peps/rev/85a0892a4b5c changeset: 4885:85a0892a4b5c user: Eli Bendersky date: Sat May 11 10:19:02 2013 -0700 summary: Some clarifications about pickling of Enums files: pep-0435.txt | 37 +++++++++++++++++++------------------ 1 files changed, 19 insertions(+), 18 deletions(-) diff --git a/pep-0435.txt b/pep-0435.txt --- a/pep-0435.txt +++ b/pep-0435.txt @@ -415,6 +415,21 @@ and don't specify another data type such as ``int`` or ``str``. +Pickling +-------- + +Enumerations be pickled and unpickled:: + + >>> from enum.tests.fruit import Fruit + >>> from pickle import dumps, loads + >>> Fruit.tomato is loads(dumps(Fruit.tomato)) + True + +The usual restrictions for pickling apply: picklable enums must be defined in +the top level of a module, since unpickling requires them to be imporatable +from that module. + + Functional API -------------- @@ -431,9 +446,10 @@ [, , , ] The semantics of this API resemble ``namedtuple``. The first argument -of the call to ``Enum`` is the name of the enumeration. To support -pickling of these enums, the module name can be specified using the -``module`` keyword-only argument. E.g.:: +of the call to ``Enum`` is the name of the enumeration. Pickling enums +created with the functional API will work on CPython and PyPy, but for +IronPython and Jython you may need to specify the module name explicitly +as follows:: >>> Animals = Enum('Animals', 'ant bee cat dog', module=__name__) @@ -452,21 +468,6 @@ ... dog = 4 -Pickling --------- - -Enumerations be pickled and unpickled:: - - >>> from enum.tests.fruit import Fruit - >>> from pickle import dumps, loads - >>> Fruit.tomato is loads(dumps(Fruit.tomato)) - True - -The usual restrictions for pickling apply: picklable enums must be defined in -the top level of a module, to be importable from that module when unpickling -occurs. - - Proposed variations =================== -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat May 11 20:03:14 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 11 May 2013 20:03:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_-Wformat_is_ne?= =?utf-8?q?eded_by_gcc_4=2E8_=28closes_=2317547=29?= Message-ID: <3b7GNy6DT4zRNj@mail.python.org> http://hg.python.org/cpython/rev/9d50af4c482f changeset: 83711:9d50af4c482f branch: 2.7 parent: 83707:9c93a631e95a user: Benjamin Peterson date: Sat May 11 13:00:05 2013 -0500 summary: -Wformat is needed by gcc 4.8 (closes #17547) files: Misc/NEWS | 3 +++ configure | 2 +- configure.ac | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -95,6 +95,9 @@ Build ----- +- Issue #17547: In configure, explicitly pass -Wformat for the benefit for GCC + 4.8. + - Issue #17682: Add the _io module to Modules/Setup.dist (commented out). - Issue #17086: Search the include and library directories provided by the diff --git a/configure b/configure --- a/configure +++ b/configure @@ -6253,7 +6253,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gcc supports ParseTuple __format__" >&5 $as_echo_n "checking whether gcc supports ParseTuple __format__... " >&6; } save_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -Werror" + CFLAGS="$CFLAGS -Werror -Wformat" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -1326,7 +1326,7 @@ then AC_MSG_CHECKING(whether gcc supports ParseTuple __format__) save_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -Werror" + CFLAGS="$CFLAGS -Werror -Wformat" AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[void f(char*,...)__attribute((format(PyArg_ParseTuple, 1, 2)));]], [[]]) ],[ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 11 20:03:16 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 11 May 2013 20:03:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_-Wformat_is_ne?= =?utf-8?q?eded_by_gcc_4=2E8_=28closes_=2317547=29?= Message-ID: <3b7GP021GJzS1X@mail.python.org> http://hg.python.org/cpython/rev/94a7475d3a5f changeset: 83712:94a7475d3a5f branch: 3.3 parent: 83709:0f8022ac88ad user: Benjamin Peterson date: Sat May 11 13:00:05 2013 -0500 summary: -Wformat is needed by gcc 4.8 (closes #17547) files: Misc/NEWS | 6 ++++++ configure | 2 +- configure.ac | 2 +- pyconfig.h.in | 3 --- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -223,6 +223,12 @@ - Issue #6696: add documentation for the Profile objects, and improve profile/cProfile docs. Patch by Tom Pinckney. +Build +----- + +- Issue #17547: In configure, explicitly pass -Wformat for the benefit for GCC + 4.8. + What's New in Python 3.3.1? =========================== diff --git a/configure b/configure --- a/configure +++ b/configure @@ -6525,7 +6525,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gcc supports ParseTuple __format__" >&5 $as_echo_n "checking whether gcc supports ParseTuple __format__... " >&6; } save_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -Werror" + CFLAGS="$CFLAGS -Werror -Wformat" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -1331,7 +1331,7 @@ then AC_MSG_CHECKING(whether gcc supports ParseTuple __format__) save_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -Werror" + CFLAGS="$CFLAGS -Werror -Wformat" AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[void f(char*,...)__attribute((format(PyArg_ParseTuple, 1, 2)));]], [[]]) ],[ diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1187,9 +1187,6 @@ /* Define if setpgrp() must be called as setpgrp(0, 0). */ #undef SETPGRP_HAVE_ARG -/* Define this to be extension of shared libraries (including the dot!). */ -#undef SHLIB_EXT - /* Define if i>>j for signed int i does not extend the sign bit when i < 0 */ #undef SIGNED_RIGHT_SHIFT_ZERO_FILLS -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 11 20:03:17 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 11 May 2013 20:03:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4zICgjMTc1NDcp?= Message-ID: <3b7GP15Hq0z7Ljg@mail.python.org> http://hg.python.org/cpython/rev/f12e3ce66ae6 changeset: 83713:f12e3ce66ae6 parent: 83710:201ae2d02328 parent: 83712:94a7475d3a5f user: Benjamin Peterson date: Sat May 11 13:02:59 2013 -0500 summary: merge 3.3 (#17547) files: Misc/NEWS | 6 ++++++ configure | 2 +- configure.ac | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -300,6 +300,12 @@ - Issue #14735: Update IDLE docs to omit "Control-z on Windows". +Build +----- + +- Issue #17547: In configure, explicitly pass -Wformat for the benefit for GCC + 4.8. + What's New in Python 3.3.1 release candidate 1? =============================================== diff --git a/configure b/configure --- a/configure +++ b/configure @@ -6529,7 +6529,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gcc supports ParseTuple __format__" >&5 $as_echo_n "checking whether gcc supports ParseTuple __format__... " >&6; } save_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -Werror" + CFLAGS="$CFLAGS -Werror -Wformat" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -1333,7 +1333,7 @@ then AC_MSG_CHECKING(whether gcc supports ParseTuple __format__) save_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -Werror" + CFLAGS="$CFLAGS -Werror -Wformat" AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[void f(char*,...)__attribute((format(PyArg_ParseTuple, 1, 2)));]], [[]]) ],[ -- Repository URL: http://hg.python.org/cpython From root at python.org Sat May 11 20:05:22 2013 From: root at python.org (Cron Daemon) Date: Sat, 11 May 2013 20:05:22 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: abort: error: Connection timed out From root at python.org Sat May 11 20:10:23 2013 From: root at python.org (Cron Daemon) Date: Sat, 11 May 2013 20:10:23 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: abort: error: Connection timed out From root at python.org Sat May 11 20:15:22 2013 From: root at python.org (Cron Daemon) Date: Sat, 11 May 2013 20:15:22 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: abort: error: Connection timed out From root at python.org Sat May 11 20:35:31 2013 From: root at python.org (Cron Daemon) Date: Sat, 11 May 2013 20:35:31 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: abort: error: From python-checkins at python.org Sat May 11 20:48:00 2013 From: python-checkins at python.org (brett.cannon) Date: Sat, 11 May 2013 20:48:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Touch_up_grammar_for_dict?= =?utf-8?q?=2Eupdate=28=29_docstring=2E?= Message-ID: <3b7HNc3msjzRgr@mail.python.org> http://hg.python.org/cpython/rev/61214ebd347d changeset: 83714:61214ebd347d parent: 83710:201ae2d02328 user: Brett Cannon date: Sat May 11 14:46:48 2013 -0400 summary: Touch up grammar for dict.update() docstring. files: Objects/dictobject.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2473,10 +2473,10 @@ 2-tuple; but raise KeyError if D is empty."); PyDoc_STRVAR(update__doc__, -"D.update([E, ]**F) -> None. Update D from dict/iterable E and F.\n" -"If E present and has a .keys() method, does: for k in E: D[k] = E[k]\n\ -If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v\n\ -In either case, this is followed by: for k in F: D[k] = F[k]"); +"D.update([E, ]**F) -> None. Update D from dict/iterable E and F.\n\ +If E is present and has a .keys() method, then does: for k in E: D[k] = E[k]\n\ +If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v\n\ +In either case, this is followed by: for k in F: D[k] = F[k]"); PyDoc_STRVAR(fromkeys__doc__, "dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.\n\ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 11 20:48:01 2013 From: python-checkins at python.org (brett.cannon) Date: Sat, 11 May 2013 20:48:01 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3b7HNd6MPqzRgr@mail.python.org> http://hg.python.org/cpython/rev/0dd04c39fb89 changeset: 83715:0dd04c39fb89 parent: 83714:61214ebd347d parent: 83713:f12e3ce66ae6 user: Brett Cannon date: Sat May 11 14:47:12 2013 -0400 summary: merge files: Misc/NEWS | 6 ++++++ configure | 2 +- configure.ac | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -300,6 +300,12 @@ - Issue #14735: Update IDLE docs to omit "Control-z on Windows". +Build +----- + +- Issue #17547: In configure, explicitly pass -Wformat for the benefit for GCC + 4.8. + What's New in Python 3.3.1 release candidate 1? =============================================== diff --git a/configure b/configure --- a/configure +++ b/configure @@ -6529,7 +6529,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gcc supports ParseTuple __format__" >&5 $as_echo_n "checking whether gcc supports ParseTuple __format__... " >&6; } save_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -Werror" + CFLAGS="$CFLAGS -Werror -Wformat" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -1333,7 +1333,7 @@ then AC_MSG_CHECKING(whether gcc supports ParseTuple __format__) save_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -Werror" + CFLAGS="$CFLAGS -Werror -Wformat" AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[void f(char*,...)__attribute((format(PyArg_ParseTuple, 1, 2)));]], [[]]) ],[ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 11 21:08:40 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 11 May 2013 21:08:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_backout_214d89?= =?utf-8?q?09513d_for_regressions_=28=231159051=29?= Message-ID: <3b7HrS0r62z7Ljl@mail.python.org> http://hg.python.org/cpython/rev/abc780332b60 changeset: 83716:abc780332b60 branch: 2.7 parent: 83711:9d50af4c482f user: Benjamin Peterson date: Sat May 11 13:17:13 2013 -0500 summary: backout 214d8909513d for regressions (#1159051) files: Lib/gzip.py | 69 ++++++++++++++++-------------- Lib/test/test_bz2.py | 18 -------- Lib/test/test_gzip.py | 17 ------- Misc/NEWS | 3 - 4 files changed, 36 insertions(+), 71 deletions(-) diff --git a/Lib/gzip.py b/Lib/gzip.py --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -21,6 +21,9 @@ # or unsigned. output.write(struct.pack(" self.extrasize: - if not self._read(readsize): - if size > self.extrasize: - size = self.extrasize - break - readsize = min(self.max_read_chunk, readsize * 2) + try: + while size > self.extrasize: + self._read(readsize) + readsize = min(self.max_read_chunk, readsize * 2) + except EOFError: + if size > self.extrasize: + size = self.extrasize offset = self.offset - self.extrastart chunk = self.extrabuf[offset: offset + size] @@ -275,7 +277,7 @@ def _read(self, size=1024): if self.fileobj is None: - return False + raise EOFError, "Reached EOF" if self._new_member: # If the _new_member flag is set, we have to @@ -286,7 +288,7 @@ pos = self.fileobj.tell() # Save current position self.fileobj.seek(0, 2) # Seek to end of file if pos == self.fileobj.tell(): - return False + raise EOFError, "Reached EOF" else: self.fileobj.seek( pos ) # Return to original position @@ -303,10 +305,9 @@ if buf == "": uncompress = self.decompress.flush() - self.fileobj.seek(-len(self.decompress.unused_data), 1) self._read_eof() self._add_read_data( uncompress ) - return False + raise EOFError, 'Reached EOF' uncompress = self.decompress.decompress(buf) self._add_read_data( uncompress ) @@ -316,14 +317,13 @@ # so seek back to the start of the unused data, finish up # this member, and read a new gzip header. # (The number of bytes to seek back is the length of the unused - # data) - self.fileobj.seek(-len(self.decompress.unused_data), 1) + # data, minus 8 because _read_eof() will rewind a further 8 bytes) + self.fileobj.seek( -len(self.decompress.unused_data)+8, 1) # Check the CRC and file size, and set the flag so we read # a new member on the next call self._read_eof() self._new_member = True - return True def _add_read_data(self, data): self.crc = zlib.crc32(data, self.crc) & 0xffffffffL @@ -334,11 +334,14 @@ self.size = self.size + len(data) def _read_eof(self): - # We've read to the end of the file. + # We've read to the end of the file, so we have to rewind in order + # to reread the 8 bytes containing the CRC and the file size. # We check the that the computed CRC and size of the # uncompressed data matches the stored values. Note that the size # stored is the true file size mod 2**32. - crc32, isize = struct.unpack(" http://hg.python.org/cpython/rev/1b595399e070 changeset: 83717:1b595399e070 parent: 83715:0dd04c39fb89 user: Benjamin Peterson date: Sat May 11 16:10:52 2013 -0500 summary: simplify #17947 test with weakrefs files: Lib/test/test_scope.py | 19 +++++-------------- 1 files changed, 5 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_scope.py b/Lib/test/test_scope.py --- a/Lib/test/test_scope.py +++ b/Lib/test/test_scope.py @@ -1,5 +1,7 @@ import gc import unittest +import weakref + from test.support import check_syntax_error, cpython_only, run_unittest @@ -740,16 +742,7 @@ # (though it will be cleared when the frame is collected). # Without the lambda, setting self to None is enough to break # the cycle. - logs = [] - class Canary: - def __del__(self): - logs.append('canary') - class Base: - def dig(self): - pass - class Tester(Base): - def __init__(self): - self.canary = Canary() + class Tester: def dig(self): if 0: lambda: self @@ -757,14 +750,12 @@ 1/0 except Exception as exc: self.exc = exc - super().dig() self = None # Break the cycle tester = Tester() tester.dig() + ref = weakref.ref(tester) del tester - logs.append('collect') - gc.collect() - self.assertEqual(logs, ['canary', 'collect']) + self.assertIsNone(ref()) def test_main(): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 11 23:13:10 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 11 May 2013 23:13:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_remove_unused_import?= Message-ID: <3b7Lc66Cm3zRLj@mail.python.org> http://hg.python.org/cpython/rev/62416c1ab8f8 changeset: 83718:62416c1ab8f8 user: Benjamin Peterson date: Sat May 11 16:12:57 2013 -0500 summary: remove unused import files: Lib/test/test_scope.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_scope.py b/Lib/test/test_scope.py --- a/Lib/test/test_scope.py +++ b/Lib/test/test_scope.py @@ -1,4 +1,3 @@ -import gc import unittest import weakref -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 11 23:29:24 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 11 May 2013 23:29:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_only_close_non?= =?utf-8?q?-None_files?= Message-ID: <3b7Lyr2fdGzSCR@mail.python.org> http://hg.python.org/cpython/rev/2966c9dbace9 changeset: 83719:2966c9dbace9 branch: 3.3 parent: 83712:94a7475d3a5f user: Benjamin Peterson date: Sat May 11 16:29:03 2013 -0500 summary: only close non-None files files: Lib/test/test_imp.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -241,7 +241,8 @@ # Issue #15902 name = '_heapq' found = imp.find_module(name) - found[0].close() + if found[0] is not None: + found[0].close() if found[2][2] != imp.C_EXTENSION: return imp.load_module(name, None, *found[1:]) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 11 23:29:25 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 11 May 2013 23:29:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3b7Lys4sNFz7LjP@mail.python.org> http://hg.python.org/cpython/rev/5fc96401e0c5 changeset: 83720:5fc96401e0c5 parent: 83718:62416c1ab8f8 parent: 83719:2966c9dbace9 user: Benjamin Peterson date: Sat May 11 16:29:11 2013 -0500 summary: merge 3.3 files: Lib/test/test_imp.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -267,7 +267,8 @@ # Issue #15902 name = '_testimportmultiple' found = imp.find_module(name) - found[0].close() + if found[0] is not None: + found[0].close() if found[2][2] != imp.C_EXTENSION: return imp.load_module(name, None, *found[1:]) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 00:28:34 2013 From: python-checkins at python.org (brett.cannon) Date: Sun, 12 May 2013 00:28:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Grammatical_fixes?= Message-ID: <3b7NH66pmvz7LkB@mail.python.org> http://hg.python.org/peps/rev/2782d983f66d changeset: 4886:2782d983f66d user: Brett Cannon date: Sat May 11 18:28:29 2013 -0400 summary: Grammatical fixes files: pep-0435.txt | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0435.txt b/pep-0435.txt --- a/pep-0435.txt +++ b/pep-0435.txt @@ -418,7 +418,7 @@ Pickling -------- -Enumerations be pickled and unpickled:: +Enumerations can be pickled and unpickled:: >>> from enum.tests.fruit import Fruit >>> from pickle import dumps, loads @@ -426,7 +426,7 @@ True The usual restrictions for pickling apply: picklable enums must be defined in -the top level of a module, since unpickling requires them to be imporatable +the top level of a module, since unpickling requires them to be importable from that module. -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun May 12 01:05:09 2013 From: python-checkins at python.org (vinay.sajip) Date: Sun, 12 May 2013 01:05:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Re-enabled_test_with_more_?= =?utf-8?q?diagnostics=2E?= Message-ID: <3b7P5K3p8Nz7LjS@mail.python.org> http://hg.python.org/cpython/rev/66e8ffee9190 changeset: 83721:66e8ffee9190 user: Vinay Sajip date: Sun May 12 00:04:58 2013 +0100 summary: Re-enabled test with more diagnostics. files: Lib/test/test_logging.py | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3964,7 +3964,7 @@ finally: rh.close() - @unittest.skipIf(True, 'Temporarily skipped while failures investigated.') + #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.') def test_compute_rollover_weekly_attime(self): currentTime = int(time.time()) today = currentTime - currentTime % 86400 @@ -3992,6 +3992,7 @@ actual = rh.computeRollover(today) if actual != expected: print('failed in timezone: %d' % time.timezone) + print('local vars: %s' % locals()) self.assertEqual(actual, expected) if day == wday: # goes into following week @@ -3999,6 +4000,7 @@ actual = rh.computeRollover(today + 13 * 60 * 60) if actual != expected: print('failed in timezone: %d' % time.timezone) + print('local vars: %s' % locals()) self.assertEqual(actual, expected) finally: rh.close() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 01:18:13 2013 From: python-checkins at python.org (vinay.sajip) Date: Sun, 12 May 2013 01:18:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Diagnostics_collected=2C_t?= =?utf-8?q?est_disabled_for_now=2E?= Message-ID: <3b7PNP2mQRz7LjS@mail.python.org> http://hg.python.org/cpython/rev/3fe80a481dd9 changeset: 83722:3fe80a481dd9 user: Vinay Sajip date: Sun May 12 00:18:02 2013 +0100 summary: Diagnostics collected, test disabled for now. files: Lib/test/test_logging.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3964,7 +3964,7 @@ finally: rh.close() - #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.') + @unittest.skipIf(True, 'Temporarily skipped while failures investigated.') def test_compute_rollover_weekly_attime(self): currentTime = int(time.time()) today = currentTime - currentTime % 86400 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 05:24:52 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 12 May 2013 05:24:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_prevent_IDLE_f?= =?utf-8?q?rom_trying_to_close_when_sys=2Estdin_is_reassigned_=28=2317838?= =?utf-8?q?=29?= Message-ID: <3b7Vs03v6gz7LjP@mail.python.org> http://hg.python.org/cpython/rev/4b3d18117813 changeset: 83723:4b3d18117813 branch: 2.7 parent: 83716:abc780332b60 user: Benjamin Peterson date: Sat May 11 22:24:28 2013 -0500 summary: prevent IDLE from trying to close when sys.stdin is reassigned (#17838) files: Lib/idlelib/run.py | 5 +++++ Misc/NEWS | 2 ++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -264,6 +264,11 @@ IOBinding.encoding) sys.stderr = PyShell.PseudoOutputFile(self.console, "stderr", IOBinding.encoding) + + # Keep a reference to stdin so that it won't try to exit IDLE if + # sys.stdin gets changed from within IDLE's shell. See issue17838. + self._keep_stdin = sys.stdin + self.interp = self.get_remote_proxy("interp") rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -122,6 +122,8 @@ IDLE ---- +- Issue #17838: Allow sys.stdin to be reassigned. + - Issue #14735: Update IDLE docs to omit "Control-z on Windows". - Issue #17585: Fixed IDLE regression. Now closes when using exit() or quit(). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 05:33:16 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 12 May 2013 05:33:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_bump_version_t?= =?utf-8?q?o_2=2E7=2E5?= Message-ID: <3b7W2h3ymkz7Ljc@mail.python.org> http://hg.python.org/cpython/rev/6390fce344de changeset: 83724:6390fce344de branch: 2.7 user: Benjamin Peterson date: Sat May 11 22:29:20 2013 -0500 summary: bump version to 2.7.5 files: Include/patchlevel.h | 4 ++-- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/NEWS | 2 +- Misc/RPM/python-2.7.spec | 2 +- README | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -22,12 +22,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 2 #define PY_MINOR_VERSION 7 -#define PY_MICRO_VERSION 4 +#define PY_MICRO_VERSION 5 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "2.7.4+" +#define PY_VERSION "2.7.5" /*--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.4" +__version__ = "2.7.5" #--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.4" +IDLE_VERSION = "2.7.5" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -4,7 +4,7 @@ What's New in Python 2.7.5? =========================== -*Release date: XXXX-XX-XX* +*Release date: 2013-05-12* 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.4 +%define version 2.7.5 %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.4 +This is Python version 2.7.5 ============================ Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 05:33:19 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 12 May 2013 05:33:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_update_topics?= Message-ID: <3b7W2l61nHz7Ljw@mail.python.org> http://hg.python.org/cpython/rev/ab05e7dd2788 changeset: 83725:ab05e7dd2788 branch: 2.7 tag: v2.7.5 user: Benjamin Peterson date: Sat May 11 22:31:33 2013 -0500 summary: update topics files: Lib/pydoc_data/topics.py | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 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,7 +1,7 @@ -# Autogenerated by Sphinx on Sat Apr 6 09:55:30 2013 +# Autogenerated by Sphinx on Sat May 11 22:31:13 2013 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 in front of the name, with leading underscores removed, and\na single underscore inserted in front of the class name. For example,\nthe identifier ``__spam`` occurring in a class named ``Ham`` will be\ntransformed to ``_Ham__spam``. This transformation is independent of\nthe syntactical context in which the identifier is used. If the\ntransformed name is extremely long (longer than 255 characters),\nimplementation defined truncation may happen. If the class name\nconsists only of underscores, no transformation is done.\n', + 'atom-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', @@ -33,14 +33,14 @@ '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\nThe *fill* character can be any character other than \'{\' or \'}\'. The\npresence of a fill character is signaled by the character following\nit, which must be one of the alignment options. If the second\ncharacter of *format_spec* is not a valid alignment option, then it is\nassumed that both the fill character and the alignment option are\nabsent.\n\nThe meaning of the various alignment options is as follows:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'<\'`` | Forces the field to be left-aligned within the available |\n | | space (this is the default for most objects). |\n +-----------+------------------------------------------------------------+\n | ``\'>\'`` | Forces the field to be right-aligned within the available |\n | | space (this is the default for numbers). |\n +-----------+------------------------------------------------------------+\n | ``\'=\'`` | Forces the padding to be placed after the sign (if any) |\n | | but before the digits. This is used for printing fields |\n | | in the form \'+000000120\'. This alignment option is only |\n | | valid for numeric types. |\n +-----------+------------------------------------------------------------+\n | ``\'^\'`` | Forces the field to be centered within the available |\n | | space. |\n +-----------+------------------------------------------------------------+\n\nNote that unless a minimum field width is defined, the field width\nwill always be the same size as the data to fill it, so that the\nalignment option has no meaning in this case.\n\nThe *sign* option is only valid for number types, and can be one of\nthe following:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'+\'`` | indicates that a sign should be used for both positive as |\n | | well as negative numbers. |\n +-----------+------------------------------------------------------------+\n | ``\'-\'`` | indicates that a sign should be used only for negative |\n | | numbers (this is the default behavior). |\n +-----------+------------------------------------------------------------+\n | space | indicates that a leading space should be used on positive |\n | | numbers, and a minus sign on negative numbers. |\n +-----------+------------------------------------------------------------+\n\nThe ``\'#\'`` option is only valid for integers, and only for binary,\noctal, or hexadecimal output. If present, it specifies that the\noutput will be prefixed by ``\'0b\'``, ``\'0o\'``, or ``\'0x\'``,\nrespectively.\n\nThe ``\',\'`` option signals the use of a comma for a thousands\nseparator. For a locale aware separator, use the ``\'n\'`` integer\npresentation type instead.\n\nChanged in version 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 +-----------+------------------------------------------------------------+\n | ``\'E\'`` | Exponent notation. Same as ``\'e\'`` except it uses an upper |\n | | case \'E\' as the separator character. |\n +-----------+------------------------------------------------------------+\n | ``\'f\'`` | Fixed point. Displays the number as a fixed-point number. |\n +-----------+------------------------------------------------------------+\n | ``\'F\'`` | Fixed point. Same as ``\'f\'``. |\n +-----------+------------------------------------------------------------+\n | ``\'g\'`` | General format. For a given precision ``p >= 1``, this |\n | | rounds the number to ``p`` significant digits and then |\n | | formats the result in either fixed-point format or in |\n | | scientific notation, depending on its magnitude. The |\n | | precise rules are as follows: suppose that the result |\n | | formatted with presentation type ``\'e\'`` and precision |\n | | ``p-1`` would have exponent ``exp``. Then if ``-4 <= exp |\n | | < p``, the number is formatted with presentation type |\n | | ``\'f\'`` and precision ``p-1-exp``. Otherwise, the number |\n | | is formatted with presentation type ``\'e\'`` and precision |\n | | ``p-1``. In both cases insignificant trailing zeros are |\n | | removed from the significand, and the decimal point is |\n | | also removed if there are no remaining digits following |\n | | it. Positive and negative infinity, positive and negative |\n | | zero, and nans, are formatted as ``inf``, ``-inf``, ``0``, |\n | | ``-0`` and ``nan`` respectively, regardless of the |\n | | precision. A precision of ``0`` is treated as equivalent |\n | | to a precision of ``1``. |\n +-----------+------------------------------------------------------------+\n | ``\'G\'`` | General format. Same as ``\'g\'`` except switches to ``\'E\'`` |\n | | if the number gets too large. The representations of |\n | | infinity and NaN are uppercased, too. |\n +-----------+------------------------------------------------------------+\n | ``\'n\'`` | Number. This is the same as ``\'g\'``, except that it uses |\n | | the current locale setting to insert the appropriate |\n | | number separator characters. |\n +-----------+------------------------------------------------------------+\n | ``\'%\'`` | Percentage. Multiplies the number by 100 and displays in |\n | | fixed (``\'f\'``) format, followed by a percent sign. |\n +-----------+------------------------------------------------------------+\n | None | 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', + '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\nThe *fill* character can be any character other than \'{\' or \'}\'. The\npresence of a fill character is signaled by the character following\nit, which must be one of the alignment options. If the second\ncharacter of *format_spec* is not a valid alignment option, then it is\nassumed that both the fill character and the alignment option are\nabsent.\n\nThe meaning of the various alignment options is as follows:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'<\'`` | Forces the field to be left-aligned within the available |\n | | space (this is the default for most objects). |\n +-----------+------------------------------------------------------------+\n | ``\'>\'`` | Forces the field to be right-aligned within the available |\n | | space (this is the default for numbers). |\n +-----------+------------------------------------------------------------+\n | ``\'=\'`` | Forces the padding to be placed after the sign (if any) |\n | | but before the digits. This is used for printing fields |\n | | in the form \'+000000120\'. This alignment option is only |\n | | valid for numeric types. |\n +-----------+------------------------------------------------------------+\n | ``\'^\'`` | Forces the field to be centered within the available |\n | | space. |\n +-----------+------------------------------------------------------------+\n\nNote that unless a minimum field width is defined, the field width\nwill always be the same size as the data to fill it, so that the\nalignment option has no meaning in this case.\n\nThe *sign* option is only valid for number types, and can be one of\nthe following:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'+\'`` | indicates that a sign should be used for both positive as |\n | | well as negative numbers. |\n +-----------+------------------------------------------------------------+\n | ``\'-\'`` | indicates that a sign should be used only for negative |\n | | numbers (this is the default behavior). |\n +-----------+------------------------------------------------------------+\n | space | indicates that a leading space should be used on positive |\n | | numbers, and a minus sign on negative numbers. |\n +-----------+------------------------------------------------------------+\n\nThe ``\'#\'`` option is only valid for integers, and only for binary,\noctal, or hexadecimal output. If present, it specifies that the\noutput will be prefixed by ``\'0b\'``, ``\'0o\'``, or ``\'0x\'``,\nrespectively.\n\nThe ``\',\'`` option signals the use of a comma for a thousands\nseparator. For a locale aware separator, use the ``\'n\'`` integer\npresentation type instead.\n\nChanged in version 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 forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements.\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', + '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_form ::= "lambda" [parameter_list]: expression\n old_lambda_form ::= "lambda" [parameter_list]: old_expression\n\nLambda forms (lambda expressions) have the same syntactic position as\nexpressions. They are a shorthand to create anonymous functions; the\nexpression ``lambda arguments: expression`` yields a function object.\nThe unnamed object behaves like a function object defined with\n\n def name(arguments):\n return expression\n\nSee section *Function definitions* for the syntax of parameter lists.\nNote that functions created with lambda forms cannot contain\nstatements.\n', @@ -49,7 +49,7 @@ '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', + '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', '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', @@ -59,19 +59,19 @@ '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 ``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. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\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', + '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). Individual code units which form parts of a surrogate\n pair can be encoded using this escape sequence.\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\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 the only\n 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 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 | ``func_doc`` | The function\'s documentation | Writable |\n | | string, or ``None`` if | |\n | | unavailable | |\n +-------------------------+---------------------------------+-------------+\n | ``__doc__`` | Another way of spelling | Writable |\n | | ``func_doc`` | |\n +-------------------------+---------------------------------+-------------+\n | ``func_name`` | The function\'s name | Writable |\n +-------------------------+---------------------------------+-------------+\n | ``__name__`` | Another way of spelling | 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 | ``func_defaults`` | A tuple containing default | Writable |\n | | argument values for those | |\n | | arguments that have defaults, | |\n | | or ``None`` if no arguments | |\n | | have a default value | |\n +-------------------------+---------------------------------+-------------+\n | ``func_code`` | The code object representing | Writable |\n | | the compiled function body. | |\n +-------------------------+---------------------------------+-------------+\n | ``func_globals`` | A reference to the dictionary | Read-only |\n | | that holds the function\'s | |\n | | global variables --- the global | |\n | | namespace of the module in | |\n | | which the function was defined. | |\n +-------------------------+---------------------------------+-------------+\n | ``func_dict`` | The namespace supporting | Writable |\n | | arbitrary function attributes. | |\n +-------------------------+---------------------------------+-------------+\n | ``func_closure`` | ``None`` or a tuple of cells | Read-only |\n | | 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 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 (the same as the ``im_class``\n attribute), and its ``im_func`` attribute is the function object\n 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_class`` and ``im_self`` attributes are\n both ``C``. When it would yield a static method object, it is\n transformed into the object wrapped by the static method object.\n See section *Implementing Descriptors* for another way in which\n attributes retrieved from a class may differ from those actually\n contained in its ``__dict__`` (note that only new-style classes\n 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', + '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 the only\n 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 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 | ``func_doc`` | The function\'s documentation | Writable |\n | | string, or ``None`` if | |\n | | unavailable | |\n +-------------------------+---------------------------------+-------------+\n | ``__doc__`` | Another way of spelling | Writable |\n | | ``func_doc`` | |\n +-------------------------+---------------------------------+-------------+\n | ``func_name`` | The function\'s name | Writable |\n +-------------------------+---------------------------------+-------------+\n | ``__name__`` | Another way of spelling | 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 | ``func_defaults`` | A tuple containing default | Writable |\n | | argument values for those | |\n | | arguments that have defaults, | |\n | | or ``None`` if no arguments | |\n | | have a default value | |\n +-------------------------+---------------------------------+-------------+\n | ``func_code`` | The code object representing | Writable |\n | | the compiled function body. | |\n +-------------------------+---------------------------------+-------------+\n | ``func_globals`` | A reference to the dictionary | Read-only |\n | | that holds the function\'s | |\n | | global variables --- the global | |\n | | namespace of the module in | |\n | | which the function was defined. | |\n +-------------------------+---------------------------------+-------------+\n | ``func_dict`` | The namespace supporting | Writable |\n | | arbitrary function attributes. | |\n +-------------------------+---------------------------------+-------------+\n | ``func_closure`` | ``None`` or a tuple of cells | Read-only |\n | | 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 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 *iterator*\n object. Each item in the iterable must itself be an iterator with\n exactly two objects. The first object of each item becomes a key\n in the new dictionary, and the second object the corresponding\n value. If a key occurs more than once, the last value for that key\n becomes the corresponding value in the new dictionary.\n\n If keyword arguments are given, the keyword arguments and their\n values are added to the dictionary created from the positional\n argument. If a key being added is already present, the value from\n the keyword argument replaces the value from the positional\n argument.\n\n To illustrate, the following examples all return a dictionary equal\n to ``{"one": 1, "two": 2, "three": 3}``:\n\n >>> a = dict(one=1, two=2, three=3)\n >>> b = {\'one\': 1, \'two\': 2, \'three\': 3}\n >>> c = dict(zip([\'one\', \'two\', \'three\'], [1, 2, 3]))\n >>> d = dict([(\'two\', 2), (\'one\', 1), (\'three\', 3)])\n >>> e = dict({\'three\': 3, \'one\': 1, \'two\': 2})\n >>> a == b == c == d == e\n True\n\n Providing keyword arguments as in the first example only works for\n keys that are valid Python identifiers. Otherwise, any valid keys\n can be used.\n\n 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(i)`` | index of the first occurence of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.count(i)`` | total number of occurences of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n\nSequence types also support comparisons. In particular, tuples and\nlists are compared lexicographically by comparing corresponding\nelements. This means that to compare equal, every element must 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. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\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 is only supported by the list and array types.\n The optional argument *i* defaults to ``-1``, so that by default\n 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': '\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(i)`` | index of the first occurence of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.count(i)`` | total number of occurences of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n\nSequence types also support comparisons. In particular, tuples and\nlists are compared lexicographically by comparing corresponding\nelements. This means that to compare equal, every element must 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 is only supported by the list and array types.\n The optional argument *i* defaults to ``-1``, so that by default\n 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 is only supported by the list and array types.\n The optional argument *i* defaults to ``-1``, so that by default\n 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\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'} + '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'} -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 05:33:21 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 12 May 2013 05:33:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_Added_tag_v2?= =?utf-8?q?=2E7=2E5_for_changeset_ab05e7dd2788?= Message-ID: <3b7W2n1GSrz7LkR@mail.python.org> http://hg.python.org/cpython/rev/921b69c9d7ac changeset: 83726:921b69c9d7ac branch: 2.7 user: Benjamin Peterson date: Sat May 11 22:31:46 2013 -0500 summary: Added tag v2.7.5 for changeset ab05e7dd2788 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -158,3 +158,4 @@ 70274d53c1ddc60c5f9a2b8a422a49884021447c v2.7.3 a8d18780bc2bccf16bf580587e1e3c934a98f6a7 v2.7.4rc1 026ee0057e2d3305f90a9da41daf7c3f9eb1e814 v2.7.4 +ab05e7dd27889b93f20d97bae86170aabfe45ace v2.7.5 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 05:36:17 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 12 May 2013 05:36:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogb250byAyLjcuNg==?= Message-ID: <3b7W690LqTz7Ljs@mail.python.org> http://hg.python.org/cpython/rev/f420a9ea4f25 changeset: 83727:f420a9ea4f25 branch: 2.7 user: Benjamin Peterson date: Sat May 11 22:36:05 2013 -0500 summary: onto 2.7.6 files: Include/patchlevel.h | 2 +- Misc/NEWS | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -27,7 +27,7 @@ #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "2.7.5" +#define PY_VERSION "2.7.5+" /*--end constants--*/ /* Subversion Revision number of this file (not of the repository). Empty diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1,6 +1,18 @@ Python News +++++++++++ +What's New in Python 2.7.6? +=========================== + +*Release date: XXXX-XX-XX* + +Core and Builtins +----------------- + +Library +------- + + What's New in Python 2.7.5? =========================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 05:38:31 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 12 May 2013 05:38:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_add_2=2E7=2E5_date?= Message-ID: <3b7W8l2Kzgz7Ljs@mail.python.org> http://hg.python.org/peps/rev/f40289b5be02 changeset: 4887:f40289b5be02 user: Benjamin Peterson date: Sat May 11 22:37:32 2013 -0500 summary: add 2.7.5 date files: pep-0373.txt | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/pep-0373.txt b/pep-0373.txt --- a/pep-0373.txt +++ b/pep-0373.txt @@ -65,6 +65,7 @@ - 2.7.3 2012-03-09 - 2.7.4rc1 2013-03-23 - 2.7.4 2013-04-06 +- 2.7.5 2013-05-12 Possible features for 2.7 -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun May 12 05:39:59 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sun, 12 May 2013 05:39:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_tentative_future_2=2E7_releas?= =?utf-8?q?e_dates?= Message-ID: <3b7WBR4Ck6z7Ljs@mail.python.org> http://hg.python.org/peps/rev/d31f5e9ea95c changeset: 4888:d31f5e9ea95c user: Benjamin Peterson date: Sat May 11 22:39:48 2013 -0500 summary: tentative future 2.7 release dates files: pep-0373.txt | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/pep-0373.txt b/pep-0373.txt --- a/pep-0373.txt +++ b/pep-0373.txt @@ -56,6 +56,11 @@ Planned future release dates: +- 2.7.6 November 2013 +- 2.7.7 May 2014 +- 2.7.8 November 2014 +- 2.7.9 May 2015 + Dates of previous maintenance releases: - 2.7.1 2010-11-27 -- Repository URL: http://hg.python.org/peps From solipsis at pitrou.net Sun May 12 06:06:33 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 12 May 2013 06:06:33 +0200 Subject: [Python-checkins] Daily reference leaks (3fe80a481dd9): sum=6 Message-ID: results for 3fe80a481dd9 on branch "default" -------------------------------------------- test_unittest leaked [-1, 2, 1] memory blocks, sum=2 test_concurrent_futures leaked [-2, 3, 1] memory blocks, sum=2 test_multiprocessing leaked [-1, 2, 1] memory blocks, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogrH5YXl', '-x'] From python-checkins at python.org Sun May 12 11:24:19 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 11:24:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_prevent_IDLE_f?= =?utf-8?q?rom_trying_to_close_when_sys=2Estdin_is_reassigned_=28=2317838?= =?utf-8?q?=29?= Message-ID: <3b7fql0w02z7LjR@mail.python.org> http://hg.python.org/cpython/rev/5f62c848f713 changeset: 83728:5f62c848f713 branch: 3.3 parent: 83576:4e58cafbebfc user: Benjamin Peterson date: Sat May 11 22:24:28 2013 -0500 summary: prevent IDLE from trying to close when sys.stdin is reassigned (#17838) files: Lib/idlelib/run.py | 5 +++++ Misc/NEWS | 2 ++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -297,6 +297,11 @@ # page help() text to shell. import pydoc # import must be done here to capture i/o binding pydoc.pager = pydoc.plainpager + + # Keep a reference to stdin so that it won't try to exit IDLE if + # sys.stdin gets changed from within IDLE's shell. See issue17838. + self._keep_stdin = sys.stdin + self.interp = self.get_remote_proxy("interp") rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -118,6 +118,8 @@ IDLE ---- +- Issue #17838: Allow sys.stdin to be reassigned. + - Issue #14735: Update IDLE docs to omit "Control-z on Windows". - Issue #17585: Fixed IDLE regression. Now closes when using exit() or quit(). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 11:24:20 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 11:24:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317838=3A_merge_with_3=2E3?= Message-ID: <3b7fqm3G1Fz7Lk7@mail.python.org> http://hg.python.org/cpython/rev/bc322854c336 changeset: 83729:bc322854c336 parent: 83722:3fe80a481dd9 parent: 83728:5f62c848f713 user: Georg Brandl date: Sun May 12 11:21:27 2013 +0200 summary: Issue #17838: merge with 3.3 files: Lib/idlelib/run.py | 5 +++++ Misc/NEWS | 2 ++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -297,6 +297,11 @@ # page help() text to shell. import pydoc # import must be done here to capture i/o binding pydoc.pager = pydoc.plainpager + + # Keep a reference to stdin so that it won't try to exit IDLE if + # sys.stdin gets changed from within IDLE's shell. See issue17838. + self._keep_stdin = sys.stdin + self.interp = self.get_remote_proxy("interp") rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -294,6 +294,8 @@ IDLE ---- +- Issue #17838: Allow sys.stdin to be reassigned. + - Issue #13495: Avoid loading the color delegator twice in IDLE. - Issue #17798: Allow IDLE to edit new files when specified on command line. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 11:24:21 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 11:24:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuMyk6?= =?utf-8?q?_merge_heads?= Message-ID: <3b7fqn5Yvhz7Ljg@mail.python.org> http://hg.python.org/cpython/rev/011f88d6cd16 changeset: 83730:011f88d6cd16 branch: 3.3 parent: 83719:2966c9dbace9 parent: 83728:5f62c848f713 user: Georg Brandl date: Sun May 12 11:24:47 2013 +0200 summary: merge heads files: Lib/idlelib/run.py | 5 +++++ Misc/NEWS | 2 ++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -297,6 +297,11 @@ # page help() text to shell. import pydoc # import must be done here to capture i/o binding pydoc.pager = pydoc.plainpager + + # Keep a reference to stdin so that it won't try to exit IDLE if + # sys.stdin gets changed from within IDLE's shell. See issue17838. + self._keep_stdin = sys.stdin + self.interp = self.get_remote_proxy("interp") rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -147,6 +147,8 @@ IDLE ---- +- Issue #17838: Allow sys.stdin to be reassigned. + - Issue #13495: Avoid loading the color delegator twice in IDLE. - Issue #17798: Allow IDLE to edit new files when specified on command line. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 11:24:23 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 11:24:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3b7fqq0hyhz7Lkl@mail.python.org> http://hg.python.org/cpython/rev/e98cf2cec516 changeset: 83731:e98cf2cec516 parent: 83729:bc322854c336 parent: 83730:011f88d6cd16 user: Georg Brandl date: Sun May 12 11:24:58 2013 +0200 summary: merge files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 12:32:44 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 12:32:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogQ2xvc2UgIzE3NjY2?= =?utf-8?q?=3A_Fix_reading_gzip_files_with_an_extra_field=2E?= Message-ID: <3b7hLh1zs2z7Lkp@mail.python.org> http://hg.python.org/cpython/rev/c31ff361cde3 changeset: 83732:c31ff361cde3 branch: 3.2 parent: 83565:64627891ca23 user: Serhiy Storchaka date: Mon Apr 08 22:35:02 2013 +0300 summary: Close #17666: Fix reading gzip files with an extra field. files: Lib/gzip.py | 3 ++- Lib/test/test_gzip.py | 7 +++++++ Misc/NEWS | 19 +++++++++++++++---- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/Lib/gzip.py b/Lib/gzip.py --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -280,7 +280,8 @@ if flag & FEXTRA: # Read & discard the extra field, if present - self._read_exact(struct.unpack(" http://hg.python.org/cpython/rev/31eaf8a137ea changeset: 83733:31eaf8a137ea branch: 3.2 user: Georg Brandl date: Sun May 12 11:09:11 2013 +0200 summary: Issue #15535: Fix pickling of named tuples. files: Lib/collections.py | 4 ++++ Lib/test/test_collections.py | 1 + Misc/NEWS | 3 +++ 3 files changed, 8 insertions(+), 0 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -281,6 +281,10 @@ 'Return self as a plain tuple. Used by copy and pickle.' return tuple(self) + def __getstate__(self): + 'Exclude the OrderedDict from pickling' + return None + {field_defs} ''' 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 @@ -272,6 +272,7 @@ q = loads(dumps(p, protocol)) self.assertEqual(p, q) self.assertEqual(p._fields, q._fields) + self.assertNotIn(b'OrderedDict', dumps(p, protocol)) def test_copy(self): p = TestNT(x=10, y=20, z=30) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -16,6 +16,9 @@ - Issue #17666: Fix reading gzip files with an extra field. +- Issue #15535: Fix namedtuple pickles which were picking up the OrderedDict + instead of just the underlying tuple. + What's New in Python 3.2.4? =========================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 12:32:46 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 12:32:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE3ODQz?= =?utf-8?q?=3A_Remove_bz2_test_data_that_triggers_antivirus_warnings=2E?= Message-ID: <3b7hLk6gz7z7Lky@mail.python.org> http://hg.python.org/cpython/rev/9da98ab823c9 changeset: 83734:9da98ab823c9 branch: 3.2 user: Georg Brandl date: Sun May 12 11:11:51 2013 +0200 summary: Issue #17843: Remove bz2 test data that triggers antivirus warnings. files: Lib/test/test_bz2.py | 13 ++++++------- Lib/test/testbz2_bigmem.bz2 | Bin Misc/NEWS | 6 ++++++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py --- a/Lib/test/test_bz2.py +++ b/Lib/test/test_bz2.py @@ -26,9 +26,6 @@ DATA_CRLF = b'BZh91AY&SY\xaez\xbbN\x00\x01H\xdf\x80\x00\x12@\x02\xff\xf0\x01\x07n\x00?\xe7\xff\xe0@\x01\xbc\xc6`\x86*\x8d=M\xa9\x9a\x86\xd0L@\x0fI\xa6!\xa1\x13\xc8\x88jdi\x8d@\x03@\x1a\x1a\x0c\x0c\x83 \x00\xc4h2\x19\x01\x82D\x84e\t\xe8\x99\x89\x19\x1ah\x00\r\x1a\x11\xaf\x9b\x0fG\xf5(\x1b\x1f?\t\x12\xcf\xb5\xfc\x95E\x00ps\x89\x12^\xa4\xdd\xa2&\x05(\x87\x04\x98\x89u\xe40%\xb6\x19\'\x8c\xc4\x89\xca\x07\x0e\x1b!\x91UIFU%C\x994!DI\xd2\xfa\xf0\xf1N8W\xde\x13A\xf5\x9cr%?\x9f3;I45A\xd1\x8bT\xb1\xa4\xc7\x8d\x1a\\"\xad\xa1\xabyBg\x15\xb9l\x88\x88\x91k"\x94\xa4\xd4\x89\xae*\xa6\x0b\x10\x0c\xd6\xd4m\xe86\xec\xb5j\x8a\x86j\';\xca.\x01I\xf2\xaaJ\xe8\x88\x8cU+t3\xfb\x0c\n\xa33\x13r2\r\x16\xe0\xb3(\xbf\x1d\x83r\xe7M\xf0D\x1365\xd8\x88\xd3\xa4\x92\xcb2\x06\x04\\\xc1\xb0\xea//\xbek&\xd8\xe6+t\xe5\xa1\x13\xada\x16\xder5"w]\xa2i\xb7[\x97R \xe2IT\xcd;Z\x04dk4\xad\x8a\t\xd3\x81z\x10\xf1:^`\xab\x1f\xc5\xdc\x91N\x14$+\x9e\xae\xd3\x80' EMPTY_DATA = b'BZh9\x17rE8P\x90\x00\x00\x00\x00' - with open(findfile("testbz2_bigmem.bz2"), "rb") as f: - DATA_BIGMEM = f.read() - if has_cmdline_bunzip2: def decompress(self, data): pop = subprocess.Popen("bunzip2", shell=True, @@ -395,9 +392,10 @@ @bigmemtest(size=_4G, memuse=1.25, dry_run=False) def testBigmem(self, unused_size): # Issue #14398: decompression fails when output data is >=2GB. - text = bz2.BZ2Decompressor().decompress(self.DATA_BIGMEM) + compressed = bz2.compress(b"a" * _4G) + text = bz2.BZ2Decompressor().decompress(compressed) self.assertEqual(len(text), _4G) - self.assertEqual(text.strip(b"\0"), b"") + self.assertEqual(text.strip(b"a"), b"") class FuncTest(BaseTest): @@ -442,9 +440,10 @@ @bigmemtest(size=_4G, memuse=1.25, dry_run=False) def testDecompressBigmem(self, unused_size): # Issue #14398: decompression fails when output data is >=2GB. - text = bz2.decompress(self.DATA_BIGMEM) + compressed = bz2.compress(b"a" * _4G) + text = bz2.BZ2Decompressor().decompress(compressed) self.assertEqual(len(text), _4G) - self.assertEqual(text.strip(b"\0"), b"") + self.assertEqual(text.strip(b"a"), b"") def test_main(): support.run_unittest( diff --git a/Lib/test/testbz2_bigmem.bz2 b/Lib/test/testbz2_bigmem.bz2 deleted file mode 100644 Binary file Lib/test/testbz2_bigmem.bz2 has changed diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -19,6 +19,12 @@ - Issue #15535: Fix namedtuple pickles which were picking up the OrderedDict instead of just the underlying tuple. +Tests +----- + +- Issue #17843: Removed bz2 test data file that was triggering false-positive + virus warnings with certain antivirus software. + What's New in Python 3.2.4? =========================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 12:32:48 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 12:32:48 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE3ODU3?= =?utf-8?q?=3A_Prevent_build_failures_with_pre-3=2E5=2E0_versions_of_sqlit?= =?utf-8?b?ZTMs?= Message-ID: <3b7hLm20hsz7Lkh@mail.python.org> http://hg.python.org/cpython/rev/d5b5116bf953 changeset: 83735:d5b5116bf953 branch: 3.2 user: Serhiy Storchaka date: Sun Apr 28 14:10:27 2013 +0300 summary: Issue #17857: Prevent build failures with pre-3.5.0 versions of sqlite3, such as was shipped with Centos 5 and Mac OS X 10.4. files: Misc/NEWS | 6 ++++++ Modules/_sqlite/cursor.c | 2 +- Modules/_sqlite/util.c | 8 ++++---- Modules/_sqlite/util.h | 4 ++-- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -19,6 +19,12 @@ - Issue #15535: Fix namedtuple pickles which were picking up the OrderedDict instead of just the underlying tuple. +Build +----- + +- Issue #17857: Prevent build failures with pre-3.5.0 versions of sqlite3, + such as was shipped with Centos 5 and Mac OS X 10.4. + Tests ----- diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c --- a/Modules/_sqlite/cursor.c +++ b/Modules/_sqlite/cursor.c @@ -716,7 +716,7 @@ Py_DECREF(self->lastrowid); if (!multiple && statement_type == STATEMENT_INSERT) { - sqlite3_int64 lastrowid; + sqlite_int64 lastrowid; Py_BEGIN_ALLOW_THREADS lastrowid = sqlite3_last_insert_rowid(self->connection->db); Py_END_ALLOW_THREADS diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c --- a/Modules/_sqlite/util.c +++ b/Modules/_sqlite/util.c @@ -111,7 +111,7 @@ #endif PyObject * -_pysqlite_long_from_int64(sqlite3_int64 value) +_pysqlite_long_from_int64(sqlite_int64 value) { #ifdef HAVE_LONG_LONG # if SIZEOF_LONG_LONG < 8 @@ -135,7 +135,7 @@ return PyLong_FromLong(value); } -sqlite3_int64 +sqlite_int64 _pysqlite_long_as_int64(PyObject * py_val) { int overflow; @@ -158,8 +158,8 @@ #endif return value; } - else if (sizeof(value) < sizeof(sqlite3_int64)) { - sqlite3_int64 int64val; + else if (sizeof(value) < sizeof(sqlite_int64)) { + sqlite_int64 int64val; if (_PyLong_AsByteArray((PyLongObject *)py_val, (unsigned char *)&int64val, sizeof(int64val), IS_LITTLE_ENDIAN, 1 /* signed */) >= 0) { diff --git a/Modules/_sqlite/util.h b/Modules/_sqlite/util.h --- a/Modules/_sqlite/util.h +++ b/Modules/_sqlite/util.h @@ -36,7 +36,7 @@ */ int _pysqlite_seterror(sqlite3* db, sqlite3_stmt* st); -PyObject * _pysqlite_long_from_int64(sqlite3_int64 value); -sqlite3_int64 _pysqlite_long_as_int64(PyObject * value); +PyObject * _pysqlite_long_from_int64(sqlite_int64 value); +sqlite_int64 _pysqlite_long_as_int64(PyObject * value); #endif -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 12:32:49 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 12:32:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzExNTkw?= =?utf-8?q?51=3A_Back_out_a_fix_for_handling_corrupted_gzip_files_that?= Message-ID: <3b7hLn5X42z7LkB@mail.python.org> http://hg.python.org/cpython/rev/854ba6f414a8 changeset: 83736:854ba6f414a8 branch: 3.2 user: Georg Brandl date: Sun May 12 11:29:27 2013 +0200 summary: Issue #1159051: Back out a fix for handling corrupted gzip files that broke backwards compatibility. files: Lib/gzip.py | 73 ++++++++++++++++-------------- Lib/test/test_bz2.py | 18 ------- Lib/test/test_gzip.py | 13 ----- Misc/NEWS | 5 +- 4 files changed, 41 insertions(+), 68 deletions(-) diff --git a/Lib/gzip.py b/Lib/gzip.py --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -33,6 +33,9 @@ # or unsigned. output.write(struct.pack(" self.extrasize: - if not self._read(readsize): - if size > self.extrasize: - size = self.extrasize - break - readsize = min(self.max_read_chunk, readsize * 2) + try: + while size > self.extrasize: + self._read(readsize) + readsize = min(self.max_read_chunk, readsize * 2) + except EOFError: + if size > self.extrasize: + size = self.extrasize offset = self.offset - self.extrastart chunk = self.extrabuf[offset: offset + size] @@ -365,9 +366,12 @@ if self.extrasize == 0: if self.fileobj is None: return b'' - # Ensure that we don't return b"" if we haven't reached EOF. - # 1024 is the same buffering heuristic used in read() - while self.extrasize == 0 and self._read(max(n, 1024)): + try: + # Ensure that we don't return b"" if we haven't reached EOF. + while self.extrasize == 0: + # 1024 is the same buffering heuristic used in read() + self._read(max(n, 1024)) + except EOFError: pass offset = self.offset - self.extrastart remaining = self.extrasize @@ -380,14 +384,13 @@ def _read(self, size=1024): if self.fileobj is None: - return False + raise EOFError("Reached EOF") if self._new_member: # If the _new_member flag is set, we have to # jump to the next member, if there is one. self._init_read() - if not self._read_gzip_header(): - return False + self._read_gzip_header() self.decompress = zlib.decompressobj(-zlib.MAX_WBITS) self._new_member = False @@ -404,7 +407,7 @@ self.fileobj.prepend(self.decompress.unused_data, True) self._read_eof() self._add_read_data( uncompress ) - return False + raise EOFError('Reached EOF') uncompress = self.decompress.decompress(buf) self._add_read_data( uncompress ) @@ -420,7 +423,6 @@ # a new member on the next call self._read_eof() self._new_member = True - return True def _add_read_data(self, data): self.crc = zlib.crc32(data, self.crc) & 0xffffffff @@ -435,7 +437,8 @@ # We check the that the computed CRC and size of the # uncompressed data matches the stored values. Note that the size # stored is the true file size mod 2**32. - crc32, isize = struct.unpack(" http://hg.python.org/cpython/rev/1c01571ce0f4 changeset: 83737:1c01571ce0f4 branch: 3.2 user: Georg Brandl date: Sun May 12 11:41:12 2013 +0200 summary: Issue #17915: Fix interoperability of xml.sax with file objects returned by codecs.open(). files: Lib/test/test_sax.py | 31 +++++++++++++++++++++++++++++ Lib/xml/sax/saxutils.py | 5 ++++ Misc/NEWS | 3 ++ 3 files changed, 39 insertions(+), 0 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 @@ -15,6 +15,7 @@ from xml.sax.handler import feature_namespaces from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl from io import BytesIO, StringIO +import codecs import os.path import shutil from test import support @@ -538,6 +539,34 @@ def getvalue(self): return b''.join(self) +class StreamWriterXmlgenTest(XmlgenTest, unittest.TestCase): + def ioclass(self): + raw = BytesIO() + writer = codecs.getwriter('ascii')(raw, 'xmlcharrefreplace') + writer.getvalue = raw.getvalue + return writer + + def xml(self, doc, encoding='iso-8859-1'): + return ('\n%s' % + (encoding, doc)).encode('ascii', 'xmlcharrefreplace') + +class StreamReaderWriterXmlgenTest(XmlgenTest, unittest.TestCase): + fname = support.TESTFN + '-codecs' + + def ioclass(self): + writer = codecs.open(self.fname, 'w', encoding='ascii', + errors='xmlcharrefreplace', buffering=0) + self.addCleanup(support.unlink, self.fname) + writer.getvalue = self.getvalue + return writer + + def getvalue(self): + with open(self.fname, 'rb') as f: + return f.read() + + def xml(self, doc, encoding='iso-8859-1'): + return ('\n%s' % + (encoding, doc)).encode('ascii', 'xmlcharrefreplace') start = b'\n' @@ -946,6 +975,8 @@ StringXmlgenTest, BytesXmlgenTest, WriterXmlgenTest, + StreamWriterXmlgenTest, + StreamReaderWriterXmlgenTest, ExpatReaderTest, ErrorReportingTest, XmlReaderTest) 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 @@ -5,6 +5,7 @@ import os, urllib.parse, urllib.request import io +import codecs from . import handler from . import xmlreader @@ -77,6 +78,10 @@ # use a text writer as is return out + if isinstance(out, (codecs.StreamWriter, codecs.StreamReaderWriter)): + # use a codecs stream writer as is + return out + # wrap a binary writer with TextIOWrapper if isinstance(out, io.RawIOBase): # Keep the original file open when the TextIOWrapper is diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -20,6 +20,9 @@ - Issue #1159051: Back out a fix for handling corrupted gzip files that broke backwards compatibility. +- Issue #17915: Fix interoperability of xml.sax with file objects returned by + codecs.open(). + Build ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 12:32:52 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 12:32:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_Bump_to_versio?= =?utf-8?b?biAzLjIuNS4=?= Message-ID: <3b7hLr2ytBz7Ll5@mail.python.org> http://hg.python.org/cpython/rev/cef745775b65 changeset: 83738:cef745775b65 branch: 3.2 tag: v3.2.5 user: Georg Brandl date: Sun May 12 12:28:20 2013 +0200 summary: Bump to version 3.2.5. files: Include/patchlevel.h | 4 ++-- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/NEWS | 2 +- Misc/RPM/python-3.2.spec | 2 +- README | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -18,12 +18,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 2 -#define PY_MICRO_VERSION 4 +#define PY_MICRO_VERSION 5 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.2.4" +#define PY_VERSION "3.2.5" /*--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 @@ -13,5 +13,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.2.4" +__version__ = "3.2.5" #--end constants-- diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1,1 +1,1 @@ -IDLE_VERSION = "3.2.4" +IDLE_VERSION = "3.2.5" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1,4 +1,4 @@ -+++++++++++ +++++++++++ Python News +++++++++++ diff --git a/Misc/RPM/python-3.2.spec b/Misc/RPM/python-3.2.spec --- a/Misc/RPM/python-3.2.spec +++ b/Misc/RPM/python-3.2.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 3.2.4 +%define version 3.2.5 %define libvers 3.2 #--end constants-- %define release 1pydotorg diff --git a/README b/README --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Python version 3.2.4 +This is Python version 3.2.5 ============================ Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 12:32:53 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 12:32:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E2=29=3A_Added_tag_v3?= =?utf-8?q?=2E2=2E5_for_changeset_cef745775b65?= Message-ID: <3b7hLs59Rvz7Ll2@mail.python.org> http://hg.python.org/cpython/rev/6255b40c6a61 changeset: 83739:6255b40c6a61 branch: 3.2 user: Georg Brandl date: Sun May 12 12:28:30 2013 +0200 summary: Added tag v3.2.5 for changeset cef745775b65 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -101,3 +101,4 @@ 3d0686d90f55a78f96d9403da2c52dc2411419d0 v3.2.3 b2cb7bc1edb8493c0a78f9331eae3e8fba6a881d v3.2.4rc1 1e10bdeabe3de02f038a63c001911561ac1d13a7 v3.2.4 +cef745775b6583446572cffad704100983db2bea v3.2.5 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 12:47:25 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 12:47:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMyk6?= =?utf-8?q?_merge_with_3=2E2?= Message-ID: <3b7hgd5XcSzR0l@mail.python.org> http://hg.python.org/cpython/rev/da9c443e67ba changeset: 83740:da9c443e67ba branch: 3.3 parent: 83730:011f88d6cd16 parent: 83736:854ba6f414a8 user: Georg Brandl date: Sun May 12 11:51:26 2013 +0200 summary: merge with 3.2 files: Misc/NEWS | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -49,6 +49,12 @@ Library ------- +- Issue #1159051: Back out a fix for handling corrupted gzip files that + broke backwards compatibility. + +- Issue #17915: Fix interoperability of xml.sax with file objects returned by + codecs.open(). + - Issue #16601: Restarting iteration over tarfile no more continues from where it left off. Patch by Michael Birtwell. @@ -217,6 +223,9 @@ - Issue #17692: test_sqlite now works with unittest test discovery. Patch by Zachary Ware. +- Issue #17843: Removed bz2 test data file that was triggering false-positive + virus warnings with certain antivirus software. + Documentation ------------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 12:47:27 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 12:47:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4yIC0+IDMuMyk6?= =?utf-8?q?_merge_with_3=2E2?= Message-ID: <3b7hgg0jDTz7Lk7@mail.python.org> http://hg.python.org/cpython/rev/19a5fbb924b1 changeset: 83741:19a5fbb924b1 branch: 3.3 parent: 83740:da9c443e67ba parent: 83737:1c01571ce0f4 user: Georg Brandl date: Sun May 12 11:52:22 2013 +0200 summary: merge with 3.2 files: Lib/test/test_sax.py | 31 +++++++++++++++++++++++++++++ Lib/xml/sax/saxutils.py | 5 ++++ Misc/NEWS | 3 ++ 3 files changed, 39 insertions(+), 0 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 @@ -15,6 +15,7 @@ from xml.sax.handler import feature_namespaces from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl from io import BytesIO, StringIO +import codecs import os.path import shutil from test import support @@ -538,6 +539,34 @@ def getvalue(self): return b''.join(self) +class StreamWriterXmlgenTest(XmlgenTest, unittest.TestCase): + def ioclass(self): + raw = BytesIO() + writer = codecs.getwriter('ascii')(raw, 'xmlcharrefreplace') + writer.getvalue = raw.getvalue + return writer + + def xml(self, doc, encoding='iso-8859-1'): + return ('\n%s' % + (encoding, doc)).encode('ascii', 'xmlcharrefreplace') + +class StreamReaderWriterXmlgenTest(XmlgenTest, unittest.TestCase): + fname = support.TESTFN + '-codecs' + + def ioclass(self): + writer = codecs.open(self.fname, 'w', encoding='ascii', + errors='xmlcharrefreplace', buffering=0) + self.addCleanup(support.unlink, self.fname) + writer.getvalue = self.getvalue + return writer + + def getvalue(self): + with open(self.fname, 'rb') as f: + return f.read() + + def xml(self, doc, encoding='iso-8859-1'): + return ('\n%s' % + (encoding, doc)).encode('ascii', 'xmlcharrefreplace') start = b'\n' @@ -946,6 +975,8 @@ StringXmlgenTest, BytesXmlgenTest, WriterXmlgenTest, + StreamWriterXmlgenTest, + StreamReaderWriterXmlgenTest, ExpatReaderTest, ErrorReportingTest, XmlReaderTest) 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 @@ -5,6 +5,7 @@ import os, urllib.parse, urllib.request import io +import codecs from . import handler from . import xmlreader @@ -77,6 +78,10 @@ # use a text writer as is return out + if isinstance(out, (codecs.StreamWriter, codecs.StreamReaderWriter)): + # use a codecs stream writer as is + return out + # wrap a binary writer with TextIOWrapper if isinstance(out, io.RawIOBase): # Keep the original file open when the TextIOWrapper is diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -234,6 +234,9 @@ - Issue #6696: add documentation for the Profile objects, and improve profile/cProfile docs. Patch by Tom Pinckney. +- Issue #17915: Fix interoperability of xml.sax with file objects returned by + codecs.open(). + Build ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 12:47:28 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 12:47:28 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Back_out_patch?= =?utf-8?q?_for_=231159051=2C_which_caused_backwards_compatibility_problem?= =?utf-8?q?s=2E?= Message-ID: <3b7hgh4TRbz7Lkv@mail.python.org> http://hg.python.org/cpython/rev/9c2831fe84e9 changeset: 83742:9c2831fe84e9 branch: 3.3 user: Georg Brandl date: Sun May 12 11:57:26 2013 +0200 summary: Back out patch for #1159051, which caused backwards compatibility problems. files: Lib/gzip.py | 81 ++++++++++++++++-------------- Lib/test/test_bz2.py | 14 ----- Lib/test/test_gzip.py | 14 ----- Lib/test/test_lzma.py | 14 ----- Misc/NEWS | 3 - 5 files changed, 44 insertions(+), 82 deletions(-) diff --git a/Lib/gzip.py b/Lib/gzip.py --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -65,6 +65,9 @@ # or unsigned. output.write(struct.pack(" self.extrasize: - if not self._read(readsize): - if size > self.extrasize: - size = self.extrasize - break - readsize = min(self.max_read_chunk, readsize * 2) + try: + while size > self.extrasize: + self._read(readsize) + readsize = min(self.max_read_chunk, readsize * 2) + except EOFError: + if size > self.extrasize: + size = self.extrasize offset = self.offset - self.extrastart chunk = self.extrabuf[offset: offset + size] @@ -384,9 +386,12 @@ if self.extrasize <= 0 and self.fileobj is None: return b'' - # For certain input data, a single call to _read() may not return - # any data. In this case, retry until we get some data or reach EOF. - while self.extrasize <= 0 and self._read(): + try: + # For certain input data, a single call to _read() may not return + # any data. In this case, retry until we get some data or reach EOF. + while self.extrasize <= 0: + self._read() + except EOFError: pass if size < 0 or size > self.extrasize: size = self.extrasize @@ -409,9 +414,12 @@ if self.extrasize == 0: if self.fileobj is None: return b'' - # Ensure that we don't return b"" if we haven't reached EOF. - # 1024 is the same buffering heuristic used in read() - while self.extrasize == 0 and self._read(max(n, 1024)): + try: + # Ensure that we don't return b"" if we haven't reached EOF. + while self.extrasize == 0: + # 1024 is the same buffering heuristic used in read() + self._read(max(n, 1024)) + except EOFError: pass offset = self.offset - self.extrastart remaining = self.extrasize @@ -424,14 +432,13 @@ def _read(self, size=1024): if self.fileobj is None: - return False + raise EOFError("Reached EOF") if self._new_member: # If the _new_member flag is set, we have to # jump to the next member, if there is one. self._init_read() - if not self._read_gzip_header(): - return False + self._read_gzip_header() self.decompress = zlib.decompressobj(-zlib.MAX_WBITS) self._new_member = False @@ -448,7 +455,7 @@ self.fileobj.prepend(self.decompress.unused_data, True) self._read_eof() self._add_read_data( uncompress ) - return False + raise EOFError('Reached EOF') uncompress = self.decompress.decompress(buf) self._add_read_data( uncompress ) @@ -464,7 +471,6 @@ # a new member on the next call self._read_eof() self._new_member = True - return True def _add_read_data(self, data): self.crc = zlib.crc32(data, self.crc) & 0xffffffff @@ -479,7 +485,8 @@ # We check the that the computed CRC and size of the # uncompressed data matches the stored values. Note that the size # stored is the true file size mod 2**32. - crc32, isize = struct.unpack(" http://hg.python.org/cpython/rev/ca133fab2f8e changeset: 83743:ca133fab2f8e parent: 83731:e98cf2cec516 parent: 83741:19a5fbb924b1 user: Georg Brandl date: Sun May 12 12:08:05 2013 +0200 summary: merge with 3.3 files: Lib/test/test_sax.py | 31 +++++++++++++++++++++++++++++ Lib/xml/sax/saxutils.py | 5 ++++ Misc/NEWS | 9 ++++++++ 3 files changed, 45 insertions(+), 0 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 @@ -15,6 +15,7 @@ from xml.sax.handler import feature_namespaces from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl from io import BytesIO, StringIO +import codecs import os.path import shutil from test import support @@ -538,6 +539,34 @@ def getvalue(self): return b''.join(self) +class StreamWriterXmlgenTest(XmlgenTest, unittest.TestCase): + def ioclass(self): + raw = BytesIO() + writer = codecs.getwriter('ascii')(raw, 'xmlcharrefreplace') + writer.getvalue = raw.getvalue + return writer + + def xml(self, doc, encoding='iso-8859-1'): + return ('\n%s' % + (encoding, doc)).encode('ascii', 'xmlcharrefreplace') + +class StreamReaderWriterXmlgenTest(XmlgenTest, unittest.TestCase): + fname = support.TESTFN + '-codecs' + + def ioclass(self): + writer = codecs.open(self.fname, 'w', encoding='ascii', + errors='xmlcharrefreplace', buffering=0) + self.addCleanup(support.unlink, self.fname) + writer.getvalue = self.getvalue + return writer + + def getvalue(self): + with open(self.fname, 'rb') as f: + return f.read() + + def xml(self, doc, encoding='iso-8859-1'): + return ('\n%s' % + (encoding, doc)).encode('ascii', 'xmlcharrefreplace') start = b'\n' @@ -946,6 +975,8 @@ StringXmlgenTest, BytesXmlgenTest, WriterXmlgenTest, + StreamWriterXmlgenTest, + StreamReaderWriterXmlgenTest, ExpatReaderTest, ErrorReportingTest, XmlReaderTest) 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 @@ -5,6 +5,7 @@ import os, urllib.parse, urllib.request import io +import codecs from . import handler from . import xmlreader @@ -77,6 +78,10 @@ # use a text writer as is return out + if isinstance(out, (codecs.StreamWriter, codecs.StreamReaderWriter)): + # use a codecs stream writer as is + return out + # wrap a binary writer with TextIOWrapper if isinstance(out, io.RawIOBase): # Keep the original file open when the TextIOWrapper is diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -91,6 +91,9 @@ Library ------- +- Issue #17915: Fix interoperability of xml.sax with file objects returned by + codecs.open(). + - Issue #16601: Restarting iteration over tarfile no more continues from where it left off. Patch by Michael Birtwell. @@ -280,6 +283,12 @@ - Issue #17692: test_sqlite now works with unittest test discovery. Patch by Zachary Ware. + +Documentation +------------- + +- Issue #15940: Specify effect of locale on time functions. + - Issue #6696: add documentation for the Profile objects, and improve profile/cProfile docs. Patch by Tom Pinckney. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 12:47:31 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 12:47:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_null-merge_reversion_of_=231159051_patch_from_3=2E3?= Message-ID: <3b7hgl27DWzRQZ@mail.python.org> http://hg.python.org/cpython/rev/5400e8fbc1de changeset: 83744:5400e8fbc1de parent: 83743:ca133fab2f8e parent: 83742:9c2831fe84e9 user: Georg Brandl date: Sun May 12 12:08:30 2013 +0200 summary: null-merge reversion of #1159051 patch from 3.3 files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 12:47:32 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 12:47:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Closes_issue_?= =?utf-8?q?=2317732=3A_ignore_install-directory_specific_options_in?= Message-ID: <3b7hgm5bh1z7Ll0@mail.python.org> http://hg.python.org/cpython/rev/6c5a3d194a10 changeset: 83745:6c5a3d194a10 branch: 3.3 parent: 83742:9c2831fe84e9 user: Georg Brandl date: Sun May 12 12:36:07 2013 +0200 summary: Closes issue #17732: ignore install-directory specific options in distutils.cfg when a venv is active. files: Doc/install/index.rst | 5 + Doc/library/venv.rst | 4 + Lib/distutils/dist.py | 14 ++++- Lib/distutils/tests/test_dist.py | 64 +++++++++++++++++++- Misc/NEWS | 3 + 5 files changed, 87 insertions(+), 3 deletions(-) diff --git a/Doc/install/index.rst b/Doc/install/index.rst --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -645,6 +645,11 @@ the Distutils are the only ones you can use.) See section :ref:`inst-config-files` for details. +.. note:: When a :ref:`virtual environment ` is activated, any options + that change the installation path will be ignored from all distutils configuration + files to prevent inadvertently installing projects outside of the virtual + environment. + .. XXX need some Windows examples---when would custom installation schemes be needed on those platforms? diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -57,6 +57,10 @@ :attr:`sys.exec_prefix` is the same as :attr:`sys.base_exec_prefix` (they all point to a non-venv Python installation). + When a venv is active, any options that change the installation path will be + ignored from all distutils configuration files to prevent projects being + inadvertently installed outside of the virtual environment. + API --- diff --git a/Lib/distutils/dist.py b/Lib/distutils/dist.py --- a/Lib/distutils/dist.py +++ b/Lib/distutils/dist.py @@ -343,6 +343,18 @@ def parse_config_files(self, filenames=None): from configparser import ConfigParser + # Ignore install directory options if we have a venv + if sys.prefix != sys.base_prefix: + ignore_options = [ + 'install-base', 'install-platbase', 'install-lib', + 'install-platlib', 'install-purelib', 'install-headers', + 'install-scripts', 'install-data', 'prefix', 'exec-prefix', + 'home', 'user', 'root'] + else: + ignore_options = [] + + ignore_options = frozenset(ignore_options) + if filenames is None: filenames = self.find_config_files() @@ -359,7 +371,7 @@ opt_dict = self.get_option_dict(section) for opt in options: - if opt != '__name__': + if opt != '__name__' and opt not in ignore_options: val = parser.get(section,opt) opt = opt.replace('-', '_') opt_dict[opt] = (filename, val) diff --git a/Lib/distutils/tests/test_dist.py b/Lib/distutils/tests/test_dist.py --- a/Lib/distutils/tests/test_dist.py +++ b/Lib/distutils/tests/test_dist.py @@ -6,6 +6,8 @@ import warnings import textwrap +from unittest import mock + from distutils.dist import Distribution, fix_help_options from distutils.cmd import Command @@ -18,7 +20,7 @@ user_options = [ ("sample-option=", "S", "help text"), - ] + ] def initialize_options(self): self.sample_option = None @@ -77,6 +79,64 @@ self.assertIsInstance(cmd, test_dist) self.assertEqual(cmd.sample_option, "sometext") + def test_venv_install_options(self): + sys.argv.append("install") + self.addCleanup(os.unlink, TESTFN) + + fakepath = '/somedir' + + with open(TESTFN, "w") as f: + print(("[install]\n" + "install-base = {0}\n" + "install-platbase = {0}\n" + "install-lib = {0}\n" + "install-platlib = {0}\n" + "install-purelib = {0}\n" + "install-headers = {0}\n" + "install-scripts = {0}\n" + "install-data = {0}\n" + "prefix = {0}\n" + "exec-prefix = {0}\n" + "home = {0}\n" + "user = {0}\n" + "root = {0}").format(fakepath), file=f) + + # Base case: Not in a Virtual Environment + with mock.patch.multiple(sys, prefix='/a', base_prefix='/a') as values: + d = self.create_distribution([TESTFN]) + + option_tuple = (TESTFN, fakepath) + + result_dict = { + 'install_base': option_tuple, + 'install_platbase': option_tuple, + 'install_lib': option_tuple, + 'install_platlib': option_tuple, + 'install_purelib': option_tuple, + 'install_headers': option_tuple, + 'install_scripts': option_tuple, + 'install_data': option_tuple, + 'prefix': option_tuple, + 'exec_prefix': option_tuple, + 'home': option_tuple, + 'user': option_tuple, + 'root': option_tuple, + } + + self.assertEqual( + sorted(d.command_options.get('install').keys()), + sorted(result_dict.keys())) + + for (key, value) in d.command_options.get('install').items(): + self.assertEqual(value, result_dict[key]) + + # Test case: In a Virtual Environment + with mock.patch.multiple(sys, prefix='/a', base_prefix='/b') as values: + d = self.create_distribution([TESTFN]) + + for key in result_dict.keys(): + self.assertNotIn(key, d.command_options.get('install', {})) + def test_command_packages_configfile(self): sys.argv.append("build") self.addCleanup(os.unlink, TESTFN) @@ -304,7 +364,7 @@ os.environ['HOME'] = temp_dir files = dist.find_config_files() self.assertIn(user_filename, files, - '%r not found in %r' % (user_filename, files)) + '%r not found in %r' % (user_filename, files)) finally: os.remove(user_filename) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -49,6 +49,9 @@ Library ------- +- Issue #17732: Ignore distutils.cfg options pertaining to install paths if a + virtual environment is active. + - Issue #1159051: Back out a fix for handling corrupted gzip files that broke backwards compatibility. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 12:47:34 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 12:47:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge_with_3=2E3?= Message-ID: <3b7hgp24SBz7Lk9@mail.python.org> http://hg.python.org/cpython/rev/47752459be5b changeset: 83746:47752459be5b parent: 83744:5400e8fbc1de parent: 83745:6c5a3d194a10 user: Georg Brandl date: Sun May 12 12:37:12 2013 +0200 summary: merge with 3.3 files: Doc/install/index.rst | 5 + Doc/library/venv.rst | 4 + Lib/distutils/dist.py | 14 ++++- Lib/distutils/tests/test_dist.py | 64 +++++++++++++++++++- Misc/NEWS | 3 + 5 files changed, 87 insertions(+), 3 deletions(-) diff --git a/Doc/install/index.rst b/Doc/install/index.rst --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -645,6 +645,11 @@ the Distutils are the only ones you can use.) See section :ref:`inst-config-files` for details. +.. note:: When a :ref:`virtual environment ` is activated, any options + that change the installation path will be ignored from all distutils configuration + files to prevent inadvertently installing projects outside of the virtual + environment. + .. XXX need some Windows examples---when would custom installation schemes be needed on those platforms? diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -57,6 +57,10 @@ :attr:`sys.exec_prefix` is the same as :attr:`sys.base_exec_prefix` (they all point to a non-venv Python installation). + When a venv is active, any options that change the installation path will be + ignored from all distutils configuration files to prevent projects being + inadvertently installed outside of the virtual environment. + API --- diff --git a/Lib/distutils/dist.py b/Lib/distutils/dist.py --- a/Lib/distutils/dist.py +++ b/Lib/distutils/dist.py @@ -343,6 +343,18 @@ def parse_config_files(self, filenames=None): from configparser import ConfigParser + # Ignore install directory options if we have a venv + if sys.prefix != sys.base_prefix: + ignore_options = [ + 'install-base', 'install-platbase', 'install-lib', + 'install-platlib', 'install-purelib', 'install-headers', + 'install-scripts', 'install-data', 'prefix', 'exec-prefix', + 'home', 'user', 'root'] + else: + ignore_options = [] + + ignore_options = frozenset(ignore_options) + if filenames is None: filenames = self.find_config_files() @@ -359,7 +371,7 @@ opt_dict = self.get_option_dict(section) for opt in options: - if opt != '__name__': + if opt != '__name__' and opt not in ignore_options: val = parser.get(section,opt) opt = opt.replace('-', '_') opt_dict[opt] = (filename, val) diff --git a/Lib/distutils/tests/test_dist.py b/Lib/distutils/tests/test_dist.py --- a/Lib/distutils/tests/test_dist.py +++ b/Lib/distutils/tests/test_dist.py @@ -6,6 +6,8 @@ import warnings import textwrap +from unittest import mock + from distutils.dist import Distribution, fix_help_options from distutils.cmd import Command @@ -18,7 +20,7 @@ user_options = [ ("sample-option=", "S", "help text"), - ] + ] def initialize_options(self): self.sample_option = None @@ -77,6 +79,64 @@ self.assertIsInstance(cmd, test_dist) self.assertEqual(cmd.sample_option, "sometext") + def test_venv_install_options(self): + sys.argv.append("install") + self.addCleanup(os.unlink, TESTFN) + + fakepath = '/somedir' + + with open(TESTFN, "w") as f: + print(("[install]\n" + "install-base = {0}\n" + "install-platbase = {0}\n" + "install-lib = {0}\n" + "install-platlib = {0}\n" + "install-purelib = {0}\n" + "install-headers = {0}\n" + "install-scripts = {0}\n" + "install-data = {0}\n" + "prefix = {0}\n" + "exec-prefix = {0}\n" + "home = {0}\n" + "user = {0}\n" + "root = {0}").format(fakepath), file=f) + + # Base case: Not in a Virtual Environment + with mock.patch.multiple(sys, prefix='/a', base_prefix='/a') as values: + d = self.create_distribution([TESTFN]) + + option_tuple = (TESTFN, fakepath) + + result_dict = { + 'install_base': option_tuple, + 'install_platbase': option_tuple, + 'install_lib': option_tuple, + 'install_platlib': option_tuple, + 'install_purelib': option_tuple, + 'install_headers': option_tuple, + 'install_scripts': option_tuple, + 'install_data': option_tuple, + 'prefix': option_tuple, + 'exec_prefix': option_tuple, + 'home': option_tuple, + 'user': option_tuple, + 'root': option_tuple, + } + + self.assertEqual( + sorted(d.command_options.get('install').keys()), + sorted(result_dict.keys())) + + for (key, value) in d.command_options.get('install').items(): + self.assertEqual(value, result_dict[key]) + + # Test case: In a Virtual Environment + with mock.patch.multiple(sys, prefix='/a', base_prefix='/b') as values: + d = self.create_distribution([TESTFN]) + + for key in result_dict.keys(): + self.assertNotIn(key, d.command_options.get('install', {})) + def test_command_packages_configfile(self): sys.argv.append("build") self.addCleanup(os.unlink, TESTFN) @@ -304,7 +364,7 @@ os.environ['HOME'] = temp_dir files = dist.find_config_files() self.assertIn(user_filename, files, - '%r not found in %r' % (user_filename, files)) + '%r not found in %r' % (user_filename, files)) finally: os.remove(user_filename) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -91,6 +91,9 @@ Library ------- +- Issue #17732: Ignore distutils.cfg options pertaining to install paths if a + virtual environment is active. + - Issue #17915: Fix interoperability of xml.sax with file objects returned by codecs.open(). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 16:32:49 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 12 May 2013 16:32:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3NjA2?= =?utf-8?q?=3A_Fixed_support_of_encoded_byte_strings_in_the_XMLGenerator?= Message-ID: <3b7ngj6BHkz7LkN@mail.python.org> http://hg.python.org/cpython/rev/a32a3b79f5e8 changeset: 83747:a32a3b79f5e8 branch: 2.7 parent: 83727:f420a9ea4f25 user: Serhiy Storchaka date: Sun May 12 17:29:34 2013 +0300 summary: Issue #17606: Fixed support of encoded byte strings in the XMLGenerator characters() and ignorableWhitespace() methods. Original patch by Sebastian Ortiz Vasquez. files: Lib/test/test_sax.py | 20 ++++++++++++++++++++ Lib/xml/sax/saxutils.py | 8 ++++++-- Misc/ACKS | 1 + Misc/NEWS | 4 ++++ 4 files changed, 31 insertions(+), 2 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 @@ -284,6 +284,26 @@ self.assertEqual(result.getvalue(), start + " ") + def test_xmlgen_encoding_bytes(self): + encodings = ('iso-8859-15', 'utf-8', + 'utf-16be', 'utf-16le', + 'utf-32be', 'utf-32le') + for encoding in encodings: + result = self.ioclass() + gen = XMLGenerator(result, encoding=encoding) + + gen.startDocument() + gen.startElement("doc", {"a": u'\u20ac'}) + gen.characters(u"\u20ac".encode(encoding)) + gen.ignorableWhitespace(" ".encode(encoding)) + gen.endElement("doc") + gen.endDocument() + + self.assertEqual(result.getvalue(), ( + u'\n' + u'\u20ac ' % encoding + ).encode(encoding, 'xmlcharrefreplace')) + def test_xmlgen_ns(self): result = self.ioclass() gen = XMLGenerator(result) 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 @@ -180,10 +180,14 @@ self._write(u'' % self._qname(name)) def characters(self, content): - self._write(escape(unicode(content))) + if not isinstance(content, unicode): + content = unicode(content, self._encoding) + self._write(escape(content)) def ignorableWhitespace(self, content): - self._write(unicode(content)) + if not isinstance(content, unicode): + content = unicode(content, self._encoding) + self._write(content) def processingInstruction(self, target, data): self._write(u'' % (target, data)) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1045,6 +1045,7 @@ Kyle VanderBeek Atul Varma Dmitry Vasiliev +Sebastian Ortiz Vasquez Alexandre Vassalotti Frank Vercruesse Mike Verdone diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -38,6 +38,10 @@ Library ------- +- Issue #17606: Fixed support of encoded byte strings in the XMLGenerator + .characters() and ignorableWhitespace() methods. Original patch by Sebastian + Ortiz Vasquez. + - Issue #16601: Restarting iteration over tarfile no more continues from where it left off. Patch by Michael Birtwell. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 16:32:51 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 12 May 2013 16:32:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3NjA2?= =?utf-8?q?=3A_Fixed_support_of_encoded_byte_strings_in_the_XMLGenerator?= Message-ID: <3b7ngl1SFLz7Lkw@mail.python.org> http://hg.python.org/cpython/rev/e730447caf20 changeset: 83748:e730447caf20 branch: 3.3 parent: 83745:6c5a3d194a10 user: Serhiy Storchaka date: Sun May 12 17:31:16 2013 +0300 summary: Issue #17606: Fixed support of encoded byte strings in the XMLGenerator characters() and ignorableWhitespace() methods. Original patch by Sebastian Ortiz Vasquez. files: Lib/test/test_sax.py | 18 ++++++++++++++++++ Lib/xml/sax/saxutils.py | 4 ++++ Misc/ACKS | 1 + Misc/NEWS | 4 ++++ 4 files changed, 27 insertions(+), 0 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 @@ -319,6 +319,24 @@ self.assertEqual(result.getvalue(), self.xml(" ")) + def test_xmlgen_encoding_bytes(self): + encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig', + 'utf-16', 'utf-16be', 'utf-16le', + 'utf-32', 'utf-32be', 'utf-32le') + for encoding in encodings: + result = self.ioclass() + gen = XMLGenerator(result, encoding=encoding) + + gen.startDocument() + gen.startElement("doc", {"a": '\u20ac'}) + gen.characters("\u20ac".encode(encoding)) + gen.ignorableWhitespace(" ".encode(encoding)) + gen.endElement("doc") + gen.endDocument() + + self.assertEqual(result.getvalue(), + self.xml('\u20ac ', encoding=encoding)) + def test_xmlgen_ns(self): result = self.ioclass() gen = XMLGenerator(result) 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 @@ -209,11 +209,15 @@ def characters(self, content): if content: self._finish_pending_start_element() + if not isinstance(content, str): + content = str(content, self._encoding) self._write(escape(content)) def ignorableWhitespace(self, content): if content: self._finish_pending_start_element() + if not isinstance(content, str): + content = str(content, self._encoding) self._write(content) def processingInstruction(self, target, data): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1254,6 +1254,7 @@ Andrew Vant Atul Varma Dmitry Vasiliev +Sebastian Ortiz Vasquez Alexandre Vassalotti Nadeem Vawda Frank Vercruesse diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -49,6 +49,10 @@ Library ------- +- Issue #17606: Fixed support of encoded byte strings in the XMLGenerator + .characters() and ignorableWhitespace() methods. Original patch by Sebastian + Ortiz Vasquez. + - Issue #17732: Ignore distutils.cfg options pertaining to install paths if a virtual environment is active. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 16:32:52 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 12 May 2013 16:32:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317606=3A_Fixed_support_of_encoded_byte_strings_?= =?utf-8?q?in_the_XMLGenerator?= Message-ID: <3b7ngm3pNCz7LkY@mail.python.org> http://hg.python.org/cpython/rev/00afa5350f6a changeset: 83749:00afa5350f6a parent: 83746:47752459be5b parent: 83748:e730447caf20 user: Serhiy Storchaka date: Sun May 12 17:31:59 2013 +0300 summary: Issue #17606: Fixed support of encoded byte strings in the XMLGenerator characters() and ignorableWhitespace() methods. Original patch by Sebastian Ortiz Vasquez. files: Lib/test/test_sax.py | 18 ++++++++++++++++++ Lib/xml/sax/saxutils.py | 4 ++++ Misc/ACKS | 1 + Misc/NEWS | 4 ++++ 4 files changed, 27 insertions(+), 0 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 @@ -319,6 +319,24 @@ self.assertEqual(result.getvalue(), self.xml(" ")) + def test_xmlgen_encoding_bytes(self): + encodings = ('iso-8859-15', 'utf-8', 'utf-8-sig', + 'utf-16', 'utf-16be', 'utf-16le', + 'utf-32', 'utf-32be', 'utf-32le') + for encoding in encodings: + result = self.ioclass() + gen = XMLGenerator(result, encoding=encoding) + + gen.startDocument() + gen.startElement("doc", {"a": '\u20ac'}) + gen.characters("\u20ac".encode(encoding)) + gen.ignorableWhitespace(" ".encode(encoding)) + gen.endElement("doc") + gen.endDocument() + + self.assertEqual(result.getvalue(), + self.xml('\u20ac ', encoding=encoding)) + def test_xmlgen_ns(self): result = self.ioclass() gen = XMLGenerator(result) 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 @@ -209,11 +209,15 @@ def characters(self, content): if content: self._finish_pending_start_element() + if not isinstance(content, str): + content = str(content, self._encoding) self._write(escape(content)) def ignorableWhitespace(self, content): if content: self._finish_pending_start_element() + if not isinstance(content, str): + content = str(content, self._encoding) self._write(content) def processingInstruction(self, target, data): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1281,6 +1281,7 @@ Andrew Vant Atul Varma Dmitry Vasiliev +Sebastian Ortiz Vasquez Alexandre Vassalotti Nadeem Vawda Frank Vercruesse diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -91,6 +91,10 @@ Library ------- +- Issue #17606: Fixed support of encoded byte strings in the XMLGenerator + .characters() and ignorableWhitespace() methods. Original patch by Sebastian + Ortiz Vasquez. + - Issue #17732: Ignore distutils.cfg options pertaining to install paths if a virtual environment is active. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 19:55:19 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 19:55:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogYnVtcCB0byAzLjMu?= =?utf-8?q?2?= Message-ID: <3b7t9M4bCsz7Ll4@mail.python.org> http://hg.python.org/cpython/rev/0934c5818417 changeset: 83750:0934c5818417 branch: 3.3 parent: 83745:6c5a3d194a10 user: Georg Brandl date: Sun May 12 12:51:38 2013 +0200 summary: bump to 3.3.2 files: Include/patchlevel.h | 4 ++-- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/NEWS | 6 +++--- Misc/RPM/python-3.3.spec | 2 +- README | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -18,12 +18,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 3 -#define PY_MICRO_VERSION 1 +#define PY_MICRO_VERSION 2 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.3.1+" +#define PY_VERSION "3.3.2" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -13,5 +13,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.3.1" +__version__ = "3.3.2" #--end constants-- diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1,1 +1,1 @@ -IDLE_VERSION = "3.3.1" +IDLE_VERSION = "3.3.2" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -5,9 +5,9 @@ What's New in Python 3.3.2? =========================== -.. *Release date: XXXX-XX-XX* - -*Not yet released, see sections below for changes released in 3.3.1* +*Release date: 13-May-2013* + +.. *Not yet released, see sections below for changes released in 3.3.1* Core and Builtins ----------------- diff --git a/Misc/RPM/python-3.3.spec b/Misc/RPM/python-3.3.spec --- a/Misc/RPM/python-3.3.spec +++ b/Misc/RPM/python-3.3.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 3.3.1 +%define version 3.3.2 %define libvers 3.3 #--end constants-- %define release 1pydotorg diff --git a/README b/README --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Python version 3.3.1 +This is Python version 3.3.2 ============================ Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 19:55:21 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 19:55:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAobWVyZ2UgMy4zIC0+IDMuMyk6?= =?utf-8?q?_merge?= Message-ID: <3b7t9P4CRPz7Lks@mail.python.org> http://hg.python.org/cpython/rev/8ae3baa76b75 changeset: 83751:8ae3baa76b75 branch: 3.3 parent: 83748:e730447caf20 parent: 83750:0934c5818417 user: Georg Brandl date: Sun May 12 19:44:21 2013 +0200 summary: merge files: Include/patchlevel.h | 4 ++-- Lib/distutils/__init__.py | 2 +- Lib/idlelib/idlever.py | 2 +- Misc/NEWS | 6 +++--- Misc/RPM/python-3.3.spec | 2 +- README | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -18,12 +18,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 3 -#define PY_MICRO_VERSION 1 +#define PY_MICRO_VERSION 2 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.3.1+" +#define PY_VERSION "3.3.2" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/distutils/__init__.py b/Lib/distutils/__init__.py --- a/Lib/distutils/__init__.py +++ b/Lib/distutils/__init__.py @@ -13,5 +13,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.3.1" +__version__ = "3.3.2" #--end constants-- diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py --- a/Lib/idlelib/idlever.py +++ b/Lib/idlelib/idlever.py @@ -1,1 +1,1 @@ -IDLE_VERSION = "3.3.1" +IDLE_VERSION = "3.3.2" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -5,9 +5,9 @@ What's New in Python 3.3.2? =========================== -.. *Release date: XXXX-XX-XX* - -*Not yet released, see sections below for changes released in 3.3.1* +*Release date: 13-May-2013* + +.. *Not yet released, see sections below for changes released in 3.3.1* Core and Builtins ----------------- diff --git a/Misc/RPM/python-3.3.spec b/Misc/RPM/python-3.3.spec --- a/Misc/RPM/python-3.3.spec +++ b/Misc/RPM/python-3.3.spec @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 3.3.1 +%define version 3.3.2 %define libvers 3.3 #--end constants-- %define release 1pydotorg diff --git a/README b/README --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is Python version 3.3.1 +This is Python version 3.3.2 ============================ Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 19:55:23 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 19:55:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogQ2xvc2VzICMxNzk2?= =?utf-8?q?2=3A_Build_with_OpenSSL_1=2E0=2E1e_on_Windows=2E?= Message-ID: <3b7t9R2Rrpz7LlH@mail.python.org> http://hg.python.org/cpython/rev/d047928ae3f6 changeset: 83752:d047928ae3f6 branch: 3.3 tag: v3.3.2 user: Georg Brandl date: Sun May 12 19:50:34 2013 +0200 summary: Closes #17962: Build with OpenSSL 1.0.1e on Windows. files: Misc/NEWS | 2 ++ PC/VC6/readme.txt | 4 ++-- PC/VS8.0/pyproject.vsprops | 2 +- PC/VS9.0/pyproject.vsprops | 2 +- PCbuild/pyproject.props | 2 +- PCbuild/readme.txt | 2 +- Tools/buildbot/external-common.bat | 8 ++++---- 7 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -250,6 +250,8 @@ - Issue #17547: In configure, explicitly pass -Wformat for the benefit for GCC 4.8. +- Issue #17962: Build with OpenSSL 1.0.1e on Windows. + What's New in Python 3.3.1? =========================== diff --git a/PC/VC6/readme.txt b/PC/VC6/readme.txt --- a/PC/VC6/readme.txt +++ b/PC/VC6/readme.txt @@ -153,9 +153,9 @@ Unpack into the "dist" directory, retaining the folder name from the archive - for example, the latest stable OpenSSL will install as - dist/openssl-1.0.1d + dist/openssl-1.0.1e - You need to use version 1.0.1d of OpenSSL. + You need to use version 1.0.1e of OpenSSL. You can install the NASM assembler from http://www.nasm.us/ diff --git a/PC/VS8.0/pyproject.vsprops b/PC/VS8.0/pyproject.vsprops --- a/PC/VS8.0/pyproject.vsprops +++ b/PC/VS8.0/pyproject.vsprops @@ -58,7 +58,7 @@ /> $(externalsDir)\sqlite-3.7.12 $(externalsDir)\bzip2-1.0.6 $(externalsDir)\xz-5.0.3 - $(externalsDir)\openssl-1.0.1d + $(externalsDir)\openssl-1.0.1e $(externalsDir)\tcltk $(externalsDir)\tcltk64 $(tcltkDir)\lib\tcl85.lib;$(tcltkDir)\lib\tk85.lib diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -142,7 +142,7 @@ Get the source code through - svn export http://svn.python.org/projects/external/openssl-1.0.1d + svn export http://svn.python.org/projects/external/openssl-1.0.1e ** NOTE: if you use the Tools\buildbot\external(-amd64).bat approach for obtaining external sources then you don't need to manually get the source 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 @@ -14,7 +14,7 @@ @rem if exist tk8.4.16 rd /s/q tk8.4.16 @rem if exist tk-8.4.18.1 rd /s/q tk-8.4.18.1 @rem if exist db-4.4.20 rd /s/q db-4.4.20 - at rem if exist openssl-1.0.1d rd /s/q openssl-1.0.1d + at rem if exist openssl-1.0.1e rd /s/q openssl-1.0.1e @rem if exist sqlite-3.7.12 rd /s/q sqlite-3.7.12 @rem bzip @@ -24,9 +24,9 @@ ) @rem OpenSSL -if not exist openssl-1.0.1d ( - rd /s/q openssl-1.0.1c - svn export http://svn.python.org/projects/external/openssl-1.0.1d +if not exist openssl-1.0.1e ( + rd /s/q openssl-1.0.1d + svn export http://svn.python.org/projects/external/openssl-1.0.1e ) @rem tcl/tk -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 19:55:24 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 19:55:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Added_tag_v3?= =?utf-8?q?=2E3=2E2_for_changeset_d047928ae3f6?= Message-ID: <3b7t9S64j6z7Llf@mail.python.org> http://hg.python.org/cpython/rev/f4345201048f changeset: 83753:f4345201048f branch: 3.3 user: Georg Brandl date: Sun May 12 19:55:55 2013 +0200 summary: Added tag v3.3.2 for changeset d047928ae3f6 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -113,3 +113,4 @@ bd8afb90ebf28ba4edc901d4a235f75e7bbc79fd v3.3.0 92c2cfb924055ce68c4f78f836dcfe688437ceb8 v3.3.1rc1 d9893d13c6289aa03d33559ec67f97dcbf5c9e3c v3.3.1 +d047928ae3f6314a13b6137051315453d0ae89b6 v3.3.2 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 12 19:56:43 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 12 May 2013 19:56:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge_with_3=2E3?= Message-ID: <3b7tBz3FNGz7Lks@mail.python.org> http://hg.python.org/cpython/rev/2626a8bb7615 changeset: 83754:2626a8bb7615 parent: 83749:00afa5350f6a parent: 83753:f4345201048f user: Georg Brandl date: Sun May 12 19:57:26 2013 +0200 summary: merge with 3.3 files: .hgtags | 1 + PC/VS9.0/pyproject.vsprops | 2 +- PCbuild/pyproject.props | 2 +- PCbuild/readme.txt | 2 +- Tools/buildbot/external-common.bat | 8 ++++---- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -113,3 +113,4 @@ bd8afb90ebf28ba4edc901d4a235f75e7bbc79fd v3.3.0 92c2cfb924055ce68c4f78f836dcfe688437ceb8 v3.3.1rc1 d9893d13c6289aa03d33559ec67f97dcbf5c9e3c v3.3.1 +d047928ae3f6314a13b6137051315453d0ae89b6 v3.3.2 diff --git a/PC/VS9.0/pyproject.vsprops b/PC/VS9.0/pyproject.vsprops --- a/PC/VS9.0/pyproject.vsprops +++ b/PC/VS9.0/pyproject.vsprops @@ -62,7 +62,7 @@ /> $(externalsDir)\sqlite-3.7.12 $(externalsDir)\bzip2-1.0.6 $(externalsDir)\xz-5.0.3 - $(externalsDir)\openssl-1.0.1d + $(externalsDir)\openssl-1.0.1e $(externalsDir)\tcltk $(externalsDir)\tcltk64 $(tcltkDir)\lib\tcl85.lib;$(tcltkDir)\lib\tk85.lib diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -142,7 +142,7 @@ Get the source code through - svn export http://svn.python.org/projects/external/openssl-1.0.1d + svn export http://svn.python.org/projects/external/openssl-1.0.1e ** NOTE: if you use the Tools\buildbot\external(-amd64).bat approach for obtaining external sources then you don't need to manually get the source 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 @@ -14,7 +14,7 @@ @rem if exist tk8.4.16 rd /s/q tk8.4.16 @rem if exist tk-8.4.18.1 rd /s/q tk-8.4.18.1 @rem if exist db-4.4.20 rd /s/q db-4.4.20 - at rem if exist openssl-1.0.1d rd /s/q openssl-1.0.1d + at rem if exist openssl-1.0.1e rd /s/q openssl-1.0.1e @rem if exist sqlite-3.7.12 rd /s/q sqlite-3.7.12 @rem bzip @@ -24,9 +24,9 @@ ) @rem OpenSSL -if not exist openssl-1.0.1d ( - rd /s/q openssl-1.0.1c - svn export http://svn.python.org/projects/external/openssl-1.0.1d +if not exist openssl-1.0.1e ( + rd /s/q openssl-1.0.1d + svn export http://svn.python.org/projects/external/openssl-1.0.1e ) @rem tcl/tk -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 13 01:18:17 2013 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 13 May 2013 01:18:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_when_an_argument_is_a_cell?= =?utf-8?q?=2C_set_the_local_copy_to_NULL_=28see_=2317927=29?= Message-ID: <3b81L10Nh3z7LmB@mail.python.org> http://hg.python.org/cpython/rev/f6223bab5657 changeset: 83755:f6223bab5657 user: Benjamin Peterson date: Sun May 12 18:16:06 2013 -0500 summary: when an argument is a cell, set the local copy to NULL (see #17927) files: Lib/test/test_super.py | 13 +++++++++++++ Objects/typeobject.c | 14 +++++++++++--- Python/ceval.c | 12 ++++-------- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Lib/test/test_super.py b/Lib/test/test_super.py --- a/Lib/test/test_super.py +++ b/Lib/test/test_super.py @@ -130,6 +130,19 @@ super() self.assertRaises(RuntimeError, X().f) + def test_cell_as_self(self): + class X: + def meth(self): + super() + + def f(): + k = X() + def g(): + return k + return g + c = f().__closure__[0] + self.assertRaises(TypeError, X.meth, c) + def test_main(): support.run_unittest(TestSuper) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6510,9 +6510,17 @@ return -1; } obj = f->f_localsplus[0]; - if (obj != NULL && PyCell_Check(obj)) { - /* It might be a cell. See cell var initialization in ceval.c. */ - obj = PyCell_GET(obj); + if (obj == NULL && co->co_cell2arg) { + /* The first argument might be a cell. */ + n = PyTuple_GET_SIZE(co->co_cellvars); + for (i = 0; i < n; i++) { + if (co->co_cell2arg[i] == 0) { + PyObject *cell = f->f_localsplus[co->co_nlocals + i]; + assert(PyCell_Check(cell)); + obj = PyCell_GET(cell); + break; + } + } } if (obj == NULL) { PyErr_SetString(PyExc_RuntimeError, diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3521,18 +3521,14 @@ if (co->co_cell2arg != NULL && (arg = co->co_cell2arg[i]) != CO_CELL_NOT_AN_ARG) { c = PyCell_New(GETLOCAL(arg)); - if (c == NULL) - goto fail; - /* Reference the cell from the argument slot, for super(). - See typeobject.c. */ - Py_INCREF(c); - SETLOCAL(arg, c); + /* Clear the local copy. */ + SETLOCAL(arg, NULL); } else { c = PyCell_New(NULL); - if (c == NULL) - goto fail; } + if (c == NULL) + goto fail; SETLOCAL(co->co_nlocals + i, c); } for (i = 0; i < PyTuple_GET_SIZE(co->co_freevars); ++i) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 13 02:02:45 2013 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 13 May 2013 02:02:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_use_correct_fo?= =?utf-8?q?rmat_code_for_exceptions?= Message-ID: <3b82KK5cc0z7LmP@mail.python.org> http://hg.python.org/cpython/rev/27e470952085 changeset: 83756:27e470952085 branch: 3.3 parent: 83753:f4345201048f user: Benjamin Peterson date: Sun May 12 19:01:52 2013 -0500 summary: use correct format code for exceptions files: Lib/urllib/request.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -2294,7 +2294,7 @@ conn, retrlen = self.ftp.ntransfercmd(cmd) except ftplib.error_perm as reason: if str(reason)[:3] != '550': - raise URLError('ftp error: %d' % reason).with_traceback( + raise URLError('ftp error: %r' % reason).with_traceback( sys.exc_info()[2]) if not conn: # Set transfer mode to ASCII! @@ -2306,7 +2306,7 @@ try: self.ftp.cwd(file) except ftplib.error_perm as reason: - raise URLError('ftp error: %d' % reason) from reason + raise URLError('ftp error: %r' % reason) from reason finally: self.ftp.cwd(pwd) cmd = 'LIST ' + file -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 13 02:02:47 2013 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 13 May 2013 02:02:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3b82KM0dGbz7Lmk@mail.python.org> http://hg.python.org/cpython/rev/b0f8918399df changeset: 83757:b0f8918399df parent: 83755:f6223bab5657 parent: 83756:27e470952085 user: Benjamin Peterson date: Sun May 12 19:02:05 2013 -0500 summary: merge 3.3 files: Lib/urllib/request.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -2324,7 +2324,7 @@ conn, retrlen = self.ftp.ntransfercmd(cmd) except ftplib.error_perm as reason: if str(reason)[:3] != '550': - raise URLError('ftp error: %d' % reason).with_traceback( + raise URLError('ftp error: %r' % reason).with_traceback( sys.exc_info()[2]) if not conn: # Set transfer mode to ASCII! @@ -2336,7 +2336,7 @@ try: self.ftp.cwd(file) except ftplib.error_perm as reason: - raise URLError('ftp error: %d' % reason) from reason + raise URLError('ftp error: %r' % reason) from reason finally: self.ftp.cwd(pwd) cmd = 'LIST ' + file -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 13 06:08:41 2013 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 13 May 2013 06:08:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_remove_support_GCC_PyArg?= =?utf-8?q?=5FParseTuple_format_patch=2C_last_seen_in_2006?= Message-ID: <3b87n51nSqz7Lnk@mail.python.org> http://hg.python.org/cpython/rev/6eab274d3e34 changeset: 83758:6eab274d3e34 user: Benjamin Peterson date: Sun May 12 23:08:28 2013 -0500 summary: remove support GCC PyArg_ParseTuple format patch, last seen in 2006 files: Include/modsupport.h | 2 +- Include/pyport.h | 9 ------- configure | 38 -------------------------------- configure.ac | 18 --------------- pyconfig.h.in | 3 -- 5 files changed, 1 insertions(+), 69 deletions(-) diff --git a/Include/modsupport.h b/Include/modsupport.h --- a/Include/modsupport.h +++ b/Include/modsupport.h @@ -26,7 +26,7 @@ /* Due to a glitch in 3.2, the _SizeT versions weren't exported from the DLL. */ #if !defined(PY_SSIZE_T_CLEAN) || !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000 PyAPI_FUNC(int) PyArg_Parse(PyObject *, const char *, ...); -PyAPI_FUNC(int) PyArg_ParseTuple(PyObject *, const char *, ...) Py_FORMAT_PARSETUPLE(PyArg_ParseTuple, 2, 3); +PyAPI_FUNC(int) PyArg_ParseTuple(PyObject *, const char *, ...); PyAPI_FUNC(int) PyArg_ParseTupleAndKeywords(PyObject *, PyObject *, const char *, char **, ...); PyAPI_FUNC(int) PyArg_ValidateKeywordArguments(PyObject *); diff --git a/Include/pyport.h b/Include/pyport.h --- a/Include/pyport.h +++ b/Include/pyport.h @@ -832,15 +832,6 @@ #endif /* - * Add PyArg_ParseTuple format where available. - */ -#ifdef HAVE_ATTRIBUTE_FORMAT_PARSETUPLE -#define Py_FORMAT_PARSETUPLE(func,p1,p2) __attribute__((format(func,p1,p2))) -#else -#define Py_FORMAT_PARSETUPLE(func,p1,p2) -#endif - -/* * Specify alignment on compilers that support it. */ #if defined(__GNUC__) && __GNUC__ >= 3 diff --git a/configure b/configure --- a/configure +++ b/configure @@ -6523,44 +6523,6 @@ BASECFLAGS="$BASECFLAGS $ac_arch_flags" fi -# Check whether GCC supports PyArg_ParseTuple format -if test "$GCC" = "yes" -then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gcc supports ParseTuple __format__" >&5 -$as_echo_n "checking whether gcc supports ParseTuple __format__... " >&6; } - save_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -Werror -Wformat" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - void f(char*,...)__attribute((format(PyArg_ParseTuple, 1, 2))); -int -main () -{ - - ; - return 0; -} - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - - -$as_echo "#define HAVE_ATTRIBUTE_FORMAT_PARSETUPLE 1" >>confdefs.h - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - -else - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS=$save_CFLAGS -fi - # On some compilers, pthreads are available without further options # (e.g. MacOS X). On some of these systems, the compiler will not # complain if unaccepted options are passed (e.g. gcc on Mac OS X). diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -1328,24 +1328,6 @@ BASECFLAGS="$BASECFLAGS $ac_arch_flags" fi -# Check whether GCC supports PyArg_ParseTuple format -if test "$GCC" = "yes" -then - AC_MSG_CHECKING(whether gcc supports ParseTuple __format__) - save_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -Werror -Wformat" - AC_COMPILE_IFELSE([ - AC_LANG_PROGRAM([[void f(char*,...)__attribute((format(PyArg_ParseTuple, 1, 2)));]], [[]]) - ],[ - AC_DEFINE(HAVE_ATTRIBUTE_FORMAT_PARSETUPLE, 1, - [Define if GCC supports __attribute__((format(PyArg_ParseTuple, 2, 3)))]) - AC_MSG_RESULT(yes) - ],[ - AC_MSG_RESULT(no) - ]) - CFLAGS=$save_CFLAGS -fi - # On some compilers, pthreads are available without further options # (e.g. MacOS X). On some of these systems, the compiler will not # complain if unaccepted options are passed (e.g. gcc on Mac OS X). diff --git a/pyconfig.h.in b/pyconfig.h.in --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -61,9 +61,6 @@ /* Define to 1 if you have the `atanh' function. */ #undef HAVE_ATANH -/* Define if GCC supports __attribute__((format(PyArg_ParseTuple, 2, 3))) */ -#undef HAVE_ATTRIBUTE_FORMAT_PARSETUPLE - /* Define to 1 if you have the `bind_textdomain_codeset' function. */ #undef HAVE_BIND_TEXTDOMAIN_CODESET -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon May 13 06:11:42 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 13 May 2013 06:11:42 +0200 Subject: [Python-checkins] Daily reference leaks (b0f8918399df): sum=4 Message-ID: results for b0f8918399df on branch "default" -------------------------------------------- test_unittest leaked [-1, 2, 1] memory blocks, sum=2 test_multiprocessing leaked [-1, 2, 1] memory blocks, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogRFOqnC', '-x'] From root at python.org Mon May 13 19:30:22 2013 From: root at python.org (Cron Daemon) Date: Mon, 13 May 2013 19:30:22 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: abort: error: Connection timed out From root at python.org Mon May 13 19:35:22 2013 From: root at python.org (Cron Daemon) Date: Mon, 13 May 2013 19:35:22 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: abort: error: Connection timed out From root at python.org Mon May 13 19:40:22 2013 From: root at python.org (Cron Daemon) Date: Mon, 13 May 2013 19:40:22 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: abort: error: Connection timed out From python-checkins at python.org Mon May 13 19:48:58 2013 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 13 May 2013 19:48:58 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3OTY4?= =?utf-8?q?=3A_Fix_memory_leak_in_os=2Elistxattr=28=29=2E?= Message-ID: <3b8TzZ4b1SzS35@mail.python.org> http://hg.python.org/cpython/rev/2187cf880e5b changeset: 83759:2187cf880e5b branch: 3.3 parent: 83756:27e470952085 user: Antoine Pitrou date: Mon May 13 19:46:29 2013 +0200 summary: Issue #17968: Fix memory leak in os.listxattr(). files: Misc/NEWS | 4 +++- Modules/posixmodule.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -49,8 +49,10 @@ Library ------- +- Issue #17968: Fix memory leak in os.listxattr(). + - Issue #17606: Fixed support of encoded byte strings in the XMLGenerator - .characters() and ignorableWhitespace() methods. Original patch by Sebastian + characters() and ignorableWhitespace() methods. Original patch by Sebastian Ortiz Vasquez. - Issue #17732: Ignore distutils.cfg options pertaining to install paths if a diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -10625,8 +10625,10 @@ Py_END_ALLOW_THREADS; if (length < 0) { - if (errno == ERANGE) + if (errno == ERANGE) { + PyMem_FREE(buffer); continue; + } path_error("listxattr", &path); break; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 13 19:49:00 2013 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 13 May 2013 19:49:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317968=3A_Fix_memory_leak_in_os=2Elistxattr=28?= =?utf-8?b?KS4=?= Message-ID: <3b8Tzc0zgRz7Ljd@mail.python.org> http://hg.python.org/cpython/rev/1fa1a021ed23 changeset: 83760:1fa1a021ed23 parent: 83758:6eab274d3e34 parent: 83759:2187cf880e5b user: Antoine Pitrou date: Mon May 13 19:48:46 2013 +0200 summary: Issue #17968: Fix memory leak in os.listxattr(). files: Misc/NEWS | 4 +++- Modules/posixmodule.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -91,8 +91,10 @@ Library ------- +- Issue #17968: Fix memory leak in os.listxattr(). + - Issue #17606: Fixed support of encoded byte strings in the XMLGenerator - .characters() and ignorableWhitespace() methods. Original patch by Sebastian + characters() and ignorableWhitespace() methods. Original patch by Sebastian Ortiz Vasquez. - Issue #17732: Ignore distutils.cfg options pertaining to install paths if a diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -10119,8 +10119,10 @@ Py_END_ALLOW_THREADS; if (length < 0) { - if (errno == ERANGE) + if (errno == ERANGE) { + PyMem_FREE(buffer); continue; + } path_error(&path); break; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 13 21:54:15 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 13 May 2013 21:54:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Complete_2_to_?= =?utf-8?q?3_conversion?= Message-ID: <3b8Xm71LfdzRXw@mail.python.org> http://hg.python.org/cpython/rev/905e32ba16bf changeset: 83761:905e32ba16bf branch: 3.3 parent: 83759:2187cf880e5b user: Terry Jan Reedy date: Mon May 13 15:39:24 2013 -0400 summary: Complete 2 to 3 conversion files: Lib/idlelib/textView.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/textView.py b/Lib/idlelib/textView.py --- a/Lib/idlelib/textView.py +++ b/Lib/idlelib/textView.py @@ -80,7 +80,7 @@ root=Tk() root.title('textView test') filename = './textView.py' - text = file(filename, 'r').read() + text = open(filename, 'r').read() btn1 = Button(root, text='view_text', command=lambda:view_text(root, 'view_text', text)) btn1.pack(side=LEFT) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 13 21:54:16 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 13 May 2013 21:54:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Complete_2_to_3_conversion?= Message-ID: <3b8Xm83f4kz7Ljm@mail.python.org> http://hg.python.org/cpython/rev/eeb89ebfa9b6 changeset: 83762:eeb89ebfa9b6 parent: 83760:1fa1a021ed23 parent: 83761:905e32ba16bf user: Terry Jan Reedy date: Mon May 13 15:44:30 2013 -0400 summary: Complete 2 to 3 conversion files: Lib/idlelib/textView.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/textView.py b/Lib/idlelib/textView.py --- a/Lib/idlelib/textView.py +++ b/Lib/idlelib/textView.py @@ -80,7 +80,7 @@ root=Tk() root.title('textView test') filename = './textView.py' - text = file(filename, 'r').read() + text = open(filename, 'r').read() btn1 = Button(root, text='view_text', command=lambda:view_text(root, 'view_text', text)) btn1.pack(side=LEFT) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 13 22:17:10 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 13 May 2013 22:17:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Silence_unclos?= =?utf-8?q?ed_open_file_ResourceWarning=2E?= Message-ID: <3b8YGZ69NXzNdF@mail.python.org> http://hg.python.org/cpython/rev/c1383ddf7cb9 changeset: 83763:c1383ddf7cb9 branch: 3.3 parent: 83761:905e32ba16bf user: Terry Jan Reedy date: Mon May 13 16:07:44 2013 -0400 summary: Silence unclosed open file ResourceWarning. files: Lib/idlelib/textView.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/textView.py b/Lib/idlelib/textView.py --- a/Lib/idlelib/textView.py +++ b/Lib/idlelib/textView.py @@ -80,7 +80,8 @@ root=Tk() root.title('textView test') filename = './textView.py' - text = open(filename, 'r').read() + with open(filename, 'r') as f: + text = f.read() btn1 = Button(root, text='view_text', command=lambda:view_text(root, 'view_text', text)) btn1.pack(side=LEFT) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 13 22:17:12 2013 From: python-checkins at python.org (terry.reedy) Date: Mon, 13 May 2013 22:17:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E3?= Message-ID: <3b8YGc1FRzzQwc@mail.python.org> http://hg.python.org/cpython/rev/2368f6f9963f changeset: 83764:2368f6f9963f parent: 83762:eeb89ebfa9b6 parent: 83763:c1383ddf7cb9 user: Terry Jan Reedy date: Mon May 13 16:09:47 2013 -0400 summary: Merge with 3.3 files: Lib/idlelib/textView.py | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/idlelib/textView.py b/Lib/idlelib/textView.py --- a/Lib/idlelib/textView.py +++ b/Lib/idlelib/textView.py @@ -80,7 +80,8 @@ root=Tk() root.title('textView test') filename = './textView.py' - text = open(filename, 'r').read() + with open(filename, 'r') as f: + text = f.read() btn1 = Button(root, text='view_text', command=lambda:view_text(root, 'view_text', text)) btn1.pack(side=LEFT) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 13 22:35:46 2013 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 13 May 2013 22:35:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Fix_ResourceWa?= =?utf-8?q?rnings_in_test=5Fsax?= Message-ID: <3b8Yh26zt0zRpB@mail.python.org> http://hg.python.org/cpython/rev/6481f819e6f0 changeset: 83765:6481f819e6f0 branch: 3.3 parent: 83763:c1383ddf7cb9 user: Antoine Pitrou date: Mon May 13 22:34:21 2013 +0200 summary: Fix ResourceWarnings in test_sax files: Lib/test/test_sax.py | 5 ++++- 1 files changed, 4 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 @@ -574,7 +574,10 @@ def ioclass(self): writer = codecs.open(self.fname, 'w', encoding='ascii', errors='xmlcharrefreplace', buffering=0) - self.addCleanup(support.unlink, self.fname) + def cleanup(): + writer.close() + support.unlink(self.fname) + self.addCleanup(cleanup) writer.getvalue = self.getvalue return writer -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 13 22:35:48 2013 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 13 May 2013 22:35:48 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Fix_ResourceWarnings_in_test=5Fsax?= Message-ID: <3b8Yh426Dfz7Ljr@mail.python.org> http://hg.python.org/cpython/rev/13cae79b155d changeset: 83766:13cae79b155d parent: 83764:2368f6f9963f parent: 83765:6481f819e6f0 user: Antoine Pitrou date: Mon May 13 22:35:38 2013 +0200 summary: Fix ResourceWarnings in test_sax files: Lib/test/test_sax.py | 5 ++++- 1 files changed, 4 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 @@ -574,7 +574,10 @@ def ioclass(self): writer = codecs.open(self.fname, 'w', encoding='ascii', errors='xmlcharrefreplace', buffering=0) - self.addCleanup(support.unlink, self.fname) + def cleanup(): + writer.close() + support.unlink(self.fname) + self.addCleanup(cleanup) writer.getvalue = self.getvalue return writer -- Repository URL: http://hg.python.org/cpython From tjreedy at udel.edu Mon May 13 22:32:50 2013 From: tjreedy at udel.edu (Terry Reedy) Date: Mon, 13 May 2013 16:32:50 -0400 Subject: [Python-checkins] cpython (merge 3.3 -> default): Complete 2 to 3 conversion In-Reply-To: <3b8Xm83f4kz7Ljm@mail.python.org> References: <3b8Xm83f4kz7Ljm@mail.python.org> Message-ID: <51914DF2.9020403@udel.edu> On 5/13/2013 3:54 PM, terry.reedy wrote: > http://hg.python.org/cpython/rev/eeb89ebfa9b6 > changeset: 83762:eeb89ebfa9b6 > parent: 83760:1fa1a021ed23 > parent: 83761:905e32ba16bf > user: Terry Jan Reedy > date: Mon May 13 15:44:30 2013 -0400 > summary: > Complete 2 to 3 conversion > > files: > Lib/idlelib/textView.py | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > > diff --git a/Lib/idlelib/textView.py b/Lib/idlelib/textView.py > --- a/Lib/idlelib/textView.py > +++ b/Lib/idlelib/textView.py > @@ -80,7 +80,7 @@ > root=Tk() > root.title('textView test') > filename = './textView.py' > - text = file(filename, 'r').read() > + text = open(filename, 'r').read() > btn1 = Button(root, text='view_text', > command=lambda:view_text(root, 'view_text', text)) > btn1.pack(side=LEFT) Something does not seem quite right. When I did the merge, it made the change in the file but claimed there was a merge conflict when there obviously was not one -- or should not have been one. I right-clicked on filename (in HgWorkbench) and selected 'mark as resolved' (or somesuch) and it seemed to work, but I should not have to do that. The same thing happened with the merge of the next change (Silence unclosed... Warning). That time I selected hg resolve and that re-marked the file. The diff above is what I see in HgWorkbench if i select "Show changes from first parent". If I select "Show changes from second parent" I see try: with open(filename, 'r', encoding=encoding) as file: contents = file.read() - except IOError: + except OSError: import tkinter.messagebox as tkMessageBox tkMessageBox.showerror(title='File Load Error', message='Unable to load file %r .' % filename, This is a difference between 3.3 and 3.4 versions of file (I don't know why change was not also made in 3.3 -- another issue), but has nothing to do with anything I have done. Puzzledly yours, Terry From python-checkins at python.org Tue May 14 02:56:48 2013 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 14 May 2013 02:56:48 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_prevent_double?= =?utf-8?q?_free_in_cleanup_code_=28=2317968=29?= Message-ID: <3b8gTD2x3Bz7Lkw@mail.python.org> http://hg.python.org/cpython/rev/7aa157971810 changeset: 83767:7aa157971810 branch: 3.3 parent: 83765:6481f819e6f0 user: Benjamin Peterson date: Mon May 13 19:55:40 2013 -0500 summary: prevent double free in cleanup code (#17968) files: Modules/posixmodule.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -10627,6 +10627,7 @@ if (length < 0) { if (errno == ERANGE) { PyMem_FREE(buffer); + buffer = NULL; continue; } path_error("listxattr", &path); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 14 02:56:49 2013 From: python-checkins at python.org (benjamin.peterson) Date: Tue, 14 May 2013 02:56:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4zICgjMTc5Njgp?= Message-ID: <3b8gTF5KZmz7Lky@mail.python.org> http://hg.python.org/cpython/rev/617cb2f978b0 changeset: 83768:617cb2f978b0 parent: 83766:13cae79b155d parent: 83767:7aa157971810 user: Benjamin Peterson date: Mon May 13 19:56:35 2013 -0500 summary: merge 3.3 (#17968) files: Modules/posixmodule.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -10121,6 +10121,7 @@ if (length < 0) { if (errno == ERANGE) { PyMem_FREE(buffer); + buffer = NULL; continue; } path_error(&path); -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue May 14 06:02:18 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 14 May 2013 06:02:18 +0200 Subject: [Python-checkins] Daily reference leaks (617cb2f978b0): sum=9 Message-ID: results for 617cb2f978b0 on branch "default" -------------------------------------------- test_concurrent_futures leaked [2, 1, 1] memory blocks, sum=4 test_multiprocessing leaked [1, 3, 1] memory blocks, sum=5 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog1a1GUD', '-x'] From python-checkins at python.org Tue May 14 17:38:51 2013 From: python-checkins at python.org (barry.warsaw) Date: Tue, 14 May 2013 17:38:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogLSBJc3N1ZSAjMTc5?= =?utf-8?q?77=3A_The_documentation_for_the_cadefault_argument=27s_default_?= =?utf-8?q?value?= Message-ID: <3b932z0hF4z7Lky@mail.python.org> http://hg.python.org/cpython/rev/e2288953e9f1 changeset: 83769:e2288953e9f1 branch: 3.3 parent: 83767:7aa157971810 user: Barry Warsaw date: Tue May 14 11:35:16 2013 -0400 summary: - Issue #17977: The documentation for the cadefault argument's default value in urllib.request.urlopen() is fixed to match the code. files: Doc/library/urllib.request.rst | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 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 @@ -16,7 +16,7 @@ The :mod:`urllib.request` module defines the following functions: -.. function:: urlopen(url, data=None[, timeout], *, cafile=None, capath=None, cadefault=True) +.. function:: urlopen(url, data=None[, timeout], *, cafile=None, capath=None, cadefault=False) Open the URL *url*, which can be either a string or a :class:`Request` object. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -238,6 +238,9 @@ Documentation ------------- +- Issue #17977: The documentation for the cadefault argument's default value + in urllib.request.urlopen() is fixed to match the code. + - Issue #15940: Specify effect of locale on time functions. - Issue #6696: add documentation for the Profile objects, and improve -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 14 17:38:52 2013 From: python-checkins at python.org (barry.warsaw) Date: Tue, 14 May 2013 17:38:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_-_Issue_=2317977=3A_The_documentation_for_the_cadefault_?= =?utf-8?q?argument=27s_default_value?= Message-ID: <3b93302zBmz7Lky@mail.python.org> http://hg.python.org/cpython/rev/85ecc4761a6c changeset: 83770:85ecc4761a6c parent: 83768:617cb2f978b0 parent: 83769:e2288953e9f1 user: Barry Warsaw date: Tue May 14 11:38:38 2013 -0400 summary: - Issue #17977: The documentation for the cadefault argument's default value in urllib.request.urlopen() is fixed to match the code. files: Doc/library/urllib.request.rst | 2 +- Misc/NEWS | 3 +++ 2 files changed, 4 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 @@ -16,7 +16,7 @@ The :mod:`urllib.request` module defines the following functions: -.. function:: urlopen(url, data=None[, timeout], *, cafile=None, capath=None, cadefault=True) +.. function:: urlopen(url, data=None[, timeout], *, cafile=None, capath=None, cadefault=False) Open the URL *url*, which can be either a string or a :class:`Request` object. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -296,6 +296,9 @@ Documentation ------------- +- Issue #17977: The documentation for the cadefault argument's default value + in urllib.request.urlopen() is fixed to match the code. + - Issue #15940: Specify effect of locale on time functions. - Issue #6696: add documentation for the Profile objects, and improve -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 14 20:38:04 2013 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 14 May 2013 20:38:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Backout_c89febab4648_follo?= =?utf-8?q?wing_private_feedback_by_Guido=2E?= Message-ID: <3b971m1MgVz7Ljn@mail.python.org> http://hg.python.org/cpython/rev/edefd3450834 changeset: 83771:edefd3450834 user: Antoine Pitrou date: Tue May 14 20:37:52 2013 +0200 summary: Backout c89febab4648 following private feedback by Guido. (Issue #17807: Generators can now be finalized even when they are part of a reference cycle) files: Include/frameobject.h | 9 - Include/genobject.h | 1 - Lib/test/test_generators.py | 53 ----- Lib/test/test_sys.py | 2 +- Misc/NEWS | 3 - Modules/gcmodule.c | 5 +- Objects/frameobject.c | 254 +---------------------- Objects/genobject.c | 251 ++++++++++++++++++++--- 8 files changed, 244 insertions(+), 334 deletions(-) diff --git a/Include/frameobject.h b/Include/frameobject.h --- a/Include/frameobject.h +++ b/Include/frameobject.h @@ -36,8 +36,6 @@ non-generator frames. See the save_exc_state and swap_exc_state functions in ceval.c for details of their use. */ PyObject *f_exc_type, *f_exc_value, *f_exc_traceback; - /* Borrowed referenced to a generator, or NULL */ - PyObject *f_gen; PyThreadState *f_tstate; int f_lasti; /* Last instruction if called */ @@ -86,13 +84,6 @@ /* Return the line of code the frame is currently executing. */ PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *); -/* Generator support */ -PyAPI_FUNC(PyObject *) _PyFrame_YieldingFrom(PyFrameObject *); -PyAPI_FUNC(PyObject *) _PyFrame_GeneratorSend(PyFrameObject *, PyObject *, int exc); -PyAPI_FUNC(PyObject *) _PyFrame_Finalize(PyFrameObject *); -PyAPI_FUNC(int) _PyFrame_CloseIterator(PyObject *); - - #ifdef __cplusplus } #endif diff --git a/Include/genobject.h b/Include/genobject.h --- a/Include/genobject.h +++ b/Include/genobject.h @@ -33,7 +33,6 @@ #define PyGen_CheckExact(op) (Py_TYPE(op) == &PyGen_Type) PyAPI_FUNC(PyObject *) PyGen_New(struct _frame *); -/* Deprecated, kept for backwards compatibility. */ PyAPI_FUNC(int) PyGen_NeedsFinalizing(PyGenObject *); PyAPI_FUNC(int) _PyGen_FetchStopIterationValue(PyObject **); PyObject *_PyGen_Send(PyGenObject *, PyObject *); diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -1,55 +1,3 @@ -import gc -import sys -import unittest -import weakref - -from test import support - - -class FinalizationTest(unittest.TestCase): - - def test_frame_resurrect(self): - # A generator frame can be resurrected by a generator's finalization. - def gen(): - nonlocal frame - try: - yield - finally: - frame = sys._getframe() - - g = gen() - wr = weakref.ref(g) - next(g) - del g - support.gc_collect() - self.assertIs(wr(), None) - self.assertTrue(frame) - del frame - support.gc_collect() - - def test_refcycle(self): - # A generator caught in a refcycle gets finalized anyway. - old_garbage = gc.garbage[:] - finalized = False - def gen(): - nonlocal finalized - try: - g = yield - yield 1 - finally: - finalized = True - - g = gen() - next(g) - g.send(g) - self.assertGreater(sys.getrefcount(g), 2) - self.assertFalse(finalized) - del g - support.gc_collect() - self.assertTrue(finalized) - self.assertEqual(gc.garbage, old_garbage) - - tutorial_tests = """ Let's try a simple generator: @@ -1932,7 +1880,6 @@ # so this works as expected in both ways of running regrtest. def test_main(verbose=None): from test import support, test_generators - support.run_unittest(__name__) support.run_doctest(test_generators, verbose) # This part isn't needed for regrtest, but for running the test directly. 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 @@ -764,7 +764,7 @@ nfrees = len(x.f_code.co_freevars) extras = x.f_code.co_stacksize + x.f_code.co_nlocals +\ ncells + nfrees - 1 - check(x, vsize('13P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) + check(x, vsize('12P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P')) # function def func(): pass check(func, size('12P')) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -15,9 +15,6 @@ - Issue #17927: Frame objects kept arguments alive if they had been copied into a cell, even if the cell was cleared. -- Issue #17807: Generators can now be finalized even when they are part of - a reference cycle. - - Issue #1545463: At shutdown, defer finalization of codec modules so that stderr remains usable. diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -524,7 +524,10 @@ static int has_finalizer(PyObject *op) { - return op->ob_type->tp_del != NULL; + if (PyGen_CheckExact(op)) + return PyGen_NeedsFinalizing((PyGenObject *)op); + else + return op->ob_type->tp_del != NULL; } /* Move the objects in unreachable with __del__ methods into `finalizers`. diff --git a/Objects/frameobject.c b/Objects/frameobject.c --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -31,195 +31,6 @@ return f->f_locals; } -/* - * Generator support. - */ - -PyObject * -_PyFrame_YieldingFrom(PyFrameObject *f) -{ - PyObject *yf = NULL; - - if (f && f->f_stacktop) { - PyObject *bytecode = f->f_code->co_code; - unsigned char *code = (unsigned char *)PyBytes_AS_STRING(bytecode); - - if (code[f->f_lasti + 1] != YIELD_FROM) - return NULL; - yf = f->f_stacktop[-1]; - Py_INCREF(yf); - } - return yf; -} - -PyObject * -_PyFrame_GeneratorSend(PyFrameObject *f, PyObject *arg, int exc) -{ - PyThreadState *tstate = PyThreadState_GET(); - PyObject *result; - PyGenObject *gen = (PyGenObject *) f->f_gen; - - assert(gen == NULL || PyGen_CheckExact(gen)); - if (gen && gen->gi_running) { - PyErr_SetString(PyExc_ValueError, - "generator already executing"); - return NULL; - } - if (f->f_stacktop == NULL) { - /* Only set exception if send() called, not throw() or next() */ - if (arg && !exc) - PyErr_SetNone(PyExc_StopIteration); - return NULL; - } - - if (f->f_lasti == -1) { - if (arg && arg != Py_None) { - PyErr_SetString(PyExc_TypeError, - "can't send non-None value to a " - "just-started generator"); - return NULL; - } - } else { - /* Push arg onto the frame's value stack */ - result = arg ? arg : Py_None; - Py_INCREF(result); - *(f->f_stacktop++) = result; - } - - /* Generators always return to their most recent caller, not - * necessarily their creator. */ - Py_XINCREF(tstate->frame); - assert(f->f_back == NULL); - f->f_back = tstate->frame; - - if (gen) { - Py_INCREF(gen); - gen->gi_running = 1; - } - result = PyEval_EvalFrameEx(f, exc); - if (gen) { - gen->gi_running = 0; - /* In case running the frame has lost all external references - * to gen, we must be careful not to hold on an invalid object. */ - if (Py_REFCNT(gen) == 1) - Py_CLEAR(gen); - else - Py_DECREF(gen); - } - - /* Don't keep the reference to f_back any longer than necessary. It - * may keep a chain of frames alive or it could create a reference - * cycle. */ - assert(f->f_back == tstate->frame); - Py_CLEAR(f->f_back); - - /* If the generator just returned (as opposed to yielding), signal - * that the generator is exhausted. */ - if (result && f->f_stacktop == NULL) { - if (result == Py_None) { - /* Delay exception instantiation if we can */ - PyErr_SetNone(PyExc_StopIteration); - } else { - PyObject *e = PyObject_CallFunctionObjArgs( - PyExc_StopIteration, result, NULL); - if (e != NULL) { - PyErr_SetObject(PyExc_StopIteration, e); - Py_DECREF(e); - } - } - Py_CLEAR(result); - } - - if (f->f_stacktop == NULL) { - /* generator can't be rerun, so release the frame */ - /* first clean reference cycle through stored exception traceback */ - PyObject *t, *v, *tb; - t = f->f_exc_type; - v = f->f_exc_value; - tb = f->f_exc_traceback; - f->f_exc_type = NULL; - f->f_exc_value = NULL; - f->f_exc_traceback = NULL; - Py_XDECREF(t); - Py_XDECREF(v); - Py_XDECREF(tb); - if (gen) { - f->f_gen = NULL; - Py_CLEAR(gen->gi_frame); - } - } - - return result; -} - -int -_PyFrame_CloseIterator(PyObject *yf) -{ - PyObject *retval = NULL; - _Py_IDENTIFIER(close); - - if (PyGen_CheckExact(yf)) { - PyFrameObject *f = ((PyGenObject *) yf)->gi_frame; - assert(f != NULL); - retval = _PyFrame_Finalize(f); - if (retval == NULL) - return -1; - } else { - PyObject *meth = _PyObject_GetAttrId(yf, &PyId_close); - if (meth == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - PyErr_WriteUnraisable(yf); - PyErr_Clear(); - } else { - retval = PyObject_CallFunction(meth, ""); - Py_DECREF(meth); - if (retval == NULL) - return -1; - } - } - Py_XDECREF(retval); - return 0; -} - -PyObject * -_PyFrame_Finalize(PyFrameObject *f) -{ - int err = 0; - PyObject *retval; - PyGenObject *gen = (PyGenObject *) f->f_gen; - PyObject *yf = _PyFrame_YieldingFrom(f); - - assert(gen == NULL || PyGen_CheckExact(gen)); - if (yf) { - if (gen) - gen->gi_running = 1; - err = _PyFrame_CloseIterator(yf); - if (gen) - gen->gi_running = 0; - Py_DECREF(yf); - } - if (err == 0) - PyErr_SetNone(PyExc_GeneratorExit); - retval = _PyFrame_GeneratorSend(f, Py_None, 1); - if (retval) { - Py_DECREF(retval); - PyErr_SetString(PyExc_RuntimeError, - "generator ignored GeneratorExit"); - return NULL; - } - if (PyErr_ExceptionMatches(PyExc_StopIteration) - || PyErr_ExceptionMatches(PyExc_GeneratorExit)) { - PyErr_Clear(); /* ignore these errors */ - Py_INCREF(Py_None); - return Py_None; - } - return NULL; -} - -/* - * Line number support. - */ - int PyFrame_GetLineNumber(PyFrameObject *f) { @@ -609,43 +420,32 @@ #define PyFrame_MAXFREELIST 200 static void -frame_clear(PyFrameObject *f); - -static void frame_dealloc(PyFrameObject *f) { + PyObject **p, **valuestack; PyCodeObject *co; - Py_REFCNT(f)++; - frame_clear(f); - Py_REFCNT(f)--; - if (Py_REFCNT(f) > 0) { - /* Frame resurrected! */ - Py_ssize_t refcnt = Py_REFCNT(f); - _Py_NewReference((PyObject *) f); - Py_REFCNT(f) = refcnt; - /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so - * we need to undo that. */ - _Py_DEC_REFTOTAL; - /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object - * chain, so no more to do there. - * If COUNT_ALLOCS, the original decref bumped tp_frees, and - * _Py_NewReference bumped tp_allocs: both of those need to be - * undone. - */ -#ifdef COUNT_ALLOCS - --(Py_TYPE(self)->tp_frees); - --(Py_TYPE(self)->tp_allocs); -#endif - } - PyObject_GC_UnTrack(f); Py_TRASHCAN_SAFE_BEGIN(f) + /* Kill all local variables */ + valuestack = f->f_valuestack; + for (p = f->f_localsplus; p < valuestack; p++) + Py_CLEAR(*p); + + /* Free stack */ + if (f->f_stacktop != NULL) { + for (p = valuestack; p < f->f_stacktop; p++) + Py_XDECREF(*p); + } Py_XDECREF(f->f_back); Py_DECREF(f->f_builtins); Py_DECREF(f->f_globals); Py_CLEAR(f->f_locals); + Py_CLEAR(f->f_trace); + Py_CLEAR(f->f_exc_type); + Py_CLEAR(f->f_exc_value); + Py_CLEAR(f->f_exc_traceback); co = f->f_code; if (co->co_zombieframe == NULL) @@ -697,25 +497,12 @@ { PyObject **fastlocals, **p, **oldtop; Py_ssize_t i, slots; - PyObject *retval; - if (f->f_back == NULL) { - PyObject *t, *v, *tb; - PyErr_Fetch(&t, &v, &tb); - /* Note that this can finalize a suspended generator frame even - * if the generator object was disposed of (i.e. if f_gen is NULL). - */ - retval = _PyFrame_Finalize(f); - if (retval == NULL) { - if (PyErr_Occurred()) - PyErr_WriteUnraisable((PyObject *) f); - } - else - Py_DECREF(retval); - PyErr_Restore(t, v, tb); - } - - /* Make sure the frame is now clearly marked as being defunct */ + /* Before anything else, make sure that this frame is clearly marked + * as being defunct! Else, e.g., a generator reachable from this + * frame may also point to this frame, believe itself to still be + * active, and try cleaning up this frame again. + */ oldtop = f->f_stacktop; f->f_stacktop = NULL; @@ -926,7 +713,6 @@ f->f_lasti = -1; f->f_lineno = code->co_firstlineno; f->f_iblock = 0; - f->f_gen = NULL; _PyObject_GC_TRACK(f); return f; diff --git a/Objects/genobject.c b/Objects/genobject.c --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -19,50 +19,112 @@ gen_dealloc(PyGenObject *gen) { PyObject *self = (PyObject *) gen; - PyFrameObject *f = gen->gi_frame; _PyObject_GC_UNTRACK(gen); if (gen->gi_weakreflist != NULL) PyObject_ClearWeakRefs(self); - gen->gi_frame = NULL; - if (f) { - /* Close the generator by finalizing the frame */ - PyObject *retval, *t, *v, *tb; - PyErr_Fetch(&t, &v, &tb); - f->f_gen = NULL; - retval = _PyFrame_Finalize(f); - if (retval) - Py_DECREF(retval); - else if (PyErr_Occurred()) - PyErr_WriteUnraisable((PyObject *) gen); - Py_DECREF(f); - PyErr_Restore(t, v, tb); + _PyObject_GC_TRACK(self); + + if (gen->gi_frame != NULL && gen->gi_frame->f_stacktop != NULL) { + /* Generator is paused, so we need to close */ + Py_TYPE(gen)->tp_del(self); + if (self->ob_refcnt > 0) + return; /* resurrected. :( */ } + + _PyObject_GC_UNTRACK(self); + Py_CLEAR(gen->gi_frame); Py_CLEAR(gen->gi_code); PyObject_GC_Del(gen); } + static PyObject * gen_send_ex(PyGenObject *gen, PyObject *arg, int exc) { + PyThreadState *tstate = PyThreadState_GET(); PyFrameObject *f = gen->gi_frame; + PyObject *result; - /* For compatibility, we check gi_running before f == NULL */ if (gen->gi_running) { PyErr_SetString(PyExc_ValueError, "generator already executing"); return NULL; } - if (f == NULL) { - /* Only set exception if send() called, not throw() or next() */ + if (f == NULL || f->f_stacktop == NULL) { + /* Only set exception if called from send() */ if (arg && !exc) PyErr_SetNone(PyExc_StopIteration); return NULL; } - return _PyFrame_GeneratorSend(f, arg, exc); + if (f->f_lasti == -1) { + if (arg && arg != Py_None) { + PyErr_SetString(PyExc_TypeError, + "can't send non-None value to a " + "just-started generator"); + return NULL; + } + } else { + /* Push arg onto the frame's value stack */ + result = arg ? arg : Py_None; + Py_INCREF(result); + *(f->f_stacktop++) = result; + } + + /* Generators always return to their most recent caller, not + * necessarily their creator. */ + Py_XINCREF(tstate->frame); + assert(f->f_back == NULL); + f->f_back = tstate->frame; + + gen->gi_running = 1; + result = PyEval_EvalFrameEx(f, exc); + gen->gi_running = 0; + + /* Don't keep the reference to f_back any longer than necessary. It + * may keep a chain of frames alive or it could create a reference + * cycle. */ + assert(f->f_back == tstate->frame); + Py_CLEAR(f->f_back); + + /* If the generator just returned (as opposed to yielding), signal + * that the generator is exhausted. */ + if (result && f->f_stacktop == NULL) { + if (result == Py_None) { + /* Delay exception instantiation if we can */ + PyErr_SetNone(PyExc_StopIteration); + } else { + PyObject *e = PyObject_CallFunctionObjArgs( + PyExc_StopIteration, result, NULL); + if (e != NULL) { + PyErr_SetObject(PyExc_StopIteration, e); + Py_DECREF(e); + } + } + Py_CLEAR(result); + } + + if (!result || f->f_stacktop == NULL) { + /* generator can't be rerun, so release the frame */ + /* first clean reference cycle through stored exception traceback */ + PyObject *t, *v, *tb; + t = f->f_exc_type; + v = f->f_exc_value; + tb = f->f_exc_traceback; + f->f_exc_type = NULL; + f->f_exc_value = NULL; + f->f_exc_traceback = NULL; + Py_XDECREF(t); + Py_XDECREF(v); + Py_XDECREF(tb); + gen->gi_frame = NULL; + Py_DECREF(f); + } + + return result; } PyDoc_STRVAR(send_doc, @@ -83,33 +145,146 @@ * close a subiterator being delegated to by yield-from. */ +static int +gen_close_iter(PyObject *yf) +{ + PyObject *retval = NULL; + _Py_IDENTIFIER(close); + + if (PyGen_CheckExact(yf)) { + retval = gen_close((PyGenObject *)yf, NULL); + if (retval == NULL) + return -1; + } else { + PyObject *meth = _PyObject_GetAttrId(yf, &PyId_close); + if (meth == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + PyErr_WriteUnraisable(yf); + PyErr_Clear(); + } else { + retval = PyObject_CallFunction(meth, ""); + Py_DECREF(meth); + if (retval == NULL) + return -1; + } + } + Py_XDECREF(retval); + return 0; +} + static PyObject * gen_yf(PyGenObject *gen) { + PyObject *yf = NULL; PyFrameObject *f = gen->gi_frame; - if (f) - return _PyFrame_YieldingFrom(f); - else - return NULL; + + if (f && f->f_stacktop) { + PyObject *bytecode = f->f_code->co_code; + unsigned char *code = (unsigned char *)PyBytes_AS_STRING(bytecode); + + if (code[f->f_lasti + 1] != YIELD_FROM) + return NULL; + yf = f->f_stacktop[-1]; + Py_INCREF(yf); + } + + return yf; } static PyObject * gen_close(PyGenObject *gen, PyObject *args) { - PyFrameObject *f = gen->gi_frame; + PyObject *retval; + PyObject *yf = gen_yf(gen); + int err = 0; - /* For compatibility, we check gi_running before f == NULL */ - if (gen->gi_running) { - PyErr_SetString(PyExc_ValueError, - "generator already executing"); + if (yf) { + gen->gi_running = 1; + err = gen_close_iter(yf); + gen->gi_running = 0; + Py_DECREF(yf); + } + if (err == 0) + PyErr_SetNone(PyExc_GeneratorExit); + retval = gen_send_ex(gen, Py_None, 1); + if (retval) { + Py_DECREF(retval); + PyErr_SetString(PyExc_RuntimeError, + "generator ignored GeneratorExit"); return NULL; } - if (f == NULL) - Py_RETURN_NONE; + if (PyErr_ExceptionMatches(PyExc_StopIteration) + || PyErr_ExceptionMatches(PyExc_GeneratorExit)) { + PyErr_Clear(); /* ignore these errors */ + Py_INCREF(Py_None); + return Py_None; + } + return NULL; +} - return _PyFrame_Finalize(f); +static void +gen_del(PyObject *self) +{ + PyObject *res; + PyObject *error_type, *error_value, *error_traceback; + PyGenObject *gen = (PyGenObject *)self; + + if (gen->gi_frame == NULL || gen->gi_frame->f_stacktop == NULL) + /* Generator isn't paused, so no need to close */ + return; + + /* Temporarily resurrect the object. */ + assert(self->ob_refcnt == 0); + self->ob_refcnt = 1; + + /* Save the current exception, if any. */ + PyErr_Fetch(&error_type, &error_value, &error_traceback); + + res = gen_close(gen, NULL); + + if (res == NULL) + PyErr_WriteUnraisable(self); + else + Py_DECREF(res); + + /* Restore the saved exception. */ + PyErr_Restore(error_type, error_value, error_traceback); + + /* Undo the temporary resurrection; can't use DECREF here, it would + * cause a recursive call. + */ + assert(self->ob_refcnt > 0); + if (--self->ob_refcnt == 0) + return; /* this is the normal path out */ + + /* close() resurrected it! Make it look like the original Py_DECREF + * never happened. + */ + { + Py_ssize_t refcnt = self->ob_refcnt; + _Py_NewReference(self); + self->ob_refcnt = refcnt; + } + assert(PyType_IS_GC(Py_TYPE(self)) && + _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED); + + /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so + * we need to undo that. */ + _Py_DEC_REFTOTAL; + /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object + * chain, so no more to do there. + * If COUNT_ALLOCS, the original decref bumped tp_frees, and + * _Py_NewReference bumped tp_allocs: both of those need to be + * undone. + */ +#ifdef COUNT_ALLOCS + --(Py_TYPE(self)->tp_frees); + --(Py_TYPE(self)->tp_allocs); +#endif } + + PyDoc_STRVAR(throw_doc, "throw(typ[,val[,tb]]) -> raise exception in generator,\n\ return next yielded value or raise StopIteration."); @@ -131,7 +306,7 @@ int err; if (PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit)) { gen->gi_running = 1; - err = _PyFrame_CloseIterator(yf); + err = gen_close_iter(yf); gen->gi_running = 0; Py_DECREF(yf); if (err < 0) @@ -369,6 +544,7 @@ 0, /* tp_cache */ 0, /* tp_subclasses */ 0, /* tp_weaklist */ + gen_del, /* tp_del */ }; PyObject * @@ -380,7 +556,6 @@ return NULL; } gen->gi_frame = f; - f->f_gen = (PyObject *) gen; Py_INCREF(f->f_code); gen->gi_code = (PyObject *)(f->f_code); gen->gi_running = 0; @@ -392,5 +567,17 @@ int PyGen_NeedsFinalizing(PyGenObject *gen) { + int i; + PyFrameObject *f = gen->gi_frame; + + if (f == NULL || f->f_stacktop == NULL) + return 0; /* no frame or empty blockstack == no finalization */ + + /* Any block type besides a loop requires cleanup. */ + for (i = 0; i < f->f_iblock; i++) + if (f->f_blockstack[i].b_type != SETUP_LOOP) + return 1; + + /* No blocks except loops, it's safe to skip finalization. */ return 0; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 15 05:32:50 2013 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 15 May 2013 05:32:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_when_arguments?= =?utf-8?q?_are_cells_clear_the_locals_slot_=28backport_of_=2317927=29?= Message-ID: <3b9Ltp3D7wz7LkR@mail.python.org> http://hg.python.org/cpython/rev/2b4b289c1abb changeset: 83772:2b4b289c1abb branch: 3.3 parent: 83769:e2288953e9f1 user: Benjamin Peterson date: Tue May 14 22:31:26 2013 -0500 summary: when arguments are cells clear the locals slot (backport of #17927) files: Lib/test/test_scope.py | 29 +++++++++++++++++++++++++++++ Lib/test/test_super.py | 13 +++++++++++++ Misc/NEWS | 3 +++ Objects/typeobject.c | 12 ++++++++++++ Python/ceval.c | 8 ++++++-- 5 files changed, 63 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_scope.py b/Lib/test/test_scope.py --- a/Lib/test/test_scope.py +++ b/Lib/test/test_scope.py @@ -1,4 +1,6 @@ import unittest +import weakref + from test.support import check_syntax_error, cpython_only, run_unittest @@ -713,6 +715,33 @@ def b(): global a + @cpython_only + def testCellLeak(self): + # Issue 17927. + # + # The issue was that if self was part of a cycle involving the + # frame of a method call, *and* the method contained a nested + # function referencing self, thereby forcing 'self' into a + # cell, setting self to None would not be enough to break the + # frame -- the frame had another reference to the instance, + # which could not be cleared by the code running in the frame + # (though it will be cleared when the frame is collected). + # Without the lambda, setting self to None is enough to break + # the cycle. + class Tester: + def dig(self): + if 0: + lambda: self + try: + 1/0 + except Exception as exc: + self.exc = exc + self = None # Break the cycle + tester = Tester() + tester.dig() + ref = weakref.ref(tester) + del tester + self.assertIsNone(ref()) def test_main(): diff --git a/Lib/test/test_super.py b/Lib/test/test_super.py --- a/Lib/test/test_super.py +++ b/Lib/test/test_super.py @@ -130,6 +130,19 @@ super() self.assertRaises(RuntimeError, X().f) + def test_cell_as_self(self): + class X: + def meth(self): + super() + + def f(): + k = X() + def g(): + return k + return g + c = f().__closure__[0] + self.assertRaises(TypeError, X.meth, c) + def test_main(): support.run_unittest(TestSuper) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ Core and Builtins ----------------- +- Issue #17927: Frame objects kept arguments alive if they had been copied into + a cell, even if the cell was cleared. + - Issue #17237: Fix crash in the ASCII decoder on m68k. - Issue #17408: Avoid using an obsolete instance of the copyreg module when diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6519,6 +6519,18 @@ return -1; } obj = f->f_localsplus[0]; + if (obj == NULL && co->co_cell2arg) { + /* The first argument might be a cell. */ + n = PyTuple_GET_SIZE(co->co_cellvars); + for (i = 0; i < n; i++) { + if (co->co_cell2arg[i] == 0) { + PyObject *cell = f->f_localsplus[co->co_nlocals + i]; + assert(PyCell_Check(cell)); + obj = PyCell_GET(cell); + break; + } + } + } if (obj == NULL) { PyErr_SetString(PyExc_RuntimeError, "super(): arg[0] deleted"); diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3403,10 +3403,14 @@ int arg; /* Possibly account for the cell variable being an argument. */ if (co->co_cell2arg != NULL && - (arg = co->co_cell2arg[i]) != CO_CELL_NOT_AN_ARG) + (arg = co->co_cell2arg[i]) != CO_CELL_NOT_AN_ARG) { c = PyCell_New(GETLOCAL(arg)); - else + /* Clear the local copy. */ + SETLOCAL(arg, NULL); + } + else { c = PyCell_New(NULL); + } if (c == NULL) goto fail; SETLOCAL(co->co_nlocals + i, c); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 15 05:32:51 2013 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 15 May 2013 05:32:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_null_merge_3=2E3_from_backport?= Message-ID: <3b9Ltq5jMyz7Lks@mail.python.org> http://hg.python.org/cpython/rev/bb8093e427f9 changeset: 83773:bb8093e427f9 parent: 83771:edefd3450834 parent: 83772:2b4b289c1abb user: Benjamin Peterson date: Tue May 14 22:32:34 2013 -0500 summary: null merge 3.3 from backport files: -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed May 15 06:01:08 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 15 May 2013 06:01:08 +0200 Subject: [Python-checkins] Daily reference leaks (edefd3450834): sum=11 Message-ID: results for edefd3450834 on branch "default" -------------------------------------------- test_support leaked [1, 0, 0] references, sum=1 test_support leaked [1, 2, 1] memory blocks, sum=4 test_concurrent_futures leaked [0, 2, 1] memory blocks, sum=3 test_multiprocessing leaked [-2, 3, 2] memory blocks, sum=3 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogGlA4AF', '-x'] From python-checkins at python.org Wed May 15 15:48:06 2013 From: python-checkins at python.org (matthias.klose) Date: Wed, 15 May 2013 15:48:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogLSBJc3N1ZSAjMTc3?= =?utf-8?q?54=3A_Make_ctypes=2Eutil=2Efind=5Flibrary=28=29_independent_of_?= =?utf-8?q?the_locale=2E?= Message-ID: <3b9cXk200Vz7Ljs@mail.python.org> http://hg.python.org/cpython/rev/4f594f9b296a changeset: 83774:4f594f9b296a branch: 2.7 parent: 83747:a32a3b79f5e8 user: doko at ubuntu.com date: Wed May 15 15:46:11 2013 +0200 summary: - Issue #17754: Make ctypes.util.find_library() independent of the locale. files: Lib/ctypes/util.py | 2 +- Misc/NEWS | 1 + 2 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py --- a/Lib/ctypes/util.py +++ b/Lib/ctypes/util.py @@ -93,7 +93,7 @@ fdout, ccout = tempfile.mkstemp() os.close(fdout) cmd = 'if type gcc >/dev/null 2>&1; then CC=gcc; elif type cc >/dev/null 2>&1; then CC=cc;else exit 10; fi;' \ - '$CC -Wl,-t -o ' + ccout + ' 2>&1 -l' + name + 'LANG=C LC_ALL=C $CC -Wl,-t -o ' + ccout + ' 2>&1 -l' + name try: f = os.popen(cmd) try: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,7 @@ Library ------- +- Issue #17754: Make ctypes.util.find_library() independent of the locale. What's New in Python 2.7.5? =========================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 15 16:54:30 2013 From: python-checkins at python.org (matthias.klose) Date: Wed, 15 May 2013 16:54:30 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_-_Fix_typos_in?= =?utf-8?q?_the_multiprocessing_module=2E?= Message-ID: <3b9f1L2Mf4z7Lmt@mail.python.org> http://hg.python.org/cpython/rev/149340b3004a changeset: 83775:149340b3004a branch: 2.7 user: doko at ubuntu.com date: Wed May 15 16:54:16 2013 +0200 summary: - Fix typos in the multiprocessing module. files: Lib/multiprocessing/synchronize.py | 2 +- Misc/NEWS | 2 ++ Modules/_multiprocessing/multiprocessing.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/multiprocessing/synchronize.py b/Lib/multiprocessing/synchronize.py --- a/Lib/multiprocessing/synchronize.py +++ b/Lib/multiprocessing/synchronize.py @@ -226,7 +226,7 @@ num_waiters = (self._sleeping_count._semlock._get_value() - self._woken_count._semlock._get_value()) except Exception: - num_waiters = 'unkown' + num_waiters = 'unknown' return '' % (self._lock, num_waiters) def wait(self, timeout=None): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -14,6 +14,8 @@ - Issue #17754: Make ctypes.util.find_library() independent of the locale. +- Fix typos in the multiprocessing module. + What's New in Python 2.7.5? =========================== diff --git a/Modules/_multiprocessing/multiprocessing.c b/Modules/_multiprocessing/multiprocessing.c --- a/Modules/_multiprocessing/multiprocessing.c +++ b/Modules/_multiprocessing/multiprocessing.c @@ -63,7 +63,7 @@ break; default: PyErr_Format(PyExc_RuntimeError, - "unkown error number %d", num); + "unknown error number %d", num); } return NULL; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 15 18:00:19 2013 From: python-checkins at python.org (matthias.klose) Date: Wed, 15 May 2013 18:00:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogTWlzYy9ORVdTOiBB?= =?utf-8?q?dd_3=2E3=2E3_section_and_move_entries_made_after_the_3=2E3=2E2_?= =?utf-8?q?release?= Message-ID: <3b9gTH530rzNpZ@mail.python.org> http://hg.python.org/cpython/rev/2bc63e65b3bf changeset: 83776:2bc63e65b3bf branch: 3.3 parent: 83772:2b4b289c1abb user: doko at ubuntu.com date: Wed May 15 18:00:05 2013 +0200 summary: Misc/NEWS: Add 3.3.3 section and move entries made after the 3.3.2 release to the new section. files: Misc/NEWS | 31 +++++++++++++++++++++++-------- 1 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,6 +2,29 @@ Python News +++++++++++ +What's New in Python 3.3.3? +=========================== + +*Release date: TBD* + +Core and Builtins +----------------- + +- Issue #17927: Frame objects kept arguments alive if they had been copied into + a cell, even if the cell was cleared. + +Library +------- + +- Issue #17968: Fix memory leak in os.listxattr(). + +Documentation +------------- + +- Issue #17977: The documentation for the cadefault argument's default value + in urllib.request.urlopen() is fixed to match the code. + + What's New in Python 3.3.2? =========================== @@ -12,9 +35,6 @@ Core and Builtins ----------------- -- Issue #17927: Frame objects kept arguments alive if they had been copied into - a cell, even if the cell was cleared. - - Issue #17237: Fix crash in the ASCII decoder on m68k. - Issue #17408: Avoid using an obsolete instance of the copyreg module when @@ -52,8 +72,6 @@ Library ------- -- Issue #17968: Fix memory leak in os.listxattr(). - - Issue #17606: Fixed support of encoded byte strings in the XMLGenerator characters() and ignorableWhitespace() methods. Original patch by Sebastian Ortiz Vasquez. @@ -241,9 +259,6 @@ Documentation ------------- -- Issue #17977: The documentation for the cadefault argument's default value - in urllib.request.urlopen() is fixed to match the code. - - Issue #15940: Specify effect of locale on time functions. - Issue #6696: add documentation for the Profile objects, and improve -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 15 18:05:04 2013 From: python-checkins at python.org (matthias.klose) Date: Wed, 15 May 2013 18:05:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogLSBJc3N1ZSAjMTc3?= =?utf-8?q?54=3A_Make_ctypes=2Eutil=2Efind=5Flibrary=28=29_independent_of_?= =?utf-8?q?the_locale=2E?= Message-ID: <3b9gZm0N7Kz7Llg@mail.python.org> http://hg.python.org/cpython/rev/d6a43a99aea3 changeset: 83777:d6a43a99aea3 branch: 3.3 user: doko at ubuntu.com date: Wed May 15 18:02:13 2013 +0200 summary: - Issue #17754: Make ctypes.util.find_library() independent of the locale. files: Lib/ctypes/util.py | 2 +- Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py --- a/Lib/ctypes/util.py +++ b/Lib/ctypes/util.py @@ -92,7 +92,7 @@ fdout, ccout = tempfile.mkstemp() os.close(fdout) cmd = 'if type gcc >/dev/null 2>&1; then CC=gcc; elif type cc >/dev/null 2>&1; then CC=cc;else exit 10; fi;' \ - '$CC -Wl,-t -o ' + ccout + ' 2>&1 -l' + name + 'LANG=C LC_ALL=C $CC -Wl,-t -o ' + ccout + ' 2>&1 -l' + name try: f = os.popen(cmd) try: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #17754: Make ctypes.util.find_library() independent of the locale. + - Issue #17927: Frame objects kept arguments alive if they had been copied into a cell, even if the cell was cleared. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 15 18:05:05 2013 From: python-checkins at python.org (matthias.klose) Date: Wed, 15 May 2013 18:05:05 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_-_Issue_=2317754=3A_Make_ctypes=2Eutil=2Efind=5Flibrary?= =?utf-8?q?=28=29_independent_of_the_locale=2E?= Message-ID: <3b9gZn2mJQz7LmC@mail.python.org> http://hg.python.org/cpython/rev/9a44f12df844 changeset: 83778:9a44f12df844 parent: 83773:bb8093e427f9 parent: 83777:d6a43a99aea3 user: doko at ubuntu.com date: Wed May 15 18:04:50 2013 +0200 summary: - Issue #17754: Make ctypes.util.find_library() independent of the locale. files: Lib/ctypes/util.py | 2 +- Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 1 deletions(-) diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py --- a/Lib/ctypes/util.py +++ b/Lib/ctypes/util.py @@ -92,7 +92,7 @@ fdout, ccout = tempfile.mkstemp() os.close(fdout) cmd = 'if type gcc >/dev/null 2>&1; then CC=gcc; elif type cc >/dev/null 2>&1; then CC=cc;else exit 10; fi;' \ - '$CC -Wl,-t -o ' + ccout + ' 2>&1 -l' + name + 'LANG=C LC_ALL=C $CC -Wl,-t -o ' + ccout + ' 2>&1 -l' + name try: f = os.popen(cmd) try: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -88,6 +88,8 @@ Library ------- +- Issue #17754: Make ctypes.util.find_library() independent of the locale. + - Issue #17968: Fix memory leak in os.listxattr(). - Issue #17606: Fixed support of encoded byte strings in the XMLGenerator -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 15 18:08:17 2013 From: python-checkins at python.org (matthias.klose) Date: Wed, 15 May 2013 18:08:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_-_Fix_typos_in?= =?utf-8?q?_the_multiprocessing_module=2E?= Message-ID: <3b9gfT3Yf1z7LjS@mail.python.org> http://hg.python.org/cpython/rev/36be00c51a66 changeset: 83779:36be00c51a66 branch: 3.3 parent: 83777:d6a43a99aea3 user: doko at ubuntu.com date: Wed May 15 18:06:56 2013 +0200 summary: - Fix typos in the multiprocessing module. files: Lib/multiprocessing/synchronize.py | 2 +- Misc/NEWS | 6 ++++-- Modules/_multiprocessing/multiprocessing.c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Lib/multiprocessing/synchronize.py b/Lib/multiprocessing/synchronize.py --- a/Lib/multiprocessing/synchronize.py +++ b/Lib/multiprocessing/synchronize.py @@ -199,7 +199,7 @@ num_waiters = (self._sleeping_count._semlock._get_value() - self._woken_count._semlock._get_value()) except Exception: - num_waiters = 'unkown' + num_waiters = 'unknown' return '' % (self._lock, num_waiters) def wait(self, timeout=None): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,14 +10,16 @@ Core and Builtins ----------------- -- Issue #17754: Make ctypes.util.find_library() independent of the locale. - - Issue #17927: Frame objects kept arguments alive if they had been copied into a cell, even if the cell was cleared. Library ------- +- Fix typos in the multiprocessing module. + +- Issue #17754: Make ctypes.util.find_library() independent of the locale. + - Issue #17968: Fix memory leak in os.listxattr(). Documentation diff --git a/Modules/_multiprocessing/multiprocessing.c b/Modules/_multiprocessing/multiprocessing.c --- a/Modules/_multiprocessing/multiprocessing.c +++ b/Modules/_multiprocessing/multiprocessing.c @@ -46,7 +46,7 @@ break; default: PyErr_Format(PyExc_RuntimeError, - "unkown error number %d", num); + "unknown error number %d", num); } return NULL; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 15 18:08:18 2013 From: python-checkins at python.org (matthias.klose) Date: Wed, 15 May 2013 18:08:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_-_Fix_typos_in_the_multiprocessing_module=2E?= Message-ID: <3b9gfV5xMLz7LlP@mail.python.org> http://hg.python.org/cpython/rev/9ab2ac5ce676 changeset: 83780:9ab2ac5ce676 parent: 83778:9a44f12df844 parent: 83779:36be00c51a66 user: doko at ubuntu.com date: Wed May 15 18:08:03 2013 +0200 summary: - Fix typos in the multiprocessing module. files: Lib/multiprocessing/synchronize.py | 2 +- Misc/NEWS | 2 ++ Modules/_multiprocessing/multiprocessing.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/multiprocessing/synchronize.py b/Lib/multiprocessing/synchronize.py --- a/Lib/multiprocessing/synchronize.py +++ b/Lib/multiprocessing/synchronize.py @@ -199,7 +199,7 @@ num_waiters = (self._sleeping_count._semlock._get_value() - self._woken_count._semlock._get_value()) except Exception: - num_waiters = 'unkown' + num_waiters = 'unknown' return '' % (self._lock, num_waiters) def wait(self, timeout=None): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -88,6 +88,8 @@ Library ------- +- Fix typos in the multiprocessing module. + - Issue #17754: Make ctypes.util.find_library() independent of the locale. - Issue #17968: Fix memory leak in os.listxattr(). diff --git a/Modules/_multiprocessing/multiprocessing.c b/Modules/_multiprocessing/multiprocessing.c --- a/Modules/_multiprocessing/multiprocessing.c +++ b/Modules/_multiprocessing/multiprocessing.c @@ -44,7 +44,7 @@ break; default: PyErr_Format(PyExc_RuntimeError, - "unkown error number %d", num); + "unknown error number %d", num); } return NULL; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 15 19:02:00 2013 From: python-checkins at python.org (georg.brandl) Date: Wed, 15 May 2013 19:02:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_3=2E2_=26_3=2E3_schedule_upda?= =?utf-8?q?te?= Message-ID: <3b9hrS2Tt8z7LjS@mail.python.org> http://hg.python.org/peps/rev/26aff864a750 changeset: 4889:26aff864a750 user: Georg Brandl date: Wed May 15 19:02:42 2013 +0200 summary: 3.2 & 3.3 schedule update files: pep-0392.txt | 6 ++++++ pep-0398.txt | 5 +++++ 2 files changed, 11 insertions(+), 0 deletions(-) diff --git a/pep-0392.txt b/pep-0392.txt --- a/pep-0392.txt +++ b/pep-0392.txt @@ -90,7 +90,12 @@ - 3.2.4 candidate 1: March 23, 2013 - 3.2.4 final: April 6, 2013 --- Only security releases after 3.2.4 -- +3.2.5 schedule (regression fix release) +--------------------------------------- + +- 3.2.5 final: May 13, 2013 + +-- Only security releases after 3.2.5 -- Features for 3.2 diff --git a/pep-0398.txt b/pep-0398.txt --- a/pep-0398.txt +++ b/pep-0398.txt @@ -73,6 +73,11 @@ - 3.3.1 candidate 1: March 23, 2013 - 3.3.1 final: April 6, 2013 +3.3.2 schedule +-------------- + +- 3.3.2 final: May 13, 2013 + Features for 3.3 ================ -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed May 15 19:41:55 2013 From: python-checkins at python.org (georg.brandl) Date: Wed, 15 May 2013 19:41:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_post-release_u?= =?utf-8?q?pdate=2E?= Message-ID: <3b9jkW3GF7z7Lp8@mail.python.org> http://hg.python.org/cpython/rev/f3097c6e7119 changeset: 83781:f3097c6e7119 branch: 3.3 parent: 83779:36be00c51a66 user: Georg Brandl date: Wed May 15 19:42:39 2013 +0200 summary: post-release update. files: Include/patchlevel.h | 2 +- Misc/NEWS | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Include/patchlevel.h b/Include/patchlevel.h --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.3.2" +#define PY_VERSION "3.3.2+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -2,10 +2,12 @@ Python News +++++++++++ -What's New in Python 3.3.3? -=========================== - -*Release date: TBD* +What's New in Python 3.3.3 release candidate 1? +=============================================== + +*Not yet released, see sections below for changes released in 3.3.2* + +.. *Release date: TBD* Core and Builtins ----------------- @@ -34,8 +36,6 @@ *Release date: 13-May-2013* -.. *Not yet released, see sections below for changes released in 3.3.1* - Core and Builtins ----------------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 15 19:42:31 2013 From: python-checkins at python.org (georg.brandl) Date: Wed, 15 May 2013 19:42:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_null-merge_from_3=2E3?= Message-ID: <3b9jlC3BNYz7LkV@mail.python.org> http://hg.python.org/cpython/rev/4e687d53b645 changeset: 83782:4e687d53b645 parent: 83780:9ab2ac5ce676 parent: 83781:f3097c6e7119 user: Georg Brandl date: Wed May 15 19:43:15 2013 +0200 summary: null-merge from 3.3 files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 15 22:27:40 2013 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 15 May 2013 22:27:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbjogaGlkZSB0aGUgX19jbGFzc19f?= =?utf-8?q?_closure_from_the_class_body_=28=2312370=29?= Message-ID: <3b9nPm048dz7Lmv@mail.python.org> http://hg.python.org/cpython/rev/3d858f1eef54 changeset: 83783:3d858f1eef54 user: Benjamin Peterson date: Wed May 15 15:26:42 2013 -0500 summary: hide the __class__ closure from the class body (#12370) files: Include/symtable.h | 3 + Lib/importlib/_bootstrap.py | 3 +- Lib/test/test_super.py | 28 ++- Misc/NEWS | 3 + Python/compile.c | 64 ++++- Python/importlib.h | 238 ++++++++++++------------ Python/symtable.c | 34 +- 7 files changed, 221 insertions(+), 152 deletions(-) diff --git a/Include/symtable.h b/Include/symtable.h --- a/Include/symtable.h +++ b/Include/symtable.h @@ -53,6 +53,9 @@ unsigned ste_varkeywords : 1; /* true if block has varkeywords */ unsigned ste_returns_value : 1; /* true if namespace uses return with an argument */ + unsigned ste_needs_class_closure : 1; /* for class scopes, true if a + closure over __class__ + should be created */ int ste_lineno; /* first line of block */ int ste_col_offset; /* offset of first line of block */ int ste_opt_lineno; /* lineno of last exec or import * */ diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -390,12 +390,13 @@ # keyword-only defaults) # Python 3.4a1 3260 (add LOAD_CLASSDEREF; allow locals of class to override # free vars) +# Python 3.4a1 3270 (various tweaks to the __class_ closure) # # MAGIC must change whenever the bytecode emitted by the compiler may no # longer be understood by older implementations of the eval loop (usually # due to the addition of new opcodes). -_MAGIC_BYTES = (3260).to_bytes(2, 'little') + b'\r\n' +_MAGIC_BYTES = (3270).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(_MAGIC_BYTES, 'little') _PYCACHE = '__pycache__' diff --git a/Lib/test/test_super.py b/Lib/test/test_super.py --- a/Lib/test/test_super.py +++ b/Lib/test/test_super.py @@ -81,8 +81,7 @@ self.assertEqual(E().f(), 'AE') - @unittest.expectedFailure - def test___class___set(self): + def test_various___class___pathologies(self): # See issue #12370 class X(A): def f(self): @@ -91,6 +90,31 @@ x = X() self.assertEqual(x.f(), 'A') self.assertEqual(x.__class__, 413) + class X: + x = __class__ + def f(): + __class__ + self.assertIs(X.x, type(self)) + with self.assertRaises(NameError) as e: + exec("""class X: + __class__ + def f(): + __class__""", globals(), {}) + self.assertIs(type(e.exception), NameError) # Not UnboundLocalError + class X: + global __class__ + __class__ = 42 + def f(): + __class__ + self.assertEqual(globals()["__class__"], 42) + del globals()["__class__"] + self.assertNotIn("__class__", X.__dict__) + class X: + nonlocal __class__ + __class__ = 42 + def f(): + __class__ + self.assertEqual(__class__, 42) def test___class___instancemethod(self): # See issue #14857 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #12370: Prevent class bodies from interfering with the __class__ + closure. + - Issue #17237: Fix crash in the ASCII decoder on m68k. - Issue #17927: Frame objects kept arguments alive if they had been diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -535,6 +535,37 @@ compiler_unit_free(u); return 0; } + if (u->u_ste->ste_needs_class_closure) { + /* Cook up a implicit __class__ cell. */ + _Py_IDENTIFIER(__class__); + PyObject *tuple, *name, *zero; + int res; + assert(u->u_scope_type == COMPILER_SCOPE_CLASS); + assert(PyDict_Size(u->u_cellvars) == 0); + name = _PyUnicode_FromId(&PyId___class__); + if (!name) { + compiler_unit_free(u); + return 0; + } + tuple = PyTuple_Pack(2, name, Py_TYPE(name)); + if (!tuple) { + compiler_unit_free(u); + return 0; + } + zero = PyLong_FromLong(0); + if (!zero) { + Py_DECREF(tuple); + compiler_unit_free(u); + return 0; + } + res = PyDict_SetItem(u->u_cellvars, tuple, zero); + Py_DECREF(tuple); + Py_DECREF(zero); + if (res < 0) { + compiler_unit_free(u); + return 0; + } + } u->u_freevars = dictbytype(u->u_ste->ste_symbols, FREE, DEF_FREE_CLASS, PyDict_Size(u->u_cellvars)); @@ -1331,6 +1362,9 @@ static int get_ref_type(struct compiler *c, PyObject *name) { + if (c->u->u_scope_type == COMPILER_SCOPE_CLASS && + !PyUnicode_CompareWithASCIIString(name, "__class__")) + return CELL; int scope = PyST_GetScope(c->u->u_ste, name); if (scope == 0) { char buf[350]; @@ -1704,23 +1738,23 @@ compiler_exit_scope(c); return 0; } - /* return the (empty) __class__ cell */ - str = PyUnicode_InternFromString("__class__"); - if (str == NULL) { - compiler_exit_scope(c); - return 0; - } - i = compiler_lookup_arg(c->u->u_cellvars, str); - Py_DECREF(str); - if (i == -1) { - /* This happens when nobody references the cell */ - PyErr_Clear(); - /* Return None */ - ADDOP_O(c, LOAD_CONST, Py_None, consts); + if (c->u->u_ste->ste_needs_class_closure) { + /* return the (empty) __class__ cell */ + str = PyUnicode_InternFromString("__class__"); + if (str == NULL) { + compiler_exit_scope(c); + return 0; + } + i = compiler_lookup_arg(c->u->u_cellvars, str); + Py_DECREF(str); + assert(i == 0); + /* Return the cell where to store __class__ */ + ADDOP_I(c, LOAD_CLOSURE, i); } else { - /* Return the cell where to store __class__ */ - ADDOP_I(c, LOAD_CLOSURE, i); + assert(PyDict_Size(c->u->u_cellvars) == 0); + /* This happens when nobody references the cell. Return None. */ + ADDOP_O(c, LOAD_CONST, Py_None, consts); } ADDOP_IN_SCOPE(c, RETURN_VALUE); /* create the code object */ diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] diff --git a/Python/symtable.c b/Python/symtable.c --- a/Python/symtable.c +++ b/Python/symtable.c @@ -77,6 +77,7 @@ ste->ste_child_free = 0; ste->ste_generator = 0; ste->ste_returns_value = 0; + ste->ste_needs_class_closure = 0; if (PyDict_SetItem(st->st_blocks, ste->ste_id, (PyObject *)ste) < 0) goto fail; @@ -514,13 +515,10 @@ Note that the current block's free variables are included in free. That's safe because no name can be free and local in the same scope. - - The 'restricted' argument may be set to a string to restrict the analysis - to the one variable whose name equals that string (e.g. "__class__"). */ static int -analyze_cells(PyObject *scopes, PyObject *free, const char *restricted) +analyze_cells(PyObject *scopes, PyObject *free) { PyObject *name, *v, *v_cell; int success = 0; @@ -537,9 +535,6 @@ continue; if (!PySet_Contains(free, name)) continue; - if (restricted != NULL && - PyUnicode_CompareWithASCIIString(name, restricted)) - continue; /* Replace LOCAL with CELL for this name, and remove from free. It is safe to replace the value of name in the dict, because it will not cause a resize. @@ -555,6 +550,20 @@ return success; } +static int +drop_class_free(PySTEntryObject *ste, PyObject *free) +{ + int res; + if (!GET_IDENTIFIER(__class__)) + return 0; + res = PySet_Discard(free, __class__); + if (res < 0) + return 0; + if (res) + ste->ste_needs_class_closure = 1; + return 1; +} + /* Check for illegal statements in unoptimized namespaces */ static int check_unoptimized(const PySTEntryObject* ste) { @@ -785,7 +794,6 @@ /* Special-case __class__ */ if (!GET_IDENTIFIER(__class__)) goto error; - assert(PySet_Contains(local, __class__) == 1); if (PySet_Add(newbound, __class__) < 0) goto error; } @@ -818,11 +826,9 @@ Py_DECREF(temp); /* Check if any local variables must be converted to cell variables */ - if (ste->ste_type == FunctionBlock && !analyze_cells(scopes, newfree, - NULL)) + if (ste->ste_type == FunctionBlock && !analyze_cells(scopes, newfree)) goto error; - else if (ste->ste_type == ClassBlock && !analyze_cells(scopes, newfree, - "__class__")) + else if (ste->ste_type == ClassBlock && !drop_class_free(ste, newfree)) goto error; /* Records the results of the analysis in the symbol table entry */ if (!update_symbols(ste->ste_symbols, scopes, bound, newfree, @@ -1179,9 +1185,7 @@ if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock, (void *)s, s->lineno, s->col_offset)) VISIT_QUIT(st, 0); - if (!GET_IDENTIFIER(__class__) || - !symtable_add_def(st, __class__, DEF_LOCAL) || - !GET_IDENTIFIER(__locals__) || + if (!GET_IDENTIFIER(__locals__) || !symtable_add_def(st, __locals__, DEF_PARAM)) { symtable_exit_block(st, s); VISIT_QUIT(st, 0); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 15 23:19:05 2013 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 15 May 2013 23:19:05 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_complain_about?= =?utf-8?q?_=22global_=5F=5Fclass=5F=5F=22_in_a_class_body_=28closes_=2317?= =?utf-8?q?983=29?= Message-ID: <3b9pY52SX0z7LlF@mail.python.org> http://hg.python.org/cpython/rev/cd9141a4f999 changeset: 83784:cd9141a4f999 branch: 3.3 parent: 83781:f3097c6e7119 user: Benjamin Peterson date: Wed May 15 16:17:25 2013 -0500 summary: complain about "global __class__" in a class body (closes #17983) files: Lib/test/test_scope.py | 4 ++++ Misc/NEWS | 3 +++ Python/symtable.c | 6 ++++++ 3 files changed, 13 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_scope.py b/Lib/test/test_scope.py --- a/Lib/test/test_scope.py +++ b/Lib/test/test_scope.py @@ -743,6 +743,10 @@ del tester self.assertIsNone(ref()) + def test__Class__Global(self): + s = "class X:\n global __class__\n def f(self): super()" + self.assertRaises(SyntaxError, exec, s) + def test_main(): run_unittest(ScopeTests) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ Core and Builtins ----------------- +- Issue #17983: Raise a SyntaxError for a ``global __class__`` statement in a + class body. + - Issue #17927: Frame objects kept arguments alive if they had been copied into a cell, even if the cell was cleared. diff --git a/Python/symtable.c b/Python/symtable.c --- a/Python/symtable.c +++ b/Python/symtable.c @@ -1236,6 +1236,12 @@ asdl_seq *seq = s->v.Global.names; for (i = 0; i < asdl_seq_LEN(seq); i++) { identifier name = (identifier)asdl_seq_GET(seq, i); + if (st->st_cur->ste_type == ClassBlock && + !PyUnicode_CompareWithASCIIString(name, "__class__")) { + PyErr_SetString(PyExc_SyntaxError, "cannot make __class__ global"); + PyErr_SyntaxLocationEx(st->st_filename, s->lineno, s->col_offset); + return 0; + } long cur = symtable_lookup(st, name); if (cur < 0) VISIT_QUIT(st, 0); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 15 23:19:06 2013 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 15 May 2013 23:19:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_null_mege_3=2E3_with_fix_not_applicable_here?= Message-ID: <3b9pY64rQ0z7Ln8@mail.python.org> http://hg.python.org/cpython/rev/e74f4d6c0c81 changeset: 83785:e74f4d6c0c81 parent: 83783:3d858f1eef54 parent: 83784:cd9141a4f999 user: Benjamin Peterson date: Wed May 15 16:18:51 2013 -0500 summary: null mege 3.3 with fix not applicable here files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 15 23:59:07 2013 From: python-checkins at python.org (phillip.eby) Date: Wed, 15 May 2013 23:59:07 +0200 (CEST) Subject: [Python-checkins] r88994 - in sandbox/trunk/setuptools: pkg_resources.py setup.py setuptools.txt setuptools/command/easy_install.py setuptools/dist.py setuptools/package_index.py setuptools/sandbox.py setuptools/tests/api_tests.txt setuptools/tests/test_resources.py Message-ID: <3b9qRH406Fz7Lmr@mail.python.org> Author: phillip.eby Date: Wed May 15 23:59:07 2013 New Revision: 88994 Log: Snapshot pre-merger changes, mostly SSL support and a few bugfixes Modified: sandbox/trunk/setuptools/pkg_resources.py sandbox/trunk/setuptools/setup.py sandbox/trunk/setuptools/setuptools.txt sandbox/trunk/setuptools/setuptools/command/easy_install.py sandbox/trunk/setuptools/setuptools/dist.py sandbox/trunk/setuptools/setuptools/package_index.py sandbox/trunk/setuptools/setuptools/sandbox.py sandbox/trunk/setuptools/setuptools/tests/api_tests.txt sandbox/trunk/setuptools/setuptools/tests/test_resources.py Modified: sandbox/trunk/setuptools/pkg_resources.py ============================================================================== --- sandbox/trunk/setuptools/pkg_resources.py (original) +++ sandbox/trunk/setuptools/pkg_resources.py Wed May 15 23:59:07 2013 @@ -144,7 +144,7 @@ # Parsing functions and string utilities 'parse_requirements', 'parse_version', 'safe_name', 'safe_version', 'get_platform', 'compatible_platforms', 'yield_lines', 'split_sections', - 'safe_extra', 'to_filename', + 'safe_extra', 'to_filename', 'invalid_marker', 'evaluate_marker', # filesystem utilities 'ensure_directory', 'normalize_path', @@ -1146,6 +1146,129 @@ +_marker_names = { + 'os': ['name'], 'sys': ['platform'], + 'platform': ['version','machine','python_implementation'], + 'python_version': [], 'python_full_version': [], 'extra':[], +} + +_marker_values = { + 'os_name': lambda: os.name, + 'sys_platform': lambda: sys.platform, + 'python_full_version': lambda: sys.version.split()[0], + 'python_version': lambda:'%s.%s' % (sys.version_info[0], sys.version_info[1]), + 'platform_version': lambda: _platinfo('version'), + 'platform_machine': lambda: _platinfo('machine'), + 'python_implementation': lambda: _platinfo('python_implementation') or _pyimp(), +} + +def _platinfo(attr): + try: + import platform + except ImportError: + return '' + return getattr(platform, attr, lambda:'')() + +def _pyimp(): + if sys.platform=='cli': + return 'IronPython' + elif sys.platform.startswith('java'): + return 'Jython' + elif '__pypy__' in sys.builtin_module_names: + return 'PyPy' + else: + return 'CPython' + +def invalid_marker(text): + """Validate text as a PEP 426 environment marker; return exception or False""" + try: + evaluate_marker(text) + except SyntaxError: + return sys.exc_info()[1] + return False + +def evaluate_marker(text, extra=None, _ops={}): + """Evaluate a PEP 426 environment marker; SyntaxError if marker is invalid""" + + if not _ops: + + from token import NAME, STRING + import token, symbol, operator + + def and_test(nodelist): + # MUST NOT short-circuit evaluation, or invalid syntax can be skipped! + return reduce(operator.and_, [interpret(nodelist[i]) for i in range(1,len(nodelist),2)]) + + def test(nodelist): + # MUST NOT short-circuit evaluation, or invalid syntax can be skipped! + return reduce(operator.or_, [interpret(nodelist[i]) for i in range(1,len(nodelist),2)]) + + def atom(nodelist): + t = nodelist[1][0] + if t == token.LPAR: + if nodelist[2][0] == token.RPAR: + raise SyntaxError("Empty parentheses") + return interpret(nodelist[2]) + raise SyntaxError("Language feature not supported in environment markers") + + def comparison(nodelist): + if len(nodelist)>4: + raise SyntaxError("Chained comparison not allowed in environment markers") + comp = nodelist[2][1] + cop = comp[1] + if comp[0] == NAME: + if len(nodelist[2]) == 3: + if cop == 'not': + cop = 'not in' + else: + cop = 'is not' + try: + cop = _ops[cop] + except KeyError: + raise SyntaxError(repr(cop)+" operator not allowed in environment markers") + return cop(evaluate(nodelist[1]), evaluate(nodelist[3])) + + _ops.update({ + symbol.test: test, symbol.and_test: and_test, symbol.atom: atom, + symbol.comparison: comparison, 'not in': lambda x,y: x not in y, + 'in': lambda x,y: x in y, '==': operator.eq, '!=': operator.ne, + }) + if hasattr(symbol,'or_test'): + _ops[symbol.or_test] = test + + def interpret(nodelist): + while len(nodelist)==2: nodelist = nodelist[1] + try: + op = _ops[nodelist[0]] + except KeyError: + raise SyntaxError("Comparison or logical expression expected") + raise SyntaxError("Language feature not supported in environment markers: "+symbol.sym_name[nodelist[0]]) + return op(nodelist) + + def evaluate(nodelist): + while len(nodelist)==2: nodelist = nodelist[1] + kind = nodelist[0] + name = nodelist[1] + #while len(name)==2: name = name[1] + if kind==NAME: + try: + op = _marker_values[name] + except KeyError: + raise SyntaxError("Unknown name %r" % name) + return op() + if kind==STRING: + s = nodelist[1] + if s[:1] not in "'\"" or s.startswith('"""') or s.startswith("'''") \ + or '\\' in s: + raise SyntaxError( + "Only plain strings allowed in environment markers") + return s[1:-1] + raise SyntaxError("Language feature not supported in environment markers") + + import parser + return interpret(parser.expr(text).totuple(1)[1]) + + class NullProvider: """Try to implement resources and metadata for arbitrary PEP 302 loaders""" @@ -1843,7 +1966,6 @@ parts.pop() parts.append(part) return tuple(parts) - class EntryPoint(object): """Object representing an advertised importable object""" @@ -2057,7 +2179,14 @@ dm = self.__dep_map = {None: []} for name in 'requires.txt', 'depends.txt': for extra,reqs in split_sections(self._get_metadata(name)): - if extra: extra = safe_extra(extra) + if extra: + if ':' in extra: + extra, marker = extra.split(':',1) + if invalid_marker(marker): + reqs=[] # XXX warn + elif not evaluate_marker(marker): + reqs=[] + extra = safe_extra(extra) or None dm.setdefault(extra,[]).extend(parse_requirements(reqs)) return dm _dep_map = property(_dep_map) @@ -2081,6 +2210,8 @@ for line in self.get_metadata_lines(name): yield line + + def activate(self,path=None): """Ensure distribution is importable on `path` (default=sys.path)""" if path is None: path = sys.path @@ -2119,6 +2250,9 @@ raise AttributeError,attr return getattr(self._provider, attr) + + + #@classmethod def from_filename(cls,filename,metadata=None, **kw): return cls.from_location( @@ -2156,18 +2290,6 @@ - - - - - - - - - - - - Modified: sandbox/trunk/setuptools/setup.py ============================================================================== --- sandbox/trunk/setuptools/setup.py (original) +++ sandbox/trunk/setuptools/setup.py Wed May 15 23:59:07 2013 @@ -91,31 +91,31 @@ Topic :: System :: Archiving :: Packaging Topic :: System :: Systems Administration Topic :: Utilities""".splitlines() if f.strip()], + extras_require = { + "ssl:sys_platform=='win32'": "wincertstore==0.1", + "ssl:sys_platform=='win32' and python_version in '2.3, 2.4'": "ctypes==1.0.2", + "ssl:python_version in '2.3, 2.4, 2.5'":"ssl==1.16", + "certs": "certifi==0.0.8", + }, + dependency_links = [ + 'http://pypi.python.org/packages/source/c/certifi/certifi-0.0.8.tar.gz#md5=dc5f5e7f0b5fc08d27654b17daa6ecec', + 'http://pypi.python.org/packages/source/s/ssl/ssl-1.16.tar.gz#md5=fb12d335d56f3c8c7c1fefc1c06c4bfb', + 'http://pypi.python.org/packages/source/w/wincertstore/wincertstore-0.1.zip#md5=2f9accbebe8f7b4c06ac7aa83879b81c', + 'http://sourceforge.net/projects/ctypes/files/ctypes/1.0.2/ctypes-1.0.2.win32-py2.3.exe/download#md5=9afe4b75240a8808a24df7a76b6081e3', + 'http://sourceforge.net/projects/ctypes/files/ctypes/1.0.2/ctypes-1.0.2.win32-py2.4.exe/download#md5=9092a0ad5a3d79fa2d980f1ddc5e9dbc', + 'http://peak.telecommunity.com/dist/ssl-1.16-py2.3-win32.egg#md5=658f74b3eb6f32050e8531bb73de8e74', + 'http://peak.telecommunity.com/dist/ssl-1.16-py2.4-win32.egg#md5=3cfa2c526dc66e318e8520b6f1aadce5', + 'http://peak.telecommunity.com/dist/ssl-1.16-py2.5-win32.egg#md5=85ad1cda806d639743121c0bbcb5f39b', + ], scripts = [], # uncomment for testing # setup_requires = ['setuptools>=0.6a0'], + # tests_require = "setuptools[ssl]", ) - - - - - - - - - - - - - - - - - Modified: sandbox/trunk/setuptools/setuptools.txt ============================================================================== --- sandbox/trunk/setuptools/setuptools.txt (original) +++ sandbox/trunk/setuptools/setuptools.txt Wed May 15 23:59:07 2013 @@ -217,11 +217,7 @@ but here are a few tips that will keep you out of trouble in the corner cases: * Don't use ``-`` or any other character than ``.`` as a separator, unless you - really want a post-release. Remember that ``2.1-rc2`` means you've - *already* released ``2.1``, whereas ``2.1rc2`` and ``2.1.c2`` are candidates - you're putting out *before* ``2.1``. If you accidentally distribute copies - of a post-release that you meant to be a pre-release, the only safe fix is to - bump your main release number (e.g. to ``2.1.1``) and re-release the project. + really want a post-release. * Don't stick adjoining pre-release tags together without a dot or number between them. Version ``1.9adev`` is the ``adev`` prerelease of ``1.9``, @@ -239,7 +235,7 @@ >>> parse_version('1.9.a.dev') == parse_version('1.9a0dev') True >>> parse_version('2.1-rc2') < parse_version('2.1') - False + True >>> parse_version('0.6a9dev-r41475') < parse_version('0.6a9') True Modified: sandbox/trunk/setuptools/setuptools/command/easy_install.py ============================================================================== --- sandbox/trunk/setuptools/setuptools/command/easy_install.py (original) +++ sandbox/trunk/setuptools/setuptools/command/easy_install.py Wed May 15 23:59:07 2013 @@ -156,7 +156,7 @@ else: self.all_site_dirs.append(normalize_path(d)) if not self.editable: self.check_site_dir() - self.index_url = self.index_url or "http://pypi.python.org/simple" + self.index_url = self.index_url or "https://pypi.python.org/simple" self.shadow_path = self.all_site_dirs[:] for path_item in self.install_dir, normalize_path(self.script_dir): if path_item not in self.shadow_path: Modified: sandbox/trunk/setuptools/setuptools/dist.py ============================================================================== --- sandbox/trunk/setuptools/setuptools/dist.py (original) +++ sandbox/trunk/setuptools/setuptools/dist.py Wed May 15 23:59:07 2013 @@ -47,7 +47,6 @@ raise DistutilsSetupError( "%r must be a list of strings (got %r)" % (attr,value) ) - def check_nsp(dist, attr, value): """Verify that namespace packages are valid""" assert_string_list(dist,attr,value) @@ -69,6 +68,10 @@ """Verify that extras_require mapping is valid""" try: for k,v in value.items(): + if ':' in k: + k,m = k.split(':',1) + if pkg_resources.invalid_marker(m): + raise DistutilsSetupError("Invalid environment marker: "+m) list(pkg_resources.parse_requirements(v)) except (TypeError,ValueError,AttributeError): raise DistutilsSetupError( @@ -77,9 +80,6 @@ "requirement specifiers." ) - - - def assert_bool(dist, attr, value): """Verify that value is True, False, 0, or 1""" if bool(value) != value: Modified: sandbox/trunk/setuptools/setuptools/package_index.py ============================================================================== --- sandbox/trunk/setuptools/setuptools/package_index.py (original) +++ sandbox/trunk/setuptools/setuptools/package_index.py Wed May 15 23:59:07 2013 @@ -1,6 +1,6 @@ """PyPI and direct package downloading""" import sys, os.path, re, urlparse, urllib2, shutil, random, socket, cStringIO -import httplib, urllib +import httplib, urllib; from setuptools import ssl_support from pkg_resources import * from distutils import log from distutils.errors import DistutilsError @@ -145,12 +145,11 @@ urllib2.__version__, require('setuptools')[0].version ) - class PackageIndex(Environment): """A distribution index that scans web pages for download URLs""" - def __init__(self, index_url="http://pypi.python.org/simple", hosts=('*',), - *args, **kw + def __init__(self, index_url="https://pypi.python.org/simple", hosts=('*',), + ca_bundle=None, verify_ssl=True, *args, **kw ): Environment.__init__(self,*args,**kw) self.index_url = index_url + "/"[:not index_url.endswith('/')] @@ -159,8 +158,9 @@ self.package_pages = {} self.allows = re.compile('|'.join(map(translate,hosts))).match self.to_scan = [] - - + if verify_ssl and ssl_support.is_available and (ca_bundle or ssl_support.find_ca_bundle()): + self.opener = ssl_support.opener_for(ca_bundle) + else: self.opener = urllib2.urlopen def process_url(self, url, retrieve=False): """Evaluate a URL as a possible download, and maybe retrieve it""" @@ -575,12 +575,13 @@ def open_url(self, url, warning=None): if url.startswith('file:'): return local_open(url) try: - return open_with_auth(url) - except urllib2.HTTPError, v: - return v - except urllib2.URLError, v: - reason = v.reason - except httplib.HTTPException, v: + return open_with_auth(url, self.opener) + except urllib2.HTTPError: + return sys.exc_info()[1] + except urllib2.URLError: + reason = sys.exc_info()[1].reason + except httplib.HTTPException: + v = sys.exc_info()[1] reason = "%s: %s" % (v.__doc__ or v.__class__.__name__, v) if warning: self.warn(warning, reason) @@ -612,7 +613,6 @@ self.url_ok(url, True) # raises error if not allowed return self._attempt_download(url, filename) - def scan_url(self, url): self.process_url(url, True) @@ -736,7 +736,7 @@ -def open_with_auth(url): +def open_with_auth(url, opener=urllib2.urlopen): """Open a urllib2 request, handling HTTP authentication""" scheme, netloc, path, params, query, frag = urlparse.urlparse(url) @@ -755,7 +755,7 @@ request = urllib2.Request(url) request.add_header('User-Agent', user_agent) - fp = urllib2.urlopen(request) + fp = opener(request) if auth: # Put authentication info back into request URL if same host, Modified: sandbox/trunk/setuptools/setuptools/sandbox.py ============================================================================== --- sandbox/trunk/setuptools/setuptools/sandbox.py (original) +++ sandbox/trunk/setuptools/setuptools/sandbox.py Wed May 15 23:59:07 2013 @@ -206,7 +206,7 @@ def tmpnam(self): self._violation("tmpnam") def _ok(self,path): - if hasattr(_os,'devnull') and path==_os.devnull: return True + if hasattr(os,'devnull') and path==os.devnull: return True active = self._active try: self._active = False Modified: sandbox/trunk/setuptools/setuptools/tests/api_tests.txt ============================================================================== --- sandbox/trunk/setuptools/setuptools/tests/api_tests.txt (original) +++ sandbox/trunk/setuptools/setuptools/tests/api_tests.txt Wed May 15 23:59:07 2013 @@ -328,3 +328,94 @@ >>> cp("darwin-8.2.0-Power_Macintosh", "macosx-10.3-ppc") False + +Environment Markers +------------------- + + >>> from pkg_resources import invalid_marker as im, evaluate_marker as em + >>> import os + + >>> print(im("sys_platform")) + Comparison or logical expression expected + + >>> print(im("sys_platform==")) + unexpected EOF while parsing (line 1) + + >>> print(im("sys_platform=='win32'")) + False + + >>> print(im("sys=='x'")) + Unknown name 'sys' + + >>> print(im("(extra)")) + Comparison or logical expression expected + + >>> print(im("(extra")) + unexpected EOF while parsing (line 1) + + >>> print(im("os.open('foo')=='y'")) + Language feature not supported in environment markers + + >>> print(im("'x'=='y' and os.open('foo')=='y'")) # no short-circuit! + Language feature not supported in environment markers + + >>> print(im("'x'=='x' or os.open('foo')=='y'")) # no short-circuit! + Language feature not supported in environment markers + + >>> print(im("'x' < 'y'")) + '<' operator not allowed in environment markers + + >>> print(im("'x' < 'y' < 'z'")) + Chained comparison not allowed in environment markers + + >>> print(im("r'x'=='x'")) + Only plain strings allowed in environment markers + + >>> print(im("'''x'''=='x'")) + Only plain strings allowed in environment markers + + >>> print(im('"""x"""=="x"')) + Only plain strings allowed in environment markers + + >>> print(im(r"'x\n'=='x'")) + Only plain strings allowed in environment markers + + >>> print(im("os.open=='y'")) + Language feature not supported in environment markers + + >>> em('"x"=="x"') + True + + >>> em('"x"=="y"') + False + + >>> em('"x"=="y" and "x"=="x"') + False + + >>> em('"x"=="y" or "x"=="x"') + True + + >>> em('"x"=="y" and "x"=="q" or "z"=="z"') + True + + >>> em('"x"=="y" and ("x"=="q" or "z"=="z")') + False + + >>> em('"x"=="y" and "z"=="z" or "x"=="q"') + False + + >>> em('"x"=="x" and "z"=="z" or "x"=="q"') + True + + >>> em("sys_platform=='win32'") == (sys.platform=='win32') + True + + >>> em("'x' in 'yx'") + True + + >>> em("'yx' in 'x'") + False + + + + Modified: sandbox/trunk/setuptools/setuptools/tests/test_resources.py ============================================================================== --- sandbox/trunk/setuptools/setuptools/tests/test_resources.py (original) +++ sandbox/trunk/setuptools/setuptools/tests/test_resources.py Wed May 15 23:59:07 2013 @@ -507,7 +507,7 @@ def test_get_script_header_jython_workaround(self): platform = sys.platform sys.platform = 'java1.5.0_13' - stdout = sys.stdout + stdout, stderr = sys.stdout, sys.stderr try: # A mock sys.executable that uses a shebang line (this file) exe = os.path.normpath(os.path.splitext(__file__)[0] + '.py') @@ -517,17 +517,17 @@ # Ensure we generate what is basically a broken shebang line # when there's options, with a warning emitted - sys.stdout = StringIO.StringIO() + sys.stdout = sys.stderr = StringIO.StringIO() self.assertEqual(get_script_header('#!/usr/bin/python -x', executable=exe), '#!%s -x\n' % exe) self.assert_('Unable to adapt shebang line' in sys.stdout.getvalue()) - sys.stdout = StringIO.StringIO() + sys.stdout = sys.stderr = StringIO.StringIO() self.assertEqual(get_script_header('#!/usr/bin/python', executable=self.non_ascii_exe), '#!%s -x\n' % self.non_ascii_exe) self.assert_('Unable to adapt shebang line' in sys.stdout.getvalue()) finally: sys.platform = platform - sys.stdout = stdout + sys.stdout, sys.stderr = stdout, stderr From python-checkins at python.org Thu May 16 00:01:01 2013 From: python-checkins at python.org (phillip.eby) Date: Thu, 16 May 2013 00:01:01 +0200 (CEST) Subject: [Python-checkins] r88996 - in sandbox/trunk/setuptools: setuptools.egg-info/dependency_links.txt setuptools.egg-info/requires.txt setuptools/ssl_support.py Message-ID: <3b9qTT6bTZz7LkR@mail.python.org> Author: phillip.eby Date: Thu May 16 00:01:01 2013 New Revision: 88996 Log: Oops, forgot some files Added: sandbox/trunk/setuptools/setuptools.egg-info/dependency_links.txt (contents, props changed) sandbox/trunk/setuptools/setuptools.egg-info/requires.txt (contents, props changed) sandbox/trunk/setuptools/setuptools/ssl_support.py (contents, props changed) Added: sandbox/trunk/setuptools/setuptools.egg-info/dependency_links.txt ============================================================================== --- (empty file) +++ sandbox/trunk/setuptools/setuptools.egg-info/dependency_links.txt Thu May 16 00:01:01 2013 @@ -0,0 +1,8 @@ +http://pypi.python.org/packages/source/c/certifi/certifi-0.0.8.tar.gz#md5=dc5f5e7f0b5fc08d27654b17daa6ecec +http://pypi.python.org/packages/source/s/ssl/ssl-1.16.tar.gz#md5=fb12d335d56f3c8c7c1fefc1c06c4bfb +http://pypi.python.org/packages/source/w/wincertstore/wincertstore-0.1.zip#md5=2f9accbebe8f7b4c06ac7aa83879b81c +http://sourceforge.net/projects/ctypes/files/ctypes/1.0.2/ctypes-1.0.2.win32-py2.3.exe/download#md5=9afe4b75240a8808a24df7a76b6081e3 +http://sourceforge.net/projects/ctypes/files/ctypes/1.0.2/ctypes-1.0.2.win32-py2.4.exe/download#md5=9092a0ad5a3d79fa2d980f1ddc5e9dbc +http://peak.telecommunity.com/dist/ssl-1.16-py2.3-win32.egg#md5=658f74b3eb6f32050e8531bb73de8e74 +http://peak.telecommunity.com/dist/ssl-1.16-py2.4-win32.egg#md5=3cfa2c526dc66e318e8520b6f1aadce5 +http://peak.telecommunity.com/dist/ssl-1.16-py2.5-win32.egg#md5=85ad1cda806d639743121c0bbcb5f39b Added: sandbox/trunk/setuptools/setuptools.egg-info/requires.txt ============================================================================== --- (empty file) +++ sandbox/trunk/setuptools/setuptools.egg-info/requires.txt Thu May 16 00:01:01 2013 @@ -0,0 +1,13 @@ + + +[ssl:sys_platform=='win32'] +wincertstore==0.1 + +[certs] +certifi==0.0.8 + +[ssl:sys_platform=='win32' and python_version in '2.3, 2.4'] +ctypes==1.0.2 + +[ssl:python_version in '2.3, 2.4, 2.5'] +ssl==1.16 \ No newline at end of file Added: sandbox/trunk/setuptools/setuptools/ssl_support.py ============================================================================== --- (empty file) +++ sandbox/trunk/setuptools/setuptools/ssl_support.py Thu May 16 00:01:01 2013 @@ -0,0 +1,246 @@ +import sys, os, socket, urllib2, atexit, re +from pkg_resources import ResolutionError, ExtractionError + +try: + import ssl +except ImportError: + ssl = None + +__all__ = [ + 'VerifyingHTTPSHandler', 'find_ca_bundle', 'is_available', 'cert_paths', + 'opener_for' +] + +cert_paths = """ +/etc/pki/tls/certs/ca-bundle.crt +/etc/ssl/certs/ca-certificates.crt +/usr/share/ssl/certs/ca-bundle.crt +/usr/local/share/certs/ca-root.crt +/etc/ssl/cert.pem +/System/Library/OpenSSL/certs/cert.pem +""".strip().split() + + +HTTPSHandler = HTTPSConnection = object + +for what, where in ( + ('HTTPSHandler', ['urllib2','urllib.request']), + ('HTTPSConnection', ['httplib', 'http.client']), +): + for module in where: + try: + exec("from %s import %s" % (module, what)) + except ImportError: + pass + +is_available = ssl is not None and object not in (HTTPSHandler, HTTPSConnection) + + + + + +try: + from socket import create_connection +except ImportError: + _GLOBAL_DEFAULT_TIMEOUT = getattr(socket, '_GLOBAL_DEFAULT_TIMEOUT', object()) + def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, + source_address=None): + """Connect to *address* and return the socket object. + + Convenience function. Connect to *address* (a 2-tuple ``(host, + port)``) and return the socket object. Passing the optional + *timeout* parameter will set the timeout on the socket instance + before attempting to connect. If no *timeout* is supplied, the + global default timeout setting returned by :func:`getdefaulttimeout` + is used. If *source_address* is set it must be a tuple of (host, port) + for the socket to bind as a source address before making the connection. + An host of '' or port 0 tells the OS to use the default. + """ + host, port = address + err = None + for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM): + af, socktype, proto, canonname, sa = res + sock = None + try: + sock = socket.socket(af, socktype, proto) + if timeout is not _GLOBAL_DEFAULT_TIMEOUT: + sock.settimeout(timeout) + if source_address: + sock.bind(source_address) + sock.connect(sa) + return sock + + except error: + err = True + if sock is not None: + sock.close() + if err: + raise + else: + raise error("getaddrinfo returns an empty list") + + +try: + from ssl import CertificateError, match_hostname +except ImportError: + class CertificateError(ValueError): + pass + + def _dnsname_to_pat(dn): + pats = [] + for frag in dn.split(r'.'): + if frag == '*': + # When '*' is a fragment by itself, it matches a non-empty dotless + # fragment. + pats.append('[^.]+') + else: + # Otherwise, '*' matches any dotless fragment. + frag = re.escape(frag) + pats.append(frag.replace(r'\*', '[^.]*')) + return re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE) + + def match_hostname(cert, hostname): + """Verify that *cert* (in decoded format as returned by + SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 rules + are mostly followed, but IP addresses are not accepted for *hostname*. + + CertificateError is raised on failure. On success, the function + returns nothing. + """ + if not cert: + raise ValueError("empty or no certificate") + dnsnames = [] + san = cert.get('subjectAltName', ()) + for key, value in san: + if key == 'DNS': + if _dnsname_to_pat(value).match(hostname): + return + dnsnames.append(value) + if not dnsnames: + # The subject is only checked when there is no dNSName entry + # in subjectAltName + for sub in cert.get('subject', ()): + for key, value in sub: + # XXX according to RFC 2818, the most specific Common Name + # must be used. + if key == 'commonName': + if _dnsname_to_pat(value).match(hostname): + return + dnsnames.append(value) + if len(dnsnames) > 1: + raise CertificateError("hostname %r " + "doesn't match either of %s" + % (hostname, ', '.join(map(repr, dnsnames)))) + elif len(dnsnames) == 1: + raise CertificateError("hostname %r " + "doesn't match %r" + % (hostname, dnsnames[0])) + else: + raise CertificateError("no appropriate commonName or " + "subjectAltName fields were found") + + + + + + + + + + + + + + + + + + + + + + + + +class VerifyingHTTPSHandler(HTTPSHandler): + """Simple verifying handler: no auth, subclasses, timeouts, etc.""" + + def __init__(self, ca_bundle): + self.ca_bundle = ca_bundle + HTTPSHandler.__init__(self) + + def https_open(self, req): + return self.do_open( + lambda host, **kw: VerifyingHTTPSConn(host, self.ca_bundle, **kw), req + ) + + +class VerifyingHTTPSConn(HTTPSConnection): + """Simple verifying connection: no auth, subclasses, timeouts, etc.""" + def __init__(self, host, ca_bundle, **kw): + HTTPSConnection.__init__(self, host, **kw) + self.ca_bundle = ca_bundle + + def connect(self): + sock = create_connection( + (self.host, self.port), getattr(self,'source_address',None) + ) + self.sock = ssl.wrap_socket( + sock, cert_reqs=ssl.CERT_REQUIRED, ca_certs=self.ca_bundle + ) + try: + match_hostname(self.sock.getpeercert(), self.host) + except CertificateError: + self.sock.shutdown(socket.SHUT_RDWR) + self.sock.close() + raise + +def opener_for(ca_bundle=None): + """Get a urlopen() replacement that uses ca_bundle for verification""" + return urllib2.build_opener( + VerifyingHTTPSHandler(ca_bundle or find_ca_bundle()) + ).open + + + +_wincerts = None + +def get_win_certfile(): + global _wincerts + if _wincerts is not None: + return _wincerts.name + + try: + from wincertstore import CertFile + except ImportError: + return None + + class MyCertFile(CertFile): + def __init__(self, stores=(), certs=()): + CertFile.__init__(self) + for store in stores: + self.addstore(store) + self.addcerts(certs) + atexit.register(self.close) + + _wincerts = MyCertFile(stores=['CA', 'ROOT']) + return _wincerts.name + + +def find_ca_bundle(): + """Return an existing CA bundle path, or None""" + if os.name=='nt': + return get_win_certfile() + else: + for cert_path in cert_paths: + if os.path.isfile(cert_path): + return cert_path + try: + return pkg_resources.resource_filename('certifi', 'cacert.pem') + except (ImportError, ResolutionError, ExtractionError): + return None + + + + + From python-checkins at python.org Thu May 16 00:04:59 2013 From: python-checkins at python.org (phillip.eby) Date: Thu, 16 May 2013 00:04:59 +0200 (CEST) Subject: [Python-checkins] r88997 - in sandbox/branches/setuptools-0.6: EasyInstall.txt api_tests.txt pkg_resources.py setup.py setuptools.egg-info/dependency_links.txt setuptools.egg-info/entry_points.txt setuptools.egg-info/requires.txt setuptools.txt setuptools/command/easy_install.py setuptools/dist.py setuptools/package_index.py setuptools/sandbox.py setuptools/ssl_support.py setuptools/tests/test_resources.py Message-ID: <3b9qZ35KTSz7LkR@mail.python.org> Author: phillip.eby Date: Thu May 16 00:04:59 2013 New Revision: 88997 Log: Snapshotting pre-merge changes, mostly SSL support and a few bug fixes Added: sandbox/branches/setuptools-0.6/setuptools.egg-info/dependency_links.txt (contents, props changed) sandbox/branches/setuptools-0.6/setuptools.egg-info/requires.txt (contents, props changed) sandbox/branches/setuptools-0.6/setuptools/ssl_support.py (contents, props changed) Modified: sandbox/branches/setuptools-0.6/EasyInstall.txt sandbox/branches/setuptools-0.6/api_tests.txt sandbox/branches/setuptools-0.6/pkg_resources.py sandbox/branches/setuptools-0.6/setup.py sandbox/branches/setuptools-0.6/setuptools.egg-info/entry_points.txt sandbox/branches/setuptools-0.6/setuptools.txt sandbox/branches/setuptools-0.6/setuptools/command/easy_install.py sandbox/branches/setuptools-0.6/setuptools/dist.py sandbox/branches/setuptools-0.6/setuptools/package_index.py sandbox/branches/setuptools-0.6/setuptools/sandbox.py sandbox/branches/setuptools-0.6/setuptools/tests/test_resources.py Modified: sandbox/branches/setuptools-0.6/EasyInstall.txt ============================================================================== --- sandbox/branches/setuptools-0.6/EasyInstall.txt (original) +++ sandbox/branches/setuptools-0.6/EasyInstall.txt Thu May 16 00:04:59 2013 @@ -1217,7 +1217,9 @@ Release Notes/Change History ============================ -0.6final +0.6c12 + * Default --index-URL to SSL version of PyPI + * Fixed AttributeError under Python 2.3 when processing "HTTP authentication" URLs (i.e., ones with a ``user:password at host``). Modified: sandbox/branches/setuptools-0.6/api_tests.txt ============================================================================== --- sandbox/branches/setuptools-0.6/api_tests.txt (original) +++ sandbox/branches/setuptools-0.6/api_tests.txt Thu May 16 00:04:59 2013 @@ -328,3 +328,94 @@ >>> cp("darwin-8.2.0-Power_Macintosh", "macosx-10.3-ppc") False + +Environment Markers +------------------- + + >>> from pkg_resources import invalid_marker as im, evaluate_marker as em + >>> import os + + >>> print(im("sys_platform")) + Comparison or logical expression expected + + >>> print(im("sys_platform==")) + unexpected EOF while parsing (line 1) + + >>> print(im("sys_platform=='win32'")) + False + + >>> print(im("sys=='x'")) + Unknown name 'sys' + + >>> print(im("(extra)")) + Comparison or logical expression expected + + >>> print(im("(extra")) + unexpected EOF while parsing (line 1) + + >>> print(im("os.open('foo')=='y'")) + Language feature not supported in environment markers + + >>> print(im("'x'=='y' and os.open('foo')=='y'")) # no short-circuit! + Language feature not supported in environment markers + + >>> print(im("'x'=='x' or os.open('foo')=='y'")) # no short-circuit! + Language feature not supported in environment markers + + >>> print(im("'x' < 'y'")) + '<' operator not allowed in environment markers + + >>> print(im("'x' < 'y' < 'z'")) + Chained comparison not allowed in environment markers + + >>> print(im("r'x'=='x'")) + Only plain strings allowed in environment markers + + >>> print(im("'''x'''=='x'")) + Only plain strings allowed in environment markers + + >>> print(im('"""x"""=="x"')) + Only plain strings allowed in environment markers + + >>> print(im(r"'x\n'=='x'")) + Only plain strings allowed in environment markers + + >>> print(im("os.open=='y'")) + Language feature not supported in environment markers + + >>> em('"x"=="x"') + True + + >>> em('"x"=="y"') + False + + >>> em('"x"=="y" and "x"=="x"') + False + + >>> em('"x"=="y" or "x"=="x"') + True + + >>> em('"x"=="y" and "x"=="q" or "z"=="z"') + True + + >>> em('"x"=="y" and ("x"=="q" or "z"=="z")') + False + + >>> em('"x"=="y" and "z"=="z" or "x"=="q"') + False + + >>> em('"x"=="x" and "z"=="z" or "x"=="q"') + True + + >>> em("sys_platform=='win32'") == (sys.platform=='win32') + True + + >>> em("'x' in 'yx'") + True + + >>> em("'yx' in 'x'") + False + + + + Modified: sandbox/branches/setuptools-0.6/pkg_resources.py ============================================================================== --- sandbox/branches/setuptools-0.6/pkg_resources.py (original) +++ sandbox/branches/setuptools-0.6/pkg_resources.py Thu May 16 00:04:59 2013 @@ -144,7 +144,7 @@ # Parsing functions and string utilities 'parse_requirements', 'parse_version', 'safe_name', 'safe_version', 'get_platform', 'compatible_platforms', 'yield_lines', 'split_sections', - 'safe_extra', 'to_filename', + 'safe_extra', 'to_filename', 'invalid_marker', 'evaluate_marker', # filesystem utilities 'ensure_directory', 'normalize_path', @@ -1146,6 +1146,129 @@ +_marker_names = { + 'os': ['name'], 'sys': ['platform'], + 'platform': ['version','machine','python_implementation'], + 'python_version': [], 'python_full_version': [], 'extra':[], +} + +_marker_values = { + 'os_name': lambda: os.name, + 'sys_platform': lambda: sys.platform, + 'python_full_version': lambda: sys.version.split()[0], + 'python_version': lambda:'%s.%s' % (sys.version_info[0], sys.version_info[1]), + 'platform_version': lambda: _platinfo('version'), + 'platform_machine': lambda: _platinfo('machine'), + 'python_implementation': lambda: _platinfo('python_implementation') or _pyimp(), +} + +def _platinfo(attr): + try: + import platform + except ImportError: + return '' + return getattr(platform, attr, lambda:'')() + +def _pyimp(): + if sys.platform=='cli': + return 'IronPython' + elif sys.platform.startswith('java'): + return 'Jython' + elif '__pypy__' in sys.builtin_module_names: + return 'PyPy' + else: + return 'CPython' + +def invalid_marker(text): + """Validate text as a PEP 426 environment marker; return exception or False""" + try: + evaluate_marker(text) + except SyntaxError: + return sys.exc_info()[1] + return False + +def evaluate_marker(text, extra=None, _ops={}): + """Evaluate a PEP 426 environment marker; SyntaxError if marker is invalid""" + + if not _ops: + + from token import NAME, STRING + import token, symbol, operator + + def and_test(nodelist): + # MUST NOT short-circuit evaluation, or invalid syntax can be skipped! + return reduce(operator.and_, [interpret(nodelist[i]) for i in range(1,len(nodelist),2)]) + + def test(nodelist): + # MUST NOT short-circuit evaluation, or invalid syntax can be skipped! + return reduce(operator.or_, [interpret(nodelist[i]) for i in range(1,len(nodelist),2)]) + + def atom(nodelist): + t = nodelist[1][0] + if t == token.LPAR: + if nodelist[2][0] == token.RPAR: + raise SyntaxError("Empty parentheses") + return interpret(nodelist[2]) + raise SyntaxError("Language feature not supported in environment markers") + + def comparison(nodelist): + if len(nodelist)>4: + raise SyntaxError("Chained comparison not allowed in environment markers") + comp = nodelist[2][1] + cop = comp[1] + if comp[0] == NAME: + if len(nodelist[2]) == 3: + if cop == 'not': + cop = 'not in' + else: + cop = 'is not' + try: + cop = _ops[cop] + except KeyError: + raise SyntaxError(repr(cop)+" operator not allowed in environment markers") + return cop(evaluate(nodelist[1]), evaluate(nodelist[3])) + + _ops.update({ + symbol.test: test, symbol.and_test: and_test, symbol.atom: atom, + symbol.comparison: comparison, 'not in': lambda x,y: x not in y, + 'in': lambda x,y: x in y, '==': operator.eq, '!=': operator.ne, + }) + if hasattr(symbol,'or_test'): + _ops[symbol.or_test] = test + + def interpret(nodelist): + while len(nodelist)==2: nodelist = nodelist[1] + try: + op = _ops[nodelist[0]] + except KeyError: + raise SyntaxError("Comparison or logical expression expected") + raise SyntaxError("Language feature not supported in environment markers: "+symbol.sym_name[nodelist[0]]) + return op(nodelist) + + def evaluate(nodelist): + while len(nodelist)==2: nodelist = nodelist[1] + kind = nodelist[0] + name = nodelist[1] + #while len(name)==2: name = name[1] + if kind==NAME: + try: + op = _marker_values[name] + except KeyError: + raise SyntaxError("Unknown name %r" % name) + return op() + if kind==STRING: + s = nodelist[1] + if s[:1] not in "'\"" or s.startswith('"""') or s.startswith("'''") \ + or '\\' in s: + raise SyntaxError( + "Only plain strings allowed in environment markers") + return s[1:-1] + raise SyntaxError("Language feature not supported in environment markers") + + import parser + return interpret(parser.expr(text).totuple(1)[1]) + + class NullProvider: """Try to implement resources and metadata for arbitrary PEP 302 loaders""" @@ -1925,7 +2048,6 @@ parts.pop() parts.append(part) return tuple(parts) - class EntryPoint(object): """Object representing an advertised importable object""" @@ -2139,7 +2261,14 @@ dm = self.__dep_map = {None: []} for name in 'requires.txt', 'depends.txt': for extra,reqs in split_sections(self._get_metadata(name)): - if extra: extra = safe_extra(extra) + if extra: + if ':' in extra: + extra, marker = extra.split(':',1) + if invalid_marker(marker): + reqs=[] # XXX warn + elif not evaluate_marker(marker): + reqs=[] + extra = safe_extra(extra) or None dm.setdefault(extra,[]).extend(parse_requirements(reqs)) return dm _dep_map = property(_dep_map) @@ -2163,6 +2292,8 @@ for line in self.get_metadata_lines(name): yield line + + def activate(self,path=None): """Ensure distribution is importable on `path` (default=sys.path)""" if path is None: path = sys.path @@ -2201,6 +2332,9 @@ raise AttributeError,attr return getattr(self._provider, attr) + + + #@classmethod def from_filename(cls,filename,metadata=None, **kw): return cls.from_location( @@ -2238,18 +2372,6 @@ - - - - - - - - - - - - Modified: sandbox/branches/setuptools-0.6/setup.py ============================================================================== --- sandbox/branches/setuptools-0.6/setup.py (original) +++ sandbox/branches/setuptools-0.6/setup.py Thu May 16 00:04:59 2013 @@ -91,31 +91,31 @@ Topic :: System :: Archiving :: Packaging Topic :: System :: Systems Administration Topic :: Utilities""".splitlines() if f.strip()], - scripts = scripts, + extras_require = { + "ssl:sys_platform=='win32'": "wincertstore==0.1", + "ssl:sys_platform=='win32' and python_version in '2.3, 2.4'": "ctypes==1.0.2", + "ssl:python_version in '2.3, 2.4, 2.5'":"ssl==1.16", + "certs": "certifi==0.0.8", + }, + dependency_links = [ + 'http://pypi.python.org/packages/source/c/certifi/certifi-0.0.8.tar.gz#md5=dc5f5e7f0b5fc08d27654b17daa6ecec', + 'http://pypi.python.org/packages/source/s/ssl/ssl-1.16.tar.gz#md5=fb12d335d56f3c8c7c1fefc1c06c4bfb', + 'http://pypi.python.org/packages/source/w/wincertstore/wincertstore-0.1.zip#md5=2f9accbebe8f7b4c06ac7aa83879b81c', + 'http://sourceforge.net/projects/ctypes/files/ctypes/1.0.2/ctypes-1.0.2.win32-py2.3.exe/download#md5=9afe4b75240a8808a24df7a76b6081e3', + 'http://sourceforge.net/projects/ctypes/files/ctypes/1.0.2/ctypes-1.0.2.win32-py2.4.exe/download#md5=9092a0ad5a3d79fa2d980f1ddc5e9dbc', + 'http://peak.telecommunity.com/dist/ssl-1.16-py2.3-win32.egg#md5=658f74b3eb6f32050e8531bb73de8e74', + 'http://peak.telecommunity.com/dist/ssl-1.16-py2.4-win32.egg#md5=3cfa2c526dc66e318e8520b6f1aadce5', + 'http://peak.telecommunity.com/dist/ssl-1.16-py2.5-win32.egg#md5=85ad1cda806d639743121c0bbcb5f39b', + ], + scripts = [], # uncomment for testing # setup_requires = ['setuptools>=0.6a0'], + # tests_require = "setuptools[ssl]", ) - - - - - - - - - - - - - - - - - Added: sandbox/branches/setuptools-0.6/setuptools.egg-info/dependency_links.txt ============================================================================== --- (empty file) +++ sandbox/branches/setuptools-0.6/setuptools.egg-info/dependency_links.txt Thu May 16 00:04:59 2013 @@ -0,0 +1,8 @@ +http://pypi.python.org/packages/source/c/certifi/certifi-0.0.8.tar.gz#md5=dc5f5e7f0b5fc08d27654b17daa6ecec +http://pypi.python.org/packages/source/s/ssl/ssl-1.16.tar.gz#md5=fb12d335d56f3c8c7c1fefc1c06c4bfb +http://pypi.python.org/packages/source/w/wincertstore/wincertstore-0.1.zip#md5=2f9accbebe8f7b4c06ac7aa83879b81c +http://sourceforge.net/projects/ctypes/files/ctypes/1.0.2/ctypes-1.0.2.win32-py2.3.exe/download#md5=9afe4b75240a8808a24df7a76b6081e3 +http://sourceforge.net/projects/ctypes/files/ctypes/1.0.2/ctypes-1.0.2.win32-py2.4.exe/download#md5=9092a0ad5a3d79fa2d980f1ddc5e9dbc +http://peak.telecommunity.com/dist/ssl-1.16-py2.3-win32.egg#md5=658f74b3eb6f32050e8531bb73de8e74 +http://peak.telecommunity.com/dist/ssl-1.16-py2.4-win32.egg#md5=3cfa2c526dc66e318e8520b6f1aadce5 +http://peak.telecommunity.com/dist/ssl-1.16-py2.5-win32.egg#md5=85ad1cda806d639743121c0bbcb5f39b Modified: sandbox/branches/setuptools-0.6/setuptools.egg-info/entry_points.txt ============================================================================== --- sandbox/branches/setuptools-0.6/setuptools.egg-info/entry_points.txt (original) +++ sandbox/branches/setuptools-0.6/setuptools.egg-info/entry_points.txt Thu May 16 00:04:59 2013 @@ -7,6 +7,7 @@ saveopts = setuptools.command.saveopts:saveopts egg_info = setuptools.command.egg_info:egg_info register = setuptools.command.register:register +upload = setuptools.command.upload:upload install_egg_info = setuptools.command.install_egg_info:install_egg_info alias = setuptools.command.alias:alias easy_install = setuptools.command.easy_install:easy_install Added: sandbox/branches/setuptools-0.6/setuptools.egg-info/requires.txt ============================================================================== --- (empty file) +++ sandbox/branches/setuptools-0.6/setuptools.egg-info/requires.txt Thu May 16 00:04:59 2013 @@ -0,0 +1,13 @@ + + +[ssl:sys_platform=='win32'] +wincertstore==0.1 + +[certs] +certifi==0.0.8 + +[ssl:sys_platform=='win32' and python_version in '2.3, 2.4'] +ctypes==1.0.2 + +[ssl:python_version in '2.3, 2.4, 2.5'] +ssl==1.16 \ No newline at end of file Modified: sandbox/branches/setuptools-0.6/setuptools.txt ============================================================================== --- sandbox/branches/setuptools-0.6/setuptools.txt (original) +++ sandbox/branches/setuptools-0.6/setuptools.txt Thu May 16 00:04:59 2013 @@ -217,11 +217,7 @@ but here are a few tips that will keep you out of trouble in the corner cases: * Don't use ``-`` or any other character than ``.`` as a separator, unless you - really want a post-release. Remember that ``2.1-rc2`` means you've - *already* released ``2.1``, whereas ``2.1rc2`` and ``2.1.c2`` are candidates - you're putting out *before* ``2.1``. If you accidentally distribute copies - of a post-release that you meant to be a pre-release, the only safe fix is to - bump your main release number (e.g. to ``2.1.1``) and re-release the project. + really want a post-release. * Don't stick adjoining pre-release tags together without a dot or number between them. Version ``1.9adev`` is the ``adev`` prerelease of ``1.9``, @@ -239,7 +235,7 @@ >>> parse_version('1.9.a.dev') == parse_version('1.9a0dev') True >>> parse_version('2.1-rc2') < parse_version('2.1') - False + True >>> parse_version('0.6a9dev-r41475') < parse_version('0.6a9') True @@ -2632,6 +2628,10 @@ Release Notes/Change History ---------------------------- +0.6c12 + * Fix documentation describing incorrect pre/post release version comparison + logic. + 0.6c11 * Fix "bdist_wininst upload" trying to upload same file twice Modified: sandbox/branches/setuptools-0.6/setuptools/command/easy_install.py ============================================================================== --- sandbox/branches/setuptools-0.6/setuptools/command/easy_install.py (original) +++ sandbox/branches/setuptools-0.6/setuptools/command/easy_install.py Thu May 16 00:04:59 2013 @@ -156,7 +156,7 @@ else: self.all_site_dirs.append(normalize_path(d)) if not self.editable: self.check_site_dir() - self.index_url = self.index_url or "http://pypi.python.org/simple" + self.index_url = self.index_url or "https://pypi.python.org/simple" self.shadow_path = self.all_site_dirs[:] for path_item in self.install_dir, normalize_path(self.script_dir): if path_item not in self.shadow_path: Modified: sandbox/branches/setuptools-0.6/setuptools/dist.py ============================================================================== --- sandbox/branches/setuptools-0.6/setuptools/dist.py (original) +++ sandbox/branches/setuptools-0.6/setuptools/dist.py Thu May 16 00:04:59 2013 @@ -47,7 +47,6 @@ raise DistutilsSetupError( "%r must be a list of strings (got %r)" % (attr,value) ) - def check_nsp(dist, attr, value): """Verify that namespace packages are valid""" assert_string_list(dist,attr,value) @@ -69,6 +68,10 @@ """Verify that extras_require mapping is valid""" try: for k,v in value.items(): + if ':' in k: + k,m = k.split(':',1) + if pkg_resources.invalid_marker(m): + raise DistutilsSetupError("Invalid environment marker: "+m) list(pkg_resources.parse_requirements(v)) except (TypeError,ValueError,AttributeError): raise DistutilsSetupError( @@ -77,9 +80,6 @@ "requirement specifiers." ) - - - def assert_bool(dist, attr, value): """Verify that value is True, False, 0, or 1""" if bool(value) != value: Modified: sandbox/branches/setuptools-0.6/setuptools/package_index.py ============================================================================== --- sandbox/branches/setuptools-0.6/setuptools/package_index.py (original) +++ sandbox/branches/setuptools-0.6/setuptools/package_index.py Thu May 16 00:04:59 2013 @@ -1,6 +1,6 @@ """PyPI and direct package downloading""" import sys, os.path, re, urlparse, urllib2, shutil, random, socket, cStringIO -import httplib, urllib +import httplib, urllib; from setuptools import ssl_support from pkg_resources import * from distutils import log from distutils.errors import DistutilsError @@ -145,12 +145,11 @@ urllib2.__version__, require('setuptools')[0].version ) - class PackageIndex(Environment): """A distribution index that scans web pages for download URLs""" - def __init__(self, index_url="http://pypi.python.org/simple", hosts=('*',), - *args, **kw + def __init__(self, index_url="https://pypi.python.org/simple", hosts=('*',), + ca_bundle=None, verify_ssl=True, *args, **kw ): Environment.__init__(self,*args,**kw) self.index_url = index_url + "/"[:not index_url.endswith('/')] @@ -159,8 +158,9 @@ self.package_pages = {} self.allows = re.compile('|'.join(map(translate,hosts))).match self.to_scan = [] - - + if verify_ssl and ssl_support.is_available and (ca_bundle or ssl_support.find_ca_bundle()): + self.opener = ssl_support.opener_for(ca_bundle) + else: self.opener = urllib2.urlopen def process_url(self, url, retrieve=False): """Evaluate a URL as a possible download, and maybe retrieve it""" @@ -575,12 +575,13 @@ def open_url(self, url, warning=None): if url.startswith('file:'): return local_open(url) try: - return open_with_auth(url) - except urllib2.HTTPError, v: - return v - except urllib2.URLError, v: - reason = v.reason - except httplib.HTTPException, v: + return open_with_auth(url, self.opener) + except urllib2.HTTPError: + return sys.exc_info()[1] + except urllib2.URLError: + reason = sys.exc_info()[1].reason + except httplib.HTTPException: + v = sys.exc_info()[1] reason = "%s: %s" % (v.__doc__ or v.__class__.__name__, v) if warning: self.warn(warning, reason) @@ -612,7 +613,6 @@ self.url_ok(url, True) # raises error if not allowed return self._attempt_download(url, filename) - def scan_url(self, url): self.process_url(url, True) @@ -736,7 +736,7 @@ -def open_with_auth(url): +def open_with_auth(url, opener=urllib2.urlopen): """Open a urllib2 request, handling HTTP authentication""" scheme, netloc, path, params, query, frag = urlparse.urlparse(url) @@ -755,7 +755,7 @@ request = urllib2.Request(url) request.add_header('User-Agent', user_agent) - fp = urllib2.urlopen(request) + fp = opener(request) if auth: # Put authentication info back into request URL if same host, Modified: sandbox/branches/setuptools-0.6/setuptools/sandbox.py ============================================================================== --- sandbox/branches/setuptools-0.6/setuptools/sandbox.py (original) +++ sandbox/branches/setuptools-0.6/setuptools/sandbox.py Thu May 16 00:04:59 2013 @@ -206,7 +206,7 @@ def tmpnam(self): self._violation("tmpnam") def _ok(self,path): - if hasattr(_os,'devnull') and path==_os.devnull: return True + if hasattr(os,'devnull') and path==os.devnull: return True active = self._active try: self._active = False Added: sandbox/branches/setuptools-0.6/setuptools/ssl_support.py ============================================================================== --- (empty file) +++ sandbox/branches/setuptools-0.6/setuptools/ssl_support.py Thu May 16 00:04:59 2013 @@ -0,0 +1,246 @@ +import sys, os, socket, urllib2, atexit, re +from pkg_resources import ResolutionError, ExtractionError + +try: + import ssl +except ImportError: + ssl = None + +__all__ = [ + 'VerifyingHTTPSHandler', 'find_ca_bundle', 'is_available', 'cert_paths', + 'opener_for' +] + +cert_paths = """ +/etc/pki/tls/certs/ca-bundle.crt +/etc/ssl/certs/ca-certificates.crt +/usr/share/ssl/certs/ca-bundle.crt +/usr/local/share/certs/ca-root.crt +/etc/ssl/cert.pem +/System/Library/OpenSSL/certs/cert.pem +""".strip().split() + + +HTTPSHandler = HTTPSConnection = object + +for what, where in ( + ('HTTPSHandler', ['urllib2','urllib.request']), + ('HTTPSConnection', ['httplib', 'http.client']), +): + for module in where: + try: + exec("from %s import %s" % (module, what)) + except ImportError: + pass + +is_available = ssl is not None and object not in (HTTPSHandler, HTTPSConnection) + + + + + +try: + from socket import create_connection +except ImportError: + _GLOBAL_DEFAULT_TIMEOUT = getattr(socket, '_GLOBAL_DEFAULT_TIMEOUT', object()) + def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, + source_address=None): + """Connect to *address* and return the socket object. + + Convenience function. Connect to *address* (a 2-tuple ``(host, + port)``) and return the socket object. Passing the optional + *timeout* parameter will set the timeout on the socket instance + before attempting to connect. If no *timeout* is supplied, the + global default timeout setting returned by :func:`getdefaulttimeout` + is used. If *source_address* is set it must be a tuple of (host, port) + for the socket to bind as a source address before making the connection. + An host of '' or port 0 tells the OS to use the default. + """ + host, port = address + err = None + for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM): + af, socktype, proto, canonname, sa = res + sock = None + try: + sock = socket.socket(af, socktype, proto) + if timeout is not _GLOBAL_DEFAULT_TIMEOUT: + sock.settimeout(timeout) + if source_address: + sock.bind(source_address) + sock.connect(sa) + return sock + + except error: + err = True + if sock is not None: + sock.close() + if err: + raise + else: + raise error("getaddrinfo returns an empty list") + + +try: + from ssl import CertificateError, match_hostname +except ImportError: + class CertificateError(ValueError): + pass + + def _dnsname_to_pat(dn): + pats = [] + for frag in dn.split(r'.'): + if frag == '*': + # When '*' is a fragment by itself, it matches a non-empty dotless + # fragment. + pats.append('[^.]+') + else: + # Otherwise, '*' matches any dotless fragment. + frag = re.escape(frag) + pats.append(frag.replace(r'\*', '[^.]*')) + return re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE) + + def match_hostname(cert, hostname): + """Verify that *cert* (in decoded format as returned by + SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 rules + are mostly followed, but IP addresses are not accepted for *hostname*. + + CertificateError is raised on failure. On success, the function + returns nothing. + """ + if not cert: + raise ValueError("empty or no certificate") + dnsnames = [] + san = cert.get('subjectAltName', ()) + for key, value in san: + if key == 'DNS': + if _dnsname_to_pat(value).match(hostname): + return + dnsnames.append(value) + if not dnsnames: + # The subject is only checked when there is no dNSName entry + # in subjectAltName + for sub in cert.get('subject', ()): + for key, value in sub: + # XXX according to RFC 2818, the most specific Common Name + # must be used. + if key == 'commonName': + if _dnsname_to_pat(value).match(hostname): + return + dnsnames.append(value) + if len(dnsnames) > 1: + raise CertificateError("hostname %r " + "doesn't match either of %s" + % (hostname, ', '.join(map(repr, dnsnames)))) + elif len(dnsnames) == 1: + raise CertificateError("hostname %r " + "doesn't match %r" + % (hostname, dnsnames[0])) + else: + raise CertificateError("no appropriate commonName or " + "subjectAltName fields were found") + + + + + + + + + + + + + + + + + + + + + + + + +class VerifyingHTTPSHandler(HTTPSHandler): + """Simple verifying handler: no auth, subclasses, timeouts, etc.""" + + def __init__(self, ca_bundle): + self.ca_bundle = ca_bundle + HTTPSHandler.__init__(self) + + def https_open(self, req): + return self.do_open( + lambda host, **kw: VerifyingHTTPSConn(host, self.ca_bundle, **kw), req + ) + + +class VerifyingHTTPSConn(HTTPSConnection): + """Simple verifying connection: no auth, subclasses, timeouts, etc.""" + def __init__(self, host, ca_bundle, **kw): + HTTPSConnection.__init__(self, host, **kw) + self.ca_bundle = ca_bundle + + def connect(self): + sock = create_connection( + (self.host, self.port), getattr(self,'source_address',None) + ) + self.sock = ssl.wrap_socket( + sock, cert_reqs=ssl.CERT_REQUIRED, ca_certs=self.ca_bundle + ) + try: + match_hostname(self.sock.getpeercert(), self.host) + except CertificateError: + self.sock.shutdown(socket.SHUT_RDWR) + self.sock.close() + raise + +def opener_for(ca_bundle=None): + """Get a urlopen() replacement that uses ca_bundle for verification""" + return urllib2.build_opener( + VerifyingHTTPSHandler(ca_bundle or find_ca_bundle()) + ).open + + + +_wincerts = None + +def get_win_certfile(): + global _wincerts + if _wincerts is not None: + return _wincerts.name + + try: + from wincertstore import CertFile + except ImportError: + return None + + class MyCertFile(CertFile): + def __init__(self, stores=(), certs=()): + CertFile.__init__(self) + for store in stores: + self.addstore(store) + self.addcerts(certs) + atexit.register(self.close) + + _wincerts = MyCertFile(stores=['CA', 'ROOT']) + return _wincerts.name + + +def find_ca_bundle(): + """Return an existing CA bundle path, or None""" + if os.name=='nt': + return get_win_certfile() + else: + for cert_path in cert_paths: + if os.path.isfile(cert_path): + return cert_path + try: + return pkg_resources.resource_filename('certifi', 'cacert.pem') + except (ImportError, ResolutionError, ExtractionError): + return None + + + + + Modified: sandbox/branches/setuptools-0.6/setuptools/tests/test_resources.py ============================================================================== --- sandbox/branches/setuptools-0.6/setuptools/tests/test_resources.py (original) +++ sandbox/branches/setuptools-0.6/setuptools/tests/test_resources.py Thu May 16 00:04:59 2013 @@ -507,7 +507,7 @@ def test_get_script_header_jython_workaround(self): platform = sys.platform sys.platform = 'java1.5.0_13' - stdout = sys.stdout + stdout, stderr = sys.stdout, sys.stderr try: # A mock sys.executable that uses a shebang line (this file) exe = os.path.normpath(os.path.splitext(__file__)[0] + '.py') @@ -517,17 +517,17 @@ # Ensure we generate what is basically a broken shebang line # when there's options, with a warning emitted - sys.stdout = StringIO.StringIO() + sys.stdout = sys.stderr = StringIO.StringIO() self.assertEqual(get_script_header('#!/usr/bin/python -x', executable=exe), '#!%s -x\n' % exe) self.assert_('Unable to adapt shebang line' in sys.stdout.getvalue()) - sys.stdout = StringIO.StringIO() + sys.stdout = sys.stderr = StringIO.StringIO() self.assertEqual(get_script_header('#!/usr/bin/python', executable=self.non_ascii_exe), '#!%s -x\n' % self.non_ascii_exe) self.assert_('Unable to adapt shebang line' in sys.stdout.getvalue()) finally: sys.platform = platform - sys.stdout = stdout + sys.stdout, sys.stderr = stdout, stderr From python-checkins at python.org Thu May 16 03:02:49 2013 From: python-checkins at python.org (ned.deily) Date: Thu, 16 May 2013 03:02:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3OTkw?= =?utf-8?q?=3A_Only_modify_include_and_library_search_paths_when_cross-com?= =?utf-8?q?piling=2E?= Message-ID: <3b9vWF19p0z7Lnl@mail.python.org> http://hg.python.org/cpython/rev/cd577c328886 changeset: 83786:cd577c328886 branch: 2.7 parent: 83775:149340b3004a user: Ned Deily date: Wed May 15 18:00:45 2013 -0700 summary: Issue #17990: Only modify include and library search paths when cross-compiling. files: setup.py | 8 +++++--- 1 files changed, 5 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -437,9 +437,11 @@ def detect_modules(self): # Ensure that /usr/local is always used - add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib') - add_dir_to_list(self.compiler.include_dirs, '/usr/local/include') - self.add_gcc_paths() + if not cross_compiling: + add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib') + add_dir_to_list(self.compiler.include_dirs, '/usr/local/include') + if cross_compiling: + self.add_gcc_paths() self.add_multiarch_paths() # Add paths specified in the environment variables LDFLAGS and -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Thu May 16 05:58:27 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 16 May 2013 05:58:27 +0200 Subject: [Python-checkins] Daily reference leaks (e74f4d6c0c81): sum=5 Message-ID: results for e74f4d6c0c81 on branch "default" -------------------------------------------- test_imaplib leaked [1, 0, 0] references, sum=1 test_imaplib leaked [1, 2, 1] memory blocks, sum=4 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogbucxRl', '-x'] From python-checkins at python.org Thu May 16 15:12:25 2013 From: python-checkins at python.org (giampaolo.rodola) Date: Thu, 16 May 2013 15:12:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_ftplib_tests=3A_provide_a_?= =?utf-8?q?global_socket=27s_TIMEOUT_variable_and_use_it_everywhere?= Message-ID: <3bBCj556pPz7Lkd@mail.python.org> http://hg.python.org/cpython/rev/3772e68a31db changeset: 83787:3772e68a31db parent: 83785:e74f4d6c0c81 user: Giampaolo Rodola' date: Thu May 16 15:12:01 2013 +0200 summary: ftplib tests: provide a global socket's TIMEOUT variable and use it everywhere so that failing tests won't accidentally hang files: Lib/test/test_ftplib.py | 29 +++++++++++++++-------------- 1 files changed, 15 insertions(+), 14 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 @@ -21,6 +21,7 @@ from test.support import HOST threading = support.import_module('threading') +TIMEOUT = 3 # the dummy data returned by server over the data channel when # RETR, LIST, NLST, MLSD commands are issued RETR_DATA = 'abcde12345\r\n' * 1000 @@ -125,7 +126,7 @@ addr = list(map(int, arg.split(','))) ip = '%d.%d.%d.%d' %tuple(addr[:4]) port = (addr[4] * 256) + addr[5] - s = socket.create_connection((ip, port), timeout=2) + s = socket.create_connection((ip, port), timeout=TIMEOUT) self.dtp = self.dtp_handler(s, baseclass=self) self.push('200 active data connection established') @@ -133,7 +134,7 @@ with socket.socket() as sock: sock.bind((self.socket.getsockname()[0], 0)) sock.listen(5) - sock.settimeout(10) + sock.settimeout(TIMEOUT) ip, port = sock.getsockname()[:2] ip = ip.replace('.', ','); p1 = port / 256; p2 = port % 256 self.push('227 entering passive mode (%s,%d,%d)' %(ip, p1, p2)) @@ -143,7 +144,7 @@ def cmd_eprt(self, arg): af, ip, port = arg.split(arg[0])[1:-1] port = int(port) - s = socket.create_connection((ip, port), timeout=2) + s = socket.create_connection((ip, port), timeout=TIMEOUT) self.dtp = self.dtp_handler(s, baseclass=self) self.push('200 active data connection established') @@ -151,7 +152,7 @@ with socket.socket(socket.AF_INET6) as sock: sock.bind((self.socket.getsockname()[0], 0)) sock.listen(5) - sock.settimeout(10) + sock.settimeout(TIMEOUT) port = sock.getsockname()[1] self.push('229 entering extended passive mode (|||%d|)' %port) conn, addr = sock.accept() @@ -454,7 +455,7 @@ def setUp(self): self.server = DummyFTPServer((HOST, 0)) self.server.start() - self.client = ftplib.FTP(timeout=2) + self.client = ftplib.FTP(timeout=TIMEOUT) self.client.connect(self.server.host, self.server.port) def tearDown(self): @@ -667,7 +668,7 @@ def test_makepasv(self): host, port = self.client.makepasv() - conn = socket.create_connection((host, port), 10) + conn = socket.create_connection((host, port), timeout=TIMEOUT) conn.close() # IPv4 is in use, just make sure send_epsv has not been used self.assertEqual(self.server.handler_instance.last_received_cmd, 'pasv') @@ -685,7 +686,7 @@ return True # base test - with ftplib.FTP(timeout=2) as self.client: + with ftplib.FTP(timeout=TIMEOUT) as self.client: self.client.connect(self.server.host, self.server.port) self.client.sendcmd('noop') self.assertTrue(is_client_connected()) @@ -693,7 +694,7 @@ self.assertFalse(is_client_connected()) # QUIT sent inside the with block - with ftplib.FTP(timeout=2) as self.client: + with ftplib.FTP(timeout=TIMEOUT) as self.client: self.client.connect(self.server.host, self.server.port) self.client.sendcmd('noop') self.client.quit() @@ -703,7 +704,7 @@ # force a wrong response code to be sent on QUIT: error_perm # is expected and the connection is supposed to be closed try: - with ftplib.FTP(timeout=2) as self.client: + with ftplib.FTP(timeout=TIMEOUT) as self.client: self.client.connect(self.server.host, self.server.port) self.client.sendcmd('noop') self.server.handler_instance.next_response = '550 error on quit' @@ -759,7 +760,7 @@ def setUp(self): self.server = DummyFTPServer(('::1', 0), af=socket.AF_INET6) self.server.start() - self.client = ftplib.FTP() + self.client = ftplib.FTP(timeout=TIMEOUT) self.client.connect(self.server.host, self.server.port) def tearDown(self): @@ -776,7 +777,7 @@ def test_makepasv(self): host, port = self.client.makepasv() - conn = socket.create_connection((host, port), 10) + conn = socket.create_connection((host, port), timeout=TIMEOUT) conn.close() self.assertEqual(self.server.handler_instance.last_received_cmd, 'epsv') @@ -802,7 +803,7 @@ def setUp(self): self.server = DummyTLS_FTPServer((HOST, 0)) self.server.start() - self.client = ftplib.FTP_TLS(timeout=2) + self.client = ftplib.FTP_TLS(timeout=TIMEOUT) self.client.connect(self.server.host, self.server.port) # enable TLS self.client.auth() @@ -815,7 +816,7 @@ def setUp(self): self.server = DummyTLS_FTPServer((HOST, 0)) self.server.start() - self.client = ftplib.FTP_TLS(timeout=2) + self.client = ftplib.FTP_TLS(timeout=TIMEOUT) self.client.connect(self.server.host, self.server.port) def tearDown(self): @@ -875,7 +876,7 @@ self.assertRaises(ValueError, ftplib.FTP_TLS, certfile=CERTFILE, keyfile=CERTFILE, context=ctx) - self.client = ftplib.FTP_TLS(context=ctx, timeout=2) + self.client = ftplib.FTP_TLS(context=ctx, timeout=TIMEOUT) self.client.connect(self.server.host, self.server.port) self.assertNotIsInstance(self.client.sock, ssl.SSLSocket) self.client.auth() -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 16 15:22:07 2013 From: python-checkins at python.org (giampaolo.rodola) Date: Thu, 16 May 2013 15:22:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2317992=3A_Add_time?= =?utf-8?q?outs_to_asyncore_and_asynchat_tests_so_that_they_won=27t?= Message-ID: <3bBCwH03GQz7LkY@mail.python.org> http://hg.python.org/cpython/rev/3ee61b048173 changeset: 83788:3ee61b048173 user: Giampaolo Rodola' date: Thu May 16 15:21:53 2013 +0200 summary: Issue #17992: Add timeouts to asyncore and asynchat tests so that they won't accidentally hang. files: Lib/test/test_asynchat.py | 29 ++++++++++++++++++++------ Lib/test/test_asyncore.py | 13 +++++++++-- Misc/NEWS | 3 ++ 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_asynchat.py b/Lib/test/test_asynchat.py --- a/Lib/test/test_asynchat.py +++ b/Lib/test/test_asynchat.py @@ -15,6 +15,7 @@ HOST = support.HOST SERVER_QUIT = b'QUIT\n' +TIMEOUT = 3.0 if threading: class echo_server(threading.Thread): @@ -123,7 +124,9 @@ c.push(b"I'm not dead yet!" + term) c.push(SERVER_QUIT) asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01) - s.join() + s.join(timeout=TIMEOUT) + if s.is_alive(): + self.fail("join() timed out") self.assertEqual(c.contents, [b"hello world", b"I'm not dead yet!"]) @@ -154,7 +157,9 @@ c.push(data) c.push(SERVER_QUIT) asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01) - s.join() + s.join(timeout=TIMEOUT) + if s.is_alive(): + self.fail("join() timed out") self.assertEqual(c.contents, [data[:termlen]]) @@ -174,7 +179,9 @@ c.push(data) c.push(SERVER_QUIT) asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01) - s.join() + s.join(timeout=TIMEOUT) + if s.is_alive(): + self.fail("join() timed out") self.assertEqual(c.contents, []) self.assertEqual(c.buffer, data) @@ -186,7 +193,9 @@ p = asynchat.simple_producer(data+SERVER_QUIT, buffer_size=8) c.push_with_producer(p) asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01) - s.join() + s.join(timeout=TIMEOUT) + if s.is_alive(): + self.fail("join() timed out") self.assertEqual(c.contents, [b"hello world", b"I'm not dead yet!"]) @@ -196,7 +205,9 @@ data = b"hello world\nI'm not dead yet!\n" c.push_with_producer(data+SERVER_QUIT) asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01) - s.join() + s.join(timeout=TIMEOUT) + if s.is_alive(): + self.fail("join() timed out") self.assertEqual(c.contents, [b"hello world", b"I'm not dead yet!"]) @@ -207,7 +218,9 @@ c.push(b"hello world\n\nI'm not dead yet!\n") c.push(SERVER_QUIT) asyncore.loop(use_poll=self.usepoll, count=300, timeout=.01) - s.join() + s.join(timeout=TIMEOUT) + if s.is_alive(): + self.fail("join() timed out") self.assertEqual(c.contents, [b"hello world", b"", b"I'm not dead yet!"]) @@ -226,7 +239,9 @@ # where the server echoes all of its data before we can check that it # got any down below. s.start_resend_event.set() - s.join() + s.join(timeout=TIMEOUT) + if s.is_alive(): + self.fail("join() timed out") self.assertEqual(c.contents, []) # the server might have been able to send a byte or two back, but this diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py --- a/Lib/test/test_asyncore.py +++ b/Lib/test/test_asyncore.py @@ -20,7 +20,7 @@ threading = None HOST = support.HOST - +TIMEOUT = 3 HAS_UNIX_SOCKETS = hasattr(socket, 'AF_UNIX') class dummysocket: @@ -397,7 +397,10 @@ self.assertEqual(cap.getvalue(), data*2) finally: - t.join() + t.join(timeout=TIMEOUT) + if t.is_alive(): + self.fail("join() timed out") + class DispatcherWithSendTests_UsePoll(DispatcherWithSendTests): @@ -789,7 +792,11 @@ t = threading.Thread(target=lambda: asyncore.loop(timeout=0.1, count=500)) t.start() - self.addCleanup(t.join) + def cleanup(): + t.join(timeout=TIMEOUT) + if t.is_alive(): + self.fail("join() timed out") + self.addCleanup(cleanup) s = socket.socket(self.family, socket.SOCK_STREAM) s.settimeout(.2) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -258,6 +258,9 @@ Tests ----- +- Issue #17992: Add timeouts to asyncore and asynchat tests so that they won't + accidentally hang. + - Issue #17833: Fix test_gdb failures seen on machines where debug symbols for glibc are available (seen on PPC64 Linux). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 16 19:03:54 2013 From: python-checkins at python.org (brian.curtin) Date: Thu, 16 May 2013 19:03:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Add_Nick_Sloan?= =?utf-8?q?_for_his_contribution_to_=2317732?= Message-ID: <3bBJrB1B0Mz7Lqh@mail.python.org> http://hg.python.org/cpython/rev/d62f71bd2192 changeset: 83789:d62f71bd2192 branch: 3.3 parent: 83784:cd9141a4f999 user: Brian Curtin date: Thu May 16 11:59:29 2013 -0500 summary: Add Nick Sloan for his contribution to #17732 files: Misc/ACKS | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1137,6 +1137,7 @@ J. Sipprell Kragen Sitaker Michael Sloan +Nick Sloan Christopher Smith Eric V. Smith Gregory P. Smith -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 16 19:03:55 2013 From: python-checkins at python.org (brian.curtin) Date: Thu, 16 May 2013 19:03:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E3?= Message-ID: <3bBJrC3XSKz7LpX@mail.python.org> http://hg.python.org/cpython/rev/5b89f1b09756 changeset: 83790:5b89f1b09756 parent: 83788:3ee61b048173 parent: 83789:d62f71bd2192 user: Brian Curtin date: Thu May 16 12:03:40 2013 -0500 summary: Merge with 3.3 files: Misc/ACKS | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1161,6 +1161,7 @@ J. Sipprell Kragen Sitaker Michael Sloan +Nick Sloan V?clav ?milauer Christopher Smith Eric V. Smith -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 16 21:37:33 2013 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 16 May 2013 21:37:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_rather_than_passing_locals?= =?utf-8?q?_to_the_class_body=2C_just_execute_the_class_body_in?= Message-ID: <3bBNFT5dfpzS6H@mail.python.org> http://hg.python.org/cpython/rev/6db3741e59be changeset: 83791:6db3741e59be user: Benjamin Peterson date: Thu May 16 14:37:25 2013 -0500 summary: rather than passing locals to the class body, just execute the class body in the proper environment files: Doc/library/dis.rst | 6 - Include/opcode.h | 1 - Lib/importlib/_bootstrap.py | 3 +- Lib/opcode.py | 1 - Python/bltinmodule.c | 9 +- Python/ceval.c | 8 - Python/compile.c | 11 +- Python/importlib.h | 6270 +++++++++++----------- Python/opcode_targets.h | 2 +- Python/symtable.c | 7 +- 10 files changed, 3143 insertions(+), 3175 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -596,12 +596,6 @@ .. XXX explain the WHY stuff! -.. opcode:: STORE_LOCALS - - Pops TOS from the stack and stores it as the current frame's ``f_locals``. - This is used in class construction. - - All of the following opcodes expect arguments. An argument is two bytes, with the more significant byte last. diff --git a/Include/opcode.h b/Include/opcode.h --- a/Include/opcode.h +++ b/Include/opcode.h @@ -49,7 +49,6 @@ #define BINARY_OR 66 #define INPLACE_POWER 67 #define GET_ITER 68 -#define STORE_LOCALS 69 #define PRINT_EXPR 70 #define LOAD_BUILD_CLASS 71 #define YIELD_FROM 72 diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -391,12 +391,13 @@ # Python 3.4a1 3260 (add LOAD_CLASSDEREF; allow locals of class to override # free vars) # Python 3.4a1 3270 (various tweaks to the __class_ closure) +# Python 3.4a1 3280 (remove implicit class argument) # # MAGIC must change whenever the bytecode emitted by the compiler may no # longer be understood by older implementations of the eval loop (usually # due to the addition of new opcodes). -_MAGIC_BYTES = (3270).to_bytes(2, 'little') + b'\r\n' +_MAGIC_BYTES = (3280).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(_MAGIC_BYTES, 'little') _PYCACHE = '__pycache__' diff --git a/Lib/opcode.py b/Lib/opcode.py --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -84,7 +84,6 @@ def_op('BINARY_OR', 66) def_op('INPLACE_POWER', 67) def_op('GET_ITER', 68) -def_op('STORE_LOCALS', 69) def_op('PRINT_EXPR', 70) def_op('LOAD_BUILD_CLASS', 71) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -57,6 +57,11 @@ return NULL; } func = PyTuple_GET_ITEM(args, 0); /* Better be callable */ + if (!PyFunction_Check(func)) { + PyErr_SetString(PyExc_TypeError, + "__build__class__: func must be a function"); + return NULL; + } name = PyTuple_GET_ITEM(args, 1); if (!PyUnicode_Check(name)) { PyErr_SetString(PyExc_TypeError, @@ -155,7 +160,9 @@ Py_DECREF(bases); return NULL; } - cell = PyObject_CallFunctionObjArgs(func, ns, NULL); + cell = PyEval_EvalCodeEx(PyFunction_GET_CODE(func), PyFunction_GET_GLOBALS(func), ns, + NULL, 0, NULL, 0, NULL, 0, NULL, + PyFunction_GET_CLOSURE(func)); if (cell != NULL) { PyObject *margs; margs = PyTuple_Pack(3, name, bases, ns); diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1873,14 +1873,6 @@ goto error; } - TARGET(STORE_LOCALS) { - PyObject *locals = POP(); - PyObject *old = f->f_locals; - Py_XDECREF(old); - f->f_locals = locals; - DISPATCH(); - } - TARGET(RETURN_VALUE) { retval = POP(); why = WHY_RETURN; diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -893,8 +893,6 @@ return 7; case WITH_CLEANUP: return -1; /* XXX Sometimes more */ - case STORE_LOCALS: - return -1; case RETURN_VALUE: return -1; case IMPORT_STAR: @@ -1696,12 +1694,6 @@ Py_INCREF(s->v.ClassDef.name); Py_XDECREF(c->u->u_private); c->u->u_private = s->v.ClassDef.name; - /* force it to have one mandatory argument */ - c->u->u_argcount = 1; - /* load the first argument (__locals__) ... */ - ADDOP_I(c, LOAD_FAST, 0); - /* ... and store it into f_locals */ - ADDOP_IN_SCOPE(c, STORE_LOCALS); /* load (global) __name__ ... */ str = PyUnicode_InternFromString("__name__"); if (!str || !compiler_nameop(c, str, Load)) { @@ -4110,9 +4102,8 @@ { PySTEntryObject *ste = c->u->u_ste; int flags = 0, n; - if (ste->ste_type != ModuleBlock) + if (ste->ste_type == FunctionBlock) { flags |= CO_NEWLOCALS; - if (ste->ste_type == FunctionBlock) { if (!ste->ste_unoptimized) flags |= CO_OPTIMIZED; if (ste->ste_nested) diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -68,7 +68,7 @@ &&TARGET_BINARY_OR, &&TARGET_INPLACE_POWER, &&TARGET_GET_ITER, - &&TARGET_STORE_LOCALS, + &&_unknown_opcode, &&TARGET_PRINT_EXPR, &&TARGET_LOAD_BUILD_CLASS, &&TARGET_YIELD_FROM, diff --git a/Python/symtable.c b/Python/symtable.c --- a/Python/symtable.c +++ b/Python/symtable.c @@ -192,7 +192,7 @@ static identifier top = NULL, lambda = NULL, genexpr = NULL, listcomp = NULL, setcomp = NULL, dictcomp = NULL, - __class__ = NULL, __locals__ = NULL; + __class__ = NULL; #define GET_IDENTIFIER(VAR) \ ((VAR) ? (VAR) : ((VAR) = PyUnicode_InternFromString(# VAR))) @@ -1185,11 +1185,6 @@ if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock, (void *)s, s->lineno, s->col_offset)) VISIT_QUIT(st, 0); - if (!GET_IDENTIFIER(__locals__) || - !symtable_add_def(st, __locals__, DEF_PARAM)) { - symtable_exit_block(st, s); - VISIT_QUIT(st, 0); - } tmp = st->st_private; st->st_private = s->v.ClassDef.name; VISIT_SEQ(st, stmt, s->v.ClassDef.body); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 16 22:17:43 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 16 May 2013 22:17:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_fix_compilation_on_Windows?= Message-ID: <3bBP7q4xSRzRkQ@mail.python.org> http://hg.python.org/cpython/rev/d1ba1228a04f changeset: 83792:d1ba1228a04f user: Victor Stinner date: Thu May 16 22:17:17 2013 +0200 summary: fix compilation on Windows files: Python/compile.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Python/compile.c b/Python/compile.c --- a/Python/compile.c +++ b/Python/compile.c @@ -1360,10 +1360,11 @@ static int get_ref_type(struct compiler *c, PyObject *name) { + int scope; if (c->u->u_scope_type == COMPILER_SCOPE_CLASS && !PyUnicode_CompareWithASCIIString(name, "__class__")) return CELL; - int scope = PyST_GetScope(c->u->u_ste, name); + scope = PyST_GetScope(c->u->u_ste, name); if (scope == 0) { char buf[350]; PyOS_snprintf(buf, sizeof(buf), -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 16 22:27:01 2013 From: python-checkins at python.org (victor.stinner) Date: Thu, 16 May 2013 22:27:01 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2317964=3A_Fix_os?= =?utf-8?q?=2Esysconf=28=29=3A_the_return_type_of_the_C_sysconf=28=29_func?= =?utf-8?q?tion?= Message-ID: <3bBPLY2wbqz7LjW@mail.python.org> http://hg.python.org/cpython/rev/7c60cf756097 changeset: 83793:7c60cf756097 user: Victor Stinner date: Thu May 16 22:26:29 2013 +0200 summary: Issue #17964: Fix os.sysconf(): the return type of the C sysconf() function is long, not int. files: Misc/NEWS | 3 +++ Modules/posixmodule.c | 2 +- 2 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -91,6 +91,9 @@ Library ------- +- Issue #17964: Fix os.sysconf(): the return type of the C sysconf() function + is long, not int. + - Fix typos in the multiprocessing module. - Issue #17754: Make ctypes.util.find_library() independent of the locale. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -9550,7 +9550,7 @@ int name; if (PyArg_ParseTuple(args, "O&:sysconf", conv_sysconf_confname, &name)) { - int value; + long value; errno = 0; value = sysconf(name); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 16 22:33:12 2013 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 16 May 2013 22:33:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_C89_declaratio?= =?utf-8?q?n_compliance?= Message-ID: <3bBPTh46gLz7LjS@mail.python.org> http://hg.python.org/cpython/rev/e2e104ba42ff changeset: 83794:e2e104ba42ff branch: 3.3 parent: 83789:d62f71bd2192 user: Benjamin Peterson date: Thu May 16 15:29:44 2013 -0500 summary: C89 declaration compliance files: Modules/_cursesmodule.c | 2 +- Modules/socketmodule.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -2261,9 +2261,9 @@ PyObject *data; size_t datalen; WINDOW *win; + _Py_IDENTIFIER(read); PyCursesInitialised; - _Py_IDENTIFIER(read); strcpy(fn, "/tmp/py.curses.getwin.XXXXXX"); fd = mkstemp(fn); diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -1662,8 +1662,9 @@ struct sockaddr_can *addr; PyObject *interfaceName; struct ifreq ifr; + Py_ssize_t len; + addr = (struct sockaddr_can *)addr_ret; - Py_ssize_t len; if (!PyArg_ParseTuple(args, "O&", PyUnicode_FSConverter, &interfaceName)) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 16 22:33:13 2013 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 16 May 2013 22:33:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3bBPTj6T68z7LjS@mail.python.org> http://hg.python.org/cpython/rev/dedc900f5030 changeset: 83795:dedc900f5030 parent: 83793:7c60cf756097 parent: 83794:e2e104ba42ff user: Benjamin Peterson date: Thu May 16 15:30:09 2013 -0500 summary: merge 3.3 files: Modules/_cursesmodule.c | 2 +- Modules/socketmodule.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -2261,9 +2261,9 @@ PyObject *data; size_t datalen; WINDOW *win; + _Py_IDENTIFIER(read); PyCursesInitialised; - _Py_IDENTIFIER(read); strcpy(fn, "/tmp/py.curses.getwin.XXXXXX"); fd = mkstemp(fn); diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -1604,8 +1604,9 @@ struct sockaddr_can *addr; PyObject *interfaceName; struct ifreq ifr; + Py_ssize_t len; + addr = (struct sockaddr_can *)addr_ret; - Py_ssize_t len; if (!PyArg_ParseTuple(args, "O&", PyUnicode_FSConverter, &interfaceName)) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 16 22:33:15 2013 From: python-checkins at python.org (benjamin.peterson) Date: Thu, 16 May 2013 22:33:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_make_GCC_complain_about_de?= =?utf-8?q?clarations_not_at_the_top_of_blocks?= Message-ID: <3bBPTl1y0wz7Lmr@mail.python.org> http://hg.python.org/cpython/rev/a3559c8c614b changeset: 83796:a3559c8c614b user: Benjamin Peterson date: Thu May 16 15:33:00 2013 -0500 summary: make GCC complain about declarations not at the top of blocks files: configure | 2 ++ configure.ac | 2 ++ 2 files changed, 4 insertions(+), 0 deletions(-) diff --git a/configure b/configure --- a/configure +++ b/configure @@ -6264,6 +6264,8 @@ # tweak BASECFLAGS based on compiler and platform case $GCC in yes) + BASECFLAGS="$BASECFLAGS -Werror=declaration-after-statement" + # Python doesn't violate C99 aliasing rules, but older versions of # GCC produce warnings for legal Python code. Enable # -fno-strict-aliasing on versions of GCC that support but produce diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -1127,6 +1127,8 @@ # tweak BASECFLAGS based on compiler and platform case $GCC in yes) + BASECFLAGS="$BASECFLAGS -Werror=declaration-after-statement" + # Python doesn't violate C99 aliasing rules, but older versions of # GCC produce warnings for legal Python code. Enable # -fno-strict-aliasing on versions of GCC that support but produce -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 16 23:23:56 2013 From: python-checkins at python.org (ned.deily) Date: Thu, 16 May 2013 23:23:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?devguide=3A_Add_comment_about_avoidin?= =?utf-8?q?g_--enable-shared_for_uninstalled_builds=2E__This_should?= Message-ID: <3bBQcD0nxrz7LjS@mail.python.org> http://hg.python.org/devguide/rev/3d523f0c0a9d changeset: 620:3d523f0c0a9d user: Ned Deily date: Thu May 16 14:23:47 2013 -0700 summary: Add comment about avoiding --enable-shared for uninstalled builds. This should also cause the resources ref link in the Editors and Tools section to be updated (Issue17952). files: setup.rst | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/setup.rst b/setup.rst --- a/setup.rst +++ b/setup.rst @@ -163,7 +163,11 @@ of Python! The interpreter will realize where it is being run from and thus use the files found in the working copy. If you are worried you might accidentally install your working copy build, you can add -``--prefix=/tmp/python`` to the configuration step. +``--prefix=/tmp/python`` to the configuration step. When running from your +working directory, it is best to avoid using the ``--enable-shared`` flag +to ``configure``; unless you are very careful, you may accidentally run +with code from an older, installed shared Python library rather than from +the interpreter you just built. .. _issue tracker: http://bugs.python.org -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Fri May 17 00:03:13 2013 From: python-checkins at python.org (vinay.sajip) Date: Fri, 17 May 2013 00:03:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3OTgx?= =?utf-8?q?=3A_Closed_socket_on_error_in_SysLogHandler=2E?= Message-ID: <3bBRTY32HTz7LjM@mail.python.org> http://hg.python.org/cpython/rev/d91da96a55bf changeset: 83797:d91da96a55bf branch: 2.7 parent: 83786:cd577c328886 user: Vinay Sajip date: Thu May 16 22:47:47 2013 +0100 summary: Issue #17981: Closed socket on error in SysLogHandler. files: Lib/logging/handlers.py | 1 + Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -856,6 +856,7 @@ try: self.socket.send(msg) except socket.error: + self.socket.close() # See issue 17981 self._connect_unixsocket(self.address) self.socket.send(msg) elif self.socktype == socket.SOCK_DGRAM: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,8 @@ Library ------- +- Issue #17981: Closed socket on error in SysLogHandler. + - Issue #17754: Make ctypes.util.find_library() independent of the locale. - Fix typos in the multiprocessing module. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 17 00:03:14 2013 From: python-checkins at python.org (vinay.sajip) Date: Fri, 17 May 2013 00:03:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3OTgx?= =?utf-8?q?=3A_Closed_socket_on_error_in_SysLogHandler=2E?= Message-ID: <3bBRTZ5NL6z7LkQ@mail.python.org> http://hg.python.org/cpython/rev/590b865aa73c changeset: 83798:590b865aa73c branch: 3.3 parent: 83794:e2e104ba42ff user: Vinay Sajip date: Thu May 16 22:57:02 2013 +0100 summary: Issue #17981: Closed socket on error in SysLogHandler. files: Lib/logging/handlers.py | 1 + Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -882,6 +882,7 @@ try: self.socket.send(msg) except socket.error: + self.socket.close() self._connect_unixsocket(self.address) self.socket.send(msg) elif self.socktype == socket.SOCK_DGRAM: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -21,6 +21,8 @@ Library ------- +- Issue #17981: Closed socket on error in SysLogHandler. + - Fix typos in the multiprocessing module. - Issue #17754: Make ctypes.util.find_library() independent of the locale. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 17 00:03:16 2013 From: python-checkins at python.org (vinay.sajip) Date: Fri, 17 May 2013 00:03:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Closes_=2317981=3A_Merged_fix_from_3=2E3=2E?= Message-ID: <3bBRTc0gmnz7Llh@mail.python.org> http://hg.python.org/cpython/rev/f2809c7a7c3c changeset: 83799:f2809c7a7c3c parent: 83796:a3559c8c614b parent: 83798:590b865aa73c user: Vinay Sajip date: Thu May 16 23:02:54 2013 +0100 summary: Closes #17981: Merged fix from 3.3. files: Lib/logging/handlers.py | 1 + Misc/NEWS | 2 ++ 2 files changed, 3 insertions(+), 0 deletions(-) diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -876,6 +876,7 @@ try: self.socket.send(msg) except OSError: + self.socket.close() self._connect_unixsocket(self.address) self.socket.send(msg) elif self.socktype == socket.SOCK_DGRAM: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -91,6 +91,8 @@ Library ------- +- Issue #17981: Closed socket on error in SysLogHandler. + - Issue #17964: Fix os.sysconf(): the return type of the C sysconf() function is long, not int. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 17 00:06:34 2013 From: python-checkins at python.org (victor.stinner) Date: Fri, 17 May 2013 00:06:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_a_compilater_warning_o?= =?utf-8?q?n_Windows_64-bit?= Message-ID: <3bBRYQ5PTFz7LmY@mail.python.org> http://hg.python.org/cpython/rev/e5dc97fb304d changeset: 83800:e5dc97fb304d user: Victor Stinner date: Thu May 16 23:48:01 2013 +0200 summary: Fix a compilater warning on Windows 64-bit idx variable is used for a tuple indexn so use Py_ssize_t (not int). files: Python/ceval.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2256,7 +2256,7 @@ TARGET(LOAD_CLASSDEREF) { PyObject *name, *value, *locals = f->f_locals; - int idx; + Py_ssize_t idx; assert(locals); assert(oparg >= PyTuple_GET_SIZE(co->co_cellvars)); idx = oparg - PyTuple_GET_SIZE(co->co_cellvars); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 17 00:06:36 2013 From: python-checkins at python.org (victor.stinner) Date: Fri, 17 May 2013 00:06:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_a_compilater_warning_o?= =?utf-8?q?n_Windows_64-bit?= Message-ID: <3bBRYS0SLMz7LjS@mail.python.org> http://hg.python.org/cpython/rev/16a00dd78cd0 changeset: 83801:16a00dd78cd0 user: Victor Stinner date: Fri May 17 00:04:56 2013 +0200 summary: Fix a compilater warning on Windows 64-bit files: Python/formatter_unicode.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/formatter_unicode.c b/Python/formatter_unicode.c --- a/Python/formatter_unicode.c +++ b/Python/formatter_unicode.c @@ -315,7 +315,7 @@ /* Do the padding, and return a pointer to where the caller-supplied content goes. */ -static Py_ssize_t +static int fill_padding(_PyUnicodeWriter *writer, Py_ssize_t nchars, Py_UCS4 fill_char, Py_ssize_t n_lpadding, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 17 00:12:18 2013 From: python-checkins at python.org (victor.stinner) Date: Fri, 17 May 2013 00:12:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_compilater_warnings_on?= =?utf-8?q?_Windows_64-bit?= Message-ID: <3bBRh2068tz7LkY@mail.python.org> http://hg.python.org/cpython/rev/ef5dd5bda323 changeset: 83802:ef5dd5bda323 user: Victor Stinner date: Fri May 17 00:12:04 2013 +0200 summary: Fix compilater warnings on Windows 64-bit files: Python/getargs.c | 6 +++--- Python/traceback.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Python/getargs.c b/Python/getargs.c --- a/Python/getargs.c +++ b/Python/getargs.c @@ -55,7 +55,7 @@ /* Forward */ static int vgetargs1(PyObject *, const char *, va_list *, int); -static void seterror(int, const char *, int *, const char *, const char *); +static void seterror(Py_ssize_t, const char *, int *, const char *, const char *); static char *convertitem(PyObject *, const char **, va_list *, int, int *, char *, size_t, freelist_t *); static char *converttuple(PyObject *, const char **, va_list *, int, @@ -357,7 +357,7 @@ static void -seterror(int iarg, const char *msg, int *levels, const char *fname, +seterror(Py_ssize_t iarg, const char *msg, int *levels, const char *fname, const char *message) { char buf[512]; @@ -373,7 +373,7 @@ } if (iarg != 0) { PyOS_snprintf(p, sizeof(buf) - (p - buf), - "argument %d", iarg); + "argument %zd", iarg); i = 0; p += strlen(p); while (levels[i] > 0 && i < 32 && (int)(p-buf) < 220) { diff --git a/Python/traceback.c b/Python/traceback.c --- a/Python/traceback.c +++ b/Python/traceback.c @@ -13,7 +13,7 @@ #define OFF(x) offsetof(PyTracebackObject, x) -#define PUTS(fd, str) write(fd, str, strlen(str)) +#define PUTS(fd, str) write(fd, str, (int)strlen(str)) #define MAX_STRING_LENGTH 500 #define MAX_FRAME_DEPTH 100 #define MAX_NTHREADS 100 -- Repository URL: http://hg.python.org/cpython From tjreedy at udel.edu Fri May 17 02:31:50 2013 From: tjreedy at udel.edu (Terry Reedy) Date: Thu, 16 May 2013 20:31:50 -0400 Subject: [Python-checkins] cpython: fix compilation on Windows In-Reply-To: <3bBP7q4xSRzRkQ@mail.python.org> References: <3bBP7q4xSRzRkQ@mail.python.org> Message-ID: <51957A76.7030601@udel.edu> On 5/16/2013 4:17 PM, victor.stinner wrote: > summary: fix compilation on Windows That fixed my problem with compiling 3.4, 32 bit, Win 7. Thanks. But I cannot compile 3.3 python_d since May 6. In fact, there are more errors now than 8 hours ago. 7 things failed to build instead of 5 (3 is normal for me, given the lack of some dependencies). I believe the following is new. Red error box with .../p33/PCBuild/make_versioninfo_d.exe is not a valid Win32 application. The VS gui output box has "Please verify that you have sufficient rights to run this command." Some more errors: 10>..\PC\pylauncher.rc(16): error RC2104: undefined keyword or key name: FIELD3 10> 9> symtable.c 9>..\Python\symtable.c(1245): error C2143: syntax error : missing ';' before 'type' 9>..\Python\symtable.c(1246): error C2065: 'cur' : undeclared identifier 9>..\Python\symtable.c(1248): error C2065: 'cur' : undeclared identifier 9>..\Python\symtable.c(1253): error C2065: 'cur' : undeclared identifier 23> Traceback (most recent call last): 23> File "build_ssl.py", line 253, in 23> main() 23> File "build_ssl.py", line 187, in main 23> os.chdir(ssl_dir) 23> FileNotFoundError: [WinError 2] The system cannot find the file specified: '..\\..\\openssl-1.0.1e' Earlier, about 4 other files had several warnings. I do no see the warnings now because they compiled then and have not changed. Errors are more urgent, but should warnings be ignored? Terry From python-checkins at python.org Fri May 17 02:38:59 2013 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 17 May 2013 02:38:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_move_definitio?= =?utf-8?q?n_to_top_of_block?= Message-ID: <3bBVxH5dffz7LpN@mail.python.org> http://hg.python.org/cpython/rev/86783c4fd528 changeset: 83803:86783c4fd528 branch: 3.3 parent: 83798:590b865aa73c user: Benjamin Peterson date: Thu May 16 19:38:22 2013 -0500 summary: move definition to top of block files: Python/symtable.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/Python/symtable.c b/Python/symtable.c --- a/Python/symtable.c +++ b/Python/symtable.c @@ -1236,13 +1236,14 @@ asdl_seq *seq = s->v.Global.names; for (i = 0; i < asdl_seq_LEN(seq); i++) { identifier name = (identifier)asdl_seq_GET(seq, i); + long cur; if (st->st_cur->ste_type == ClassBlock && !PyUnicode_CompareWithASCIIString(name, "__class__")) { PyErr_SetString(PyExc_SyntaxError, "cannot make __class__ global"); PyErr_SyntaxLocationEx(st->st_filename, s->lineno, s->col_offset); return 0; } - long cur = symtable_lookup(st, name); + cur = symtable_lookup(st, name); if (cur < 0) VISIT_QUIT(st, 0); if (cur & (DEF_LOCAL | USE)) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 17 02:39:01 2013 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 17 May 2013 02:39:01 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3bBVxK0l3pz7Lp2@mail.python.org> http://hg.python.org/cpython/rev/8bcdd2343bf5 changeset: 83804:8bcdd2343bf5 parent: 83802:ef5dd5bda323 parent: 83803:86783c4fd528 user: Benjamin Peterson date: Thu May 16 19:38:48 2013 -0500 summary: merge 3.3 files: -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri May 17 06:06:36 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 17 May 2013 06:06:36 +0200 Subject: [Python-checkins] Daily reference leaks (8bcdd2343bf5): sum=2 Message-ID: results for 8bcdd2343bf5 on branch "default" -------------------------------------------- test_unittest leaked [-1, 1, 2] memory blocks, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogp4biab', '-x'] From python-checkins at python.org Fri May 17 09:19:29 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 17 May 2013 09:19:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Fix_some_bugs_?= =?utf-8?q?in_Tools/scripts/abitype=2Epy=2E?= Message-ID: <3bBgqP5yvcz7LnJ@mail.python.org> http://hg.python.org/cpython/rev/26531f21bc4c changeset: 83805:26531f21bc4c branch: 3.3 parent: 83803:86783c4fd528 user: Serhiy Storchaka date: Fri May 17 10:17:43 2013 +0300 summary: Fix some bugs in Tools/scripts/abitype.py. files: Tools/scripts/abitype.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tools/scripts/abitype.py b/Tools/scripts/abitype.py --- a/Tools/scripts/abitype.py +++ b/Tools/scripts/abitype.py @@ -126,8 +126,8 @@ 'tp_cache', 'tp_subclasses', 'tp_weaklist', - 'tp_del' - 'tp_version_tag' + 'tp_del', + 'tp_version_tag', ] # Generate a PyType_Spec definition @@ -194,7 +194,7 @@ break start = m.start() end = m.end() - name, fields = get_fields(start, m) + name, fields = get_fields(start, end) tokens[start:end] = [('',make_slots(name, fields))] # Output result to stdout -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 17 09:19:31 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 17 May 2013 09:19:31 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Fix_some_bugs_in_Tools/scripts/abitype=2Epy=2E?= Message-ID: <3bBgqR0wtqz7Lq0@mail.python.org> http://hg.python.org/cpython/rev/27cc0e0b7637 changeset: 83806:27cc0e0b7637 parent: 83804:8bcdd2343bf5 parent: 83805:26531f21bc4c user: Serhiy Storchaka date: Fri May 17 10:18:40 2013 +0300 summary: Fix some bugs in Tools/scripts/abitype.py. files: Tools/scripts/abitype.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tools/scripts/abitype.py b/Tools/scripts/abitype.py --- a/Tools/scripts/abitype.py +++ b/Tools/scripts/abitype.py @@ -126,8 +126,8 @@ 'tp_cache', 'tp_subclasses', 'tp_weaklist', - 'tp_del' - 'tp_version_tag' + 'tp_del', + 'tp_version_tag', ] # Generate a PyType_Spec definition @@ -194,7 +194,7 @@ break start = m.start() end = m.end() - name, fields = get_fields(start, m) + name, fields = get_fields(start, end) tokens[start:end] = [('',make_slots(name, fields))] # Output result to stdout -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 17 09:50:22 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 17 May 2013 09:50:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2314596=3A_The_stru?= =?utf-8?q?ct=2EStruct=28=29_objects_now_use_more_compact_implementation?= =?utf-8?q?=2E?= Message-ID: <3bBhW20P76z7Lmk@mail.python.org> http://hg.python.org/cpython/rev/6707637f68ca changeset: 83807:6707637f68ca user: Serhiy Storchaka date: Fri May 17 10:49:44 2013 +0300 summary: Issue #14596: The struct.Struct() objects now use more compact implementation. files: Lib/test/test_struct.py | 9 +- Misc/NEWS | 2 + Modules/_struct.c | 175 +++++++++++++++------------ 3 files changed, 99 insertions(+), 87 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -8,7 +8,6 @@ from test import support ISBIGENDIAN = sys.byteorder == "big" -IS32BIT = sys.maxsize == 0x7fffffff integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'n', 'N' byteorders = '', '@', '=', '<', '>', '!' @@ -538,10 +537,6 @@ hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2) self.assertRaises(struct.error, struct.calcsize, hugecount2) - if IS32BIT: - def test_crasher(self): - self.assertRaises(MemoryError, struct.pack, "357913941b", "a") - def test_trailing_counter(self): store = array.array('b', b' '*100) @@ -578,7 +573,7 @@ # The size of 'PyStructObject' totalsize = support.calcobjsize('2n3P') # The size taken up by the 'formatcode' dynamic array - totalsize += struct.calcsize('P2n0P') * (number_of_codes + 1) + totalsize += struct.calcsize('P3n0P') * (number_of_codes + 1) support.check_sizeof(self, struct.Struct(format_str), totalsize) @support.cpython_only @@ -589,7 +584,7 @@ self.check_sizeof('B' * 1234, 1234) self.check_sizeof('fd', 2) self.check_sizeof('xxxxxxxxxxxxxx', 0) - self.check_sizeof('100H', 100) + self.check_sizeof('100H', 1) self.check_sizeof('187s', 1) self.check_sizeof('20p', 1) self.check_sizeof('0s', 1) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -91,6 +91,8 @@ Library ------- +- Issue #14596: The struct.Struct() objects now use more compact implementation. + - Issue #17981: Closed socket on error in SysLogHandler. - Issue #17964: Fix os.sysconf(): the return type of the C sysconf() function diff --git a/Modules/_struct.c b/Modules/_struct.c --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -26,6 +26,7 @@ const struct _formatdef *fmtdef; Py_ssize_t offset; Py_ssize_t size; + Py_ssize_t repeat; } formatcode; /* Struct object interface */ @@ -1263,7 +1264,7 @@ const char *s; const char *fmt; char c; - Py_ssize_t size, len, num, itemsize; + Py_ssize_t size, len, ncodes, num, itemsize; fmt = PyBytes_AS_STRING(self->s_format); @@ -1272,6 +1273,7 @@ s = fmt; size = 0; len = 0; + ncodes = 0; while ((c = *s++) != '\0') { if (Py_ISSPACE(Py_CHARMASK(c))) continue; @@ -1301,9 +1303,9 @@ switch (c) { case 's': /* fall through */ - case 'p': len++; break; + case 'p': len++; ncodes++; break; case 'x': break; - default: len += num; break; + default: len += num; if (num) ncodes++; break; } itemsize = e->size; @@ -1318,14 +1320,14 @@ } /* check for overflow */ - if ((len + 1) > (PY_SSIZE_T_MAX / sizeof(formatcode))) { + if ((ncodes + 1) > (PY_SSIZE_T_MAX / sizeof(formatcode))) { PyErr_NoMemory(); return -1; } self->s_size = size; self->s_len = len; - codes = PyMem_MALLOC((len + 1) * sizeof(formatcode)); + codes = PyMem_MALLOC((ncodes + 1) * sizeof(formatcode)); if (codes == NULL) { PyErr_NoMemory(); return -1; @@ -1357,23 +1359,24 @@ codes->offset = size; codes->size = num; codes->fmtdef = e; + codes->repeat = 1; codes++; size += num; } else if (c == 'x') { size += num; - } else { - while (--num >= 0) { - codes->offset = size; - codes->size = e->size; - codes->fmtdef = e; - codes++; - size += e->size; - } + } else if (num) { + codes->offset = size; + codes->size = e->size; + codes->fmtdef = e; + codes->repeat = num; + codes++; + size += e->size * num; } } codes->fmtdef = NULL; codes->offset = size; codes->size = 0; + codes->repeat = 0; return 0; @@ -1462,22 +1465,26 @@ return NULL; for (code = soself->s_codes; code->fmtdef != NULL; code++) { - PyObject *v; const formatdef *e = code->fmtdef; const char *res = startfrom + code->offset; - if (e->format == 's') { - v = PyBytes_FromStringAndSize(res, code->size); - } else if (e->format == 'p') { - Py_ssize_t n = *(unsigned char*)res; - if (n >= code->size) - n = code->size - 1; - v = PyBytes_FromStringAndSize(res + 1, n); - } else { - v = e->unpack(res, e); + Py_ssize_t j = code->repeat; + while (j--) { + PyObject *v; + if (e->format == 's') { + v = PyBytes_FromStringAndSize(res, code->size); + } else if (e->format == 'p') { + Py_ssize_t n = *(unsigned char*)res; + if (n >= code->size) + n = code->size - 1; + v = PyBytes_FromStringAndSize(res + 1, n); + } else { + v = e->unpack(res, e); + } + if (v == NULL) + goto fail; + PyTuple_SET_ITEM(result, i++, v); + res += code->size; } - if (v == NULL) - goto fail; - PyTuple_SET_ITEM(result, i++, v); } return result; @@ -1716,62 +1723,67 @@ memset(buf, '\0', soself->s_size); i = offset; for (code = soself->s_codes; code->fmtdef != NULL; code++) { - Py_ssize_t n; - PyObject *v = PyTuple_GET_ITEM(args, i++); const formatdef *e = code->fmtdef; char *res = buf + code->offset; - if (e->format == 's') { - int isstring; - void *p; - isstring = PyBytes_Check(v); - if (!isstring && !PyByteArray_Check(v)) { - PyErr_SetString(StructError, - "argument for 's' must be a bytes object"); - return -1; + Py_ssize_t j = code->repeat; + while (j--) { + PyObject *v = PyTuple_GET_ITEM(args, i++); + if (e->format == 's') { + Py_ssize_t n; + int isstring; + void *p; + isstring = PyBytes_Check(v); + if (!isstring && !PyByteArray_Check(v)) { + PyErr_SetString(StructError, + "argument for 's' must be a bytes object"); + return -1; + } + if (isstring) { + n = PyBytes_GET_SIZE(v); + p = PyBytes_AS_STRING(v); + } + else { + n = PyByteArray_GET_SIZE(v); + p = PyByteArray_AS_STRING(v); + } + if (n > code->size) + n = code->size; + if (n > 0) + memcpy(res, p, n); + } else if (e->format == 'p') { + Py_ssize_t n; + int isstring; + void *p; + isstring = PyBytes_Check(v); + if (!isstring && !PyByteArray_Check(v)) { + PyErr_SetString(StructError, + "argument for 'p' must be a bytes object"); + return -1; + } + if (isstring) { + n = PyBytes_GET_SIZE(v); + p = PyBytes_AS_STRING(v); + } + else { + n = PyByteArray_GET_SIZE(v); + p = PyByteArray_AS_STRING(v); + } + if (n > (code->size - 1)) + n = code->size - 1; + if (n > 0) + memcpy(res + 1, p, n); + if (n > 255) + n = 255; + *res = Py_SAFE_DOWNCAST(n, Py_ssize_t, unsigned char); + } else { + if (e->pack(res, v, e) < 0) { + if (PyLong_Check(v) && PyErr_ExceptionMatches(PyExc_OverflowError)) + PyErr_SetString(StructError, + "long too large to convert to int"); + return -1; + } } - if (isstring) { - n = PyBytes_GET_SIZE(v); - p = PyBytes_AS_STRING(v); - } - else { - n = PyByteArray_GET_SIZE(v); - p = PyByteArray_AS_STRING(v); - } - if (n > code->size) - n = code->size; - if (n > 0) - memcpy(res, p, n); - } else if (e->format == 'p') { - int isstring; - void *p; - isstring = PyBytes_Check(v); - if (!isstring && !PyByteArray_Check(v)) { - PyErr_SetString(StructError, - "argument for 'p' must be a bytes object"); - return -1; - } - if (isstring) { - n = PyBytes_GET_SIZE(v); - p = PyBytes_AS_STRING(v); - } - else { - n = PyByteArray_GET_SIZE(v); - p = PyByteArray_AS_STRING(v); - } - if (n > (code->size - 1)) - n = code->size - 1; - if (n > 0) - memcpy(res + 1, p, n); - if (n > 255) - n = 255; - *res = Py_SAFE_DOWNCAST(n, Py_ssize_t, unsigned char); - } else { - if (e->pack(res, v, e) < 0) { - if (PyLong_Check(v) && PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(StructError, - "long too large to convert to int"); - return -1; - } + res += code->size; } } @@ -1907,8 +1919,11 @@ s_sizeof(PyStructObject *self, void *unused) { Py_ssize_t size; + formatcode *code; - size = sizeof(PyStructObject) + sizeof(formatcode) * (self->s_len + 1); + size = sizeof(PyStructObject) + sizeof(formatcode); + for (code = self->s_codes; code->fmtdef != NULL; code++) + size += sizeof(formatcode); return PyLong_FromSsize_t(size); } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 17 11:25:14 2013 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 17 May 2013 11:25:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Ignore_Mac_OS_?= =?utf-8?q?X_entries_for_=2EDS=5FStore?= Message-ID: <3bBkcV2z75z7LjM@mail.python.org> http://hg.python.org/cpython/rev/86c2dcb2e0df changeset: 83808:86c2dcb2e0df branch: 3.3 parent: 83805:26531f21bc4c user: Raymond Hettinger date: Fri May 17 02:23:16 2013 -0700 summary: Ignore Mac OS X entries for .DS_Store files: .hgignore | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -1,6 +1,7 @@ .gdb_history .purify .svn/ +.DS_Store Makefile$ Makefile.pre$ TAGS$ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 17 11:25:15 2013 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 17 May 2013 11:25:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3bBkcW5zXFz7Lnx@mail.python.org> http://hg.python.org/cpython/rev/9ff8b6d4d479 changeset: 83809:9ff8b6d4d479 parent: 83807:6707637f68ca parent: 83808:86c2dcb2e0df user: Raymond Hettinger date: Fri May 17 02:24:18 2013 -0700 summary: merge files: .hgignore | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -1,7 +1,7 @@ .gdb_history .purify .svn/ -DS_Store +.DS_Store Makefile$ Makefile.pre$ TAGS$ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 17 11:29:40 2013 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 17 May 2013 11:29:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Remove_unneces?= =?utf-8?q?sary_exception_handler=2E?= Message-ID: <3bBkjc1GPhz7Llw@mail.python.org> http://hg.python.org/cpython/rev/17fcdaddbaa7 changeset: 83810:17fcdaddbaa7 branch: 3.3 parent: 83808:86c2dcb2e0df user: Raymond Hettinger date: Fri May 17 02:28:33 2013 -0700 summary: Remove unnecessary exception handler. files: Lib/collections/__init__.py | 5 +---- 1 files changed, 1 insertions(+), 4 deletions(-) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -363,10 +363,7 @@ # Execute the template string in a temporary namespace and support # tracing utilities by setting a value for frame.f_globals['__name__'] namespace = dict(__name__='namedtuple_%s' % typename) - try: - exec(class_definition, namespace) - except SyntaxError as e: - raise SyntaxError(e.msg + ':\n\n' + class_definition) + exec(class_definition, namespace) result = namespace[typename] result._source = class_definition if verbose: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 17 11:29:41 2013 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 17 May 2013 11:29:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3bBkjd3V8tz7Lp2@mail.python.org> http://hg.python.org/cpython/rev/1babfb6261fa changeset: 83811:1babfb6261fa parent: 83809:9ff8b6d4d479 parent: 83810:17fcdaddbaa7 user: Raymond Hettinger date: Fri May 17 02:29:27 2013 -0700 summary: merge files: Lib/collections/__init__.py | 5 +---- 1 files changed, 1 insertions(+), 4 deletions(-) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -363,10 +363,7 @@ # Execute the template string in a temporary namespace and support # tracing utilities by setting a value for frame.f_globals['__name__'] namespace = dict(__name__='namedtuple_%s' % typename) - try: - exec(class_definition, namespace) - except SyntaxError as e: - raise SyntaxError(e.msg + ':\n\n' + class_definition) + exec(class_definition, namespace) result = namespace[typename] result._source = class_definition if verbose: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 17 12:25:18 2013 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 17 May 2013 12:25:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3NTYz?= =?utf-8?q?=3A_Fix_dict_resize_performance_regression=2E?= Message-ID: <3bBlxp3L89z7Llw@mail.python.org> http://hg.python.org/cpython/rev/cd2457463eeb changeset: 83812:cd2457463eeb branch: 3.3 parent: 83810:17fcdaddbaa7 user: Raymond Hettinger date: Fri May 17 03:01:13 2013 -0700 summary: Issue #17563: Fix dict resize performance regression. files: Objects/dictobject.c | 18 +++++++++++------- 1 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -305,14 +305,18 @@ * #define USABLE_FRACTION(n) (((n) >> 1) + ((n) >> 2) - ((n) >> 3)) */ -/* GROWTH_RATE. Growth rate upon hitting maximum load. Currently set to *2. - * Raising this to *4 doubles memory consumption depending on the size of +/* GROWTH_RATE. Growth rate upon hitting maximum load. + * Currently set to used*2 + capacity/2. + * This means that dicts double in size when growing without deletions, + * but have more head room when the number of deletions is on a par with the + * number of insertions. + * Raising this to used*4 doubles memory consumption depending on the size of * the dictionary, but results in half the number of resizes, less effort to - * resize and better sparseness for some (but not all dict sizes). - * Setting to *4 eliminates every other resize step. - * GROWTH_RATE was set to *4 up to version 3.2. + * resize. + * GROWTH_RATE was set to used*4 up to version 3.2. + * GROWTH_RATE was set to used*2 in version 3.3.0 */ -#define GROWTH_RATE(x) ((x) * 2) +#define GROWTH_RATE(d) (((d)->ma_used*2)+((d)->ma_keys->dk_size>>1)) #define ENSURE_ALLOWS_DELETIONS(d) \ if ((d)->ma_keys->dk_lookup == lookdict_unicode_nodummy) { \ @@ -790,7 +794,7 @@ static int insertion_resize(PyDictObject *mp) { - return dictresize(mp, GROWTH_RATE(mp->ma_used)); + return dictresize(mp, GROWTH_RATE(mp)); } /* -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 17 12:25:19 2013 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 17 May 2013 12:25:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3bBlxq5Xzcz7Lm5@mail.python.org> http://hg.python.org/cpython/rev/ffd353a4fdc7 changeset: 83813:ffd353a4fdc7 parent: 83811:1babfb6261fa parent: 83812:cd2457463eeb user: Raymond Hettinger date: Fri May 17 03:24:54 2013 -0700 summary: merge files: Objects/dictobject.c | 18 +++++++++++------- 1 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -305,14 +305,18 @@ * #define USABLE_FRACTION(n) (((n) >> 1) + ((n) >> 2) - ((n) >> 3)) */ -/* GROWTH_RATE. Growth rate upon hitting maximum load. Currently set to *2. - * Raising this to *4 doubles memory consumption depending on the size of +/* GROWTH_RATE. Growth rate upon hitting maximum load. + * Currently set to used*2 + capacity/2. + * This means that dicts double in size when growing without deletions, + * but have more head room when the number of deletions is on a par with the + * number of insertions. + * Raising this to used*4 doubles memory consumption depending on the size of * the dictionary, but results in half the number of resizes, less effort to - * resize and better sparseness for some (but not all dict sizes). - * Setting to *4 eliminates every other resize step. - * GROWTH_RATE was set to *4 up to version 3.2. + * resize. + * GROWTH_RATE was set to used*4 up to version 3.2. + * GROWTH_RATE was set to used*2 in version 3.3.0 */ -#define GROWTH_RATE(x) ((x) * 2) +#define GROWTH_RATE(d) (((d)->ma_used*2)+((d)->ma_keys->dk_size>>1)) #define ENSURE_ALLOWS_DELETIONS(d) \ if ((d)->ma_keys->dk_lookup == lookdict_unicode_nodummy) { \ @@ -790,7 +794,7 @@ static int insertion_resize(PyDictObject *mp) { - return dictresize(mp, GROWTH_RATE(mp->ma_used)); + return dictresize(mp, GROWTH_RATE(mp)); } /* -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 17 18:33:39 2013 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 17 May 2013 18:33:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbjogcmVzZXQgX19jbGFzc19fLCBz?= =?utf-8?q?o_multiple_runs_don=27t_fail_=28closes_=2317999=29?= Message-ID: <3bBw6q4sv6z7Lm5@mail.python.org> http://hg.python.org/cpython/rev/b4553d22c163 changeset: 83814:b4553d22c163 user: Benjamin Peterson date: Fri May 17 11:33:26 2013 -0500 summary: reset __class__, so multiple runs don't fail (closes #17999) files: Lib/test/test_super.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_super.py b/Lib/test/test_super.py --- a/Lib/test/test_super.py +++ b/Lib/test/test_super.py @@ -44,6 +44,11 @@ class TestSuper(unittest.TestCase): + def tearDown(self): + # This fixes the damage that test_various___class___pathologies does. + nonlocal __class__ + __class__ = TestSuper + def test_basics_working(self): self.assertEqual(D().f(), 'ABCD') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 17 23:20:21 2013 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 17 May 2013 23:20:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_New_PEP=3A_Safe_object_finali?= =?utf-8?q?zation?= Message-ID: <3bC2Td0Td6z7LjT@mail.python.org> http://hg.python.org/peps/rev/0763444c74b3 changeset: 4890:0763444c74b3 user: Antoine Pitrou date: Fri May 17 23:17:31 2013 +0200 summary: New PEP: Safe object finalization files: pep-0442.txt | 284 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 284 insertions(+), 0 deletions(-) diff --git a/pep-0442.txt b/pep-0442.txt new file mode 100644 --- /dev/null +++ b/pep-0442.txt @@ -0,0 +1,284 @@ +PEP: 442 +Title: Safe object finalization +Version: $Revision$ +Last-Modified: $Date$ +Author: Antoine Pitrou +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 2013-04-18 +Python-Version: 3.4 +Post-History: +Resolution: TBD + + +Abstract +======== + +This PEP proposes to deal with the current limitations of object +finalization. The goal is to be able to define and run finalizers +for any object, regardless of their position in the object graph. + +This PEP doesn't call for any change in Python code. Objects +with existing finalizers will benefit automatically. + + +Definitions +=========== + +Reference + A directional link from an object to another. The target of the + reference is kept alive by the reference, as long as the source is + itself alive and the reference isn't cleared. + +Weak reference + A directional link from an object to another, which doesn't keep + alive its target. This PEP focusses on non-weak references. + +Reference cycle + A cyclic subgraph of directional links between objects, which keeps + those objects from being collected in a pure reference-counting + scheme. + +Cyclic isolate (CI) + A reference cycle in which no object is referenced from outside the + cycle *and* whose objects are still in a usable, non-broken state: + they can access each other from their respective finalizers. + +Cyclic garbage collector (GC) + A device able to detect cyclic isolates and turn them into cyclic + trash. Objects in cyclic trash are eventually disposed of by + the natural effect of the references being cleared and their + reference counts dropping to zero. + +Cyclic trash (CT) + A reference cycle, or former reference cycle, in which no object + is referenced from outside the cycle *and* whose objects have + started being cleared by the GC. Objects in cyclic trash are potential + zombies; if they are accessed by Python code, the symptoms can vary + from weird AttributeErrors to crashes. + +Zombie / broken object + An object part of cyclic trash. The term stresses that the object + is not safe: its outgoing references may have been cleared, or one + of the objects it references may be zombie. Therefore, + it should not be accessed by arbitrary code (such as finalizers). + +Finalizer + A function or method called when an object is intended to be + disposed of. The finalizer can access the object and release any + resource held by the object (for example mutexes or file descriptors). + An example is a ``__del__`` method. + +Resurrection + The process by which a finalizer creates a new reference to an + object in a CI. This can happen as a quirky but supported side-effect + of ``__del__`` methods. + + +Impact +====== + +While this PEP discusses CPython-specific implementation details, the +change in finalization semantics is expected to affect the Python +ecosystem as a whole. In particular, this PEP obsoletes the current +guideline that "objects with a __del__ method should not be part of a +reference cycle". + + +Benefits +======== + +The primary benefits of this PEP regard objects with finalizers, such +as objects with a ``__del__`` method and generators with a ``finally`` +block. Those objects can now be reclaimed when they are part of a +reference cycle. + +The PEP also paves the way for further benefits: + +* The module shutdown procedure may not need to set global variables to + None anymore. This could solve a well-known class of irritating issues. + +The PEP doesn't change the semantics of: + +* Weak references caught in reference cycles. + +* C extension types with a custom ``tp_dealloc`` function. + + +Description +=========== + +Reference-counted disposal +-------------------------- + +In normal reference-counted disposal, an object's finalizer is called +just before the object is deallocated. If the finalizer resurrects +the object, deallocation is aborted. + +*However*, if the object was already finalized, then the finalizer isn't +called. This prevents us from finalizing zombies (see below). + +Disposal of cyclic isolates +--------------------------- + +Cyclic isolates are first detected by the garbage collector, and then +disposed of. The detection phase doesn't change and won't be described here. +Disposal of a CI traditionally works in the following order: + +1. Weakrefs to CI objects are cleared, and their callbacks called. At this + point, the objects are still safe to use. + +2. The CI becomes a CT as the GC systematically breaks all + known references inside it (using the ``tp_clear`` function). + +3. Nothing. All CT objects should have been disposed of in step 2 + (as a side-effect of clearing references); this collection is finished. + +This PEP proposes to turn CI disposal into the following sequence (new +steps are in bold): + +1. Weakrefs to CI objects are cleared, and their callbacks called. At this + point, the objects are still safe to use. + +2. **The finalizers of all CI objects are called.** + +3. **The CI is traversed again to determine if it is still isolated. + If it is determined that at least one object in CI is now reachable + from outside the CI, this collection is aborted and the whole CI + is resurrected. Otherwise, proceed.** + +4. The CI becomes a CT as the GC systematically breaks all + known references inside it (using the ``tp_clear`` function). + +5. Nothing. All CT objects should have been disposed of in step 4 + (as a side-effect of clearing references); this collection is finished. + + +C-level changes +=============== + +Type objects get a new ``tp_finalize`` slot to which ``__del__`` methods +are bound. Generators are also modified to use this slot, rather than +``tp_del``. At the C level, a ``tp_finalize`` function is a normal +function which will be called with a regular, alive object as its only +argument. It should not attempt to revive or collect the object. + +For compatibility, ``tp_del`` is kept in the type structure. Handling +of objects with a non-NULL ``tp_del`` is unchanged: when part of a CI, +they are not finalized and end up in ``gc.garbage``. However, a non-NULL +``tp_del`` is not encountered anymore in the CPython source tree (except +for testing purposes). + + +Discussion +========== + +Predictability +-------------- + +Following this scheme, an object's finalizer is always called exactly +once. The only exception is if an object is resurrected: the finalizer +will be called again later. + +For CI objects, the order in which finalizers are called (step 2 above) +is undefined. + +Safety +------ + +It is important to explain why the proposed change is safe. There +are two aspects to be discussed: + +* Can a finalizer access zombie objects (including the object being + finalized)? + +* What happens if a finalizer mutates the object graph so as to impact + the CI? + +Let's discuss the first issue. We will divide possible cases in two +categories: + +* If the object being finalized is part of the CI: by construction, no + objects in CI are zombies yet, since CI finalizers are called before + any reference breaking is done. Therefore, the finalizer cannot + access zombie objects, which don't exist. + +* If the object being finalized is not part of the CI/CT: by definition, + objects in the CI/CT don't have any references pointing to them from + outside the CI/CT. Therefore, the finalizer cannot reach any zombie + object (that is, even if the object being finalized was itself + referenced from a zombie object). + +Now for the second issue. There are three potential cases: + +* The finalizer clears an existing reference to a CI object. The CI + object may be disposed of before the GC tries to break it, which + is fine (the GC simply has to be aware of this possibility). + +* The finalizer creates a new reference to a CI object. This can only + happen from a CI object's finalizer (see above why). Therefore, the + new reference will be detected by the GC after all CI finalizers are + called (step 3 above), and collection will be aborted without any + objects being broken. + +* The finalizer clears or creates a reference to a non-CI object. By + construction, this is not a problem. + + +Implementation +============== + +An implementation is available in branch ``finalize`` of the repository +at http://hg.python.org/features/finalize/. + + +Validation +========== + +Besides running the normal Python test suite, the implementation adds +test cases for various finalization possibilities including reference cycles, +object resurrection and legacy ``tp_del`` slots. + +The implementation has also been checked to not produce any regressions on +the following test suites: + +* `Tulip `_, which makes an extensive + use of generators + +* `Tornado `_ + +* `SQLAlchemy `_ + +* `Django `_ + +* `zope.interface `_ + + +References +========== + +Notes about reference cycle collection and weak reference callbacks: +http://hg.python.org/cpython/file/4e687d53b645/Modules/gc_weakref.txt + +Generator memory leak: http://bugs.python.org/issue17468 + +Allow objects to decide if they can be collected by GC: +http://bugs.python.org/issue9141 + +Module shutdown procedure based on GC +http://bugs.python.org/issue812369 + +Copyright +========= + +This document has been placed in the public domain. + +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + coding: utf-8 + End: -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri May 17 23:25:01 2013 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 17 May 2013 23:25:01 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_The_date_isn=27t_right?= Message-ID: <3bC2b11qPnz7Ljm@mail.python.org> http://hg.python.org/peps/rev/2cf40b5f6b08 changeset: 4891:2cf40b5f6b08 user: Antoine Pitrou date: Fri May 17 23:24:50 2013 +0200 summary: The date isn't right files: pep-0442.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0442.txt b/pep-0442.txt --- a/pep-0442.txt +++ b/pep-0442.txt @@ -6,7 +6,7 @@ Status: Draft Type: Standards Track Content-Type: text/x-rst -Created: 2013-04-18 +Created: 2013-05-18 Python-Version: 3.4 Post-History: Resolution: TBD -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri May 17 23:30:18 2013 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 17 May 2013 23:30:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Mention_the_new_bit_in_the_GC?= =?utf-8?q?_header?= Message-ID: <3bC2j66DLsz7Ljm@mail.python.org> http://hg.python.org/peps/rev/c9440776e935 changeset: 4892:c9440776e935 user: Antoine Pitrou date: Fri May 17 23:30:10 2013 +0200 summary: Mention the new bit in the GC header files: pep-0442.txt | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/pep-0442.txt b/pep-0442.txt --- a/pep-0442.txt +++ b/pep-0442.txt @@ -82,7 +82,7 @@ While this PEP discusses CPython-specific implementation details, the change in finalization semantics is expected to affect the Python ecosystem as a whole. In particular, this PEP obsoletes the current -guideline that "objects with a __del__ method should not be part of a +guideline that "objects with a ``__del__`` method should not be part of a reference cycle". @@ -170,6 +170,11 @@ ``tp_del`` is not encountered anymore in the CPython source tree (except for testing purposes). +On the internal side, a bit is reserved in the GC header for GC-managed +objects to signal that they were finalized. This helps avoid finalizing +an object twice (and, especially, finalizing a CT object after it was broken +by the GC). + Discussion ========== -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat May 18 00:36:44 2013 From: python-checkins at python.org (richard.oudkerk) Date: Sat, 18 May 2013 00:36:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2315758=3A_Fix_File?= =?utf-8?q?IO=2Ereadall=28=29_so_it_no_longer_has_O=28n**2=29_complexity?= =?utf-8?q?=2E?= Message-ID: <3bC49m5XHxz7Ljv@mail.python.org> http://hg.python.org/cpython/rev/e4c303d23d01 changeset: 83815:e4c303d23d01 user: Richard Oudkerk date: Fri May 17 23:34:42 2013 +0100 summary: Issue #15758: Fix FileIO.readall() so it no longer has O(n**2) complexity. files: Misc/NEWS | 2 + Modules/_io/fileio.c | 118 +++++++++++++----------------- 2 files changed, 54 insertions(+), 66 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -91,6 +91,8 @@ Library ------- +- Issue #15758: Fix FileIO.readall() so it no longer has O(n**2) complexity. + - Issue #14596: The struct.Struct() objects now use more compact implementation. - Issue #17981: Closed socket on error in SysLogHandler. diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -556,33 +556,27 @@ return PyLong_FromSsize_t(n); } +#ifndef HAVE_FSTAT + +static PyObject * +fileio_readall(fileio *self) +{ + _Py_IDENTIFIER(readall); + return _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type, + &PyId_readall, "O", self); +} + +#else + static size_t -new_buffersize(fileio *self, size_t currentsize -#ifdef HAVE_FSTAT - , Py_off_t pos, Py_off_t end -#endif - ) +new_buffersize(fileio *self, size_t currentsize) { size_t addend; -#ifdef HAVE_FSTAT - if (end != (Py_off_t)-1) { - /* Files claiming a size smaller than SMALLCHUNK may - actually be streaming pseudo-files. In this case, we - apply the more aggressive algorithm below. - */ - if (end >= SMALLCHUNK && end >= pos && pos >= 0) { - /* Add 1 so if the file were to grow we'd notice. */ - Py_off_t bufsize = currentsize + end - pos + 1; - if (bufsize < PY_SSIZE_T_MAX) - return (size_t)bufsize; - else - return PY_SSIZE_T_MAX; - } - } -#endif + /* Expand the buffer by an amount proportional to the current size, giving us amortized linear-time behavior. For bigger sizes, use a less-than-double growth factor to avoid excessive allocation. */ + assert(currentsize <= PY_SSIZE_T_MAX); if (currentsize > 65536) addend = currentsize >> 3; else @@ -596,25 +590,18 @@ static PyObject * fileio_readall(fileio *self) { -#ifdef HAVE_FSTAT struct stat st; Py_off_t pos, end; -#endif PyObject *result; - Py_ssize_t total = 0; + Py_ssize_t bytes_read = 0; Py_ssize_t n; - size_t newsize; + size_t bufsize; if (self->fd < 0) return err_closed(); if (!_PyVerify_fd(self->fd)) return PyErr_SetFromErrno(PyExc_IOError); - result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK); - if (result == NULL) - return NULL; - -#ifdef HAVE_FSTAT #if defined(MS_WIN64) || defined(MS_WINDOWS) pos = _lseeki64(self->fd, 0L, SEEK_CUR); #else @@ -624,44 +611,46 @@ end = st.st_size; else end = (Py_off_t)-1; -#endif + + if (end > 0 && end >= pos && pos >= 0 && end - pos < PY_SSIZE_T_MAX) { + /* This is probably a real file, so we try to allocate a + buffer one byte larger than the rest of the file. If the + calculation is right then we should get EOF without having + to enlarge the buffer. */ + bufsize = (size_t)(end - pos + 1); + } else { + bufsize = SMALLCHUNK; + } + + result = PyBytes_FromStringAndSize(NULL, bufsize); + if (result == NULL) + return NULL; + while (1) { -#ifdef HAVE_FSTAT - newsize = new_buffersize(self, total, pos, end); -#else - newsize = new_buffersize(self, total); -#endif - if (newsize > PY_SSIZE_T_MAX || newsize <= 0) { - PyErr_SetString(PyExc_OverflowError, - "unbounded read returned more bytes " - "than a Python string can hold "); - Py_DECREF(result); - return NULL; - } + if (bytes_read >= (Py_ssize_t)bufsize) { + bufsize = new_buffersize(self, bytes_read); + if (bufsize > PY_SSIZE_T_MAX || bufsize <= 0) { + PyErr_SetString(PyExc_OverflowError, + "unbounded read returned more bytes " + "than a Python string can hold "); + Py_DECREF(result); + return NULL; + } - if (PyBytes_GET_SIZE(result) < (Py_ssize_t)newsize) { - if (_PyBytes_Resize(&result, newsize) < 0) { - if (total == 0) { - Py_DECREF(result); + if (PyBytes_GET_SIZE(result) < (Py_ssize_t)bufsize) { + if (_PyBytes_Resize(&result, bufsize) < 0) return NULL; - } - PyErr_Clear(); - break; } } Py_BEGIN_ALLOW_THREADS errno = 0; - n = newsize - total; + n = bufsize - bytes_read; #if defined(MS_WIN64) || defined(MS_WINDOWS) if (n > INT_MAX) n = INT_MAX; - n = read(self->fd, - PyBytes_AS_STRING(result) + total, - (int)n); + n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, (int)n); #else - n = read(self->fd, - PyBytes_AS_STRING(result) + total, - n); + n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, n); #endif Py_END_ALLOW_THREADS if (n == 0) @@ -674,7 +663,7 @@ } continue; } - if (total > 0) + if (bytes_read > 0) break; if (errno == EAGAIN) { Py_DECREF(result); @@ -684,22 +673,19 @@ PyErr_SetFromErrno(PyExc_IOError); return NULL; } - total += n; -#ifdef HAVE_FSTAT + bytes_read += n; pos += n; -#endif } - if (PyBytes_GET_SIZE(result) > total) { - if (_PyBytes_Resize(&result, total) < 0) { - /* This should never happen, but just in case */ - Py_DECREF(result); + if (PyBytes_GET_SIZE(result) > bytes_read) { + if (_PyBytes_Resize(&result, bytes_read) < 0) return NULL; - } } return result; } +#endif /* HAVE_FSTAT */ + static PyObject * fileio_read(fileio *self, PyObject *args) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 18 00:39:02 2013 From: python-checkins at python.org (victor.stinner) Date: Sat, 18 May 2013 00:39:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbjogRmlsZUlPLnJlYWRhbGwoKTog?= =?utf-8?q?remove_trailing_space_from_an_exception_message?= Message-ID: <3bC4DQ460sz7Lkn@mail.python.org> http://hg.python.org/cpython/rev/1471e94a8b27 changeset: 83816:1471e94a8b27 user: Victor Stinner date: Sat May 18 00:38:43 2013 +0200 summary: FileIO.readall(): remove trailing space from an exception message files: Modules/_io/fileio.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -632,7 +632,7 @@ if (bufsize > PY_SSIZE_T_MAX || bufsize <= 0) { PyErr_SetString(PyExc_OverflowError, "unbounded read returned more bytes " - "than a Python string can hold "); + "than a Python string can hold"); Py_DECREF(result); return NULL; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 18 01:23:07 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 18 May 2013 01:23:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_only_recursive?= =?utf-8?q?ly_expand_in_the_format_spec_=28closes_=2317644=29?= Message-ID: <3bC5CH48zhz7Ljv@mail.python.org> http://hg.python.org/cpython/rev/6786e681ed58 changeset: 83817:6786e681ed58 branch: 3.3 parent: 83812:cd2457463eeb user: Benjamin Peterson date: Fri May 17 17:34:30 2013 -0500 summary: only recursively expand in the format spec (closes #17644) files: Lib/test/test_unicode.py | 2 ++ Misc/NEWS | 3 +++ Objects/stringlib/unicode_format.h | 10 ++++++++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -934,6 +934,8 @@ self.assertEqual("{0:.0s}".format("ABC\u0410\u0411\u0412"), '') + self.assertEqual("{[{}]}".format({"{}": 5}), "5") + def test_format_map(self): self.assertEqual(''.format_map({}), '') self.assertEqual('a'.format_map({}), 'a') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ Core and Builtins ----------------- +- Issue #17644: Fix a crash in str.format when curly braces are used in square + brackets. + - Issue #17983: Raise a SyntaxError for a ``global __class__`` statement in a class body. diff --git a/Objects/stringlib/unicode_format.h b/Objects/stringlib/unicode_format.h --- a/Objects/stringlib/unicode_format.h +++ b/Objects/stringlib/unicode_format.h @@ -638,7 +638,7 @@ SubString *format_spec, Py_UCS4 *conversion, int *format_spec_needs_expanding) { - int at_end; + int at_end, hit_format_spec; Py_UCS4 c = 0; Py_ssize_t start; int count; @@ -723,12 +723,18 @@ /* we know we can't have a zero length string, so don't worry about that case */ + hit_format_spec = 0; while (self->str.start < self->str.end) { switch (c = PyUnicode_READ_CHAR(self->str.str, self->str.start++)) { + case ':': + hit_format_spec = 1; + count = 1; + break; case '{': /* the format spec needs to be recursively expanded. this is an optimization, and not strictly needed */ - *format_spec_needs_expanding = 1; + if (hit_format_spec) + *format_spec_needs_expanding = 1; count++; break; case '}': -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 18 01:23:08 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 18 May 2013 01:23:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3bC5CJ6YSqz7Lkn@mail.python.org> http://hg.python.org/cpython/rev/9f6684820b5f changeset: 83818:9f6684820b5f parent: 83816:1471e94a8b27 parent: 83817:6786e681ed58 user: Benjamin Peterson date: Fri May 17 17:35:28 2013 -0500 summary: merge 3.3 files: Lib/test/test_unicode.py | 2 ++ Misc/NEWS | 3 +++ Objects/stringlib/unicode_format.h | 10 ++++++++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -943,6 +943,8 @@ self.assertEqual("{0:.0s}".format("ABC\u0410\u0411\u0412"), '') + self.assertEqual("{[{}]}".format({"{}": 5}), "5") + def test_format_map(self): self.assertEqual(''.format_map({}), '') self.assertEqual('a'.format_map({}), 'a') diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ - Issue #12370: Prevent class bodies from interfering with the __class__ closure. +- Issue #17644: Fix a crash in str.format when curly braces are used in square + brackets. + - Issue #17237: Fix crash in the ASCII decoder on m68k. - Issue #17927: Frame objects kept arguments alive if they had been diff --git a/Objects/stringlib/unicode_format.h b/Objects/stringlib/unicode_format.h --- a/Objects/stringlib/unicode_format.h +++ b/Objects/stringlib/unicode_format.h @@ -638,7 +638,7 @@ SubString *format_spec, Py_UCS4 *conversion, int *format_spec_needs_expanding) { - int at_end; + int at_end, hit_format_spec; Py_UCS4 c = 0; Py_ssize_t start; int count; @@ -723,12 +723,18 @@ /* we know we can't have a zero length string, so don't worry about that case */ + hit_format_spec = 0; while (self->str.start < self->str.end) { switch (c = PyUnicode_READ_CHAR(self->str.str, self->str.start++)) { + case ':': + hit_format_spec = 1; + count = 1; + break; case '{': /* the format spec needs to be recursively expanded. this is an optimization, and not strictly needed */ - *format_spec_needs_expanding = 1; + if (hit_format_spec) + *format_spec_needs_expanding = 1; count++; break; case '}': -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 18 01:23:10 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 18 May 2013 01:23:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_rewrite_the_parsing_of_fie?= =?utf-8?q?ld_names_to_be_more_consistent_wrt_recursive_expansion?= Message-ID: <3bC5CL2zy4z7Lp1@mail.python.org> http://hg.python.org/cpython/rev/f914130c15bb changeset: 83819:f914130c15bb user: Benjamin Peterson date: Fri May 17 18:22:31 2013 -0500 summary: rewrite the parsing of field names to be more consistent wrt recursive expansion files: Lib/test/test_unicode.py | 10 +- Objects/stringlib/unicode_format.h | 115 +++++++--------- 2 files changed, 62 insertions(+), 63 deletions(-) diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -892,7 +892,7 @@ self.assertRaises(ValueError, "{0".format) self.assertRaises(IndexError, "{0.}".format) self.assertRaises(ValueError, "{0.}".format, 0) - self.assertRaises(IndexError, "{0[}".format) + self.assertRaises(ValueError, "{0[}".format) self.assertRaises(ValueError, "{0[}".format, []) self.assertRaises(KeyError, "{0]}".format) self.assertRaises(ValueError, "{0.[]}".format, 0) @@ -944,6 +944,14 @@ '') self.assertEqual("{[{}]}".format({"{}": 5}), "5") + self.assertEqual("{[{}]}".format({"{}" : "a"}), "a") + self.assertEqual("{[{]}".format({"{" : "a"}), "a") + self.assertEqual("{[}]}".format({"}" : "a"}), "a") + self.assertEqual("{[[]}".format({"[" : "a"}), "a") + self.assertEqual("{[!]}".format({"!" : "a"}), "a") + self.assertRaises(ValueError, "{a{}b}".format, 42) + self.assertRaises(ValueError, "{a{b}".format, 42) + self.assertRaises(ValueError, "{[}".format, 42) def test_format_map(self): self.assertEqual(''.format_map({}), '') diff --git a/Objects/stringlib/unicode_format.h b/Objects/stringlib/unicode_format.h --- a/Objects/stringlib/unicode_format.h +++ b/Objects/stringlib/unicode_format.h @@ -543,7 +543,7 @@ static int parse_field(SubString *str, SubString *field_name, SubString *format_spec, - Py_UCS4 *conversion) + int *format_spec_needs_expanding, Py_UCS4 *conversion) { /* Note this function works if the field name is zero length, which is good. Zero length field names are handled later, in @@ -561,6 +561,15 @@ field_name->start = str->start; while (str->start < str->end) { switch ((c = PyUnicode_READ_CHAR(str->str, str->start++))) { + case '{': + PyErr_SetString(PyExc_ValueError, "unexpected '{' in field name"); + return 0; + case '[': + for (; str->start < str->end; str->start++) + if (PyUnicode_READ_CHAR(str->str, str->start) == ']') + break; + continue; + case '}': case ':': case '!': break; @@ -570,41 +579,62 @@ break; } + field_name->end = str->start - 1; if (c == '!' || c == ':') { + Py_ssize_t count; /* we have a format specifier and/or a conversion */ /* don't include the last character */ - field_name->end = str->start-1; - - /* the format specifier is the rest of the string */ - format_spec->str = str->str; - format_spec->start = str->start; - format_spec->end = str->end; /* see if there's a conversion specifier */ if (c == '!') { /* there must be another character present */ - if (format_spec->start >= format_spec->end) { + if (str->start >= str->end) { PyErr_SetString(PyExc_ValueError, - "end of format while looking for conversion " + "end of string while looking for conversion " "specifier"); return 0; } - *conversion = PyUnicode_READ_CHAR(format_spec->str, format_spec->start++); + *conversion = PyUnicode_READ_CHAR(str->str, str->start++); - /* if there is another character, it must be a colon */ - if (format_spec->start < format_spec->end) { - c = PyUnicode_READ_CHAR(format_spec->str, format_spec->start++); + if (str->start < str->end) { + c = PyUnicode_READ_CHAR(str->str, str->start++); + if (c == '}') + return 1; if (c != ':') { PyErr_SetString(PyExc_ValueError, - "expected ':' after format specifier"); + "expected ':' after conversion specifier"); return 0; } } } + format_spec->str = str->str; + format_spec->start = str->start; + count = 1; + while (str->start < str->end) { + switch ((c = PyUnicode_READ_CHAR(str->str, str->start++))) { + case '{': + *format_spec_needs_expanding = 1; + count++; + break; + case '}': + count--; + if (count == 0) { + format_spec->end = str->start - 1; + return 1; + } + break; + default: + break; + } + } + + PyErr_SetString(PyExc_ValueError, "unmatched '{' in format spec"); + return 0; } - else - /* end of string, there's no format_spec or conversion */ - field_name->end = str->start; + else if (c != '}') { + PyErr_SetString(PyExc_ValueError, "expected '}' before end of string"); + return 0; + } return 1; } @@ -638,10 +668,9 @@ SubString *format_spec, Py_UCS4 *conversion, int *format_spec_needs_expanding) { - int at_end, hit_format_spec; + int at_end; Py_UCS4 c = 0; Py_ssize_t start; - int count; Py_ssize_t len; int markup_follows = 0; @@ -713,50 +742,12 @@ if (!markup_follows) return 2; - /* this is markup, find the end of the string by counting nested - braces. note that this prohibits escaped braces, so that - format_specs cannot have braces in them. */ + /* this is markup; parse the field */ *field_present = 1; - count = 1; - - start = self->str.start; - - /* we know we can't have a zero length string, so don't worry - about that case */ - hit_format_spec = 0; - while (self->str.start < self->str.end) { - switch (c = PyUnicode_READ_CHAR(self->str.str, self->str.start++)) { - case ':': - hit_format_spec = 1; - count = 1; - break; - case '{': - /* the format spec needs to be recursively expanded. - this is an optimization, and not strictly needed */ - if (hit_format_spec) - *format_spec_needs_expanding = 1; - count++; - break; - case '}': - count--; - if (count <= 0) { - /* we're done. parse and get out */ - SubString s; - - SubString_init(&s, self->str.str, start, self->str.start - 1); - if (parse_field(&s, field_name, format_spec, conversion) == 0) - return 0; - - /* success */ - return 2; - } - break; - } - } - - /* end of string while searching for matching '}' */ - PyErr_SetString(PyExc_ValueError, "unmatched '{' in format"); - return 0; + if (!parse_field(&self->str, field_name, format_spec, + format_spec_needs_expanding, conversion)) + return 0; + return 2; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 18 01:44:10 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 18 May 2013 01:44:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Update_docstri?= =?utf-8?q?ng_for_=5Fasdict=28=29_to_indicate_it_is_obsolete=2E?= Message-ID: <3bC5gZ0sgcz7Ljr@mail.python.org> http://hg.python.org/cpython/rev/c946f9b62852 changeset: 83820:c946f9b62852 branch: 3.3 parent: 83817:6786e681ed58 user: Raymond Hettinger date: Fri May 17 16:43:14 2013 -0700 summary: Update docstring for _asdict() to indicate it is obsolete. Use the cleaner looking @property style for __dict__. Move _replace() to be just after make() to indicate that it is a core method on named tuples. files: Lib/collections/__init__.py | 29 ++++++++++++++---------- 1 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -236,7 +236,7 @@ ### namedtuple ################################################################################ -_class_template = '''\ +_class_template = """\ from builtins import property as _property, tuple as _tuple from operator import itemgetter as _itemgetter from collections import OrderedDict @@ -260,16 +260,6 @@ raise TypeError('Expected {num_fields:d} arguments, got %d' % len(result)) return result - def __repr__(self): - 'Return a nicely formatted representation string' - return self.__class__.__name__ + '({repr_fmt})' % self - - def _asdict(self): - 'Return a new OrderedDict which maps field names to their values' - return OrderedDict(zip(self._fields, self)) - - __dict__ = property(_asdict) - def _replace(_self, **kwds): 'Return a new {typename} object replacing specified fields with new values' result = _self._make(map(kwds.pop, {field_names!r}, _self)) @@ -277,6 +267,21 @@ raise ValueError('Got unexpected field names: %r' % list(kwds)) return result + def __repr__(self): + 'Return a nicely formatted representation string' + return self.__class__.__name__ + '({repr_fmt})' % self + + @property + def __dict__(self): + 'A new OrderedDict mapping field names to their values' + return OrderedDict(zip(self._fields, self)) + + def _asdict(self): + '''Return a new OrderedDict which maps field names to their values. + This method is obsolete. Use vars(nt) or nt.__dict__ instead. + ''' + return self.__dict__ + def __getnewargs__(self): 'Return self as a plain tuple. Used by copy and pickle.' return tuple(self) @@ -286,7 +291,7 @@ return None {field_defs} -''' +""" _repr_template = '{name}=%r' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 18 01:44:11 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 18 May 2013 01:44:11 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3bC5gb34Kwz7Ljr@mail.python.org> http://hg.python.org/cpython/rev/031c93ae6c72 changeset: 83821:031c93ae6c72 parent: 83819:f914130c15bb parent: 83820:c946f9b62852 user: Raymond Hettinger date: Fri May 17 16:43:58 2013 -0700 summary: merge files: Lib/collections/__init__.py | 29 ++++++++++++++---------- 1 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -236,7 +236,7 @@ ### namedtuple ################################################################################ -_class_template = '''\ +_class_template = """\ from builtins import property as _property, tuple as _tuple from operator import itemgetter as _itemgetter from collections import OrderedDict @@ -260,16 +260,6 @@ raise TypeError('Expected {num_fields:d} arguments, got %d' % len(result)) return result - def __repr__(self): - 'Return a nicely formatted representation string' - return self.__class__.__name__ + '({repr_fmt})' % self - - def _asdict(self): - 'Return a new OrderedDict which maps field names to their values' - return OrderedDict(zip(self._fields, self)) - - __dict__ = property(_asdict) - def _replace(_self, **kwds): 'Return a new {typename} object replacing specified fields with new values' result = _self._make(map(kwds.pop, {field_names!r}, _self)) @@ -277,6 +267,21 @@ raise ValueError('Got unexpected field names: %r' % list(kwds)) return result + def __repr__(self): + 'Return a nicely formatted representation string' + return self.__class__.__name__ + '({repr_fmt})' % self + + @property + def __dict__(self): + 'A new OrderedDict mapping field names to their values' + return OrderedDict(zip(self._fields, self)) + + def _asdict(self): + '''Return a new OrderedDict which maps field names to their values. + This method is obsolete. Use vars(nt) or nt.__dict__ instead. + ''' + return self.__dict__ + def __getnewargs__(self): 'Return self as a plain tuple. Used by copy and pickle.' return tuple(self) @@ -286,7 +291,7 @@ return None {field_defs} -''' +""" _repr_template = '{name}=%r' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 18 02:14:43 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 18 May 2013 02:14:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Deprecate_nametuple=2E=5Fa?= =?utf-8?q?sdict=28=29?= Message-ID: <3bC6Lq1G6Lz7LjT@mail.python.org> http://hg.python.org/cpython/rev/c4ca39bece9d changeset: 83822:c4ca39bece9d user: Raymond Hettinger date: Fri May 17 17:14:27 2013 -0700 summary: Deprecate nametuple._asdict() files: Doc/library/collections.rst | 7 +++++-- Lib/collections/__init__.py | 3 +++ Lib/test/test_collections.py | 7 +++++-- Misc/NEWS | 3 +++ 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -829,6 +829,9 @@ .. versionchanged:: 3.1 Returns an :class:`OrderedDict` instead of a regular :class:`dict`. + .. deprecated:: 3.4 + Use ``vars(nt)`` or ``nt.__dict__`` instead. + .. method:: somenamedtuple._replace(kwargs) Return a new instance of the named tuple replacing specified fields with new @@ -845,8 +848,8 @@ A string with the pure Python source code used to create the named tuple class. The source makes the named tuple self-documenting. - It can be printed, executed using :func:`exec`, or saved to a file - and imported. + It can be printed, executed using :func:`exec`, customized, or saved + to a file and imported. .. versionadded:: 3.3 diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -280,6 +280,9 @@ '''Return a new OrderedDict which maps field names to their values. This method is obsolete. Use vars(nt) or nt.__dict__ instead. ''' + import warnings + warnings.warn('_asdict() is deprecated. Use vars(nt) instead.', + DeprecationWarning, stacklevel=2) return self.__dict__ def __getnewargs__(self): diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -217,8 +217,11 @@ self.assertEqual(p, Point._make([11, 22])) # test _make classmethod self.assertEqual(p._fields, ('x', 'y')) # test _fields attribute self.assertEqual(p._replace(x=1), (1, 22)) # test _replace method - self.assertEqual(p._asdict(), dict(x=11, y=22)) # test _asdict method - self.assertEqual(vars(p), p._asdict()) # verify that vars() works + self.assertEqual(p.__dict__, + OrderedDict([('x', 11), ('y', 22)])) # test __dict__ attribute + self.assertEqual(vars(p), p.__dict__) # verify that vars() works + with self.assertWarns(DeprecationWarning): # check deprecate of _asdict + p._asdict() try: p._replace(x=1, error=2) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -96,6 +96,9 @@ - Issue #15758: Fix FileIO.readall() so it no longer has O(n**2) complexity. +- Deprecated the _asdict() method on named tuples. Use __dict__ or vars(nt) + instead. + - Issue #14596: The struct.Struct() objects now use more compact implementation. - Issue #17981: Closed socket on error in SysLogHandler. -- Repository URL: http://hg.python.org/cpython From tjreedy at udel.edu Sat May 18 01:20:41 2013 From: tjreedy at udel.edu (Terry Reedy) Date: Fri, 17 May 2013 19:20:41 -0400 Subject: [Python-checkins] peps: New PEP: Safe object finalization In-Reply-To: <3bC2Td0Td6z7LjT@mail.python.org> References: <3bC2Td0Td6z7LjT@mail.python.org> Message-ID: <5196BB49.6090408@udel.edu> On 5/17/2013 5:20 PM, antoine.pitrou wrote: > http://hg.python.org/peps/rev/0763444c74b3 > changeset: 4890:0763444c74b3 > user: Antoine Pitrou > date: Fri May 17 23:17:31 2013 +0200 > summary: > New PEP: Safe object finalization My summary: A . __del__ method can do anything that any method can do. This includes 'insane' things (for a deletion process) like constructing new links. This imposes constraints and a cost on the 'ghost cycle' deletion process. A ghost cycle is dead but still 'here' in the sense of taking up space and gc time. The current solution is to not call finalizers in ghost cycles. Key idea: shift the cost (in the form of keeping some ghost cycles around forever, and making efforts to avoid creating immortal ghosts) from everyone to those who write 'insane' finalizers for objects that might end up in ghost cycles. The gain for most is that ghost cycles, even those with sane finalizers, get sent to the great beyond, freeing space and time in the world we care about. The cost for the few is possible indeterminate behavior. Whether a ghost cycle is deleted or resurrected, and in the latter case, which reference causes the resurrection, may depend on the arbitrary order of calling finalizers. I think it a good tradeoff. +1 Key insight (which seems correct): calling finalizers in ghost cycles can be made safe by calling each just once and then checking for resurrection of the cycle. ... > +3. **The CI is traversed again to determine if it is still isolated. > + If it is determined that at least one object in CI is now reachable > + from outside the CI, this collection is aborted and the whole CI > + is resurrected. Otherwise, proceed.** ... > +* The finalizer creates a new reference to a CI object. This can only > + happen from a CI object's finalizer (see above why). Therefore, the > + new reference will be detected by the GC after all CI finalizers are > + called (step 3 above), and collection will be aborted without any > + objects being broken. I think this case should be split in two cases that have different answers to the question in 3 above. A. The finalizer causes the creation of a new reference *between* a CI objects. Increasing the density the CI graph is not a problem. Collection can proceed. B. The finalizer causes the creation of a new reference from a non-CI object to a CI object. The cycle is resurrected and collection aborted. -- Terry Jan Reedy From solipsis at pitrou.net Sat May 18 05:59:18 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 18 May 2013 05:59:18 +0200 Subject: [Python-checkins] Daily reference leaks (c4ca39bece9d): sum=0 Message-ID: results for c4ca39bece9d on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog4g2feC', '-x'] From python-checkins at python.org Sat May 18 09:06:09 2013 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 18 May 2013 09:06:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Undo_the_deprecation_of_?= =?utf-8?b?X2FzZGljdCgpLg==?= Message-ID: <3bCHTY1dCHzRwP@mail.python.org> http://hg.python.org/cpython/rev/1b760f926846 changeset: 83823:1b760f926846 user: Raymond Hettinger date: Sat May 18 00:05:20 2013 -0700 summary: Undo the deprecation of _asdict(). Backed out changeset c4ca39bece9d files: Doc/library/collections.rst | 7 ++----- Lib/collections/__init__.py | 3 --- Lib/test/test_collections.py | 7 ++----- Misc/NEWS | 3 --- 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -829,9 +829,6 @@ .. versionchanged:: 3.1 Returns an :class:`OrderedDict` instead of a regular :class:`dict`. - .. deprecated:: 3.4 - Use ``vars(nt)`` or ``nt.__dict__`` instead. - .. method:: somenamedtuple._replace(kwargs) Return a new instance of the named tuple replacing specified fields with new @@ -848,8 +845,8 @@ A string with the pure Python source code used to create the named tuple class. The source makes the named tuple self-documenting. - It can be printed, executed using :func:`exec`, customized, or saved - to a file and imported. + It can be printed, executed using :func:`exec`, or saved to a file + and imported. .. versionadded:: 3.3 diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -280,9 +280,6 @@ '''Return a new OrderedDict which maps field names to their values. This method is obsolete. Use vars(nt) or nt.__dict__ instead. ''' - import warnings - warnings.warn('_asdict() is deprecated. Use vars(nt) instead.', - DeprecationWarning, stacklevel=2) return self.__dict__ def __getnewargs__(self): diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -217,11 +217,8 @@ self.assertEqual(p, Point._make([11, 22])) # test _make classmethod self.assertEqual(p._fields, ('x', 'y')) # test _fields attribute self.assertEqual(p._replace(x=1), (1, 22)) # test _replace method - self.assertEqual(p.__dict__, - OrderedDict([('x', 11), ('y', 22)])) # test __dict__ attribute - self.assertEqual(vars(p), p.__dict__) # verify that vars() works - with self.assertWarns(DeprecationWarning): # check deprecate of _asdict - p._asdict() + self.assertEqual(p._asdict(), dict(x=11, y=22)) # test _asdict method + self.assertEqual(vars(p), p._asdict()) # verify that vars() works try: p._replace(x=1, error=2) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -96,9 +96,6 @@ - Issue #15758: Fix FileIO.readall() so it no longer has O(n**2) complexity. -- Deprecated the _asdict() method on named tuples. Use __dict__ or vars(nt) - instead. - - Issue #14596: The struct.Struct() objects now use more compact implementation. - Issue #17981: Closed socket on error in SysLogHandler. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 18 09:30:42 2013 From: python-checkins at python.org (nick.coghlan) Date: Sat, 18 May 2013 09:30:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Record_rejection_of_PEP_437?= Message-ID: <3bCJ1t6yMHz7LjP@mail.python.org> http://hg.python.org/peps/rev/25d09d4bc90d changeset: 4893:25d09d4bc90d user: Nick Coghlan date: Sat May 18 17:30:25 2013 +1000 summary: Record rejection of PEP 437 files: pep-0437.txt | 14 ++++++++++++-- 1 files changed, 12 insertions(+), 2 deletions(-) diff --git a/pep-0437.txt b/pep-0437.txt --- a/pep-0437.txt +++ b/pep-0437.txt @@ -3,13 +3,13 @@ Version: $Revision$ Last-Modified: $Date$ Author: Stefan Krah -Status: Draft +Status: Rejected Type: Standards Track Content-Type: text/x-rst Created: 2013-03-11 Python-Version: 3.4 Post-History: -Resolution: +Resolution: http://mail.python.org/pipermail/python-dev/2013-May/126117.html Abstract ======== @@ -31,6 +31,14 @@ function*. +Rejection Notice +================ + +This PEP was rejected by Guido van Rossum at PyCon US 2013. However, several +of the specific issues raised by this PEP were taken into account when +designing the `second iteration of the PEP 436 DSL`_. + + Rationale ========= @@ -388,6 +396,8 @@ .. _Open Publication License: http://www.opencontent.org/openpub/ +.. _second iteration of the PEP 436 DSL: + http://hg.python.org/peps/rev/a2fa10b2424b .. -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat May 18 09:50:58 2013 From: python-checkins at python.org (nick.coghlan) Date: Sat, 18 May 2013 09:50:58 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Mass_deferral_as_proposed_on_?= =?utf-8?q?python-dev?= Message-ID: <3bCJTG4L44z7Llm@mail.python.org> http://hg.python.org/peps/rev/7f35a31df000 changeset: 4894:7f35a31df000 user: Nick Coghlan date: Sat May 18 17:50:40 2013 +1000 summary: Mass deferral as proposed on python-dev files: pep-0286.txt | 12 +++++++++++- pep-0337.txt | 9 ++++++++- pep-0368.txt | 9 ++++++++- pep-0396.txt | 9 ++++++++- pep-0400.txt | 9 ++++++++- pep-0419.txt | 10 +++++++++- pep-0423.txt | 7 ++++++- pep-0444.txt | 14 +++++++++++++- pep-3124.txt | 2 +- pep-3143.txt | 10 +++++++++- pep-3145.txt | 9 ++++++++- pep-3152.txt | 9 ++++++++- 12 files changed, 97 insertions(+), 12 deletions(-) diff --git a/pep-0286.txt b/pep-0286.txt --- a/pep-0286.txt +++ b/pep-0286.txt @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: martin at v.loewis.de (Martin von L?wis) -Status: Draft +Status: Deferred Type: Standards Track Created: 3-Mar-2002 Python-Version: 2.3 @@ -16,6 +16,16 @@ an argument converter creates new memory. To deal with these cases, a specialized argument type is proposed. +PEP Deferral + + Further exploration of the concepts covered in this PEP has been deferred + for lack of a current champion interested in promoting the goals of the + PEP and collecting and incorporating feedback, and with sufficient + available time to do so effectively. + + The resolution of this PEP may also be affected by the resolution of + PEP 426, which proposes the use of a preprocessing step to generate + some aspects of C API interface code. Problem description diff --git a/pep-0337.txt b/pep-0337.txt --- a/pep-0337.txt +++ b/pep-0337.txt @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Michael P. Dubner -Status: Draft +Status: Deferred Type: Standards Track Content-Type: text/plain Created: 02-Oct-2004 @@ -26,6 +26,13 @@ logging.getLogger('py.BaseHTTPServer').setLevel(logging.FATAL) +PEP Deferral + + Further exploration of the concepts covered in this PEP has been deferred + for lack of a current champion interested in promoting the goals of the + PEP and collecting and incorporating feedback, and with sufficient + available time to do so effectively. + Rationale diff --git a/pep-0368.txt b/pep-0368.txt --- a/pep-0368.txt +++ b/pep-0368.txt @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Lino Mastrodomenico -Status: Draft +Status: Deferred Type: Standards Track Content-Type: text/x-rst Created: 28-Jun-2007 @@ -39,6 +39,13 @@ also proposed, together with a mixin class that helps adding support for the protocol to existing image classes. +PEP Deferral +============ + +Further exploration of the concepts covered in this PEP has been deferred +for lack of a current champion interested in promoting the goals of the PEP +and collecting and incorporating feedback, and with sufficient available +time to do so effectively. Rationale ========= diff --git a/pep-0396.txt b/pep-0396.txt --- a/pep-0396.txt +++ b/pep-0396.txt @@ -3,7 +3,7 @@ Version: $Revision: 65628 $ Last-Modified: $Date: 2008-08-10 09:59:20 -0400 (Sun, 10 Aug 2008) $ Author: Barry Warsaw -Status: Draft +Status: Deferred Type: Informational Content-Type: text/x-rst Created: 2011-03-16 @@ -24,6 +24,13 @@ (such as ``distutils2`` [1]_) may be adapted to use the conventions defined here. +PEP Deferral +============ + +Further exploration of the concepts covered in this PEP has been deferred +for lack of a current champion interested in promoting the goals of the PEP +and collecting and incorporating feedback, and with sufficient available +time to do so effectively. User Stories ============ diff --git a/pep-0400.txt b/pep-0400.txt --- a/pep-0400.txt +++ b/pep-0400.txt @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Victor Stinner -Status: Draft +Status: Deferred Type: Standards Track Content-Type: text/x-rst Created: 28-May-2011 @@ -25,6 +25,13 @@ `_), and reimplemented in C in Python 2.7 and 3.1. +PEP Deferral +============ + +Further exploration of the concepts covered in this PEP has been deferred +for lack of a current champion interested in promoting the goals of the PEP +and collecting and incorporating feedback, and with sufficient available +time to do so effectively. Motivation ========== diff --git a/pep-0419.txt b/pep-0419.txt --- a/pep-0419.txt +++ b/pep-0419.txt @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Paul Colomiets -Status: Draft +Status: Deferred Type: Standards Track Content-Type: text/x-rst Created: 06-Apr-2012 @@ -16,6 +16,14 @@ This PEP proposes a way to protect Python code from being interrupted inside a finally clause or during context manager cleanup. +PEP Deferral +============ + +Further exploration of the concepts covered in this PEP has been deferred +for lack of a current champion interested in promoting the goals of the PEP +and collecting and incorporating feedback, and with sufficient available +time to do so effectively. + Rationale ========= diff --git a/pep-0423.txt b/pep-0423.txt --- a/pep-0423.txt +++ b/pep-0423.txt @@ -4,7 +4,7 @@ Last-Modified: $Date$ Author: Benoit Bryon Discussions-To: -Status: Draft +Status: Deferred Type: Informational Content-Type: text/x-rst Created: 24-May-2012 @@ -28,6 +28,11 @@ `specific recipes for existing projects <#how-to-apply-naming-guidelines-on-existing-projects>`_. +PEP Deferral +============ + +Further consideration of this PEP has been deferred at least until after +PEP 426 (package metadata 2.0) and related updates have been resolved. Terminology =========== diff --git a/pep-0444.txt b/pep-0444.txt --- a/pep-0444.txt +++ b/pep-0444.txt @@ -5,7 +5,7 @@ Author: Chris McDonough , Armin Ronacher Discussions-To: Python Web-SIG -Status: Draft +Status: Deferred Type: Informational Content-Type: text/x-rst Created: 19-Jul-2010 @@ -18,6 +18,18 @@ interface between web servers and Python web applications or frameworks. +PEP Deferral +============ + +Further exploration of the concepts covered in this PEP has been deferred +for lack of a current champion interested in promoting the goals of the PEP +and collecting and incorporating feedback, and with sufficient available +time to do so effectively. + +Note that since this PEP was first created, PEP 3333 was created as a more +incremental update that permitted use of WSGI on Python 3.2+. However, an +alternative specification that furthers the Python 3 goals of a cleaner +separation of binary and text data may still be valuable. Rationale and Goals =================== diff --git a/pep-3124.txt b/pep-3124.txt --- a/pep-3124.txt +++ b/pep-3124.txt @@ -4,7 +4,7 @@ Last-Modified: $Date$ Author: Phillip J. Eby Discussions-To: Python 3000 List -Status: Draft +Status: Deferred Type: Standards Track Content-Type: text/x-rst Requires: 3107, 3115, 3119 diff --git a/pep-3143.txt b/pep-3143.txt --- a/pep-3143.txt +++ b/pep-3143.txt @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Ben Finney -Status: Draft +Status: Deferred Type: Standards Track Content-Type: text/x-rst Created: 2009-01-26 @@ -40,6 +40,14 @@ References Copyright +============ +PEP Deferral +============ + +Further exploration of the concepts covered in this PEP has been deferred +for lack of a current champion interested in promoting the goals of the PEP +and collecting and incorporating feedback, and with sufficient available +time to do so effectively. ============= Specification diff --git a/pep-3145.txt b/pep-3145.txt --- a/pep-3145.txt +++ b/pep-3145.txt @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: (James) Eric Pruitt, Charles R. McCreary, Josiah Carlson -Status: Draft +Status: Deferred Type: Standards Track Content-Type: text/plain Created: 04-Aug-2009 @@ -18,6 +18,13 @@ subprocess.Popen more asynchronous to help alleviate these problems. + +PEP Deferral: + + Further exploration of the concepts covered in this PEP has been deferred + at least until after PEP 3156 has been resolved. + + Motivation: A search for "python asynchronous subprocess" will turn up numerous diff --git a/pep-3152.txt b/pep-3152.txt --- a/pep-3152.txt +++ b/pep-3152.txt @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Gregory Ewing -Status: Draft +Status: Deferred Type: Standards Track Content-Type: text/x-rst Created: 13-Feb-2009 @@ -27,6 +27,13 @@ independently of PEP 380 if so desired. +PEP Deferral +============ + +Further exploration of the concepts covered in this PEP has been deferred +at least until after PEP 3156 has been resolved. + + Specification ============= -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat May 18 10:08:59 2013 From: python-checkins at python.org (nick.coghlan) Date: Sat, 18 May 2013 10:08:59 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_setup=2Ecfg_support_won=27t_b?= =?utf-8?q?e_added_to_the_stdlib?= Message-ID: <3bCJt34VJ1z7LjP@mail.python.org> http://hg.python.org/peps/rev/de64d7d6ae6d changeset: 4895:de64d7d6ae6d user: Nick Coghlan date: Sat May 18 18:08:49 2013 +1000 summary: setup.cfg support won't be added to the stdlib files: pep-0390.txt | 17 ++++++++++++++++- 1 files changed, 16 insertions(+), 1 deletions(-) diff --git a/pep-0390.txt b/pep-0390.txt --- a/pep-0390.txt +++ b/pep-0390.txt @@ -3,12 +3,15 @@ Version: $Revision$ Last-Modified: $Date$ Author: Tarek Ziad? -Status: Draft +BDFL-Delegate: Nick Coghlan +Discussions-To: +Status: Rejected Type: Standards Track Content-Type: text/x-rst Created: 10-October-2009 Python-Version: 2.7 and 3.2 Post-History: +Resolution: http://mail.python.org/pipermail/distutils-sig/2013-April/020597.html Abstract ======== @@ -16,6 +19,18 @@ This PEP describes a new section and a new format for the ``setup.cfg`` file, that allows describing the Metadata of a package without using ``setup.py``. + +Rejection Notice +================ + +As distutils2 is no longer going to be incorporated into the standard +library, this PEP was rejected by Nick Coghlan in late April, 2013. + +A replacement PEP based on PEP 426 (metadata 2.0) will be created that +defines the minimum amount of information needed to generate an sdist +archive given a source tarball or VCS checkout. + + Rationale ========= -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat May 18 11:00:26 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 18 May 2013 11:00:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Wrap_at_fewer_columns=2E?= Message-ID: <3bCL1Q3Tm0z7Lmd@mail.python.org> http://hg.python.org/peps/rev/c569e6d4e92c changeset: 4896:c569e6d4e92c user: Antoine Pitrou date: Sat May 18 11:00:19 2013 +0200 summary: Wrap at fewer columns. files: pep-0442.txt | 36 +++++++++++++++++++----------------- 1 files changed, 19 insertions(+), 17 deletions(-) diff --git a/pep-0442.txt b/pep-0442.txt --- a/pep-0442.txt +++ b/pep-0442.txt @@ -54,9 +54,9 @@ Cyclic trash (CT) A reference cycle, or former reference cycle, in which no object is referenced from outside the cycle *and* whose objects have - started being cleared by the GC. Objects in cyclic trash are potential - zombies; if they are accessed by Python code, the symptoms can vary - from weird AttributeErrors to crashes. + started being cleared by the GC. Objects in cyclic trash are + potential zombies; if they are accessed by Python code, the symptoms + can vary from weird AttributeErrors to crashes. Zombie / broken object An object part of cyclic trash. The term stresses that the object @@ -67,13 +67,13 @@ Finalizer A function or method called when an object is intended to be disposed of. The finalizer can access the object and release any - resource held by the object (for example mutexes or file descriptors). - An example is a ``__del__`` method. + resource held by the object (for example mutexes or file + descriptors). An example is a ``__del__`` method. Resurrection The process by which a finalizer creates a new reference to an - object in a CI. This can happen as a quirky but supported side-effect - of ``__del__`` methods. + object in a CI. This can happen as a quirky but supported + side-effect of ``__del__`` methods. Impact @@ -123,23 +123,24 @@ --------------------------- Cyclic isolates are first detected by the garbage collector, and then -disposed of. The detection phase doesn't change and won't be described here. -Disposal of a CI traditionally works in the following order: +disposed of. The detection phase doesn't change and won't be described +here. Disposal of a CI traditionally works in the following order: -1. Weakrefs to CI objects are cleared, and their callbacks called. At this - point, the objects are still safe to use. +1. Weakrefs to CI objects are cleared, and their callbacks called. At + this point, the objects are still safe to use. 2. The CI becomes a CT as the GC systematically breaks all known references inside it (using the ``tp_clear`` function). 3. Nothing. All CT objects should have been disposed of in step 2 - (as a side-effect of clearing references); this collection is finished. + (as a side-effect of clearing references); this collection is + finished. This PEP proposes to turn CI disposal into the following sequence (new steps are in bold): -1. Weakrefs to CI objects are cleared, and their callbacks called. At this - point, the objects are still safe to use. +1. Weakrefs to CI objects are cleared, and their callbacks called. At + this point, the objects are still safe to use. 2. **The finalizers of all CI objects are called.** @@ -152,7 +153,8 @@ known references inside it (using the ``tp_clear`` function). 5. Nothing. All CT objects should have been disposed of in step 4 - (as a side-effect of clearing references); this collection is finished. + (as a side-effect of clearing references); this collection is + finished. C-level changes @@ -172,8 +174,8 @@ On the internal side, a bit is reserved in the GC header for GC-managed objects to signal that they were finalized. This helps avoid finalizing -an object twice (and, especially, finalizing a CT object after it was broken -by the GC). +an object twice (and, especially, finalizing a CT object after it was +broken by the GC). Discussion -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat May 18 16:53:53 2013 From: python-checkins at python.org (eli.bendersky) Date: Sat, 18 May 2013 16:53:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3OTg5?= =?utf-8?q?=3A_element=5Fsetattro_returned_incorrect_error_value=2E?= Message-ID: <3bCTsF3MvTzSH7@mail.python.org> http://hg.python.org/cpython/rev/9682241dc8fc changeset: 83824:9682241dc8fc branch: 3.3 parent: 83820:c946f9b62852 user: Eli Bendersky date: Sat May 18 07:52:34 2013 -0700 summary: Issue #17989: element_setattro returned incorrect error value. This caused an exception to be raised later than expected. files: Modules/_elementtree.c | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -1808,17 +1808,16 @@ return res; } -static PyObject* +static int element_setattro(ElementObject* self, PyObject* nameobj, PyObject* value) { char *name = ""; if (PyUnicode_Check(nameobj)) name = _PyUnicode_AsString(nameobj); - if (name == NULL) - return NULL; - - if (strcmp(name, "tag") == 0) { + if (name == NULL) { + return -1; + } else if (strcmp(name, "tag") == 0) { Py_DECREF(self->tag); self->tag = value; Py_INCREF(self->tag); @@ -1837,11 +1836,12 @@ self->extra->attrib = value; Py_INCREF(self->extra->attrib); } else { - PyErr_SetString(PyExc_AttributeError, name); - return NULL; + PyErr_SetString(PyExc_AttributeError, + "Can't set arbitraty attributes on Element"); + return -1; } - return NULL; + return 0; } static PySequenceMethods element_as_sequence = { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 18 16:53:54 2013 From: python-checkins at python.org (eli.bendersky) Date: Sat, 18 May 2013 16:53:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317989=3A_element=5Fsetattro_returned_incorrect_?= =?utf-8?q?error_value=2E?= Message-ID: <3bCTsG5gCgz7LjM@mail.python.org> http://hg.python.org/cpython/rev/b111ae4f83ef changeset: 83825:b111ae4f83ef parent: 83823:1b760f926846 parent: 83824:9682241dc8fc user: Eli Bendersky date: Sat May 18 07:53:47 2013 -0700 summary: Issue #17989: element_setattro returned incorrect error value. This caused an exception to be raised later than expected. files: Modules/_elementtree.c | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -1768,17 +1768,16 @@ return res; } -static PyObject* +static int element_setattro(ElementObject* self, PyObject* nameobj, PyObject* value) { char *name = ""; if (PyUnicode_Check(nameobj)) name = _PyUnicode_AsString(nameobj); - if (name == NULL) - return NULL; - - if (strcmp(name, "tag") == 0) { + if (name == NULL) { + return -1; + } else if (strcmp(name, "tag") == 0) { Py_DECREF(self->tag); self->tag = value; Py_INCREF(self->tag); @@ -1797,11 +1796,12 @@ self->extra->attrib = value; Py_INCREF(self->extra->attrib); } else { - PyErr_SetString(PyExc_AttributeError, name); - return NULL; + PyErr_SetString(PyExc_AttributeError, + "Can't set arbitraty attributes on Element"); + return -1; } - return NULL; + return 0; } static PySequenceMethods element_as_sequence = { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 18 17:59:24 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 18 May 2013 17:59:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4yKTogSXNzdWUgIzE3OTgw?= =?utf-8?q?=3A_Fix_possible_abuse_of_ssl=2Ematch=5Fhostname=28=29_for_deni?= =?utf-8?q?al_of_service?= Message-ID: <3bCWJr1PjdzRvP@mail.python.org> http://hg.python.org/cpython/rev/b9b521efeba3 changeset: 83826:b9b521efeba3 branch: 3.2 parent: 83739:6255b40c6a61 user: Antoine Pitrou date: Sat May 18 17:56:42 2013 +0200 summary: Issue #17980: Fix possible abuse of ssl.match_hostname() for denial of service using certificates with many wildcards (CVE-2013-2099). files: Lib/ssl.py | 9 ++++++++- Lib/test/test_ssl.py | 11 +++++++++++ Misc/NEWS | 3 +++ 3 files changed, 22 insertions(+), 1 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -108,9 +108,16 @@ pass -def _dnsname_to_pat(dn): +def _dnsname_to_pat(dn, max_wildcards=1): pats = [] for frag in dn.split(r'.'): + if frag.count('*') > max_wildcards: + # Issue #17980: avoid denials of service by refusing more + # than one wildcard per fragment. A survery of established + # policy among SSL implementations showed it to be a + # reasonable choice. + raise CertificateError( + "too many wildcards in certificate DNS name: " + repr(dn)) if frag == '*': # When '*' is a fragment by itself, it matches a non-empty dotless # fragment. 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 @@ -326,6 +326,17 @@ self.assertRaises(ValueError, ssl.match_hostname, None, 'example.com') self.assertRaises(ValueError, ssl.match_hostname, {}, 'example.com') + # Issue #17980: avoid denials of service by refusing more than one + # wildcard per fragment. + cert = {'subject': ((('commonName', 'a*b.com'),),)} + ok(cert, 'axxb.com') + cert = {'subject': ((('commonName', 'a*b.co*'),),)} + ok(cert, 'axxb.com') + cert = {'subject': ((('commonName', 'a*b*.com'),),)} + with self.assertRaises(ssl.CertificateError) as cm: + ssl.match_hostname(cert, 'axxbxxc.com') + self.assertIn("too many wildcards", str(cm.exception)) + def test_server_side(self): # server_hostname doesn't work for server sockets ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Library ------- +- Issue #17980: Fix possible abuse of ssl.match_hostname() for denial of + service using certificates with many wildcards (CVE-2013-2099). + - Issue #17192: Restore the patch for Issue #11729 and Issue #10309 which were omitted in 3.2.4 when updating the bundled version of libffi used by ctypes. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 18 17:59:25 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 18 May 2013 17:59:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3OTgw?= =?utf-8?q?=3A_Fix_possible_abuse_of_ssl=2Ematch=5Fhostname=28=29_for_deni?= =?utf-8?q?al_of_service?= Message-ID: <3bCWJs3z00zSGq@mail.python.org> http://hg.python.org/cpython/rev/c627638753e2 changeset: 83827:c627638753e2 branch: 3.3 parent: 83824:9682241dc8fc user: Antoine Pitrou date: Sat May 18 17:56:42 2013 +0200 summary: Issue #17980: Fix possible abuse of ssl.match_hostname() for denial of service using certificates with many wildcards (CVE-2013-2099). files: Lib/ssl.py | 9 ++++++++- Lib/test/test_ssl.py | 11 +++++++++++ Misc/NEWS | 3 +++ 3 files changed, 22 insertions(+), 1 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -129,9 +129,16 @@ pass -def _dnsname_to_pat(dn): +def _dnsname_to_pat(dn, max_wildcards=1): pats = [] for frag in dn.split(r'.'): + if frag.count('*') > max_wildcards: + # Issue #17980: avoid denials of service by refusing more + # than one wildcard per fragment. A survery of established + # policy among SSL implementations showed it to be a + # reasonable choice. + raise CertificateError( + "too many wildcards in certificate DNS name: " + repr(dn)) if frag == '*': # When '*' is a fragment by itself, it matches a non-empty dotless # fragment. 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 @@ -349,6 +349,17 @@ self.assertRaises(ValueError, ssl.match_hostname, None, 'example.com') self.assertRaises(ValueError, ssl.match_hostname, {}, 'example.com') + # Issue #17980: avoid denials of service by refusing more than one + # wildcard per fragment. + cert = {'subject': ((('commonName', 'a*b.com'),),)} + ok(cert, 'axxb.com') + cert = {'subject': ((('commonName', 'a*b.co*'),),)} + ok(cert, 'axxb.com') + cert = {'subject': ((('commonName', 'a*b*.com'),),)} + with self.assertRaises(ssl.CertificateError) as cm: + ssl.match_hostname(cert, 'axxbxxc.com') + self.assertIn("too many wildcards", str(cm.exception)) + def test_server_side(self): # server_hostname doesn't work for server sockets ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,9 @@ Library ------- +- Issue #17980: Fix possible abuse of ssl.match_hostname() for denial of + service using certificates with many wildcards (CVE-2013-2099). + - Issue #17981: Closed socket on error in SysLogHandler. - Fix typos in the multiprocessing module. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 18 17:59:26 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 18 May 2013 17:59:26 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317980=3A_Fix_possible_abuse_of_ssl=2Ematch=5Fho?= =?utf-8?q?stname=28=29_for_denial_of_service?= Message-ID: <3bCWJt6LnDzSWR@mail.python.org> http://hg.python.org/cpython/rev/fafd33db6ff6 changeset: 83828:fafd33db6ff6 parent: 83825:b111ae4f83ef parent: 83827:c627638753e2 user: Antoine Pitrou date: Sat May 18 17:59:12 2013 +0200 summary: Issue #17980: Fix possible abuse of ssl.match_hostname() for denial of service using certificates with many wildcards (CVE-2013-2099). files: Lib/ssl.py | 9 ++++++++- Lib/test/test_ssl.py | 11 +++++++++++ Misc/NEWS | 3 +++ 3 files changed, 22 insertions(+), 1 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -160,9 +160,16 @@ pass -def _dnsname_to_pat(dn): +def _dnsname_to_pat(dn, max_wildcards=1): pats = [] for frag in dn.split(r'.'): + if frag.count('*') > max_wildcards: + # Issue #17980: avoid denials of service by refusing more + # than one wildcard per fragment. A survery of established + # policy among SSL implementations showed it to be a + # reasonable choice. + raise CertificateError( + "too many wildcards in certificate DNS name: " + repr(dn)) if frag == '*': # When '*' is a fragment by itself, it matches a non-empty dotless # fragment. 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 @@ -349,6 +349,17 @@ self.assertRaises(ValueError, ssl.match_hostname, None, 'example.com') self.assertRaises(ValueError, ssl.match_hostname, {}, 'example.com') + # Issue #17980: avoid denials of service by refusing more than one + # wildcard per fragment. + cert = {'subject': ((('commonName', 'a*b.com'),),)} + ok(cert, 'axxb.com') + cert = {'subject': ((('commonName', 'a*b.co*'),),)} + ok(cert, 'axxb.com') + cert = {'subject': ((('commonName', 'a*b*.com'),),)} + with self.assertRaises(ssl.CertificateError) as cm: + ssl.match_hostname(cert, 'axxbxxc.com') + self.assertIn("too many wildcards", str(cm.exception)) + def test_server_side(self): # server_hostname doesn't work for server sockets ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -94,6 +94,9 @@ Library ------- +- Issue #17980: Fix possible abuse of ssl.match_hostname() for denial of + service using certificates with many wildcards (CVE-2013-2099). + - Issue #15758: Fix FileIO.readall() so it no longer has O(n**2) complexity. - Issue #14596: The struct.Struct() objects now use more compact implementation. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 18 18:37:11 2013 From: python-checkins at python.org (richard.oudkerk) Date: Sat, 18 May 2013 18:37:11 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Use_PY=5FFORMAT=5FSIZE=5FT?= =?utf-8?q?_because_Visual_Studio_does_not_understand_=25zd_format=2E?= Message-ID: <3bCX8R6JBhzSbk@mail.python.org> http://hg.python.org/cpython/rev/0648e7fe7a72 changeset: 83829:0648e7fe7a72 user: Richard Oudkerk date: Sat May 18 17:35:19 2013 +0100 summary: Use PY_FORMAT_SIZE_T because Visual Studio does not understand %zd format. files: Python/getargs.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Python/getargs.c b/Python/getargs.c --- a/Python/getargs.c +++ b/Python/getargs.c @@ -373,7 +373,7 @@ } if (iarg != 0) { PyOS_snprintf(p, sizeof(buf) - (p - buf), - "argument %zd", iarg); + "argument %" PY_FORMAT_SIZE_T "d", iarg); i = 0; p += strlen(p); while (levels[i] > 0 && i < 32 && (int)(p-buf) < 220) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 18 19:14:16 2013 From: python-checkins at python.org (richard.oudkerk) Date: Sat, 18 May 2013 19:14:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Close_file_bef?= =?utf-8?q?ore_reopening_to_keep_Windows_happy_in_test=5Fsax=2E?= Message-ID: <3bCXzD53mczPk2@mail.python.org> http://hg.python.org/cpython/rev/e5d2af7a35c0 changeset: 83830:e5d2af7a35c0 branch: 3.3 parent: 83827:c627638753e2 user: Richard Oudkerk date: Sat May 18 18:11:30 2013 +0100 summary: Close file before reopening to keep Windows happy in test_sax. files: Lib/test/test_sax.py | 11 ++++++----- 1 files changed, 6 insertions(+), 5 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 @@ -578,13 +578,14 @@ writer.close() support.unlink(self.fname) self.addCleanup(cleanup) - writer.getvalue = self.getvalue + def getvalue(): + # Windows will not let use reopen without first closing + writer.close() + with open(writer.name, 'rb') as f: + return f.read() + writer.getvalue = getvalue return writer - def getvalue(self): - with open(self.fname, 'rb') as f: - return f.read() - def xml(self, doc, encoding='iso-8859-1'): return ('\n%s' % (encoding, doc)).encode('ascii', 'xmlcharrefreplace') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 18 19:14:18 2013 From: python-checkins at python.org (richard.oudkerk) Date: Sat, 18 May 2013 19:14:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogTWVyZ2Uu?= Message-ID: <3bCXzG0CcRzPk2@mail.python.org> http://hg.python.org/cpython/rev/0ecb7ccad300 changeset: 83831:0ecb7ccad300 parent: 83829:0648e7fe7a72 parent: 83830:e5d2af7a35c0 user: Richard Oudkerk date: Sat May 18 18:13:16 2013 +0100 summary: Merge. files: Lib/test/test_sax.py | 11 ++++++----- 1 files changed, 6 insertions(+), 5 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 @@ -578,13 +578,14 @@ writer.close() support.unlink(self.fname) self.addCleanup(cleanup) - writer.getvalue = self.getvalue + def getvalue(): + # Windows will not let use reopen without first closing + writer.close() + with open(writer.name, 'rb') as f: + return f.read() + writer.getvalue = getvalue return writer - def getvalue(self): - with open(self.fname, 'rb') as f: - return f.read() - def xml(self, doc, encoding='iso-8859-1'): return ('\n%s' % (encoding, doc)).encode('ascii', 'xmlcharrefreplace') -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 18 19:20:20 2013 From: python-checkins at python.org (vinay.sajip) Date: Sat, 18 May 2013 19:20:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Re-enabled_skipped_test=2E?= Message-ID: <3bCY6D3bhxzRWt@mail.python.org> http://hg.python.org/cpython/rev/23836f17e4a2 changeset: 83832:23836f17e4a2 user: Vinay Sajip date: Sat May 18 10:19:54 2013 -0700 summary: Re-enabled skipped test. files: Lib/test/test_logging.py | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3964,14 +3964,14 @@ finally: rh.close() - @unittest.skipIf(True, 'Temporarily skipped while failures investigated.') + #@unittest.skipIf(True, 'Temporarily skipped while failures investigated.') def test_compute_rollover_weekly_attime(self): currentTime = int(time.time()) today = currentTime - currentTime % 86400 atTime = datetime.time(12, 0, 0) - wday = datetime.datetime.fromtimestamp(currentTime + time.timezone).weekday() + wday = time.gmtime(today).tm_wday for day in range(7): rh = logging.handlers.TimedRotatingFileHandler( self.fn, when='W%d' % day, interval=1, backupCount=0, utc=True, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 19 00:48:05 2013 From: python-checkins at python.org (eli.bendersky) Date: Sun, 19 May 2013 00:48:05 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3OTAx?= =?utf-8?q?=3A_fix_TreeBuilder_construction_for_an_explicit_element=5Ffact?= =?utf-8?q?ory=3DNone?= Message-ID: <3bChNP54BDzRwQ@mail.python.org> http://hg.python.org/cpython/rev/c430bea30457 changeset: 83833:c430bea30457 branch: 3.3 parent: 83830:e5d2af7a35c0 user: Eli Bendersky date: Sat May 18 15:47:16 2013 -0700 summary: Issue #17901: fix TreeBuilder construction for an explicit element_factory=None Based on report and patch by Aaron Oakley. files: Lib/test/test_xml_etree.py | 6 ++++++ Misc/ACKS | 1 + Modules/_elementtree.c | 2 +- 3 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -1762,6 +1762,12 @@ parser.feed(self.sample1) self.assertIsNone(parser.close()) + def test_treebuilder_elementfactory_none(self): + parser = ET.XMLParser(target=ET.TreeBuilder(element_factory=None)) + parser.feed(self.sample1) + e = parser.close() + self._check_sample1_element(e) + def test_subclass(self): class MyTreeBuilder(ET.TreeBuilder): def foobar(self, x): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -887,6 +887,7 @@ Kevin O'Connor Tim O'Malley Zooko O'Whielacronx +Aaron Oakley James Oakley Jon Oberheide Pascal Oberndoerfer diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -2381,7 +2381,7 @@ self->data = NULL; } - if (self->element_factory) { + if (self->element_factory && self->element_factory != Py_None) { node = PyObject_CallFunction(self->element_factory, "OO", tag, attrib); } else { node = create_new_element(tag, attrib); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 19 00:48:07 2013 From: python-checkins at python.org (eli.bendersky) Date: Sun, 19 May 2013 00:48:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317901=3A_fix_TreeBuilder_construction_for_an_ex?= =?utf-8?q?plicit_element=5Ffactory=3DNone?= Message-ID: <3bChNR08RGzSB9@mail.python.org> http://hg.python.org/cpython/rev/e79df5d1f680 changeset: 83834:e79df5d1f680 parent: 83832:23836f17e4a2 parent: 83833:c430bea30457 user: Eli Bendersky date: Sat May 18 15:47:58 2013 -0700 summary: Issue #17901: fix TreeBuilder construction for an explicit element_factory=None Based on report and patch by Aaron Oakley. files: Lib/test/test_xml_etree.py | 6 ++++++ Misc/ACKS | 1 + Modules/_elementtree.c | 2 +- 3 files changed, 8 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -1896,6 +1896,12 @@ parser.feed(self.sample1) self.assertIsNone(parser.close()) + def test_treebuilder_elementfactory_none(self): + parser = ET.XMLParser(target=ET.TreeBuilder(element_factory=None)) + parser.feed(self.sample1) + e = parser.close() + self._check_sample1_element(e) + def test_subclass(self): class MyTreeBuilder(ET.TreeBuilder): def foobar(self, x): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -905,6 +905,7 @@ Kevin O'Connor Tim O'Malley Zooko O'Whielacronx +Aaron Oakley James Oakley Jon Oberheide Pascal Oberndoerfer diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -2341,7 +2341,7 @@ self->data = NULL; } - if (self->element_factory) { + if (self->element_factory && self->element_factory != Py_None) { node = PyObject_CallFunction(self->element_factory, "OO", tag, attrib); } else { node = create_new_element(tag, attrib); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 19 00:53:06 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 19 May 2013 00:53:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Fix_a_definition_and_add_some?= =?utf-8?q?_clarifications?= Message-ID: <3bChVB1zsszRR7@mail.python.org> http://hg.python.org/peps/rev/78c9cb157954 changeset: 4897:78c9cb157954 user: Antoine Pitrou date: Sun May 19 00:51:45 2013 +0200 summary: Fix a definition and add some clarifications files: pep-0442.txt | 41 +++++++++++++++++++++++++++------------ 1 files changed, 28 insertions(+), 13 deletions(-) diff --git a/pep-0442.txt b/pep-0442.txt --- a/pep-0442.txt +++ b/pep-0442.txt @@ -41,9 +41,10 @@ scheme. Cyclic isolate (CI) - A reference cycle in which no object is referenced from outside the - cycle *and* whose objects are still in a usable, non-broken state: - they can access each other from their respective finalizers. + A standalone subgraph of objects in which no object is referenced + from the outside, containing one or several reference cycles, *and* + whose objects are still in a usable, non-broken state: they can + access each other from their respective finalizers. Cyclic garbage collector (GC) A device able to detect cyclic isolates and turn them into cyclic @@ -52,11 +53,10 @@ reference counts dropping to zero. Cyclic trash (CT) - A reference cycle, or former reference cycle, in which no object - is referenced from outside the cycle *and* whose objects have - started being cleared by the GC. Objects in cyclic trash are - potential zombies; if they are accessed by Python code, the symptoms - can vary from weird AttributeErrors to crashes. + A former cyclic isolate whose objects have started being cleared + by the GC. Objects in cyclic trash are potential zombies; if they + are accessed by Python code, the symptoms can vary from weird + AttributeErrors to crashes. Zombie / broken object An object part of cyclic trash. The term stresses that the object @@ -156,15 +156,21 @@ (as a side-effect of clearing references); this collection is finished. +.. note:: + The GC doesn't recalculate the CI after step 2 above, hence the need + for step 3 to check that the whole subgraph is still isolated. + C-level changes =============== Type objects get a new ``tp_finalize`` slot to which ``__del__`` methods -are bound. Generators are also modified to use this slot, rather than -``tp_del``. At the C level, a ``tp_finalize`` function is a normal -function which will be called with a regular, alive object as its only -argument. It should not attempt to revive or collect the object. +are mapped (and reciprocally). Generators are modified to use this slot, +rather than ``tp_del``. A ``tp_finalize`` function is a normal C +function which will be called with a valid and alive ``PyObject`` as its +only argument. It doesn't need to manipulate the object's reference count, +as this will be done by the caller. However, it must ensure that the +original exception state is restored before returning to the caller. For compatibility, ``tp_del`` is kept in the type structure. Handling of objects with a non-NULL ``tp_del`` is unchanged: when part of a CI, @@ -172,11 +178,20 @@ ``tp_del`` is not encountered anymore in the CPython source tree (except for testing purposes). +Two new C API functions are provided to ease calling of ``tp_finalize``, +especially from custom deallocators. + On the internal side, a bit is reserved in the GC header for GC-managed objects to signal that they were finalized. This helps avoid finalizing an object twice (and, especially, finalizing a CT object after it was broken by the GC). +.. note:: + Objects which are not GC-enabled can also have a ``tp_finalize`` slot. + They don't need the additional bit since their ``tp_finalize`` function + can only be called from the deallocator: it therefore cannot be called + twice, except when resurrected. + Discussion ========== @@ -186,7 +201,7 @@ Following this scheme, an object's finalizer is always called exactly once. The only exception is if an object is resurrected: the finalizer -will be called again later. +will be called again when the object becomes unreachable again. For CI objects, the order in which finalizers are called (step 2 above) is undefined. -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun May 19 00:53:07 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 19 May 2013 00:53:07 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Fill_in_Post-History?= Message-ID: <3bChVC3wnBzRR7@mail.python.org> http://hg.python.org/peps/rev/fdcabe7c9a35 changeset: 4898:fdcabe7c9a35 user: Antoine Pitrou date: Sun May 19 00:52:59 2013 +0200 summary: Fill in Post-History files: pep-0442.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0442.txt b/pep-0442.txt --- a/pep-0442.txt +++ b/pep-0442.txt @@ -8,7 +8,7 @@ Content-Type: text/x-rst Created: 2013-05-18 Python-Version: 3.4 -Post-History: +Post-History: 2013-05-18 Resolution: TBD -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun May 19 01:12:20 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 19 May 2013 01:12:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2317937=3A_Try_hard?= =?utf-8?q?er_to_collect_cyclic_garbage_at_shutdown=2E?= Message-ID: <3bChwN6hpqzSGt@mail.python.org> http://hg.python.org/cpython/rev/5abe85aefe29 changeset: 83835:5abe85aefe29 user: Antoine Pitrou date: Sun May 19 01:11:58 2013 +0200 summary: Issue #17937: Try harder to collect cyclic garbage at shutdown. files: Include/objimpl.h | 4 ++++ Misc/NEWS | 2 ++ Modules/gcmodule.c | 31 +++++++++++++++++++++++++------ Python/import.c | 1 + 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/Include/objimpl.h b/Include/objimpl.h --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -232,6 +232,10 @@ /* C equivalent of gc.collect(). */ PyAPI_FUNC(Py_ssize_t) PyGC_Collect(void); +#ifndef Py_LIMITED_API +PyAPI_FUNC(Py_ssize_t) _PyGC_CollectNoFail(void); +#endif + /* Test if a type has a GC head */ #define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,8 @@ Core and Builtins ----------------- +- Issue #17937: Try harder to collect cyclic garbage at shutdown. + - Issue #12370: Prevent class bodies from interfering with the __class__ closure. diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -853,7 +853,8 @@ /* This is the main function. Read this to understand how the * collection process works. */ static Py_ssize_t -collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable) +collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable, + int nofail) { int i; Py_ssize_t m = 0; /* # objects collected */ @@ -1000,10 +1001,15 @@ } if (PyErr_Occurred()) { - if (gc_str == NULL) - gc_str = PyUnicode_FromString("garbage collection"); - PyErr_WriteUnraisable(gc_str); - Py_FatalError("unexpected exception during garbage collection"); + if (nofail) { + PyErr_Clear(); + } + else { + if (gc_str == NULL) + gc_str = PyUnicode_FromString("garbage collection"); + PyErr_WriteUnraisable(gc_str); + Py_FatalError("unexpected exception during garbage collection"); + } } /* Update stats */ @@ -1062,7 +1068,7 @@ { Py_ssize_t result, collected, uncollectable; invoke_gc_callback("start", generation, 0, 0); - result = collect(generation, &collected, &uncollectable); + result = collect(generation, &collected, &uncollectable, 0); invoke_gc_callback("stop", generation, collected, uncollectable); return result; } @@ -1544,6 +1550,19 @@ return n; } +Py_ssize_t +_PyGC_CollectNoFail(void) +{ + Py_ssize_t n; + + /* This function should only be called on interpreter shutdown, and + therefore not recursively. */ + assert(!collecting); + collecting = 1; + n = collect(NUM_GENERATIONS - 1, NULL, NULL, 1); + collecting = 0; + return n; +} void _PyGC_DumpShutdownStats(void) diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -444,6 +444,7 @@ /* Finally, clear and delete the modules directory */ PyDict_Clear(modules); + _PyGC_CollectNoFail(); interp->modules = NULL; Py_DECREF(modules); } -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun May 19 05:47:04 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 19 May 2013 05:47:04 +0200 Subject: [Python-checkins] Daily reference leaks (5abe85aefe29): sum=0 Message-ID: results for 5abe85aefe29 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog8YMrPY', '-x'] From python-checkins at python.org Sun May 19 07:19:39 2013 From: python-checkins at python.org (georg.brandl) Date: Sun, 19 May 2013 07:19:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?release=3A_Use_=22hg_touch=22_where_a?= =?utf-8?q?vailable_to_update_generated_file_timestamps=2E_Fixes?= Message-ID: <3bCs4C3tKBz7Ljh@mail.python.org> http://hg.python.org/release/rev/2dd672c67008 changeset: 63:2dd672c67008 user: Georg Brandl date: Sun May 19 07:20:25 2013 +0200 summary: Use "hg touch" where available to update generated file timestamps. Fixes #18008. files: release.py | 27 +++++++++++++++++---------- 1 files changed, 17 insertions(+), 10 deletions(-) diff --git a/release.py b/release.py --- a/release.py +++ b/release.py @@ -264,6 +264,23 @@ run_cmd(['hg', 'archive', '--config', 'ui.archivemeta=off', '-r', tag.hgname, archivename]) with changed_dir(archivename): + # Touch a few files that get generated so they're up-to-date in + # the tarball. + if os.path.isfile('.hgtouch'): + # Use "hg touch" if available + run_cmd(['hg', '-v', 'touch', '--config', + 'extensions.touch=Tools/hg/hgtouch.py']) + else: + touchables = ['Include/Python-ast.h', 'Python/Python-ast.c'] + if os.path.exists('Python/opcode_targets.h'): + # This file isn't in Python < 3.1 + touchables.append('Python/opcode_targets.h') + print('Touching:', COMMASPACE.join(name.rsplit('/', 1)[-1] + for name in touchables)) + for name in touchables: + os.utime(name, None) + + # Remove files we don't want to ship in tarballs. print('Removing VCS .*ignore and .hg*') for name in ('.hgignore', '.hgeol', '.hgtags', '.hgtouch', '.bzrignore', '.gitignore'): @@ -271,16 +288,6 @@ os.unlink(name) except OSError: pass - # Touch a few files that get generated so they're up-to-date in - # the tarball. - touchables = ['Include/Python-ast.h', 'Python/Python-ast.c'] - if os.path.exists('Python/opcode_targets.h'): - # This file isn't in Python < 3.1 - touchables.append('Python/opcode_targets.h') - print('Touching:', COMMASPACE.join(name.rsplit('/', 1)[-1] - for name in touchables)) - for name in touchables: - os.utime(name, None) if tag.is_final: docdist = build_docs() -- Repository URL: http://hg.python.org/release From python-checkins at python.org Sun May 19 07:58:13 2013 From: python-checkins at python.org (richard.jones) Date: Sun, 19 May 2013 07:58:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_accept_pep_438?= Message-ID: <3bCswj6DWzzS9Q@mail.python.org> http://hg.python.org/peps/rev/451adcfa6e0c changeset: 4899:451adcfa6e0c user: Richard Jones date: Sun May 19 15:58:06 2013 +1000 summary: accept pep 438 files: pep-0438.txt | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0438.txt b/pep-0438.txt --- a/pep-0438.txt +++ b/pep-0438.txt @@ -5,11 +5,11 @@ Author: Holger Krekel , Carl Meyer BDFL-Delegate: Richard Jones Discussions-To: distutils-sig at python.org -Status: Draft +Status: Accepted Type: Process Content-Type: text/x-rst Created: 15-Mar-2013 -Post-History: +Post-History: 19-May-2013 Abstract -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun May 19 10:50:02 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 19 May 2013 10:50:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3ODEy?= =?utf-8?q?=3A_Fixed_quadratic_complexity_of_base64=2Eb32encode=28=29=2E?= Message-ID: <3bCxky1Fmgz7LjZ@mail.python.org> http://hg.python.org/cpython/rev/4b5467d997f1 changeset: 83836:4b5467d997f1 branch: 3.3 parent: 83833:c430bea30457 user: Serhiy Storchaka date: Sun May 19 11:41:15 2013 +0300 summary: Issue #17812: Fixed quadratic complexity of base64.b32encode(). files: Lib/base64.py | 12 ++++++------ Misc/NEWS | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Lib/base64.py b/Lib/base64.py --- a/Lib/base64.py +++ b/Lib/base64.py @@ -166,7 +166,7 @@ if leftover: s = s + bytes(5 - leftover) # Don't use += ! quanta += 1 - encoded = bytes() + encoded = bytearray() for i in range(quanta): # c1 and c2 are 16 bits wide, c3 is 8 bits wide. The intent of this # code is to process the 40 bits in units of 5 bits. So we take the 1 @@ -187,14 +187,14 @@ ]) # Adjust for any leftover partial quanta if leftover == 1: - return encoded[:-6] + b'======' + encoded[-6:] = b'======' elif leftover == 2: - return encoded[:-4] + b'====' + encoded[-4:] = b'====' elif leftover == 3: - return encoded[:-3] + b'===' + encoded[-3:] = b'===' elif leftover == 4: - return encoded[:-1] + b'=' - return encoded + encoded[-1:] = b'=' + return bytes(encoded) def b32decode(s, casefold=False, map01=None): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,8 @@ Library ------- +- Issue #17812: Fixed quadratic complexity of base64.b32encode(). + - Issue #17980: Fix possible abuse of ssl.match_hostname() for denial of service using certificates with many wildcards (CVE-2013-2099). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 19 10:50:03 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Sun, 19 May 2013 10:50:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317812=3A_Fixed_quadratic_complexity_of_base64?= =?utf-8?b?LmIzMmVuY29kZSgpLg==?= Message-ID: <3bCxkz4rp7z7LkW@mail.python.org> http://hg.python.org/cpython/rev/1b5ef05d6ced changeset: 83837:1b5ef05d6ced parent: 83835:5abe85aefe29 parent: 83836:4b5467d997f1 user: Serhiy Storchaka date: Sun May 19 11:49:32 2013 +0300 summary: Issue #17812: Fixed quadratic complexity of base64.b32encode(). Optimize base64.b32encode() and base64.b32decode() (speed up to 3x). files: Lib/base64.py | 125 ++++++++++++++----------------------- Misc/NEWS | 3 + 2 files changed, 51 insertions(+), 77 deletions(-) diff --git a/Lib/base64.py b/Lib/base64.py --- a/Lib/base64.py +++ b/Lib/base64.py @@ -138,21 +138,10 @@ # Base32 encoding/decoding must be done in Python -_b32alphabet = { - 0: b'A', 9: b'J', 18: b'S', 27: b'3', - 1: b'B', 10: b'K', 19: b'T', 28: b'4', - 2: b'C', 11: b'L', 20: b'U', 29: b'5', - 3: b'D', 12: b'M', 21: b'V', 30: b'6', - 4: b'E', 13: b'N', 22: b'W', 31: b'7', - 5: b'F', 14: b'O', 23: b'X', - 6: b'G', 15: b'P', 24: b'Y', - 7: b'H', 16: b'Q', 25: b'Z', - 8: b'I', 17: b'R', 26: b'2', - } - -_b32tab = [v[0] for k, v in sorted(_b32alphabet.items())] -_b32rev = dict([(v[0], k) for k, v in _b32alphabet.items()]) - +_b32alphabet = b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567' +_b32tab = [bytes([i]) for i in _b32alphabet] +_b32tab2 = [a + b for a in _b32tab for b in _b32tab] +_b32rev = {v: k for k, v in enumerate(_b32alphabet)} def b32encode(s): """Encode a byte string using Base32. @@ -161,41 +150,30 @@ """ if not isinstance(s, bytes_types): raise TypeError("expected bytes, not %s" % s.__class__.__name__) - quanta, leftover = divmod(len(s), 5) + leftover = len(s) % 5 # Pad the last quantum with zero bits if necessary if leftover: s = s + bytes(5 - leftover) # Don't use += ! - quanta += 1 - encoded = bytes() - for i in range(quanta): - # c1 and c2 are 16 bits wide, c3 is 8 bits wide. The intent of this - # code is to process the 40 bits in units of 5 bits. So we take the 1 - # leftover bit of c1 and tack it onto c2. Then we take the 2 leftover - # bits of c2 and tack them onto c3. The shifts and masks are intended - # to give us values of exactly 5 bits in width. - c1, c2, c3 = struct.unpack('!HHB', s[i*5:(i+1)*5]) - c2 += (c1 & 1) << 16 # 17 bits wide - c3 += (c2 & 3) << 8 # 10 bits wide - encoded += bytes([_b32tab[c1 >> 11], # bits 1 - 5 - _b32tab[(c1 >> 6) & 0x1f], # bits 6 - 10 - _b32tab[(c1 >> 1) & 0x1f], # bits 11 - 15 - _b32tab[c2 >> 12], # bits 16 - 20 (1 - 5) - _b32tab[(c2 >> 7) & 0x1f], # bits 21 - 25 (6 - 10) - _b32tab[(c2 >> 2) & 0x1f], # bits 26 - 30 (11 - 15) - _b32tab[c3 >> 5], # bits 31 - 35 (1 - 5) - _b32tab[c3 & 0x1f], # bits 36 - 40 (1 - 5) - ]) + encoded = bytearray() + from_bytes = int.from_bytes + b32tab2 = _b32tab2 + for i in range(0, len(s), 5): + c = from_bytes(s[i: i + 5], 'big') + encoded += (b32tab2[c >> 30] + # bits 1 - 10 + b32tab2[(c >> 20) & 0x3ff] + # bits 11 - 20 + b32tab2[(c >> 10) & 0x3ff] + # bits 21 - 30 + b32tab2[c & 0x3ff] # bits 31 - 40 + ) # Adjust for any leftover partial quanta if leftover == 1: - return encoded[:-6] + b'======' + encoded[-6:] = b'======' elif leftover == 2: - return encoded[:-4] + b'====' + encoded[-4:] = b'====' elif leftover == 3: - return encoded[:-3] + b'===' + encoded[-3:] = b'===' elif leftover == 4: - return encoded[:-1] + b'=' - return encoded - + encoded[-1:] = b'=' + return bytes(encoded) def b32decode(s, casefold=False, map01=None): """Decode a Base32 encoded byte string. @@ -217,8 +195,7 @@ characters present in the input. """ s = _bytes_from_decode_data(s) - quanta, leftover = divmod(len(s), 8) - if leftover: + if len(s) % 8: raise binascii.Error('Incorrect padding') # Handle section 2.4 zero and one mapping. The flag map01 will be either # False, or the character to map the digit 1 (one) to. It should be @@ -232,42 +209,36 @@ # Strip off pad characters from the right. We need to count the pad # characters because this will tell us how many null bytes to remove from # the end of the decoded string. - padchars = 0 - mo = re.search(b'(?P[=]*)$', s) - if mo: - padchars = len(mo.group('pad')) - if padchars > 0: - s = s[:-padchars] + l = len(s) + s = s.rstrip(b'=') + padchars = l - len(s) # Now decode the full quanta - parts = [] - acc = 0 - shift = 35 - for c in s: - val = _b32rev.get(c) - if val is None: + decoded = bytearray() + b32rev = _b32rev + for i in range(0, len(s), 8): + quanta = s[i: i + 8] + acc = 0 + try: + for c in quanta: + acc = (acc << 5) + b32rev[c] + except KeyError: raise TypeError('Non-base32 digit found') - acc += _b32rev[c] << shift - shift -= 5 - if shift < 0: - parts.append(binascii.unhexlify(bytes('%010x' % acc, "ascii"))) - acc = 0 - shift = 35 + decoded += acc.to_bytes(5, 'big') # Process the last, partial quanta - last = binascii.unhexlify(bytes('%010x' % acc, "ascii")) - if padchars == 0: - last = b'' # No characters - elif padchars == 1: - last = last[:-1] - elif padchars == 3: - last = last[:-2] - elif padchars == 4: - last = last[:-3] - elif padchars == 6: - last = last[:-4] - else: - raise binascii.Error('Incorrect padding') - parts.append(last) - return b''.join(parts) + if padchars: + acc <<= 5 * padchars + last = acc.to_bytes(5, 'big') + if padchars == 1: + decoded[-5:] = last[:-1] + elif padchars == 3: + decoded[-5:] = last[:-2] + elif padchars == 4: + decoded[-5:] = last[:-3] + elif padchars == 6: + decoded[-5:] = last[:-4] + else: + raise binascii.Error('Incorrect padding') + return bytes(decoded) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #17812: Fixed quadratic complexity of base64.b32encode(). + Optimize base64.b32encode() and base64.b32decode() (speed up to 3x). + - Issue #17937: Try harder to collect cyclic garbage at shutdown. - Issue #12370: Prevent class bodies from interfering with the __class__ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 19 13:53:00 2013 From: python-checkins at python.org (nick.coghlan) Date: Sun, 19 May 2013 13:53:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Add_PEP_438_resolution_link?= Message-ID: <3bD1p4108fz7Lk1@mail.python.org> http://hg.python.org/peps/rev/c62f1353cac0 changeset: 4900:c62f1353cac0 user: Nick Coghlan date: Sun May 19 21:52:51 2013 +1000 summary: Add PEP 438 resolution link files: pep-0438.txt | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/pep-0438.txt b/pep-0438.txt --- a/pep-0438.txt +++ b/pep-0438.txt @@ -10,6 +10,7 @@ Content-Type: text/x-rst Created: 15-Mar-2013 Post-History: 19-May-2013 +Resolution: http://mail.python.org/pipermail/distutils-sig/2013-May/020773.html Abstract -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sun May 19 15:46:46 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 19 May 2013 15:46:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzExOTk1?= =?utf-8?q?=3A_test=5Fpydoc_doesn=27t_import_all_sys=2Epath_modules_anymor?= =?utf-8?q?e=2E?= Message-ID: <3bD4KL6zZNz7Ljv@mail.python.org> http://hg.python.org/cpython/rev/58ace614df6b changeset: 83838:58ace614df6b branch: 3.3 parent: 83836:4b5467d997f1 user: Antoine Pitrou date: Sun May 19 15:44:54 2013 +0200 summary: Issue #11995: test_pydoc doesn't import all sys.path modules anymore. files: Lib/test/test_pydoc.py | 73 +++++++++++++++++++++++------ Misc/NEWS | 5 ++ 2 files changed, 63 insertions(+), 15 deletions(-) diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -1,10 +1,12 @@ import os import sys import builtins +import contextlib import difflib import inspect import pydoc import keyword +import pkgutil import re import string import test.support @@ -17,7 +19,8 @@ from test.script_helper import assert_python_ok from test.support import ( TESTFN, rmtree, - reap_children, reap_threads, captured_output, captured_stdout, unlink + reap_children, reap_threads, captured_output, captured_stdout, + captured_stderr, unlink ) from test import pydoc_mod @@ -259,6 +262,29 @@ return title +class PydocBaseTest(unittest.TestCase): + + def _restricted_walk_packages(self, walk_packages, path=None): + """ + A version of pkgutil.walk_packages() that will restrict itself to + a given path. + """ + default_path = path or [os.path.dirname(__file__)] + def wrapper(path=None, prefix='', onerror=None): + return walk_packages(path or default_path, prefix, onerror) + return wrapper + + @contextlib.contextmanager + def restrict_walk_packages(self, path=None): + walk_packages = pkgutil.walk_packages + pkgutil.walk_packages = self._restricted_walk_packages(walk_packages, + path) + try: + yield + finally: + pkgutil.walk_packages = walk_packages + + class PydocDocTest(unittest.TestCase): @unittest.skipIf(sys.flags.optimize >= 2, @@ -420,7 +446,7 @@ self.assertDictEqual(methods, expected) -class PydocImportTest(unittest.TestCase): +class PydocImportTest(PydocBaseTest): def setUp(self): self.test_dir = os.mkdir(TESTFN) @@ -454,8 +480,19 @@ badsyntax = os.path.join(pkgdir, "__init__") + os.extsep + "py" with open(badsyntax, 'w') as f: f.write("invalid python syntax = $1\n") - result = run_pydoc('zqwykjv', '-k', PYTHONPATH=TESTFN) - self.assertEqual(b'', result) + with self.restrict_walk_packages(path=[TESTFN]): + with captured_stdout() as out: + with captured_stderr() as err: + pydoc.apropos('xyzzy') + # No result, no error + self.assertEqual(out.getvalue(), '') + self.assertEqual(err.getvalue(), '') + # The package name is still matched + with captured_stdout() as out: + with captured_stderr() as err: + pydoc.apropos('syntaxerr') + self.assertEqual(out.getvalue().strip(), 'syntaxerr') + self.assertEqual(err.getvalue(), '') def test_apropos_with_unreadable_dir(self): # Issue 7367 - pydoc -k failed when unreadable dir on path @@ -464,8 +501,13 @@ self.addCleanup(os.rmdir, self.unreadable_dir) # Note, on Windows the directory appears to be still # readable so this is not really testing the issue there - result = run_pydoc('zqwykjv', '-k', PYTHONPATH=TESTFN) - self.assertEqual(b'', result) + with self.restrict_walk_packages(path=[TESTFN]): + with captured_stdout() as out: + with captured_stderr() as err: + pydoc.apropos('SOMEKEY') + # No result, no error + self.assertEqual(out.getvalue(), '') + self.assertEqual(err.getvalue(), '') class TestDescriptions(unittest.TestCase): @@ -527,7 +569,7 @@ self.assertEqual(serverthread.error, None) -class PydocUrlHandlerTest(unittest.TestCase): +class PydocUrlHandlerTest(PydocBaseTest): """Tests for pydoc._url_handler""" def test_content_type_err(self): @@ -554,18 +596,19 @@ ("getfile?key=foobar", "Pydoc: Error - getfile?key=foobar"), ] - for url, title in requests: + with self.restrict_walk_packages(): + for url, title in requests: + text = pydoc._url_handler(url, "text/html") + result = get_html_title(text) + self.assertEqual(result, title, text) + + path = string.__file__ + title = "Pydoc: getfile " + path + url = "getfile?key=" + path text = pydoc._url_handler(url, "text/html") result = get_html_title(text) self.assertEqual(result, title) - path = string.__file__ - title = "Pydoc: getfile " + path - url = "getfile?key=" + path - text = pydoc._url_handler(url, "text/html") - result = get_html_title(text) - self.assertEqual(result, title) - class TestHelper(unittest.TestCase): def test_keywords(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,6 +37,11 @@ - Issue #17968: Fix memory leak in os.listxattr(). +Tests +----- + +- Issue #11995: test_pydoc doesn't import all sys.path modules anymore. + Documentation ------------- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 19 15:46:48 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 19 May 2013 15:46:48 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2311995=3A_test=5Fpydoc_doesn=27t_import_all_sys?= =?utf-8?q?=2Epath_modules_anymore=2E?= Message-ID: <3bD4KN3LJlz7Lk4@mail.python.org> http://hg.python.org/cpython/rev/13d817cb72e7 changeset: 83839:13d817cb72e7 parent: 83837:1b5ef05d6ced parent: 83838:58ace614df6b user: Antoine Pitrou date: Sun May 19 15:46:37 2013 +0200 summary: Issue #11995: test_pydoc doesn't import all sys.path modules anymore. files: Lib/test/test_pydoc.py | 73 +++++++++++++++++++++++------ Misc/NEWS | 6 ++- 2 files changed, 63 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -1,10 +1,12 @@ import os import sys import builtins +import contextlib import difflib import inspect import pydoc import keyword +import pkgutil import re import string import test.support @@ -17,7 +19,8 @@ from test.script_helper import assert_python_ok from test.support import ( TESTFN, rmtree, - reap_children, reap_threads, captured_output, captured_stdout, unlink + reap_children, reap_threads, captured_output, captured_stdout, + captured_stderr, unlink ) from test import pydoc_mod @@ -255,6 +258,29 @@ return title +class PydocBaseTest(unittest.TestCase): + + def _restricted_walk_packages(self, walk_packages, path=None): + """ + A version of pkgutil.walk_packages() that will restrict itself to + a given path. + """ + default_path = path or [os.path.dirname(__file__)] + def wrapper(path=None, prefix='', onerror=None): + return walk_packages(path or default_path, prefix, onerror) + return wrapper + + @contextlib.contextmanager + def restrict_walk_packages(self, path=None): + walk_packages = pkgutil.walk_packages + pkgutil.walk_packages = self._restricted_walk_packages(walk_packages, + path) + try: + yield + finally: + pkgutil.walk_packages = walk_packages + + class PydocDocTest(unittest.TestCase): @unittest.skipIf(sys.flags.optimize >= 2, @@ -441,7 +467,7 @@ self.assertDictEqual(methods, expected) -class PydocImportTest(unittest.TestCase): +class PydocImportTest(PydocBaseTest): def setUp(self): self.test_dir = os.mkdir(TESTFN) @@ -475,8 +501,19 @@ badsyntax = os.path.join(pkgdir, "__init__") + os.extsep + "py" with open(badsyntax, 'w') as f: f.write("invalid python syntax = $1\n") - result = run_pydoc('zqwykjv', '-k', PYTHONPATH=TESTFN) - self.assertEqual(b'', result) + with self.restrict_walk_packages(path=[TESTFN]): + with captured_stdout() as out: + with captured_stderr() as err: + pydoc.apropos('xyzzy') + # No result, no error + self.assertEqual(out.getvalue(), '') + self.assertEqual(err.getvalue(), '') + # The package name is still matched + with captured_stdout() as out: + with captured_stderr() as err: + pydoc.apropos('syntaxerr') + self.assertEqual(out.getvalue().strip(), 'syntaxerr') + self.assertEqual(err.getvalue(), '') def test_apropos_with_unreadable_dir(self): # Issue 7367 - pydoc -k failed when unreadable dir on path @@ -485,8 +522,13 @@ self.addCleanup(os.rmdir, self.unreadable_dir) # Note, on Windows the directory appears to be still # readable so this is not really testing the issue there - result = run_pydoc('zqwykjv', '-k', PYTHONPATH=TESTFN) - self.assertEqual(b'', result) + with self.restrict_walk_packages(path=[TESTFN]): + with captured_stdout() as out: + with captured_stderr() as err: + pydoc.apropos('SOMEKEY') + # No result, no error + self.assertEqual(out.getvalue(), '') + self.assertEqual(err.getvalue(), '') class TestDescriptions(unittest.TestCase): @@ -548,7 +590,7 @@ self.assertEqual(serverthread.error, None) -class PydocUrlHandlerTest(unittest.TestCase): +class PydocUrlHandlerTest(PydocBaseTest): """Tests for pydoc._url_handler""" def test_content_type_err(self): @@ -575,18 +617,19 @@ ("getfile?key=foobar", "Pydoc: Error - getfile?key=foobar"), ] - for url, title in requests: + with self.restrict_walk_packages(): + for url, title in requests: + text = pydoc._url_handler(url, "text/html") + result = get_html_title(text) + self.assertEqual(result, title, text) + + path = string.__file__ + title = "Pydoc: getfile " + path + url = "getfile?key=" + path text = pydoc._url_handler(url, "text/html") result = get_html_title(text) self.assertEqual(result, title) - path = string.__file__ - title = "Pydoc: getfile " + path - url = "getfile?key=" + path - text = pydoc._url_handler(url, "text/html") - result = get_html_title(text) - self.assertEqual(result, title) - class TestHelper(unittest.TestCase): def test_keywords(self): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -331,6 +331,11 @@ - Issue #6696: add documentation for the Profile objects, and improve profile/cProfile docs. Patch by Tom Pinckney. +Tests +----- + +- Issue #11995: test_pydoc doesn't import all sys.path modules anymore. + C-API ----- @@ -338,7 +343,6 @@ - Issue #17327: Add PyDict_SetDefault. - IDLE ---- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 19 15:51:22 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 19 May 2013 15:51:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzExOTk1?= =?utf-8?q?=3A_test=5Fpydoc_doesn=27t_import_all_sys=2Epath_modules_anymor?= =?utf-8?q?e=2E?= Message-ID: <3bD4Qf2d1Pz7Lk4@mail.python.org> http://hg.python.org/cpython/rev/68d2337688c1 changeset: 83840:68d2337688c1 branch: 2.7 parent: 83797:d91da96a55bf user: Antoine Pitrou date: Sun May 19 15:44:54 2013 +0200 summary: Issue #11995: test_pydoc doesn't import all sys.path modules anymore. files: Lib/test/test_pydoc.py | 57 +++++++++++++++++++++++++---- Misc/NEWS | 6 +++ 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -4,15 +4,17 @@ import __builtin__ import re import pydoc +import contextlib import inspect import keyword +import pkgutil import unittest import xml.etree import test.test_support from collections import namedtuple from test.script_helper import assert_python_ok from test.test_support import ( - TESTFN, rmtree, reap_children, captured_stdout) + TESTFN, rmtree, reap_children, captured_stdout, captured_stderr) from test import pydoc_mod @@ -228,7 +230,30 @@ print '\n' + ''.join(diffs) -class PyDocDocTest(unittest.TestCase): +class PydocBaseTest(unittest.TestCase): + + def _restricted_walk_packages(self, walk_packages, path=None): + """ + A version of pkgutil.walk_packages() that will restrict itself to + a given path. + """ + default_path = path or [os.path.dirname(__file__)] + def wrapper(path=None, prefix='', onerror=None): + return walk_packages(path or default_path, prefix, onerror) + return wrapper + + @contextlib.contextmanager + def restrict_walk_packages(self, path=None): + walk_packages = pkgutil.walk_packages + pkgutil.walk_packages = self._restricted_walk_packages(walk_packages, + path) + try: + yield + finally: + pkgutil.walk_packages = walk_packages + + +class PydocDocTest(unittest.TestCase): @unittest.skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -O2 and above") @@ -303,7 +328,7 @@ "") -class PydocImportTest(unittest.TestCase): +class PydocImportTest(PydocBaseTest): def setUp(self): self.test_dir = os.mkdir(TESTFN) @@ -338,8 +363,19 @@ badsyntax = os.path.join(pkgdir, "__init__") + os.extsep + "py" with open(badsyntax, 'w') as f: f.write("invalid python syntax = $1\n") - result = run_pydoc('zqwykjv', '-k', PYTHONPATH=TESTFN) - self.assertEqual('', result) + with self.restrict_walk_packages(path=[TESTFN]): + with captured_stdout() as out: + with captured_stderr() as err: + pydoc.apropos('xyzzy') + # No result, no error + self.assertEqual(out.getvalue(), '') + self.assertEqual(err.getvalue(), '') + # The package name is still matched + with captured_stdout() as out: + with captured_stderr() as err: + pydoc.apropos('syntaxerr') + self.assertEqual(out.getvalue().strip(), 'syntaxerr') + self.assertEqual(err.getvalue(), '') def test_apropos_with_unreadable_dir(self): # Issue 7367 - pydoc -k failed when unreadable dir on path @@ -348,8 +384,13 @@ self.addCleanup(os.rmdir, self.unreadable_dir) # Note, on Windows the directory appears to be still # readable so this is not really testing the issue there - result = run_pydoc('zqwykjv', '-k', PYTHONPATH=TESTFN) - self.assertEqual('', result) + with self.restrict_walk_packages(path=[TESTFN]): + with captured_stdout() as out: + with captured_stderr() as err: + pydoc.apropos('SOMEKEY') + # No result, no error + self.assertEqual(out.getvalue(), '') + self.assertEqual(err.getvalue(), '') class TestDescriptions(unittest.TestCase): @@ -412,7 +453,7 @@ def test_main(): try: - test.test_support.run_unittest(PyDocDocTest, + test.test_support.run_unittest(PydocDocTest, PydocImportTest, TestDescriptions, TestHelper) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,12 @@ - Fix typos in the multiprocessing module. +Tests +----- + +- Issue #11995: test_pydoc doesn't import all sys.path modules anymore. + + What's New in Python 2.7.5? =========================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 19 15:56:06 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 19 May 2013 15:56:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Try_to_make_te?= =?utf-8?q?st_more_reliable_=28saw_some_sporadic_failures_on_buildbots=29?= Message-ID: <3bD4X65NXlz7Ljv@mail.python.org> http://hg.python.org/cpython/rev/256b8dc71046 changeset: 83841:256b8dc71046 branch: 3.3 parent: 83838:58ace614df6b user: Antoine Pitrou date: Sun May 19 15:55:40 2013 +0200 summary: Try to make test more reliable (saw some sporadic failures on buildbots) files: Lib/test/test_subprocess.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -948,10 +948,10 @@ def test_wait_timeout(self): p = subprocess.Popen([sys.executable, - "-c", "import time; time.sleep(0.1)"]) + "-c", "import time; time.sleep(0.3)"]) with self.assertRaises(subprocess.TimeoutExpired) as c: - p.wait(timeout=0.01) - self.assertIn("0.01", str(c.exception)) # For coverage of __str__. + p.wait(timeout=0.0001) + self.assertIn("0.0001", str(c.exception)) # For coverage of __str__. # Some heavily loaded buildbots (sparc Debian 3.x) require this much # time to start. self.assertEqual(p.wait(timeout=3), 0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 19 15:56:08 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 19 May 2013 15:56:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Try_to_make_test_more_reliable_=28saw_some_sporadic_fail?= =?utf-8?q?ures_on_buildbots=29?= Message-ID: <3bD4X80YPdz7LkR@mail.python.org> http://hg.python.org/cpython/rev/79bf4e7e4004 changeset: 83842:79bf4e7e4004 parent: 83839:13d817cb72e7 parent: 83841:256b8dc71046 user: Antoine Pitrou date: Sun May 19 15:55:59 2013 +0200 summary: Try to make test more reliable (saw some sporadic failures on buildbots) files: Lib/test/test_subprocess.py | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -982,10 +982,10 @@ def test_wait_timeout(self): p = subprocess.Popen([sys.executable, - "-c", "import time; time.sleep(0.1)"]) + "-c", "import time; time.sleep(0.3)"]) with self.assertRaises(subprocess.TimeoutExpired) as c: - p.wait(timeout=0.01) - self.assertIn("0.01", str(c.exception)) # For coverage of __str__. + p.wait(timeout=0.0001) + self.assertIn("0.0001", str(c.exception)) # For coverage of __str__. # Some heavily loaded buildbots (sparc Debian 3.x) require this much # time to start. self.assertEqual(p.wait(timeout=3), 0) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 19 18:01:57 2013 From: python-checkins at python.org (eli.bendersky) Date: Sun, 19 May 2013 18:01:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_=5Felementtree=2EXMLParser?= =?utf-8?q?=2E=5Fsetevents_should_support_any_sequence=2C_not_just_tuples?= Message-ID: <3bD7KK4FSgzSbL@mail.python.org> http://hg.python.org/cpython/rev/b6c333579c2b changeset: 83843:b6c333579c2b user: Eli Bendersky date: Sun May 19 09:01:49 2013 -0700 summary: _elementtree.XMLParser._setevents should support any sequence, not just tuples Also clean up some code around this files: Lib/test/test_xml_etree.py | 35 +++++++++ Lib/xml/etree/ElementTree.py | 29 ++++--- Modules/_elementtree.c | 92 +++++++++++------------ 3 files changed, 96 insertions(+), 60 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -979,6 +979,21 @@ parser.eof_received() self.assertEqual(parser.root.tag, '{namespace}root') + def test_ns_events(self): + parser = ET.IncrementalParser(events=('start-ns', 'end-ns')) + self._feed(parser, "\n") + self._feed(parser, "\n") + self.assertEqual( + list(parser.events()), + [('start-ns', ('', 'namespace'))]) + self._feed(parser, "text\n") + self._feed(parser, "texttail\n") + self._feed(parser, "\n") + self._feed(parser, "\n") + self.assertEqual(list(parser.events()), [('end-ns', None)]) + parser.eof_received() + def test_events(self): parser = ET.IncrementalParser(events=()) self._feed(parser, "\n") @@ -1026,6 +1041,26 @@ parser.eof_received() self.assertEqual(parser.root.tag, 'root') + def test_events_sequence(self): + # Test that events can be some sequence that's not just a tuple or list + eventset = {'end', 'start'} + parser = ET.IncrementalParser(events=eventset) + self._feed(parser, "bar") + self.assert_event_tags(parser, [('start', 'foo'), ('end', 'foo')]) + + class DummyIter: + def __init__(self): + self.events = iter(['start', 'end', 'start-ns']) + def __iter__(self): + return self + def __next__(self): + return next(self.events) + + parser = ET.IncrementalParser(events=DummyIter()) + self._feed(parser, "bar") + self.assert_event_tags(parser, [('start', 'foo'), ('end', 'foo')]) + + def test_unknown_event(self): with self.assertRaises(ValueError): ET.IncrementalParser(events=('start', 'end', 'bogus')) diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -1498,33 +1498,38 @@ except AttributeError: pass # unknown - def _setevents(self, event_list, events): + def _setevents(self, events_queue, events_to_report): # Internal API for IncrementalParser + # events_to_report: a list of events to report during parsing (same as + # the *events* of IncrementalParser's constructor. + # events_queue: a list of actual parsing events that will be populated + # by the underlying parser. + # parser = self._parser - append = event_list.append - for event in events: - if event == "start": + append = events_queue.append + for event_name in events_to_report: + if event_name == "start": parser.ordered_attributes = 1 parser.specified_attributes = 1 - def handler(tag, attrib_in, event=event, append=append, + def handler(tag, attrib_in, event=event_name, append=append, start=self._start_list): append((event, start(tag, attrib_in))) parser.StartElementHandler = handler - elif event == "end": - def handler(tag, event=event, append=append, + elif event_name == "end": + def handler(tag, event=event_name, append=append, end=self._end): append((event, end(tag))) parser.EndElementHandler = handler - elif event == "start-ns": - def handler(prefix, uri, event=event, append=append): + elif event_name == "start-ns": + def handler(prefix, uri, event=event_name, append=append): append((event, (prefix or "", uri or ""))) parser.StartNamespaceDeclHandler = handler - elif event == "end-ns": - def handler(prefix, event=event, append=append): + elif event_name == "end-ns": + def handler(prefix, event=event_name, append=append): append((event, None)) parser.EndNamespaceDeclHandler = handler else: - raise ValueError("unknown event %r" % event) + raise ValueError("unknown event %r" % event_name) def _raiseerror(self, value): err = ParseError(value) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -3431,14 +3431,14 @@ xmlparser_setevents(XMLParserObject *self, PyObject* args) { /* activate element event reporting */ - - Py_ssize_t i; - TreeBuilderObject* target; - - PyObject* events; /* event collector */ - PyObject* event_set = Py_None; - if (!PyArg_ParseTuple(args, "O!|O:_setevents", &PyList_Type, &events, - &event_set)) + Py_ssize_t i, seqlen; + TreeBuilderObject *target; + + PyObject *events_queue; + PyObject *events_to_report = Py_None; + PyObject *events_seq; + if (!PyArg_ParseTuple(args, "O!|O:_setevents", &PyList_Type, &events_queue, + &events_to_report)) return NULL; if (!TreeBuilder_CheckExact(self->target)) { @@ -3452,9 +3452,9 @@ target = (TreeBuilderObject*) self->target; - Py_INCREF(events); + Py_INCREF(events_queue); Py_XDECREF(target->events); - target->events = events; + target->events = events_queue; /* clear out existing events */ Py_CLEAR(target->start_event_obj); @@ -3462,69 +3462,65 @@ Py_CLEAR(target->start_ns_event_obj); Py_CLEAR(target->end_ns_event_obj); - if (event_set == Py_None) { + if (events_to_report == Py_None) { /* default is "end" only */ target->end_event_obj = PyUnicode_FromString("end"); Py_RETURN_NONE; } - if (!PyTuple_Check(event_set)) /* FIXME: handle arbitrary sequences */ - goto error; - - for (i = 0; i < PyTuple_GET_SIZE(event_set); i++) { - PyObject* item = PyTuple_GET_ITEM(event_set, i); - char* event; - if (PyUnicode_Check(item)) { - event = _PyUnicode_AsString(item); - if (event == NULL) - goto error; - } else if (PyBytes_Check(item)) - event = PyBytes_AS_STRING(item); - else { - goto error; + if (!(events_seq = PySequence_Fast(events_to_report, + "events must be a sequence"))) { + return NULL; + } + + seqlen = PySequence_Size(events_seq); + for (i = 0; i < seqlen; ++i) { + PyObject *event_name_obj = PySequence_Fast_GET_ITEM(events_seq, i); + char *event_name = NULL; + if (PyUnicode_Check(event_name_obj)) { + event_name = _PyUnicode_AsString(event_name_obj); + } else if (PyBytes_Check(event_name_obj)) { + event_name = PyBytes_AS_STRING(event_name_obj); } - if (strcmp(event, "start") == 0) { - Py_INCREF(item); - target->start_event_obj = item; - } else if (strcmp(event, "end") == 0) { - Py_INCREF(item); + + if (event_name == NULL) { + Py_DECREF(events_seq); + PyErr_Format(PyExc_ValueError, "invalid events sequence"); + return NULL; + } else if (strcmp(event_name, "start") == 0) { + Py_INCREF(event_name_obj); + target->start_event_obj = event_name_obj; + } else if (strcmp(event_name, "end") == 0) { + Py_INCREF(event_name_obj); Py_XDECREF(target->end_event_obj); - target->end_event_obj = item; - } else if (strcmp(event, "start-ns") == 0) { - Py_INCREF(item); + target->end_event_obj = event_name_obj; + } else if (strcmp(event_name, "start-ns") == 0) { + Py_INCREF(event_name_obj); Py_XDECREF(target->start_ns_event_obj); - target->start_ns_event_obj = item; + target->start_ns_event_obj = event_name_obj; EXPAT(SetNamespaceDeclHandler)( self->parser, (XML_StartNamespaceDeclHandler) expat_start_ns_handler, (XML_EndNamespaceDeclHandler) expat_end_ns_handler ); - } else if (strcmp(event, "end-ns") == 0) { - Py_INCREF(item); + } else if (strcmp(event_name, "end-ns") == 0) { + Py_INCREF(event_name_obj); Py_XDECREF(target->end_ns_event_obj); - target->end_ns_event_obj = item; + target->end_ns_event_obj = event_name_obj; EXPAT(SetNamespaceDeclHandler)( self->parser, (XML_StartNamespaceDeclHandler) expat_start_ns_handler, (XML_EndNamespaceDeclHandler) expat_end_ns_handler ); } else { - PyErr_Format( - PyExc_ValueError, - "unknown event '%s'", event - ); + Py_DECREF(events_seq); + PyErr_Format(PyExc_ValueError, "unknown event '%s'", event_name); return NULL; } } + Py_DECREF(events_seq); Py_RETURN_NONE; - - error: - PyErr_SetString( - PyExc_TypeError, - "invalid event tuple" - ); - return NULL; } static PyMethodDef xmlparser_methods[] = { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 19 18:09:32 2013 From: python-checkins at python.org (eli.bendersky) Date: Sun, 19 May 2013 18:09:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Clarify_docs_too=3A_events?= =?utf-8?q?_can_be_any_sequence_=28not_that_the_C_code_supports_it=29?= Message-ID: <3bD7V44tFQz7LlC@mail.python.org> http://hg.python.org/cpython/rev/75a8b9c60523 changeset: 83844:75a8b9c60523 user: Eli Bendersky date: Sun May 19 09:09:24 2013 -0700 summary: Clarify docs too: events can be any sequence (not that the C code supports it) files: Doc/library/xml.etree.elementtree.rst | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst --- a/Doc/library/xml.etree.elementtree.rst +++ b/Doc/library/xml.etree.elementtree.rst @@ -411,7 +411,7 @@ Parses an XML section into an element tree incrementally, and reports what's going on to the user. *source* is a filename or :term:`file object` - containing XML data. *events* is a list of events to report back. The + containing XML data. *events* is a sequence of events to report back. The supported events are the strings ``"start"``, ``"end"``, ``"start-ns"`` and ``"end-ns"`` (the "ns" events are used to get detailed namespace information). If *events* is omitted, only ``"end"`` events are reported. @@ -875,8 +875,8 @@ .. class:: IncrementalParser(events=None, parser=None) An incremental, event-driven parser suitable for non-blocking applications. - *events* is a list of events to report back. The supported events are the - strings ``"start"``, ``"end"``, ``"start-ns"`` and ``"end-ns"`` (the "ns" + *events* is a sequence of events to report back. The supported events are + the strings ``"start"``, ``"end"``, ``"start-ns"`` and ``"end-ns"`` (the "ns" events are used to get detailed namespace information). If *events* is omitted, only ``"end"`` events are reported. *parser* is an optional parser instance. If not given, the standard :class:`XMLParser` parser is -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 19 18:21:02 2013 From: python-checkins at python.org (eli.bendersky) Date: Sun, 19 May 2013 18:21:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2317988=3A_remove_u?= =?utf-8?q?nused_alias_for_Element_and_rename_the_used_one?= Message-ID: <3bD7lL0h17z7LlC@mail.python.org> http://hg.python.org/cpython/rev/16a03959819a changeset: 83845:16a03959819a user: Eli Bendersky date: Sun May 19 09:20:50 2013 -0700 summary: Issue #17988: remove unused alias for Element and rename the used one Renaming to _Element_Py for clarity and moving it to a more logical location. _ElementInterface OTOH is unused and is therefore removed. Close #17988 files: Lib/test/test_xml_etree.py | 2 +- Lib/xml/etree/ElementTree.py | 24 ++++++------------------ 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -1983,7 +1983,7 @@ # Mimick SimpleTAL's behaviour (issue #16089): both versions of # TreeBuilder should be able to cope with a subclass of the # pure Python Element class. - base = ET._Element + base = ET._Element_Py # Not from a C extension self.assertEqual(base.__module__, 'xml.etree.ElementTree') # Force some multiple inheritance with a C class to make things diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -246,7 +246,6 @@ self._assert_is_element(element) self._children.extend(elements) - def insert(self, index, subelement): """Insert *subelement* at position *index*.""" self._assert_is_element(subelement) @@ -255,10 +254,9 @@ def _assert_is_element(self, e): # Need to refer to the actual Python implementation, not the # shadowing C implementation. - if not isinstance(e, _Element): + if not isinstance(e, _Element_Py): raise TypeError('expected an Element, not %s' % type(e).__name__) - def remove(self, subelement): """Remove matching subelement. @@ -287,7 +285,6 @@ ) return self._children - def find(self, path, namespaces=None): """Find first matching element by tag name or path. @@ -299,7 +296,6 @@ """ return ElementPath.find(self, path, namespaces) - def findtext(self, path, default=None, namespaces=None): """Find text for first matching element by tag name or path. @@ -314,7 +310,6 @@ """ return ElementPath.findtext(self, path, default, namespaces) - def findall(self, path, namespaces=None): """Find all matching subelements by tag name or path. @@ -326,7 +321,6 @@ """ return ElementPath.findall(self, path, namespaces) - def iterfind(self, path, namespaces=None): """Find all matching subelements by tag name or path. @@ -338,7 +332,6 @@ """ return ElementPath.iterfind(self, path, namespaces) - def clear(self): """Reset element. @@ -350,7 +343,6 @@ self._children = [] self.text = self.tail = None - def get(self, key, default=None): """Get element attribute. @@ -364,7 +356,6 @@ """ return self.attrib.get(key, default) - def set(self, key, value): """Set element attribute. @@ -375,7 +366,6 @@ """ self.attrib[key] = value - def keys(self): """Get list of attribute names. @@ -385,7 +375,6 @@ """ return self.attrib.keys() - def items(self): """Get element attributes as a sequence. @@ -397,7 +386,6 @@ """ return self.attrib.items() - def iter(self, tag=None): """Create tree iterator. @@ -430,7 +418,6 @@ ) return list(self.iter(tag)) - def itertext(self): """Create text iterator. @@ -448,9 +435,6 @@ if e.tail: yield e.tail -# compatibility -_Element = _ElementInterface = Element - def SubElement(parent, tag, attrib={}, **extra): """Subelement factory which creates an element instance, and appends it @@ -1663,13 +1647,17 @@ # Import the C accelerators try: + # Element is going to be shadowed by the C implementation. We need to keep + # the Python version of it accessible for some "creative" by external code + # (see tests) + _Element_Py = Element + # Element, SubElement, ParseError, TreeBuilder, XMLParser from _elementtree import * except ImportError: pass else: # Overwrite 'ElementTree.parse' to use the C XMLParser - class ElementTree(ElementTree): __doc__ = ElementTree.__doc__ def parse(self, source, parser=None): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 19 18:24:52 2013 From: python-checkins at python.org (eli.bendersky) Date: Sun, 19 May 2013 18:24:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Cleanup_more_old_ET_librar?= =?utf-8?q?y_leftovers?= Message-ID: <3bD7qm2CbZz7LlC@mail.python.org> http://hg.python.org/cpython/rev/7e0447ce6689 changeset: 83846:7e0447ce6689 user: Eli Bendersky date: Sun May 19 09:24:43 2013 -0700 summary: Cleanup more old ET library leftovers files: Lib/test/test_xml_etree.py | 12 +----------- Lib/xml/etree/ElementTree.py | 11 ++++------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -240,7 +240,6 @@ self.assertEqual(ET.XML, ET.fromstring) self.assertEqual(ET.PI, ET.ProcessingInstruction) - self.assertEqual(ET.XMLParser, ET.XMLTreeBuilder) def test_simpleops(self): # Basic method sanity checks. @@ -433,15 +432,6 @@ ' \n' '') - parser = ET.XMLTreeBuilder() # 1.2 compatibility - parser.feed(data) - self.serialize_check(parser.close(), - '\n' - ' text\n' - ' texttail\n' - ' \n' - '') - target = ET.TreeBuilder() parser = ET.XMLParser(target=target) parser.feed(data) @@ -1407,7 +1397,7 @@ # Don't crash when using custom entities. ENTITIES = {'rsquo': '\u2019', 'lsquo': '\u2018'} - parser = ET.XMLTreeBuilder() + parser = ET.XMLParser() parser.entity.update(ENTITIES) parser.feed(""" diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -85,7 +85,7 @@ "TreeBuilder", "VERSION", "XML", "XMLID", - "XMLParser", "XMLTreeBuilder", + "XMLParser", "register_namespace", ] @@ -1654,9 +1654,7 @@ # Element, SubElement, ParseError, TreeBuilder, XMLParser from _elementtree import * -except ImportError: - pass -else: + # Overwrite 'ElementTree.parse' to use the C XMLParser class ElementTree(ElementTree): __doc__ = ElementTree.__doc__ @@ -1681,11 +1679,10 @@ finally: if close_source: source.close() +except ImportError: + pass -# compatibility -XMLTreeBuilder = XMLParser - # workaround circular import. try: from ElementC14N import _serialize_c14n -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 19 18:27:21 2013 From: python-checkins at python.org (eli.bendersky) Date: Sun, 19 May 2013 18:27:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Cleanup_even_more_dead_cod?= =?utf-8?q?e?= Message-ID: <3bD7td5vMfz7LlC@mail.python.org> http://hg.python.org/cpython/rev/762c279a3cc5 changeset: 83847:762c279a3cc5 user: Eli Bendersky date: Sun May 19 09:25:52 2013 -0700 summary: Cleanup even more dead code files: Lib/xml/etree/ElementTree.py | 7 ------- 1 files changed, 0 insertions(+), 7 deletions(-) diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -1682,10 +1682,3 @@ except ImportError: pass - -# workaround circular import. -try: - from ElementC14N import _serialize_c14n - _serialize["c14n"] = _serialize_c14n -except ImportError: - pass -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sun May 19 18:27:23 2013 From: python-checkins at python.org (eli.bendersky) Date: Sun, 19 May 2013 18:27:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_normalize_whitespace?= Message-ID: <3bD7tg0zcsz7LlC@mail.python.org> http://hg.python.org/cpython/rev/93cc4e083eb2 changeset: 83848:93cc4e083eb2 user: Eli Bendersky date: Sun May 19 09:27:13 2013 -0700 summary: normalize whitespace files: Lib/xml/etree/ElementTree.py | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -1382,12 +1382,10 @@ self._last.text = text self._data = [] - def data(self, data): """Add text to current element.""" self._data.append(data) - def start(self, tag, attrs): """Open new element and return it. @@ -1403,7 +1401,6 @@ self._tail = 0 return elem - def end(self, tag): """Close and return current Element. @@ -1681,4 +1678,3 @@ source.close() except ImportError: pass - -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 02:00:39 2013 From: python-checkins at python.org (eli.bendersky) Date: Mon, 20 May 2013 02:00:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3OTg5?= =?utf-8?q?=3A_fix_typo_in_error_message?= Message-ID: <3bDKxg1wSpz7Lmh@mail.python.org> http://hg.python.org/cpython/rev/65680e3a7f07 changeset: 83849:65680e3a7f07 branch: 3.3 parent: 83841:256b8dc71046 user: Eli Bendersky date: Sun May 19 16:59:59 2013 -0700 summary: Issue #17989: fix typo in error message files: Modules/_elementtree.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -1837,7 +1837,7 @@ Py_INCREF(self->extra->attrib); } else { PyErr_SetString(PyExc_AttributeError, - "Can't set arbitraty attributes on Element"); + "Can't set arbitrary attributes on Element"); return -1; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 02:00:40 2013 From: python-checkins at python.org (eli.bendersky) Date: Mon, 20 May 2013 02:00:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317989=3A_fix_typo_in_error_message?= Message-ID: <3bDKxh45zrz7LnF@mail.python.org> http://hg.python.org/cpython/rev/19767536ce84 changeset: 83850:19767536ce84 parent: 83848:93cc4e083eb2 parent: 83849:65680e3a7f07 user: Eli Bendersky date: Sun May 19 17:00:28 2013 -0700 summary: Issue #17989: fix typo in error message files: Modules/_elementtree.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -1797,7 +1797,7 @@ Py_INCREF(self->extra->attrib); } else { PyErr_SetString(PyExc_AttributeError, - "Can't set arbitraty attributes on Element"); + "Can't set arbitrary attributes on Element"); return -1; } -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 02:50:02 2013 From: python-checkins at python.org (eli.bendersky) Date: Mon, 20 May 2013 02:50:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Add_some_testing_to_verify?= =?utf-8?q?_which_module_was_imported_in_ET_tests=2E?= Message-ID: <3bDM2f4hxzz7Lmh@mail.python.org> http://hg.python.org/cpython/rev/c0d7adb189b5 changeset: 83851:c0d7adb189b5 user: Eli Bendersky date: Sun May 19 17:49:54 2013 -0700 summary: Add some testing to verify which module was imported in ET tests. This is useful when mucking with import_fresh_module to either force or block importing of the _elementtree accelerator. These tests in place provide an immediate indication whether the accelerator was actually imported and overrode the classes it should have. files: Lib/test/test_xml_etree.py | 8 ++++++-- Lib/test/test_xml_etree_c.py | 9 +++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -10,6 +10,7 @@ import operator import pickle import sys +import types import unittest import weakref @@ -2398,8 +2399,11 @@ # Test that the C accelerator was not imported for pyET def test_correct_import_pyET(self): - self.assertEqual(pyET.Element.__module__, 'xml.etree.ElementTree') - self.assertEqual(pyET.SubElement.__module__, 'xml.etree.ElementTree') + # The type of methods defined in Python code is types.FunctionType, + # while the type of methods defined inside _elementtree is + # + self.assertIsInstance(pyET.Element.__init__, types.FunctionType) + self.assertIsInstance(pyET.XMLParser.__init__, types.FunctionType) # -------------------------------------------------------------------- diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py --- a/Lib/test/test_xml_etree_c.py +++ b/Lib/test/test_xml_etree_c.py @@ -2,6 +2,7 @@ import sys, struct from test import support from test.support import import_fresh_module +import types import unittest cET = import_fresh_module('xml.etree.ElementTree', @@ -33,14 +34,22 @@ @unittest.skipUnless(cET, 'requires _elementtree') + at support.cpython_only class TestAcceleratorImported(unittest.TestCase): # Test that the C accelerator was imported, as expected def test_correct_import_cET(self): + # SubElement is a function so it retains _elementtree as its module. self.assertEqual(cET.SubElement.__module__, '_elementtree') def test_correct_import_cET_alias(self): self.assertEqual(cET_alias.SubElement.__module__, '_elementtree') + def test_parser_comes_from_C(self): + # The type of methods defined in Python code is types.FunctionType, + # while the type of methods defined inside _elementtree is + # + self.assertNotIsInstance(cET.Element.__init__, types.FunctionType) + @unittest.skipUnless(cET, 'requires _elementtree') @support.cpython_only -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 03:47:33 2013 From: python-checkins at python.org (eli.bendersky) Date: Mon, 20 May 2013 03:47:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Get_rid_of_ugly_code_dupli?= =?utf-8?q?cation_for_ElementTree=2Eparse_when_the_accelerator?= Message-ID: <3bDNK12l1sz7LpH@mail.python.org> http://hg.python.org/cpython/rev/8425e8cc2bf2 changeset: 83852:8425e8cc2bf2 user: Eli Bendersky date: Sun May 19 18:47:23 2013 -0700 summary: Get rid of ugly code duplication for ElementTree.parse when the accelerator is imported. Instead, ElementTree.parse can look for a special internal method defined by the accelerator. files: Lib/xml/etree/ElementTree.py | 39 ++++++----------------- Modules/_elementtree.c | 7 +-- 2 files changed, 14 insertions(+), 32 deletions(-) diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -587,9 +587,17 @@ source = open(source, "rb") close_source = True try: - if not parser: - parser = XMLParser(target=TreeBuilder()) - while 1: + if parser is None: + # If no parser was specified, create a default XMLParser + parser = XMLParser() + if hasattr(parser, '_parse_whole'): + # The default XMLParser, when it comes from an accelerator, + # can define an internal _parse_whole API for efficiency. + # It can be used to parse the whole source without feeding + # it with chunks. + self._root = parser._parse_whole(source) + return self._root + while True: data = source.read(65536) if not data: break @@ -1651,30 +1659,5 @@ # Element, SubElement, ParseError, TreeBuilder, XMLParser from _elementtree import * - - # Overwrite 'ElementTree.parse' to use the C XMLParser - class ElementTree(ElementTree): - __doc__ = ElementTree.__doc__ - def parse(self, source, parser=None): - __doc__ = ElementTree.parse.__doc__ - close_source = False - if not hasattr(source, 'read'): - source = open(source, 'rb') - close_source = True - try: - if parser is not None: - while True: - data = source.read(65536) - if not data: - break - parser.feed(data) - self._root = parser.close() - else: - parser = XMLParser() - self._root = parser._parse(source) - return self._root - finally: - if close_source: - source.close() except ImportError: pass diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -3347,10 +3347,9 @@ } static PyObject* -xmlparser_parse(XMLParserObject* self, PyObject* args) +xmlparser_parse_whole(XMLParserObject* self, PyObject* args) { - /* (internal) parse until end of input stream */ - + /* (internal) parse the whole input, until end of stream */ PyObject* reader; PyObject* buffer; PyObject* temp; @@ -3526,7 +3525,7 @@ static PyMethodDef xmlparser_methods[] = { {"feed", (PyCFunction) xmlparser_feed, METH_VARARGS}, {"close", (PyCFunction) xmlparser_close, METH_VARARGS}, - {"_parse", (PyCFunction) xmlparser_parse, METH_VARARGS}, + {"_parse_whole", (PyCFunction) xmlparser_parse_whole, METH_VARARGS}, {"_setevents", (PyCFunction) xmlparser_setevents, METH_VARARGS}, {"doctype", (PyCFunction) xmlparser_doctype, METH_VARARGS}, {NULL, NULL} -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 04:39:54 2013 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 20 May 2013 04:39:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_add_missing_NU?= =?utf-8?q?LL_check_=28closes_=2318019=29?= Message-ID: <3bDPTQ3r1sz7LpF@mail.python.org> http://hg.python.org/cpython/rev/3568f8f1ccac changeset: 83853:3568f8f1ccac branch: 2.7 parent: 83840:68d2337688c1 user: Benjamin Peterson date: Sun May 19 19:38:12 2013 -0700 summary: add missing NULL check (closes #18019) files: Lib/test/test_dictviews.py | 5 +++++ Misc/NEWS | 3 +++ Objects/dictobject.c | 4 ++++ 3 files changed, 12 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_dictviews.py b/Lib/test/test_dictviews.py --- a/Lib/test/test_dictviews.py +++ b/Lib/test/test_dictviews.py @@ -144,6 +144,11 @@ self.assertEqual(d1.viewitems() ^ d3.viewitems(), {('a', 1), ('b', 2), ('d', 4), ('e', 5)}) + def test_recursive_repr(self): + d = {} + d[42] = d.viewvalues() + self.assertRaises(RuntimeError, repr, d) + diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,9 @@ Core and Builtins ----------------- +- Issue #18019: Fix crash in the repr of dictionaries containing their own + views. + Library ------- diff --git a/Objects/dictobject.c b/Objects/dictobject.c --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2919,6 +2919,10 @@ return NULL; seq_str = PyObject_Repr(seq); + if (seq_str == NULL) { + Py_DECREF(seq); + return NULL; + } result = PyString_FromFormat("%s(%s)", Py_TYPE(dv)->tp_name, PyString_AS_STRING(seq_str)); Py_DECREF(seq_str); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 04:39:55 2013 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 20 May 2013 04:39:55 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_add_recursive_?= =?utf-8?q?repr_test?= Message-ID: <3bDPTR60T0z7LpZ@mail.python.org> http://hg.python.org/cpython/rev/f194b50105bd changeset: 83854:f194b50105bd branch: 3.3 parent: 83849:65680e3a7f07 user: Benjamin Peterson date: Sun May 19 19:39:38 2013 -0700 summary: add recursive repr test files: Lib/test/test_dictviews.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_dictviews.py b/Lib/test/test_dictviews.py --- a/Lib/test/test_dictviews.py +++ b/Lib/test/test_dictviews.py @@ -179,6 +179,11 @@ self.assertTrue(de.items().isdisjoint(de.items())) self.assertTrue(de.items().isdisjoint([1])) + def test_recursive_repr(self): + d = {} + d[42] = d.values() + self.assertRaises(RuntimeError, repr, d) + def test_main(): support.run_unittest(DictSetTest) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 04:39:57 2013 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 20 May 2013 04:39:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3bDPTT157yz7LpF@mail.python.org> http://hg.python.org/cpython/rev/4d5b69af8b04 changeset: 83855:4d5b69af8b04 parent: 83852:8425e8cc2bf2 parent: 83854:f194b50105bd user: Benjamin Peterson date: Sun May 19 19:39:46 2013 -0700 summary: merge 3.3 files: Lib/test/test_dictviews.py | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_dictviews.py b/Lib/test/test_dictviews.py --- a/Lib/test/test_dictviews.py +++ b/Lib/test/test_dictviews.py @@ -179,6 +179,11 @@ self.assertTrue(de.items().isdisjoint(de.items())) self.assertTrue(de.items().isdisjoint([1])) + def test_recursive_repr(self): + d = {} + d[42] = d.values() + self.assertRaises(RuntimeError, repr, d) + def test_main(): support.run_unittest(DictSetTest) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon May 20 05:49:09 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 20 May 2013 05:49:09 +0200 Subject: [Python-checkins] Daily reference leaks (c0d7adb189b5): sum=2 Message-ID: results for c0d7adb189b5 on branch "default" -------------------------------------------- test_unittest leaked [-1, 2, 1] memory blocks, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogAdtRlk', '-x'] From python-checkins at python.org Mon May 20 07:14:27 2013 From: python-checkins at python.org (ezio.melotti) Date: Mon, 20 May 2013 07:14:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE0MDk3OiBpbXBy?= =?utf-8?q?ove_the_=22introduction=22_page_of_the_tutorial=2E?= Message-ID: <3bDSvl6K4JzSGt@mail.python.org> http://hg.python.org/cpython/rev/796d1371605d changeset: 83856:796d1371605d branch: 3.3 parent: 83854:f194b50105bd user: Ezio Melotti date: Mon May 20 08:12:32 2013 +0300 summary: #14097: improve the "introduction" page of the tutorial. files: Doc/tutorial/introduction.rst | 609 +++++++++------------ Misc/NEWS | 2 + 2 files changed, 263 insertions(+), 348 deletions(-) diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -5,7 +5,7 @@ ********************************** In the following examples, input and output are distinguished by the presence or -absence of prompts (``>>>`` and ``...``): to repeat the example, you must type +absence of prompts (:term:`>>>` and :term:`...`): to repeat the example, you must type everything after the prompt, when the prompt appears; lines that do not begin with a prompt are output from the interpreter. Note that a secondary prompt on a line by itself in an example means you must type a blank line; this is used to @@ -22,9 +22,9 @@ Some examples:: # this is the first comment - SPAM = 1 # and this is the second comment - # ... and now a third! - STRING = "# This is not a comment." + spam = 1 # and this is the second comment + # ... and now a third! + text = "# This is not a comment because it's inside quotes." .. _tut-calculator: @@ -44,55 +44,53 @@ The interpreter acts as a simple calculator: you can type an expression at it and it will write the value. Expression syntax is straightforward: the operators ``+``, ``-``, ``*`` and ``/`` work just like in most other languages -(for example, Pascal or C); parentheses can be used for grouping. For example:: +(for example, Pascal or C); parentheses (``()``) can be used for grouping. +For example:: - >>> 2+2 + >>> 2 + 2 4 - >>> # This is a comment - ... 2+2 - 4 - >>> 2+2 # and a comment on the same line as code - 4 - >>> (50-5*6)/4 + >>> 50 - 5*6 + 20 + >>> (50 - 5*6) / 4 5.0 - >>> 8/5 # Fractions aren't lost when dividing integers + >>> 8 / 5 # division always returns a floating point number 1.6 -Note: You might not see exactly the same result; floating point results can -differ from one machine to another. We will say more later about controlling -the appearance of floating point output. See also :ref:`tut-fp-issues` for a -full discussion of some of the subtleties of floating point numbers and their -representations. +The integer numbers (e.g. ``2``, ``4``, ``20``) have type :class:`int`, +the ones with a fractional part (e.g. ``5.0``, ``1.6``) have type +:class:`float`. We will see more about numberic types later in the tutorial. -To do integer division and get an integer result, -discarding any fractional result, there is another operator, ``//``:: +Division (``/``) always returns a float. To do :term:`floor division` and +get an integer result (discarding any fractional result) you can use the ``//`` +operator; to calculate the remainder you can use ``%``:: - >>> # Integer division returns the floor: - ... 7//3 + >>> 17 / 3 # classic division returns a float + 5.666666666666667 + >>> + >>> 17 // 3 # floor division discards the fractional part + 5 + >>> 17 % 3 # the % operator returns the remainder of the division 2 - >>> 7//-3 - -3 + >>> 5 * 3 + 2 # result * divisor + remainder + 17 -The equal sign (``'='``) is used to assign a value to a variable. Afterwards, no +With Python is possible to use the ``**`` operator to calculate powers [#]_:: + + >>> 5 ** 2 # 5 squared + 25 + >>> 2 ** 7 # 2 to the power of 7 + 128 + +The equal sign (``=``) is used to assign a value to a variable. Afterwards, no result is displayed before the next interactive prompt:: >>> width = 20 - >>> height = 5*9 + >>> height = 5 * 9 >>> width * height 900 -A value can be assigned to several variables simultaneously:: - - >>> x = y = z = 0 # Zero x, y and z - >>> x - 0 - >>> y - 0 - >>> z - 0 - -Variables must be "defined" (assigned a value) before they can be used, or an -error will occur:: +If a variable is not "defined" (assigned a value), trying to use it will +give you an error:: >>> n # try to access an undefined variable Traceback (most recent call last): @@ -107,49 +105,6 @@ >>> 7.0 / 2 3.5 -Complex numbers are also supported; imaginary numbers are written with a suffix -of ``j`` or ``J``. Complex numbers with a nonzero real component are written as -``(real+imagj)``, or can be created with the ``complex(real, imag)`` function. -:: - - >>> 1j * 1J - (-1+0j) - >>> 1j * complex(0, 1) - (-1+0j) - >>> 3+1j*3 - (3+3j) - >>> (3+1j)*3 - (9+3j) - >>> (1+2j)/(1+1j) - (1.5+0.5j) - -Complex numbers are always represented as two floating point numbers, the real -and imaginary part. To extract these parts from a complex number *z*, use -``z.real`` and ``z.imag``. :: - - >>> a=1.5+0.5j - >>> a.real - 1.5 - >>> a.imag - 0.5 - -The conversion functions to floating point and integer (:func:`float`, -:func:`int`) don't work for complex numbers --- there is not one correct way to -convert a complex number to a real number. Use ``abs(z)`` to get its magnitude -(as a float) or ``z.real`` to get its real part:: - - >>> a=3.0+4.0j - >>> float(a) - Traceback (most recent call last): - File "", line 1, in ? - TypeError: can't convert complex to float; use abs(z) - >>> a.real - 3.0 - >>> a.imag - 4.0 - >>> abs(a) # sqrt(a.real**2 + a.imag**2) - 5.0 - In interactive mode, the last printed expression is assigned to the variable ``_``. This means that when you are using Python as a desk calculator, it is somewhat easier to continue calculations, for example:: @@ -167,20 +122,28 @@ assign a value to it --- you would create an independent local variable with the same name masking the built-in variable with its magic behavior. +In addition to :class:`int` and :class:`float`, Python supports other types of +numbers, such as :class:`~decimal.Decimal` and :class:`~fractions.Fraction`. +Python also has built-in support for :ref:`complex numbers `, +and uses the ``j`` or ``J`` suffix to indicate the imaginary part +(e.g. ``3+5j``). + .. _tut-strings: Strings ------- -Besides numbers, Python can also manipulate strings, which can be expressed in -several ways. They can be enclosed in single quotes or double quotes:: +Besides numbers, Python can also manipulate strings, which can be expressed +in several ways. They can be enclosed in single quotes (``'...'``) or +double quotes (``"..."``) with the same result [#]_. ``\`` can be used +to escape quotes:: - >>> 'spam eggs' + >>> 'spam eggs' # single quotes 'spam eggs' - >>> 'doesn\'t' + >>> 'doesn\'t' # use \' to escape the single quote... "doesn't" - >>> "doesn't" + >>> "doesn't" # ...or use double quotes instead "doesn't" >>> '"Yes," he said.' '"Yes," he said.' @@ -189,38 +152,40 @@ >>> '"Isn\'t," she said.' '"Isn\'t," she said.' -The interpreter prints the result of string operations in the same way as they -are typed for input: inside quotes, and with quotes and other funny characters -escaped by backslashes, to show the precise value. The string is enclosed in -double quotes if the string contains a single quote and no double quotes, else -it's enclosed in single quotes. The :func:`print` function produces a more -readable output for such input strings. +In the interactive interpreter, the output string is enclosed in quotes and +special characters are escaped with backslashes. While this might sometimes +look different from the input (the enclosing quotes could change), the two +strings are equivalent. The string is enclosed in double quotes if +the string contains a single quote and no double quotes, otherwise it is +enclosed in single quotes. The :func:`print` function produces a more +readable output, by omitting the enclosing quotes and by printing escaped +and special characters:: -String literals can span multiple lines in several ways. Continuation lines can -be used, with a backslash as the last character on the line indicating that the -next line is a logical continuation of the line:: + >>> '"Isn\'t," she said.' + '"Isn\'t," she said.' + >>> print('"Isn\'t," she said.') + "Isn't," she said. + >>> s = 'First line.\nSecond line.' # \n means newline + >>> s # without print(), \n is included in the output + 'First line.\nSecond line.' + >>> print(s) # with print(), \n produces a new line + First line. + Second line. - hello = "This is a rather long string containing\n\ - several lines of text just as you would do in C.\n\ - Note that whitespace at the beginning of the line is\ - significant." +If you don't want characters prefaced by ``\`` to be interpreted as +special characters, you can use *raw strings* by adding an ``r`` before +the first quote:: - print(hello) + >>> print('C:\some\name') # here \n means newline! + C:\some + ame + >>> print(r'C:\some\name') # note the r before the quote + C:\some\name -Note that newlines still need to be embedded in the string using ``\n`` -- the -newline following the trailing backslash is discarded. This example would print -the following: - -.. code-block:: text - - This is a rather long string containing - several lines of text just as you would do in C. - Note that whitespace at the beginning of the line is significant. - -Or, strings can be surrounded in a pair of matching triple-quotes: ``"""`` or -``'''``. End of lines do not need to be escaped when using triple-quotes, but -they will be included in the string. So the following uses one escape to -avoid an unwanted initial blank line. :: +String literals can span multiple lines. One way is using triple-quotes: +``"""..."""`` or ``'''...'''``. End of lines are automatically +included in the string, but it's possible to prevent this by adding a ``\`` at +the end of the line. The following example:: print("""\ Usage: thingy [OPTIONS] @@ -228,7 +193,7 @@ -H hostname Hostname to connect to """) -produces the following output: +produces the following output (note that the initial newline is not included): .. code-block:: text @@ -236,143 +201,100 @@ -h Display this usage message -H hostname Hostname to connect to -If we make the string literal a "raw" string, ``\n`` sequences are not converted -to newlines, but the backslash at the end of the line, and the newline character -in the source, are both included in the string as data. Thus, the example:: - - hello = r"This is a rather long string containing\n\ - several lines of text much as you would do in C." - - print(hello) - -would print: - -.. code-block:: text - - This is a rather long string containing\n\ - several lines of text much as you would do in C. - Strings can be concatenated (glued together) with the ``+`` operator, and repeated with ``*``:: - >>> word = 'Help' + 'A' - >>> word - 'HelpA' - >>> '<' + word*5 + '>' - '' + >>> # 3 times 'un', followed by 'ium' + >>> 3 * 'un' + 'ium' + 'unununium' -Two string literals next to each other are automatically concatenated; the first -line above could also have been written ``word = 'Help' 'A'``; this only works -with two literals, not with arbitrary string expressions:: +Two or more *string literals* (i.e. the ones enclosed between quotes) next +to each other are automatically concatenated. :: - >>> 'str' 'ing' # <- This is ok - 'string' - >>> 'str'.strip() + 'ing' # <- This is ok - 'string' - >>> 'str'.strip() 'ing' # <- This is invalid - File "", line 1, in ? - 'str'.strip() 'ing' - ^ + >>> 'Py' 'thon' + 'Python' + +This only works with two literals though, not with variables or expressions:: + + >>> prefix = 'Py' + >>> prefix 'thon' # can't concatenate a variable and a string literal + ... + SyntaxError: invalid syntax + >>> ('un' * 3) 'ium' + ... SyntaxError: invalid syntax -Strings can be subscripted (indexed); like in C, the first character of a string -has subscript (index) 0. There is no separate character type; a character is -simply a string of size one. As in the Icon programming language, substrings -can be specified with the *slice notation*: two indices separated by a colon. -:: +If you want to concatenate variables or a variable and a literal, use ``+``:: - >>> word[4] - 'A' - >>> word[0:2] - 'He' - >>> word[2:4] - 'lp' + >>> prefix + 'thon' + 'Python' + +This feature is particularly useful when you want to break long strings:: + + >>> text = ('Put several strings within parentheses ' + 'to have them joined together.') + >>> text + 'Put several strings within parentheses to have them joined together.' + +Strings can be *indexed* (subscripted), with the first character having index 0. +There is no separate character type; a character is simply a string of size +one:: + + >>> word = 'Python' + >>> word[0] # character in position 0 + 'P' + >>> word[5] # character in position 5 + 'n' + +Indices may also be negative numbers, to start counting from the right:: + + >>> word[-1] # last character + 'n' + >>> word[-2] # second-last character + 'o' + >>> word[-6] + 'P' + +Note that since -0 is the same as 0, negative indices start from -1. + +In addition to indexing, *slicing* is also supported. While indexing is used +to obtain individual characters, *slicing* allows you to obtain substring:: + + >>> word[0:2] # characters from position 0 (included) to 2 (excluded) + 'Py' + >>> word[2:5] # characters from position 2 (included) to 4 (excluded) + 'tho' + +Note how the start is always included, and the end always excluded. This +makes sure that ``s[:i] + s[i:]`` is always equal to ``s``:: + + >>> word[:2] + word[2:] + 'Python' + >>> word[:4] + word[4:] + 'Python' Slice indices have useful defaults; an omitted first index defaults to zero, an omitted second index defaults to the size of the string being sliced. :: - >>> word[:2] # The first two characters - 'He' - >>> word[2:] # Everything except the first two characters - 'lpA' - -Unlike a C string, Python strings cannot be changed. Assigning to an indexed -position in the string results in an error:: - - >>> word[0] = 'x' - Traceback (most recent call last): - File "", line 1, in ? - TypeError: 'str' object does not support item assignment - >>> word[:1] = 'Splat' - Traceback (most recent call last): - File "", line 1, in ? - TypeError: 'str' object does not support slice assignment - -However, creating a new string with the combined content is easy and efficient:: - - >>> 'x' + word[1:] - 'xelpA' - >>> 'Splat' + word[4] - 'SplatA' - -Here's a useful invariant of slice operations: ``s[:i] + s[i:]`` equals ``s``. -:: - - >>> word[:2] + word[2:] - 'HelpA' - >>> word[:3] + word[3:] - 'HelpA' - -Degenerate slice indices are handled gracefully: an index that is too large is -replaced by the string size, an upper bound smaller than the lower bound returns -an empty string. :: - - >>> word[1:100] - 'elpA' - >>> word[10:] - '' - >>> word[2:1] - '' - -Indices may be negative numbers, to start counting from the right. For example:: - - >>> word[-1] # The last character - 'A' - >>> word[-2] # The last-but-one character - 'p' - >>> word[-2:] # The last two characters - 'pA' - >>> word[:-2] # Everything except the last two characters - 'Hel' - -But note that -0 is really the same as 0, so it does not count from the right! -:: - - >>> word[-0] # (since -0 equals 0) - 'H' - -Out-of-range negative slice indices are truncated, but don't try this for -single-element (non-slice) indices:: - - >>> word[-100:] - 'HelpA' - >>> word[-10] # error - Traceback (most recent call last): - File "", line 1, in ? - IndexError: string index out of range + >>> word[:2] # character from the beginning to position 2 (excluded) + 'Py' + >>> word[4:] # characters from position 4 (included) to the end + 'on' + >>> word[-2:] # characters from the second-last (included) to the end + 'on' One way to remember how slices work is to think of the indices as pointing *between* characters, with the left edge of the first character numbered 0. Then the right edge of the last character of a string of *n* characters has index *n*, for example:: - +---+---+---+---+---+ - | H | e | l | p | A | - +---+---+---+---+---+ - 0 1 2 3 4 5 - -5 -4 -3 -2 -1 + +---+---+---+---+---+---+ + | P | y | t | h | o | n | + +---+---+---+---+---+---+ + 0 1 2 3 4 5 6 + -6 -5 -4 -3 -2 -1 -The first row of numbers gives the position of the indices 0...5 in the string; +The first row of numbers gives the position of the indices 0...6 in the string; the second row gives the corresponding negative indices. The slice from *i* to *j* consists of all characters between the edges labeled *i* and *j*, respectively. @@ -381,6 +303,38 @@ indices, if both are within bounds. For example, the length of ``word[1:3]`` is 2. +Attempting to use a index that is too large will result in an error:: + + >>> word[42] # the word only has 7 characters + Traceback (most recent call last): + File "", line 1, in + IndexError: string index out of range + +However, out of range slice indexes are handled gracefully when used for +slicing:: + + >>> word[4:42] + 'on' + >>> word[42:] + '' + +Python strings cannot be changed --- they are :term:`immutable`. +Therefore, assigning to an indexed position in the string results in an error:: + + >>> word[0] = 'J' + ... + TypeError: 'str' object does not support item assignment + >>> word[2:] = 'py' + ... + TypeError: 'str' object does not support item assignment + +If you need a different string, you should create a new one:: + + >>> 'J' + word[1:] + 'Jython' + >>> word[:2] + 'py' + 'Pypy' + The built-in function :func:`len` returns the length of a string:: >>> s = 'supercalifragilisticexpialidocious' @@ -407,51 +361,6 @@ the left operand of the ``%`` operator are described in more detail here. -.. _tut-unicodestrings: - -About Unicode -------------- - -.. sectionauthor:: Marc-Andr? Lemburg - - -Starting with Python 3.0 all strings support Unicode (see -http://www.unicode.org/). - -Unicode has the advantage of providing one ordinal for every character in every -script used in modern and ancient texts. Previously, there were only 256 -possible ordinals for script characters. Texts were typically bound to a code -page which mapped the ordinals to script characters. This lead to very much -confusion especially with respect to internationalization (usually written as -``i18n`` --- ``'i'`` + 18 characters + ``'n'``) of software. Unicode solves -these problems by defining one code page for all scripts. - -If you want to include special characters in a string, -you can do so by using the Python *Unicode-Escape* encoding. The following -example shows how:: - - >>> 'Hello\u0020World !' - 'Hello World !' - -The escape sequence ``\u0020`` indicates to insert the Unicode character with -the ordinal value 0x0020 (the space character) at the given position. - -Other characters are interpreted by using their respective ordinal values -directly as Unicode ordinals. If you have literal strings in the standard -Latin-1 encoding that is used in many Western countries, you will find it -convenient that the lower 256 characters of Unicode are the same as the 256 -characters of Latin-1. - -Apart from these standard encodings, Python provides a whole set of other ways -of creating Unicode strings on the basis of a known encoding. - -To convert a string into a sequence of bytes using a specific encoding, -string objects provide an :func:`encode` method that takes one argument, the -name of the encoding. Lowercase names for encodings are preferred. :: - - >>> "?pfel".encode('utf-8') - b'\xc3\x84pfel' - .. _tut-lists: Lists @@ -459,97 +368,89 @@ Python knows a number of *compound* data types, used to group together other values. The most versatile is the *list*, which can be written as a list of -comma-separated values (items) between square brackets. List items need not all -have the same type. :: +comma-separated values (items) between square brackets. Lists might contain +items of different types, but usually the items all have the same type. :: - >>> a = ['spam', 'eggs', 100, 1234] - >>> a - ['spam', 'eggs', 100, 1234] + >>> squares = [1, 2, 4, 9, 16, 25] + >>> squares + [1, 2, 4, 9, 16, 25] -Like string indices, list indices start at 0, and lists can be sliced, -concatenated and so on:: +Like strings (and all other built-in :term:`sequence` type), lists can be +indexed and sliced:: - >>> a[0] - 'spam' - >>> a[3] - 1234 - >>> a[-2] - 100 - >>> a[1:-1] - ['eggs', 100] - >>> a[:2] + ['bacon', 2*2] - ['spam', 'eggs', 'bacon', 4] - >>> 3*a[:3] + ['Boo!'] - ['spam', 'eggs', 100, 'spam', 'eggs', 100, 'spam', 'eggs', 100, 'Boo!'] + >>> squares[0] # indexing returns the item + 1 + >>> squares[-1] + 25 + >>> squares[-3:] # slicing returns a new list + [9, 16, 25] All slice operations return a new list containing the requested elements. This -means that the following slice returns a shallow copy of the list *a*:: +means that the following slice returns a new (shallow) copy of the list:: - >>> a[:] - ['spam', 'eggs', 100, 1234] + >>> squares[:] + [1, 2, 4, 9, 16, 25] -Unlike strings, which are *immutable*, it is possible to change individual -elements of a list:: +Lists also supports operations like concatenation:: - >>> a - ['spam', 'eggs', 100, 1234] - >>> a[2] = a[2] + 23 - >>> a - ['spam', 'eggs', 123, 1234] + >>> squares + [36, 49, 64, 81, 100] + [1, 2, 4, 9, 16, 25, 36, 49, 64, 81, 100] + +Unlike strings, which are :term:`immutable`, lists are a :term:`mutable` +type, i.e. it is possible to change their content:: + + >>> cubes = [1, 8, 27, 65, 125] # something's wrong here + >>> 4 ** 3 # the cube of 4 is 64, not 65! + 64 + >>> cubes[3] = 64 # replace the wrong value + >>> cubes + [1, 8, 27, 64, 125] + +You can also add new items at the end of the list, by using +the :meth:`~list.append` *method* (we will see more about methods later):: + + >>> cubes.append(216) # add the cube of 6 + >>> cubes.append(7 ** 3) # and the cube of 7 + >>> cubes + [1, 8, 27, 64, 125, 216, 343] Assignment to slices is also possible, and this can even change the size of the list or clear it entirely:: - >>> # Replace some items: - ... a[0:2] = [1, 12] - >>> a - [1, 12, 123, 1234] - >>> # Remove some: - ... a[0:2] = [] - >>> a - [123, 1234] - >>> # Insert some: - ... a[1:1] = ['bletch', 'xyzzy'] - >>> a - [123, 'bletch', 'xyzzy', 1234] - >>> # Insert (a copy of) itself at the beginning - >>> a[:0] = a - >>> a - [123, 'bletch', 'xyzzy', 1234, 123, 'bletch', 'xyzzy', 1234] - >>> # Clear the list: replace all items with an empty list - >>> a[:] = [] - >>> a + >>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] + >>> letters + ['a', 'b', 'c', 'd', 'e', 'f', 'g'] + >>> # replace some values + >>> letters[2:5] = ['C', 'D', 'E'] + >>> letters + ['a', 'b', 'C', 'D', 'E', 'f', 'g'] + >>> # now remove them + >>> letters[2:5] = [] + >>> letters + ['a', 'b', 'f', 'g'] + >>> # clear the list by replacing all the elements with an empty list + >>> letters[:] = [] + >>> letters [] The built-in function :func:`len` also applies to lists:: - >>> a = ['a', 'b', 'c', 'd'] - >>> len(a) + >>> letters = ['a', 'b', 'c', 'd'] + >>> len(letters) 4 It is possible to nest lists (create lists containing other lists), for example:: - >>> q = [2, 3] - >>> p = [1, q, 4] - >>> len(p) - 3 - >>> p[1] - [2, 3] - >>> p[1][0] - 2 - -You can add something to the end of the list:: - - >>> p[1].append('xtra') - >>> p - [1, [2, 3, 'xtra'], 4] - >>> q - [2, 3, 'xtra'] - -Note that in the last example, ``p[1]`` and ``q`` really refer to the same -object! We'll come back to *object semantics* later. - + >>> a = ['a', 'b', 'c'] + >>> n = [1, 2, 3] + >>> x = [a, n] + >>> x + [['a', 'b', 'c'], [1, 2, 3]] + >>> p[0] + ['a', 'b', 'c'] + >>> p[0][1] + 'b' .. _tut-firststeps: @@ -620,3 +521,15 @@ ... a, b = b, a+b ... 1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987, + + +.. rubric:: Footnotes + +.. [#] Since ``**`` has higher precedence than ``-``, ``-3**2`` will be + interpreted as ``-(3**2)`` and thus result in ``-9``. To avoid this + and get ``9``, you can use ``(-3)**2``. + +.. [#] Unlike other languages, special characters such as ``\n`` have the + same meaning with both single (``'...'``) and double (``"..."``) quotes. + The only difference between the two is that within single quotes you don't + need to escape ``"`` (but you have to escape ``\'``) and vice versa. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -45,6 +45,8 @@ Documentation ------------- +- Issue #14097: improve the "introduction" page of the tutorial. + - Issue #17977: The documentation for the cadefault argument's default value in urllib.request.urlopen() is fixed to match the code. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 07:14:29 2013 From: python-checkins at python.org (ezio.melotti) Date: Mon, 20 May 2013 07:14:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzE0MDk3OiBtZXJnZSB3aXRoIDMuMy4=?= Message-ID: <3bDSvn42L9zSnB@mail.python.org> http://hg.python.org/cpython/rev/42dda22a6f8c changeset: 83857:42dda22a6f8c parent: 83855:4d5b69af8b04 parent: 83856:796d1371605d user: Ezio Melotti date: Mon May 20 08:14:14 2013 +0300 summary: #14097: merge with 3.3. files: Doc/tutorial/introduction.rst | 609 +++++++++------------ Misc/NEWS | 2 + 2 files changed, 263 insertions(+), 348 deletions(-) diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -5,7 +5,7 @@ ********************************** In the following examples, input and output are distinguished by the presence or -absence of prompts (``>>>`` and ``...``): to repeat the example, you must type +absence of prompts (:term:`>>>` and :term:`...`): to repeat the example, you must type everything after the prompt, when the prompt appears; lines that do not begin with a prompt are output from the interpreter. Note that a secondary prompt on a line by itself in an example means you must type a blank line; this is used to @@ -22,9 +22,9 @@ Some examples:: # this is the first comment - SPAM = 1 # and this is the second comment - # ... and now a third! - STRING = "# This is not a comment." + spam = 1 # and this is the second comment + # ... and now a third! + text = "# This is not a comment because it's inside quotes." .. _tut-calculator: @@ -44,55 +44,53 @@ The interpreter acts as a simple calculator: you can type an expression at it and it will write the value. Expression syntax is straightforward: the operators ``+``, ``-``, ``*`` and ``/`` work just like in most other languages -(for example, Pascal or C); parentheses can be used for grouping. For example:: +(for example, Pascal or C); parentheses (``()``) can be used for grouping. +For example:: - >>> 2+2 + >>> 2 + 2 4 - >>> # This is a comment - ... 2+2 - 4 - >>> 2+2 # and a comment on the same line as code - 4 - >>> (50-5*6)/4 + >>> 50 - 5*6 + 20 + >>> (50 - 5*6) / 4 5.0 - >>> 8/5 # Fractions aren't lost when dividing integers + >>> 8 / 5 # division always returns a floating point number 1.6 -Note: You might not see exactly the same result; floating point results can -differ from one machine to another. We will say more later about controlling -the appearance of floating point output. See also :ref:`tut-fp-issues` for a -full discussion of some of the subtleties of floating point numbers and their -representations. +The integer numbers (e.g. ``2``, ``4``, ``20``) have type :class:`int`, +the ones with a fractional part (e.g. ``5.0``, ``1.6``) have type +:class:`float`. We will see more about numberic types later in the tutorial. -To do integer division and get an integer result, -discarding any fractional result, there is another operator, ``//``:: +Division (``/``) always returns a float. To do :term:`floor division` and +get an integer result (discarding any fractional result) you can use the ``//`` +operator; to calculate the remainder you can use ``%``:: - >>> # Integer division returns the floor: - ... 7//3 + >>> 17 / 3 # classic division returns a float + 5.666666666666667 + >>> + >>> 17 // 3 # floor division discards the fractional part + 5 + >>> 17 % 3 # the % operator returns the remainder of the division 2 - >>> 7//-3 - -3 + >>> 5 * 3 + 2 # result * divisor + remainder + 17 -The equal sign (``'='``) is used to assign a value to a variable. Afterwards, no +With Python is possible to use the ``**`` operator to calculate powers [#]_:: + + >>> 5 ** 2 # 5 squared + 25 + >>> 2 ** 7 # 2 to the power of 7 + 128 + +The equal sign (``=``) is used to assign a value to a variable. Afterwards, no result is displayed before the next interactive prompt:: >>> width = 20 - >>> height = 5*9 + >>> height = 5 * 9 >>> width * height 900 -A value can be assigned to several variables simultaneously:: - - >>> x = y = z = 0 # Zero x, y and z - >>> x - 0 - >>> y - 0 - >>> z - 0 - -Variables must be "defined" (assigned a value) before they can be used, or an -error will occur:: +If a variable is not "defined" (assigned a value), trying to use it will +give you an error:: >>> n # try to access an undefined variable Traceback (most recent call last): @@ -107,49 +105,6 @@ >>> 7.0 / 2 3.5 -Complex numbers are also supported; imaginary numbers are written with a suffix -of ``j`` or ``J``. Complex numbers with a nonzero real component are written as -``(real+imagj)``, or can be created with the ``complex(real, imag)`` function. -:: - - >>> 1j * 1J - (-1+0j) - >>> 1j * complex(0, 1) - (-1+0j) - >>> 3+1j*3 - (3+3j) - >>> (3+1j)*3 - (9+3j) - >>> (1+2j)/(1+1j) - (1.5+0.5j) - -Complex numbers are always represented as two floating point numbers, the real -and imaginary part. To extract these parts from a complex number *z*, use -``z.real`` and ``z.imag``. :: - - >>> a=1.5+0.5j - >>> a.real - 1.5 - >>> a.imag - 0.5 - -The conversion functions to floating point and integer (:func:`float`, -:func:`int`) don't work for complex numbers --- there is not one correct way to -convert a complex number to a real number. Use ``abs(z)`` to get its magnitude -(as a float) or ``z.real`` to get its real part:: - - >>> a=3.0+4.0j - >>> float(a) - Traceback (most recent call last): - File "", line 1, in ? - TypeError: can't convert complex to float; use abs(z) - >>> a.real - 3.0 - >>> a.imag - 4.0 - >>> abs(a) # sqrt(a.real**2 + a.imag**2) - 5.0 - In interactive mode, the last printed expression is assigned to the variable ``_``. This means that when you are using Python as a desk calculator, it is somewhat easier to continue calculations, for example:: @@ -167,20 +122,28 @@ assign a value to it --- you would create an independent local variable with the same name masking the built-in variable with its magic behavior. +In addition to :class:`int` and :class:`float`, Python supports other types of +numbers, such as :class:`~decimal.Decimal` and :class:`~fractions.Fraction`. +Python also has built-in support for :ref:`complex numbers `, +and uses the ``j`` or ``J`` suffix to indicate the imaginary part +(e.g. ``3+5j``). + .. _tut-strings: Strings ------- -Besides numbers, Python can also manipulate strings, which can be expressed in -several ways. They can be enclosed in single quotes or double quotes:: +Besides numbers, Python can also manipulate strings, which can be expressed +in several ways. They can be enclosed in single quotes (``'...'``) or +double quotes (``"..."``) with the same result [#]_. ``\`` can be used +to escape quotes:: - >>> 'spam eggs' + >>> 'spam eggs' # single quotes 'spam eggs' - >>> 'doesn\'t' + >>> 'doesn\'t' # use \' to escape the single quote... "doesn't" - >>> "doesn't" + >>> "doesn't" # ...or use double quotes instead "doesn't" >>> '"Yes," he said.' '"Yes," he said.' @@ -189,38 +152,40 @@ >>> '"Isn\'t," she said.' '"Isn\'t," she said.' -The interpreter prints the result of string operations in the same way as they -are typed for input: inside quotes, and with quotes and other funny characters -escaped by backslashes, to show the precise value. The string is enclosed in -double quotes if the string contains a single quote and no double quotes, else -it's enclosed in single quotes. The :func:`print` function produces a more -readable output for such input strings. +In the interactive interpreter, the output string is enclosed in quotes and +special characters are escaped with backslashes. While this might sometimes +look different from the input (the enclosing quotes could change), the two +strings are equivalent. The string is enclosed in double quotes if +the string contains a single quote and no double quotes, otherwise it is +enclosed in single quotes. The :func:`print` function produces a more +readable output, by omitting the enclosing quotes and by printing escaped +and special characters:: -String literals can span multiple lines in several ways. Continuation lines can -be used, with a backslash as the last character on the line indicating that the -next line is a logical continuation of the line:: + >>> '"Isn\'t," she said.' + '"Isn\'t," she said.' + >>> print('"Isn\'t," she said.') + "Isn't," she said. + >>> s = 'First line.\nSecond line.' # \n means newline + >>> s # without print(), \n is included in the output + 'First line.\nSecond line.' + >>> print(s) # with print(), \n produces a new line + First line. + Second line. - hello = "This is a rather long string containing\n\ - several lines of text just as you would do in C.\n\ - Note that whitespace at the beginning of the line is\ - significant." +If you don't want characters prefaced by ``\`` to be interpreted as +special characters, you can use *raw strings* by adding an ``r`` before +the first quote:: - print(hello) + >>> print('C:\some\name') # here \n means newline! + C:\some + ame + >>> print(r'C:\some\name') # note the r before the quote + C:\some\name -Note that newlines still need to be embedded in the string using ``\n`` -- the -newline following the trailing backslash is discarded. This example would print -the following: - -.. code-block:: text - - This is a rather long string containing - several lines of text just as you would do in C. - Note that whitespace at the beginning of the line is significant. - -Or, strings can be surrounded in a pair of matching triple-quotes: ``"""`` or -``'''``. End of lines do not need to be escaped when using triple-quotes, but -they will be included in the string. So the following uses one escape to -avoid an unwanted initial blank line. :: +String literals can span multiple lines. One way is using triple-quotes: +``"""..."""`` or ``'''...'''``. End of lines are automatically +included in the string, but it's possible to prevent this by adding a ``\`` at +the end of the line. The following example:: print("""\ Usage: thingy [OPTIONS] @@ -228,7 +193,7 @@ -H hostname Hostname to connect to """) -produces the following output: +produces the following output (note that the initial newline is not included): .. code-block:: text @@ -236,143 +201,100 @@ -h Display this usage message -H hostname Hostname to connect to -If we make the string literal a "raw" string, ``\n`` sequences are not converted -to newlines, but the backslash at the end of the line, and the newline character -in the source, are both included in the string as data. Thus, the example:: - - hello = r"This is a rather long string containing\n\ - several lines of text much as you would do in C." - - print(hello) - -would print: - -.. code-block:: text - - This is a rather long string containing\n\ - several lines of text much as you would do in C. - Strings can be concatenated (glued together) with the ``+`` operator, and repeated with ``*``:: - >>> word = 'Help' + 'A' - >>> word - 'HelpA' - >>> '<' + word*5 + '>' - '' + >>> # 3 times 'un', followed by 'ium' + >>> 3 * 'un' + 'ium' + 'unununium' -Two string literals next to each other are automatically concatenated; the first -line above could also have been written ``word = 'Help' 'A'``; this only works -with two literals, not with arbitrary string expressions:: +Two or more *string literals* (i.e. the ones enclosed between quotes) next +to each other are automatically concatenated. :: - >>> 'str' 'ing' # <- This is ok - 'string' - >>> 'str'.strip() + 'ing' # <- This is ok - 'string' - >>> 'str'.strip() 'ing' # <- This is invalid - File "", line 1, in ? - 'str'.strip() 'ing' - ^ + >>> 'Py' 'thon' + 'Python' + +This only works with two literals though, not with variables or expressions:: + + >>> prefix = 'Py' + >>> prefix 'thon' # can't concatenate a variable and a string literal + ... + SyntaxError: invalid syntax + >>> ('un' * 3) 'ium' + ... SyntaxError: invalid syntax -Strings can be subscripted (indexed); like in C, the first character of a string -has subscript (index) 0. There is no separate character type; a character is -simply a string of size one. As in the Icon programming language, substrings -can be specified with the *slice notation*: two indices separated by a colon. -:: +If you want to concatenate variables or a variable and a literal, use ``+``:: - >>> word[4] - 'A' - >>> word[0:2] - 'He' - >>> word[2:4] - 'lp' + >>> prefix + 'thon' + 'Python' + +This feature is particularly useful when you want to break long strings:: + + >>> text = ('Put several strings within parentheses ' + 'to have them joined together.') + >>> text + 'Put several strings within parentheses to have them joined together.' + +Strings can be *indexed* (subscripted), with the first character having index 0. +There is no separate character type; a character is simply a string of size +one:: + + >>> word = 'Python' + >>> word[0] # character in position 0 + 'P' + >>> word[5] # character in position 5 + 'n' + +Indices may also be negative numbers, to start counting from the right:: + + >>> word[-1] # last character + 'n' + >>> word[-2] # second-last character + 'o' + >>> word[-6] + 'P' + +Note that since -0 is the same as 0, negative indices start from -1. + +In addition to indexing, *slicing* is also supported. While indexing is used +to obtain individual characters, *slicing* allows you to obtain substring:: + + >>> word[0:2] # characters from position 0 (included) to 2 (excluded) + 'Py' + >>> word[2:5] # characters from position 2 (included) to 4 (excluded) + 'tho' + +Note how the start is always included, and the end always excluded. This +makes sure that ``s[:i] + s[i:]`` is always equal to ``s``:: + + >>> word[:2] + word[2:] + 'Python' + >>> word[:4] + word[4:] + 'Python' Slice indices have useful defaults; an omitted first index defaults to zero, an omitted second index defaults to the size of the string being sliced. :: - >>> word[:2] # The first two characters - 'He' - >>> word[2:] # Everything except the first two characters - 'lpA' - -Unlike a C string, Python strings cannot be changed. Assigning to an indexed -position in the string results in an error:: - - >>> word[0] = 'x' - Traceback (most recent call last): - File "", line 1, in ? - TypeError: 'str' object does not support item assignment - >>> word[:1] = 'Splat' - Traceback (most recent call last): - File "", line 1, in ? - TypeError: 'str' object does not support slice assignment - -However, creating a new string with the combined content is easy and efficient:: - - >>> 'x' + word[1:] - 'xelpA' - >>> 'Splat' + word[4] - 'SplatA' - -Here's a useful invariant of slice operations: ``s[:i] + s[i:]`` equals ``s``. -:: - - >>> word[:2] + word[2:] - 'HelpA' - >>> word[:3] + word[3:] - 'HelpA' - -Degenerate slice indices are handled gracefully: an index that is too large is -replaced by the string size, an upper bound smaller than the lower bound returns -an empty string. :: - - >>> word[1:100] - 'elpA' - >>> word[10:] - '' - >>> word[2:1] - '' - -Indices may be negative numbers, to start counting from the right. For example:: - - >>> word[-1] # The last character - 'A' - >>> word[-2] # The last-but-one character - 'p' - >>> word[-2:] # The last two characters - 'pA' - >>> word[:-2] # Everything except the last two characters - 'Hel' - -But note that -0 is really the same as 0, so it does not count from the right! -:: - - >>> word[-0] # (since -0 equals 0) - 'H' - -Out-of-range negative slice indices are truncated, but don't try this for -single-element (non-slice) indices:: - - >>> word[-100:] - 'HelpA' - >>> word[-10] # error - Traceback (most recent call last): - File "", line 1, in ? - IndexError: string index out of range + >>> word[:2] # character from the beginning to position 2 (excluded) + 'Py' + >>> word[4:] # characters from position 4 (included) to the end + 'on' + >>> word[-2:] # characters from the second-last (included) to the end + 'on' One way to remember how slices work is to think of the indices as pointing *between* characters, with the left edge of the first character numbered 0. Then the right edge of the last character of a string of *n* characters has index *n*, for example:: - +---+---+---+---+---+ - | H | e | l | p | A | - +---+---+---+---+---+ - 0 1 2 3 4 5 - -5 -4 -3 -2 -1 + +---+---+---+---+---+---+ + | P | y | t | h | o | n | + +---+---+---+---+---+---+ + 0 1 2 3 4 5 6 + -6 -5 -4 -3 -2 -1 -The first row of numbers gives the position of the indices 0...5 in the string; +The first row of numbers gives the position of the indices 0...6 in the string; the second row gives the corresponding negative indices. The slice from *i* to *j* consists of all characters between the edges labeled *i* and *j*, respectively. @@ -381,6 +303,38 @@ indices, if both are within bounds. For example, the length of ``word[1:3]`` is 2. +Attempting to use a index that is too large will result in an error:: + + >>> word[42] # the word only has 7 characters + Traceback (most recent call last): + File "", line 1, in + IndexError: string index out of range + +However, out of range slice indexes are handled gracefully when used for +slicing:: + + >>> word[4:42] + 'on' + >>> word[42:] + '' + +Python strings cannot be changed --- they are :term:`immutable`. +Therefore, assigning to an indexed position in the string results in an error:: + + >>> word[0] = 'J' + ... + TypeError: 'str' object does not support item assignment + >>> word[2:] = 'py' + ... + TypeError: 'str' object does not support item assignment + +If you need a different string, you should create a new one:: + + >>> 'J' + word[1:] + 'Jython' + >>> word[:2] + 'py' + 'Pypy' + The built-in function :func:`len` returns the length of a string:: >>> s = 'supercalifragilisticexpialidocious' @@ -407,51 +361,6 @@ the left operand of the ``%`` operator are described in more detail here. -.. _tut-unicodestrings: - -About Unicode -------------- - -.. sectionauthor:: Marc-Andr? Lemburg - - -Starting with Python 3.0 all strings support Unicode (see -http://www.unicode.org/). - -Unicode has the advantage of providing one ordinal for every character in every -script used in modern and ancient texts. Previously, there were only 256 -possible ordinals for script characters. Texts were typically bound to a code -page which mapped the ordinals to script characters. This lead to very much -confusion especially with respect to internationalization (usually written as -``i18n`` --- ``'i'`` + 18 characters + ``'n'``) of software. Unicode solves -these problems by defining one code page for all scripts. - -If you want to include special characters in a string, -you can do so by using the Python *Unicode-Escape* encoding. The following -example shows how:: - - >>> 'Hello\u0020World !' - 'Hello World !' - -The escape sequence ``\u0020`` indicates to insert the Unicode character with -the ordinal value 0x0020 (the space character) at the given position. - -Other characters are interpreted by using their respective ordinal values -directly as Unicode ordinals. If you have literal strings in the standard -Latin-1 encoding that is used in many Western countries, you will find it -convenient that the lower 256 characters of Unicode are the same as the 256 -characters of Latin-1. - -Apart from these standard encodings, Python provides a whole set of other ways -of creating Unicode strings on the basis of a known encoding. - -To convert a string into a sequence of bytes using a specific encoding, -string objects provide an :func:`encode` method that takes one argument, the -name of the encoding. Lowercase names for encodings are preferred. :: - - >>> "?pfel".encode('utf-8') - b'\xc3\x84pfel' - .. _tut-lists: Lists @@ -459,97 +368,89 @@ Python knows a number of *compound* data types, used to group together other values. The most versatile is the *list*, which can be written as a list of -comma-separated values (items) between square brackets. List items need not all -have the same type. :: +comma-separated values (items) between square brackets. Lists might contain +items of different types, but usually the items all have the same type. :: - >>> a = ['spam', 'eggs', 100, 1234] - >>> a - ['spam', 'eggs', 100, 1234] + >>> squares = [1, 2, 4, 9, 16, 25] + >>> squares + [1, 2, 4, 9, 16, 25] -Like string indices, list indices start at 0, and lists can be sliced, -concatenated and so on:: +Like strings (and all other built-in :term:`sequence` type), lists can be +indexed and sliced:: - >>> a[0] - 'spam' - >>> a[3] - 1234 - >>> a[-2] - 100 - >>> a[1:-1] - ['eggs', 100] - >>> a[:2] + ['bacon', 2*2] - ['spam', 'eggs', 'bacon', 4] - >>> 3*a[:3] + ['Boo!'] - ['spam', 'eggs', 100, 'spam', 'eggs', 100, 'spam', 'eggs', 100, 'Boo!'] + >>> squares[0] # indexing returns the item + 1 + >>> squares[-1] + 25 + >>> squares[-3:] # slicing returns a new list + [9, 16, 25] All slice operations return a new list containing the requested elements. This -means that the following slice returns a shallow copy of the list *a*:: +means that the following slice returns a new (shallow) copy of the list:: - >>> a[:] - ['spam', 'eggs', 100, 1234] + >>> squares[:] + [1, 2, 4, 9, 16, 25] -Unlike strings, which are *immutable*, it is possible to change individual -elements of a list:: +Lists also supports operations like concatenation:: - >>> a - ['spam', 'eggs', 100, 1234] - >>> a[2] = a[2] + 23 - >>> a - ['spam', 'eggs', 123, 1234] + >>> squares + [36, 49, 64, 81, 100] + [1, 2, 4, 9, 16, 25, 36, 49, 64, 81, 100] + +Unlike strings, which are :term:`immutable`, lists are a :term:`mutable` +type, i.e. it is possible to change their content:: + + >>> cubes = [1, 8, 27, 65, 125] # something's wrong here + >>> 4 ** 3 # the cube of 4 is 64, not 65! + 64 + >>> cubes[3] = 64 # replace the wrong value + >>> cubes + [1, 8, 27, 64, 125] + +You can also add new items at the end of the list, by using +the :meth:`~list.append` *method* (we will see more about methods later):: + + >>> cubes.append(216) # add the cube of 6 + >>> cubes.append(7 ** 3) # and the cube of 7 + >>> cubes + [1, 8, 27, 64, 125, 216, 343] Assignment to slices is also possible, and this can even change the size of the list or clear it entirely:: - >>> # Replace some items: - ... a[0:2] = [1, 12] - >>> a - [1, 12, 123, 1234] - >>> # Remove some: - ... a[0:2] = [] - >>> a - [123, 1234] - >>> # Insert some: - ... a[1:1] = ['bletch', 'xyzzy'] - >>> a - [123, 'bletch', 'xyzzy', 1234] - >>> # Insert (a copy of) itself at the beginning - >>> a[:0] = a - >>> a - [123, 'bletch', 'xyzzy', 1234, 123, 'bletch', 'xyzzy', 1234] - >>> # Clear the list: replace all items with an empty list - >>> a[:] = [] - >>> a + >>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] + >>> letters + ['a', 'b', 'c', 'd', 'e', 'f', 'g'] + >>> # replace some values + >>> letters[2:5] = ['C', 'D', 'E'] + >>> letters + ['a', 'b', 'C', 'D', 'E', 'f', 'g'] + >>> # now remove them + >>> letters[2:5] = [] + >>> letters + ['a', 'b', 'f', 'g'] + >>> # clear the list by replacing all the elements with an empty list + >>> letters[:] = [] + >>> letters [] The built-in function :func:`len` also applies to lists:: - >>> a = ['a', 'b', 'c', 'd'] - >>> len(a) + >>> letters = ['a', 'b', 'c', 'd'] + >>> len(letters) 4 It is possible to nest lists (create lists containing other lists), for example:: - >>> q = [2, 3] - >>> p = [1, q, 4] - >>> len(p) - 3 - >>> p[1] - [2, 3] - >>> p[1][0] - 2 - -You can add something to the end of the list:: - - >>> p[1].append('xtra') - >>> p - [1, [2, 3, 'xtra'], 4] - >>> q - [2, 3, 'xtra'] - -Note that in the last example, ``p[1]`` and ``q`` really refer to the same -object! We'll come back to *object semantics* later. - + >>> a = ['a', 'b', 'c'] + >>> n = [1, 2, 3] + >>> x = [a, n] + >>> x + [['a', 'b', 'c'], [1, 2, 3]] + >>> p[0] + ['a', 'b', 'c'] + >>> p[0][1] + 'b' .. _tut-firststeps: @@ -620,3 +521,15 @@ ... a, b = b, a+b ... 1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987, + + +.. rubric:: Footnotes + +.. [#] Since ``**`` has higher precedence than ``-``, ``-3**2`` will be + interpreted as ``-(3**2)`` and thus result in ``-9``. To avoid this + and get ``9``, you can use ``(-3)**2``. + +.. [#] Unlike other languages, special characters such as ``\n`` have the + same meaning with both single (``'...'``) and double (``"..."``) quotes. + The only difference between the two is that within single quotes you don't + need to escape ``"`` (but you have to escape ``\'``) and vice versa. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -323,6 +323,8 @@ Documentation ------------- +- Issue #14097: improve the "introduction" page of the tutorial. + - Issue #17977: The documentation for the cadefault argument's default value in urllib.request.urlopen() is fixed to match the code. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 14:41:54 2013 From: python-checkins at python.org (charles-francois.natali) Date: Mon, 20 May 2013 14:41:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2317914=3A_Add_os?= =?utf-8?q?=2Ecpu=5Fcount=28=29=2E_Patch_by_Yogesh_Chaudhari=2C_based_on_a?= =?utf-8?q?n?= Message-ID: <3bDfr230m1z7Lm3@mail.python.org> http://hg.python.org/cpython/rev/5e0c56557390 changeset: 83858:5e0c56557390 user: Charles-Francois Natali date: Mon May 20 14:40:46 2013 +0200 summary: Issue #17914: Add os.cpu_count(). Patch by Yogesh Chaudhari, based on an initial patch by Trent Nelson. files: Doc/library/multiprocessing.rst | 3 + Doc/library/os.rst | 11 ++- Lib/multiprocessing/__init__.py | 25 +------ Lib/test/test_os.py | 10 +++ Misc/NEWS | 3 + Modules/posixmodule.c | 68 +++++++++++++++++++++ 6 files changed, 94 insertions(+), 26 deletions(-) diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -702,6 +702,9 @@ Return the number of CPUs in the system. May raise :exc:`NotImplementedError`. + .. seealso:: + :func:`os.cpu_count` + .. function:: current_process() Return the :class:`Process` object corresponding to the current process. diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -3155,10 +3155,6 @@ Return the set of CPUs the process with PID *pid* (or the current process if zero) is restricted to. - .. seealso:: - :func:`multiprocessing.cpu_count` returns the number of CPUs in the - system. - .. _os-path: @@ -3196,6 +3192,13 @@ Availability: Unix. +.. function:: cpu_count() + + Return the number of CPUs in the system. Returns None if undetermined. + + .. versionadded:: 3.4 + + .. function:: getloadavg() Return the number of processes in the system run queue averaged over the last diff --git a/Lib/multiprocessing/__init__.py b/Lib/multiprocessing/__init__.py --- a/Lib/multiprocessing/__init__.py +++ b/Lib/multiprocessing/__init__.py @@ -85,30 +85,11 @@ ''' Returns the number of CPUs in the system ''' - if sys.platform == 'win32': - try: - num = int(os.environ['NUMBER_OF_PROCESSORS']) - except (ValueError, KeyError): - num = 0 - elif 'bsd' in sys.platform or sys.platform == 'darwin': - comm = '/sbin/sysctl -n hw.ncpu' - if sys.platform == 'darwin': - comm = '/usr' + comm - try: - with os.popen(comm) as p: - num = int(p.read()) - except ValueError: - num = 0 + num = os.cpu_count() + if num is None: + raise NotImplementedError('cannot determine number of cpus') else: - try: - num = os.sysconf('SC_NPROCESSORS_ONLN') - except (ValueError, OSError, AttributeError): - num = 0 - - if num >= 1: return num - else: - raise NotImplementedError('cannot determine number of cpus') def freeze_support(): ''' diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -2216,6 +2216,15 @@ else: self.fail("No exception thrown by {}".format(func)) +class CPUCountTests(unittest.TestCase): + def test_cpu_count(self): + cpus = os.cpu_count() + if cpus is not None: + self.assertIsInstance(cpus, int) + self.assertGreater(cpus, 0) + else: + self.skipTest("Could not determine the number of CPUs") + @support.reap_threads def test_main(): support.run_unittest( @@ -2246,6 +2255,7 @@ TermsizeTests, OSErrorTests, RemoveDirsTests, + CPUCountTests, ) if __name__ == "__main__": diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -99,6 +99,9 @@ Library ------- +- Issue #17914: Add os.cpu_count(). Patch by Yogesh Chaudhari, based on an + initial patch by Trent Nelson. + - Issue #17980: Fix possible abuse of ssl.match_hostname() for denial of service using certificates with many wildcards (CVE-2013-2099). diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -113,6 +113,18 @@ #include #endif +#ifdef __hpux +#include +#endif + +#if defined(__DragonFly__) || \ + defined(__OpenBSD__) || \ + defined(__FreeBSD__) || \ + defined(__NetBSD__) || \ + defined(__APPLE__) +#include +#endif + #if defined(MS_WINDOWS) # define TERMSIZE_USE_CONIO #elif defined(HAVE_SYS_IOCTL_H) @@ -10302,6 +10314,60 @@ } #endif /* defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL) */ +PyDoc_STRVAR(posix_cpu_count__doc__, +"cpu_count() -> integer\n\n\ +Return the number of CPUs in the system, or None if this value cannot be\n\ +established."); + +#if defined(__DragonFly__) || \ + defined(__OpenBSD__) || \ + defined(__FreeBSD__) || \ + defined(__NetBSD__) || \ + defined(__APPLE__) +static long +_bsd_cpu_count(void) +{ + long ncpu = 0; + int mib[2]; + size_t len = sizeof(int); + + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == 0) + return ncpu; + else + return 0; +} +#endif + +static PyObject * +posix_cpu_count(PyObject *self) +{ + long ncpu = 0; +#ifdef MS_WINDOWS + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + ncpu = sysinfo.dwNumberOfProcessors; +#elif defined(__hpux) + ncpu = mpctl(MPC_GETNUMSPUS, NULL, NULL); +#elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN) + ncpu = sysconf(_SC_NPROCESSORS_ONLN); +#elif defined(__APPLE__) + size_t len = sizeof(int); + if (sysctlnametomib("hw.logicalcpu", &ncpu, &len, NULL, 0) != 0) + ncpu = _bsd_cpu_count(); +#elif defined(__DragonFly__) || \ + defined(__OpenBSD__) || \ + defined(__FreeBSD__) || \ + defined(__NetBSD__) + ncpu = _bsd_cpu_count(); +#endif + if (ncpu >= 1) + return PyLong_FromLong(ncpu); + else + Py_RETURN_NONE; +} + static PyMethodDef posix_methods[] = { {"access", (PyCFunction)posix_access, @@ -10747,6 +10813,8 @@ #if defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL) {"get_terminal_size", get_terminal_size, METH_VARARGS, termsize__doc__}, #endif + {"cpu_count", (PyCFunction)posix_cpu_count, + METH_NOARGS, posix_cpu_count__doc__}, {NULL, NULL} /* Sentinel */ }; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 16:15:22 2013 From: python-checkins at python.org (andrew.kuchling) Date: Mon, 20 May 2013 16:15:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_=2317955=3A_minor_updates_?= =?utf-8?q?to_Functional_howto?= Message-ID: <3bDhvt25XYz7LkD@mail.python.org> http://hg.python.org/cpython/rev/20409786cf8e changeset: 83859:20409786cf8e user: Andrew Kuchling date: Mon May 20 10:14:53 2013 -0400 summary: #17955: minor updates to Functional howto * Describe compress() and accumulate() * Add a subsection on combinatoric functions. * Add a forward link to skip the theoretical discussion in the first section. * Clarify what filterfalse() is the opposite of. * Remove the old outline and some notes at the end. * Various small edits. files: Doc/howto/functional.rst | 144 +++++++++++++++++--------- 1 files changed, 91 insertions(+), 53 deletions(-) diff --git a/Doc/howto/functional.rst b/Doc/howto/functional.rst --- a/Doc/howto/functional.rst +++ b/Doc/howto/functional.rst @@ -3,7 +3,7 @@ ******************************** :Author: A. M. Kuchling -:Release: 0.31 +:Release: 0.32 In this document, we'll take a tour of Python's features suitable for implementing programs in a functional style. After an introduction to the @@ -15,9 +15,9 @@ Introduction ============ -This section explains the basic concept of functional programming; if you're -just interested in learning about Python language features, skip to the next -section. +This section explains the basic concept of functional programming; if +you're just interested in learning about Python language features, +skip to the next section on :ref:`functional-howto-iterators`. Programming languages support decomposing problems in several different ways: @@ -173,6 +173,8 @@ a few functions specialized for the current task. +.. _functional-howto-iterators: + Iterators ========= @@ -670,7 +672,7 @@ :func:`sorted(iterable, key=None, reverse=False) ` collects all the elements of the iterable into a list, sorts the list, and returns the sorted -result. The *key*, and *reverse* arguments are passed through to the +result. The *key* and *reverse* arguments are passed through to the constructed list's :meth:`~list.sort` method. :: >>> import random @@ -836,7 +838,8 @@ predicate. :func:`itertools.filterfalse(predicate, iter) ` is the -opposite, returning all elements for which the predicate returns false:: +opposite of :func:`filter`, returning all elements for which the predicate +returns false:: itertools.filterfalse(is_even, itertools.count()) => 1, 3, 5, 7, 9, 11, 13, 15, ... @@ -864,6 +867,77 @@ itertools.dropwhile(is_even, itertools.count()) => 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ... +:func:`itertools.compress(data, selectors) ` takes two +iterators and returns only those elements of *data* for which the corresponding +element of *selectors* is true, stopping whenever either one is exhausted:: + + itertools.compress([1,2,3,4,5], [True, True, False, False, True]) => + 1, 2, 5 + + +Combinatoric functions +---------------------- + +The :func:`itertools.combinations(iterable, r) ` +returns an iterator giving all possible *r*-tuple combinations of the +elements contained in *iterable*. :: + + itertools.combinations([1, 2, 3, 4, 5], 2) => + (1, 2), (1, 3), (1, 4), (1, 5), + (2, 3), (2, 4), (2, 5), + (3, 4), (3, 5), + (4, 5) + + itertools.combinations([1, 2, 3, 4, 5], 3) => + (1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5), (1, 4, 5), + (2, 3, 4), (2, 3, 5), (2, 4, 5), + (3, 4, 5) + +The elements within each tuple remain in the same order as +*iterable* returned them. For example, the number 1 is always before +2, 3, 4, or 5 in the examples above. A similar function, +:func:`itertools.permutations(iterable, r=None) `, +removes this constraint on the order, returning all possible +arrangements of length *r*:: + + itertools.permutations([1, 2, 3, 4, 5], 2) => + (1, 2), (1, 3), (1, 4), (1, 5), + (2, 1), (2, 3), (2, 4), (2, 5), + (3, 1), (3, 2), (3, 4), (3, 5), + (4, 1), (4, 2), (4, 3), (4, 5), + (5, 1), (5, 2), (5, 3), (5, 4) + + itertools.permutations([1, 2, 3, 4, 5]) => + (1, 2, 3, 4, 5), (1, 2, 3, 5, 4), (1, 2, 4, 3, 5), + ... + (5, 4, 3, 2, 1) + +If you don't supply a value for *r* the length of the iterable is used, +meaning that all the elements are permuted. + +Note that these functions produce all of the possible combinations by +position and don't require that the contents of *iterable* are unique:: + + itertools.permutations('aba', 3) => + ('a', 'b', 'a'), ('a', 'a', 'b'), ('b', 'a', 'a'), + ('b', 'a', 'a'), ('a', 'a', 'b'), ('a', 'b', 'a') + +The identical tuple ``('a', 'a', 'b')`` occurs twice, but the two 'a' +strings came from different positions. + +The :func:`itertools.combinations_with_replacement(iterable, r) ` +function relaxes a different constraint: elements can be repeated +within a single tuple. Conceptually an element is selected for the +first position of each tuple and then is replaced before the second +element is selected. :: + + itertools.combinations_with_replacement([1, 2, 3, 4, 5], 2) => + (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), + (2, 2), (2, 3), (2, 4), (2, 5), + (3, 3), (3, 4), (3, 5), + (4, 4), (4, 5), + (5, 5) + Grouping elements ----------------- @@ -986,6 +1060,17 @@ for i in [1,2,3]: product *= i +A related function is `itertools.accumulate(iterable, func=operator.add) + 1, 3, 6, 10, 15 + + itertools.accumulate([1,2,3,4,5], operator.mul) => + 1, 2, 6, 24, 120 + The operator module ------------------- @@ -1159,51 +1244,6 @@ .. comment - Topics to place - ----------------------------- - - XXX os.walk() - - XXX Need a large example. - - But will an example add much? I'll post a first draft and see - what the comments say. - -.. comment - - Original outline: - Introduction - Idea of FP - Programs built out of functions - Functions are strictly input-output, no internal state - Opposed to OO programming, where objects have state - - Why FP? - Formal provability - Assignment is difficult to reason about - Not very relevant to Python - Modularity - Small functions that do one thing - Debuggability: - Easy to test due to lack of state - Easy to verify output from intermediate steps - Composability - You assemble a toolbox of functions that can be mixed - - Tackling a problem - Need a significant example - - Iterators - Generators - The itertools module - List comprehensions - Small functions and the lambda statement - Built-in functions - map - filter - -.. comment - Handy little function for printing part of an iterator -- used while writing this document. @@ -1214,5 +1254,3 @@ sys.stdout.write(str(elem)) sys.stdout.write(', ') print(elem[-1]) - - -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 16:35:17 2013 From: python-checkins at python.org (r.david.murray) Date: Mon, 20 May 2013 16:35:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE3OTczOiBBZGQg?= =?utf-8?b?RkFRIGVudHJ5IGZvciAoW10sKVswXSArPSBbMV0gYm90aCBleHRlbmRpbmcg?= =?utf-8?q?and_raising=2E?= Message-ID: <3bDjLs4fyNz7Lkh@mail.python.org> http://hg.python.org/cpython/rev/b363473cfe9c changeset: 83860:b363473cfe9c branch: 3.3 parent: 83856:796d1371605d user: R David Murray date: Mon May 20 10:32:46 2013 -0400 summary: #17973: Add FAQ entry for ([],)[0] += [1] both extending and raising. This has come up often enough now on the tracker that it deserves a FAQ entry. files: Doc/faq/programming.rst | 83 +++++++++++++++++++++++++++++ 1 files changed, 83 insertions(+), 0 deletions(-) diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -1103,6 +1103,89 @@ result = [obj.method() for obj in mylist] +Why does a_tuple[i] += ['item'] raise an exception when the addition works? +--------------------------------------------------------------------------- + +This is because of a combination of the fact that augmented assignment +operators are *assignment* operators, and the difference between mutable and +immutable objects in Python. + +This discussion applies in general when augmented assignment operators are +applied to elements of a tuple that point to mutable objects, but we'll use +a ``list`` and ``+=`` as our exemplar. + +If you wrote:: + + >>> a_tuple = (1, 2) + >>> a_tuple[0] += 1 + Traceback (most recent call last): + ... + TypeError: 'tuple' object does not support item assignment + +The reason for the exception should be immediately clear: ``1`` is added to the +object ``a_tuple[0]`` points to (``1``), producing the result object, ``2``, +but when we attempt to assign the result of the computation, ``2``, to element +``0`` of the tuple, we get an error because we can't change what an element of +a tuple points to. + +Under the covers, what this augmented assignment statement is doing is +approximately this:: + + >>> result = a_tuple[0].__iadd__(1) + >>> a_tuple[0] = result + Traceback (most recent call last): + ... + TypeError: 'tuple' object does not support item assignment + +It is the assignment part of the operation that produces the error, since a +tuple is immutable. + +When you write something like:: + + >>> a_tuple = (['foo'], 'bar') + >>> a_tuple[0] += ['item'] + Traceback (most recent call last): + ... + TypeError: 'tuple' object does not support item assignment + +The exception is a bit more surprising, and even more surprising is the fact +that even though there was an error, the append worked:: + + >>> a_tuple[0] + ['foo', 'item'] + +To see why this happens, you need to know that for lists, ``__iadd__`` is equivalent +to calling ``extend`` on the list and returning the list. That's why we say +that for lists, ``+=`` is a "shorthand" for ``list.extend``:: + + >>> a_list = [] + >>> a_list += [1] + >>> a_list + [1] + +is equivalent to:: + + >>> result = a_list.__iadd__([1]) + >>> a_list = result + +The object pointed to by a_list has been mutated, and the pointer to the +mutated object is assigned back to ``a_list``. The end result of the +assignment is a no-op, since it is a pointer to the same object that ``a_list`` +was previously pointing to, but the assignment still happens. + +Thus, in our tuple example what is happening is equivalent to:: + + >>> result = a_tuple[0].__iadd__(['item']) + >>> a_tuple[0] = result + Traceback (most recent call last): + ... + TypeError: 'tuple' object does not support item assignment + +The ``__iadd__`` succeeds, and thus the list is extended, but even though +``result`` points to the same object that ``a_tuple[0]`` already points to, +that final assignment still results in an error, because tuples are immutable. + + Dictionaries ============ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 16:35:18 2013 From: python-checkins at python.org (r.david.murray) Date: Mon, 20 May 2013 16:35:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgIzE3OTczOiBBZGQgRkFRIGVudHJ5IGZvciAoW10sKVswXSAr?= =?utf-8?q?=3D_=5B1=5D_both_extending_and_raising=2E?= Message-ID: <3bDjLt6yrqz7LnQ@mail.python.org> http://hg.python.org/cpython/rev/6d2f0edb0758 changeset: 83861:6d2f0edb0758 parent: 83859:20409786cf8e parent: 83860:b363473cfe9c user: R David Murray date: Mon May 20 10:33:27 2013 -0400 summary: Merge #17973: Add FAQ entry for ([],)[0] += [1] both extending and raising. files: Doc/faq/programming.rst | 83 +++++++++++++++++++++++++++++ 1 files changed, 83 insertions(+), 0 deletions(-) diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -1103,6 +1103,89 @@ result = [obj.method() for obj in mylist] +Why does a_tuple[i] += ['item'] raise an exception when the addition works? +--------------------------------------------------------------------------- + +This is because of a combination of the fact that augmented assignment +operators are *assignment* operators, and the difference between mutable and +immutable objects in Python. + +This discussion applies in general when augmented assignment operators are +applied to elements of a tuple that point to mutable objects, but we'll use +a ``list`` and ``+=`` as our exemplar. + +If you wrote:: + + >>> a_tuple = (1, 2) + >>> a_tuple[0] += 1 + Traceback (most recent call last): + ... + TypeError: 'tuple' object does not support item assignment + +The reason for the exception should be immediately clear: ``1`` is added to the +object ``a_tuple[0]`` points to (``1``), producing the result object, ``2``, +but when we attempt to assign the result of the computation, ``2``, to element +``0`` of the tuple, we get an error because we can't change what an element of +a tuple points to. + +Under the covers, what this augmented assignment statement is doing is +approximately this:: + + >>> result = a_tuple[0].__iadd__(1) + >>> a_tuple[0] = result + Traceback (most recent call last): + ... + TypeError: 'tuple' object does not support item assignment + +It is the assignment part of the operation that produces the error, since a +tuple is immutable. + +When you write something like:: + + >>> a_tuple = (['foo'], 'bar') + >>> a_tuple[0] += ['item'] + Traceback (most recent call last): + ... + TypeError: 'tuple' object does not support item assignment + +The exception is a bit more surprising, and even more surprising is the fact +that even though there was an error, the append worked:: + + >>> a_tuple[0] + ['foo', 'item'] + +To see why this happens, you need to know that for lists, ``__iadd__`` is equivalent +to calling ``extend`` on the list and returning the list. That's why we say +that for lists, ``+=`` is a "shorthand" for ``list.extend``:: + + >>> a_list = [] + >>> a_list += [1] + >>> a_list + [1] + +is equivalent to:: + + >>> result = a_list.__iadd__([1]) + >>> a_list = result + +The object pointed to by a_list has been mutated, and the pointer to the +mutated object is assigned back to ``a_list``. The end result of the +assignment is a no-op, since it is a pointer to the same object that ``a_list`` +was previously pointing to, but the assignment still happens. + +Thus, in our tuple example what is happening is equivalent to:: + + >>> result = a_tuple[0].__iadd__(['item']) + >>> a_tuple[0] = result + Traceback (most recent call last): + ... + TypeError: 'tuple' object does not support item assignment + +The ``__iadd__`` succeeds, and thus the list is extended, but even though +``result`` points to the same object that ``a_tuple[0]`` already points to, +that final assignment still results in an error, because tuples are immutable. + + Dictionaries ============ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 16:35:20 2013 From: python-checkins at python.org (r.david.murray) Date: Mon, 20 May 2013 16:35:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE3OTczOiBBZGQg?= =?utf-8?b?RkFRIGVudHJ5IGZvciAoW10sKVswXSArPSBbMV0gYm90aCBleHRlbmRpbmcg?= =?utf-8?q?and_raising=2E?= Message-ID: <3bDjLw26RGz7Lms@mail.python.org> http://hg.python.org/cpython/rev/8edfe539d4c6 changeset: 83862:8edfe539d4c6 branch: 2.7 parent: 83853:3568f8f1ccac user: R David Murray date: Mon May 20 10:34:58 2013 -0400 summary: #17973: Add FAQ entry for ([],)[0] += [1] both extending and raising. This has come up often enough now on the tracker that it deserves a FAQ entry. files: Doc/faq/programming.rst | 83 +++++++++++++++++++++++++++++ 1 files changed, 83 insertions(+), 0 deletions(-) diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -1223,6 +1223,89 @@ return map(apply, methods, [arguments]*nobjects) +Why does a_tuple[i] += ['item'] raise an exception when the addition works? +--------------------------------------------------------------------------- + +This is because of a combination of the fact that augmented assignment +operators are *assignment* operators, and the difference between mutable and +immutable objects in Python. + +This discussion applies in general when augmented assignment operators are +applied to elements of a tuple that point to mutable objects, but we'll use +a ``list`` and ``+=`` as our exemplar. + +If you wrote:: + + >>> a_tuple = (1, 2) + >>> a_tuple[0] += 1 + Traceback (most recent call last): + ... + TypeError: 'tuple' object does not support item assignment + +The reason for the exception should be immediately clear: ``1`` is added to the +object ``a_tuple[0]`` points to (``1``), producing the result object, ``2``, +but when we attempt to assign the result of the computation, ``2``, to element +``0`` of the tuple, we get an error because we can't change what an element of +a tuple points to. + +Under the covers, what this augmented assignment statement is doing is +approximately this:: + + >>> result = a_tuple[0].__iadd__(1) + >>> a_tuple[0] = result + Traceback (most recent call last): + ... + TypeError: 'tuple' object does not support item assignment + +It is the assignment part of the operation that produces the error, since a +tuple is immutable. + +When you write something like:: + + >>> a_tuple = (['foo'], 'bar') + >>> a_tuple[0] += ['item'] + Traceback (most recent call last): + ... + TypeError: 'tuple' object does not support item assignment + +The exception is a bit more surprising, and even more surprising is the fact +that even though there was an error, the append worked:: + + >>> a_tuple[0] + ['foo', 'item'] + +To see why this happens, you need to know that for lists, ``__iadd__`` is equivalent +to calling ``extend`` on the list and returning the list. That's why we say +that for lists, ``+=`` is a "shorthand" for ``list.extend``:: + + >>> a_list = [] + >>> a_list += [1] + >>> a_list + [1] + +is equivalent to:: + + >>> result = a_list.__iadd__([1]) + >>> a_list = result + +The object pointed to by a_list has been mutated, and the pointer to the +mutated object is assigned back to ``a_list``. The end result of the +assignment is a no-op, since it is a pointer to the same object that ``a_list`` +was previously pointing to, but the assignment still happens. + +Thus, in our tuple example what is happening is equivalent to:: + + >>> result = a_tuple[0].__iadd__(['item']) + >>> a_tuple[0] = result + Traceback (most recent call last): + ... + TypeError: 'tuple' object does not support item assignment + +The ``__iadd__`` succeeds, and thus the list is extended, but even though +``result`` points to the same object that ``a_tuple[0]`` already points to, +that final assignment still results in an error, because tuples are immutable. + + Dictionaries ============ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 17:23:57 2013 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 20 May 2013 17:23:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_test_that_the_compiler_sup?= =?utf-8?q?port_-Werror=3Dstatement-after-declaration_before_using?= Message-ID: <3bDkR15pxVz7Lkh@mail.python.org> http://hg.python.org/cpython/rev/e47806951fb2 changeset: 83863:e47806951fb2 parent: 83861:6d2f0edb0758 user: Benjamin Peterson date: Mon May 20 08:22:04 2013 -0700 summary: test that the compiler support -Werror=statement-after-declaration before using it files: configure | 45 ++++++++++++++++++++++++++++++++++++++- configure.ac | 24 +++++++++++++++++++- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/configure b/configure --- a/configure +++ b/configure @@ -6264,8 +6264,6 @@ # tweak BASECFLAGS based on compiler and platform case $GCC in yes) - BASECFLAGS="$BASECFLAGS -Werror=declaration-after-statement" - # Python doesn't violate C99 aliasing rules, but older versions of # GCC produce warnings for legal Python code. Enable # -fno-strict-aliasing on versions of GCC that support but produce @@ -6379,6 +6377,49 @@ BASECFLAGS="$BASECFLAGS -Wno-unused-result" fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -Werror=declaration-after-statement" >&5 +$as_echo_n "checking for -Werror=declaration-after-statement... " >&6; } + ac_save_cc="$CC" + CC="$CC -Werror=declaration-after-statement" + save_CFLAGS="$CFLAGS" + if ${ac_cv_declaration_after_statement_warning+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +int +main () +{ + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + ac_cv_declaration_after_statement_warning=yes + +else + + ac_cv_declaration_after_statement_warning=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + CFLAGS="$save_CFLAGS" + CC="$ac_save_cc" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_declaration_after_statement_warning" >&5 +$as_echo "$ac_cv_declaration_after_statement_warning" >&6; } + + if test $ac_cv_declaration_after_statement_warning = yes + then + BASECFLAGS="$BASECFLAGS -Werror=declaration-after-statement" + fi + # if using gcc on alpha, use -mieee to get (near) full IEEE 754 # support. Without this, treatment of subnormals doesn't follow # the standard. diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -1127,8 +1127,6 @@ # tweak BASECFLAGS based on compiler and platform case $GCC in yes) - BASECFLAGS="$BASECFLAGS -Werror=declaration-after-statement" - # Python doesn't violate C99 aliasing rules, but older versions of # GCC produce warnings for legal Python code. Enable # -fno-strict-aliasing on versions of GCC that support but produce @@ -1186,6 +1184,28 @@ BASECFLAGS="$BASECFLAGS -Wno-unused-result" fi + AC_MSG_CHECKING(for -Werror=declaration-after-statement) + ac_save_cc="$CC" + CC="$CC -Werror=declaration-after-statement" + save_CFLAGS="$CFLAGS" + AC_CACHE_VAL(ac_cv_declaration_after_statement_warning, + AC_COMPILE_IFELSE( + [ + AC_LANG_PROGRAM([[]], [[]]) + ],[ + ac_cv_declaration_after_statement_warning=yes + ],[ + ac_cv_declaration_after_statement_warning=no + ])) + CFLAGS="$save_CFLAGS" + CC="$ac_save_cc" + AC_MSG_RESULT($ac_cv_declaration_after_statement_warning) + + if test $ac_cv_declaration_after_statement_warning = yes + then + BASECFLAGS="$BASECFLAGS -Werror=declaration-after-statement" + fi + # if using gcc on alpha, use -mieee to get (near) full IEEE 754 # support. Without this, treatment of subnormals doesn't follow # the standard. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 17:31:30 2013 From: python-checkins at python.org (charles-francois.natali) Date: Mon, 20 May 2013 17:31:30 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2317914=3A_Remove_O?= =?utf-8?q?S-X_special-case=2C_and_use_the_correct_int_type=2E?= Message-ID: <3bDkbk58kqz7Ll0@mail.python.org> http://hg.python.org/cpython/rev/a85ac58e9eaf changeset: 83864:a85ac58e9eaf user: Charles-Francois Natali date: Mon May 20 17:31:06 2013 +0200 summary: Issue #17914: Remove OS-X special-case, and use the correct int type. files: Modules/posixmodule.c | 15 ++++++--------- 1 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -10324,12 +10324,12 @@ defined(__FreeBSD__) || \ defined(__NetBSD__) || \ defined(__APPLE__) -static long +static int _bsd_cpu_count(void) { - long ncpu = 0; + int ncpu = 0; int mib[2]; - size_t len = sizeof(int); + size_t len = sizeof(ncpu); mib[0] = CTL_HW; mib[1] = HW_NCPU; @@ -10343,7 +10343,7 @@ static PyObject * posix_cpu_count(PyObject *self) { - long ncpu = 0; + int ncpu = 0; #ifdef MS_WINDOWS SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); @@ -10352,14 +10352,11 @@ ncpu = mpctl(MPC_GETNUMSPUS, NULL, NULL); #elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN) ncpu = sysconf(_SC_NPROCESSORS_ONLN); -#elif defined(__APPLE__) - size_t len = sizeof(int); - if (sysctlnametomib("hw.logicalcpu", &ncpu, &len, NULL, 0) != 0) - ncpu = _bsd_cpu_count(); #elif defined(__DragonFly__) || \ defined(__OpenBSD__) || \ defined(__FreeBSD__) || \ - defined(__NetBSD__) + defined(__NetBSD__) || \ + defined(__APPLE__) ncpu = _bsd_cpu_count(); #endif if (ncpu >= 1) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 17:41:23 2013 From: python-checkins at python.org (charles-francois.natali) Date: Mon, 20 May 2013 17:41:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2317914=3A_We_can_n?= =?utf-8?b?b3cgaW5saW5lIF9ic2RfY3B1X2NvdW50KCku?= Message-ID: <3bDkq73WgBz7LjM@mail.python.org> http://hg.python.org/cpython/rev/f9d815522cdb changeset: 83865:f9d815522cdb user: Charles-Francois Natali date: Mon May 20 17:40:32 2013 +0200 summary: Issue #17914: We can now inline _bsd_cpu_count(). files: Modules/posixmodule.c | 28 ++++++---------------------- 1 files changed, 6 insertions(+), 22 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -10319,27 +10319,6 @@ Return the number of CPUs in the system, or None if this value cannot be\n\ established."); -#if defined(__DragonFly__) || \ - defined(__OpenBSD__) || \ - defined(__FreeBSD__) || \ - defined(__NetBSD__) || \ - defined(__APPLE__) -static int -_bsd_cpu_count(void) -{ - int ncpu = 0; - int mib[2]; - size_t len = sizeof(ncpu); - - mib[0] = CTL_HW; - mib[1] = HW_NCPU; - if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == 0) - return ncpu; - else - return 0; -} -#endif - static PyObject * posix_cpu_count(PyObject *self) { @@ -10357,7 +10336,12 @@ defined(__FreeBSD__) || \ defined(__NetBSD__) || \ defined(__APPLE__) - ncpu = _bsd_cpu_count(); + int mib[2]; + size_t len = sizeof(ncpu); + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + if (sysctl(mib, 2, &ncpu, &len, NULL, 0) != 0) + ncpu = 0; #endif if (ncpu >= 1) return PyLong_FromLong(ncpu); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 19:14:06 2013 From: python-checkins at python.org (charles-francois.natali) Date: Mon, 20 May 2013 19:14:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2317684=3A_Fix_some?= =?utf-8?q?_test=5Fsocket_failures_due_to_limited_FD_passing_support?= Message-ID: <3bDmt63m4pz7Ln1@mail.python.org> http://hg.python.org/cpython/rev/9cfaefa58bdc changeset: 83866:9cfaefa58bdc user: Charles-Francois Natali date: Mon May 20 19:08:19 2013 +0200 summary: Issue #17684: Fix some test_socket failures due to limited FD passing support on OS-X. Patch by Jeff Ramnani. files: Lib/test/test_socket.py | 10 ++++------ 1 files changed, 4 insertions(+), 6 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 @@ -2618,8 +2618,7 @@ def _testFDPassCMSG_LEN(self): self.createAndSendFDs(1) - # Issue #12958: The following test has problems on Mac OS X - @support.anticipate_failure(sys.platform == "darwin") + @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958") @requireAttrs(socket, "CMSG_SPACE") def testFDPassSeparate(self): # Pass two FDs in two separate arrays. Arrays may be combined @@ -2629,7 +2628,7 @@ maxcmsgs=2) @testFDPassSeparate.client_skip - @support.anticipate_failure(sys.platform == "darwin") + @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958") def _testFDPassSeparate(self): fd0, fd1 = self.newFDs(2) self.assertEqual( @@ -2641,8 +2640,7 @@ array.array("i", [fd1]))]), len(MSG)) - # Issue #12958: The following test has problems on Mac OS X - @support.anticipate_failure(sys.platform == "darwin") + @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958") @requireAttrs(socket, "CMSG_SPACE") def testFDPassSeparateMinSpace(self): # Pass two FDs in two separate arrays, receiving them into the @@ -2654,7 +2652,7 @@ maxcmsgs=2, ignoreflags=socket.MSG_CTRUNC) @testFDPassSeparateMinSpace.client_skip - @support.anticipate_failure(sys.platform == "darwin") + @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958") def _testFDPassSeparateMinSpace(self): fd0, fd1 = self.newFDs(2) self.assertEqual( -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 19:14:08 2013 From: python-checkins at python.org (charles-francois.natali) Date: Mon, 20 May 2013 19:14:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2317917=3A_Use_PyMo?= =?utf-8?q?dule=5FAddIntMacro=28=29_instead_of_PyModule=5FAddIntConstant?= =?utf-8?b?KCk=?= Message-ID: <3bDmt86lcyz7Ln1@mail.python.org> http://hg.python.org/cpython/rev/12cbb5183d98 changeset: 83867:12cbb5183d98 user: Charles-Francois Natali date: Mon May 20 19:13:19 2013 +0200 summary: Issue #17917: Use PyModule_AddIntMacro() instead of PyModule_AddIntConstant() when applicable. files: Modules/_datetimemodule.c | 4 +- Modules/_testbuffer.c | 60 +- Modules/fcntlmodule.c | 163 ++--- Modules/posixmodule.c | 244 ++++---- Modules/resource.c | 34 +- Modules/selectmodule.c | 50 +- Modules/socketmodule.c | 666 ++++++++++++------------- Modules/symtablemodule.c | 32 +- Modules/syslogmodule.c | 66 +- Modules/zlibmodule.c | 26 +- PC/_msi.c | 64 +- Python/Python-ast.c | 2 +- 12 files changed, 692 insertions(+), 719 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -5299,8 +5299,8 @@ return NULL; /* module initialization */ - PyModule_AddIntConstant(m, "MINYEAR", MINYEAR); - PyModule_AddIntConstant(m, "MAXYEAR", MAXYEAR); + PyModule_AddIntMacro(m, MINYEAR); + PyModule_AddIntMacro(m, MAXYEAR); Py_INCREF(&PyDateTime_DateType); PyModule_AddObject(m, "date", (PyObject *) &PyDateTime_DateType); diff --git a/Modules/_testbuffer.c b/Modules/_testbuffer.c --- a/Modules/_testbuffer.c +++ b/Modules/_testbuffer.c @@ -2837,36 +2837,36 @@ if (simple_format == NULL) return NULL; - PyModule_AddIntConstant(m, "ND_MAX_NDIM", ND_MAX_NDIM); - PyModule_AddIntConstant(m, "ND_VAREXPORT", ND_VAREXPORT); - PyModule_AddIntConstant(m, "ND_WRITABLE", ND_WRITABLE); - PyModule_AddIntConstant(m, "ND_FORTRAN", ND_FORTRAN); - PyModule_AddIntConstant(m, "ND_SCALAR", ND_SCALAR); - PyModule_AddIntConstant(m, "ND_PIL", ND_PIL); - PyModule_AddIntConstant(m, "ND_GETBUF_FAIL", ND_GETBUF_FAIL); - PyModule_AddIntConstant(m, "ND_GETBUF_UNDEFINED", ND_GETBUF_UNDEFINED); - PyModule_AddIntConstant(m, "ND_REDIRECT", ND_REDIRECT); - - PyModule_AddIntConstant(m, "PyBUF_SIMPLE", PyBUF_SIMPLE); - PyModule_AddIntConstant(m, "PyBUF_WRITABLE", PyBUF_WRITABLE); - PyModule_AddIntConstant(m, "PyBUF_FORMAT", PyBUF_FORMAT); - PyModule_AddIntConstant(m, "PyBUF_ND", PyBUF_ND); - PyModule_AddIntConstant(m, "PyBUF_STRIDES", PyBUF_STRIDES); - PyModule_AddIntConstant(m, "PyBUF_INDIRECT", PyBUF_INDIRECT); - PyModule_AddIntConstant(m, "PyBUF_C_CONTIGUOUS", PyBUF_C_CONTIGUOUS); - PyModule_AddIntConstant(m, "PyBUF_F_CONTIGUOUS", PyBUF_F_CONTIGUOUS); - PyModule_AddIntConstant(m, "PyBUF_ANY_CONTIGUOUS", PyBUF_ANY_CONTIGUOUS); - PyModule_AddIntConstant(m, "PyBUF_FULL", PyBUF_FULL); - PyModule_AddIntConstant(m, "PyBUF_FULL_RO", PyBUF_FULL_RO); - PyModule_AddIntConstant(m, "PyBUF_RECORDS", PyBUF_RECORDS); - PyModule_AddIntConstant(m, "PyBUF_RECORDS_RO", PyBUF_RECORDS_RO); - PyModule_AddIntConstant(m, "PyBUF_STRIDED", PyBUF_STRIDED); - PyModule_AddIntConstant(m, "PyBUF_STRIDED_RO", PyBUF_STRIDED_RO); - PyModule_AddIntConstant(m, "PyBUF_CONTIG", PyBUF_CONTIG); - PyModule_AddIntConstant(m, "PyBUF_CONTIG_RO", PyBUF_CONTIG_RO); - - PyModule_AddIntConstant(m, "PyBUF_READ", PyBUF_READ); - PyModule_AddIntConstant(m, "PyBUF_WRITE", PyBUF_WRITE); + PyModule_AddIntMacro(m, ND_MAX_NDIM); + PyModule_AddIntMacro(m, ND_VAREXPORT); + PyModule_AddIntMacro(m, ND_WRITABLE); + PyModule_AddIntMacro(m, ND_FORTRAN); + PyModule_AddIntMacro(m, ND_SCALAR); + PyModule_AddIntMacro(m, ND_PIL); + PyModule_AddIntMacro(m, ND_GETBUF_FAIL); + PyModule_AddIntMacro(m, ND_GETBUF_UNDEFINED); + PyModule_AddIntMacro(m, ND_REDIRECT); + + PyModule_AddIntMacro(m, PyBUF_SIMPLE); + PyModule_AddIntMacro(m, PyBUF_WRITABLE); + PyModule_AddIntMacro(m, PyBUF_FORMAT); + PyModule_AddIntMacro(m, PyBUF_ND); + PyModule_AddIntMacro(m, PyBUF_STRIDES); + PyModule_AddIntMacro(m, PyBUF_INDIRECT); + PyModule_AddIntMacro(m, PyBUF_C_CONTIGUOUS); + PyModule_AddIntMacro(m, PyBUF_F_CONTIGUOUS); + PyModule_AddIntMacro(m, PyBUF_ANY_CONTIGUOUS); + PyModule_AddIntMacro(m, PyBUF_FULL); + PyModule_AddIntMacro(m, PyBUF_FULL_RO); + PyModule_AddIntMacro(m, PyBUF_RECORDS); + PyModule_AddIntMacro(m, PyBUF_RECORDS_RO); + PyModule_AddIntMacro(m, PyBUF_STRIDED); + PyModule_AddIntMacro(m, PyBUF_STRIDED_RO); + PyModule_AddIntMacro(m, PyBUF_CONTIG); + PyModule_AddIntMacro(m, PyBUF_CONTIG_RO); + + PyModule_AddIntMacro(m, PyBUF_READ); + PyModule_AddIntMacro(m, PyBUF_WRITE); return m; } diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c --- a/Modules/fcntlmodule.c +++ b/Modules/fcntlmodule.c @@ -424,191 +424,179 @@ /* Module initialisation */ -static int -ins(PyObject* d, char* symbol, long value) -{ - PyObject* v = PyLong_FromLong(value); - if (!v || PyDict_SetItemString(d, symbol, v) < 0) - return -1; - - Py_DECREF(v); - return 0; -} - -#define INS(x) if (ins(d, #x, (long)x)) return -1 static int -all_ins(PyObject* d) +all_ins(PyObject* m) { - if (ins(d, "LOCK_SH", (long)LOCK_SH)) return -1; - if (ins(d, "LOCK_EX", (long)LOCK_EX)) return -1; - if (ins(d, "LOCK_NB", (long)LOCK_NB)) return -1; - if (ins(d, "LOCK_UN", (long)LOCK_UN)) return -1; + if (PyModule_AddIntMacro(m, LOCK_SH)) return -1; + if (PyModule_AddIntMacro(m, LOCK_EX)) return -1; + if (PyModule_AddIntMacro(m, LOCK_NB)) return -1; + if (PyModule_AddIntMacro(m, LOCK_UN)) return -1; /* GNU extensions, as of glibc 2.2.4 */ #ifdef LOCK_MAND - if (ins(d, "LOCK_MAND", (long)LOCK_MAND)) return -1; + if (PyModule_AddIntMacro(m, LOCK_MAND)) return -1; #endif #ifdef LOCK_READ - if (ins(d, "LOCK_READ", (long)LOCK_READ)) return -1; + if (PyModule_AddIntMacro(m, LOCK_READ)) return -1; #endif #ifdef LOCK_WRITE - if (ins(d, "LOCK_WRITE", (long)LOCK_WRITE)) return -1; + if (PyModule_AddIntMacro(m, LOCK_WRITE)) return -1; #endif #ifdef LOCK_RW - if (ins(d, "LOCK_RW", (long)LOCK_RW)) return -1; + if (PyModule_AddIntMacro(m, LOCK_RW)) return -1; #endif #ifdef F_DUPFD - if (ins(d, "F_DUPFD", (long)F_DUPFD)) return -1; + if (PyModule_AddIntMacro(m, F_DUPFD)) return -1; #endif #ifdef F_DUPFD_CLOEXEC - if (ins(d, "F_DUPFD_CLOEXEC", (long)F_DUPFD_CLOEXEC)) return -1; + if (PyModule_AddIntMacro(m, F_DUPFD_CLOEXEC)) return -1; #endif #ifdef F_GETFD - if (ins(d, "F_GETFD", (long)F_GETFD)) return -1; + if (PyModule_AddIntMacro(m, F_GETFD)) return -1; #endif #ifdef F_SETFD - if (ins(d, "F_SETFD", (long)F_SETFD)) return -1; + if (PyModule_AddIntMacro(m, F_SETFD)) return -1; #endif #ifdef F_GETFL - if (ins(d, "F_GETFL", (long)F_GETFL)) return -1; + if (PyModule_AddIntMacro(m, F_GETFL)) return -1; #endif #ifdef F_SETFL - if (ins(d, "F_SETFL", (long)F_SETFL)) return -1; + if (PyModule_AddIntMacro(m, F_SETFL)) return -1; #endif #ifdef F_GETLK - if (ins(d, "F_GETLK", (long)F_GETLK)) return -1; + if (PyModule_AddIntMacro(m, F_GETLK)) return -1; #endif #ifdef F_SETLK - if (ins(d, "F_SETLK", (long)F_SETLK)) return -1; + if (PyModule_AddIntMacro(m, F_SETLK)) return -1; #endif #ifdef F_SETLKW - if (ins(d, "F_SETLKW", (long)F_SETLKW)) return -1; + if (PyModule_AddIntMacro(m, F_SETLKW)) return -1; #endif #ifdef F_GETOWN - if (ins(d, "F_GETOWN", (long)F_GETOWN)) return -1; + if (PyModule_AddIntMacro(m, F_GETOWN)) return -1; #endif #ifdef F_SETOWN - if (ins(d, "F_SETOWN", (long)F_SETOWN)) return -1; + if (PyModule_AddIntMacro(m, F_SETOWN)) return -1; #endif #ifdef F_GETSIG - if (ins(d, "F_GETSIG", (long)F_GETSIG)) return -1; + if (PyModule_AddIntMacro(m, F_GETSIG)) return -1; #endif #ifdef F_SETSIG - if (ins(d, "F_SETSIG", (long)F_SETSIG)) return -1; + if (PyModule_AddIntMacro(m, F_SETSIG)) return -1; #endif #ifdef F_RDLCK - if (ins(d, "F_RDLCK", (long)F_RDLCK)) return -1; + if (PyModule_AddIntMacro(m, F_RDLCK)) return -1; #endif #ifdef F_WRLCK - if (ins(d, "F_WRLCK", (long)F_WRLCK)) return -1; + if (PyModule_AddIntMacro(m, F_WRLCK)) return -1; #endif #ifdef F_UNLCK - if (ins(d, "F_UNLCK", (long)F_UNLCK)) return -1; + if (PyModule_AddIntMacro(m, F_UNLCK)) return -1; #endif /* LFS constants */ #ifdef F_GETLK64 - if (ins(d, "F_GETLK64", (long)F_GETLK64)) return -1; + if (PyModule_AddIntMacro(m, F_GETLK64)) return -1; #endif #ifdef F_SETLK64 - if (ins(d, "F_SETLK64", (long)F_SETLK64)) return -1; + if (PyModule_AddIntMacro(m, F_SETLK64)) return -1; #endif #ifdef F_SETLKW64 - if (ins(d, "F_SETLKW64", (long)F_SETLKW64)) return -1; + if (PyModule_AddIntMacro(m, F_SETLKW64)) return -1; #endif /* GNU extensions, as of glibc 2.2.4. */ #ifdef FASYNC - if (ins(d, "FASYNC", (long)FASYNC)) return -1; + if (PyModule_AddIntMacro(m, FASYNC)) return -1; #endif #ifdef F_SETLEASE - if (ins(d, "F_SETLEASE", (long)F_SETLEASE)) return -1; + if (PyModule_AddIntMacro(m, F_SETLEASE)) return -1; #endif #ifdef F_GETLEASE - if (ins(d, "F_GETLEASE", (long)F_GETLEASE)) return -1; + if (PyModule_AddIntMacro(m, F_GETLEASE)) return -1; #endif #ifdef F_NOTIFY - if (ins(d, "F_NOTIFY", (long)F_NOTIFY)) return -1; + if (PyModule_AddIntMacro(m, F_NOTIFY)) return -1; #endif /* Old BSD flock(). */ #ifdef F_EXLCK - if (ins(d, "F_EXLCK", (long)F_EXLCK)) return -1; + if (PyModule_AddIntMacro(m, F_EXLCK)) return -1; #endif #ifdef F_SHLCK - if (ins(d, "F_SHLCK", (long)F_SHLCK)) return -1; + if (PyModule_AddIntMacro(m, F_SHLCK)) return -1; #endif /* OS X specifics */ #ifdef F_FULLFSYNC - if (ins(d, "F_FULLFSYNC", (long)F_FULLFSYNC)) return -1; + if (PyModule_AddIntMacro(m, F_FULLFSYNC)) return -1; #endif #ifdef F_NOCACHE - if (ins(d, "F_NOCACHE", (long)F_NOCACHE)) return -1; + if (PyModule_AddIntMacro(m, F_NOCACHE)) return -1; #endif /* For F_{GET|SET}FL */ #ifdef FD_CLOEXEC - if (ins(d, "FD_CLOEXEC", (long)FD_CLOEXEC)) return -1; + if (PyModule_AddIntMacro(m, FD_CLOEXEC)) return -1; #endif /* For F_NOTIFY */ #ifdef DN_ACCESS - if (ins(d, "DN_ACCESS", (long)DN_ACCESS)) return -1; + if (PyModule_AddIntMacro(m, DN_ACCESS)) return -1; #endif #ifdef DN_MODIFY - if (ins(d, "DN_MODIFY", (long)DN_MODIFY)) return -1; + if (PyModule_AddIntMacro(m, DN_MODIFY)) return -1; #endif #ifdef DN_CREATE - if (ins(d, "DN_CREATE", (long)DN_CREATE)) return -1; + if (PyModule_AddIntMacro(m, DN_CREATE)) return -1; #endif #ifdef DN_DELETE - if (ins(d, "DN_DELETE", (long)DN_DELETE)) return -1; + if (PyModule_AddIntMacro(m, DN_DELETE)) return -1; #endif #ifdef DN_RENAME - if (ins(d, "DN_RENAME", (long)DN_RENAME)) return -1; + if (PyModule_AddIntMacro(m, DN_RENAME)) return -1; #endif #ifdef DN_ATTRIB - if (ins(d, "DN_ATTRIB", (long)DN_ATTRIB)) return -1; + if (PyModule_AddIntMacro(m, DN_ATTRIB)) return -1; #endif #ifdef DN_MULTISHOT - if (ins(d, "DN_MULTISHOT", (long)DN_MULTISHOT)) return -1; + if (PyModule_AddIntMacro(m, DN_MULTISHOT)) return -1; #endif #ifdef HAVE_STROPTS_H /* Unix 98 guarantees that these are in stropts.h. */ - INS(I_PUSH); - INS(I_POP); - INS(I_LOOK); - INS(I_FLUSH); - INS(I_FLUSHBAND); - INS(I_SETSIG); - INS(I_GETSIG); - INS(I_FIND); - INS(I_PEEK); - INS(I_SRDOPT); - INS(I_GRDOPT); - INS(I_NREAD); - INS(I_FDINSERT); - INS(I_STR); - INS(I_SWROPT); + if (PyModule_AddIntMacro(m, I_PUSH)) return -1; + if (PyModule_AddIntMacro(m, I_POP)) return -1; + if (PyModule_AddIntMacro(m, I_LOOK)) return -1; + if (PyModule_AddIntMacro(m, I_FLUSH)) return -1; + if (PyModule_AddIntMacro(m, I_FLUSHBAND)) return -1; + if (PyModule_AddIntMacro(m, I_SETSIG)) return -1; + if (PyModule_AddIntMacro(m, I_GETSIG)) return -1; + if (PyModule_AddIntMacro(m, I_FIND)) return -1; + if (PyModule_AddIntMacro(m, I_PEEK)) return -1; + if (PyModule_AddIntMacro(m, I_SRDOPT)) return -1; + if (PyModule_AddIntMacro(m, I_GRDOPT)) return -1; + if (PyModule_AddIntMacro(m, I_NREAD)) return -1; + if (PyModule_AddIntMacro(m, I_FDINSERT)) return -1; + if (PyModule_AddIntMacro(m, I_STR)) return -1; + if (PyModule_AddIntMacro(m, I_SWROPT)) return -1; #ifdef I_GWROPT /* despite the comment above, old-ish glibcs miss a couple... */ - INS(I_GWROPT); + if (PyModule_AddIntMacro(m, I_GWROPT)) return -1; #endif - INS(I_SENDFD); - INS(I_RECVFD); - INS(I_LIST); - INS(I_ATMARK); - INS(I_CKBAND); - INS(I_GETBAND); - INS(I_CANPUT); - INS(I_SETCLTIME); + if (PyModule_AddIntMacro(m, I_SENDFD)) return -1; + if (PyModule_AddIntMacro(m, I_RECVFD)) return -1; + if (PyModule_AddIntMacro(m, I_LIST)) return -1; + if (PyModule_AddIntMacro(m, I_ATMARK)) return -1; + if (PyModule_AddIntMacro(m, I_CKBAND)) return -1; + if (PyModule_AddIntMacro(m, I_GETBAND)) return -1; + if (PyModule_AddIntMacro(m, I_CANPUT)) return -1; + if (PyModule_AddIntMacro(m, I_SETCLTIME)) return -1; #ifdef I_GETCLTIME - INS(I_GETCLTIME); + if (PyModule_AddIntMacro(m, I_GETCLTIME)) return -1; #endif - INS(I_LINK); - INS(I_UNLINK); - INS(I_PLINK); - INS(I_PUNLINK); + if (PyModule_AddIntMacro(m, I_LINK)) return -1; + if (PyModule_AddIntMacro(m, I_UNLINK)) return -1; + if (PyModule_AddIntMacro(m, I_PLINK)) return -1; + if (PyModule_AddIntMacro(m, I_PUNLINK)) return -1; #endif return 0; @@ -630,7 +618,7 @@ PyMODINIT_FUNC PyInit_fcntl(void) { - PyObject *m, *d; + PyObject *m; /* Create the module and add the functions and documentation */ m = PyModule_Create(&fcntlmodule); @@ -638,7 +626,6 @@ return NULL; /* Add some symbolic constants to the module */ - d = PyModule_GetDict(m); - all_ins(d); + all_ins(m); return m; } diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -10800,12 +10800,6 @@ }; -static int -ins(PyObject *module, char *symbol, long value) -{ - return PyModule_AddIntConstant(module, symbol, value); -} - #if defined(HAVE_SYMLINK) && defined(MS_WINDOWS) static int enable_symlink() @@ -10836,376 +10830,376 @@ #endif /* defined(HAVE_SYMLINK) && defined(MS_WINDOWS) */ static int -all_ins(PyObject *d) +all_ins(PyObject *m) { #ifdef F_OK - if (ins(d, "F_OK", (long)F_OK)) return -1; + if (PyModule_AddIntMacro(m, F_OK)) return -1; #endif #ifdef R_OK - if (ins(d, "R_OK", (long)R_OK)) return -1; + if (PyModule_AddIntMacro(m, R_OK)) return -1; #endif #ifdef W_OK - if (ins(d, "W_OK", (long)W_OK)) return -1; + if (PyModule_AddIntMacro(m, W_OK)) return -1; #endif #ifdef X_OK - if (ins(d, "X_OK", (long)X_OK)) return -1; + if (PyModule_AddIntMacro(m, X_OK)) return -1; #endif #ifdef NGROUPS_MAX - if (ins(d, "NGROUPS_MAX", (long)NGROUPS_MAX)) return -1; + if (PyModule_AddIntMacro(m, NGROUPS_MAX)) return -1; #endif #ifdef TMP_MAX - if (ins(d, "TMP_MAX", (long)TMP_MAX)) return -1; + if (PyModule_AddIntMacro(m, TMP_MAX)) return -1; #endif #ifdef WCONTINUED - if (ins(d, "WCONTINUED", (long)WCONTINUED)) return -1; + if (PyModule_AddIntMacro(m, WCONTINUED)) return -1; #endif #ifdef WNOHANG - if (ins(d, "WNOHANG", (long)WNOHANG)) return -1; + if (PyModule_AddIntMacro(m, WNOHANG)) return -1; #endif #ifdef WUNTRACED - if (ins(d, "WUNTRACED", (long)WUNTRACED)) return -1; + if (PyModule_AddIntMacro(m, WUNTRACED)) return -1; #endif #ifdef O_RDONLY - if (ins(d, "O_RDONLY", (long)O_RDONLY)) return -1; + if (PyModule_AddIntMacro(m, O_RDONLY)) return -1; #endif #ifdef O_WRONLY - if (ins(d, "O_WRONLY", (long)O_WRONLY)) return -1; + if (PyModule_AddIntMacro(m, O_WRONLY)) return -1; #endif #ifdef O_RDWR - if (ins(d, "O_RDWR", (long)O_RDWR)) return -1; + if (PyModule_AddIntMacro(m, O_RDWR)) return -1; #endif #ifdef O_NDELAY - if (ins(d, "O_NDELAY", (long)O_NDELAY)) return -1; + if (PyModule_AddIntMacro(m, O_NDELAY)) return -1; #endif #ifdef O_NONBLOCK - if (ins(d, "O_NONBLOCK", (long)O_NONBLOCK)) return -1; + if (PyModule_AddIntMacro(m, O_NONBLOCK)) return -1; #endif #ifdef O_APPEND - if (ins(d, "O_APPEND", (long)O_APPEND)) return -1; + if (PyModule_AddIntMacro(m, O_APPEND)) return -1; #endif #ifdef O_DSYNC - if (ins(d, "O_DSYNC", (long)O_DSYNC)) return -1; + if (PyModule_AddIntMacro(m, O_DSYNC)) return -1; #endif #ifdef O_RSYNC - if (ins(d, "O_RSYNC", (long)O_RSYNC)) return -1; + if (PyModule_AddIntMacro(m, O_RSYNC)) return -1; #endif #ifdef O_SYNC - if (ins(d, "O_SYNC", (long)O_SYNC)) return -1; + if (PyModule_AddIntMacro(m, O_SYNC)) return -1; #endif #ifdef O_NOCTTY - if (ins(d, "O_NOCTTY", (long)O_NOCTTY)) return -1; + if (PyModule_AddIntMacro(m, O_NOCTTY)) return -1; #endif #ifdef O_CREAT - if (ins(d, "O_CREAT", (long)O_CREAT)) return -1; + if (PyModule_AddIntMacro(m, O_CREAT)) return -1; #endif #ifdef O_EXCL - if (ins(d, "O_EXCL", (long)O_EXCL)) return -1; + if (PyModule_AddIntMacro(m, O_EXCL)) return -1; #endif #ifdef O_TRUNC - if (ins(d, "O_TRUNC", (long)O_TRUNC)) return -1; + if (PyModule_AddIntMacro(m, O_TRUNC)) return -1; #endif #ifdef O_BINARY - if (ins(d, "O_BINARY", (long)O_BINARY)) return -1; + if (PyModule_AddIntMacro(m, O_BINARY)) return -1; #endif #ifdef O_TEXT - if (ins(d, "O_TEXT", (long)O_TEXT)) return -1; + if (PyModule_AddIntMacro(m, O_TEXT)) return -1; #endif #ifdef O_XATTR - if (ins(d, "O_XATTR", (long)O_XATTR)) return -1; + if (PyModule_AddIntMacro(m, O_XATTR)) return -1; #endif #ifdef O_LARGEFILE - if (ins(d, "O_LARGEFILE", (long)O_LARGEFILE)) return -1; + if (PyModule_AddIntMacro(m, O_LARGEFILE)) return -1; #endif #ifdef O_SHLOCK - if (ins(d, "O_SHLOCK", (long)O_SHLOCK)) return -1; + if (PyModule_AddIntMacro(m, O_SHLOCK)) return -1; #endif #ifdef O_EXLOCK - if (ins(d, "O_EXLOCK", (long)O_EXLOCK)) return -1; + if (PyModule_AddIntMacro(m, O_EXLOCK)) return -1; #endif #ifdef O_EXEC - if (ins(d, "O_EXEC", (long)O_EXEC)) return -1; + if (PyModule_AddIntMacro(m, O_EXEC)) return -1; #endif #ifdef O_SEARCH - if (ins(d, "O_SEARCH", (long)O_SEARCH)) return -1; + if (PyModule_AddIntMacro(m, O_SEARCH)) return -1; #endif #ifdef O_PATH - if (ins(d, "O_PATH", (long)O_PATH)) return -1; + if (PyModule_AddIntMacro(m, O_PATH)) return -1; #endif #ifdef O_TTY_INIT - if (ins(d, "O_TTY_INIT", (long)O_TTY_INIT)) return -1; + if (PyModule_AddIntMacro(m, O_TTY_INIT)) return -1; #endif #ifdef PRIO_PROCESS - if (ins(d, "PRIO_PROCESS", (long)PRIO_PROCESS)) return -1; + if (PyModule_AddIntMacro(m, PRIO_PROCESS)) return -1; #endif #ifdef PRIO_PGRP - if (ins(d, "PRIO_PGRP", (long)PRIO_PGRP)) return -1; + if (PyModule_AddIntMacro(m, PRIO_PGRP)) return -1; #endif #ifdef PRIO_USER - if (ins(d, "PRIO_USER", (long)PRIO_USER)) return -1; + if (PyModule_AddIntMacro(m, PRIO_USER)) return -1; #endif #ifdef O_CLOEXEC - if (ins(d, "O_CLOEXEC", (long)O_CLOEXEC)) return -1; + if (PyModule_AddIntMacro(m, O_CLOEXEC)) return -1; #endif #ifdef O_ACCMODE - if (ins(d, "O_ACCMODE", (long)O_ACCMODE)) return -1; + if (PyModule_AddIntMacro(m, O_ACCMODE)) return -1; #endif #ifdef SEEK_HOLE - if (ins(d, "SEEK_HOLE", (long)SEEK_HOLE)) return -1; + if (PyModule_AddIntMacro(m, SEEK_HOLE)) return -1; #endif #ifdef SEEK_DATA - if (ins(d, "SEEK_DATA", (long)SEEK_DATA)) return -1; + if (PyModule_AddIntMacro(m, SEEK_DATA)) return -1; #endif /* MS Windows */ #ifdef O_NOINHERIT /* Don't inherit in child processes. */ - if (ins(d, "O_NOINHERIT", (long)O_NOINHERIT)) return -1; + if (PyModule_AddIntMacro(m, O_NOINHERIT)) return -1; #endif #ifdef _O_SHORT_LIVED /* Optimize for short life (keep in memory). */ /* MS forgot to define this one with a non-underscore form too. */ - if (ins(d, "O_SHORT_LIVED", (long)_O_SHORT_LIVED)) return -1; + if (PyModule_AddIntConstant(m, "O_SHORT_LIVED", _O_SHORT_LIVED)) return -1; #endif #ifdef O_TEMPORARY /* Automatically delete when last handle is closed. */ - if (ins(d, "O_TEMPORARY", (long)O_TEMPORARY)) return -1; + if (PyModule_AddIntMacro(m, O_TEMPORARY)) return -1; #endif #ifdef O_RANDOM /* Optimize for random access. */ - if (ins(d, "O_RANDOM", (long)O_RANDOM)) return -1; + if (PyModule_AddIntMacro(m, O_RANDOM)) return -1; #endif #ifdef O_SEQUENTIAL /* Optimize for sequential access. */ - if (ins(d, "O_SEQUENTIAL", (long)O_SEQUENTIAL)) return -1; + if (PyModule_AddIntMacro(m, O_SEQUENTIAL)) return -1; #endif /* GNU extensions. */ #ifdef O_ASYNC /* Send a SIGIO signal whenever input or output becomes available on file descriptor */ - if (ins(d, "O_ASYNC", (long)O_ASYNC)) return -1; + if (PyModule_AddIntMacro(m, O_ASYNC)) return -1; #endif #ifdef O_DIRECT /* Direct disk access. */ - if (ins(d, "O_DIRECT", (long)O_DIRECT)) return -1; + if (PyModule_AddIntMacro(m, O_DIRECT)) return -1; #endif #ifdef O_DIRECTORY /* Must be a directory. */ - if (ins(d, "O_DIRECTORY", (long)O_DIRECTORY)) return -1; + if (PyModule_AddIntMacro(m, O_DIRECTORY)) return -1; #endif #ifdef O_NOFOLLOW /* Do not follow links. */ - if (ins(d, "O_NOFOLLOW", (long)O_NOFOLLOW)) return -1; + if (PyModule_AddIntMacro(m, O_NOFOLLOW)) return -1; #endif #ifdef O_NOLINKS /* Fails if link count of the named file is greater than 1 */ - if (ins(d, "O_NOLINKS", (long)O_NOLINKS)) return -1; + if (PyModule_AddIntMacro(m, O_NOLINKS)) return -1; #endif #ifdef O_NOATIME /* Do not update the access time. */ - if (ins(d, "O_NOATIME", (long)O_NOATIME)) return -1; + if (PyModule_AddIntMacro(m, O_NOATIME)) return -1; #endif /* These come from sysexits.h */ #ifdef EX_OK - if (ins(d, "EX_OK", (long)EX_OK)) return -1; + if (PyModule_AddIntMacro(m, EX_OK)) return -1; #endif /* EX_OK */ #ifdef EX_USAGE - if (ins(d, "EX_USAGE", (long)EX_USAGE)) return -1; + if (PyModule_AddIntMacro(m, EX_USAGE)) return -1; #endif /* EX_USAGE */ #ifdef EX_DATAERR - if (ins(d, "EX_DATAERR", (long)EX_DATAERR)) return -1; + if (PyModule_AddIntMacro(m, EX_DATAERR)) return -1; #endif /* EX_DATAERR */ #ifdef EX_NOINPUT - if (ins(d, "EX_NOINPUT", (long)EX_NOINPUT)) return -1; + if (PyModule_AddIntMacro(m, EX_NOINPUT)) return -1; #endif /* EX_NOINPUT */ #ifdef EX_NOUSER - if (ins(d, "EX_NOUSER", (long)EX_NOUSER)) return -1; + if (PyModule_AddIntMacro(m, EX_NOUSER)) return -1; #endif /* EX_NOUSER */ #ifdef EX_NOHOST - if (ins(d, "EX_NOHOST", (long)EX_NOHOST)) return -1; + if (PyModule_AddIntMacro(m, EX_NOHOST)) return -1; #endif /* EX_NOHOST */ #ifdef EX_UNAVAILABLE - if (ins(d, "EX_UNAVAILABLE", (long)EX_UNAVAILABLE)) return -1; + if (PyModule_AddIntMacro(m, EX_UNAVAILABLE)) return -1; #endif /* EX_UNAVAILABLE */ #ifdef EX_SOFTWARE - if (ins(d, "EX_SOFTWARE", (long)EX_SOFTWARE)) return -1; + if (PyModule_AddIntMacro(m, EX_SOFTWARE)) return -1; #endif /* EX_SOFTWARE */ #ifdef EX_OSERR - if (ins(d, "EX_OSERR", (long)EX_OSERR)) return -1; + if (PyModule_AddIntMacro(m, EX_OSERR)) return -1; #endif /* EX_OSERR */ #ifdef EX_OSFILE - if (ins(d, "EX_OSFILE", (long)EX_OSFILE)) return -1; + if (PyModule_AddIntMacro(m, EX_OSFILE)) return -1; #endif /* EX_OSFILE */ #ifdef EX_CANTCREAT - if (ins(d, "EX_CANTCREAT", (long)EX_CANTCREAT)) return -1; + if (PyModule_AddIntMacro(m, EX_CANTCREAT)) return -1; #endif /* EX_CANTCREAT */ #ifdef EX_IOERR - if (ins(d, "EX_IOERR", (long)EX_IOERR)) return -1; + if (PyModule_AddIntMacro(m, EX_IOERR)) return -1; #endif /* EX_IOERR */ #ifdef EX_TEMPFAIL - if (ins(d, "EX_TEMPFAIL", (long)EX_TEMPFAIL)) return -1; + if (PyModule_AddIntMacro(m, EX_TEMPFAIL)) return -1; #endif /* EX_TEMPFAIL */ #ifdef EX_PROTOCOL - if (ins(d, "EX_PROTOCOL", (long)EX_PROTOCOL)) return -1; + if (PyModule_AddIntMacro(m, EX_PROTOCOL)) return -1; #endif /* EX_PROTOCOL */ #ifdef EX_NOPERM - if (ins(d, "EX_NOPERM", (long)EX_NOPERM)) return -1; + if (PyModule_AddIntMacro(m, EX_NOPERM)) return -1; #endif /* EX_NOPERM */ #ifdef EX_CONFIG - if (ins(d, "EX_CONFIG", (long)EX_CONFIG)) return -1; + if (PyModule_AddIntMacro(m, EX_CONFIG)) return -1; #endif /* EX_CONFIG */ #ifdef EX_NOTFOUND - if (ins(d, "EX_NOTFOUND", (long)EX_NOTFOUND)) return -1; + if (PyModule_AddIntMacro(m, EX_NOTFOUND)) return -1; #endif /* EX_NOTFOUND */ /* statvfs */ #ifdef ST_RDONLY - if (ins(d, "ST_RDONLY", (long)ST_RDONLY)) return -1; + if (PyModule_AddIntMacro(m, ST_RDONLY)) return -1; #endif /* ST_RDONLY */ #ifdef ST_NOSUID - if (ins(d, "ST_NOSUID", (long)ST_NOSUID)) return -1; + if (PyModule_AddIntMacro(m, ST_NOSUID)) return -1; #endif /* ST_NOSUID */ /* FreeBSD sendfile() constants */ #ifdef SF_NODISKIO - if (ins(d, "SF_NODISKIO", (long)SF_NODISKIO)) return -1; + if (PyModule_AddIntMacro(m, SF_NODISKIO)) return -1; #endif #ifdef SF_MNOWAIT - if (ins(d, "SF_MNOWAIT", (long)SF_MNOWAIT)) return -1; + if (PyModule_AddIntMacro(m, SF_MNOWAIT)) return -1; #endif #ifdef SF_SYNC - if (ins(d, "SF_SYNC", (long)SF_SYNC)) return -1; + if (PyModule_AddIntMacro(m, SF_SYNC)) return -1; #endif /* constants for posix_fadvise */ #ifdef POSIX_FADV_NORMAL - if (ins(d, "POSIX_FADV_NORMAL", (long)POSIX_FADV_NORMAL)) return -1; + if (PyModule_AddIntMacro(m, POSIX_FADV_NORMAL)) return -1; #endif #ifdef POSIX_FADV_SEQUENTIAL - if (ins(d, "POSIX_FADV_SEQUENTIAL", (long)POSIX_FADV_SEQUENTIAL)) return -1; + if (PyModule_AddIntMacro(m, POSIX_FADV_SEQUENTIAL)) return -1; #endif #ifdef POSIX_FADV_RANDOM - if (ins(d, "POSIX_FADV_RANDOM", (long)POSIX_FADV_RANDOM)) return -1; + if (PyModule_AddIntMacro(m, POSIX_FADV_RANDOM)) return -1; #endif #ifdef POSIX_FADV_NOREUSE - if (ins(d, "POSIX_FADV_NOREUSE", (long)POSIX_FADV_NOREUSE)) return -1; + if (PyModule_AddIntMacro(m, POSIX_FADV_NOREUSE)) return -1; #endif #ifdef POSIX_FADV_WILLNEED - if (ins(d, "POSIX_FADV_WILLNEED", (long)POSIX_FADV_WILLNEED)) return -1; + if (PyModule_AddIntMacro(m, POSIX_FADV_WILLNEED)) return -1; #endif #ifdef POSIX_FADV_DONTNEED - if (ins(d, "POSIX_FADV_DONTNEED", (long)POSIX_FADV_DONTNEED)) return -1; + if (PyModule_AddIntMacro(m, POSIX_FADV_DONTNEED)) return -1; #endif /* constants for waitid */ #if defined(HAVE_SYS_WAIT_H) && defined(HAVE_WAITID) - if (ins(d, "P_PID", (long)P_PID)) return -1; - if (ins(d, "P_PGID", (long)P_PGID)) return -1; - if (ins(d, "P_ALL", (long)P_ALL)) return -1; + if (PyModule_AddIntMacro(m, P_PID)) return -1; + if (PyModule_AddIntMacro(m, P_PGID)) return -1; + if (PyModule_AddIntMacro(m, P_ALL)) return -1; #endif #ifdef WEXITED - if (ins(d, "WEXITED", (long)WEXITED)) return -1; + if (PyModule_AddIntMacro(m, WEXITED)) return -1; #endif #ifdef WNOWAIT - if (ins(d, "WNOWAIT", (long)WNOWAIT)) return -1; + if (PyModule_AddIntMacro(m, WNOWAIT)) return -1; #endif #ifdef WSTOPPED - if (ins(d, "WSTOPPED", (long)WSTOPPED)) return -1; + if (PyModule_AddIntMacro(m, WSTOPPED)) return -1; #endif #ifdef CLD_EXITED - if (ins(d, "CLD_EXITED", (long)CLD_EXITED)) return -1; + if (PyModule_AddIntMacro(m, CLD_EXITED)) return -1; #endif #ifdef CLD_DUMPED - if (ins(d, "CLD_DUMPED", (long)CLD_DUMPED)) return -1; + if (PyModule_AddIntMacro(m, CLD_DUMPED)) return -1; #endif #ifdef CLD_TRAPPED - if (ins(d, "CLD_TRAPPED", (long)CLD_TRAPPED)) return -1; + if (PyModule_AddIntMacro(m, CLD_TRAPPED)) return -1; #endif #ifdef CLD_CONTINUED - if (ins(d, "CLD_CONTINUED", (long)CLD_CONTINUED)) return -1; + if (PyModule_AddIntMacro(m, CLD_CONTINUED)) return -1; #endif /* constants for lockf */ #ifdef F_LOCK - if (ins(d, "F_LOCK", (long)F_LOCK)) return -1; + if (PyModule_AddIntMacro(m, F_LOCK)) return -1; #endif #ifdef F_TLOCK - if (ins(d, "F_TLOCK", (long)F_TLOCK)) return -1; + if (PyModule_AddIntMacro(m, F_TLOCK)) return -1; #endif #ifdef F_ULOCK - if (ins(d, "F_ULOCK", (long)F_ULOCK)) return -1; + if (PyModule_AddIntMacro(m, F_ULOCK)) return -1; #endif #ifdef F_TEST - if (ins(d, "F_TEST", (long)F_TEST)) return -1; + if (PyModule_AddIntMacro(m, F_TEST)) return -1; #endif #ifdef HAVE_SPAWNV - if (ins(d, "P_WAIT", (long)_P_WAIT)) return -1; - if (ins(d, "P_NOWAIT", (long)_P_NOWAIT)) return -1; - if (ins(d, "P_OVERLAY", (long)_OLD_P_OVERLAY)) return -1; - if (ins(d, "P_NOWAITO", (long)_P_NOWAITO)) return -1; - if (ins(d, "P_DETACH", (long)_P_DETACH)) return -1; + if (PyModule_AddIntConstant(m, "P_WAIT", _P_WAIT)) return -1; + if (PyModule_AddIntConstant(m, "P_NOWAIT", _P_NOWAIT)) return -1; + if (PyModule_AddIntConstant(m, "P_OVERLAY", _OLD_P_OVERLAY)) return -1; + if (PyModule_AddIntConstant(m, "P_NOWAITO", _P_NOWAITO)) return -1; + if (PyModule_AddIntConstant(m, "P_DETACH", _P_DETACH)) return -1; #endif #ifdef HAVE_SCHED_H - if (ins(d, "SCHED_OTHER", (long)SCHED_OTHER)) return -1; - if (ins(d, "SCHED_FIFO", (long)SCHED_FIFO)) return -1; - if (ins(d, "SCHED_RR", (long)SCHED_RR)) return -1; + if (PyModule_AddIntMacro(m, SCHED_OTHER)) return -1; + if (PyModule_AddIntMacro(m, SCHED_FIFO)) return -1; + if (PyModule_AddIntMacro(m, SCHED_RR)) return -1; #ifdef SCHED_SPORADIC - if (ins(d, "SCHED_SPORADIC", (long)SCHED_SPORADIC) return -1; + if (PyModule_AddIntMacro(m, SCHED_SPORADIC) return -1; #endif #ifdef SCHED_BATCH - if (ins(d, "SCHED_BATCH", (long)SCHED_BATCH)) return -1; + if (PyModule_AddIntMacro(m, SCHED_BATCH)) return -1; #endif #ifdef SCHED_IDLE - if (ins(d, "SCHED_IDLE", (long)SCHED_IDLE)) return -1; + if (PyModule_AddIntMacro(m, SCHED_IDLE)) return -1; #endif #ifdef SCHED_RESET_ON_FORK - if (ins(d, "SCHED_RESET_ON_FORK", (long)SCHED_RESET_ON_FORK)) return -1; + if (PyModule_AddIntMacro(m, SCHED_RESET_ON_FORK)) return -1; #endif #ifdef SCHED_SYS - if (ins(d, "SCHED_SYS", (long)SCHED_SYS)) return -1; + if (PyModule_AddIntMacro(m, SCHED_SYS)) return -1; #endif #ifdef SCHED_IA - if (ins(d, "SCHED_IA", (long)SCHED_IA)) return -1; + if (PyModule_AddIntMacro(m, SCHED_IA)) return -1; #endif #ifdef SCHED_FSS - if (ins(d, "SCHED_FSS", (long)SCHED_FSS)) return -1; + if (PyModule_AddIntMacro(m, SCHED_FSS)) return -1; #endif #ifdef SCHED_FX - if (ins(d, "SCHED_FX", (long)SCHED_FSS)) return -1; + if (PyModule_AddIntConstant(m, "SCHED_FX", SCHED_FSS)) return -1; #endif #endif #ifdef USE_XATTRS - if (ins(d, "XATTR_CREATE", (long)XATTR_CREATE)) return -1; - if (ins(d, "XATTR_REPLACE", (long)XATTR_REPLACE)) return -1; - if (ins(d, "XATTR_SIZE_MAX", (long)XATTR_SIZE_MAX)) return -1; + if (PyModule_AddIntMacro(m, XATTR_CREATE)) return -1; + if (PyModule_AddIntMacro(m, XATTR_REPLACE)) return -1; + if (PyModule_AddIntMacro(m, XATTR_SIZE_MAX)) return -1; #endif #ifdef RTLD_LAZY - if (PyModule_AddIntMacro(d, RTLD_LAZY)) return -1; + if (PyModule_AddIntMacro(m, RTLD_LAZY)) return -1; #endif #ifdef RTLD_NOW - if (PyModule_AddIntMacro(d, RTLD_NOW)) return -1; + if (PyModule_AddIntMacro(m, RTLD_NOW)) return -1; #endif #ifdef RTLD_GLOBAL - if (PyModule_AddIntMacro(d, RTLD_GLOBAL)) return -1; + if (PyModule_AddIntMacro(m, RTLD_GLOBAL)) return -1; #endif #ifdef RTLD_LOCAL - if (PyModule_AddIntMacro(d, RTLD_LOCAL)) return -1; + if (PyModule_AddIntMacro(m, RTLD_LOCAL)) return -1; #endif #ifdef RTLD_NODELETE - if (PyModule_AddIntMacro(d, RTLD_NODELETE)) return -1; + if (PyModule_AddIntMacro(m, RTLD_NODELETE)) return -1; #endif #ifdef RTLD_NOLOAD - if (PyModule_AddIntMacro(d, RTLD_NOLOAD)) return -1; + if (PyModule_AddIntMacro(m, RTLD_NOLOAD)) return -1; #endif #ifdef RTLD_DEEPBIND - if (PyModule_AddIntMacro(d, RTLD_DEEPBIND)) return -1; + if (PyModule_AddIntMacro(m, RTLD_DEEPBIND)) return -1; #endif return 0; diff --git a/Modules/resource.c b/Modules/resource.c --- a/Modules/resource.c +++ b/Modules/resource.c @@ -272,71 +272,71 @@ /* insert constants */ #ifdef RLIMIT_CPU - PyModule_AddIntConstant(m, "RLIMIT_CPU", RLIMIT_CPU); + PyModule_AddIntMacro(m, RLIMIT_CPU); #endif #ifdef RLIMIT_FSIZE - PyModule_AddIntConstant(m, "RLIMIT_FSIZE", RLIMIT_FSIZE); + PyModule_AddIntMacro(m, RLIMIT_FSIZE); #endif #ifdef RLIMIT_DATA - PyModule_AddIntConstant(m, "RLIMIT_DATA", RLIMIT_DATA); + PyModule_AddIntMacro(m, RLIMIT_DATA); #endif #ifdef RLIMIT_STACK - PyModule_AddIntConstant(m, "RLIMIT_STACK", RLIMIT_STACK); + PyModule_AddIntMacro(m, RLIMIT_STACK); #endif #ifdef RLIMIT_CORE - PyModule_AddIntConstant(m, "RLIMIT_CORE", RLIMIT_CORE); + PyModule_AddIntMacro(m, RLIMIT_CORE); #endif #ifdef RLIMIT_NOFILE - PyModule_AddIntConstant(m, "RLIMIT_NOFILE", RLIMIT_NOFILE); + PyModule_AddIntMacro(m, RLIMIT_NOFILE); #endif #ifdef RLIMIT_OFILE - PyModule_AddIntConstant(m, "RLIMIT_OFILE", RLIMIT_OFILE); + PyModule_AddIntMacro(m, RLIMIT_OFILE); #endif #ifdef RLIMIT_VMEM - PyModule_AddIntConstant(m, "RLIMIT_VMEM", RLIMIT_VMEM); + PyModule_AddIntMacro(m, RLIMIT_VMEM); #endif #ifdef RLIMIT_AS - PyModule_AddIntConstant(m, "RLIMIT_AS", RLIMIT_AS); + PyModule_AddIntMacro(m, RLIMIT_AS); #endif #ifdef RLIMIT_RSS - PyModule_AddIntConstant(m, "RLIMIT_RSS", RLIMIT_RSS); + PyModule_AddIntMacro(m, RLIMIT_RSS); #endif #ifdef RLIMIT_NPROC - PyModule_AddIntConstant(m, "RLIMIT_NPROC", RLIMIT_NPROC); + PyModule_AddIntMacro(m, RLIMIT_NPROC); #endif #ifdef RLIMIT_MEMLOCK - PyModule_AddIntConstant(m, "RLIMIT_MEMLOCK", RLIMIT_MEMLOCK); + PyModule_AddIntMacro(m, RLIMIT_MEMLOCK); #endif #ifdef RLIMIT_SBSIZE - PyModule_AddIntConstant(m, "RLIMIT_SBSIZE", RLIMIT_SBSIZE); + PyModule_AddIntMacro(m, RLIMIT_SBSIZE); #endif #ifdef RUSAGE_SELF - PyModule_AddIntConstant(m, "RUSAGE_SELF", RUSAGE_SELF); + PyModule_AddIntMacro(m, RUSAGE_SELF); #endif #ifdef RUSAGE_CHILDREN - PyModule_AddIntConstant(m, "RUSAGE_CHILDREN", RUSAGE_CHILDREN); + PyModule_AddIntMacro(m, RUSAGE_CHILDREN); #endif #ifdef RUSAGE_BOTH - PyModule_AddIntConstant(m, "RUSAGE_BOTH", RUSAGE_BOTH); + PyModule_AddIntMacro(m, RUSAGE_BOTH); #endif #ifdef RUSAGE_THREAD - PyModule_AddIntConstant(m, "RUSAGE_THREAD", RUSAGE_THREAD); + PyModule_AddIntMacro(m, RUSAGE_THREAD); #endif #if defined(HAVE_LONG_LONG) diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -2183,7 +2183,7 @@ #undef PIPE_BUF #define PIPE_BUF 512 #endif - PyModule_AddIntConstant(m, "PIPE_BUF", PIPE_BUF); + PyModule_AddIntMacro(m, PIPE_BUF); #endif #if defined(HAVE_POLL) && !defined(HAVE_BROKEN_POLL) @@ -2198,27 +2198,27 @@ #endif if (PyType_Ready(&poll_Type) < 0) return NULL; - PyModule_AddIntConstant(m, "POLLIN", POLLIN); - PyModule_AddIntConstant(m, "POLLPRI", POLLPRI); - PyModule_AddIntConstant(m, "POLLOUT", POLLOUT); - PyModule_AddIntConstant(m, "POLLERR", POLLERR); - PyModule_AddIntConstant(m, "POLLHUP", POLLHUP); - PyModule_AddIntConstant(m, "POLLNVAL", POLLNVAL); + PyModule_AddIntMacro(m, POLLIN); + PyModule_AddIntMacro(m, POLLPRI); + PyModule_AddIntMacro(m, POLLOUT); + PyModule_AddIntMacro(m, POLLERR); + PyModule_AddIntMacro(m, POLLHUP); + PyModule_AddIntMacro(m, POLLNVAL); #ifdef POLLRDNORM - PyModule_AddIntConstant(m, "POLLRDNORM", POLLRDNORM); + PyModule_AddIntMacro(m, POLLRDNORM); #endif #ifdef POLLRDBAND - PyModule_AddIntConstant(m, "POLLRDBAND", POLLRDBAND); + PyModule_AddIntMacro(m, POLLRDBAND); #endif #ifdef POLLWRNORM - PyModule_AddIntConstant(m, "POLLWRNORM", POLLWRNORM); + PyModule_AddIntMacro(m, POLLWRNORM); #endif #ifdef POLLWRBAND - PyModule_AddIntConstant(m, "POLLWRBAND", POLLWRBAND); + PyModule_AddIntMacro(m, POLLWRBAND); #endif #ifdef POLLMSG - PyModule_AddIntConstant(m, "POLLMSG", POLLMSG); + PyModule_AddIntMacro(m, POLLMSG); #endif } #endif /* HAVE_POLL */ @@ -2236,25 +2236,25 @@ Py_INCREF(&pyEpoll_Type); PyModule_AddObject(m, "epoll", (PyObject *) &pyEpoll_Type); - PyModule_AddIntConstant(m, "EPOLLIN", EPOLLIN); - PyModule_AddIntConstant(m, "EPOLLOUT", EPOLLOUT); - PyModule_AddIntConstant(m, "EPOLLPRI", EPOLLPRI); - PyModule_AddIntConstant(m, "EPOLLERR", EPOLLERR); - PyModule_AddIntConstant(m, "EPOLLHUP", EPOLLHUP); - PyModule_AddIntConstant(m, "EPOLLET", EPOLLET); + PyModule_AddIntMacro(m, EPOLLIN); + PyModule_AddIntMacro(m, EPOLLOUT); + PyModule_AddIntMacro(m, EPOLLPRI); + PyModule_AddIntMacro(m, EPOLLERR); + PyModule_AddIntMacro(m, EPOLLHUP); + PyModule_AddIntMacro(m, EPOLLET); #ifdef EPOLLONESHOT /* Kernel 2.6.2+ */ - PyModule_AddIntConstant(m, "EPOLLONESHOT", EPOLLONESHOT); + PyModule_AddIntMacro(m, EPOLLONESHOT); #endif /* PyModule_AddIntConstant(m, "EPOLL_RDHUP", EPOLLRDHUP); */ - PyModule_AddIntConstant(m, "EPOLLRDNORM", EPOLLRDNORM); - PyModule_AddIntConstant(m, "EPOLLRDBAND", EPOLLRDBAND); - PyModule_AddIntConstant(m, "EPOLLWRNORM", EPOLLWRNORM); - PyModule_AddIntConstant(m, "EPOLLWRBAND", EPOLLWRBAND); - PyModule_AddIntConstant(m, "EPOLLMSG", EPOLLMSG); + PyModule_AddIntMacro(m, EPOLLRDNORM); + PyModule_AddIntMacro(m, EPOLLRDBAND); + PyModule_AddIntMacro(m, EPOLLWRNORM); + PyModule_AddIntMacro(m, EPOLLWRBAND); + PyModule_AddIntMacro(m, EPOLLMSG); #ifdef EPOLL_CLOEXEC - PyModule_AddIntConstant(m, "EPOLL_CLOEXEC", EPOLL_CLOEXEC); + PyModule_AddIntMacro(m, EPOLL_CLOEXEC); #endif #endif /* HAVE_EPOLL */ diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -5556,184 +5556,184 @@ /* Address families (we only support AF_INET and AF_UNIX) */ #ifdef AF_UNSPEC - PyModule_AddIntConstant(m, "AF_UNSPEC", AF_UNSPEC); -#endif - PyModule_AddIntConstant(m, "AF_INET", AF_INET); + PyModule_AddIntMacro(m, AF_UNSPEC); +#endif + PyModule_AddIntMacro(m, AF_INET); #ifdef AF_INET6 - PyModule_AddIntConstant(m, "AF_INET6", AF_INET6); + PyModule_AddIntMacro(m, AF_INET6); #endif /* AF_INET6 */ #if defined(AF_UNIX) - PyModule_AddIntConstant(m, "AF_UNIX", AF_UNIX); + PyModule_AddIntMacro(m, AF_UNIX); #endif /* AF_UNIX */ #ifdef AF_AX25 /* Amateur Radio AX.25 */ - PyModule_AddIntConstant(m, "AF_AX25", AF_AX25); + PyModule_AddIntMacro(m, AF_AX25); #endif #ifdef AF_IPX - PyModule_AddIntConstant(m, "AF_IPX", AF_IPX); /* Novell IPX */ + PyModule_AddIntMacro(m, AF_IPX); /* Novell IPX */ #endif #ifdef AF_APPLETALK /* Appletalk DDP */ - PyModule_AddIntConstant(m, "AF_APPLETALK", AF_APPLETALK); + PyModule_AddIntMacro(m, AF_APPLETALK); #endif #ifdef AF_NETROM /* Amateur radio NetROM */ - PyModule_AddIntConstant(m, "AF_NETROM", AF_NETROM); + PyModule_AddIntMacro(m, AF_NETROM); #endif #ifdef AF_BRIDGE /* Multiprotocol bridge */ - PyModule_AddIntConstant(m, "AF_BRIDGE", AF_BRIDGE); + PyModule_AddIntMacro(m, AF_BRIDGE); #endif #ifdef AF_ATMPVC /* ATM PVCs */ - PyModule_AddIntConstant(m, "AF_ATMPVC", AF_ATMPVC); + PyModule_AddIntMacro(m, AF_ATMPVC); #endif #ifdef AF_AAL5 /* Reserved for Werner's ATM */ - PyModule_AddIntConstant(m, "AF_AAL5", AF_AAL5); + PyModule_AddIntMacro(m, AF_AAL5); #endif #ifdef AF_X25 /* Reserved for X.25 project */ - PyModule_AddIntConstant(m, "AF_X25", AF_X25); + PyModule_AddIntMacro(m, AF_X25); #endif #ifdef AF_INET6 - PyModule_AddIntConstant(m, "AF_INET6", AF_INET6); /* IP version 6 */ + PyModule_AddIntMacro(m, AF_INET6); /* IP version 6 */ #endif #ifdef AF_ROSE /* Amateur Radio X.25 PLP */ - PyModule_AddIntConstant(m, "AF_ROSE", AF_ROSE); + PyModule_AddIntMacro(m, AF_ROSE); #endif #ifdef AF_DECnet /* Reserved for DECnet project */ - PyModule_AddIntConstant(m, "AF_DECnet", AF_DECnet); + PyModule_AddIntMacro(m, AF_DECnet); #endif #ifdef AF_NETBEUI /* Reserved for 802.2LLC project */ - PyModule_AddIntConstant(m, "AF_NETBEUI", AF_NETBEUI); + PyModule_AddIntMacro(m, AF_NETBEUI); #endif #ifdef AF_SECURITY /* Security callback pseudo AF */ - PyModule_AddIntConstant(m, "AF_SECURITY", AF_SECURITY); + PyModule_AddIntMacro(m, AF_SECURITY); #endif #ifdef AF_KEY /* PF_KEY key management API */ - PyModule_AddIntConstant(m, "AF_KEY", AF_KEY); + PyModule_AddIntMacro(m, AF_KEY); #endif #ifdef AF_NETLINK /* */ - PyModule_AddIntConstant(m, "AF_NETLINK", AF_NETLINK); - PyModule_AddIntConstant(m, "NETLINK_ROUTE", NETLINK_ROUTE); + PyModule_AddIntMacro(m, AF_NETLINK); + PyModule_AddIntMacro(m, NETLINK_ROUTE); #ifdef NETLINK_SKIP - PyModule_AddIntConstant(m, "NETLINK_SKIP", NETLINK_SKIP); + PyModule_AddIntMacro(m, NETLINK_SKIP); #endif #ifdef NETLINK_W1 - PyModule_AddIntConstant(m, "NETLINK_W1", NETLINK_W1); -#endif - PyModule_AddIntConstant(m, "NETLINK_USERSOCK", NETLINK_USERSOCK); - PyModule_AddIntConstant(m, "NETLINK_FIREWALL", NETLINK_FIREWALL); + PyModule_AddIntMacro(m, NETLINK_W1); +#endif + PyModule_AddIntMacro(m, NETLINK_USERSOCK); + PyModule_AddIntMacro(m, NETLINK_FIREWALL); #ifdef NETLINK_TCPDIAG - PyModule_AddIntConstant(m, "NETLINK_TCPDIAG", NETLINK_TCPDIAG); + PyModule_AddIntMacro(m, NETLINK_TCPDIAG); #endif #ifdef NETLINK_NFLOG - PyModule_AddIntConstant(m, "NETLINK_NFLOG", NETLINK_NFLOG); + PyModule_AddIntMacro(m, NETLINK_NFLOG); #endif #ifdef NETLINK_XFRM - PyModule_AddIntConstant(m, "NETLINK_XFRM", NETLINK_XFRM); + PyModule_AddIntMacro(m, NETLINK_XFRM); #endif #ifdef NETLINK_ARPD - PyModule_AddIntConstant(m, "NETLINK_ARPD", NETLINK_ARPD); + PyModule_AddIntMacro(m, NETLINK_ARPD); #endif #ifdef NETLINK_ROUTE6 - PyModule_AddIntConstant(m, "NETLINK_ROUTE6", NETLINK_ROUTE6); -#endif - PyModule_AddIntConstant(m, "NETLINK_IP6_FW", NETLINK_IP6_FW); + PyModule_AddIntMacro(m, NETLINK_ROUTE6); +#endif + PyModule_AddIntMacro(m, NETLINK_IP6_FW); #ifdef NETLINK_DNRTMSG - PyModule_AddIntConstant(m, "NETLINK_DNRTMSG", NETLINK_DNRTMSG); + PyModule_AddIntMacro(m, NETLINK_DNRTMSG); #endif #ifdef NETLINK_TAPBASE - PyModule_AddIntConstant(m, "NETLINK_TAPBASE", NETLINK_TAPBASE); + PyModule_AddIntMacro(m, NETLINK_TAPBASE); #endif #endif /* AF_NETLINK */ #ifdef AF_ROUTE /* Alias to emulate 4.4BSD */ - PyModule_AddIntConstant(m, "AF_ROUTE", AF_ROUTE); + PyModule_AddIntMacro(m, AF_ROUTE); #endif #ifdef AF_ASH /* Ash */ - PyModule_AddIntConstant(m, "AF_ASH", AF_ASH); + PyModule_AddIntMacro(m, AF_ASH); #endif #ifdef AF_ECONET /* Acorn Econet */ - PyModule_AddIntConstant(m, "AF_ECONET", AF_ECONET); + PyModule_AddIntMacro(m, AF_ECONET); #endif #ifdef AF_ATMSVC /* ATM SVCs */ - PyModule_AddIntConstant(m, "AF_ATMSVC", AF_ATMSVC); + PyModule_AddIntMacro(m, AF_ATMSVC); #endif #ifdef AF_SNA /* Linux SNA Project (nutters!) */ - PyModule_AddIntConstant(m, "AF_SNA", AF_SNA); + PyModule_AddIntMacro(m, AF_SNA); #endif #ifdef AF_IRDA /* IRDA sockets */ - PyModule_AddIntConstant(m, "AF_IRDA", AF_IRDA); + PyModule_AddIntMacro(m, AF_IRDA); #endif #ifdef AF_PPPOX /* PPPoX sockets */ - PyModule_AddIntConstant(m, "AF_PPPOX", AF_PPPOX); + PyModule_AddIntMacro(m, AF_PPPOX); #endif #ifdef AF_WANPIPE /* Wanpipe API Sockets */ - PyModule_AddIntConstant(m, "AF_WANPIPE", AF_WANPIPE); + PyModule_AddIntMacro(m, AF_WANPIPE); #endif #ifdef AF_LLC /* Linux LLC */ - PyModule_AddIntConstant(m, "AF_LLC", AF_LLC); + PyModule_AddIntMacro(m, AF_LLC); #endif #ifdef USE_BLUETOOTH - PyModule_AddIntConstant(m, "AF_BLUETOOTH", AF_BLUETOOTH); - PyModule_AddIntConstant(m, "BTPROTO_L2CAP", BTPROTO_L2CAP); - PyModule_AddIntConstant(m, "BTPROTO_HCI", BTPROTO_HCI); - PyModule_AddIntConstant(m, "SOL_HCI", SOL_HCI); + PyModule_AddIntMacro(m, AF_BLUETOOTH); + PyModule_AddIntMacro(m, BTPROTO_L2CAP); + PyModule_AddIntMacro(m, BTPROTO_HCI); + PyModule_AddIntMacro(m, SOL_HCI); #if !defined(__NetBSD__) && !defined(__DragonFly__) - PyModule_AddIntConstant(m, "HCI_FILTER", HCI_FILTER); + PyModule_AddIntMacro(m, HCI_FILTER); #endif #if !defined(__FreeBSD__) #if !defined(__NetBSD__) && !defined(__DragonFly__) - PyModule_AddIntConstant(m, "HCI_TIME_STAMP", HCI_TIME_STAMP); -#endif - PyModule_AddIntConstant(m, "HCI_DATA_DIR", HCI_DATA_DIR); - PyModule_AddIntConstant(m, "BTPROTO_SCO", BTPROTO_SCO); -#endif - PyModule_AddIntConstant(m, "BTPROTO_RFCOMM", BTPROTO_RFCOMM); + PyModule_AddIntMacro(m, HCI_TIME_STAMP); +#endif + PyModule_AddIntMacro(m, HCI_DATA_DIR); + PyModule_AddIntMacro(m, BTPROTO_SCO); +#endif + PyModule_AddIntMacro(m, BTPROTO_RFCOMM); PyModule_AddStringConstant(m, "BDADDR_ANY", "00:00:00:00:00:00"); PyModule_AddStringConstant(m, "BDADDR_LOCAL", "00:00:00:FF:FF:FF"); #endif #ifdef AF_CAN /* Controller Area Network */ - PyModule_AddIntConstant(m, "AF_CAN", AF_CAN); + PyModule_AddIntMacro(m, AF_CAN); #endif #ifdef PF_CAN /* Controller Area Network */ - PyModule_AddIntConstant(m, "PF_CAN", PF_CAN); + PyModule_AddIntMacro(m, PF_CAN); #endif /* Reliable Datagram Sockets */ #ifdef AF_RDS - PyModule_AddIntConstant(m, "AF_RDS", AF_RDS); + PyModule_AddIntMacro(m, AF_RDS); #endif #ifdef PF_RDS - PyModule_AddIntConstant(m, "PF_RDS", PF_RDS); + PyModule_AddIntMacro(m, PF_RDS); #endif /* Kernel event messages */ #ifdef PF_SYSTEM - PyModule_AddIntConstant(m, "PF_SYSTEM", PF_SYSTEM); + PyModule_AddIntMacro(m, PF_SYSTEM); #endif #ifdef AF_SYSTEM - PyModule_AddIntConstant(m, "AF_SYSTEM", AF_SYSTEM); + PyModule_AddIntMacro(m, AF_SYSTEM); #endif #ifdef AF_PACKET @@ -5765,134 +5765,129 @@ #endif #ifdef HAVE_LINUX_TIPC_H - PyModule_AddIntConstant(m, "AF_TIPC", AF_TIPC); + PyModule_AddIntMacro(m, AF_TIPC); /* for addresses */ - PyModule_AddIntConstant(m, "TIPC_ADDR_NAMESEQ", TIPC_ADDR_NAMESEQ); - PyModule_AddIntConstant(m, "TIPC_ADDR_NAME", TIPC_ADDR_NAME); - PyModule_AddIntConstant(m, "TIPC_ADDR_ID", TIPC_ADDR_ID); - - PyModule_AddIntConstant(m, "TIPC_ZONE_SCOPE", TIPC_ZONE_SCOPE); - PyModule_AddIntConstant(m, "TIPC_CLUSTER_SCOPE", TIPC_CLUSTER_SCOPE); - PyModule_AddIntConstant(m, "TIPC_NODE_SCOPE", TIPC_NODE_SCOPE); + PyModule_AddIntMacro(m, TIPC_ADDR_NAMESEQ); + PyModule_AddIntMacro(m, TIPC_ADDR_NAME); + PyModule_AddIntMacro(m, TIPC_ADDR_ID); + + PyModule_AddIntMacro(m, TIPC_ZONE_SCOPE); + PyModule_AddIntMacro(m, TIPC_CLUSTER_SCOPE); + PyModule_AddIntMacro(m, TIPC_NODE_SCOPE); /* for setsockopt() */ - PyModule_AddIntConstant(m, "SOL_TIPC", SOL_TIPC); - PyModule_AddIntConstant(m, "TIPC_IMPORTANCE", TIPC_IMPORTANCE); - PyModule_AddIntConstant(m, "TIPC_SRC_DROPPABLE", TIPC_SRC_DROPPABLE); - PyModule_AddIntConstant(m, "TIPC_DEST_DROPPABLE", - TIPC_DEST_DROPPABLE); - PyModule_AddIntConstant(m, "TIPC_CONN_TIMEOUT", TIPC_CONN_TIMEOUT); - - PyModule_AddIntConstant(m, "TIPC_LOW_IMPORTANCE", - TIPC_LOW_IMPORTANCE); - PyModule_AddIntConstant(m, "TIPC_MEDIUM_IMPORTANCE", - TIPC_MEDIUM_IMPORTANCE); - PyModule_AddIntConstant(m, "TIPC_HIGH_IMPORTANCE", - TIPC_HIGH_IMPORTANCE); - PyModule_AddIntConstant(m, "TIPC_CRITICAL_IMPORTANCE", - TIPC_CRITICAL_IMPORTANCE); + PyModule_AddIntMacro(m, SOL_TIPC); + PyModule_AddIntMacro(m, TIPC_IMPORTANCE); + PyModule_AddIntMacro(m, TIPC_SRC_DROPPABLE); + PyModule_AddIntMacro(m, TIPC_DEST_DROPPABLE); + PyModule_AddIntMacro(m, TIPC_CONN_TIMEOUT); + + PyModule_AddIntMacro(m, TIPC_LOW_IMPORTANCE); + PyModule_AddIntMacro(m, TIPC_MEDIUM_IMPORTANCE); + PyModule_AddIntMacro(m, TIPC_HIGH_IMPORTANCE); + PyModule_AddIntMacro(m, TIPC_CRITICAL_IMPORTANCE); /* for subscriptions */ - PyModule_AddIntConstant(m, "TIPC_SUB_PORTS", TIPC_SUB_PORTS); - PyModule_AddIntConstant(m, "TIPC_SUB_SERVICE", TIPC_SUB_SERVICE); + PyModule_AddIntMacro(m, TIPC_SUB_PORTS); + PyModule_AddIntMacro(m, TIPC_SUB_SERVICE); #ifdef TIPC_SUB_CANCEL /* doesn't seem to be available everywhere */ - PyModule_AddIntConstant(m, "TIPC_SUB_CANCEL", TIPC_SUB_CANCEL); -#endif - PyModule_AddIntConstant(m, "TIPC_WAIT_FOREVER", TIPC_WAIT_FOREVER); - PyModule_AddIntConstant(m, "TIPC_PUBLISHED", TIPC_PUBLISHED); - PyModule_AddIntConstant(m, "TIPC_WITHDRAWN", TIPC_WITHDRAWN); - PyModule_AddIntConstant(m, "TIPC_SUBSCR_TIMEOUT", TIPC_SUBSCR_TIMEOUT); - PyModule_AddIntConstant(m, "TIPC_CFG_SRV", TIPC_CFG_SRV); - PyModule_AddIntConstant(m, "TIPC_TOP_SRV", TIPC_TOP_SRV); + PyModule_AddIntMacro(m, TIPC_SUB_CANCEL); +#endif + PyModule_AddIntMacro(m, TIPC_WAIT_FOREVER); + PyModule_AddIntMacro(m, TIPC_PUBLISHED); + PyModule_AddIntMacro(m, TIPC_WITHDRAWN); + PyModule_AddIntMacro(m, TIPC_SUBSCR_TIMEOUT); + PyModule_AddIntMacro(m, TIPC_CFG_SRV); + PyModule_AddIntMacro(m, TIPC_TOP_SRV); #endif /* Socket types */ - PyModule_AddIntConstant(m, "SOCK_STREAM", SOCK_STREAM); - PyModule_AddIntConstant(m, "SOCK_DGRAM", SOCK_DGRAM); + PyModule_AddIntMacro(m, SOCK_STREAM); + PyModule_AddIntMacro(m, SOCK_DGRAM); /* We have incomplete socket support. */ - PyModule_AddIntConstant(m, "SOCK_RAW", SOCK_RAW); - PyModule_AddIntConstant(m, "SOCK_SEQPACKET", SOCK_SEQPACKET); + PyModule_AddIntMacro(m, SOCK_RAW); + PyModule_AddIntMacro(m, SOCK_SEQPACKET); #if defined(SOCK_RDM) - PyModule_AddIntConstant(m, "SOCK_RDM", SOCK_RDM); + PyModule_AddIntMacro(m, SOCK_RDM); #endif #ifdef SOCK_CLOEXEC - PyModule_AddIntConstant(m, "SOCK_CLOEXEC", SOCK_CLOEXEC); + PyModule_AddIntMacro(m, SOCK_CLOEXEC); #endif #ifdef SOCK_NONBLOCK - PyModule_AddIntConstant(m, "SOCK_NONBLOCK", SOCK_NONBLOCK); + PyModule_AddIntMacro(m, SOCK_NONBLOCK); #endif #ifdef SO_DEBUG - PyModule_AddIntConstant(m, "SO_DEBUG", SO_DEBUG); + PyModule_AddIntMacro(m, SO_DEBUG); #endif #ifdef SO_ACCEPTCONN - PyModule_AddIntConstant(m, "SO_ACCEPTCONN", SO_ACCEPTCONN); + PyModule_AddIntMacro(m, SO_ACCEPTCONN); #endif #ifdef SO_REUSEADDR - PyModule_AddIntConstant(m, "SO_REUSEADDR", SO_REUSEADDR); + PyModule_AddIntMacro(m, SO_REUSEADDR); #endif #ifdef SO_EXCLUSIVEADDRUSE - PyModule_AddIntConstant(m, "SO_EXCLUSIVEADDRUSE", SO_EXCLUSIVEADDRUSE); + PyModule_AddIntMacro(m, SO_EXCLUSIVEADDRUSE); #endif #ifdef SO_KEEPALIVE - PyModule_AddIntConstant(m, "SO_KEEPALIVE", SO_KEEPALIVE); + PyModule_AddIntMacro(m, SO_KEEPALIVE); #endif #ifdef SO_DONTROUTE - PyModule_AddIntConstant(m, "SO_DONTROUTE", SO_DONTROUTE); + PyModule_AddIntMacro(m, SO_DONTROUTE); #endif #ifdef SO_BROADCAST - PyModule_AddIntConstant(m, "SO_BROADCAST", SO_BROADCAST); + PyModule_AddIntMacro(m, SO_BROADCAST); #endif #ifdef SO_USELOOPBACK - PyModule_AddIntConstant(m, "SO_USELOOPBACK", SO_USELOOPBACK); + PyModule_AddIntMacro(m, SO_USELOOPBACK); #endif #ifdef SO_LINGER - PyModule_AddIntConstant(m, "SO_LINGER", SO_LINGER); + PyModule_AddIntMacro(m, SO_LINGER); #endif #ifdef SO_OOBINLINE - PyModule_AddIntConstant(m, "SO_OOBINLINE", SO_OOBINLINE); + PyModule_AddIntMacro(m, SO_OOBINLINE); #endif #ifdef SO_REUSEPORT - PyModule_AddIntConstant(m, "SO_REUSEPORT", SO_REUSEPORT); + PyModule_AddIntMacro(m, SO_REUSEPORT); #endif #ifdef SO_SNDBUF - PyModule_AddIntConstant(m, "SO_SNDBUF", SO_SNDBUF); + PyModule_AddIntMacro(m, SO_SNDBUF); #endif #ifdef SO_RCVBUF - PyModule_AddIntConstant(m, "SO_RCVBUF", SO_RCVBUF); + PyModule_AddIntMacro(m, SO_RCVBUF); #endif #ifdef SO_SNDLOWAT - PyModule_AddIntConstant(m, "SO_SNDLOWAT", SO_SNDLOWAT); + PyModule_AddIntMacro(m, SO_SNDLOWAT); #endif #ifdef SO_RCVLOWAT - PyModule_AddIntConstant(m, "SO_RCVLOWAT", SO_RCVLOWAT); + PyModule_AddIntMacro(m, SO_RCVLOWAT); #endif #ifdef SO_SNDTIMEO - PyModule_AddIntConstant(m, "SO_SNDTIMEO", SO_SNDTIMEO); + PyModule_AddIntMacro(m, SO_SNDTIMEO); #endif #ifdef SO_RCVTIMEO - PyModule_AddIntConstant(m, "SO_RCVTIMEO", SO_RCVTIMEO); + PyModule_AddIntMacro(m, SO_RCVTIMEO); #endif #ifdef SO_ERROR - PyModule_AddIntConstant(m, "SO_ERROR", SO_ERROR); + PyModule_AddIntMacro(m, SO_ERROR); #endif #ifdef SO_TYPE - PyModule_AddIntConstant(m, "SO_TYPE", SO_TYPE); + PyModule_AddIntMacro(m, SO_TYPE); #endif #ifdef SO_SETFIB - PyModule_AddIntConstant(m, "SO_SETFIB", SO_SETFIB); + PyModule_AddIntMacro(m, SO_SETFIB); #endif #ifdef SO_PASSCRED - PyModule_AddIntConstant(m, "SO_PASSCRED", SO_PASSCRED); + PyModule_AddIntMacro(m, SO_PASSCRED); #endif #ifdef SO_PEERCRED - PyModule_AddIntConstant(m, "SO_PEERCRED", SO_PEERCRED); + PyModule_AddIntMacro(m, SO_PEERCRED); #endif #ifdef LOCAL_PEERCRED - PyModule_AddIntConstant(m, "LOCAL_PEERCRED", LOCAL_PEERCRED); + PyModule_AddIntMacro(m, LOCAL_PEERCRED); #endif #ifdef SO_BINDTODEVICE PyModule_AddIntMacro(m, SO_BINDTODEVICE); @@ -5900,142 +5895,142 @@ /* Maximum number of connections for "listen" */ #ifdef SOMAXCONN - PyModule_AddIntConstant(m, "SOMAXCONN", SOMAXCONN); + PyModule_AddIntMacro(m, SOMAXCONN); #else PyModule_AddIntConstant(m, "SOMAXCONN", 5); /* Common value */ #endif /* Ancilliary message types */ #ifdef SCM_RIGHTS - PyModule_AddIntConstant(m, "SCM_RIGHTS", SCM_RIGHTS); + PyModule_AddIntMacro(m, SCM_RIGHTS); #endif #ifdef SCM_CREDENTIALS - PyModule_AddIntConstant(m, "SCM_CREDENTIALS", SCM_CREDENTIALS); + PyModule_AddIntMacro(m, SCM_CREDENTIALS); #endif #ifdef SCM_CREDS - PyModule_AddIntConstant(m, "SCM_CREDS", SCM_CREDS); + PyModule_AddIntMacro(m, SCM_CREDS); #endif /* Flags for send, recv */ #ifdef MSG_OOB - PyModule_AddIntConstant(m, "MSG_OOB", MSG_OOB); + PyModule_AddIntMacro(m, MSG_OOB); #endif #ifdef MSG_PEEK - PyModule_AddIntConstant(m, "MSG_PEEK", MSG_PEEK); + PyModule_AddIntMacro(m, MSG_PEEK); #endif #ifdef MSG_DONTROUTE - PyModule_AddIntConstant(m, "MSG_DONTROUTE", MSG_DONTROUTE); + PyModule_AddIntMacro(m, MSG_DONTROUTE); #endif #ifdef MSG_DONTWAIT - PyModule_AddIntConstant(m, "MSG_DONTWAIT", MSG_DONTWAIT); + PyModule_AddIntMacro(m, MSG_DONTWAIT); #endif #ifdef MSG_EOR - PyModule_AddIntConstant(m, "MSG_EOR", MSG_EOR); + PyModule_AddIntMacro(m, MSG_EOR); #endif #ifdef MSG_TRUNC - PyModule_AddIntConstant(m, "MSG_TRUNC", MSG_TRUNC); + PyModule_AddIntMacro(m, MSG_TRUNC); #endif #ifdef MSG_CTRUNC - PyModule_AddIntConstant(m, "MSG_CTRUNC", MSG_CTRUNC); + PyModule_AddIntMacro(m, MSG_CTRUNC); #endif #ifdef MSG_WAITALL - PyModule_AddIntConstant(m, "MSG_WAITALL", MSG_WAITALL); + PyModule_AddIntMacro(m, MSG_WAITALL); #endif #ifdef MSG_BTAG - PyModule_AddIntConstant(m, "MSG_BTAG", MSG_BTAG); + PyModule_AddIntMacro(m, MSG_BTAG); #endif #ifdef MSG_ETAG - PyModule_AddIntConstant(m, "MSG_ETAG", MSG_ETAG); + PyModule_AddIntMacro(m, MSG_ETAG); #endif #ifdef MSG_NOSIGNAL - PyModule_AddIntConstant(m, "MSG_NOSIGNAL", MSG_NOSIGNAL); + PyModule_AddIntMacro(m, MSG_NOSIGNAL); #endif #ifdef MSG_NOTIFICATION - PyModule_AddIntConstant(m, "MSG_NOTIFICATION", MSG_NOTIFICATION); + PyModule_AddIntMacro(m, MSG_NOTIFICATION); #endif #ifdef MSG_CMSG_CLOEXEC - PyModule_AddIntConstant(m, "MSG_CMSG_CLOEXEC", MSG_CMSG_CLOEXEC); + PyModule_AddIntMacro(m, MSG_CMSG_CLOEXEC); #endif #ifdef MSG_ERRQUEUE - PyModule_AddIntConstant(m, "MSG_ERRQUEUE", MSG_ERRQUEUE); + PyModule_AddIntMacro(m, MSG_ERRQUEUE); #endif #ifdef MSG_CONFIRM - PyModule_AddIntConstant(m, "MSG_CONFIRM", MSG_CONFIRM); + PyModule_AddIntMacro(m, MSG_CONFIRM); #endif #ifdef MSG_MORE - PyModule_AddIntConstant(m, "MSG_MORE", MSG_MORE); + PyModule_AddIntMacro(m, MSG_MORE); #endif #ifdef MSG_EOF - PyModule_AddIntConstant(m, "MSG_EOF", MSG_EOF); + PyModule_AddIntMacro(m, MSG_EOF); #endif #ifdef MSG_BCAST - PyModule_AddIntConstant(m, "MSG_BCAST", MSG_BCAST); + PyModule_AddIntMacro(m, MSG_BCAST); #endif #ifdef MSG_MCAST - PyModule_AddIntConstant(m, "MSG_MCAST", MSG_MCAST); + PyModule_AddIntMacro(m, MSG_MCAST); #endif #ifdef MSG_FASTOPEN - PyModule_AddIntConstant(m, "MSG_FASTOPEN", MSG_FASTOPEN); + PyModule_AddIntMacro(m, MSG_FASTOPEN); #endif /* Protocol level and numbers, usable for [gs]etsockopt */ #ifdef SOL_SOCKET - PyModule_AddIntConstant(m, "SOL_SOCKET", SOL_SOCKET); + PyModule_AddIntMacro(m, SOL_SOCKET); #endif #ifdef SOL_IP - PyModule_AddIntConstant(m, "SOL_IP", SOL_IP); + PyModule_AddIntMacro(m, SOL_IP); #else PyModule_AddIntConstant(m, "SOL_IP", 0); #endif #ifdef SOL_IPX - PyModule_AddIntConstant(m, "SOL_IPX", SOL_IPX); + PyModule_AddIntMacro(m, SOL_IPX); #endif #ifdef SOL_AX25 - PyModule_AddIntConstant(m, "SOL_AX25", SOL_AX25); + PyModule_AddIntMacro(m, SOL_AX25); #endif #ifdef SOL_ATALK - PyModule_AddIntConstant(m, "SOL_ATALK", SOL_ATALK); + PyModule_AddIntMacro(m, SOL_ATALK); #endif #ifdef SOL_NETROM - PyModule_AddIntConstant(m, "SOL_NETROM", SOL_NETROM); + PyModule_AddIntMacro(m, SOL_NETROM); #endif #ifdef SOL_ROSE - PyModule_AddIntConstant(m, "SOL_ROSE", SOL_ROSE); + PyModule_AddIntMacro(m, SOL_ROSE); #endif #ifdef SOL_TCP - PyModule_AddIntConstant(m, "SOL_TCP", SOL_TCP); + PyModule_AddIntMacro(m, SOL_TCP); #else PyModule_AddIntConstant(m, "SOL_TCP", 6); #endif #ifdef SOL_UDP - PyModule_AddIntConstant(m, "SOL_UDP", SOL_UDP); + PyModule_AddIntMacro(m, SOL_UDP); #else PyModule_AddIntConstant(m, "SOL_UDP", 17); #endif #ifdef SOL_CAN_BASE - PyModule_AddIntConstant(m, "SOL_CAN_BASE", SOL_CAN_BASE); + PyModule_AddIntMacro(m, SOL_CAN_BASE); #endif #ifdef SOL_CAN_RAW - PyModule_AddIntConstant(m, "SOL_CAN_RAW", SOL_CAN_RAW); - PyModule_AddIntConstant(m, "CAN_RAW", CAN_RAW); + PyModule_AddIntMacro(m, SOL_CAN_RAW); + PyModule_AddIntMacro(m, CAN_RAW); #endif #ifdef HAVE_LINUX_CAN_H - PyModule_AddIntConstant(m, "CAN_EFF_FLAG", CAN_EFF_FLAG); - PyModule_AddIntConstant(m, "CAN_RTR_FLAG", CAN_RTR_FLAG); - PyModule_AddIntConstant(m, "CAN_ERR_FLAG", CAN_ERR_FLAG); - - PyModule_AddIntConstant(m, "CAN_SFF_MASK", CAN_SFF_MASK); - PyModule_AddIntConstant(m, "CAN_EFF_MASK", CAN_EFF_MASK); - PyModule_AddIntConstant(m, "CAN_ERR_MASK", CAN_ERR_MASK); + PyModule_AddIntMacro(m, CAN_EFF_FLAG); + PyModule_AddIntMacro(m, CAN_RTR_FLAG); + PyModule_AddIntMacro(m, CAN_ERR_FLAG); + + PyModule_AddIntMacro(m, CAN_SFF_MASK); + PyModule_AddIntMacro(m, CAN_EFF_MASK); + PyModule_AddIntMacro(m, CAN_ERR_MASK); #endif #ifdef HAVE_LINUX_CAN_RAW_H - PyModule_AddIntConstant(m, "CAN_RAW_FILTER", CAN_RAW_FILTER); - PyModule_AddIntConstant(m, "CAN_RAW_ERR_FILTER", CAN_RAW_ERR_FILTER); - PyModule_AddIntConstant(m, "CAN_RAW_LOOPBACK", CAN_RAW_LOOPBACK); - PyModule_AddIntConstant(m, "CAN_RAW_RECV_OWN_MSGS", CAN_RAW_RECV_OWN_MSGS); + PyModule_AddIntMacro(m, CAN_RAW_FILTER); + PyModule_AddIntMacro(m, CAN_RAW_ERR_FILTER); + PyModule_AddIntMacro(m, CAN_RAW_LOOPBACK); + PyModule_AddIntMacro(m, CAN_RAW_RECV_OWN_MSGS); #endif #ifdef HAVE_LINUX_CAN_BCM_H - PyModule_AddIntConstant(m, "CAN_BCM", CAN_BCM); + PyModule_AddIntMacro(m, CAN_BCM); PyModule_AddIntConstant(m, "CAN_BCM_TX_SETUP", TX_SETUP); PyModule_AddIntConstant(m, "CAN_BCM_TX_DELETE", TX_DELETE); PyModule_AddIntConstant(m, "CAN_BCM_TX_READ", TX_READ); @@ -6050,180 +6045,180 @@ PyModule_AddIntConstant(m, "CAN_BCM_RX_CHANGED", RX_CHANGED); #endif #ifdef SOL_RDS - PyModule_AddIntConstant(m, "SOL_RDS", SOL_RDS); + PyModule_AddIntMacro(m, SOL_RDS); #endif #ifdef RDS_CANCEL_SENT_TO - PyModule_AddIntConstant(m, "RDS_CANCEL_SENT_TO", RDS_CANCEL_SENT_TO); + PyModule_AddIntMacro(m, RDS_CANCEL_SENT_TO); #endif #ifdef RDS_GET_MR - PyModule_AddIntConstant(m, "RDS_GET_MR", RDS_GET_MR); + PyModule_AddIntMacro(m, RDS_GET_MR); #endif #ifdef RDS_FREE_MR - PyModule_AddIntConstant(m, "RDS_FREE_MR", RDS_FREE_MR); + PyModule_AddIntMacro(m, RDS_FREE_MR); #endif #ifdef RDS_RECVERR - PyModule_AddIntConstant(m, "RDS_RECVERR", RDS_RECVERR); + PyModule_AddIntMacro(m, RDS_RECVERR); #endif #ifdef RDS_CONG_MONITOR - PyModule_AddIntConstant(m, "RDS_CONG_MONITOR", RDS_CONG_MONITOR); + PyModule_AddIntMacro(m, RDS_CONG_MONITOR); #endif #ifdef RDS_GET_MR_FOR_DEST - PyModule_AddIntConstant(m, "RDS_GET_MR_FOR_DEST", RDS_GET_MR_FOR_DEST); + PyModule_AddIntMacro(m, RDS_GET_MR_FOR_DEST); #endif #ifdef IPPROTO_IP - PyModule_AddIntConstant(m, "IPPROTO_IP", IPPROTO_IP); + PyModule_AddIntMacro(m, IPPROTO_IP); #else PyModule_AddIntConstant(m, "IPPROTO_IP", 0); #endif #ifdef IPPROTO_HOPOPTS - PyModule_AddIntConstant(m, "IPPROTO_HOPOPTS", IPPROTO_HOPOPTS); + PyModule_AddIntMacro(m, IPPROTO_HOPOPTS); #endif #ifdef IPPROTO_ICMP - PyModule_AddIntConstant(m, "IPPROTO_ICMP", IPPROTO_ICMP); + PyModule_AddIntMacro(m, IPPROTO_ICMP); #else PyModule_AddIntConstant(m, "IPPROTO_ICMP", 1); #endif #ifdef IPPROTO_IGMP - PyModule_AddIntConstant(m, "IPPROTO_IGMP", IPPROTO_IGMP); + PyModule_AddIntMacro(m, IPPROTO_IGMP); #endif #ifdef IPPROTO_GGP - PyModule_AddIntConstant(m, "IPPROTO_GGP", IPPROTO_GGP); + PyModule_AddIntMacro(m, IPPROTO_GGP); #endif #ifdef IPPROTO_IPV4 - PyModule_AddIntConstant(m, "IPPROTO_IPV4", IPPROTO_IPV4); + PyModule_AddIntMacro(m, IPPROTO_IPV4); #endif #ifdef IPPROTO_IPV6 - PyModule_AddIntConstant(m, "IPPROTO_IPV6", IPPROTO_IPV6); + PyModule_AddIntMacro(m, IPPROTO_IPV6); #endif #ifdef IPPROTO_IPIP - PyModule_AddIntConstant(m, "IPPROTO_IPIP", IPPROTO_IPIP); + PyModule_AddIntMacro(m, IPPROTO_IPIP); #endif #ifdef IPPROTO_TCP - PyModule_AddIntConstant(m, "IPPROTO_TCP", IPPROTO_TCP); + PyModule_AddIntMacro(m, IPPROTO_TCP); #else PyModule_AddIntConstant(m, "IPPROTO_TCP", 6); #endif #ifdef IPPROTO_EGP - PyModule_AddIntConstant(m, "IPPROTO_EGP", IPPROTO_EGP); + PyModule_AddIntMacro(m, IPPROTO_EGP); #endif #ifdef IPPROTO_PUP - PyModule_AddIntConstant(m, "IPPROTO_PUP", IPPROTO_PUP); + PyModule_AddIntMacro(m, IPPROTO_PUP); #endif #ifdef IPPROTO_UDP - PyModule_AddIntConstant(m, "IPPROTO_UDP", IPPROTO_UDP); + PyModule_AddIntMacro(m, IPPROTO_UDP); #else PyModule_AddIntConstant(m, "IPPROTO_UDP", 17); #endif #ifdef IPPROTO_IDP - PyModule_AddIntConstant(m, "IPPROTO_IDP", IPPROTO_IDP); + PyModule_AddIntMacro(m, IPPROTO_IDP); #endif #ifdef IPPROTO_HELLO - PyModule_AddIntConstant(m, "IPPROTO_HELLO", IPPROTO_HELLO); + PyModule_AddIntMacro(m, IPPROTO_HELLO); #endif #ifdef IPPROTO_ND - PyModule_AddIntConstant(m, "IPPROTO_ND", IPPROTO_ND); + PyModule_AddIntMacro(m, IPPROTO_ND); #endif #ifdef IPPROTO_TP - PyModule_AddIntConstant(m, "IPPROTO_TP", IPPROTO_TP); + PyModule_AddIntMacro(m, IPPROTO_TP); #endif #ifdef IPPROTO_IPV6 - PyModule_AddIntConstant(m, "IPPROTO_IPV6", IPPROTO_IPV6); + PyModule_AddIntMacro(m, IPPROTO_IPV6); #endif #ifdef IPPROTO_ROUTING - PyModule_AddIntConstant(m, "IPPROTO_ROUTING", IPPROTO_ROUTING); + PyModule_AddIntMacro(m, IPPROTO_ROUTING); #endif #ifdef IPPROTO_FRAGMENT - PyModule_AddIntConstant(m, "IPPROTO_FRAGMENT", IPPROTO_FRAGMENT); + PyModule_AddIntMacro(m, IPPROTO_FRAGMENT); #endif #ifdef IPPROTO_RSVP - PyModule_AddIntConstant(m, "IPPROTO_RSVP", IPPROTO_RSVP); + PyModule_AddIntMacro(m, IPPROTO_RSVP); #endif #ifdef IPPROTO_GRE - PyModule_AddIntConstant(m, "IPPROTO_GRE", IPPROTO_GRE); + PyModule_AddIntMacro(m, IPPROTO_GRE); #endif #ifdef IPPROTO_ESP - PyModule_AddIntConstant(m, "IPPROTO_ESP", IPPROTO_ESP); + PyModule_AddIntMacro(m, IPPROTO_ESP); #endif #ifdef IPPROTO_AH - PyModule_AddIntConstant(m, "IPPROTO_AH", IPPROTO_AH); + PyModule_AddIntMacro(m, IPPROTO_AH); #endif #ifdef IPPROTO_MOBILE - PyModule_AddIntConstant(m, "IPPROTO_MOBILE", IPPROTO_MOBILE); + PyModule_AddIntMacro(m, IPPROTO_MOBILE); #endif #ifdef IPPROTO_ICMPV6 - PyModule_AddIntConstant(m, "IPPROTO_ICMPV6", IPPROTO_ICMPV6); + PyModule_AddIntMacro(m, IPPROTO_ICMPV6); #endif #ifdef IPPROTO_NONE - PyModule_AddIntConstant(m, "IPPROTO_NONE", IPPROTO_NONE); + PyModule_AddIntMacro(m, IPPROTO_NONE); #endif #ifdef IPPROTO_DSTOPTS - PyModule_AddIntConstant(m, "IPPROTO_DSTOPTS", IPPROTO_DSTOPTS); + PyModule_AddIntMacro(m, IPPROTO_DSTOPTS); #endif #ifdef IPPROTO_XTP - PyModule_AddIntConstant(m, "IPPROTO_XTP", IPPROTO_XTP); + PyModule_AddIntMacro(m, IPPROTO_XTP); #endif #ifdef IPPROTO_EON - PyModule_AddIntConstant(m, "IPPROTO_EON", IPPROTO_EON); + PyModule_AddIntMacro(m, IPPROTO_EON); #endif #ifdef IPPROTO_PIM - PyModule_AddIntConstant(m, "IPPROTO_PIM", IPPROTO_PIM); + PyModule_AddIntMacro(m, IPPROTO_PIM); #endif #ifdef IPPROTO_IPCOMP - PyModule_AddIntConstant(m, "IPPROTO_IPCOMP", IPPROTO_IPCOMP); + PyModule_AddIntMacro(m, IPPROTO_IPCOMP); #endif #ifdef IPPROTO_VRRP - PyModule_AddIntConstant(m, "IPPROTO_VRRP", IPPROTO_VRRP); + PyModule_AddIntMacro(m, IPPROTO_VRRP); #endif #ifdef IPPROTO_SCTP - PyModule_AddIntConstant(m, "IPPROTO_SCTP", IPPROTO_SCTP); + PyModule_AddIntMacro(m, IPPROTO_SCTP); #endif #ifdef IPPROTO_BIP - PyModule_AddIntConstant(m, "IPPROTO_BIP", IPPROTO_BIP); + PyModule_AddIntMacro(m, IPPROTO_BIP); #endif /**/ #ifdef IPPROTO_RAW - PyModule_AddIntConstant(m, "IPPROTO_RAW", IPPROTO_RAW); + PyModule_AddIntMacro(m, IPPROTO_RAW); #else PyModule_AddIntConstant(m, "IPPROTO_RAW", 255); #endif #ifdef IPPROTO_MAX - PyModule_AddIntConstant(m, "IPPROTO_MAX", IPPROTO_MAX); + PyModule_AddIntMacro(m, IPPROTO_MAX); #endif #ifdef SYSPROTO_CONTROL - PyModule_AddIntConstant(m, "SYSPROTO_CONTROL", SYSPROTO_CONTROL); + PyModule_AddIntMacro(m, SYSPROTO_CONTROL); #endif /* Some port configuration */ #ifdef IPPORT_RESERVED - PyModule_AddIntConstant(m, "IPPORT_RESERVED", IPPORT_RESERVED); + PyModule_AddIntMacro(m, IPPORT_RESERVED); #else PyModule_AddIntConstant(m, "IPPORT_RESERVED", 1024); #endif #ifdef IPPORT_USERRESERVED - PyModule_AddIntConstant(m, "IPPORT_USERRESERVED", IPPORT_USERRESERVED); + PyModule_AddIntMacro(m, IPPORT_USERRESERVED); #else PyModule_AddIntConstant(m, "IPPORT_USERRESERVED", 5000); #endif /* Some reserved IP v.4 addresses */ #ifdef INADDR_ANY - PyModule_AddIntConstant(m, "INADDR_ANY", INADDR_ANY); + PyModule_AddIntMacro(m, INADDR_ANY); #else PyModule_AddIntConstant(m, "INADDR_ANY", 0x00000000); #endif #ifdef INADDR_BROADCAST - PyModule_AddIntConstant(m, "INADDR_BROADCAST", INADDR_BROADCAST); + PyModule_AddIntMacro(m, INADDR_BROADCAST); #else PyModule_AddIntConstant(m, "INADDR_BROADCAST", 0xffffffff); #endif #ifdef INADDR_LOOPBACK - PyModule_AddIntConstant(m, "INADDR_LOOPBACK", INADDR_LOOPBACK); + PyModule_AddIntMacro(m, INADDR_LOOPBACK); #else PyModule_AddIntConstant(m, "INADDR_LOOPBACK", 0x7F000001); #endif #ifdef INADDR_UNSPEC_GROUP - PyModule_AddIntConstant(m, "INADDR_UNSPEC_GROUP", INADDR_UNSPEC_GROUP); + PyModule_AddIntMacro(m, INADDR_UNSPEC_GROUP); #else PyModule_AddIntConstant(m, "INADDR_UNSPEC_GROUP", 0xe0000000); #endif @@ -6234,356 +6229,353 @@ PyModule_AddIntConstant(m, "INADDR_ALLHOSTS_GROUP", 0xe0000001); #endif #ifdef INADDR_MAX_LOCAL_GROUP - PyModule_AddIntConstant(m, "INADDR_MAX_LOCAL_GROUP", - INADDR_MAX_LOCAL_GROUP); + PyModule_AddIntMacro(m, INADDR_MAX_LOCAL_GROUP); #else PyModule_AddIntConstant(m, "INADDR_MAX_LOCAL_GROUP", 0xe00000ff); #endif #ifdef INADDR_NONE - PyModule_AddIntConstant(m, "INADDR_NONE", INADDR_NONE); + PyModule_AddIntMacro(m, INADDR_NONE); #else PyModule_AddIntConstant(m, "INADDR_NONE", 0xffffffff); #endif /* IPv4 [gs]etsockopt options */ #ifdef IP_OPTIONS - PyModule_AddIntConstant(m, "IP_OPTIONS", IP_OPTIONS); + PyModule_AddIntMacro(m, IP_OPTIONS); #endif #ifdef IP_HDRINCL - PyModule_AddIntConstant(m, "IP_HDRINCL", IP_HDRINCL); + PyModule_AddIntMacro(m, IP_HDRINCL); #endif #ifdef IP_TOS - PyModule_AddIntConstant(m, "IP_TOS", IP_TOS); + PyModule_AddIntMacro(m, IP_TOS); #endif #ifdef IP_TTL - PyModule_AddIntConstant(m, "IP_TTL", IP_TTL); + PyModule_AddIntMacro(m, IP_TTL); #endif #ifdef IP_RECVOPTS - PyModule_AddIntConstant(m, "IP_RECVOPTS", IP_RECVOPTS); + PyModule_AddIntMacro(m, IP_RECVOPTS); #endif #ifdef IP_RECVRETOPTS - PyModule_AddIntConstant(m, "IP_RECVRETOPTS", IP_RECVRETOPTS); + PyModule_AddIntMacro(m, IP_RECVRETOPTS); #endif #ifdef IP_RECVDSTADDR - PyModule_AddIntConstant(m, "IP_RECVDSTADDR", IP_RECVDSTADDR); + PyModule_AddIntMacro(m, IP_RECVDSTADDR); #endif #ifdef IP_RETOPTS - PyModule_AddIntConstant(m, "IP_RETOPTS", IP_RETOPTS); + PyModule_AddIntMacro(m, IP_RETOPTS); #endif #ifdef IP_MULTICAST_IF - PyModule_AddIntConstant(m, "IP_MULTICAST_IF", IP_MULTICAST_IF); + PyModule_AddIntMacro(m, IP_MULTICAST_IF); #endif #ifdef IP_MULTICAST_TTL - PyModule_AddIntConstant(m, "IP_MULTICAST_TTL", IP_MULTICAST_TTL); + PyModule_AddIntMacro(m, IP_MULTICAST_TTL); #endif #ifdef IP_MULTICAST_LOOP - PyModule_AddIntConstant(m, "IP_MULTICAST_LOOP", IP_MULTICAST_LOOP); + PyModule_AddIntMacro(m, IP_MULTICAST_LOOP); #endif #ifdef IP_ADD_MEMBERSHIP - PyModule_AddIntConstant(m, "IP_ADD_MEMBERSHIP", IP_ADD_MEMBERSHIP); + PyModule_AddIntMacro(m, IP_ADD_MEMBERSHIP); #endif #ifdef IP_DROP_MEMBERSHIP - PyModule_AddIntConstant(m, "IP_DROP_MEMBERSHIP", IP_DROP_MEMBERSHIP); + PyModule_AddIntMacro(m, IP_DROP_MEMBERSHIP); #endif #ifdef IP_DEFAULT_MULTICAST_TTL - PyModule_AddIntConstant(m, "IP_DEFAULT_MULTICAST_TTL", - IP_DEFAULT_MULTICAST_TTL); + PyModule_AddIntMacro(m, IP_DEFAULT_MULTICAST_TTL); #endif #ifdef IP_DEFAULT_MULTICAST_LOOP - PyModule_AddIntConstant(m, "IP_DEFAULT_MULTICAST_LOOP", - IP_DEFAULT_MULTICAST_LOOP); + PyModule_AddIntMacro(m, IP_DEFAULT_MULTICAST_LOOP); #endif #ifdef IP_MAX_MEMBERSHIPS - PyModule_AddIntConstant(m, "IP_MAX_MEMBERSHIPS", IP_MAX_MEMBERSHIPS); + PyModule_AddIntMacro(m, IP_MAX_MEMBERSHIPS); #endif #ifdef IP_TRANSPARENT - PyModule_AddIntConstant(m, "IP_TRANSPARENT", IP_TRANSPARENT); + PyModule_AddIntMacro(m, IP_TRANSPARENT); #endif /* IPv6 [gs]etsockopt options, defined in RFC2553 */ #ifdef IPV6_JOIN_GROUP - PyModule_AddIntConstant(m, "IPV6_JOIN_GROUP", IPV6_JOIN_GROUP); + PyModule_AddIntMacro(m, IPV6_JOIN_GROUP); #endif #ifdef IPV6_LEAVE_GROUP - PyModule_AddIntConstant(m, "IPV6_LEAVE_GROUP", IPV6_LEAVE_GROUP); + PyModule_AddIntMacro(m, IPV6_LEAVE_GROUP); #endif #ifdef IPV6_MULTICAST_HOPS - PyModule_AddIntConstant(m, "IPV6_MULTICAST_HOPS", IPV6_MULTICAST_HOPS); + PyModule_AddIntMacro(m, IPV6_MULTICAST_HOPS); #endif #ifdef IPV6_MULTICAST_IF - PyModule_AddIntConstant(m, "IPV6_MULTICAST_IF", IPV6_MULTICAST_IF); + PyModule_AddIntMacro(m, IPV6_MULTICAST_IF); #endif #ifdef IPV6_MULTICAST_LOOP - PyModule_AddIntConstant(m, "IPV6_MULTICAST_LOOP", IPV6_MULTICAST_LOOP); + PyModule_AddIntMacro(m, IPV6_MULTICAST_LOOP); #endif #ifdef IPV6_UNICAST_HOPS - PyModule_AddIntConstant(m, "IPV6_UNICAST_HOPS", IPV6_UNICAST_HOPS); + PyModule_AddIntMacro(m, IPV6_UNICAST_HOPS); #endif /* Additional IPV6 socket options, defined in RFC 3493 */ #ifdef IPV6_V6ONLY - PyModule_AddIntConstant(m, "IPV6_V6ONLY", IPV6_V6ONLY); + PyModule_AddIntMacro(m, IPV6_V6ONLY); #endif /* Advanced IPV6 socket options, from RFC 3542 */ #ifdef IPV6_CHECKSUM - PyModule_AddIntConstant(m, "IPV6_CHECKSUM", IPV6_CHECKSUM); + PyModule_AddIntMacro(m, IPV6_CHECKSUM); #endif #ifdef IPV6_DONTFRAG - PyModule_AddIntConstant(m, "IPV6_DONTFRAG", IPV6_DONTFRAG); + PyModule_AddIntMacro(m, IPV6_DONTFRAG); #endif #ifdef IPV6_DSTOPTS - PyModule_AddIntConstant(m, "IPV6_DSTOPTS", IPV6_DSTOPTS); + PyModule_AddIntMacro(m, IPV6_DSTOPTS); #endif #ifdef IPV6_HOPLIMIT - PyModule_AddIntConstant(m, "IPV6_HOPLIMIT", IPV6_HOPLIMIT); + PyModule_AddIntMacro(m, IPV6_HOPLIMIT); #endif #ifdef IPV6_HOPOPTS - PyModule_AddIntConstant(m, "IPV6_HOPOPTS", IPV6_HOPOPTS); + PyModule_AddIntMacro(m, IPV6_HOPOPTS); #endif #ifdef IPV6_NEXTHOP - PyModule_AddIntConstant(m, "IPV6_NEXTHOP", IPV6_NEXTHOP); + PyModule_AddIntMacro(m, IPV6_NEXTHOP); #endif #ifdef IPV6_PATHMTU - PyModule_AddIntConstant(m, "IPV6_PATHMTU", IPV6_PATHMTU); + PyModule_AddIntMacro(m, IPV6_PATHMTU); #endif #ifdef IPV6_PKTINFO - PyModule_AddIntConstant(m, "IPV6_PKTINFO", IPV6_PKTINFO); + PyModule_AddIntMacro(m, IPV6_PKTINFO); #endif #ifdef IPV6_RECVDSTOPTS - PyModule_AddIntConstant(m, "IPV6_RECVDSTOPTS", IPV6_RECVDSTOPTS); + PyModule_AddIntMacro(m, IPV6_RECVDSTOPTS); #endif #ifdef IPV6_RECVHOPLIMIT - PyModule_AddIntConstant(m, "IPV6_RECVHOPLIMIT", IPV6_RECVHOPLIMIT); + PyModule_AddIntMacro(m, IPV6_RECVHOPLIMIT); #endif #ifdef IPV6_RECVHOPOPTS - PyModule_AddIntConstant(m, "IPV6_RECVHOPOPTS", IPV6_RECVHOPOPTS); + PyModule_AddIntMacro(m, IPV6_RECVHOPOPTS); #endif #ifdef IPV6_RECVPKTINFO - PyModule_AddIntConstant(m, "IPV6_RECVPKTINFO", IPV6_RECVPKTINFO); + PyModule_AddIntMacro(m, IPV6_RECVPKTINFO); #endif #ifdef IPV6_RECVRTHDR - PyModule_AddIntConstant(m, "IPV6_RECVRTHDR", IPV6_RECVRTHDR); + PyModule_AddIntMacro(m, IPV6_RECVRTHDR); #endif #ifdef IPV6_RECVTCLASS - PyModule_AddIntConstant(m, "IPV6_RECVTCLASS", IPV6_RECVTCLASS); + PyModule_AddIntMacro(m, IPV6_RECVTCLASS); #endif #ifdef IPV6_RTHDR - PyModule_AddIntConstant(m, "IPV6_RTHDR", IPV6_RTHDR); + PyModule_AddIntMacro(m, IPV6_RTHDR); #endif #ifdef IPV6_RTHDRDSTOPTS - PyModule_AddIntConstant(m, "IPV6_RTHDRDSTOPTS", IPV6_RTHDRDSTOPTS); + PyModule_AddIntMacro(m, IPV6_RTHDRDSTOPTS); #endif #ifdef IPV6_RTHDR_TYPE_0 - PyModule_AddIntConstant(m, "IPV6_RTHDR_TYPE_0", IPV6_RTHDR_TYPE_0); + PyModule_AddIntMacro(m, IPV6_RTHDR_TYPE_0); #endif #ifdef IPV6_RECVPATHMTU - PyModule_AddIntConstant(m, "IPV6_RECVPATHMTU", IPV6_RECVPATHMTU); + PyModule_AddIntMacro(m, IPV6_RECVPATHMTU); #endif #ifdef IPV6_TCLASS - PyModule_AddIntConstant(m, "IPV6_TCLASS", IPV6_TCLASS); + PyModule_AddIntMacro(m, IPV6_TCLASS); #endif #ifdef IPV6_USE_MIN_MTU - PyModule_AddIntConstant(m, "IPV6_USE_MIN_MTU", IPV6_USE_MIN_MTU); + PyModule_AddIntMacro(m, IPV6_USE_MIN_MTU); #endif /* TCP options */ #ifdef TCP_NODELAY - PyModule_AddIntConstant(m, "TCP_NODELAY", TCP_NODELAY); + PyModule_AddIntMacro(m, TCP_NODELAY); #endif #ifdef TCP_MAXSEG - PyModule_AddIntConstant(m, "TCP_MAXSEG", TCP_MAXSEG); + PyModule_AddIntMacro(m, TCP_MAXSEG); #endif #ifdef TCP_CORK - PyModule_AddIntConstant(m, "TCP_CORK", TCP_CORK); + PyModule_AddIntMacro(m, TCP_CORK); #endif #ifdef TCP_KEEPIDLE - PyModule_AddIntConstant(m, "TCP_KEEPIDLE", TCP_KEEPIDLE); + PyModule_AddIntMacro(m, TCP_KEEPIDLE); #endif #ifdef TCP_KEEPINTVL - PyModule_AddIntConstant(m, "TCP_KEEPINTVL", TCP_KEEPINTVL); + PyModule_AddIntMacro(m, TCP_KEEPINTVL); #endif #ifdef TCP_KEEPCNT - PyModule_AddIntConstant(m, "TCP_KEEPCNT", TCP_KEEPCNT); + PyModule_AddIntMacro(m, TCP_KEEPCNT); #endif #ifdef TCP_SYNCNT - PyModule_AddIntConstant(m, "TCP_SYNCNT", TCP_SYNCNT); + PyModule_AddIntMacro(m, TCP_SYNCNT); #endif #ifdef TCP_LINGER2 - PyModule_AddIntConstant(m, "TCP_LINGER2", TCP_LINGER2); + PyModule_AddIntMacro(m, TCP_LINGER2); #endif #ifdef TCP_DEFER_ACCEPT - PyModule_AddIntConstant(m, "TCP_DEFER_ACCEPT", TCP_DEFER_ACCEPT); + PyModule_AddIntMacro(m, TCP_DEFER_ACCEPT); #endif #ifdef TCP_WINDOW_CLAMP - PyModule_AddIntConstant(m, "TCP_WINDOW_CLAMP", TCP_WINDOW_CLAMP); + PyModule_AddIntMacro(m, TCP_WINDOW_CLAMP); #endif #ifdef TCP_INFO - PyModule_AddIntConstant(m, "TCP_INFO", TCP_INFO); + PyModule_AddIntMacro(m, TCP_INFO); #endif #ifdef TCP_QUICKACK - PyModule_AddIntConstant(m, "TCP_QUICKACK", TCP_QUICKACK); + PyModule_AddIntMacro(m, TCP_QUICKACK); #endif #ifdef TCP_FASTOPEN - PyModule_AddIntConstant(m, "TCP_FASTOPEN", TCP_FASTOPEN); + PyModule_AddIntMacro(m, TCP_FASTOPEN); #endif /* IPX options */ #ifdef IPX_TYPE - PyModule_AddIntConstant(m, "IPX_TYPE", IPX_TYPE); + PyModule_AddIntMacro(m, IPX_TYPE); #endif /* Reliable Datagram Sockets */ #ifdef RDS_CMSG_RDMA_ARGS - PyModule_AddIntConstant(m, "RDS_CMSG_RDMA_ARGS", RDS_CMSG_RDMA_ARGS); + PyModule_AddIntMacro(m, RDS_CMSG_RDMA_ARGS); #endif #ifdef RDS_CMSG_RDMA_DEST - PyModule_AddIntConstant(m, "RDS_CMSG_RDMA_DEST", RDS_CMSG_RDMA_DEST); + PyModule_AddIntMacro(m, RDS_CMSG_RDMA_DEST); #endif #ifdef RDS_CMSG_RDMA_MAP - PyModule_AddIntConstant(m, "RDS_CMSG_RDMA_MAP", RDS_CMSG_RDMA_MAP); + PyModule_AddIntMacro(m, RDS_CMSG_RDMA_MAP); #endif #ifdef RDS_CMSG_RDMA_STATUS - PyModule_AddIntConstant(m, "RDS_CMSG_RDMA_STATUS", RDS_CMSG_RDMA_STATUS); + PyModule_AddIntMacro(m, RDS_CMSG_RDMA_STATUS); #endif #ifdef RDS_CMSG_RDMA_UPDATE - PyModule_AddIntConstant(m, "RDS_CMSG_RDMA_UPDATE", RDS_CMSG_RDMA_UPDATE); + PyModule_AddIntMacro(m, RDS_CMSG_RDMA_UPDATE); #endif #ifdef RDS_RDMA_READWRITE - PyModule_AddIntConstant(m, "RDS_RDMA_READWRITE", RDS_RDMA_READWRITE); + PyModule_AddIntMacro(m, RDS_RDMA_READWRITE); #endif #ifdef RDS_RDMA_FENCE - PyModule_AddIntConstant(m, "RDS_RDMA_FENCE", RDS_RDMA_FENCE); + PyModule_AddIntMacro(m, RDS_RDMA_FENCE); #endif #ifdef RDS_RDMA_INVALIDATE - PyModule_AddIntConstant(m, "RDS_RDMA_INVALIDATE", RDS_RDMA_INVALIDATE); + PyModule_AddIntMacro(m, RDS_RDMA_INVALIDATE); #endif #ifdef RDS_RDMA_USE_ONCE - PyModule_AddIntConstant(m, "RDS_RDMA_USE_ONCE", RDS_RDMA_USE_ONCE); + PyModule_AddIntMacro(m, RDS_RDMA_USE_ONCE); #endif #ifdef RDS_RDMA_DONTWAIT - PyModule_AddIntConstant(m, "RDS_RDMA_DONTWAIT", RDS_RDMA_DONTWAIT); + PyModule_AddIntMacro(m, RDS_RDMA_DONTWAIT); #endif #ifdef RDS_RDMA_NOTIFY_ME - PyModule_AddIntConstant(m, "RDS_RDMA_NOTIFY_ME", RDS_RDMA_NOTIFY_ME); + PyModule_AddIntMacro(m, RDS_RDMA_NOTIFY_ME); #endif #ifdef RDS_RDMA_SILENT - PyModule_AddIntConstant(m, "RDS_RDMA_SILENT", RDS_RDMA_SILENT); + PyModule_AddIntMacro(m, RDS_RDMA_SILENT); #endif /* get{addr,name}info parameters */ #ifdef EAI_ADDRFAMILY - PyModule_AddIntConstant(m, "EAI_ADDRFAMILY", EAI_ADDRFAMILY); + PyModule_AddIntMacro(m, EAI_ADDRFAMILY); #endif #ifdef EAI_AGAIN - PyModule_AddIntConstant(m, "EAI_AGAIN", EAI_AGAIN); + PyModule_AddIntMacro(m, EAI_AGAIN); #endif #ifdef EAI_BADFLAGS - PyModule_AddIntConstant(m, "EAI_BADFLAGS", EAI_BADFLAGS); + PyModule_AddIntMacro(m, EAI_BADFLAGS); #endif #ifdef EAI_FAIL - PyModule_AddIntConstant(m, "EAI_FAIL", EAI_FAIL); + PyModule_AddIntMacro(m, EAI_FAIL); #endif #ifdef EAI_FAMILY - PyModule_AddIntConstant(m, "EAI_FAMILY", EAI_FAMILY); + PyModule_AddIntMacro(m, EAI_FAMILY); #endif #ifdef EAI_MEMORY - PyModule_AddIntConstant(m, "EAI_MEMORY", EAI_MEMORY); + PyModule_AddIntMacro(m, EAI_MEMORY); #endif #ifdef EAI_NODATA - PyModule_AddIntConstant(m, "EAI_NODATA", EAI_NODATA); + PyModule_AddIntMacro(m, EAI_NODATA); #endif #ifdef EAI_NONAME - PyModule_AddIntConstant(m, "EAI_NONAME", EAI_NONAME); + PyModule_AddIntMacro(m, EAI_NONAME); #endif #ifdef EAI_OVERFLOW - PyModule_AddIntConstant(m, "EAI_OVERFLOW", EAI_OVERFLOW); + PyModule_AddIntMacro(m, EAI_OVERFLOW); #endif #ifdef EAI_SERVICE - PyModule_AddIntConstant(m, "EAI_SERVICE", EAI_SERVICE); + PyModule_AddIntMacro(m, EAI_SERVICE); #endif #ifdef EAI_SOCKTYPE - PyModule_AddIntConstant(m, "EAI_SOCKTYPE", EAI_SOCKTYPE); + PyModule_AddIntMacro(m, EAI_SOCKTYPE); #endif #ifdef EAI_SYSTEM - PyModule_AddIntConstant(m, "EAI_SYSTEM", EAI_SYSTEM); + PyModule_AddIntMacro(m, EAI_SYSTEM); #endif #ifdef EAI_BADHINTS - PyModule_AddIntConstant(m, "EAI_BADHINTS", EAI_BADHINTS); + PyModule_AddIntMacro(m, EAI_BADHINTS); #endif #ifdef EAI_PROTOCOL - PyModule_AddIntConstant(m, "EAI_PROTOCOL", EAI_PROTOCOL); + PyModule_AddIntMacro(m, EAI_PROTOCOL); #endif #ifdef EAI_MAX - PyModule_AddIntConstant(m, "EAI_MAX", EAI_MAX); + PyModule_AddIntMacro(m, EAI_MAX); #endif #ifdef AI_PASSIVE - PyModule_AddIntConstant(m, "AI_PASSIVE", AI_PASSIVE); + PyModule_AddIntMacro(m, AI_PASSIVE); #endif #ifdef AI_CANONNAME - PyModule_AddIntConstant(m, "AI_CANONNAME", AI_CANONNAME); + PyModule_AddIntMacro(m, AI_CANONNAME); #endif #ifdef AI_NUMERICHOST - PyModule_AddIntConstant(m, "AI_NUMERICHOST", AI_NUMERICHOST); + PyModule_AddIntMacro(m, AI_NUMERICHOST); #endif #ifdef AI_NUMERICSERV - PyModule_AddIntConstant(m, "AI_NUMERICSERV", AI_NUMERICSERV); + PyModule_AddIntMacro(m, AI_NUMERICSERV); #endif #ifdef AI_MASK - PyModule_AddIntConstant(m, "AI_MASK", AI_MASK); + PyModule_AddIntMacro(m, AI_MASK); #endif #ifdef AI_ALL - PyModule_AddIntConstant(m, "AI_ALL", AI_ALL); + PyModule_AddIntMacro(m, AI_ALL); #endif #ifdef AI_V4MAPPED_CFG - PyModule_AddIntConstant(m, "AI_V4MAPPED_CFG", AI_V4MAPPED_CFG); + PyModule_AddIntMacro(m, AI_V4MAPPED_CFG); #endif #ifdef AI_ADDRCONFIG - PyModule_AddIntConstant(m, "AI_ADDRCONFIG", AI_ADDRCONFIG); + PyModule_AddIntMacro(m, AI_ADDRCONFIG); #endif #ifdef AI_V4MAPPED - PyModule_AddIntConstant(m, "AI_V4MAPPED", AI_V4MAPPED); + PyModule_AddIntMacro(m, AI_V4MAPPED); #endif #ifdef AI_DEFAULT - PyModule_AddIntConstant(m, "AI_DEFAULT", AI_DEFAULT); + PyModule_AddIntMacro(m, AI_DEFAULT); #endif #ifdef NI_MAXHOST - PyModule_AddIntConstant(m, "NI_MAXHOST", NI_MAXHOST); + PyModule_AddIntMacro(m, NI_MAXHOST); #endif #ifdef NI_MAXSERV - PyModule_AddIntConstant(m, "NI_MAXSERV", NI_MAXSERV); + PyModule_AddIntMacro(m, NI_MAXSERV); #endif #ifdef NI_NOFQDN - PyModule_AddIntConstant(m, "NI_NOFQDN", NI_NOFQDN); + PyModule_AddIntMacro(m, NI_NOFQDN); #endif #ifdef NI_NUMERICHOST - PyModule_AddIntConstant(m, "NI_NUMERICHOST", NI_NUMERICHOST); + PyModule_AddIntMacro(m, NI_NUMERICHOST); #endif #ifdef NI_NAMEREQD - PyModule_AddIntConstant(m, "NI_NAMEREQD", NI_NAMEREQD); + PyModule_AddIntMacro(m, NI_NAMEREQD); #endif #ifdef NI_NUMERICSERV - PyModule_AddIntConstant(m, "NI_NUMERICSERV", NI_NUMERICSERV); + PyModule_AddIntMacro(m, NI_NUMERICSERV); #endif #ifdef NI_DGRAM - PyModule_AddIntConstant(m, "NI_DGRAM", NI_DGRAM); + PyModule_AddIntMacro(m, NI_DGRAM); #endif /* shutdown() parameters */ #ifdef SHUT_RD - PyModule_AddIntConstant(m, "SHUT_RD", SHUT_RD); + PyModule_AddIntMacro(m, SHUT_RD); #elif defined(SD_RECEIVE) PyModule_AddIntConstant(m, "SHUT_RD", SD_RECEIVE); #else PyModule_AddIntConstant(m, "SHUT_RD", 0); #endif #ifdef SHUT_WR - PyModule_AddIntConstant(m, "SHUT_WR", SHUT_WR); + PyModule_AddIntMacro(m, SHUT_WR); #elif defined(SD_SEND) PyModule_AddIntConstant(m, "SHUT_WR", SD_SEND); #else PyModule_AddIntConstant(m, "SHUT_WR", 1); #endif #ifdef SHUT_RDWR - PyModule_AddIntConstant(m, "SHUT_RDWR", SHUT_RDWR); + PyModule_AddIntMacro(m, SHUT_RDWR); #elif defined(SD_BOTH) PyModule_AddIntConstant(m, "SHUT_RDWR", SD_BOTH); #else @@ -6603,14 +6595,14 @@ PyModule_AddObject(m, names[i], tmp); } } - PyModule_AddIntConstant(m, "RCVALL_OFF", RCVALL_OFF); - PyModule_AddIntConstant(m, "RCVALL_ON", RCVALL_ON); - PyModule_AddIntConstant(m, "RCVALL_SOCKETLEVELONLY", RCVALL_SOCKETLEVELONLY); + PyModule_AddIntMacro(m, RCVALL_OFF); + PyModule_AddIntMacro(m, RCVALL_ON); + PyModule_AddIntMacro(m, RCVALL_SOCKETLEVELONLY); #ifdef RCVALL_IPLEVEL - PyModule_AddIntConstant(m, "RCVALL_IPLEVEL", RCVALL_IPLEVEL); + PyModule_AddIntMacro(m, RCVALL_IPLEVEL); #endif #ifdef RCVALL_MAX - PyModule_AddIntConstant(m, "RCVALL_MAX", RCVALL_MAX); + PyModule_AddIntMacro(m, RCVALL_MAX); #endif #endif /* _MSTCPIP_ */ diff --git a/Modules/symtablemodule.c b/Modules/symtablemodule.c --- a/Modules/symtablemodule.c +++ b/Modules/symtablemodule.c @@ -69,30 +69,30 @@ m = PyModule_Create(&symtablemodule); if (m == NULL) return NULL; - PyModule_AddIntConstant(m, "USE", USE); - PyModule_AddIntConstant(m, "DEF_GLOBAL", DEF_GLOBAL); - PyModule_AddIntConstant(m, "DEF_LOCAL", DEF_LOCAL); - PyModule_AddIntConstant(m, "DEF_PARAM", DEF_PARAM); - PyModule_AddIntConstant(m, "DEF_FREE", DEF_FREE); - PyModule_AddIntConstant(m, "DEF_FREE_CLASS", DEF_FREE_CLASS); - PyModule_AddIntConstant(m, "DEF_IMPORT", DEF_IMPORT); - PyModule_AddIntConstant(m, "DEF_BOUND", DEF_BOUND); + PyModule_AddIntMacro(m, USE); + PyModule_AddIntMacro(m, DEF_GLOBAL); + PyModule_AddIntMacro(m, DEF_LOCAL); + PyModule_AddIntMacro(m, DEF_PARAM); + PyModule_AddIntMacro(m, DEF_FREE); + PyModule_AddIntMacro(m, DEF_FREE_CLASS); + PyModule_AddIntMacro(m, DEF_IMPORT); + PyModule_AddIntMacro(m, DEF_BOUND); PyModule_AddIntConstant(m, "TYPE_FUNCTION", FunctionBlock); PyModule_AddIntConstant(m, "TYPE_CLASS", ClassBlock); PyModule_AddIntConstant(m, "TYPE_MODULE", ModuleBlock); - PyModule_AddIntConstant(m, "OPT_IMPORT_STAR", OPT_IMPORT_STAR); - PyModule_AddIntConstant(m, "OPT_TOPLEVEL", OPT_TOPLEVEL); + PyModule_AddIntMacro(m, OPT_IMPORT_STAR); + PyModule_AddIntMacro(m, OPT_TOPLEVEL); - PyModule_AddIntConstant(m, "LOCAL", LOCAL); - PyModule_AddIntConstant(m, "GLOBAL_EXPLICIT", GLOBAL_EXPLICIT); - PyModule_AddIntConstant(m, "GLOBAL_IMPLICIT", GLOBAL_IMPLICIT); - PyModule_AddIntConstant(m, "FREE", FREE); - PyModule_AddIntConstant(m, "CELL", CELL); + PyModule_AddIntMacro(m, LOCAL); + PyModule_AddIntMacro(m, GLOBAL_EXPLICIT); + PyModule_AddIntMacro(m, GLOBAL_IMPLICIT); + PyModule_AddIntMacro(m, FREE); + PyModule_AddIntMacro(m, CELL); PyModule_AddIntConstant(m, "SCOPE_OFF", SCOPE_OFFSET); - PyModule_AddIntConstant(m, "SCOPE_MASK", SCOPE_MASK); + PyModule_AddIntMacro(m, SCOPE_MASK); if (PyErr_Occurred()) { Py_DECREF(m); diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -278,44 +278,44 @@ /* Add some symbolic constants to the module */ /* Priorities */ - PyModule_AddIntConstant(m, "LOG_EMERG", LOG_EMERG); - PyModule_AddIntConstant(m, "LOG_ALERT", LOG_ALERT); - PyModule_AddIntConstant(m, "LOG_CRIT", LOG_CRIT); - PyModule_AddIntConstant(m, "LOG_ERR", LOG_ERR); - PyModule_AddIntConstant(m, "LOG_WARNING", LOG_WARNING); - PyModule_AddIntConstant(m, "LOG_NOTICE", LOG_NOTICE); - PyModule_AddIntConstant(m, "LOG_INFO", LOG_INFO); - PyModule_AddIntConstant(m, "LOG_DEBUG", LOG_DEBUG); + PyModule_AddIntMacro(m, LOG_EMERG); + PyModule_AddIntMacro(m, LOG_ALERT); + PyModule_AddIntMacro(m, LOG_CRIT); + PyModule_AddIntMacro(m, LOG_ERR); + PyModule_AddIntMacro(m, LOG_WARNING); + PyModule_AddIntMacro(m, LOG_NOTICE); + PyModule_AddIntMacro(m, LOG_INFO); + PyModule_AddIntMacro(m, LOG_DEBUG); /* openlog() option flags */ - PyModule_AddIntConstant(m, "LOG_PID", LOG_PID); - PyModule_AddIntConstant(m, "LOG_CONS", LOG_CONS); - PyModule_AddIntConstant(m, "LOG_NDELAY", LOG_NDELAY); + PyModule_AddIntMacro(m, LOG_PID); + PyModule_AddIntMacro(m, LOG_CONS); + PyModule_AddIntMacro(m, LOG_NDELAY); #ifdef LOG_ODELAY - PyModule_AddIntConstant(m, "LOG_ODELAY", LOG_ODELAY); + PyModule_AddIntMacro(m, LOG_ODELAY); #endif #ifdef LOG_NOWAIT - PyModule_AddIntConstant(m, "LOG_NOWAIT", LOG_NOWAIT); + PyModule_AddIntMacro(m, LOG_NOWAIT); #endif #ifdef LOG_PERROR - PyModule_AddIntConstant(m, "LOG_PERROR", LOG_PERROR); + PyModule_AddIntMacro(m, LOG_PERROR); #endif /* Facilities */ - PyModule_AddIntConstant(m, "LOG_KERN", LOG_KERN); - PyModule_AddIntConstant(m, "LOG_USER", LOG_USER); - PyModule_AddIntConstant(m, "LOG_MAIL", LOG_MAIL); - PyModule_AddIntConstant(m, "LOG_DAEMON", LOG_DAEMON); - PyModule_AddIntConstant(m, "LOG_AUTH", LOG_AUTH); - PyModule_AddIntConstant(m, "LOG_LPR", LOG_LPR); - PyModule_AddIntConstant(m, "LOG_LOCAL0", LOG_LOCAL0); - PyModule_AddIntConstant(m, "LOG_LOCAL1", LOG_LOCAL1); - PyModule_AddIntConstant(m, "LOG_LOCAL2", LOG_LOCAL2); - PyModule_AddIntConstant(m, "LOG_LOCAL3", LOG_LOCAL3); - PyModule_AddIntConstant(m, "LOG_LOCAL4", LOG_LOCAL4); - PyModule_AddIntConstant(m, "LOG_LOCAL5", LOG_LOCAL5); - PyModule_AddIntConstant(m, "LOG_LOCAL6", LOG_LOCAL6); - PyModule_AddIntConstant(m, "LOG_LOCAL7", LOG_LOCAL7); + PyModule_AddIntMacro(m, LOG_KERN); + PyModule_AddIntMacro(m, LOG_USER); + PyModule_AddIntMacro(m, LOG_MAIL); + PyModule_AddIntMacro(m, LOG_DAEMON); + PyModule_AddIntMacro(m, LOG_AUTH); + PyModule_AddIntMacro(m, LOG_LPR); + PyModule_AddIntMacro(m, LOG_LOCAL0); + PyModule_AddIntMacro(m, LOG_LOCAL1); + PyModule_AddIntMacro(m, LOG_LOCAL2); + PyModule_AddIntMacro(m, LOG_LOCAL3); + PyModule_AddIntMacro(m, LOG_LOCAL4); + PyModule_AddIntMacro(m, LOG_LOCAL5); + PyModule_AddIntMacro(m, LOG_LOCAL6); + PyModule_AddIntMacro(m, LOG_LOCAL7); #ifndef LOG_SYSLOG #define LOG_SYSLOG LOG_DAEMON @@ -330,13 +330,13 @@ #define LOG_CRON LOG_DAEMON #endif - PyModule_AddIntConstant(m, "LOG_SYSLOG", LOG_SYSLOG); - PyModule_AddIntConstant(m, "LOG_CRON", LOG_CRON); - PyModule_AddIntConstant(m, "LOG_UUCP", LOG_UUCP); - PyModule_AddIntConstant(m, "LOG_NEWS", LOG_NEWS); + PyModule_AddIntMacro(m, LOG_SYSLOG); + PyModule_AddIntMacro(m, LOG_CRON); + PyModule_AddIntMacro(m, LOG_UUCP); + PyModule_AddIntMacro(m, LOG_NEWS); #ifdef LOG_AUTHPRIV - PyModule_AddIntConstant(m, "LOG_AUTHPRIV", LOG_AUTHPRIV); + PyModule_AddIntMacro(m, LOG_AUTHPRIV); #endif return m; diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -1266,20 +1266,20 @@ Py_INCREF(ZlibError); PyModule_AddObject(m, "error", ZlibError); } - PyModule_AddIntConstant(m, "MAX_WBITS", MAX_WBITS); - PyModule_AddIntConstant(m, "DEFLATED", DEFLATED); - PyModule_AddIntConstant(m, "DEF_MEM_LEVEL", DEF_MEM_LEVEL); - PyModule_AddIntConstant(m, "Z_BEST_SPEED", Z_BEST_SPEED); - PyModule_AddIntConstant(m, "Z_BEST_COMPRESSION", Z_BEST_COMPRESSION); - PyModule_AddIntConstant(m, "Z_DEFAULT_COMPRESSION", Z_DEFAULT_COMPRESSION); - PyModule_AddIntConstant(m, "Z_FILTERED", Z_FILTERED); - PyModule_AddIntConstant(m, "Z_HUFFMAN_ONLY", Z_HUFFMAN_ONLY); - PyModule_AddIntConstant(m, "Z_DEFAULT_STRATEGY", Z_DEFAULT_STRATEGY); + PyModule_AddIntMacro(m, MAX_WBITS); + PyModule_AddIntMacro(m, DEFLATED); + PyModule_AddIntMacro(m, DEF_MEM_LEVEL); + PyModule_AddIntMacro(m, Z_BEST_SPEED); + PyModule_AddIntMacro(m, Z_BEST_COMPRESSION); + PyModule_AddIntMacro(m, Z_DEFAULT_COMPRESSION); + PyModule_AddIntMacro(m, Z_FILTERED); + PyModule_AddIntMacro(m, Z_HUFFMAN_ONLY); + PyModule_AddIntMacro(m, Z_DEFAULT_STRATEGY); - PyModule_AddIntConstant(m, "Z_FINISH", Z_FINISH); - PyModule_AddIntConstant(m, "Z_NO_FLUSH", Z_NO_FLUSH); - PyModule_AddIntConstant(m, "Z_SYNC_FLUSH", Z_SYNC_FLUSH); - PyModule_AddIntConstant(m, "Z_FULL_FLUSH", Z_FULL_FLUSH); + PyModule_AddIntMacro(m, Z_FINISH); + PyModule_AddIntMacro(m, Z_NO_FLUSH); + PyModule_AddIntMacro(m, Z_SYNC_FLUSH); + PyModule_AddIntMacro(m, Z_FULL_FLUSH); ver = PyUnicode_FromString(ZLIB_VERSION); if (ver != NULL) diff --git a/PC/_msi.c b/PC/_msi.c --- a/PC/_msi.c +++ b/PC/_msi.c @@ -1030,40 +1030,40 @@ PyModule_AddIntConstant(m, "MSIDBOPEN_TRANSACT", (int)MSIDBOPEN_TRANSACT); PyModule_AddIntConstant(m, "MSIDBOPEN_PATCHFILE", (int)MSIDBOPEN_PATCHFILE); - PyModule_AddIntConstant(m, "MSICOLINFO_NAMES", MSICOLINFO_NAMES); - PyModule_AddIntConstant(m, "MSICOLINFO_TYPES", MSICOLINFO_TYPES); + PyModule_AddIntMacro(m, MSICOLINFO_NAMES); + PyModule_AddIntMacro(m, MSICOLINFO_TYPES); - PyModule_AddIntConstant(m, "MSIMODIFY_SEEK", MSIMODIFY_SEEK); - PyModule_AddIntConstant(m, "MSIMODIFY_REFRESH", MSIMODIFY_REFRESH); - PyModule_AddIntConstant(m, "MSIMODIFY_INSERT", MSIMODIFY_INSERT); - PyModule_AddIntConstant(m, "MSIMODIFY_UPDATE", MSIMODIFY_UPDATE); - PyModule_AddIntConstant(m, "MSIMODIFY_ASSIGN", MSIMODIFY_ASSIGN); - PyModule_AddIntConstant(m, "MSIMODIFY_REPLACE", MSIMODIFY_REPLACE); - PyModule_AddIntConstant(m, "MSIMODIFY_MERGE", MSIMODIFY_MERGE); - PyModule_AddIntConstant(m, "MSIMODIFY_DELETE", MSIMODIFY_DELETE); - PyModule_AddIntConstant(m, "MSIMODIFY_INSERT_TEMPORARY", MSIMODIFY_INSERT_TEMPORARY); - PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE", MSIMODIFY_VALIDATE); - PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_NEW", MSIMODIFY_VALIDATE_NEW); - PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_FIELD", MSIMODIFY_VALIDATE_FIELD); - PyModule_AddIntConstant(m, "MSIMODIFY_VALIDATE_DELETE", MSIMODIFY_VALIDATE_DELETE); + PyModule_AddIntMacro(m, MSIMODIFY_SEEK); + PyModule_AddIntMacro(m, MSIMODIFY_REFRESH); + PyModule_AddIntMacro(m, MSIMODIFY_INSERT); + PyModule_AddIntMacro(m, MSIMODIFY_UPDATE); + PyModule_AddIntMacro(m, MSIMODIFY_ASSIGN); + PyModule_AddIntMacro(m, MSIMODIFY_REPLACE); + PyModule_AddIntMacro(m, MSIMODIFY_MERGE); + PyModule_AddIntMacro(m, MSIMODIFY_DELETE); + PyModule_AddIntMacro(m, MSIMODIFY_INSERT_TEMPORARY); + PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE); + PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE_NEW); + PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE_FIELD); + PyModule_AddIntMacro(m, MSIMODIFY_VALIDATE_DELETE); - PyModule_AddIntConstant(m, "PID_CODEPAGE", PID_CODEPAGE); - PyModule_AddIntConstant(m, "PID_TITLE", PID_TITLE); - PyModule_AddIntConstant(m, "PID_SUBJECT", PID_SUBJECT); - PyModule_AddIntConstant(m, "PID_AUTHOR", PID_AUTHOR); - PyModule_AddIntConstant(m, "PID_KEYWORDS", PID_KEYWORDS); - PyModule_AddIntConstant(m, "PID_COMMENTS", PID_COMMENTS); - PyModule_AddIntConstant(m, "PID_TEMPLATE", PID_TEMPLATE); - PyModule_AddIntConstant(m, "PID_LASTAUTHOR", PID_LASTAUTHOR); - PyModule_AddIntConstant(m, "PID_REVNUMBER", PID_REVNUMBER); - PyModule_AddIntConstant(m, "PID_LASTPRINTED", PID_LASTPRINTED); - PyModule_AddIntConstant(m, "PID_CREATE_DTM", PID_CREATE_DTM); - PyModule_AddIntConstant(m, "PID_LASTSAVE_DTM", PID_LASTSAVE_DTM); - PyModule_AddIntConstant(m, "PID_PAGECOUNT", PID_PAGECOUNT); - PyModule_AddIntConstant(m, "PID_WORDCOUNT", PID_WORDCOUNT); - PyModule_AddIntConstant(m, "PID_CHARCOUNT", PID_CHARCOUNT); - PyModule_AddIntConstant(m, "PID_APPNAME", PID_APPNAME); - PyModule_AddIntConstant(m, "PID_SECURITY", PID_SECURITY); + PyModule_AddIntMacro(m, PID_CODEPAGE); + PyModule_AddIntMacro(m, PID_TITLE); + PyModule_AddIntMacro(m, PID_SUBJECT); + PyModule_AddIntMacro(m, PID_AUTHOR); + PyModule_AddIntMacro(m, PID_KEYWORDS); + PyModule_AddIntMacro(m, PID_COMMENTS); + PyModule_AddIntMacro(m, PID_TEMPLATE); + PyModule_AddIntMacro(m, PID_LASTAUTHOR); + PyModule_AddIntMacro(m, PID_REVNUMBER); + PyModule_AddIntMacro(m, PID_LASTPRINTED); + PyModule_AddIntMacro(m, PID_CREATE_DTM); + PyModule_AddIntMacro(m, PID_LASTSAVE_DTM); + PyModule_AddIntMacro(m, PID_PAGECOUNT); + PyModule_AddIntMacro(m, PID_WORDCOUNT); + PyModule_AddIntMacro(m, PID_CHARCOUNT); + PyModule_AddIntMacro(m, PID_APPNAME); + PyModule_AddIntMacro(m, PID_SECURITY); MSIError = PyErr_NewException ("_msi.MSIError", NULL, NULL); if (!MSIError) diff --git a/Python/Python-ast.c b/Python/Python-ast.c --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -6977,7 +6977,7 @@ d = PyModule_GetDict(m); if (PyDict_SetItemString(d, "AST", (PyObject*)&AST_type) < 0) return NULL; - if (PyModule_AddIntConstant(m, "PyCF_ONLY_AST", PyCF_ONLY_AST) < 0) + if (PyModule_AddIntMacro(m, PyCF_ONLY_AST) < 0) return NULL; if (PyDict_SetItemString(d, "mod", (PyObject*)mod_type) < 0) return NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 19:28:53 2013 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 20 May 2013 19:28:53 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_change_AST_codegen_to_use_?= =?utf-8?q?PyModule=5FAddIntMacro?= Message-ID: <3bDnC92B98z7Llg@mail.python.org> http://hg.python.org/cpython/rev/e392f1b88fff changeset: 83868:e392f1b88fff user: Benjamin Peterson date: Mon May 20 10:28:48 2013 -0700 summary: change AST codegen to use PyModule_AddIntMacro files: Parser/asdl_c.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -1011,7 +1011,7 @@ self.emit("if (!m) return NULL;", 1) self.emit("d = PyModule_GetDict(m);", 1) self.emit('if (PyDict_SetItemString(d, "AST", (PyObject*)&AST_type) < 0) return NULL;', 1) - self.emit('if (PyModule_AddIntConstant(m, "PyCF_ONLY_AST", PyCF_ONLY_AST) < 0)', 1) + self.emit('if (PyModule_AddIntMacro(m, PyCF_ONLY_AST) < 0)', 1) self.emit("return NULL;", 2) for dfn in mod.dfns: self.visit(dfn) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 23:33:45 2013 From: python-checkins at python.org (ned.deily) Date: Mon, 20 May 2013 23:33:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4MDI2?= =?utf-8?q?=3A_fix_ctypes_doc_typo?= Message-ID: <3bDtdj660Cz7Lmg@mail.python.org> http://hg.python.org/cpython/rev/7937f5c56924 changeset: 83869:7937f5c56924 branch: 2.7 parent: 83862:8edfe539d4c6 user: Ned Deily date: Mon May 20 14:27:06 2013 -0700 summary: Issue #18026: fix ctypes doc typo files: Doc/library/ctypes.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1333,7 +1333,7 @@ like ``find_library("c")`` will fail and return ``None``. If wrapping a shared library with :mod:`ctypes`, it *may* be better to determine -the shared library name at development type, and hardcode that into the wrapper +the shared library name at development time, and hardcode that into the wrapper module instead of using :func:`find_library` to locate the library at runtime. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 23:33:47 2013 From: python-checkins at python.org (ned.deily) Date: Mon, 20 May 2013 23:33:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MDI2?= =?utf-8?q?=3A_fix_ctypes_doc_typo?= Message-ID: <3bDtdl1LvGz7Lp4@mail.python.org> http://hg.python.org/cpython/rev/cac83b62b0de changeset: 83870:cac83b62b0de branch: 3.3 parent: 83860:b363473cfe9c user: Ned Deily date: Mon May 20 14:29:44 2013 -0700 summary: Issue #18026: fix ctypes doc typo files: Doc/library/ctypes.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1274,7 +1274,7 @@ like ``find_library("c")`` will fail and return ``None``. If wrapping a shared library with :mod:`ctypes`, it *may* be better to determine -the shared library name at development type, and hardcode that into the wrapper +the shared library name at development time, and hardcode that into the wrapper module instead of using :func:`find_library` to locate the library at runtime. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 20 23:33:48 2013 From: python-checkins at python.org (ned.deily) Date: Mon, 20 May 2013 23:33:48 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318026=3A_merge?= Message-ID: <3bDtdm3ZpXz7Lp4@mail.python.org> http://hg.python.org/cpython/rev/1f388bbc8917 changeset: 83871:1f388bbc8917 parent: 83868:e392f1b88fff parent: 83870:cac83b62b0de user: Ned Deily date: Mon May 20 14:32:06 2013 -0700 summary: Issue #18026: merge files: Doc/library/ctypes.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1274,7 +1274,7 @@ like ``find_library("c")`` will fail and return ``None``. If wrapping a shared library with :mod:`ctypes`, it *may* be better to determine -the shared library name at development type, and hardcode that into the wrapper +the shared library name at development time, and hardcode that into the wrapper module instead of using :func:`find_library` to locate the library at runtime. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 21 00:30:22 2013 From: python-checkins at python.org (vinay.sajip) Date: Tue, 21 May 2013 00:30:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3NzQ0?= =?utf-8?q?=3A_Now_unset_VIRTUAL=5FENV_environment_variable_when_deactivat?= =?utf-8?q?ing=2E?= Message-ID: <3bDvv247Pqz7Ll0@mail.python.org> http://hg.python.org/cpython/rev/9a2eea6fffee changeset: 83872:9a2eea6fffee branch: 3.3 parent: 83870:cac83b62b0de user: Vinay Sajip date: Mon May 20 15:28:52 2013 -0700 summary: Issue #17744: Now unset VIRTUAL_ENV environment variable when deactivating. files: Lib/venv/scripts/nt/deactivate.bat | 12 ++++++++---- 1 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Lib/venv/scripts/nt/deactivate.bat b/Lib/venv/scripts/nt/deactivate.bat --- a/Lib/venv/scripts/nt/deactivate.bat +++ b/Lib/venv/scripts/nt/deactivate.bat @@ -1,17 +1,21 @@ @echo off if defined _OLD_VIRTUAL_PROMPT ( - set PROMPT=%_OLD_VIRTUAL_PROMPT% + set "PROMPT=%_OLD_VIRTUAL_PROMPT%" ) set _OLD_VIRTUAL_PROMPT= if defined _OLD_VIRTUAL_PYTHONHOME ( - set PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME% - set _OLD_VIRTUAL_PYTHONHOME= + set "PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME%" + set _OLD_VIRTUAL_PYTHONHOME= ) -if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH% +if defined _OLD_VIRTUAL_PATH ( + set "PATH=%_OLD_VIRTUAL_PATH%" +) set _OLD_VIRTUAL_PATH= +set VIRTUAL_ENV= + :END -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 21 00:30:23 2013 From: python-checkins at python.org (vinay.sajip) Date: Tue, 21 May 2013 00:30:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Closes_=2317744=3A_Merged_fix_from_3=2E3=2E?= Message-ID: <3bDvv36M48z7Llh@mail.python.org> http://hg.python.org/cpython/rev/e29533c8ec66 changeset: 83873:e29533c8ec66 parent: 83871:1f388bbc8917 parent: 83872:9a2eea6fffee user: Vinay Sajip date: Mon May 20 15:30:10 2013 -0700 summary: Closes #17744: Merged fix from 3.3. files: Lib/venv/scripts/nt/deactivate.bat | 12 ++++++++---- 1 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Lib/venv/scripts/nt/deactivate.bat b/Lib/venv/scripts/nt/deactivate.bat --- a/Lib/venv/scripts/nt/deactivate.bat +++ b/Lib/venv/scripts/nt/deactivate.bat @@ -1,17 +1,21 @@ @echo off if defined _OLD_VIRTUAL_PROMPT ( - set PROMPT=%_OLD_VIRTUAL_PROMPT% + set "PROMPT=%_OLD_VIRTUAL_PROMPT%" ) set _OLD_VIRTUAL_PROMPT= if defined _OLD_VIRTUAL_PYTHONHOME ( - set PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME% - set _OLD_VIRTUAL_PYTHONHOME= + set "PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME%" + set _OLD_VIRTUAL_PYTHONHOME= ) -if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH% +if defined _OLD_VIRTUAL_PATH ( + set "PATH=%_OLD_VIRTUAL_PATH%" +) set _OLD_VIRTUAL_PATH= +set VIRTUAL_ENV= + :END -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 21 00:39:25 2013 From: python-checkins at python.org (vinay.sajip) Date: Tue, 21 May 2013 00:39:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3NzQz?= =?utf-8?q?=3A_Now_use_extended_syntax_of_set_command_in_=2Ebat_files=2E?= Message-ID: <3bDw5T69tPz7Ljm@mail.python.org> http://hg.python.org/cpython/rev/66c87d2b3435 changeset: 83874:66c87d2b3435 branch: 3.3 parent: 83872:9a2eea6fffee user: Vinay Sajip date: Mon May 20 15:38:12 2013 -0700 summary: Issue #17743: Now use extended syntax of set command in .bat files. files: Lib/venv/scripts/nt/activate.bat | 27 ++++++++++--------- 1 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Lib/venv/scripts/nt/activate.bat b/Lib/venv/scripts/nt/activate.bat --- a/Lib/venv/scripts/nt/activate.bat +++ b/Lib/venv/scripts/nt/activate.bat @@ -1,31 +1,32 @@ @echo off -set VIRTUAL_ENV=__VENV_DIR__ +set "VIRTUAL_ENV=__VENV_DIR__" if not defined PROMPT ( - set PROMPT=$P$G + set "PROMPT=$P$G" ) if defined _OLD_VIRTUAL_PROMPT ( - set PROMPT=%_OLD_VIRTUAL_PROMPT% + set "PROMPT=%_OLD_VIRTUAL_PROMPT%" ) if defined _OLD_VIRTUAL_PYTHONHOME ( - set PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME% + set "PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME%" ) -set _OLD_VIRTUAL_PROMPT=%PROMPT% -set PROMPT=__VENV_NAME__%PROMPT% +set "_OLD_VIRTUAL_PROMPT=%PROMPT%" +set "PROMPT=__VENV_NAME__%PROMPT%" if defined PYTHONHOME ( - set _OLD_VIRTUAL_PYTHONHOME=%PYTHONHOME% - set PYTHONHOME= + set "_OLD_VIRTUAL_PYTHONHOME=%PYTHONHOME%" + set PYTHONHOME= ) -if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH%; goto SKIPPATH +if defined _OLD_VIRTUAL_PATH ( + set "PATH=%_OLD_VIRTUAL_PATH%" +) else ( + set "_OLD_VIRTUAL_PATH=%PATH%" +) -set _OLD_VIRTUAL_PATH=%PATH% - -:SKIPPATH -set PATH=%VIRTUAL_ENV%\__VENV_BIN_NAME__;%PATH% +set "PATH=%VIRTUAL_ENV%\__VENV_BIN_NAME__;%PATH%" :END -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 21 00:39:27 2013 From: python-checkins at python.org (vinay.sajip) Date: Tue, 21 May 2013 00:39:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Closes_=2317743=3A_Merged_fix_from_3=2E3=2E?= Message-ID: <3bDw5W1Fhgz7Lkc@mail.python.org> http://hg.python.org/cpython/rev/96c842873c30 changeset: 83875:96c842873c30 parent: 83873:e29533c8ec66 parent: 83874:66c87d2b3435 user: Vinay Sajip date: Mon May 20 15:39:11 2013 -0700 summary: Closes #17743: Merged fix from 3.3. files: Lib/venv/scripts/nt/activate.bat | 27 ++++++++++--------- 1 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Lib/venv/scripts/nt/activate.bat b/Lib/venv/scripts/nt/activate.bat --- a/Lib/venv/scripts/nt/activate.bat +++ b/Lib/venv/scripts/nt/activate.bat @@ -1,31 +1,32 @@ @echo off -set VIRTUAL_ENV=__VENV_DIR__ +set "VIRTUAL_ENV=__VENV_DIR__" if not defined PROMPT ( - set PROMPT=$P$G + set "PROMPT=$P$G" ) if defined _OLD_VIRTUAL_PROMPT ( - set PROMPT=%_OLD_VIRTUAL_PROMPT% + set "PROMPT=%_OLD_VIRTUAL_PROMPT%" ) if defined _OLD_VIRTUAL_PYTHONHOME ( - set PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME% + set "PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME%" ) -set _OLD_VIRTUAL_PROMPT=%PROMPT% -set PROMPT=__VENV_NAME__%PROMPT% +set "_OLD_VIRTUAL_PROMPT=%PROMPT%" +set "PROMPT=__VENV_NAME__%PROMPT%" if defined PYTHONHOME ( - set _OLD_VIRTUAL_PYTHONHOME=%PYTHONHOME% - set PYTHONHOME= + set "_OLD_VIRTUAL_PYTHONHOME=%PYTHONHOME%" + set PYTHONHOME= ) -if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH%; goto SKIPPATH +if defined _OLD_VIRTUAL_PATH ( + set "PATH=%_OLD_VIRTUAL_PATH%" +) else ( + set "_OLD_VIRTUAL_PATH=%PATH%" +) -set _OLD_VIRTUAL_PATH=%PATH% - -:SKIPPATH -set PATH=%VIRTUAL_ENV%\__VENV_BIN_NAME__;%PATH% +set "PATH=%VIRTUAL_ENV%\__VENV_BIN_NAME__;%PATH%" :END -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 21 05:18:02 2013 From: python-checkins at python.org (roger.serwy) Date: Tue, 21 May 2013 05:18:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE0MTQ2OiBIaWdo?= =?utf-8?q?light_source_line_while_debugging_on_Windows=2E?= Message-ID: <3bF2Gy451lzSjM@mail.python.org> http://hg.python.org/cpython/rev/5ae830ff6d64 changeset: 83876:5ae830ff6d64 branch: 2.7 parent: 83869:7937f5c56924 user: Roger Serwy date: Mon May 20 22:13:39 2013 -0500 summary: #14146: Highlight source line while debugging on Windows. files: Lib/idlelib/EditorWindow.py | 30 +++++++++++++++++++++++++ Misc/NEWS | 6 +++++ 2 files changed, 36 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -346,6 +346,36 @@ self.askinteger = tkSimpleDialog.askinteger self.showerror = tkMessageBox.showerror + self._highlight_workaround() # Fix selection tags on Windows + + def _highlight_workaround(self): + # On Windows, Tk removes painting of the selection + # tags which is different behavior than on Linux and Mac. + # See issue14146 for more information. + if not sys.platform.startswith('win'): + return + + text = self.text + text.event_add("<>", "") + text.event_add("<>", "") + def highlight_fix(focus): + sel_range = text.tag_ranges("sel") + if sel_range: + if focus == 'out': + HILITE_CONFIG = idleConf.GetHighlight( + idleConf.CurrentTheme(), 'hilite') + text.tag_config("sel_fix", HILITE_CONFIG) + text.tag_raise("sel_fix") + text.tag_add("sel_fix", *sel_range) + elif focus == 'in': + text.tag_remove("sel_fix", "1.0", "end") + + text.bind("<>", + lambda ev: highlight_fix("out")) + text.bind("<>", + lambda ev: highlight_fix("in")) + + def _filename_to_unicode(self, filename): """convert filename to unicode in order to display it in Tk""" if isinstance(filename, unicode) or not filename: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -21,6 +21,12 @@ - Fix typos in the multiprocessing module. +IDLE +---- + +- Issue #14146: Highlight source line while debugging on Windows. + + Tests ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 21 05:18:03 2013 From: python-checkins at python.org (roger.serwy) Date: Tue, 21 May 2013 05:18:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE0MTQ2OiBIaWdo?= =?utf-8?q?light_source_line_while_debugging_on_Windows=2E?= Message-ID: <3bF2Gz6VqnzSmS@mail.python.org> http://hg.python.org/cpython/rev/3735b4e0fc7c changeset: 83877:3735b4e0fc7c branch: 3.3 parent: 83874:66c87d2b3435 user: Roger Serwy date: Mon May 20 22:13:39 2013 -0500 summary: #14146: Highlight source line while debugging on Windows. files: Lib/idlelib/EditorWindow.py | 30 +++++++++++++++++++++++++ Misc/NEWS | 6 +++++ 2 files changed, 36 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -340,6 +340,36 @@ self.askinteger = tkSimpleDialog.askinteger self.showerror = tkMessageBox.showerror + self._highlight_workaround() # Fix selection tags on Windows + + def _highlight_workaround(self): + # On Windows, Tk removes painting of the selection + # tags which is different behavior than on Linux and Mac. + # See issue14146 for more information. + if not sys.platform.startswith('win'): + return + + text = self.text + text.event_add("<>", "") + text.event_add("<>", "") + def highlight_fix(focus): + sel_range = text.tag_ranges("sel") + if sel_range: + if focus == 'out': + HILITE_CONFIG = idleConf.GetHighlight( + idleConf.CurrentTheme(), 'hilite') + text.tag_config("sel_fix", HILITE_CONFIG) + text.tag_raise("sel_fix") + text.tag_add("sel_fix", *sel_range) + elif focus == 'in': + text.tag_remove("sel_fix", "1.0", "end") + + text.bind("<>", + lambda ev: highlight_fix("out")) + text.bind("<>", + lambda ev: highlight_fix("in")) + + def _filename_to_unicode(self, filename): """convert filename to unicode in order to display it in Tk""" if isinstance(filename, str) or not filename: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,6 +37,12 @@ - Issue #17968: Fix memory leak in os.listxattr(). +IDLE +---- + +- Issue #14146: Highlight source line while debugging on Windows. + + Tests ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 21 05:18:05 2013 From: python-checkins at python.org (roger.serwy) Date: Tue, 21 May 2013 05:18:05 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogIzE0MTQ2OiBtZXJnZSB3aXRoIDMuMy4=?= Message-ID: <3bF2H11ny7z7LkL@mail.python.org> http://hg.python.org/cpython/rev/b56ae3f878cb changeset: 83878:b56ae3f878cb parent: 83875:96c842873c30 parent: 83877:3735b4e0fc7c user: Roger Serwy date: Mon May 20 22:16:53 2013 -0500 summary: #14146: merge with 3.3. files: Lib/idlelib/EditorWindow.py | 30 +++++++++++++++++++++++++ Misc/NEWS | 2 + 2 files changed, 32 insertions(+), 0 deletions(-) diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -340,6 +340,36 @@ self.askinteger = tkSimpleDialog.askinteger self.showerror = tkMessageBox.showerror + self._highlight_workaround() # Fix selection tags on Windows + + def _highlight_workaround(self): + # On Windows, Tk removes painting of the selection + # tags which is different behavior than on Linux and Mac. + # See issue14146 for more information. + if not sys.platform.startswith('win'): + return + + text = self.text + text.event_add("<>", "") + text.event_add("<>", "") + def highlight_fix(focus): + sel_range = text.tag_ranges("sel") + if sel_range: + if focus == 'out': + HILITE_CONFIG = idleConf.GetHighlight( + idleConf.CurrentTheme(), 'hilite') + text.tag_config("sel_fix", HILITE_CONFIG) + text.tag_raise("sel_fix") + text.tag_add("sel_fix", *sel_range) + elif focus == 'in': + text.tag_remove("sel_fix", "1.0", "end") + + text.bind("<>", + lambda ev: highlight_fix("out")) + text.bind("<>", + lambda ev: highlight_fix("in")) + + def _filename_to_unicode(self, filename): """convert filename to unicode in order to display it in Tk""" if isinstance(filename, str) or not filename: diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -351,6 +351,8 @@ IDLE ---- +- Issue #14146: Highlight source line while debugging on Windows. + - Issue #17838: Allow sys.stdin to be reassigned. - Issue #13495: Avoid loading the color delegator twice in IDLE. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue May 21 05:49:36 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 21 May 2013 05:49:36 +0200 Subject: [Python-checkins] Daily reference leaks (96c842873c30): sum=0 Message-ID: results for 96c842873c30 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/refloglhhuRr', '-x'] From python-checkins at python.org Tue May 21 09:49:46 2013 From: python-checkins at python.org (charles-francois.natali) Date: Tue, 21 May 2013 09:49:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2317683=3A_socket_m?= =?utf-8?q?odule=3A_return_AF=5FUNIX_addresses_in_Linux_abstract?= Message-ID: <3bF8JV3TY4z7Ljd@mail.python.org> http://hg.python.org/cpython/rev/c0f2b038fc12 changeset: 83879:c0f2b038fc12 user: Charles-Fran?ois Natali date: Tue May 21 09:49:18 2013 +0200 summary: Issue #17683: socket module: return AF_UNIX addresses in Linux abstract namespace as string. files: Lib/test/test_socket.py | 12 ++++++------ Misc/NEWS | 3 +++ Modules/socketmodule.c | 2 +- 3 files changed, 10 insertions(+), 7 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 @@ -4451,7 +4451,7 @@ UNIX_PATH_MAX = 108 def testLinuxAbstractNamespace(self): - address = b"\x00python-test-hello\x00\xff" + address = "\x00python-test-hello\x00\xff" with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s1: s1.bind(address) s1.listen(1) @@ -4462,7 +4462,7 @@ self.assertEqual(s2.getpeername(), address) def testMaxName(self): - address = b"\x00" + b"h" * (self.UNIX_PATH_MAX - 1) + address = "\x00" + "h" * (self.UNIX_PATH_MAX - 1) with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s: s.bind(address) self.assertEqual(s.getsockname(), address) @@ -4472,12 +4472,12 @@ with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s: self.assertRaises(OSError, s.bind, address) - def testStrName(self): - # Check that an abstract name can be passed as a string. + def testBytesName(self): + # Check that an abstract name can be passed as bytes. s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) try: - s.bind("\x00python\x00test\x00") - self.assertEqual(s.getsockname(), b"\x00python\x00test\x00") + s.bind(b"\x00python\x00test\x00") + self.assertEqual(s.getsockname(), "\x00python\x00test\x00") finally: s.close() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -99,6 +99,9 @@ Library ------- +- Issue #17683: socket module: return AF_UNIX addresses in Linux abstract + namespace as string. + - Issue #17914: Add os.cpu_count(). Patch by Yogesh Chaudhari, based on an initial patch by Trent Nelson. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -1018,7 +1018,7 @@ #ifdef linux if (a->sun_path[0] == 0) { /* Linux abstract namespace */ addrlen -= offsetof(struct sockaddr_un, sun_path); - return PyBytes_FromStringAndSize(a->sun_path, addrlen); + return PyUnicode_DecodeFSDefaultAndSize(a->sun_path, addrlen); } else #endif /* linux */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 21 10:46:13 2013 From: python-checkins at python.org (charles-francois.natali) Date: Tue, 21 May 2013 10:46:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Backed_out_changeset_c0f2b?= =?utf-8?q?038fc12?= Message-ID: <3bF9Yd2QhHzS56@mail.python.org> http://hg.python.org/cpython/rev/05f4fee706f5 changeset: 83880:05f4fee706f5 user: Charles-Fran?ois Natali date: Tue May 21 10:45:46 2013 +0200 summary: Backed out changeset c0f2b038fc12 files: Lib/test/test_socket.py | 12 ++++++------ Misc/NEWS | 3 --- Modules/socketmodule.c | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -4451,7 +4451,7 @@ UNIX_PATH_MAX = 108 def testLinuxAbstractNamespace(self): - address = "\x00python-test-hello\x00\xff" + address = b"\x00python-test-hello\x00\xff" with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s1: s1.bind(address) s1.listen(1) @@ -4462,7 +4462,7 @@ self.assertEqual(s2.getpeername(), address) def testMaxName(self): - address = "\x00" + "h" * (self.UNIX_PATH_MAX - 1) + address = b"\x00" + b"h" * (self.UNIX_PATH_MAX - 1) with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s: s.bind(address) self.assertEqual(s.getsockname(), address) @@ -4472,12 +4472,12 @@ with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s: self.assertRaises(OSError, s.bind, address) - def testBytesName(self): - # Check that an abstract name can be passed as bytes. + def testStrName(self): + # Check that an abstract name can be passed as a string. s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) try: - s.bind(b"\x00python\x00test\x00") - self.assertEqual(s.getsockname(), "\x00python\x00test\x00") + s.bind("\x00python\x00test\x00") + self.assertEqual(s.getsockname(), b"\x00python\x00test\x00") finally: s.close() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -99,9 +99,6 @@ Library ------- -- Issue #17683: socket module: return AF_UNIX addresses in Linux abstract - namespace as string. - - Issue #17914: Add os.cpu_count(). Patch by Yogesh Chaudhari, based on an initial patch by Trent Nelson. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -1018,7 +1018,7 @@ #ifdef linux if (a->sun_path[0] == 0) { /* Linux abstract namespace */ addrlen -= offsetof(struct sockaddr_un, sun_path); - return PyUnicode_DecodeFSDefaultAndSize(a->sun_path, addrlen); + return PyBytes_FromStringAndSize(a->sun_path, addrlen); } else #endif /* linux */ -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 21 11:49:24 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 21 May 2013 11:49:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2317900=3A_Allowed_?= =?utf-8?q?pickling_of_recursive_OrderedDicts=2E__Decreased_pickled?= Message-ID: <3bFByX0J6Kz7Ljd@mail.python.org> http://hg.python.org/cpython/rev/56f25569ba86 changeset: 83881:56f25569ba86 user: Serhiy Storchaka date: Tue May 21 12:47:57 2013 +0300 summary: Issue #17900: Allowed pickling of recursive OrderedDicts. Decreased pickled size and pickling time. files: Lib/collections/__init__.py | 5 +---- Lib/test/test_collections.py | 13 +++++++++++-- Misc/NEWS | 3 +++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -199,13 +199,10 @@ def __reduce__(self): 'Return state information for pickling' - items = [[k, self[k]] for k in self] inst_dict = vars(self).copy() for k in vars(OrderedDict()): inst_dict.pop(k, None) - if inst_dict: - return (self.__class__, (items,), inst_dict) - return self.__class__, (items,) + return self.__class__, (), inst_dict or None, None, iter(self.items()) def copy(self): 'od.copy() -> a shallow copy of od' 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 @@ -1245,9 +1245,18 @@ # do not save instance dictionary if not needed pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] od = OrderedDict(pairs) - self.assertEqual(len(od.__reduce__()), 2) + self.assertIsNone(od.__reduce__()[2]) od.x = 10 - self.assertEqual(len(od.__reduce__()), 3) + self.assertIsNotNone(od.__reduce__()[2]) + + def test_pickle_recursive(self): + od = OrderedDict() + od[1] = od + for proto in range(-1, pickle.HIGHEST_PROTOCOL + 1): + dup = pickle.loads(pickle.dumps(od, proto)) + self.assertIsNot(dup, od) + self.assertEqual(list(dup.keys()), [1]) + self.assertIs(dup[1], dup) def test_repr(self): od = OrderedDict([('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -99,6 +99,9 @@ Library ------- +- Issue #17900: Allowed pickling of recursive OrderedDicts. Decreased pickled + size and pickling time. + - Issue #17914: Add os.cpu_count(). Patch by Yogesh Chaudhari, based on an initial patch by Trent Nelson. -- Repository URL: http://hg.python.org/cpython From ncoghlan at gmail.com Tue May 21 15:24:17 2013 From: ncoghlan at gmail.com (Nick Coghlan) Date: Tue, 21 May 2013 23:24:17 +1000 Subject: [Python-checkins] cpython (3.3): #17973: Add FAQ entry for ([], )[0] += [1] both extending and raising. In-Reply-To: <3bDjLs4fyNz7Lkh@mail.python.org> References: <3bDjLs4fyNz7Lkh@mail.python.org> Message-ID: On Tue, May 21, 2013 at 12:35 AM, r.david.murray wrote: Yay for having this in the FAQ, but... > +If you wrote:: > + > + >>> a_tuple = (1, 2) > + >>> a_tuple[0] += 1 > + Traceback (most recent call last): > + ... > + TypeError: 'tuple' object does not support item assignment > + > +The reason for the exception should be immediately clear: ``1`` is added to the > +object ``a_tuple[0]`` points to (``1``), producing the result object, ``2``, > +but when we attempt to assign the result of the computation, ``2``, to element > +``0`` of the tuple, we get an error because we can't change what an element of > +a tuple points to. > + > +Under the covers, what this augmented assignment statement is doing is > +approximately this:: > + > + >>> result = a_tuple[0].__iadd__(1) > + >>> a_tuple[0] = result > + Traceback (most recent call last): > + ... > + TypeError: 'tuple' object does not support item assignment For the immutable case, this expansion is incorrect: >>> hasattr(0, "__iadd__") False With immutable objects, += almost always expands to: >>> result = a_tuple[0] + 1 >>> a_tuple[0] = result (For containers that support binary operators, the presence of the relevant __i*__ methods is actually a reasonable heuristic for distinguishing the mutable and immutable versions) Cheers, Nick. -- Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia From python-checkins at python.org Tue May 21 17:35:09 2013 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 21 May 2013 17:35:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Add_async=28=29=2E__See_https?= =?utf-8?q?=3A//codereview=2Eappspot=2Ecom/9245047/?= Message-ID: <3bFLdT4dlmz7LqR@mail.python.org> http://hg.python.org/peps/rev/fdcd3bba1ad5 changeset: 4901:fdcd3bba1ad5 user: Guido van Rossum date: Tue May 21 08:34:55 2013 -0700 summary: Add async(). See https://codereview.appspot.com/9245047/ files: pep-3156.txt | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-) diff --git a/pep-3156.txt b/pep-3156.txt --- a/pep-3156.txt +++ b/pep-3156.txt @@ -260,8 +260,7 @@ - Basic callbacks: ``call_soon()``, ``call_later()``, ``call_at()``. - Thread interaction: ``call_soon_threadsafe()``, - ``wrap_future()``, ``run_in_executor()``, - ``set_default_executor()``. + ``run_in_executor()``, ``set_default_executor()``. - Internet name lookups: ``getaddrinfo()``, ``getnameinfo()``. @@ -903,7 +902,13 @@ 3.3, so changes to ``concurrent.futures.Future`` are off the table for now. -There is one public function related to Futures. It is: +There are some public functions related to Futures: + +- ``async(arg)``. This takes an argument that is either a coroutine + object or a Future (i.e., anything you can use with ``yield from``) + and returns a Future. If the argument is a Future, it is returned + unchanged; if it is a coroutine object, it wraps it in a Task + (remember that ``Task`` is a subclass of ``Future``). - ``wrap_future(future)``. This takes a PEP 3148 Future (i.e., an instance of ``concurrent.futures.Future``) and returns a Future -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Tue May 21 17:48:00 2013 From: python-checkins at python.org (r.david.murray) Date: Tue, 21 May 2013 17:48:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE3OTczOiBmaXgg?= =?utf-8?q?technical_inaccuracy_in_faq_entry_=28it_now_passes_doctest=29?= =?utf-8?q?=2E?= Message-ID: <3bFLwJ5Wjrz7Lkp@mail.python.org> http://hg.python.org/cpython/rev/6ab88d6527f1 changeset: 83882:6ab88d6527f1 branch: 3.3 parent: 83877:3735b4e0fc7c user: R David Murray date: Tue May 21 11:44:41 2013 -0400 summary: #17973: fix technical inaccuracy in faq entry (it now passes doctest). files: Doc/faq/programming.rst | 13 ++++++++----- 1 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -1131,7 +1131,7 @@ Under the covers, what this augmented assignment statement is doing is approximately this:: - >>> result = a_tuple[0].__iadd__(1) + >>> result = a_tuple[0] + 1 >>> a_tuple[0] = result Traceback (most recent call last): ... @@ -1154,16 +1154,19 @@ >>> a_tuple[0] ['foo', 'item'] -To see why this happens, you need to know that for lists, ``__iadd__`` is equivalent -to calling ``extend`` on the list and returning the list. That's why we say -that for lists, ``+=`` is a "shorthand" for ``list.extend``:: +To see why this happens, you need to know that (a) if an object implements an +``__iadd__`` magic method, it gets called when the ``+=`` augmented assignment +is executed, and its return value is what gets used in the assignment statement; +and (b) for lists, ``__iadd__`` is equivalent to calling ``extend`` on the list +and returning the list. That's why we say that for lists, ``+=`` is a +"shorthand" for ``list.extend``:: >>> a_list = [] >>> a_list += [1] >>> a_list [1] -is equivalent to:: +This is equivalent to:: >>> result = a_list.__iadd__([1]) >>> a_list = result -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 21 17:48:02 2013 From: python-checkins at python.org (r.david.murray) Date: Tue, 21 May 2013 17:48:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge_=2317973=3A_fix_technical_inaccuracy_in_faq_entry_?= =?utf-8?q?=28it_now_passes_doctest=29=2E?= Message-ID: <3bFLwL0hgRz7Lkp@mail.python.org> http://hg.python.org/cpython/rev/26588b6a39d9 changeset: 83883:26588b6a39d9 parent: 83881:56f25569ba86 parent: 83882:6ab88d6527f1 user: R David Murray date: Tue May 21 11:45:09 2013 -0400 summary: merge #17973: fix technical inaccuracy in faq entry (it now passes doctest). files: Doc/faq/programming.rst | 13 ++++++++----- 1 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -1131,7 +1131,7 @@ Under the covers, what this augmented assignment statement is doing is approximately this:: - >>> result = a_tuple[0].__iadd__(1) + >>> result = a_tuple[0] + 1 >>> a_tuple[0] = result Traceback (most recent call last): ... @@ -1154,16 +1154,19 @@ >>> a_tuple[0] ['foo', 'item'] -To see why this happens, you need to know that for lists, ``__iadd__`` is equivalent -to calling ``extend`` on the list and returning the list. That's why we say -that for lists, ``+=`` is a "shorthand" for ``list.extend``:: +To see why this happens, you need to know that (a) if an object implements an +``__iadd__`` magic method, it gets called when the ``+=`` augmented assignment +is executed, and its return value is what gets used in the assignment statement; +and (b) for lists, ``__iadd__`` is equivalent to calling ``extend`` on the list +and returning the list. That's why we say that for lists, ``+=`` is a +"shorthand" for ``list.extend``:: >>> a_list = [] >>> a_list += [1] >>> a_list [1] -is equivalent to:: +This is equivalent to:: >>> result = a_list.__iadd__([1]) >>> a_list = result -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 21 17:48:03 2013 From: python-checkins at python.org (r.david.murray) Date: Tue, 21 May 2013 17:48:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE3OTczOiBmaXgg?= =?utf-8?q?technical_inaccuracy_in_faq_entry_=28it_now_passes_doctest=29?= =?utf-8?q?=2E?= Message-ID: <3bFLwM2yjXz7Lpr@mail.python.org> http://hg.python.org/cpython/rev/7fce9186accb changeset: 83884:7fce9186accb branch: 2.7 parent: 83876:5ae830ff6d64 user: R David Murray date: Tue May 21 11:46:18 2013 -0400 summary: #17973: fix technical inaccuracy in faq entry (it now passes doctest). files: Doc/faq/programming.rst | 13 ++++++++----- 1 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -1251,7 +1251,7 @@ Under the covers, what this augmented assignment statement is doing is approximately this:: - >>> result = a_tuple[0].__iadd__(1) + >>> result = a_tuple[0] + 1 >>> a_tuple[0] = result Traceback (most recent call last): ... @@ -1274,16 +1274,19 @@ >>> a_tuple[0] ['foo', 'item'] -To see why this happens, you need to know that for lists, ``__iadd__`` is equivalent -to calling ``extend`` on the list and returning the list. That's why we say -that for lists, ``+=`` is a "shorthand" for ``list.extend``:: +To see why this happens, you need to know that (a) if an object implements an +``__iadd__`` magic method, it gets called when the ``+=`` augmented assignment +is executed, and its return value is what gets used in the assignment statement; +and (b) for lists, ``__iadd__`` is equivalent to calling ``extend`` on the list +and returning the list. That's why we say that for lists, ``+=`` is a +"shorthand" for ``list.extend``:: >>> a_list = [] >>> a_list += [1] >>> a_list [1] -is equivalent to:: +This is equivalent to:: >>> result = a_list.__iadd__([1]) >>> a_list = result -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 21 21:02:16 2013 From: python-checkins at python.org (giampaolo.rodola) Date: Tue, 21 May 2013 21:02:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_issue_=2317996=3A_expo?= =?utf-8?q?se_socket=2EAF=5FLINK_constant_on_BSD_and_OSX=2E?= Message-ID: <3bFRDS45nyzSWL@mail.python.org> http://hg.python.org/cpython/rev/155e6fb309f5 changeset: 83885:155e6fb309f5 parent: 83883:26588b6a39d9 user: Giampaolo Rodola' date: Tue May 21 21:02:04 2013 +0200 summary: Fix issue #17996: expose socket.AF_LINK constant on BSD and OSX. files: Doc/library/socket.rst | 5 +++++ Misc/NEWS | 2 ++ Modules/socketmodule.c | 3 +++ 3 files changed, 10 insertions(+), 0 deletions(-) diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -293,6 +293,11 @@ TIPC related constants, matching the ones exported by the C socket API. See the TIPC documentation for more information. +.. data:: AF_LINK + + Availability: BSD, OSX. + + .. versionadded:: 3.4 .. data:: has_ipv6 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -99,6 +99,8 @@ Library ------- +- Issue #17996: socket module now exposes AF_LINK constant on BSD and OSX. + - Issue #17900: Allowed pickling of recursive OrderedDicts. Decreased pickled size and pickling time. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -5658,6 +5658,9 @@ /* Alias to emulate 4.4BSD */ PyModule_AddIntMacro(m, AF_ROUTE); #endif +#ifdef AF_LINK + PyModule_AddIntMacro(m, AF_LINK); +#endif #ifdef AF_ASH /* Ash */ PyModule_AddIntMacro(m, AF_ASH); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 21 21:54:41 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 21 May 2013 21:54:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3OTc5?= =?utf-8?q?=3A_Fixed_the_re_module_in_build_with_--disable-unicode=2E?= Message-ID: <3bFSNx6HZkzSHm@mail.python.org> http://hg.python.org/cpython/rev/8408eed151eb changeset: 83886:8408eed151eb branch: 2.7 parent: 83884:7fce9186accb user: Serhiy Storchaka date: Tue May 21 22:53:33 2013 +0300 summary: Issue #17979: Fixed the re module in build with --disable-unicode. files: Misc/NEWS | 2 ++ Modules/sre.h | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -58,6 +58,8 @@ Library ------- +- Issue #17979: Fixed the re module in build with --disable-unicode. + - Issue #17606: Fixed support of encoded byte strings in the XMLGenerator .characters() and ignorableWhitespace() methods. Original patch by Sebastian Ortiz Vasquez. diff --git a/Modules/sre.h b/Modules/sre.h --- a/Modules/sre.h +++ b/Modules/sre.h @@ -23,8 +23,8 @@ # define SRE_MAXREPEAT ((SRE_CODE)PY_SSIZE_T_MAX + 1u) # endif #else -# define SRE_CODE unsigned long -# if SIZEOF_SIZE_T > SIZEOF_LONG +# define SRE_CODE unsigned int +# if SIZEOF_SIZE_T > SIZEOF_INT # define SRE_MAXREPEAT (~(SRE_CODE)0) # else # define SRE_MAXREPEAT ((SRE_CODE)PY_SSIZE_T_MAX + 1u) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed May 22 05:48:59 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 22 May 2013 05:48:59 +0200 Subject: [Python-checkins] Daily reference leaks (155e6fb309f5): sum=-1 Message-ID: results for 155e6fb309f5 on branch "default" -------------------------------------------- test_support leaked [0, 0, -1] references, sum=-1 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogP_Qacb', '-x'] From python-checkins at python.org Wed May 22 14:36:18 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 22 May 2013 14:36:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3ODQ0?= =?utf-8?q?=3A_Refactor_a_documentation_of_Python_specific_encodings=2E?= Message-ID: <3bFtcf18qVz7LkD@mail.python.org> http://hg.python.org/cpython/rev/85c04fdaa404 changeset: 83887:85c04fdaa404 branch: 2.7 user: Serhiy Storchaka date: Wed May 22 15:28:30 2013 +0300 summary: Issue #17844: Refactor a documentation of Python specific encodings. Add links to encoders and decoders for binary-to-binary codecs. files: Doc/library/codecs.rst | 174 ++++++++++++++++------------ Misc/NEWS | 7 +- 2 files changed, 105 insertions(+), 76 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -1098,88 +1098,112 @@ | utf_8_sig | | all languages | +-----------------+--------------------------------+--------------------------------+ -A number of codecs are specific to Python, so their codec names have no meaning -outside Python. Some of them don't convert from Unicode strings to byte strings, -but instead use the property of the Python codecs machinery that any bijective -function with one argument can be considered as an encoding. +Python Specific Encodings +------------------------- -For the codecs listed below, the result in the "encoding" direction is always a -byte string. The result of the "decoding" direction is listed as operand type in -the table. +A number of predefined codecs are specific to Python, so their codec names have +no meaning outside Python. These are listed in the tables below based on the +expected input and output types (note that while text encodings are the most +common use case for codecs, the underlying codec infrastructure supports +arbitrary data transforms rather than just text encodings). For asymmetric +codecs, the stated purpose describes the encoding direction. -.. tabularcolumns:: |l|p{0.3\linewidth}|l|p{0.3\linewidth}| +The following codecs provide unicode-to-str encoding [#encoding-note]_ and +str-to-unicode decoding [#decoding-note]_, similar to the Unicode text +encodings. -+--------------------+---------------------------+----------------+---------------------------+ -| Codec | Aliases | Operand type | Purpose | -+====================+===========================+================+===========================+ -| base64_codec | base64, base-64 | byte string | Convert operand to MIME | -| | | | base64 (the result always | -| | | | includes a trailing | -| | | | ``'\n'``) | -+--------------------+---------------------------+----------------+---------------------------+ -| bz2_codec | bz2 | byte string | Compress the operand | -| | | | using bz2 | -+--------------------+---------------------------+----------------+---------------------------+ -| hex_codec | hex | byte string | Convert operand to | -| | | | hexadecimal | -| | | | representation, with two | -| | | | digits per byte | -+--------------------+---------------------------+----------------+---------------------------+ -| idna | | Unicode string | Implements :rfc:`3490`, | -| | | | see also | -| | | | :mod:`encodings.idna` | -+--------------------+---------------------------+----------------+---------------------------+ -| mbcs | dbcs | Unicode string | Windows only: Encode | -| | | | operand according to the | -| | | | ANSI codepage (CP_ACP) | -+--------------------+---------------------------+----------------+---------------------------+ -| palmos | | Unicode string | Encoding of PalmOS 3.5 | -+--------------------+---------------------------+----------------+---------------------------+ -| punycode | | Unicode string | Implements :rfc:`3492` | -+--------------------+---------------------------+----------------+---------------------------+ -| quopri_codec | quopri, quoted-printable, | byte string | Convert operand to MIME | -| | quotedprintable | | quoted printable | -+--------------------+---------------------------+----------------+---------------------------+ -| raw_unicode_escape | | Unicode string | Produce a string that is | -| | | | suitable as raw Unicode | -| | | | literal in Python source | -| | | | code | -+--------------------+---------------------------+----------------+---------------------------+ -| rot_13 | rot13 | Unicode string | Returns the Caesar-cypher | -| | | | encryption of the operand | -+--------------------+---------------------------+----------------+---------------------------+ -| string_escape | | byte string | Produce a string that is | -| | | | suitable as string | -| | | | literal in Python source | -| | | | code | -+--------------------+---------------------------+----------------+---------------------------+ -| undefined | | any | Raise an exception for | -| | | | all conversions. Can be | -| | | | used as the system | -| | | | encoding if no automatic | -| | | | :term:`coercion` between | -| | | | byte and Unicode strings | -| | | | is desired. | -+--------------------+---------------------------+----------------+---------------------------+ -| unicode_escape | | Unicode string | Produce a string that is | -| | | | suitable as Unicode | -| | | | literal in Python source | -| | | | code | -+--------------------+---------------------------+----------------+---------------------------+ -| unicode_internal | | Unicode string | Return the internal | -| | | | representation of the | -| | | | operand | -+--------------------+---------------------------+----------------+---------------------------+ -| uu_codec | uu | byte string | Convert the operand using | -| | | | uuencode | -+--------------------+---------------------------+----------------+---------------------------+ -| zlib_codec | zip, zlib | byte string | Compress the operand | -| | | | using gzip | -+--------------------+---------------------------+----------------+---------------------------+ +.. tabularcolumns:: |l|L|L| + ++--------------------+---------------------------+---------------------------+ +| Codec | Aliases | Purpose | ++====================+===========================+===========================+ +| idna | | Implements :rfc:`3490`, | +| | | see also | +| | | :mod:`encodings.idna` | ++--------------------+---------------------------+---------------------------+ +| mbcs | dbcs | Windows only: Encode | +| | | operand according to the | +| | | ANSI codepage (CP_ACP) | ++--------------------+---------------------------+---------------------------+ +| palmos | | Encoding of PalmOS 3.5 | ++--------------------+---------------------------+---------------------------+ +| punycode | | Implements :rfc:`3492` | ++--------------------+---------------------------+---------------------------+ +| raw_unicode_escape | | Produce a string that is | +| | | suitable as raw Unicode | +| | | literal in Python source | +| | | code | ++--------------------+---------------------------+---------------------------+ +| rot_13 | rot13 | Returns the Caesar-cypher | +| | | encryption of the operand | ++--------------------+---------------------------+---------------------------+ +| undefined | | Raise an exception for | +| | | all conversions. Can be | +| | | used as the system | +| | | encoding if no automatic | +| | | :term:`coercion` between | +| | | byte and Unicode strings | +| | | is desired. | ++--------------------+---------------------------+---------------------------+ +| unicode_escape | | Produce a string that is | +| | | suitable as Unicode | +| | | literal in Python source | +| | | code | ++--------------------+---------------------------+---------------------------+ +| unicode_internal | | Return the internal | +| | | representation of the | +| | | operand | ++--------------------+---------------------------+---------------------------+ .. versionadded:: 2.3 The ``idna`` and ``punycode`` encodings. +The following codecs provide str-to-str encoding and decoding +[#decoding-note]_. + +.. tabularcolumns:: |l|L|L|L| + ++--------------------+---------------------------+---------------------------+------------------------------+ +| Codec | Aliases | Purpose | Encoder/decoder | ++====================+===========================+===========================+==============================+ +| base64_codec | base64, base-64 | Convert operand to MIME | :meth:`base64.b64encode`, | +| | | base64 (the result always | :meth:`base64.b64decode` | +| | | includes a trailing | | +| | | ``'\n'``) | | ++--------------------+---------------------------+---------------------------+------------------------------+ +| bz2_codec | bz2 | Compress the operand | :meth:`bz2.compress`, | +| | | using bz2 | :meth:`bz2.decompress` | ++--------------------+---------------------------+---------------------------+------------------------------+ +| hex_codec | hex | Convert operand to | :meth:`base64.b16encode`, | +| | | hexadecimal | :meth:`base64.b16decode` | +| | | representation, with two | | +| | | digits per byte | | ++--------------------+---------------------------+---------------------------+------------------------------+ +| quopri_codec | quopri, quoted-printable, | Convert operand to MIME | :meth:`quopri.encodestring`, | +| | quotedprintable | quoted printable | :meth:`quopri.decodestring` | ++--------------------+---------------------------+---------------------------+------------------------------+ +| string_escape | | Produce a string that is | | +| | | suitable as string | | +| | | literal in Python source | | +| | | code | | ++--------------------+---------------------------+---------------------------+------------------------------+ +| uu_codec | uu | Convert the operand using | :meth:`uu.encode`, | +| | | uuencode | :meth:`uu.decode` | ++--------------------+---------------------------+---------------------------+------------------------------+ +| zlib_codec | zip, zlib | Compress the operand | :meth:`zlib.compress`, | +| | | using gzip | :meth:`zlib.decompress` | ++--------------------+---------------------------+---------------------------+------------------------------+ + +.. [#encoding-note] str objects are also accepted as input in place of unicode + objects. They are implicitly converted to unicode by decoding them using + the default encoding. If this conversion fails, it may lead to encoding + operations raising :exc:`UnicodeDecodeError`. + +.. [#decoding-note] unicode objects are also accepted as input in place of str + objects. They are implicitly converted to str by encoding them using the + default encoding. If this conversion fails, it may lead to decoding + operations raising :exc:`UnicodeEncodeError`. + :mod:`encodings.idna` --- Internationalized Domain Names in Applications ------------------------------------------------------------------------ diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -26,12 +26,17 @@ - Issue #14146: Highlight source line while debugging on Windows. - Tests ----- - Issue #11995: test_pydoc doesn't import all sys.path modules anymore. +Documentation +------------- + +- Issue #17844: Refactor a documentation of Python specific encodings. + Add links to encoders and decoders for binary-to-binary codecs. + What's New in Python 2.7.5? =========================== -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 22 14:36:19 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 22 May 2013 14:36:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3ODQ0?= =?utf-8?q?=3A_Add_links_to_encoders_and_decoders_for_bytes-to-bytes_codec?= =?utf-8?q?s=2E?= Message-ID: <3bFtcg4kYFz7Lkh@mail.python.org> http://hg.python.org/cpython/rev/039dc6dd2bc0 changeset: 83888:039dc6dd2bc0 branch: 3.3 parent: 83882:6ab88d6527f1 user: Serhiy Storchaka date: Wed May 22 15:33:09 2013 +0300 summary: Issue #17844: Add links to encoders and decoders for bytes-to-bytes codecs. files: Doc/library/codecs.rst | 52 +++++++++++++++--------------- Misc/NEWS | 3 +- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -1188,33 +1188,33 @@ The following codecs provide bytes-to-bytes mappings. -.. tabularcolumns:: |l|L| +.. tabularcolumns:: |l|L|L| -+--------------------+---------------------------+ -| Codec | Purpose | -+====================+===========================+ -| base64_codec | Convert operand to MIME | -| | base64 (the result always | -| | includes a trailing | -| | ``'\n'``) | -+--------------------+---------------------------+ -| bz2_codec | Compress the operand | -| | using bz2 | -+--------------------+---------------------------+ -| hex_codec | Convert operand to | -| | hexadecimal | -| | representation, with two | -| | digits per byte | -+--------------------+---------------------------+ -| quopri_codec | Convert operand to MIME | -| | quoted printable | -+--------------------+---------------------------+ -| uu_codec | Convert the operand using | -| | uuencode | -+--------------------+---------------------------+ -| zlib_codec | Compress the operand | -| | using gzip | -+--------------------+---------------------------+ ++--------------------+---------------------------+------------------------------+ +| Codec | Purpose | Encoder/decoder | ++====================+===========================+==============================+ +| base64_codec | Convert operand to MIME | :meth:`base64.b64encode`, | +| | base64 (the result always | :meth:`base64.b64decode` | +| | includes a trailing | | +| | ``'\n'``) | | ++--------------------+---------------------------+------------------------------+ +| bz2_codec | Compress the operand | :meth:`bz2.compress`, | +| | using bz2 | :meth:`bz2.decompress` | ++--------------------+---------------------------+------------------------------+ +| hex_codec | Convert operand to | :meth:`base64.b16encode`, | +| | hexadecimal | :meth:`base64.b16decode` | +| | representation, with two | | +| | digits per byte | | ++--------------------+---------------------------+------------------------------+ +| quopri_codec | Convert operand to MIME | :meth:`quopri.encodestring`, | +| | quoted printable | :meth:`quopri.decodestring` | ++--------------------+---------------------------+------------------------------+ +| uu_codec | Convert the operand using | :meth:`uu.encode`, | +| | uuencode | :meth:`uu.decode` | ++--------------------+---------------------------+------------------------------+ +| zlib_codec | Compress the operand | :meth:`zlib.compress`, | +| | using gzip | :meth:`zlib.decompress` | ++--------------------+---------------------------+------------------------------+ The following codecs provide string-to-string mappings. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -42,7 +42,6 @@ - Issue #14146: Highlight source line while debugging on Windows. - Tests ----- @@ -51,6 +50,8 @@ Documentation ------------- +- Issue #17844: Add links to encoders and decoders for bytes-to-bytes codecs. + - Issue #14097: improve the "introduction" page of the tutorial. - Issue #17977: The documentation for the cadefault argument's default value -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 22 14:36:21 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 22 May 2013 14:36:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317844=3A_Add_links_to_encoders_and_decoders_for?= =?utf-8?q?_bytes-to-bytes_codecs=2E?= Message-ID: <3bFtcj15msz7Lkv@mail.python.org> http://hg.python.org/cpython/rev/9afdd88fe33a changeset: 83889:9afdd88fe33a parent: 83885:155e6fb309f5 parent: 83888:039dc6dd2bc0 user: Serhiy Storchaka date: Wed May 22 15:35:35 2013 +0300 summary: Issue #17844: Add links to encoders and decoders for bytes-to-bytes codecs. files: Doc/library/codecs.rst | 52 +++++++++++++++--------------- Misc/NEWS | 3 +- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -1188,33 +1188,33 @@ The following codecs provide bytes-to-bytes mappings. -.. tabularcolumns:: |l|L| +.. tabularcolumns:: |l|L|L| -+--------------------+---------------------------+ -| Codec | Purpose | -+====================+===========================+ -| base64_codec | Convert operand to MIME | -| | base64 (the result always | -| | includes a trailing | -| | ``'\n'``) | -+--------------------+---------------------------+ -| bz2_codec | Compress the operand | -| | using bz2 | -+--------------------+---------------------------+ -| hex_codec | Convert operand to | -| | hexadecimal | -| | representation, with two | -| | digits per byte | -+--------------------+---------------------------+ -| quopri_codec | Convert operand to MIME | -| | quoted printable | -+--------------------+---------------------------+ -| uu_codec | Convert the operand using | -| | uuencode | -+--------------------+---------------------------+ -| zlib_codec | Compress the operand | -| | using gzip | -+--------------------+---------------------------+ ++--------------------+---------------------------+------------------------------+ +| Codec | Purpose | Encoder/decoder | ++====================+===========================+==============================+ +| base64_codec | Convert operand to MIME | :meth:`base64.b64encode`, | +| | base64 (the result always | :meth:`base64.b64decode` | +| | includes a trailing | | +| | ``'\n'``) | | ++--------------------+---------------------------+------------------------------+ +| bz2_codec | Compress the operand | :meth:`bz2.compress`, | +| | using bz2 | :meth:`bz2.decompress` | ++--------------------+---------------------------+------------------------------+ +| hex_codec | Convert operand to | :meth:`base64.b16encode`, | +| | hexadecimal | :meth:`base64.b16decode` | +| | representation, with two | | +| | digits per byte | | ++--------------------+---------------------------+------------------------------+ +| quopri_codec | Convert operand to MIME | :meth:`quopri.encodestring`, | +| | quoted printable | :meth:`quopri.decodestring` | ++--------------------+---------------------------+------------------------------+ +| uu_codec | Convert the operand using | :meth:`uu.encode`, | +| | uuencode | :meth:`uu.decode` | ++--------------------+---------------------------+------------------------------+ +| zlib_codec | Compress the operand | :meth:`zlib.compress`, | +| | using gzip | :meth:`zlib.decompress` | ++--------------------+---------------------------+------------------------------+ The following codecs provide string-to-string mappings. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -327,10 +327,11 @@ - Issue #17692: test_sqlite now works with unittest test discovery. Patch by Zachary Ware. - Documentation ------------- +- Issue #17844: Add links to encoders and decoders for bytes-to-bytes codecs. + - Issue #14097: improve the "introduction" page of the tutorial. - Issue #17977: The documentation for the cadefault argument's default value -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 22 16:21:36 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 22 May 2013 16:21:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE2OTg2?= =?utf-8?q?=3A_ElementTree_now_correctly_parses_a_string_input_not_only_wh?= =?utf-8?q?en?= Message-ID: <3bFwy83zR4z7LkS@mail.python.org> http://hg.python.org/cpython/rev/7781ccae7b9a changeset: 83890:7781ccae7b9a branch: 3.3 parent: 83888:039dc6dd2bc0 user: Serhiy Storchaka date: Wed May 22 17:07:51 2013 +0300 summary: Issue #16986: ElementTree now correctly parses a string input not only when an internal XML encoding is UTF-8 or US-ASCII. files: Include/pyexpat.h | 1 + Lib/test/test_xml_etree.py | 45 +++++++++++++++++-------- Misc/NEWS | 3 + Modules/_elementtree.c | 39 +++++++++++++++++----- Modules/pyexpat.c | 1 + 5 files changed, 65 insertions(+), 24 deletions(-) diff --git a/Include/pyexpat.h b/Include/pyexpat.h --- a/Include/pyexpat.h +++ b/Include/pyexpat.h @@ -45,6 +45,7 @@ void (*SetUserData)(XML_Parser parser, void *userData); void (*SetStartDoctypeDeclHandler)(XML_Parser parser, XML_StartDoctypeDeclHandler start); + enum XML_Status (*SetEncoding)(XML_Parser parser, const XML_Char *encoding); /* always add new stuff to the end! */ }; diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -677,15 +677,18 @@ elem = ET.fromstring("text") self.assertEqual(ET.tostring(elem), b'text') - def test_encoding(encoding): - def check(encoding): - ET.XML("" % encoding) - check("ascii") - check("us-ascii") - check("iso-8859-1") - check("iso-8859-15") - check("cp437") - check("mac-roman") + def test_encoding(self): + def check(encoding, body=''): + xml = ("%s" % + (encoding, body)) + self.assertEqual(ET.XML(xml.encode(encoding)).text, body) + self.assertEqual(ET.XML(xml).text, body) + check("ascii", 'a') + check("us-ascii", 'a') + check("iso-8859-1", '\xbd') + check("iso-8859-15", '\u20ac') + check("cp437", '\u221a') + check("mac-roman", '\u02da') def test_methods(self): # Test serialization methods. @@ -1842,11 +1845,13 @@ class XMLParserTest(unittest.TestCase): - sample1 = '22' - sample2 = ('' - 'text') + sample1 = b'22' + sample2 = (b'' + b'text') + sample3 = ('\n' + '$\xa3\u20ac\U0001017b') def _check_sample_element(self, e): self.assertEqual(e.tag, 'file') @@ -1882,12 +1887,21 @@ _doctype = (name, pubid, system) parser = MyParserWithDoctype() - parser.feed(self.sample2) + with self.assertWarns(DeprecationWarning): + parser.feed(self.sample2) parser.close() self.assertEqual(_doctype, ('html', '-//W3C//DTD XHTML 1.0 Transitional//EN', 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd')) + def test_parse_string(self): + parser = ET.XMLParser(target=ET.TreeBuilder()) + parser.feed(self.sample3) + e = parser.close() + self.assertEqual(e.tag, 'money') + self.assertEqual(e.attrib['value'], '$\xa3\u20ac\U0001017b') + self.assertEqual(e.text, '$\xa3\u20ac\U0001017b') + class NamespaceParseTest(unittest.TestCase): def test_find_with_namespace(self): @@ -2297,6 +2311,7 @@ ElementFindTest, ElementIterTest, TreeBuilderTest, + XMLParserTest, BugsTest, ] diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,9 @@ Library ------- +- Issue #16986: ElementTree now correctly parses a string input not only when + an internal XML encoding is UTF-8 or US-ASCII. + - Issue #17812: Fixed quadratic complexity of base64.b32encode(). - Issue #17980: Fix possible abuse of ssl.match_hostname() for denial of diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -3330,7 +3330,7 @@ } LOCAL(PyObject*) -expat_parse(XMLParserObject* self, char* data, int data_len, int final) +expat_parse(XMLParserObject* self, const char* data, int data_len, int final) { int ok; @@ -3376,16 +3376,37 @@ } static PyObject* -xmlparser_feed(XMLParserObject* self, PyObject* args) +xmlparser_feed(XMLParserObject* self, PyObject* arg) { /* feed data to parser */ - char* data; - int data_len; - if (!PyArg_ParseTuple(args, "s#:feed", &data, &data_len)) - return NULL; - - return expat_parse(self, data, data_len, 0); + if (PyUnicode_Check(arg)) { + Py_ssize_t data_len; + const char *data = PyUnicode_AsUTF8AndSize(arg, &data_len); + if (data == NULL) + return NULL; + if (data_len > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "size does not fit in an int"); + return NULL; + } + /* Explicitly set UTF-8 encoding. Return code ignored. */ + (void)EXPAT(SetEncoding)(self->parser, "utf-8"); + return expat_parse(self, data, (int)data_len, 0); + } + else { + Py_buffer view; + PyObject *res; + if (PyObject_GetBuffer(arg, &view, PyBUF_SIMPLE) < 0) + return NULL; + if (view.len > INT_MAX) { + PyBuffer_Release(&view); + PyErr_SetString(PyExc_OverflowError, "size does not fit in an int"); + return NULL; + } + res = expat_parse(self, view.buf, (int)view.len, 0); + PyBuffer_Release(&view); + return res; + } } static PyObject* @@ -3570,7 +3591,7 @@ } static PyMethodDef xmlparser_methods[] = { - {"feed", (PyCFunction) xmlparser_feed, METH_VARARGS}, + {"feed", (PyCFunction) xmlparser_feed, METH_O}, {"close", (PyCFunction) xmlparser_close, METH_VARARGS}, {"_parse", (PyCFunction) xmlparser_parse, METH_VARARGS}, {"_setevents", (PyCFunction) xmlparser_setevents, METH_VARARGS}, diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1937,6 +1937,7 @@ capi.SetUnknownEncodingHandler = XML_SetUnknownEncodingHandler; capi.SetUserData = XML_SetUserData; capi.SetStartDoctypeDeclHandler = XML_SetStartDoctypeDeclHandler; + capi.SetEncoding = XML_SetEncoding; /* export using capsule */ capi_object = PyCapsule_New(&capi, PyExpat_CAPSULE_NAME, NULL); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 22 16:21:37 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 22 May 2013 16:21:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Move_a_NEWS_entity_to_a_co?= =?utf-8?q?rrect_place=2E?= Message-ID: <3bFwy96kPRz7LkS@mail.python.org> http://hg.python.org/cpython/rev/eee4ef267509 changeset: 83891:eee4ef267509 parent: 83889:9afdd88fe33a user: Serhiy Storchaka date: Wed May 22 17:19:41 2013 +0300 summary: Move a NEWS entity to a correct place. files: Misc/NEWS | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,9 +10,6 @@ Core and Builtins ----------------- -- Issue #17812: Fixed quadratic complexity of base64.b32encode(). - Optimize base64.b32encode() and base64.b32decode() (speed up to 3x). - - Issue #17937: Try harder to collect cyclic garbage at shutdown. - Issue #12370: Prevent class bodies from interfering with the __class__ @@ -107,6 +104,9 @@ - Issue #17914: Add os.cpu_count(). Patch by Yogesh Chaudhari, based on an initial patch by Trent Nelson. +- Issue #17812: Fixed quadratic complexity of base64.b32encode(). + Optimize base64.b32encode() and base64.b32decode() (speed up to 3x). + - Issue #17980: Fix possible abuse of ssl.match_hostname() for denial of service using certificates with many wildcards (CVE-2013-2099). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 22 16:21:39 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 22 May 2013 16:21:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2316986=3A_ElementTree_now_correctly_parses_a_str?= =?utf-8?q?ing_input_not_only_when?= Message-ID: <3bFwyC3bcCz7LlX@mail.python.org> http://hg.python.org/cpython/rev/659c1ce8ed2f changeset: 83892:659c1ce8ed2f parent: 83891:eee4ef267509 parent: 83890:7781ccae7b9a user: Serhiy Storchaka date: Wed May 22 17:21:06 2013 +0300 summary: Issue #16986: ElementTree now correctly parses a string input not only when an internal XML encoding is UTF-8 or US-ASCII. files: Include/pyexpat.h | 1 + Lib/test/test_xml_etree.py | 45 +++++++++++++++++-------- Misc/NEWS | 3 + Modules/_elementtree.c | 39 +++++++++++++++++----- Modules/pyexpat.c | 1 + 5 files changed, 65 insertions(+), 24 deletions(-) diff --git a/Include/pyexpat.h b/Include/pyexpat.h --- a/Include/pyexpat.h +++ b/Include/pyexpat.h @@ -45,6 +45,7 @@ void (*SetUserData)(XML_Parser parser, void *userData); void (*SetStartDoctypeDeclHandler)(XML_Parser parser, XML_StartDoctypeDeclHandler start); + enum XML_Status (*SetEncoding)(XML_Parser parser, const XML_Char *encoding); /* always add new stuff to the end! */ }; diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -668,15 +668,18 @@ elem = ET.fromstring("text") self.assertEqual(ET.tostring(elem), b'text') - def test_encoding(encoding): - def check(encoding): - ET.XML("" % encoding) - check("ascii") - check("us-ascii") - check("iso-8859-1") - check("iso-8859-15") - check("cp437") - check("mac-roman") + def test_encoding(self): + def check(encoding, body=''): + xml = ("%s" % + (encoding, body)) + self.assertEqual(ET.XML(xml.encode(encoding)).text, body) + self.assertEqual(ET.XML(xml).text, body) + check("ascii", 'a') + check("us-ascii", 'a') + check("iso-8859-1", '\xbd') + check("iso-8859-15", '\u20ac') + check("cp437", '\u221a') + check("mac-roman", '\u02da') def test_methods(self): # Test serialization methods. @@ -2002,11 +2005,13 @@ class XMLParserTest(unittest.TestCase): - sample1 = '22' - sample2 = ('' - 'text') + sample1 = b'22' + sample2 = (b'' + b'text') + sample3 = ('\n' + '$\xa3\u20ac\U0001017b') def _check_sample_element(self, e): self.assertEqual(e.tag, 'file') @@ -2042,12 +2047,21 @@ _doctype = (name, pubid, system) parser = MyParserWithDoctype() - parser.feed(self.sample2) + with self.assertWarns(DeprecationWarning): + parser.feed(self.sample2) parser.close() self.assertEqual(_doctype, ('html', '-//W3C//DTD XHTML 1.0 Transitional//EN', 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd')) + def test_parse_string(self): + parser = ET.XMLParser(target=ET.TreeBuilder()) + parser.feed(self.sample3) + e = parser.close() + self.assertEqual(e.tag, 'money') + self.assertEqual(e.attrib['value'], '$\xa3\u20ac\U0001017b') + self.assertEqual(e.text, '$\xa3\u20ac\U0001017b') + class NamespaceParseTest(unittest.TestCase): def test_find_with_namespace(self): @@ -2473,6 +2487,7 @@ ElementFindTest, ElementIterTest, TreeBuilderTest, + XMLParserTest, BugsTest, ] diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -96,6 +96,9 @@ Library ------- +- Issue #16986: ElementTree now correctly parses a string input not only when + an internal XML encoding is UTF-8 or US-ASCII. + - Issue #17996: socket module now exposes AF_LINK constant on BSD and OSX. - Issue #17900: Allowed pickling of recursive OrderedDicts. Decreased pickled diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -3288,7 +3288,7 @@ } LOCAL(PyObject*) -expat_parse(XMLParserObject* self, char* data, int data_len, int final) +expat_parse(XMLParserObject* self, const char* data, int data_len, int final) { int ok; @@ -3334,16 +3334,37 @@ } static PyObject* -xmlparser_feed(XMLParserObject* self, PyObject* args) +xmlparser_feed(XMLParserObject* self, PyObject* arg) { /* feed data to parser */ - char* data; - int data_len; - if (!PyArg_ParseTuple(args, "s#:feed", &data, &data_len)) - return NULL; - - return expat_parse(self, data, data_len, 0); + if (PyUnicode_Check(arg)) { + Py_ssize_t data_len; + const char *data = PyUnicode_AsUTF8AndSize(arg, &data_len); + if (data == NULL) + return NULL; + if (data_len > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "size does not fit in an int"); + return NULL; + } + /* Explicitly set UTF-8 encoding. Return code ignored. */ + (void)EXPAT(SetEncoding)(self->parser, "utf-8"); + return expat_parse(self, data, (int)data_len, 0); + } + else { + Py_buffer view; + PyObject *res; + if (PyObject_GetBuffer(arg, &view, PyBUF_SIMPLE) < 0) + return NULL; + if (view.len > INT_MAX) { + PyBuffer_Release(&view); + PyErr_SetString(PyExc_OverflowError, "size does not fit in an int"); + return NULL; + } + res = expat_parse(self, view.buf, (int)view.len, 0); + PyBuffer_Release(&view); + return res; + } } static PyObject* @@ -3523,7 +3544,7 @@ } static PyMethodDef xmlparser_methods[] = { - {"feed", (PyCFunction) xmlparser_feed, METH_VARARGS}, + {"feed", (PyCFunction) xmlparser_feed, METH_O}, {"close", (PyCFunction) xmlparser_close, METH_VARARGS}, {"_parse_whole", (PyCFunction) xmlparser_parse_whole, METH_VARARGS}, {"_setevents", (PyCFunction) xmlparser_setevents, METH_VARARGS}, diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1937,6 +1937,7 @@ capi.SetUnknownEncodingHandler = XML_SetUnknownEncodingHandler; capi.SetUserData = XML_SetUserData; capi.SetStartDoctypeDeclHandler = XML_SetStartDoctypeDeclHandler; + capi.SetEncoding = XML_SetEncoding; /* export using capsule */ capi_object = PyCapsule_New(&capi, PyExpat_CAPSULE_NAME, NULL); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 22 22:22:57 2013 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 22 May 2013 22:22:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Add_pause/resume=5Fwriting=2C?= =?utf-8?q?_discard=5Foutput=2E?= Message-ID: <3bG4z55jdJz7Lkq@mail.python.org> http://hg.python.org/peps/rev/37cf2567651b changeset: 4902:37cf2567651b user: Guido van Rossum date: Wed May 22 13:22:52 2013 -0700 summary: Add pause/resume_writing, discard_output. files: pep-3156.txt | 10 ++++++++++ 1 files changed, 10 insertions(+), 0 deletions(-) diff --git a/pep-3156.txt b/pep-3156.txt --- a/pep-3156.txt +++ b/pep-3156.txt @@ -1019,6 +1019,16 @@ - ``resume()``. Restart delivery of data to the protocol via ``data_received()``. +- ``pause_writing()``. Suspend sending data to the network until a + subsequent ``resume_writing()`` call. Between ``pause_writing()`` + and ``resume_writing()`` the transport's ``write()`` method will + just be accumulating data in an internal buffer. + +- ``resume_writing()``. Restart sending data to the network. + +- ``discard_output()``. Discard all data buffered by ``write()`` but + not yet sent to the network. + - ``close()``. Sever the connection with the entity at the other end. Any data buffered by ``write()`` will (eventually) be transferred before the connection is actually closed. The protocol's -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed May 22 22:27:47 2013 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 22 May 2013 22:27:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=282=2E7=29=3A_implement_miss?= =?utf-8?q?ing_inequality_on_WeakSet?= Message-ID: <3bG54g1CHczN2l@mail.python.org> http://hg.python.org/cpython/rev/fa9c0c651f78 changeset: 83893:fa9c0c651f78 branch: 2.7 parent: 83887:85c04fdaa404 user: Benjamin Peterson date: Wed May 22 13:25:41 2013 -0700 summary: implement missing inequality on WeakSet files: Lib/_weakrefset.py | 6 ++++++ Lib/test/test_weakset.py | 6 ++++++ Misc/NEWS | 2 ++ 3 files changed, 14 insertions(+), 0 deletions(-) diff --git a/Lib/_weakrefset.py b/Lib/_weakrefset.py --- a/Lib/_weakrefset.py +++ b/Lib/_weakrefset.py @@ -171,6 +171,12 @@ return NotImplemented return self.data == set(ref(item) for item in other) + def __ne__(self, other): + opposite = self.__eq__(other) + if opposite is NotImplemented: + return NotImplemented + return not opposite + def symmetric_difference(self, other): newset = self.copy() newset.symmetric_difference_update(other) 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 @@ -351,6 +351,12 @@ self.assertFalse(self.s == tuple(self.items)) self.assertFalse(self.s == 1) + def test_ne(self): + self.assertTrue(self.s != set(self.items)) + s1 = WeakSet() + s2 = WeakSet() + self.assertFalse(s1 != s2) + 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 diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -15,6 +15,8 @@ Library ------- +- Implement inequality on weakref.WeakSet. + - Issue #17981: Closed socket on error in SysLogHandler. - Issue #17754: Make ctypes.util.find_library() independent of the locale. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 22 22:27:48 2013 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 22 May 2013 22:27:48 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_add_test_for_i?= =?utf-8?q?nequality?= Message-ID: <3bG54h3JtqzN2l@mail.python.org> http://hg.python.org/cpython/rev/f911a89d2f1d changeset: 83894:f911a89d2f1d branch: 3.3 parent: 83890:7781ccae7b9a user: Benjamin Peterson date: Wed May 22 13:27:25 2013 -0700 summary: add test for inequality files: Lib/test/test_weakset.py | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) 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 @@ -340,6 +340,12 @@ self.assertFalse(self.s == WeakSet([Foo])) self.assertFalse(self.s == 1) + def test_ne(self): + self.assertTrue(self.s != set(self.items)) + s1 = WeakSet() + s2 = WeakSet() + self.assertFalse(s1 != s2) + 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 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 22 22:27:49 2013 From: python-checkins at python.org (benjamin.peterson) Date: Wed, 22 May 2013 22:27:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3bG54j5KP8z7Llr@mail.python.org> http://hg.python.org/cpython/rev/1c6de7a3d700 changeset: 83895:1c6de7a3d700 parent: 83892:659c1ce8ed2f parent: 83894:f911a89d2f1d user: Benjamin Peterson date: Wed May 22 13:27:32 2013 -0700 summary: merge 3.3 files: Lib/test/test_weakset.py | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) 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 @@ -340,6 +340,12 @@ self.assertFalse(self.s == WeakSet([Foo])) self.assertFalse(self.s == 1) + def test_ne(self): + self.assertTrue(self.s != set(self.items)) + s1 = WeakSet() + s2 = WeakSet() + self.assertFalse(s1 != s2) + 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 -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 23 00:25:18 2013 From: python-checkins at python.org (ned.deily) Date: Thu, 23 May 2013 00:25:18 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3NTMy?= =?utf-8?q?=3A_Always_include_Options_menu_for_IDLE_on_OS_X=2E?= Message-ID: <3bG7hG4Dznz7LlK@mail.python.org> http://hg.python.org/cpython/rev/e134714e3b30 changeset: 83896:e134714e3b30 branch: 2.7 parent: 83893:fa9c0c651f78 user: Ned Deily date: Wed May 22 15:16:17 2013 -0700 summary: Issue #17532: Always include Options menu for IDLE on OS X. Patch by Guilherme Sim?es. files: Lib/idlelib/Bindings.py | 4 ++++ Lib/idlelib/EditorWindow.py | 1 - Lib/idlelib/PyShell.py | 1 - Misc/ACKS | 1 + Misc/NEWS | 3 +++ 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/Bindings.py b/Lib/idlelib/Bindings.py --- a/Lib/idlelib/Bindings.py +++ b/Lib/idlelib/Bindings.py @@ -98,6 +98,10 @@ # menu del menudefs[-1][1][0:2] + # Remove the 'Configure' entry from the options menu, it is in the + # application menu as 'Preferences' + del menudefs[-2][1][0:2] + default_keydefs = idleConf.GetCurrentKeySet() del sys diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -467,7 +467,6 @@ ] if macosxSupport.runningAsOSXApp(): - del menu_specs[-3] menu_specs[-2] = ("windows", "_Window") diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -844,7 +844,6 @@ ] if macosxSupport.runningAsOSXApp(): - del menu_specs[-3] menu_specs[-2] = ("windows", "_Window") diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -941,6 +941,7 @@ Ionel Simionescu Kirill Simonov Nathan Paul Simons +Guilherme Sim?es Ravi Sinha Janne Sinkkonen Ng Pheng Siong diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -28,6 +28,9 @@ - Issue #14146: Highlight source line while debugging on Windows. +- Issue #17532: Always include Options menu for IDLE on OS X. + Patch by Guilherme Sim?es. + Tests ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 23 00:25:19 2013 From: python-checkins at python.org (ned.deily) Date: Thu, 23 May 2013 00:25:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3NTMy?= =?utf-8?q?=3A_Always_include_Options_menu_for_IDLE_on_OS_X=2E?= Message-ID: <3bG7hH6LkSz7LlS@mail.python.org> http://hg.python.org/cpython/rev/75c3e9a659bc changeset: 83897:75c3e9a659bc branch: 3.3 parent: 83894:f911a89d2f1d user: Ned Deily date: Wed May 22 15:19:40 2013 -0700 summary: Issue #17532: Always include Options menu for IDLE on OS X. Patch by Guilherme Sim?es. files: Lib/idlelib/Bindings.py | 4 ++++ Lib/idlelib/EditorWindow.py | 1 - Lib/idlelib/PyShell.py | 1 - Misc/ACKS | 1 + Misc/NEWS | 3 +++ 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/Bindings.py b/Lib/idlelib/Bindings.py --- a/Lib/idlelib/Bindings.py +++ b/Lib/idlelib/Bindings.py @@ -98,6 +98,10 @@ # menu del menudefs[-1][1][0:2] + # Remove the 'Configure' entry from the options menu, it is in the + # application menu as 'Preferences' + del menudefs[-2][1][0:2] + default_keydefs = idleConf.GetCurrentKeySet() del sys diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -463,7 +463,6 @@ ] if macosxSupport.runningAsOSXApp(): - del menu_specs[-3] menu_specs[-2] = ("windows", "_Window") diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -822,7 +822,6 @@ ] if macosxSupport.runningAsOSXApp(): - del menu_specs[-3] menu_specs[-2] = ("windows", "_Window") diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1130,6 +1130,7 @@ Ionel Simionescu Kirill Simonov Nathan Paul Simons +Guilherme Sim?es Adam Simpkins Ravi Sinha Janne Sinkkonen diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -45,6 +45,9 @@ - Issue #14146: Highlight source line while debugging on Windows. +- Issue #17532: Always include Options menu for IDLE on OS X. + Patch by Guilherme Sim?es. + Tests ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 23 00:25:21 2013 From: python-checkins at python.org (ned.deily) Date: Thu, 23 May 2013 00:25:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317532=3A_merge?= Message-ID: <3bG7hK1VLPz7LmB@mail.python.org> http://hg.python.org/cpython/rev/d0a093f40801 changeset: 83898:d0a093f40801 parent: 83895:1c6de7a3d700 parent: 83897:75c3e9a659bc user: Ned Deily date: Wed May 22 15:24:44 2013 -0700 summary: Issue #17532: merge files: Lib/idlelib/Bindings.py | 4 ++++ Lib/idlelib/EditorWindow.py | 1 - Lib/idlelib/PyShell.py | 1 - Misc/ACKS | 1 + Misc/NEWS | 3 +++ 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/Bindings.py b/Lib/idlelib/Bindings.py --- a/Lib/idlelib/Bindings.py +++ b/Lib/idlelib/Bindings.py @@ -98,6 +98,10 @@ # menu del menudefs[-1][1][0:2] + # Remove the 'Configure' entry from the options menu, it is in the + # application menu as 'Preferences' + del menudefs[-2][1][0:2] + default_keydefs = idleConf.GetCurrentKeySet() del sys diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py +++ b/Lib/idlelib/EditorWindow.py @@ -463,7 +463,6 @@ ] if macosxSupport.runningAsOSXApp(): - del menu_specs[-3] menu_specs[-2] = ("windows", "_Window") diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -822,7 +822,6 @@ ] if macosxSupport.runningAsOSXApp(): - del menu_specs[-3] menu_specs[-2] = ("windows", "_Window") diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1154,6 +1154,7 @@ Ionel Simionescu Kirill Simonov Nathan Paul Simons +Guilherme Sim?es Adam Simpkins Ravi Sinha Janne Sinkkonen diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -370,6 +370,9 @@ - Issue #14735: Update IDLE docs to omit "Control-z on Windows". +- Issue #17532: Always include Options menu for IDLE on OS X. + Patch by Guilherme Sim?es. + Build ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 23 00:28:09 2013 From: python-checkins at python.org (lukasz.langa) Date: Thu, 23 May 2013 00:28:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_PEP_443_-_Single-dispatch_gen?= =?utf-8?q?eric_functions=2E_Initial_draft?= Message-ID: <3bG7lY5p1Qz7LmK@mail.python.org> http://hg.python.org/peps/rev/358723974ea8 changeset: 4903:358723974ea8 user: ?ukasz Langa date: Thu May 23 00:27:54 2013 +0200 summary: PEP 443 - Single-dispatch generic functions. Initial draft files: pep-0443.txt | 276 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 276 insertions(+), 0 deletions(-) diff --git a/pep-0443.txt b/pep-0443.txt new file mode 100644 --- /dev/null +++ b/pep-0443.txt @@ -0,0 +1,276 @@ +PEP: 443 +Title: Single-dispatch generic functions +Version: $Revision$ +Last-Modified: $Date$ +Author: ?ukasz Langa +Discussions-To: Python-Dev +Status: Draft +Type: Standards Track +Content-Type: text/x-rst +Created: 22-May-2013 +Post-History: 22-May-2013 +Replaces: 245, 246, 3124 + + +Abstract +======== + +This PEP proposes a new mechanism in the ``functools`` standard library +module that provides a simple form of generic programming known as +single-dispatch generic functions. + +A **generic function** is composed of multiple functions sharing the +same name. Which form should be used during a call is determined by the +dispatch algorithm. When the implementation is chosen based on the type +of a single argument, this is known as **single dispatch**. + + +Rationale and Goals +=================== + +Python has always provided a variety of built-in and standard-library +generic functions, such as ``len()``, ``iter()``, ``pprint.pprint()``, +``copy.copy()``, and most of the functions in the ``operator`` module. +However, it currently: + +1. does not have a simple or straightforward way for developers to + create new generic functions, + +2. does not have a standard way for methods to be added to existing + generic functions (i.e., some are added using registration + functions, others require defining ``__special__`` methods, possibly + by monkeypatching). + +In addition, it is currently a common anti-pattern for Python code to +inspect the types of received arguments, in order to decide what to do +with the objects. For example, code may wish to accept either an object +of some type, or a sequence of objects of that type. + +Currently, the "obvious way" to do this is by type inspection, but this +is brittle and closed to extension. Abstract Base Classes make it easier +to discover present behaviour, but don't help adding new behaviour. +A developer using an already-written library may be unable to change how +their objects are treated by such code, especially if the objects they +are using were created by a third party. + +Therefore, this PEP proposes a uniform API to address dynamic +overloading using decorators. + + +User API +======== + +To define a generic function, decorate it with the ``@singledispatch`` +decorator. Note that the dispatch happens on the type of the first +argument, create your function accordingly: + +.. code-block:: pycon + + >>> from functools import singledispatch + >>> @singledispatch + ... def fun(arg, verbose=False): + ... if verbose: + ... print("Let me just say,", end=" ") + ... print(arg) + +To add overloaded implementations to the function, use the +``register()`` attribute of the generic function. It takes a type +parameter: + +.. code-block:: pycon + + >>> @fun.register(int) + ... def _(arg, verbose=False): + ... if verbose: + ... print("Strength in numbers, eh?", end=" ") + ... print(arg) + ... + >>> @fun.register(list) + ... def _(arg, verbose=False): + ... if verbose: + ... print("Enumerate this:") + ... for i, elem in enumerate(arg): + ... print(i, elem) + +To enable registering lambdas and pre-existing functions, the +``register()`` attribute can be used in a functional form: + +.. code-block:: pycon + + >>> def nothing(arg, verbose=False): + ... print("Nothing.") + ... + >>> fun.register(type(None), nothing) + +When called, the function dispatches on the first argument: + +.. code-block:: pycon + + >>> fun("Hello, world.") + Hello, world. + >>> fun("test.", verbose=True) + Let me just say, test. + >>> fun(42, verbose=True) + Strength in numbers, eh? 42 + >>> fun(['spam', 'spam', 'eggs', 'spam'], verbose=True) + Enumerate this: + 0 spam + 1 spam + 2 eggs + 3 spam + >>> fun(None) + Nothing. + +The proposed API is intentionally limited and opinionated, as to ensure +it is easy to explain and use, as well as to maintain consistency with +existing members in the ``functools`` module. + + +Implementation Notes +==================== + +The functionality described in this PEP is already implemented in the +``pkgutil`` standard library module as ``simplegeneric``. Because this +implementation is mature, the goal is to move it largely as-is. Several +open issues remain: + +* the current implementation relies on ``__mro__`` alone, making it + incompatible with Abstract Base Classes' + ``register()``/``unregister()`` functionality. A possible solution has + been proposed by PJE on the original issue for exposing + ``pkgutil.simplegeneric`` as part of the ``functools`` API + [#issue-5135]_. + +* the dispatch type is currently specified as a decorator argument. The + implementation could allow a form using argument annotations. This + usage pattern is out of scope for the standard library [#pep-0008]_. + However, whether this registration form would be acceptable for + general usage, is up to debate. + +Based on the current ``pkgutil.simplegeneric`` implementation and +following the convention on registering virtual subclasses on Abstract +Base Classes, the dispatch registry will not be thread-safe. + + +Usage Patterns +============== + +This PEP proposes extending behaviour only of functions specifically +marked as generic. Just as a base class method may be overridden by +a subclass, so too may a function be overloaded to provide custom +functionality for a given type. + +Universal overloading does not equal *arbitrary* overloading, in the +sense that we need not expect people to randomly redefine the behavior +of existing functions in unpredictable ways. To the contrary, generic +function usage in actual programs tends to follow very predictable +patterns and overloads are highly-discoverable in the common case. + +If a module is defining a new generic operation, it will usually also +define any required overloads for existing types in the same place. +Likewise, if a module is defining a new type, then it will usually +define overloads there for any generic functions that it knows or cares +about. As a result, the vast majority of overloads can be found adjacent +to either the function being overloaded, or to a newly-defined type for +which the overload is adding support. + +It is only in rather infrequent cases that one will have overloads in +a module that contains neither the function nor the type(s) for which +the overload is added. In the absence of incompetence or deliberate +intention to be obscure, the few overloads that are not adjacent to the +relevant type(s) or function(s), will generally not need to be +understood or known about outside the scope where those overloads are +defined. (Except in the "support modules" case, where best practice +suggests naming them accordingly.) + +As mentioned earlier, single-dispatch generics are already prolific +throughout the standard library. A clean, standard way of doing them +provides a way forward to refactor those custom implementations to use +a common one, opening them up for user extensibility at the same time. + + +Alternative approaches +====================== + +In PEP 3124 [#pep-3124]_ Phillip J. Eby proposes a full-grown solution +with overloading based on arbitrary rule sets (with the default +implementation dispatching on argument types), as well as interfaces, +adaptation and method combining. PEAK-Rules [#peak-rules]_ is +a reference implementation of the concepts described in PJE's PEP. + +Such a broad approach is inherently complex, which makes reaching +a consensus hard. In contrast, this PEP focuses on a single piece of +functionality that is simple to reason about. It's important to note +this does not preclude the use of other approaches now or in the future. + +In a 2005 article on Artima [#artima2005]_ Guido van Rossum presents +a generic function implementation that dispatches on types of all +arguments on a function. The same approach was chosen in Andrey Popp's +``generic`` package available on PyPI [#pypi-generic]_, as well as David +Mertz's ``gnosis.magic.multimethods`` [#gnosis-multimethods]_. + +While this seems desirable at first, I agree with Fredrik Lundh's +comment that "if you design APIs with pages of logic just to sort out +what code a function should execute, you should probably hand over the +API design to someone else". In other words, the single argument +approach proposed in this PEP is not only easier to implement but also +clearly communicates that dispatching on a more complex state is an +anti-pattern. It also has the virtue of corresponding directly with the +familiar method dispatch mechanism in object oriented programming. The +only difference is whether the custom implementation is associated more +closely with the data (object-oriented methods) or the algorithm +(single-dispatch overloading). + + +Acknowledgements +================ + +Apart from Phillip J. Eby's work on PEP 3124 [#pep-3124]_ and +PEAK-Rules, influences include Paul Moore's original issue +[#issue-5135]_ that proposed exposing ``pkgutil.simplegeneric`` as part +of the ``functools`` API, Guido van Rossum's article on multimethods +[#artima2005]_, and discussions with Raymond Hettinger on a general +pprint rewrite. + + +References +========== + +.. [#issue-5135] http://bugs.python.org/issue5135 + +.. [#pep-0008] PEP 8 states in the "Programming Recommendations" + section that "the Python standard library will not use function + annotations as that would result in a premature commitment to + a particular annotation style". + (http://www.python.org/dev/peps/pep-0008) + +.. [#pep-3124] http://www.python.org/dev/peps/pep-3124/ + +.. [#peak-rules] http://peak.telecommunity.com/DevCenter/PEAK_2dRules + +.. [#artima2005] + http://www.artima.com/weblogs/viewpost.jsp?thread=101605 + +.. [#pypi-generic] http://pypi.python.org/pypi/generic + +.. [#gnosis-multimethods] + http://gnosis.cx/publish/programming/charming_python_b12.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: http://hg.python.org/peps From python-checkins at python.org Thu May 23 00:38:42 2013 From: python-checkins at python.org (lukasz.langa) Date: Thu, 23 May 2013 00:38:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_downgrade_from_Sphinx-specifi?= =?utf-8?q?c_markup_to_plain_docutils?= Message-ID: <3bG7zk0zNqz7LlK@mail.python.org> http://hg.python.org/peps/rev/08079eb5144f changeset: 4904:08079eb5144f user: ?ukasz Langa date: Thu May 23 00:38:27 2013 +0200 summary: downgrade from Sphinx-specific markup to plain docutils files: pep-0443.txt | 16 ++++------------ 1 files changed, 4 insertions(+), 12 deletions(-) diff --git a/pep-0443.txt b/pep-0443.txt --- a/pep-0443.txt +++ b/pep-0443.txt @@ -62,9 +62,7 @@ To define a generic function, decorate it with the ``@singledispatch`` decorator. Note that the dispatch happens on the type of the first -argument, create your function accordingly: - -.. code-block:: pycon +argument, create your function accordingly:: >>> from functools import singledispatch >>> @singledispatch @@ -75,9 +73,7 @@ To add overloaded implementations to the function, use the ``register()`` attribute of the generic function. It takes a type -parameter: - -.. code-block:: pycon +parameter:: >>> @fun.register(int) ... def _(arg, verbose=False): @@ -93,18 +89,14 @@ ... print(i, elem) To enable registering lambdas and pre-existing functions, the -``register()`` attribute can be used in a functional form: - -.. code-block:: pycon +``register()`` attribute can be used in a functional form:: >>> def nothing(arg, verbose=False): ... print("Nothing.") ... >>> fun.register(type(None), nothing) -When called, the function dispatches on the first argument: - -.. code-block:: pycon +When called, the function dispatches on the first argument:: >>> fun("Hello, world.") Hello, world. -- Repository URL: http://hg.python.org/peps From root at python.org Thu May 23 02:55:26 2013 From: root at python.org (Cron Daemon) Date: Thu, 23 May 2013 02:55:26 +0200 Subject: [Python-checkins] Cron /home/docs/build-devguide Message-ID: abort: error: Connection timed out From solipsis at pitrou.net Thu May 23 05:47:17 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 23 May 2013 05:47:17 +0200 Subject: [Python-checkins] Daily reference leaks (d0a093f40801): sum=0 Message-ID: results for d0a093f40801 on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogrdRgtE', '-x'] From python-checkins at python.org Thu May 23 09:12:45 2013 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 23 May 2013 09:12:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4MDMx?= =?utf-8?q?=3A__=25-formatting_isn=27t_dead_yet_and_might_pull_through=2E?= Message-ID: <3bGMNs5QCRz7LmS@mail.python.org> http://hg.python.org/cpython/rev/ef037ad304c1 changeset: 83899:ef037ad304c1 branch: 2.7 parent: 83896:e134714e3b30 user: Raymond Hettinger date: Thu May 23 00:12:14 2013 -0700 summary: Issue #18031: %-formatting isn't dead yet and might pull through. files: Doc/tutorial/inputoutput.rst | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diff --git a/Doc/tutorial/inputoutput.rst b/Doc/tutorial/inputoutput.rst --- a/Doc/tutorial/inputoutput.rst +++ b/Doc/tutorial/inputoutput.rst @@ -215,10 +215,6 @@ >>> print 'The value of PI is approximately %5.3f.' % math.pi The value of PI is approximately 3.142. -Since :meth:`str.format` is quite new, a lot of Python code still uses the ``%`` -operator. However, because this old style of formatting will eventually be -removed from the language, :meth:`str.format` should generally be used. - More information can be found in the :ref:`string-formatting` section. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 23 09:15:48 2013 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 23 May 2013 09:15:48 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MDMx?= =?utf-8?q?=3A__=25-formatting_isn=27t_dead_yet_and_might_pull_through=2E?= Message-ID: <3bGMSN5SXQz7Ljg@mail.python.org> http://hg.python.org/cpython/rev/e1d6140b02f0 changeset: 83900:e1d6140b02f0 branch: 3.3 parent: 83897:75c3e9a659bc user: Raymond Hettinger date: Thu May 23 00:14:47 2013 -0700 summary: Issue #18031: %-formatting isn't dead yet and might pull through. files: Doc/tutorial/inputoutput.rst | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diff --git a/Doc/tutorial/inputoutput.rst b/Doc/tutorial/inputoutput.rst --- a/Doc/tutorial/inputoutput.rst +++ b/Doc/tutorial/inputoutput.rst @@ -213,10 +213,6 @@ >>> print('The value of PI is approximately %5.3f.' % math.pi) The value of PI is approximately 3.142. -Since :meth:`str.format` is quite new, a lot of Python code still uses the ``%`` -operator. However, because this old style of formatting will eventually be -removed from the language, :meth:`str.format` should generally be used. - More information can be found in the :ref:`old-string-formatting` section. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 23 09:15:50 2013 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 23 May 2013 09:15:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3bGMSQ0Jj2z7Llr@mail.python.org> http://hg.python.org/cpython/rev/7e6d03c4a367 changeset: 83901:7e6d03c4a367 parent: 83898:d0a093f40801 parent: 83900:e1d6140b02f0 user: Raymond Hettinger date: Thu May 23 00:15:19 2013 -0700 summary: merge files: Doc/tutorial/inputoutput.rst | 4 ---- 1 files changed, 0 insertions(+), 4 deletions(-) diff --git a/Doc/tutorial/inputoutput.rst b/Doc/tutorial/inputoutput.rst --- a/Doc/tutorial/inputoutput.rst +++ b/Doc/tutorial/inputoutput.rst @@ -213,10 +213,6 @@ >>> print('The value of PI is approximately %5.3f.' % math.pi) The value of PI is approximately 3.142. -Since :meth:`str.format` is quite new, a lot of Python code still uses the ``%`` -operator. However, because this old style of formatting will eventually be -removed from the language, :meth:`str.format` should generally be used. - More information can be found in the :ref:`old-string-formatting` section. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 23 12:25:23 2013 From: python-checkins at python.org (nick.coghlan) Date: Thu, 23 May 2013 12:25:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgMTc4NDQ6?= =?utf-8?q?_Clarify_meaning_of_different_codec_tables?= Message-ID: <3bGRg73y9PzPfH@mail.python.org> http://hg.python.org/cpython/rev/85e8414060b4 changeset: 83902:85e8414060b4 branch: 3.3 parent: 83900:e1d6140b02f0 user: Nick Coghlan date: Thu May 23 20:24:02 2013 +1000 summary: Issue 17844: Clarify meaning of different codec tables files: Doc/library/codecs.rst | 78 ++++++++++++++++++----------- 1 files changed, 49 insertions(+), 29 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -1142,7 +1142,19 @@ | utf_8_sig | | all languages | +-----------------+--------------------------------+--------------------------------+ -.. XXX fix here, should be in above table +Python Specific Encodings +------------------------- + +A number of predefined codecs are specific to Python, so their codec names have +no meaning outside Python. These are listed in the tables below based on the +expected input and output types (note that while text encodings are the most +common use case for codecs, the underlying codec infrastructure supports +arbitrary data transforms rather than just text encodings). For asymmetric +codecs, the stated purpose describes the encoding direction. + +The following codecs provide :class:`str` to :class:`bytes` encoding and +:term:`bytes-like object` to :class:`str` decoding, similar to the Unicode text +encodings. .. tabularcolumns:: |l|p{0.3\linewidth}|p{0.3\linewidth}| @@ -1186,37 +1198,45 @@ | | | .. deprecated:: 3.3 | +--------------------+---------+---------------------------+ -The following codecs provide bytes-to-bytes mappings. +The following codecs provide :term:`bytes-like object` to :class:`bytes` +mappings. + .. tabularcolumns:: |l|L|L| -+--------------------+---------------------------+------------------------------+ -| Codec | Purpose | Encoder/decoder | -+====================+===========================+==============================+ -| base64_codec | Convert operand to MIME | :meth:`base64.b64encode`, | -| | base64 (the result always | :meth:`base64.b64decode` | -| | includes a trailing | | -| | ``'\n'``) | | -+--------------------+---------------------------+------------------------------+ -| bz2_codec | Compress the operand | :meth:`bz2.compress`, | -| | using bz2 | :meth:`bz2.decompress` | -+--------------------+---------------------------+------------------------------+ -| hex_codec | Convert operand to | :meth:`base64.b16encode`, | -| | hexadecimal | :meth:`base64.b16decode` | -| | representation, with two | | -| | digits per byte | | -+--------------------+---------------------------+------------------------------+ -| quopri_codec | Convert operand to MIME | :meth:`quopri.encodestring`, | -| | quoted printable | :meth:`quopri.decodestring` | -+--------------------+---------------------------+------------------------------+ -| uu_codec | Convert the operand using | :meth:`uu.encode`, | -| | uuencode | :meth:`uu.decode` | -+--------------------+---------------------------+------------------------------+ -| zlib_codec | Compress the operand | :meth:`zlib.compress`, | -| | using gzip | :meth:`zlib.decompress` | -+--------------------+---------------------------+------------------------------+ ++----------------------+---------------------------+------------------------------+ +| Codec | Purpose | Encoder/decoder | ++======================+===========================+==============================+ +| base64_codec [#b64]_ | Convert operand to MIME | :meth:`base64.b64encode`, | +| | base64 (the result always | :meth:`base64.b64decode` | +| | includes a trailing | | +| | ``'\n'``) | | ++----------------------+---------------------------+------------------------------+ +| bz2_codec | Compress the operand | :meth:`bz2.compress`, | +| | using bz2 | :meth:`bz2.decompress` | ++----------------------+---------------------------+------------------------------+ +| hex_codec | Convert operand to | :meth:`base64.b16encode`, | +| | hexadecimal | :meth:`base64.b16decode` | +| | representation, with two | | +| | digits per byte | | ++----------------------+---------------------------+------------------------------+ +| quopri_codec | Convert operand to MIME | :meth:`quopri.encodestring`, | +| | quoted printable | :meth:`quopri.decodestring` | ++----------------------+---------------------------+------------------------------+ +| uu_codec | Convert the operand using | :meth:`uu.encode`, | +| | uuencode | :meth:`uu.decode` | ++----------------------+---------------------------+------------------------------+ +| zlib_codec | Compress the operand | :meth:`zlib.compress`, | +| | using gzip | :meth:`zlib.decompress` | ++----------------------+---------------------------+------------------------------+ -The following codecs provide string-to-string mappings. +.. [#b64] Rather than accepting any :term:`bytes-like object`, + ``'base64_codec'`` accepts only :class:`bytes` and :class:`bytearray` for + encoding and only :class:`bytes`, :class:`bytearray`, and ASCII-only + instances of :class:`str` for decoding + + +The following codecs provide :class:`str` to :class:`str` mappings. .. tabularcolumns:: |l|L| @@ -1228,7 +1248,7 @@ +--------------------+---------------------------+ .. versionadded:: 3.2 - bytes-to-bytes and string-to-string codecs. + bytes-to-bytes and str-to-str codecs. :mod:`encodings.idna` --- Internationalized Domain Names in Applications -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 23 12:25:25 2013 From: python-checkins at python.org (nick.coghlan) Date: Thu, 23 May 2013 12:25:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_issue_17844_from_3=2E3?= Message-ID: <3bGRg90gJpz7LkB@mail.python.org> http://hg.python.org/cpython/rev/801567d6302c changeset: 83903:801567d6302c parent: 83901:7e6d03c4a367 parent: 83902:85e8414060b4 user: Nick Coghlan date: Thu May 23 20:25:09 2013 +1000 summary: Merge issue 17844 from 3.3 files: Doc/library/codecs.rst | 78 ++++++++++++++++++----------- 1 files changed, 49 insertions(+), 29 deletions(-) diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst --- a/Doc/library/codecs.rst +++ b/Doc/library/codecs.rst @@ -1142,7 +1142,19 @@ | utf_8_sig | | all languages | +-----------------+--------------------------------+--------------------------------+ -.. XXX fix here, should be in above table +Python Specific Encodings +------------------------- + +A number of predefined codecs are specific to Python, so their codec names have +no meaning outside Python. These are listed in the tables below based on the +expected input and output types (note that while text encodings are the most +common use case for codecs, the underlying codec infrastructure supports +arbitrary data transforms rather than just text encodings). For asymmetric +codecs, the stated purpose describes the encoding direction. + +The following codecs provide :class:`str` to :class:`bytes` encoding and +:term:`bytes-like object` to :class:`str` decoding, similar to the Unicode text +encodings. .. tabularcolumns:: |l|p{0.3\linewidth}|p{0.3\linewidth}| @@ -1186,37 +1198,45 @@ | | | .. deprecated:: 3.3 | +--------------------+---------+---------------------------+ -The following codecs provide bytes-to-bytes mappings. +The following codecs provide :term:`bytes-like object` to :class:`bytes` +mappings. + .. tabularcolumns:: |l|L|L| -+--------------------+---------------------------+------------------------------+ -| Codec | Purpose | Encoder/decoder | -+====================+===========================+==============================+ -| base64_codec | Convert operand to MIME | :meth:`base64.b64encode`, | -| | base64 (the result always | :meth:`base64.b64decode` | -| | includes a trailing | | -| | ``'\n'``) | | -+--------------------+---------------------------+------------------------------+ -| bz2_codec | Compress the operand | :meth:`bz2.compress`, | -| | using bz2 | :meth:`bz2.decompress` | -+--------------------+---------------------------+------------------------------+ -| hex_codec | Convert operand to | :meth:`base64.b16encode`, | -| | hexadecimal | :meth:`base64.b16decode` | -| | representation, with two | | -| | digits per byte | | -+--------------------+---------------------------+------------------------------+ -| quopri_codec | Convert operand to MIME | :meth:`quopri.encodestring`, | -| | quoted printable | :meth:`quopri.decodestring` | -+--------------------+---------------------------+------------------------------+ -| uu_codec | Convert the operand using | :meth:`uu.encode`, | -| | uuencode | :meth:`uu.decode` | -+--------------------+---------------------------+------------------------------+ -| zlib_codec | Compress the operand | :meth:`zlib.compress`, | -| | using gzip | :meth:`zlib.decompress` | -+--------------------+---------------------------+------------------------------+ ++----------------------+---------------------------+------------------------------+ +| Codec | Purpose | Encoder/decoder | ++======================+===========================+==============================+ +| base64_codec [#b64]_ | Convert operand to MIME | :meth:`base64.b64encode`, | +| | base64 (the result always | :meth:`base64.b64decode` | +| | includes a trailing | | +| | ``'\n'``) | | ++----------------------+---------------------------+------------------------------+ +| bz2_codec | Compress the operand | :meth:`bz2.compress`, | +| | using bz2 | :meth:`bz2.decompress` | ++----------------------+---------------------------+------------------------------+ +| hex_codec | Convert operand to | :meth:`base64.b16encode`, | +| | hexadecimal | :meth:`base64.b16decode` | +| | representation, with two | | +| | digits per byte | | ++----------------------+---------------------------+------------------------------+ +| quopri_codec | Convert operand to MIME | :meth:`quopri.encodestring`, | +| | quoted printable | :meth:`quopri.decodestring` | ++----------------------+---------------------------+------------------------------+ +| uu_codec | Convert the operand using | :meth:`uu.encode`, | +| | uuencode | :meth:`uu.decode` | ++----------------------+---------------------------+------------------------------+ +| zlib_codec | Compress the operand | :meth:`zlib.compress`, | +| | using gzip | :meth:`zlib.decompress` | ++----------------------+---------------------------+------------------------------+ -The following codecs provide string-to-string mappings. +.. [#b64] Rather than accepting any :term:`bytes-like object`, + ``'base64_codec'`` accepts only :class:`bytes` and :class:`bytearray` for + encoding and only :class:`bytes`, :class:`bytearray`, and ASCII-only + instances of :class:`str` for decoding + + +The following codecs provide :class:`str` to :class:`str` mappings. .. tabularcolumns:: |l|L| @@ -1228,7 +1248,7 @@ +--------------------+---------------------------+ .. versionadded:: 3.2 - bytes-to-bytes and string-to-string codecs. + bytes-to-bytes and str-to-str codecs. :mod:`encodings.idna` --- Internationalized Domain Names in Applications -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 23 14:28:40 2013 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 23 May 2013 14:28:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogRml4ICMxODAwNyA6?= =?utf-8?q?_Document_CookieJar=2Eadd=5Fcookie=5Fheader_request_parameter_c?= =?utf-8?q?hanges_in?= Message-ID: <3bGVPN07FJz7Ljl@mail.python.org> http://hg.python.org/cpython/rev/26ac5b9cffda changeset: 83904:26ac5b9cffda branch: 3.3 parent: 83902:85e8414060b4 user: Senthil Kumaran date: Thu May 23 05:27:38 2013 -0700 summary: Fix #18007 : Document CookieJar.add_cookie_header request parameter changes in 3.3 files: Doc/library/http.cookiejar.rst | 20 +++++++++++++++----- 1 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Doc/library/http.cookiejar.rst b/Doc/library/http.cookiejar.rst --- a/Doc/library/http.cookiejar.rst +++ b/Doc/library/http.cookiejar.rst @@ -154,9 +154,15 @@ The *request* object (usually a :class:`urllib.request..Request` instance) must support the methods :meth:`get_full_url`, :meth:`get_host`, - :meth:`get_type`, :meth:`unverifiable`, :meth:`get_origin_req_host`, - :meth:`has_header`, :meth:`get_header`, :meth:`header_items`, and - :meth:`add_unredirected_header`, as documented by :mod:`urllib.request`. + :meth:`get_type`, :meth:`unverifiable`, :meth:`has_header`, + :meth:`get_header`, :meth:`header_items`, :meth:`add_unredirected_header` + and :attr:`origin_req_host` attribute as documented by + :mod:`urllib.request`. + + .. versionchanged:: 3.3 + + *request* object needs :attr:`origin_req_host` attribute. Dependency on a + deprecated method :meth:`get_origin_req_host` has been removed. .. method:: CookieJar.extract_cookies(response, request) @@ -174,11 +180,15 @@ The *request* object (usually a :class:`urllib.request.Request` instance) must support the methods :meth:`get_full_url`, :meth:`get_host`, - :meth:`unverifiable`, and :meth:`get_origin_req_host`, as documented by - :mod:`urllib.request`. The request is used to set default values for + :meth:`unverifiable`, and :attr:`origin_req_host` attribute, as documented + by :mod:`urllib.request`. The request is used to set default values for cookie-attributes as well as for checking that the cookie is allowed to be set. + .. versionchanged:: 3.3 + + *request* object needs :attr:`origin_req_host` attribute. Dependency on a + deprecated method :meth:`get_origin_req_host` has been removed. .. method:: CookieJar.set_policy(policy) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 23 14:28:41 2013 From: python-checkins at python.org (senthil.kumaran) Date: Thu, 23 May 2013 14:28:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge_from_3=2E3?= Message-ID: <3bGVPP2kS3z7Ljy@mail.python.org> http://hg.python.org/cpython/rev/f7992397e98d changeset: 83905:f7992397e98d parent: 83903:801567d6302c parent: 83904:26ac5b9cffda user: Senthil Kumaran date: Thu May 23 05:28:34 2013 -0700 summary: merge from 3.3 Fix #18007 : Document CookieJar.add_cookie_header request parameter changes in 3.3 and 3.4. files: Doc/library/http.cookiejar.rst | 20 +++++++++++++++----- 1 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Doc/library/http.cookiejar.rst b/Doc/library/http.cookiejar.rst --- a/Doc/library/http.cookiejar.rst +++ b/Doc/library/http.cookiejar.rst @@ -154,9 +154,15 @@ The *request* object (usually a :class:`urllib.request..Request` instance) must support the methods :meth:`get_full_url`, :meth:`get_host`, - :meth:`get_type`, :meth:`unverifiable`, :meth:`get_origin_req_host`, - :meth:`has_header`, :meth:`get_header`, :meth:`header_items`, and - :meth:`add_unredirected_header`, as documented by :mod:`urllib.request`. + :meth:`get_type`, :meth:`unverifiable`, :meth:`has_header`, + :meth:`get_header`, :meth:`header_items`, :meth:`add_unredirected_header` + and :attr:`origin_req_host` attribute as documented by + :mod:`urllib.request`. + + .. versionchanged:: 3.3 + + *request* object needs :attr:`origin_req_host` attribute. Dependency on a + deprecated method :meth:`get_origin_req_host` has been removed. .. method:: CookieJar.extract_cookies(response, request) @@ -174,11 +180,15 @@ The *request* object (usually a :class:`urllib.request.Request` instance) must support the methods :meth:`get_full_url`, :meth:`get_host`, - :meth:`unverifiable`, and :meth:`get_origin_req_host`, as documented by - :mod:`urllib.request`. The request is used to set default values for + :meth:`unverifiable`, and :attr:`origin_req_host` attribute, as documented + by :mod:`urllib.request`. The request is used to set default values for cookie-attributes as well as for checking that the cookie is allowed to be set. + .. versionchanged:: 3.3 + + *request* object needs :attr:`origin_req_host` attribute. Dependency on a + deprecated method :meth:`get_origin_req_host` has been removed. .. method:: CookieJar.set_policy(policy) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 23 16:08:35 2013 From: python-checkins at python.org (lukasz.langa) Date: Thu, 23 May 2013 16:08:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_acknowledge_Nick_Coghlan=2C_a?= =?utf-8?q?dd_information_on_PyPy=27s_pairtype?= Message-ID: <3bGXcg6CHwz7Ljp@mail.python.org> http://hg.python.org/peps/rev/b7979219f3cc changeset: 4905:b7979219f3cc user: ?ukasz Langa date: Thu May 23 16:08:26 2013 +0200 summary: acknowledge Nick Coghlan, add information on PyPy's pairtype files: pep-0443.txt | 11 ++++++++++- 1 files changed, 10 insertions(+), 1 deletions(-) diff --git a/pep-0443.txt b/pep-0443.txt --- a/pep-0443.txt +++ b/pep-0443.txt @@ -213,6 +213,11 @@ closely with the data (object-oriented methods) or the algorithm (single-dispatch overloading). +PyPy's RPython offers ``extendabletype`` [#pairtype]_, a metaclass which +enables classes to be externally extended. In combination with +``pairtype()`` and ``pair()`` factories, this offers a form of +single-dispatch generics. + Acknowledgements ================ @@ -222,7 +227,8 @@ [#issue-5135]_ that proposed exposing ``pkgutil.simplegeneric`` as part of the ``functools`` API, Guido van Rossum's article on multimethods [#artima2005]_, and discussions with Raymond Hettinger on a general -pprint rewrite. +pprint rewrite. Huge thanks to Nick Coghlan for encouraging me to create +this PEP and providing initial feedback. References @@ -248,6 +254,9 @@ .. [#gnosis-multimethods] http://gnosis.cx/publish/programming/charming_python_b12.html +.. [#pairtype] + https://bitbucket.org/pypy/pypy/raw/default/rpython/tool/pairtype.py + Copyright ========= -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Thu May 23 22:15:41 2013 From: python-checkins at python.org (lukasz.langa) Date: Thu, 23 May 2013 22:15:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_*_deferred_the_annotation-dri?= =?utf-8?q?ven_form?= Message-ID: <3bGhmF2fmCz7Ljy@mail.python.org> http://hg.python.org/peps/rev/340e90cfa121 changeset: 4906:340e90cfa121 user: ?ukasz Langa date: Thu May 23 22:15:26 2013 +0200 summary: * deferred the annotation-driven form * clarified that register() returns an undecorated function files: pep-0443.txt | 42 ++++++++++++++++++++++++++------------- 1 files changed, 28 insertions(+), 14 deletions(-) diff --git a/pep-0443.txt b/pep-0443.txt --- a/pep-0443.txt +++ b/pep-0443.txt @@ -96,7 +96,21 @@ ... >>> fun.register(type(None), nothing) -When called, the function dispatches on the first argument:: +The ``register()`` attribute returns the undecorated function which +enables decorator stacking, as well as creating unit tests for each +variant independently:: + + >>> @fun.register(float) + ... @fun.register(Decimal) + ... def fun_num(arg, verbose=False): + ... if verbose: + ... print("Half of your number:", end=" ") + ... print(arg / 2) + ... + >>> fun_num is fun + False + +When called, the generic function dispatches on the first argument:: >>> fun("Hello, world.") Hello, world. @@ -112,6 +126,8 @@ 3 spam >>> fun(None) Nothing. + >>> fun_num(1.23) + 0.615 The proposed API is intentionally limited and opinionated, as to ensure it is easy to explain and use, as well as to maintain consistency with @@ -123,21 +139,19 @@ The functionality described in this PEP is already implemented in the ``pkgutil`` standard library module as ``simplegeneric``. Because this -implementation is mature, the goal is to move it largely as-is. Several -open issues remain: +implementation is mature, the goal is to move it largely as-is. -* the current implementation relies on ``__mro__`` alone, making it - incompatible with Abstract Base Classes' - ``register()``/``unregister()`` functionality. A possible solution has - been proposed by PJE on the original issue for exposing - ``pkgutil.simplegeneric`` as part of the ``functools`` API - [#issue-5135]_. +The current implementation relies on ``__mro__`` alone, it will be made +compatible with Abstract Base Classes' ``register()``/``unregister()`` +functionality. A possible solution has been proposed by PJE on the +original issue for exposing ``pkgutil.simplegeneric`` as part of the +``functools`` API [#issue-5135]_. -* the dispatch type is currently specified as a decorator argument. The - implementation could allow a form using argument annotations. This - usage pattern is out of scope for the standard library [#pep-0008]_. - However, whether this registration form would be acceptable for - general usage, is up to debate. +The dispatch type is specified as a decorator argument. An alternative +form using function annotations has been considered but its inclusion +has been deferred. As of May 2013, this usage pattern is out of scope +for the standard library [#pep-0008]_ and the best practices for +annotation usage are still debated. Based on the current ``pkgutil.simplegeneric`` implementation and following the convention on registering virtual subclasses on Abstract -- Repository URL: http://hg.python.org/peps From solipsis at pitrou.net Fri May 24 05:47:30 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 24 May 2013 05:47:30 +0200 Subject: [Python-checkins] Daily reference leaks (f7992397e98d): sum=1 Message-ID: results for f7992397e98d on branch "default" -------------------------------------------- test_unittest leaked [-1, 2, 0] memory blocks, sum=1 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogAQH3LM', '-x'] From python-checkins at python.org Fri May 24 13:51:37 2013 From: python-checkins at python.org (ronald.oussoren) Date: Fri, 24 May 2013 13:51:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE3MjY5?= =?utf-8?q?=3A_Workaround_for_a_platform_bug_in_getaddrinfo_on_OSX?= Message-ID: <3bH5X94h8wz7Lkb@mail.python.org> http://hg.python.org/cpython/rev/f4981d8eb401 changeset: 83906:f4981d8eb401 branch: 2.7 parent: 83899:ef037ad304c1 user: Ronald Oussoren date: Fri May 24 13:45:27 2013 +0200 summary: Issue #17269: Workaround for a platform bug in getaddrinfo on OSX Without this patch socket.getaddrinfo crashed when called with some unusual argument combinations. files: Lib/test/test_socket.py | 2 ++ Misc/NEWS | 5 ++++- Modules/socketmodule.c | 9 +++++++++ 3 files changed, 15 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 @@ -665,6 +665,8 @@ socket.getaddrinfo(None, 0, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE) + # Issue 17269 + socket.getaddrinfo("localhost", None, 0, 0, 0, socket.AI_NUMERICSERV) def check_sendall_interrupted(self, with_timeout): # socketpair() is not stricly required, but it makes things easier. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -23,6 +23,9 @@ - Fix typos in the multiprocessing module. +- Issue #17269: Workaround for socket.getaddrinfo crash on MacOS X + with port None or "0" and flags AI_NUMERICSERV. + IDLE ---- @@ -51,7 +54,7 @@ Core and Builtins ----------------- -- Issue #15535: Fixed regression in the pickling of named tuples by +- Issue #15535: Fixed regression in the pickling of named tuples by removing the __dict__ property introduced in 2.7.4. - Issue #17857: Prevent build failures with pre-3.5.0 versions of sqlite3, diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -4179,6 +4179,15 @@ "getaddrinfo() argument 2 must be integer or string"); goto err; } +#ifdef __APPLE__ + if ((flags & AI_NUMERICSERV) && (pptr == NULL || (pptr[0] == '0' && pptr[1] == 0))) { + /* On OSX upto at least OSX 10.8 getaddrinfo crashes + * if AI_NUMERICSERV is set and the servname is NULL or "0". + * This workaround avoids a segfault in libsystem. + */ + pptr = "00"; + } +#endif memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = socktype; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 24 13:51:38 2013 From: python-checkins at python.org (ronald.oussoren) Date: Fri, 24 May 2013 13:51:38 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3MjY5?= =?utf-8?q?=3A_Workaround_for_a_platform_bug_in_getaddrinfo_on_OSX?= Message-ID: <3bH5XB70Jzz7LlT@mail.python.org> http://hg.python.org/cpython/rev/3c4a5dc29417 changeset: 83907:3c4a5dc29417 branch: 3.3 parent: 83904:26ac5b9cffda user: Ronald Oussoren date: Fri May 24 13:47:37 2013 +0200 summary: Issue #17269: Workaround for a platform bug in getaddrinfo on OSX Without this patch socket.getaddrinfo crashed when called with some unusual argument combinations. files: Lib/test/test_socket.py | 3 +++ Misc/NEWS | 3 +++ Modules/socketmodule.c | 9 +++++++++ 3 files changed, 15 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1166,6 +1166,9 @@ # Issue #6697. self.assertRaises(UnicodeEncodeError, socket.getaddrinfo, 'localhost', '\uD800') + # Issue 17269 + socket.getaddrinfo("localhost", None, 0, 0, 0, socket.AI_NUMERICSERV) + def test_getnameinfo(self): # only IP addresses are allowed self.assertRaises(socket.error, socket.getnameinfo, ('mail.python.org',0), 0) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -40,6 +40,9 @@ - Issue #17968: Fix memory leak in os.listxattr(). +- Issue #17269: Workaround for socket.getaddrinfo crash on MacOS X + with port None or "0" and flags AI_NUMERICSERV. + IDLE ---- diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -5041,6 +5041,15 @@ PyErr_SetString(PyExc_OSError, "Int or String expected"); goto err; } +#ifdef __APPLE__ + if ((flags & AI_NUMERICSERV) && (pptr == NULL || (pptr[0] == '0' && pptr[1] == 0))) { + /* On OSX upto at least OSX 10.8 getaddrinfo crashes + * if AI_NUMERICSERV is set and the servname is NULL or "0". + * This workaround avoids a segfault in libsystem. + */ + pptr = "00"; + } +#endif memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = socktype; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 24 13:51:40 2013 From: python-checkins at python.org (ronald.oussoren) Date: Fri, 24 May 2013 13:51:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_=283=2E3-=3Edefault=29_Issue_=2317269=3A_Workaround_for_?= =?utf-8?q?a_platform_bug_in_getaddrinfo_on_OSX?= Message-ID: <3bH5XD20Qgz7Llm@mail.python.org> http://hg.python.org/cpython/rev/24ffb0148729 changeset: 83908:24ffb0148729 parent: 83905:f7992397e98d parent: 83907:3c4a5dc29417 user: Ronald Oussoren date: Fri May 24 13:51:21 2013 +0200 summary: (3.3->default) Issue #17269: Workaround for a platform bug in getaddrinfo on OSX Without this patch socket.getaddrinfo crashed when called with some unusual argument combinations. files: Lib/test/test_socket.py | 3 +++ Misc/NEWS | 3 +++ Modules/socketmodule.c | 9 +++++++++ 3 files changed, 15 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1201,6 +1201,9 @@ # Issue #6697. self.assertRaises(UnicodeEncodeError, socket.getaddrinfo, 'localhost', '\uD800') + # Issue 17269 + socket.getaddrinfo("localhost", None, 0, 0, 0, socket.AI_NUMERICSERV) + def test_getnameinfo(self): # only IP addresses are allowed self.assertRaises(OSError, socket.getnameinfo, ('mail.python.org',0), 0) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -96,6 +96,9 @@ Library ------- +- Issue #17269: Workaround for socket.getaddrinfo crash on MacOS X + with port None or "0" and flags AI_NUMERICSERV. + - Issue #16986: ElementTree now correctly parses a string input not only when an internal XML encoding is UTF-8 or US-ASCII. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -4978,6 +4978,15 @@ PyErr_SetString(PyExc_OSError, "Int or String expected"); goto err; } +#ifdef __APPLE__ + if ((flags & AI_NUMERICSERV) && (pptr == NULL || (pptr[0] == '0' && pptr[1] == 0))) { + /* On OSX upto at least OSX 10.8 getaddrinfo crashes + * if AI_NUMERICSERV is set and the servname is NULL or "0". + * This workaround avoids a segfault in libsystem. + */ + pptr = "00"; + } +#endif memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = socktype; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 24 16:12:15 2013 From: python-checkins at python.org (lukasz.langa) Date: Fri, 24 May 2013 16:12:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Document_the_=60dispatch=28?= =?utf-8?q?=29=60_attribute?= Message-ID: <3bH8fR2qpzzNv6@mail.python.org> http://hg.python.org/peps/rev/b7c693ce106a changeset: 4907:b7c693ce106a user: ?ukasz Langa date: Fri May 24 16:12:04 2013 +0200 summary: Document the `dispatch()` attribute files: pep-0443.txt | 14 +++++++++++--- 1 files changed, 11 insertions(+), 3 deletions(-) diff --git a/pep-0443.txt b/pep-0443.txt --- a/pep-0443.txt +++ b/pep-0443.txt @@ -97,8 +97,8 @@ >>> fun.register(type(None), nothing) The ``register()`` attribute returns the undecorated function which -enables decorator stacking, as well as creating unit tests for each -variant independently:: +enables decorator stacking, pickling, as well as creating unit tests for +each variant independently:: >>> @fun.register(float) ... @fun.register(Decimal) @@ -126,9 +126,17 @@ 3 spam >>> fun(None) Nothing. - >>> fun_num(1.23) + >>> fun(1.23) 0.615 +To get the implementation for a specific type, use the ``dispatch()`` +attribute:: + + >>> fun.dispatch(float) + + >>> fun.dispatch(dict) + + The proposed API is intentionally limited and opinionated, as to ensure it is easy to explain and use, as well as to maintain consistency with existing members in the ``functools`` module. -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri May 24 18:14:35 2013 From: python-checkins at python.org (senthil.kumaran) Date: Fri, 24 May 2013 18:14:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_=2317272_-_Make_Reques?= =?utf-8?q?t=2Efull=5Furl_and_Request=2Eget=5Ffull=5Furl_return_same_resul?= =?utf-8?q?t?= Message-ID: <3bHCMb1yBLz7LnC@mail.python.org> http://hg.python.org/cpython/rev/51c5870144e7 changeset: 83909:51c5870144e7 user: Senthil Kumaran date: Fri May 24 09:14:12 2013 -0700 summary: Fix #17272 - Make Request.full_url and Request.get_full_url return same result under all circumstances. Document the change of Request.full_url to a property. files: Doc/library/urllib.request.rst | 10 ++++++++++ Lib/test/test_urllib2.py | 15 +++++++++++++++ Lib/test/test_urllib2net.py | 8 ++++++++ Lib/urllib/request.py | 4 ++-- 4 files changed, 35 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 @@ -396,6 +396,12 @@ The original URL passed to the constructor. + .. versionchanged:: 3.4 + + Request.full_url is a property with setter, getter and a deleter. Getting + :attr:`~Request.full_url` returns the original request URL with the + fragment, if it was present. + .. attribute:: Request.type The URI scheme. @@ -482,6 +488,10 @@ Return the URL given in the constructor. + .. versionchanged:: 3.4 + + Returns :attr:`Request.full_url` + .. method:: Request.set_proxy(host, type) 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 @@ -11,6 +11,7 @@ # The proxy bypass method imported below has logic specific to the OSX # proxy config data structure but is testable on all platforms. from urllib.request import Request, OpenerDirector, _proxy_bypass_macosx_sysconf +from urllib.parse import urlparse import urllib.error # XXX @@ -919,7 +920,13 @@ r = Request('http://example.com') for url in urls: r.full_url = url + parsed = urlparse(url) + self.assertEqual(r.get_full_url(), url) + # full_url setter uses splittag to split into components. + # splittag sets the fragment as None while urlparse sets it to '' + self.assertEqual(r.fragment or '', parsed.fragment) + self.assertEqual(urlparse(r.get_full_url()).query, parsed.query) def test_full_url_deleter(self): r = Request('http://www.example.com') @@ -1537,6 +1544,14 @@ req = Request(url) self.assertEqual(req.get_full_url(), url) + def test_url_fullurl_get_full_url(self): + urls = ['http://docs.python.org', + 'http://docs.python.org/library/urllib2.html#OK', + 'http://www.python.org/?qs=query#fragment=true' ] + for url in urls: + req = Request(url) + self.assertEqual(req.get_full_url(), req.full_url) + def test_main(verbose=None): from test import test_urllib2 support.run_doctest(test_urllib2, verbose) 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 @@ -164,6 +164,14 @@ self.assertEqual(res.geturl(), "http://docs.python.org/2/glossary.html#glossary") + def test_redirect_url_withfrag(self): + redirect_url_with_frag = "http://bitly.com/urllibredirecttest" + 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(), + "http://docs.python.org/3.4/glossary.html#term-global-interpreter-lock") + def test_custom_headers(self): url = "http://www.example.com" with support.transient_internet(url): diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -275,6 +275,8 @@ @property def full_url(self): + if self.fragment: + return '{}#{}'.format(self._full_url, self.fragment) return self._full_url @full_url.setter @@ -326,8 +328,6 @@ return "GET" def get_full_url(self): - if self.fragment: - return '{}#{}'.format(self.full_url, self.fragment) return self.full_url def set_proxy(self, host, type): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 24 23:31:47 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 24 May 2013 23:31:47 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3OTUz?= =?utf-8?q?=3A_document_that_sys=2Emodules_shouldn=27t_be_replaced_=28than?= =?utf-8?q?ks?= Message-ID: <3bHLPb5VGNzSCk@mail.python.org> http://hg.python.org/cpython/rev/4f8160e45cb7 changeset: 83910:4f8160e45cb7 branch: 3.3 parent: 83907:3c4a5dc29417 user: Brett Cannon date: Fri May 24 08:05:07 2013 -0400 summary: Issue #17953: document that sys.modules shouldn't be replaced (thanks to interp->modules) and that deleting essential items from the dict can cause Python to blow up. Thanks to Terry Reedy for coming up with initial wording and Yogesh Chaudhari for coming up with a patch using that wording in parallel to my own patch. files: Doc/library/sys.rst | 2 ++ Misc/NEWS | 3 +++ 2 files changed, 5 insertions(+), 0 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -732,6 +732,8 @@ This is a dictionary that maps module names to modules which have already been loaded. This can be manipulated to force reloading of modules and other tricks. + However, replacing the dictionary will not necessarily work as expected and + deleting essential items from the dictionary may cause Python to fail. .. data:: path diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -59,6 +59,9 @@ Documentation ------------- +- Issue #17953: Mention that you shouldn't replace sys.modules and deleting key + items will cause Python to not be happy. + - Issue #17844: Add links to encoders and decoders for bytes-to-bytes codecs. - Issue #14097: improve the "introduction" page of the tutorial. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 24 23:31:49 2013 From: python-checkins at python.org (brett.cannon) Date: Fri, 24 May 2013 23:31:49 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge_fix_for_issue_=2317953?= Message-ID: <3bHLPd0TkLzSdv@mail.python.org> http://hg.python.org/cpython/rev/b60ae4ebf981 changeset: 83911:b60ae4ebf981 parent: 83909:51c5870144e7 parent: 83910:4f8160e45cb7 user: Brett Cannon date: Fri May 24 17:31:37 2013 -0400 summary: merge fix for issue #17953 files: Doc/library/sys.rst | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -757,6 +757,8 @@ This is a dictionary that maps module names to modules which have already been loaded. This can be manipulated to force reloading of modules and other tricks. + However, replacing the dictionary will not necessarily work as expected and + deleting essential items from the dictionary may cause Python to fail. .. data:: path -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 24 23:36:20 2013 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 24 May 2013 23:36:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_indicate_that_?= =?utf-8?q?read/write_work_with_bytes_=28closes_=2318009=29?= Message-ID: <3bHLVr4swxz7LkN@mail.python.org> http://hg.python.org/cpython/rev/7935844c6737 changeset: 83912:7935844c6737 branch: 3.3 parent: 83910:4f8160e45cb7 user: Benjamin Peterson date: Fri May 24 14:35:57 2013 -0700 summary: indicate that read/write work with bytes (closes #18009) files: Modules/posixmodule.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7838,7 +7838,7 @@ PyDoc_STRVAR(posix_read__doc__, -"read(fd, buffersize) -> string\n\n\ +"read(fd, buffersize) -> bytes\n\n\ Read a file descriptor."); static PyObject * @@ -8008,8 +8008,8 @@ #endif PyDoc_STRVAR(posix_write__doc__, -"write(fd, string) -> byteswritten\n\n\ -Write a string to a file descriptor."); +"write(fd, data) -> byteswritten\n\n\ +Write bytes to a file descriptor."); static PyObject * posix_write(PyObject *self, PyObject *args) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 24 23:36:22 2013 From: python-checkins at python.org (benjamin.peterson) Date: Fri, 24 May 2013 23:36:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogbWVyZ2UgMy4z?= Message-ID: <3bHLVt05CXz7Llq@mail.python.org> http://hg.python.org/cpython/rev/04ca3f1515cf changeset: 83913:04ca3f1515cf parent: 83911:b60ae4ebf981 parent: 83912:7935844c6737 user: Benjamin Peterson date: Fri May 24 14:36:04 2013 -0700 summary: merge 3.3 files: Modules/posixmodule.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7346,7 +7346,7 @@ PyDoc_STRVAR(posix_read__doc__, -"read(fd, buffersize) -> string\n\n\ +"read(fd, buffersize) -> bytes\n\n\ Read a file descriptor."); static PyObject * @@ -7516,8 +7516,8 @@ #endif PyDoc_STRVAR(posix_write__doc__, -"write(fd, string) -> byteswritten\n\n\ -Write a string to a file descriptor."); +"write(fd, data) -> byteswritten\n\n\ +Write bytes to a file descriptor."); static PyObject * posix_write(PyObject *self, PyObject *args) -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sat May 25 05:49:11 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 25 May 2013 05:49:11 +0200 Subject: [Python-checkins] Daily reference leaks (04ca3f1515cf): sum=1 Message-ID: results for 04ca3f1515cf on branch "default" -------------------------------------------- test_unittest leaked [-1, 2, 0] memory blocks, sum=1 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog7NDYcU', '-x'] From python-checkins at python.org Sat May 25 12:20:51 2013 From: python-checkins at python.org (vinay.sajip) Date: Sat, 25 May 2013 12:20:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Closes_=2318046=3A_Simplif?= =?utf-8?q?ied_logging_internals_relating_to_levels_and_their_names=2E?= Message-ID: <3bHgSz1tn6z7LnT@mail.python.org> http://hg.python.org/cpython/rev/5629bf4c6bba changeset: 83914:5629bf4c6bba user: Vinay Sajip date: Sat May 25 03:20:34 2013 -0700 summary: Closes #18046: Simplified logging internals relating to levels and their names. Thanks to Alex Gaynor for the patch. files: Lib/logging/__init__.py | 40 ++++++++++++++------------- Lib/logging/config.py | 6 ++-- Lib/test/test_logging.py | 9 ++++-- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -123,20 +123,22 @@ DEBUG = 10 NOTSET = 0 -_levelNames = { - CRITICAL : 'CRITICAL', - ERROR : 'ERROR', - WARNING : 'WARNING', - INFO : 'INFO', - DEBUG : 'DEBUG', - NOTSET : 'NOTSET', - 'CRITICAL' : CRITICAL, - 'ERROR' : ERROR, - 'WARN' : WARNING, - 'WARNING' : WARNING, - 'INFO' : INFO, - 'DEBUG' : DEBUG, - 'NOTSET' : NOTSET, +_levelToName = { + CRITICAL: 'CRITICAL', + ERROR: 'ERROR', + WARNING: 'WARNING', + INFO: 'INFO', + DEBUG: 'DEBUG', + NOTSET: 'NOTSET', +} +_nameToLevel = { + 'CRITICAL': CRITICAL, + 'ERROR': ERROR, + 'WARN': WARNING, + 'WARNING': WARNING, + 'INFO': INFO, + 'DEBUG': DEBUG, + 'NOTSET': NOTSET, } def getLevelName(level): @@ -153,7 +155,7 @@ Otherwise, the string "Level %s" % level is returned. """ - return _levelNames.get(level, ("Level %s" % level)) + return _levelToName.get(level, ("Level %s" % level)) def addLevelName(level, levelName): """ @@ -163,8 +165,8 @@ """ _acquireLock() try: #unlikely to cause an exception, but you never know... - _levelNames[level] = levelName - _levelNames[levelName] = level + _levelToName[level] = levelName + _nameToLevel[levelName] = level finally: _releaseLock() @@ -172,9 +174,9 @@ if isinstance(level, int): rv = level elif str(level) == level: - if level not in _levelNames: + if level not in _nameToLevel: raise ValueError("Unknown level: %r" % level) - rv = _levelNames[level] + rv = _nameToLevel[level] else: raise TypeError("Level not an integer or a valid string: %r" % level) return rv diff --git a/Lib/logging/config.py b/Lib/logging/config.py --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -144,7 +144,7 @@ h = klass(*args) if "level" in section: level = section["level"] - h.setLevel(logging._levelNames[level]) + h.setLevel(level) if len(fmt): h.setFormatter(formatters[fmt]) if issubclass(klass, logging.handlers.MemoryHandler): @@ -191,7 +191,7 @@ log = root if "level" in section: level = section["level"] - log.setLevel(logging._levelNames[level]) + log.setLevel(level) for h in root.handlers[:]: root.removeHandler(h) hlist = section["handlers"] @@ -237,7 +237,7 @@ existing.remove(qn) if "level" in section: level = section["level"] - logger.setLevel(logging._levelNames[level]) + logger.setLevel(level) for h in logger.handlers[:]: logger.removeHandler(h) logger.propagate = propagate 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 @@ -94,7 +94,8 @@ self.saved_handlers = logging._handlers.copy() self.saved_handler_list = logging._handlerList[:] self.saved_loggers = saved_loggers = logger_dict.copy() - self.saved_level_names = logging._levelNames.copy() + self.saved_name_to_level = logging._nameToLevel.copy() + self.saved_level_to_name = logging._levelToName.copy() self.logger_states = logger_states = {} for name in saved_loggers: logger_states[name] = getattr(saved_loggers[name], @@ -136,8 +137,10 @@ self.root_logger.setLevel(self.original_logging_level) logging._acquireLock() try: - logging._levelNames.clear() - logging._levelNames.update(self.saved_level_names) + logging._levelToName.clear() + logging._levelToName.update(self.saved_level_to_name) + logging._nameToLevel.clear() + logging._nameToLevel.update(self.saved_name_to_level) logging._handlers.clear() logging._handlers.update(self.saved_handlers) logging._handlerList[:] = self.saved_handler_list -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 25 13:02:41 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 25 May 2013 13:02:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=238240=3A_Set_the_S?= =?utf-8?q?SL=5FMODE=5FACCEPT=5FMOVING=5FWRITE=5FBUFFER_flag_on_SSL_socket?= =?utf-8?q?s=2E?= Message-ID: <3bHhPF4jckz7LkM@mail.python.org> http://hg.python.org/cpython/rev/60310223d075 changeset: 83915:60310223d075 user: Antoine Pitrou date: Sat May 25 13:02:32 2013 +0200 summary: Issue #8240: Set the SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER flag on SSL sockets. files: Misc/NEWS | 3 +++ Modules/_ssl.c | 4 +++- 2 files changed, 6 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -96,6 +96,9 @@ Library ------- +- Issue #8240: Set the SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER flag on SSL + sockets. + - Issue #17269: Workaround for socket.getaddrinfo crash on MacOS X with port None or "0" and flags AI_NUMERICSERV. diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -490,9 +490,11 @@ PySSL_END_ALLOW_THREADS SSL_set_app_data(self->ssl,self); SSL_set_fd(self->ssl, sock->sock_fd); + SSL_set_mode(self->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER #ifdef SSL_MODE_AUTO_RETRY - SSL_set_mode(self->ssl, SSL_MODE_AUTO_RETRY); + | SSL_MODE_AUTO_RETRY #endif + ); #if HAVE_SNI if (server_hostname != NULL) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 25 13:08:50 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 25 May 2013 13:08:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogRml4IHRlc3RfYmFk?= =?utf-8?q?=5Faddress_on_Ubuntu_13=2E04?= Message-ID: <3bHhXL596gzRwP@mail.python.org> http://hg.python.org/cpython/rev/b17662fc41af changeset: 83916:b17662fc41af branch: 3.3 parent: 83912:7935844c6737 user: Antoine Pitrou date: Sat May 25 13:08:13 2013 +0200 summary: Fix test_bad_address on Ubuntu 13.04 files: Lib/test/test_urllibnet.py | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) 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 @@ -116,7 +116,10 @@ bogus_domain = "sadflkjsasf.i.nvali.d" try: socket.gethostbyname(bogus_domain) - except socket.gaierror: + except OSError: + # socket.gaierror is too narrow, since getaddrinfo() may also + # fail with EAI_SYSTEM and ETIMEDOUT (seen on Ubuntu 13.04), + # i.e. Python's TimeoutError. pass else: # This happens with some overzealous DNS providers such as OpenDNS -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 25 13:08:51 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 25 May 2013 13:08:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Fix_test=5Fbad=5Faddress_on_Ubuntu_13=2E04?= Message-ID: <3bHhXM6yKmzRwP@mail.python.org> http://hg.python.org/cpython/rev/6f8fef208958 changeset: 83917:6f8fef208958 parent: 83915:60310223d075 parent: 83916:b17662fc41af user: Antoine Pitrou date: Sat May 25 13:08:34 2013 +0200 summary: Fix test_bad_address on Ubuntu 13.04 files: Lib/test/test_urllibnet.py | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) 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 @@ -116,7 +116,10 @@ bogus_domain = "sadflkjsasf.i.nvali.d" try: socket.gethostbyname(bogus_domain) - except socket.gaierror: + except OSError: + # socket.gaierror is too narrow, since getaddrinfo() may also + # fail with EAI_SYSTEM and ETIMEDOUT (seen on Ubuntu 13.04), + # i.e. Python's TimeoutError. pass else: # This happens with some overzealous DNS providers such as OpenDNS -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 25 13:23:11 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 25 May 2013 13:23:11 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_compilation_under_MSVC?= =?utf-8?q?=3A_ssl=5Fset=5Fmode=28=29_is_a_macro=2C_and_the_MSVC?= Message-ID: <3bHhrv4VcDz7LkK@mail.python.org> http://hg.python.org/cpython/rev/0bf4a6b56eb5 changeset: 83918:0bf4a6b56eb5 user: Antoine Pitrou date: Sat May 25 13:23:03 2013 +0200 summary: Fix compilation under MSVC: ssl_set_mode() is a macro, and the MSVC preprocessor doesn't process #ifdef's inside a macro argument list. (found explanation at http://www.tech-archive.net/Archive/VC/microsoft.public.vc.language/2007-05/msg00385.html) files: Modules/_ssl.c | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Modules/_ssl.c b/Modules/_ssl.c --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -470,6 +470,7 @@ { PySSLSocket *self; SSL_CTX *ctx = sslctx->ctx; + long mode; self = PyObject_New(PySSLSocket, &PySSLSocket_Type); if (self == NULL) @@ -490,11 +491,11 @@ PySSL_END_ALLOW_THREADS SSL_set_app_data(self->ssl,self); SSL_set_fd(self->ssl, sock->sock_fd); - SSL_set_mode(self->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER + mode = SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER; #ifdef SSL_MODE_AUTO_RETRY - | SSL_MODE_AUTO_RETRY + mode |= SSL_MODE_AUTO_RETRY; #endif - ); + SSL_set_mode(self->ssl, mode); #if HAVE_SNI if (server_hostname != NULL) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 25 14:03:42 2013 From: python-checkins at python.org (lukasz.langa) Date: Sat, 25 May 2013 14:03:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Resolve_the_open_issue_on_ABC?= =?utf-8?q?_support=2C_link_the_reference_implementation=2E?= Message-ID: <3bHjlf4RtBz7Lnf@mail.python.org> http://hg.python.org/peps/rev/66ff54bad2ba changeset: 4908:66ff54bad2ba user: ?ukasz Langa date: Sat May 25 14:03:31 2013 +0200 summary: Resolve the open issue on ABC support, link the reference implementation. files: pep-0443.txt | 90 ++++++++++++++++++++++++++++++++++++---- 1 files changed, 81 insertions(+), 9 deletions(-) diff --git a/pep-0443.txt b/pep-0443.txt --- a/pep-0443.txt +++ b/pep-0443.txt @@ -8,7 +8,7 @@ Type: Standards Track Content-Type: text/x-rst Created: 22-May-2013 -Post-History: 22-May-2013 +Post-History: 22-May-2013, 25-May-2013 Replaces: 245, 246, 3124 @@ -147,13 +147,8 @@ The functionality described in this PEP is already implemented in the ``pkgutil`` standard library module as ``simplegeneric``. Because this -implementation is mature, the goal is to move it largely as-is. - -The current implementation relies on ``__mro__`` alone, it will be made -compatible with Abstract Base Classes' ``register()``/``unregister()`` -functionality. A possible solution has been proposed by PJE on the -original issue for exposing ``pkgutil.simplegeneric`` as part of the -``functools`` API [#issue-5135]_. +implementation is mature, the goal is to move it largely as-is. The +reference implementation is available on hg.python.org [#ref-impl]_. The dispatch type is specified as a decorator argument. An alternative form using function annotations has been considered but its inclusion @@ -165,6 +160,80 @@ following the convention on registering virtual subclasses on Abstract Base Classes, the dispatch registry will not be thread-safe. +Abstract Base Classes +--------------------- + +The ``pkgutil.simplegeneric`` implementation relied on several forms of +method resultion order (MRO). ``@singledispatch`` removes special +handling of old-style classes and Zope's ExtensionClasses. More +importantly, it introduces support for Abstract Base Classes (ABC). + +When a generic function overload is registered for an ABC, the dispatch +algorithm switches to a mode of MRO calculation for the provided +argument which includes the relevant ABCs. The algorithm is as follows:: + + def _compose_mro(cls, haystack): + """Calculates the MRO for a given class `cls`, including relevant + abstract base classes from `haystack`.""" + bases = set(cls.__mro__) + mro = list(cls.__mro__) + for regcls in haystack: + if regcls in bases or not issubclass(cls, regcls): + continue # either present in the __mro__ or unrelated + for index, base in enumerate(mro): + if not issubclass(base, regcls): + break + if base in bases and not issubclass(regcls, base): + # Conflict resolution: put classes present in __mro__ + # and their subclasses first. + index += 1 + mro.insert(index, regcls) + return mro + +While this mode of operation is significantly slower, no caching is +involved because user code may ``register()`` a new class on an ABC at +any time. In such case, it is possible to create a situation with +ambiguous dispatch, for instance:: + + >>> from collections import Iterable, Container + >>> class P: + ... pass + >>> Iterable.register(P) + + >>> Container.register(P) + + +Faced with ambiguity, ``@singledispatch`` refuses the temptation to +guess:: + + >>> @singledispatch + ... def g(arg): + ... return "base" + ... + >>> g.register(Iterable, lambda arg: "iterable") + at 0x108b49110> + >>> g.register(Container, lambda arg: "container") + at 0x108b491c8> + >>> g(P()) + Traceback (most recent call last): + ... + RuntimeError: Ambiguous dispatch: + or + +Note that this exception would not be raised if ``Iterable`` and +``Container`` had been provided as base classes during class definition. +In this case dispatch happens in the MRO order:: + + >>> class Ten(Iterable, Container): + ... def __iter__(self): + ... for i in range(10): + ... yield i + ... def __contains__(self, value): + ... return value in range(10) + ... + >>> g(Ten()) + 'iterable' + Usage Patterns ============== @@ -256,7 +325,8 @@ References ========== -.. [#issue-5135] http://bugs.python.org/issue5135 +.. [#ref-impl] + http://hg.python.org/features/pep-443/file/tip/Lib/functools.py#l359 .. [#pep-0008] PEP 8 states in the "Programming Recommendations" section that "the Python standard library will not use function @@ -279,6 +349,8 @@ .. [#pairtype] https://bitbucket.org/pypy/pypy/raw/default/rpython/tool/pairtype.py +.. [#issue-5135] http://bugs.python.org/issue5135 + Copyright ========= -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat May 25 14:27:33 2013 From: python-checkins at python.org (eli.bendersky) Date: Sat, 25 May 2013 14:27:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzEzNjEy?= =?utf-8?q?=3A_handle_unknown_encodings_without_a_buffer_overflow=2E?= Message-ID: <3bHkH94lDDz7Ljq@mail.python.org> http://hg.python.org/cpython/rev/f7b47fb30169 changeset: 83919:f7b47fb30169 branch: 3.3 parent: 83916:b17662fc41af user: Eli Bendersky date: Sat May 25 05:25:48 2013 -0700 summary: Issue #13612: handle unknown encodings without a buffer overflow. This affects pyexpat and _elementtree. PyExpat_CAPI now exposes a new function - DefaultUnknownEncodingHandler. Based on a patch by Serhiy Storchaka. files: Include/pyexpat.h | 4 +- Lib/test/test_xml_etree.py | 92 ++++++++++++++++++++++++++ Modules/_elementtree.c | 43 +----------- Modules/pyexpat.c | 58 +++++++-------- 4 files changed, 123 insertions(+), 74 deletions(-) diff --git a/Include/pyexpat.h b/Include/pyexpat.h --- a/Include/pyexpat.h +++ b/Include/pyexpat.h @@ -6,7 +6,7 @@ #define PyExpat_CAPI_MAGIC "pyexpat.expat_CAPI 1.0" #define PyExpat_CAPSULE_NAME "pyexpat.expat_CAPI" -struct PyExpat_CAPI +struct PyExpat_CAPI { char* magic; /* set to PyExpat_CAPI_MAGIC */ int size; /* set to sizeof(struct PyExpat_CAPI) */ @@ -46,6 +46,8 @@ void (*SetStartDoctypeDeclHandler)(XML_Parser parser, XML_StartDoctypeDeclHandler start); enum XML_Status (*SetEncoding)(XML_Parser parser, const XML_Char *encoding); + int (*DefaultUnknownEncodingHandler)( + void *encodingHandlerData, const XML_Char *name, XML_Encoding *info); /* always add new stuff to the end! */ }; diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -690,6 +690,98 @@ check("cp437", '\u221a') check("mac-roman", '\u02da') + def xml(encoding): + return "" % encoding + def bxml(encoding): + return xml(encoding).encode(encoding) + supported_encodings = [ + 'ascii', 'utf-8', 'utf-8-sig', 'utf-16', 'utf-16be', 'utf-16le', + 'iso8859-1', 'iso8859-2', 'iso8859-3', 'iso8859-4', 'iso8859-5', + 'iso8859-6', 'iso8859-7', 'iso8859-8', 'iso8859-9', 'iso8859-10', + 'iso8859-13', 'iso8859-14', 'iso8859-15', 'iso8859-16', + 'cp437', 'cp720', 'cp737', 'cp775', 'cp850', 'cp852', + 'cp855', 'cp856', 'cp857', 'cp858', 'cp860', 'cp861', 'cp862', + 'cp863', 'cp865', 'cp866', 'cp869', 'cp874', 'cp1006', 'cp1250', + 'cp1251', 'cp1252', 'cp1253', 'cp1254', 'cp1255', 'cp1256', + 'cp1257', 'cp1258', + 'mac-cyrillic', 'mac-greek', 'mac-iceland', 'mac-latin2', + 'mac-roman', 'mac-turkish', + 'iso2022-jp', 'iso2022-jp-1', 'iso2022-jp-2', 'iso2022-jp-2004', + 'iso2022-jp-3', 'iso2022-jp-ext', + 'koi8-r', 'koi8-u', + 'hz', 'ptcp154', + ] + for encoding in supported_encodings: + self.assertEqual(ET.tostring(ET.XML(bxml(encoding))), b'') + + unsupported_ascii_compatible_encodings = [ + 'big5', 'big5hkscs', + 'cp932', 'cp949', 'cp950', + 'euc-jp', 'euc-jis-2004', 'euc-jisx0213', 'euc-kr', + 'gb2312', 'gbk', 'gb18030', + 'iso2022-kr', 'johab', + 'shift-jis', 'shift-jis-2004', 'shift-jisx0213', + 'utf-7', + ] + for encoding in unsupported_ascii_compatible_encodings: + self.assertRaises(ValueError, ET.XML, bxml(encoding)) + + unsupported_ascii_incompatible_encodings = [ + 'cp037', 'cp424', 'cp500', 'cp864', 'cp875', 'cp1026', 'cp1140', + 'utf_32', 'utf_32_be', 'utf_32_le', + ] + for encoding in unsupported_ascii_incompatible_encodings: + self.assertRaises(ET.ParseError, ET.XML, bxml(encoding)) + + self.assertRaises(ValueError, ET.XML, xml('undefined').encode('ascii')) + self.assertRaises(LookupError, ET.XML, xml('xxx').encode('ascii')) + + def xml(encoding): + return "" % encoding + def bxml(encoding): + return xml(encoding).encode(encoding) + supported_encodings = [ + 'ascii', 'utf-8', 'utf-8-sig', 'utf-16', 'utf-16be', 'utf-16le', + 'iso8859-1', 'iso8859-2', 'iso8859-3', 'iso8859-4', 'iso8859-5', + 'iso8859-6', 'iso8859-7', 'iso8859-8', 'iso8859-9', 'iso8859-10', + 'iso8859-13', 'iso8859-14', 'iso8859-15', 'iso8859-16', + 'cp437', 'cp720', 'cp737', 'cp775', 'cp850', 'cp852', + 'cp855', 'cp856', 'cp857', 'cp858', 'cp860', 'cp861', 'cp862', + 'cp863', 'cp865', 'cp866', 'cp869', 'cp874', 'cp1006', 'cp1250', + 'cp1251', 'cp1252', 'cp1253', 'cp1254', 'cp1255', 'cp1256', + 'cp1257', 'cp1258', + 'mac-cyrillic', 'mac-greek', 'mac-iceland', 'mac-latin2', + 'mac-roman', 'mac-turkish', + 'iso2022-jp', 'iso2022-jp-1', 'iso2022-jp-2', 'iso2022-jp-2004', + 'iso2022-jp-3', 'iso2022-jp-ext', + 'koi8-r', 'koi8-u', + 'hz', 'ptcp154', + ] + for encoding in supported_encodings: + self.assertEqual(ET.tostring(ET.XML(bxml(encoding))), b'') + + unsupported_ascii_compatible_encodings = [ + 'big5', 'big5hkscs', + 'cp932', 'cp949', 'cp950', + 'euc-jp', 'euc-jis-2004', 'euc-jisx0213', 'euc-kr', + 'gb2312', 'gbk', 'gb18030', + 'iso2022-kr', 'johab', + 'shift-jis', 'shift-jis-2004', 'shift-jisx0213', + 'utf-7', + ] + for encoding in unsupported_ascii_compatible_encodings: + self.assertRaises(ValueError, ET.XML, bxml(encoding)) + + unsupported_ascii_incompatible_encodings = [ + 'cp037', 'cp424', 'cp500', 'cp864', 'cp875', 'cp1026', 'cp1140', + 'utf_32', 'utf_32_be', 'utf_32_le', + ] + for encoding in unsupported_ascii_incompatible_encodings: + self.assertRaises(ET.ParseError, ET.XML, bxml(encoding)) + + self.assertRaises(ValueError, ET.XML, xml('undefined').encode('ascii')) + self.assertRaises(LookupError, ET.XML, xml('xxx').encode('ascii')) + def test_methods(self): # Test serialization methods. diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -3136,47 +3136,6 @@ } } -static int -expat_unknown_encoding_handler(XMLParserObject *self, const XML_Char *name, - XML_Encoding *info) -{ - PyObject* u; - unsigned char s[256]; - int i; - void *data; - unsigned int kind; - - memset(info, 0, sizeof(XML_Encoding)); - - for (i = 0; i < 256; i++) - s[i] = i; - - u = PyUnicode_Decode((char*) s, 256, name, "replace"); - if (!u) - return XML_STATUS_ERROR; - if (PyUnicode_READY(u)) - return XML_STATUS_ERROR; - - if (PyUnicode_GET_LENGTH(u) != 256) { - Py_DECREF(u); - return XML_STATUS_ERROR; - } - - kind = PyUnicode_KIND(u); - data = PyUnicode_DATA(u); - for (i = 0; i < 256; i++) { - Py_UCS4 ch = PyUnicode_READ(kind, data, i); - if (ch != Py_UNICODE_REPLACEMENT_CHARACTER) - info->map[i] = ch; - else - info->map[i] = -1; - } - - Py_DECREF(u); - - return XML_STATUS_OK; -} - /* -------------------------------------------------------------------- */ static PyObject * @@ -3278,7 +3237,7 @@ ); EXPAT(SetUnknownEncodingHandler)( self_xp->parser, - (XML_UnknownEncodingHandler) expat_unknown_encoding_handler, NULL + EXPAT(DefaultUnknownEncodingHandler), NULL ); return 0; diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1111,53 +1111,49 @@ Make it as simple as possible. */ -static char template_buffer[257]; - -static void -init_template_buffer(void) -{ - int i; - for (i = 0; i < 256; i++) { - template_buffer[i] = i; - } - template_buffer[256] = 0; -} - static int PyUnknownEncodingHandler(void *encodingHandlerData, const XML_Char *name, XML_Encoding *info) { - PyUnicodeObject *_u_string = NULL; - int result = 0; + static unsigned char template_buffer[256] = {0}; + PyObject* u; int i; - int kind; void *data; + unsigned int kind; - /* Yes, supports only 8bit encodings */ - _u_string = (PyUnicodeObject *) - PyUnicode_Decode(template_buffer, 256, name, "replace"); + if (template_buffer[1] == 0) { + for (i = 0; i < 256; i++) + template_buffer[i] = i; + } - if (_u_string == NULL || PyUnicode_READY(_u_string) == -1) - return result; + u = PyUnicode_Decode((char*) template_buffer, 256, name, "replace"); + if (u == NULL || PyUnicode_READY(u)) + return XML_STATUS_ERROR; - kind = PyUnicode_KIND(_u_string); - data = PyUnicode_DATA(_u_string); + if (PyUnicode_GET_LENGTH(u) != 256) { + Py_DECREF(u); + PyErr_SetString(PyExc_ValueError, + "multi-byte encodings are not supported"); + return XML_STATUS_ERROR; + } + kind = PyUnicode_KIND(u); + data = PyUnicode_DATA(u); for (i = 0; i < 256; i++) { - /* Stupid to access directly, but fast */ - Py_UCS4 c = PyUnicode_READ(kind, data, i); - if (c == Py_UNICODE_REPLACEMENT_CHARACTER) + Py_UCS4 ch = PyUnicode_READ(kind, data, i); + if (ch != Py_UNICODE_REPLACEMENT_CHARACTER) + info->map[i] = ch; + else info->map[i] = -1; - else - info->map[i] = c; } + info->data = NULL; info->convert = NULL; info->release = NULL; - result = 1; - Py_DECREF(_u_string); - return result; + Py_DECREF(u); + + return XML_STATUS_OK; } @@ -1752,7 +1748,6 @@ Py_BuildValue("(iii)", info.major, info.minor, info.micro)); } - init_template_buffer(); /* XXX When Expat supports some way of figuring out how it was compiled, this should check and set native_encoding appropriately. @@ -1938,6 +1933,7 @@ capi.SetUserData = XML_SetUserData; capi.SetStartDoctypeDeclHandler = XML_SetStartDoctypeDeclHandler; capi.SetEncoding = XML_SetEncoding; + capi.DefaultUnknownEncodingHandler = PyUnknownEncodingHandler; /* export using capsule */ capi_object = PyCapsule_New(&capi, PyExpat_CAPSULE_NAME, NULL); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 25 14:27:35 2013 From: python-checkins at python.org (eli.bendersky) Date: Sat, 25 May 2013 14:27:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2313612=3A_handle_unknown_encodings_without_a_buf?= =?utf-8?q?fer_overflow=2E?= Message-ID: <3bHkHC0nkHz7LkW@mail.python.org> http://hg.python.org/cpython/rev/47e719b11c46 changeset: 83920:47e719b11c46 parent: 83918:0bf4a6b56eb5 parent: 83919:f7b47fb30169 user: Eli Bendersky date: Sat May 25 05:27:10 2013 -0700 summary: Issue #13612: handle unknown encodings without a buffer overflow. This affects pyexpat and _elementtree. PyExpat_CAPI now exposes a new function - DefaultUnknownEncodingHandler. Based on a patch by Serhiy Storchaka. files: Include/pyexpat.h | 4 +- Lib/test/test_xml_etree.py | 92 ++++++++++++++++++++++++++ Modules/_elementtree.c | 43 +----------- Modules/pyexpat.c | 58 +++++++-------- 4 files changed, 123 insertions(+), 74 deletions(-) diff --git a/Include/pyexpat.h b/Include/pyexpat.h --- a/Include/pyexpat.h +++ b/Include/pyexpat.h @@ -6,7 +6,7 @@ #define PyExpat_CAPI_MAGIC "pyexpat.expat_CAPI 1.0" #define PyExpat_CAPSULE_NAME "pyexpat.expat_CAPI" -struct PyExpat_CAPI +struct PyExpat_CAPI { char* magic; /* set to PyExpat_CAPI_MAGIC */ int size; /* set to sizeof(struct PyExpat_CAPI) */ @@ -46,6 +46,8 @@ void (*SetStartDoctypeDeclHandler)(XML_Parser parser, XML_StartDoctypeDeclHandler start); enum XML_Status (*SetEncoding)(XML_Parser parser, const XML_Char *encoding); + int (*DefaultUnknownEncodingHandler)( + void *encodingHandlerData, const XML_Char *name, XML_Encoding *info); /* always add new stuff to the end! */ }; diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -681,6 +681,98 @@ check("cp437", '\u221a') check("mac-roman", '\u02da') + def xml(encoding): + return "" % encoding + def bxml(encoding): + return xml(encoding).encode(encoding) + supported_encodings = [ + 'ascii', 'utf-8', 'utf-8-sig', 'utf-16', 'utf-16be', 'utf-16le', + 'iso8859-1', 'iso8859-2', 'iso8859-3', 'iso8859-4', 'iso8859-5', + 'iso8859-6', 'iso8859-7', 'iso8859-8', 'iso8859-9', 'iso8859-10', + 'iso8859-13', 'iso8859-14', 'iso8859-15', 'iso8859-16', + 'cp437', 'cp720', 'cp737', 'cp775', 'cp850', 'cp852', + 'cp855', 'cp856', 'cp857', 'cp858', 'cp860', 'cp861', 'cp862', + 'cp863', 'cp865', 'cp866', 'cp869', 'cp874', 'cp1006', 'cp1250', + 'cp1251', 'cp1252', 'cp1253', 'cp1254', 'cp1255', 'cp1256', + 'cp1257', 'cp1258', + 'mac-cyrillic', 'mac-greek', 'mac-iceland', 'mac-latin2', + 'mac-roman', 'mac-turkish', + 'iso2022-jp', 'iso2022-jp-1', 'iso2022-jp-2', 'iso2022-jp-2004', + 'iso2022-jp-3', 'iso2022-jp-ext', + 'koi8-r', 'koi8-u', + 'hz', 'ptcp154', + ] + for encoding in supported_encodings: + self.assertEqual(ET.tostring(ET.XML(bxml(encoding))), b'') + + unsupported_ascii_compatible_encodings = [ + 'big5', 'big5hkscs', + 'cp932', 'cp949', 'cp950', + 'euc-jp', 'euc-jis-2004', 'euc-jisx0213', 'euc-kr', + 'gb2312', 'gbk', 'gb18030', + 'iso2022-kr', 'johab', + 'shift-jis', 'shift-jis-2004', 'shift-jisx0213', + 'utf-7', + ] + for encoding in unsupported_ascii_compatible_encodings: + self.assertRaises(ValueError, ET.XML, bxml(encoding)) + + unsupported_ascii_incompatible_encodings = [ + 'cp037', 'cp424', 'cp500', 'cp864', 'cp875', 'cp1026', 'cp1140', + 'utf_32', 'utf_32_be', 'utf_32_le', + ] + for encoding in unsupported_ascii_incompatible_encodings: + self.assertRaises(ET.ParseError, ET.XML, bxml(encoding)) + + self.assertRaises(ValueError, ET.XML, xml('undefined').encode('ascii')) + self.assertRaises(LookupError, ET.XML, xml('xxx').encode('ascii')) + + def xml(encoding): + return "" % encoding + def bxml(encoding): + return xml(encoding).encode(encoding) + supported_encodings = [ + 'ascii', 'utf-8', 'utf-8-sig', 'utf-16', 'utf-16be', 'utf-16le', + 'iso8859-1', 'iso8859-2', 'iso8859-3', 'iso8859-4', 'iso8859-5', + 'iso8859-6', 'iso8859-7', 'iso8859-8', 'iso8859-9', 'iso8859-10', + 'iso8859-13', 'iso8859-14', 'iso8859-15', 'iso8859-16', + 'cp437', 'cp720', 'cp737', 'cp775', 'cp850', 'cp852', + 'cp855', 'cp856', 'cp857', 'cp858', 'cp860', 'cp861', 'cp862', + 'cp863', 'cp865', 'cp866', 'cp869', 'cp874', 'cp1006', 'cp1250', + 'cp1251', 'cp1252', 'cp1253', 'cp1254', 'cp1255', 'cp1256', + 'cp1257', 'cp1258', + 'mac-cyrillic', 'mac-greek', 'mac-iceland', 'mac-latin2', + 'mac-roman', 'mac-turkish', + 'iso2022-jp', 'iso2022-jp-1', 'iso2022-jp-2', 'iso2022-jp-2004', + 'iso2022-jp-3', 'iso2022-jp-ext', + 'koi8-r', 'koi8-u', + 'hz', 'ptcp154', + ] + for encoding in supported_encodings: + self.assertEqual(ET.tostring(ET.XML(bxml(encoding))), b'') + + unsupported_ascii_compatible_encodings = [ + 'big5', 'big5hkscs', + 'cp932', 'cp949', 'cp950', + 'euc-jp', 'euc-jis-2004', 'euc-jisx0213', 'euc-kr', + 'gb2312', 'gbk', 'gb18030', + 'iso2022-kr', 'johab', + 'shift-jis', 'shift-jis-2004', 'shift-jisx0213', + 'utf-7', + ] + for encoding in unsupported_ascii_compatible_encodings: + self.assertRaises(ValueError, ET.XML, bxml(encoding)) + + unsupported_ascii_incompatible_encodings = [ + 'cp037', 'cp424', 'cp500', 'cp864', 'cp875', 'cp1026', 'cp1140', + 'utf_32', 'utf_32_be', 'utf_32_le', + ] + for encoding in unsupported_ascii_incompatible_encodings: + self.assertRaises(ET.ParseError, ET.XML, bxml(encoding)) + + self.assertRaises(ValueError, ET.XML, xml('undefined').encode('ascii')) + self.assertRaises(LookupError, ET.XML, xml('xxx').encode('ascii')) + def test_methods(self): # Test serialization methods. diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -3094,47 +3094,6 @@ } } -static int -expat_unknown_encoding_handler(XMLParserObject *self, const XML_Char *name, - XML_Encoding *info) -{ - PyObject* u; - unsigned char s[256]; - int i; - void *data; - unsigned int kind; - - memset(info, 0, sizeof(XML_Encoding)); - - for (i = 0; i < 256; i++) - s[i] = i; - - u = PyUnicode_Decode((char*) s, 256, name, "replace"); - if (!u) - return XML_STATUS_ERROR; - if (PyUnicode_READY(u)) - return XML_STATUS_ERROR; - - if (PyUnicode_GET_LENGTH(u) != 256) { - Py_DECREF(u); - return XML_STATUS_ERROR; - } - - kind = PyUnicode_KIND(u); - data = PyUnicode_DATA(u); - for (i = 0; i < 256; i++) { - Py_UCS4 ch = PyUnicode_READ(kind, data, i); - if (ch != Py_UNICODE_REPLACEMENT_CHARACTER) - info->map[i] = ch; - else - info->map[i] = -1; - } - - Py_DECREF(u); - - return XML_STATUS_OK; -} - /* -------------------------------------------------------------------- */ static PyObject * @@ -3236,7 +3195,7 @@ ); EXPAT(SetUnknownEncodingHandler)( self_xp->parser, - (XML_UnknownEncodingHandler) expat_unknown_encoding_handler, NULL + EXPAT(DefaultUnknownEncodingHandler), NULL ); return 0; diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1111,53 +1111,49 @@ Make it as simple as possible. */ -static char template_buffer[257]; - -static void -init_template_buffer(void) -{ - int i; - for (i = 0; i < 256; i++) { - template_buffer[i] = i; - } - template_buffer[256] = 0; -} - static int PyUnknownEncodingHandler(void *encodingHandlerData, const XML_Char *name, XML_Encoding *info) { - PyUnicodeObject *_u_string = NULL; - int result = 0; + static unsigned char template_buffer[256] = {0}; + PyObject* u; int i; - int kind; void *data; + unsigned int kind; - /* Yes, supports only 8bit encodings */ - _u_string = (PyUnicodeObject *) - PyUnicode_Decode(template_buffer, 256, name, "replace"); + if (template_buffer[1] == 0) { + for (i = 0; i < 256; i++) + template_buffer[i] = i; + } - if (_u_string == NULL || PyUnicode_READY(_u_string) == -1) - return result; + u = PyUnicode_Decode((char*) template_buffer, 256, name, "replace"); + if (u == NULL || PyUnicode_READY(u)) + return XML_STATUS_ERROR; - kind = PyUnicode_KIND(_u_string); - data = PyUnicode_DATA(_u_string); + if (PyUnicode_GET_LENGTH(u) != 256) { + Py_DECREF(u); + PyErr_SetString(PyExc_ValueError, + "multi-byte encodings are not supported"); + return XML_STATUS_ERROR; + } + kind = PyUnicode_KIND(u); + data = PyUnicode_DATA(u); for (i = 0; i < 256; i++) { - /* Stupid to access directly, but fast */ - Py_UCS4 c = PyUnicode_READ(kind, data, i); - if (c == Py_UNICODE_REPLACEMENT_CHARACTER) + Py_UCS4 ch = PyUnicode_READ(kind, data, i); + if (ch != Py_UNICODE_REPLACEMENT_CHARACTER) + info->map[i] = ch; + else info->map[i] = -1; - else - info->map[i] = c; } + info->data = NULL; info->convert = NULL; info->release = NULL; - result = 1; - Py_DECREF(_u_string); - return result; + Py_DECREF(u); + + return XML_STATUS_OK; } @@ -1752,7 +1748,6 @@ Py_BuildValue("(iii)", info.major, info.minor, info.micro)); } - init_template_buffer(); /* XXX When Expat supports some way of figuring out how it was compiled, this should check and set native_encoding appropriately. @@ -1938,6 +1933,7 @@ capi.SetUserData = XML_SetUserData; capi.SetStartDoctypeDeclHandler = XML_SetStartDoctypeDeclHandler; capi.SetEncoding = XML_SetEncoding; + capi.DefaultUnknownEncodingHandler = PyUnknownEncodingHandler; /* export using capsule */ capi_object = PyCapsule_New(&capi, PyExpat_CAPSULE_NAME, NULL); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 25 16:12:20 2013 From: python-checkins at python.org (lukasz.langa) Date: Sat, 25 May 2013 16:12:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Include_an_example_output_fro?= =?utf-8?q?m_=5Fcompose=5Fmro=28=29?= Message-ID: <3bHmc4073JzQWc@mail.python.org> http://hg.python.org/peps/rev/b68e55e3c815 changeset: 4909:b68e55e3c815 user: ?ukasz Langa date: Sat May 25 16:12:02 2013 +0200 summary: Include an example output from _compose_mro() files: pep-0443.txt | 13 +++++++++++++ 1 files changed, 13 insertions(+), 0 deletions(-) diff --git a/pep-0443.txt b/pep-0443.txt --- a/pep-0443.txt +++ b/pep-0443.txt @@ -190,6 +190,19 @@ mro.insert(index, regcls) return mro +In its most basic form, it returns the MRO for the given type:: + +>>> _compose_mro(dict, []) +[, ] + +When the haystack consists of ABCs that the specified type is a subclass +of, they are inserted in a predictable order:: + +>>> _compose_mro(dict, [Sized, MutableMapping, str, Sequence, Iterable]) +[, , + , , + ] + While this mode of operation is significantly slower, no caching is involved because user code may ``register()`` a new class on an ABC at any time. In such case, it is possible to create a situation with -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat May 25 16:13:00 2013 From: python-checkins at python.org (eli.bendersky) Date: Sat, 25 May 2013 16:13:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Clean-up_dupli?= =?utf-8?q?cated_code_in_tests?= Message-ID: <3bHmcr5rDFzQWc@mail.python.org> http://hg.python.org/cpython/rev/edfde9085cb6 changeset: 83921:edfde9085cb6 branch: 3.3 parent: 83919:f7b47fb30169 user: Eli Bendersky date: Sat May 25 07:12:14 2013 -0700 summary: Clean-up duplicated code in tests files: Lib/test/test_xml_etree.py | 46 -------------------------- 1 files changed, 0 insertions(+), 46 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -736,52 +736,6 @@ self.assertRaises(ValueError, ET.XML, xml('undefined').encode('ascii')) self.assertRaises(LookupError, ET.XML, xml('xxx').encode('ascii')) - def xml(encoding): - return "" % encoding - def bxml(encoding): - return xml(encoding).encode(encoding) - supported_encodings = [ - 'ascii', 'utf-8', 'utf-8-sig', 'utf-16', 'utf-16be', 'utf-16le', - 'iso8859-1', 'iso8859-2', 'iso8859-3', 'iso8859-4', 'iso8859-5', - 'iso8859-6', 'iso8859-7', 'iso8859-8', 'iso8859-9', 'iso8859-10', - 'iso8859-13', 'iso8859-14', 'iso8859-15', 'iso8859-16', - 'cp437', 'cp720', 'cp737', 'cp775', 'cp850', 'cp852', - 'cp855', 'cp856', 'cp857', 'cp858', 'cp860', 'cp861', 'cp862', - 'cp863', 'cp865', 'cp866', 'cp869', 'cp874', 'cp1006', 'cp1250', - 'cp1251', 'cp1252', 'cp1253', 'cp1254', 'cp1255', 'cp1256', - 'cp1257', 'cp1258', - 'mac-cyrillic', 'mac-greek', 'mac-iceland', 'mac-latin2', - 'mac-roman', 'mac-turkish', - 'iso2022-jp', 'iso2022-jp-1', 'iso2022-jp-2', 'iso2022-jp-2004', - 'iso2022-jp-3', 'iso2022-jp-ext', - 'koi8-r', 'koi8-u', - 'hz', 'ptcp154', - ] - for encoding in supported_encodings: - self.assertEqual(ET.tostring(ET.XML(bxml(encoding))), b'') - - unsupported_ascii_compatible_encodings = [ - 'big5', 'big5hkscs', - 'cp932', 'cp949', 'cp950', - 'euc-jp', 'euc-jis-2004', 'euc-jisx0213', 'euc-kr', - 'gb2312', 'gbk', 'gb18030', - 'iso2022-kr', 'johab', - 'shift-jis', 'shift-jis-2004', 'shift-jisx0213', - 'utf-7', - ] - for encoding in unsupported_ascii_compatible_encodings: - self.assertRaises(ValueError, ET.XML, bxml(encoding)) - - unsupported_ascii_incompatible_encodings = [ - 'cp037', 'cp424', 'cp500', 'cp864', 'cp875', 'cp1026', 'cp1140', - 'utf_32', 'utf_32_be', 'utf_32_le', - ] - for encoding in unsupported_ascii_incompatible_encodings: - self.assertRaises(ET.ParseError, ET.XML, bxml(encoding)) - - self.assertRaises(ValueError, ET.XML, xml('undefined').encode('ascii')) - self.assertRaises(LookupError, ET.XML, xml('xxx').encode('ascii')) - def test_methods(self): # Test serialization methods. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 25 16:13:02 2013 From: python-checkins at python.org (eli.bendersky) Date: Sat, 25 May 2013 16:13:02 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Clean-up_duplicated_code_in_tests?= Message-ID: <3bHmct0XqJzRmp@mail.python.org> http://hg.python.org/cpython/rev/5245f0d849c6 changeset: 83922:5245f0d849c6 parent: 83920:47e719b11c46 parent: 83921:edfde9085cb6 user: Eli Bendersky date: Sat May 25 07:12:38 2013 -0700 summary: Clean-up duplicated code in tests files: Lib/test/test_xml_etree.py | 46 -------------------------- 1 files changed, 0 insertions(+), 46 deletions(-) diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -727,52 +727,6 @@ self.assertRaises(ValueError, ET.XML, xml('undefined').encode('ascii')) self.assertRaises(LookupError, ET.XML, xml('xxx').encode('ascii')) - def xml(encoding): - return "" % encoding - def bxml(encoding): - return xml(encoding).encode(encoding) - supported_encodings = [ - 'ascii', 'utf-8', 'utf-8-sig', 'utf-16', 'utf-16be', 'utf-16le', - 'iso8859-1', 'iso8859-2', 'iso8859-3', 'iso8859-4', 'iso8859-5', - 'iso8859-6', 'iso8859-7', 'iso8859-8', 'iso8859-9', 'iso8859-10', - 'iso8859-13', 'iso8859-14', 'iso8859-15', 'iso8859-16', - 'cp437', 'cp720', 'cp737', 'cp775', 'cp850', 'cp852', - 'cp855', 'cp856', 'cp857', 'cp858', 'cp860', 'cp861', 'cp862', - 'cp863', 'cp865', 'cp866', 'cp869', 'cp874', 'cp1006', 'cp1250', - 'cp1251', 'cp1252', 'cp1253', 'cp1254', 'cp1255', 'cp1256', - 'cp1257', 'cp1258', - 'mac-cyrillic', 'mac-greek', 'mac-iceland', 'mac-latin2', - 'mac-roman', 'mac-turkish', - 'iso2022-jp', 'iso2022-jp-1', 'iso2022-jp-2', 'iso2022-jp-2004', - 'iso2022-jp-3', 'iso2022-jp-ext', - 'koi8-r', 'koi8-u', - 'hz', 'ptcp154', - ] - for encoding in supported_encodings: - self.assertEqual(ET.tostring(ET.XML(bxml(encoding))), b'') - - unsupported_ascii_compatible_encodings = [ - 'big5', 'big5hkscs', - 'cp932', 'cp949', 'cp950', - 'euc-jp', 'euc-jis-2004', 'euc-jisx0213', 'euc-kr', - 'gb2312', 'gbk', 'gb18030', - 'iso2022-kr', 'johab', - 'shift-jis', 'shift-jis-2004', 'shift-jisx0213', - 'utf-7', - ] - for encoding in unsupported_ascii_compatible_encodings: - self.assertRaises(ValueError, ET.XML, bxml(encoding)) - - unsupported_ascii_incompatible_encodings = [ - 'cp037', 'cp424', 'cp500', 'cp864', 'cp875', 'cp1026', 'cp1140', - 'utf_32', 'utf_32_be', 'utf_32_le', - ] - for encoding in unsupported_ascii_incompatible_encodings: - self.assertRaises(ET.ParseError, ET.XML, bxml(encoding)) - - self.assertRaises(ValueError, ET.XML, xml('undefined').encode('ascii')) - self.assertRaises(LookupError, ET.XML, xml('xxx').encode('ascii')) - def test_methods(self): # Test serialization methods. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 25 16:21:17 2013 From: python-checkins at python.org (lukasz.langa) Date: Sat, 25 May 2013 16:21:17 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Fix_a_reST_formatting_error?= Message-ID: <3bHmpP54BczScF@mail.python.org> http://hg.python.org/peps/rev/a280be103a40 changeset: 4910:a280be103a40 user: ?ukasz Langa date: Sat May 25 16:21:03 2013 +0200 summary: Fix a reST formatting error files: pep-0443.txt | 13 +++++++------ 1 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pep-0443.txt b/pep-0443.txt --- a/pep-0443.txt +++ b/pep-0443.txt @@ -192,16 +192,17 @@ In its most basic form, it returns the MRO for the given type:: ->>> _compose_mro(dict, []) -[, ] + >>> _compose_mro(dict, []) + [, ] When the haystack consists of ABCs that the specified type is a subclass of, they are inserted in a predictable order:: ->>> _compose_mro(dict, [Sized, MutableMapping, str, Sequence, Iterable]) -[, , - , , - ] + >>> _compose_mro(dict, [Sized, MutableMapping, str, + ... Sequence, Iterable]) + [, , + , , + ] While this mode of operation is significantly slower, no caching is involved because user code may ``register()`` a new class on an ABC at -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat May 25 17:26:46 2013 From: python-checkins at python.org (brett.cannon) Date: Sat, 25 May 2013 17:26:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Various_tweaks?= =?utf-8?q?_to_importlib_docs=2E?= Message-ID: <3bHpFy6pfHz7LkS@mail.python.org> http://hg.python.org/cpython/rev/674005847047 changeset: 83923:674005847047 branch: 3.3 parent: 83921:edfde9085cb6 user: Brett Cannon date: Sat May 25 11:26:11 2013 -0400 summary: Various tweaks to importlib docs. files: Doc/library/importlib.rst | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -238,6 +238,10 @@ The path to where the module data is stored (not set for built-in modules). + - :attr:`__cached__` + The path to where a compiled version of the module is/should be + stored (not set when the attribute would be inappropriate). + - :attr:`__path__` A list of strings specifying the search path within a package. This attribute is not set on modules. @@ -407,7 +411,8 @@ automatically. When writing to the path fails because the path is read-only - (:attr:`errno.EACCES`), do not propagate the exception. + (:attr:`errno.EACCES`/:exc:`PermissionError`), do not propagate the + exception. .. method:: get_code(fullname) @@ -668,8 +673,8 @@ specified by *fullname* on :data:`sys.path` or, if defined, on *path*. For each path entry that is searched, :data:`sys.path_importer_cache` is checked. If a non-false object is - found then it is used as the :term:`finder` to look for the module - being searched for. If no entry is found in + found then it is used as the :term:`path entry finder` to look for the + module being searched for. If no entry is found in :data:`sys.path_importer_cache`, then :data:`sys.path_hooks` is searched for a finder for the path entry and, if found, is stored in :data:`sys.path_importer_cache` along with being queried about the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 25 17:26:48 2013 From: python-checkins at python.org (brett.cannon) Date: Sat, 25 May 2013 17:26:48 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3bHpG01XGLz7Ll2@mail.python.org> http://hg.python.org/cpython/rev/eaa8f957351c changeset: 83924:eaa8f957351c parent: 83922:5245f0d849c6 parent: 83923:674005847047 user: Brett Cannon date: Sat May 25 11:26:36 2013 -0400 summary: merge files: Doc/library/importlib.rst | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -256,6 +256,10 @@ The path to where the module data is stored (not set for built-in modules). + - :attr:`__cached__` + The path to where a compiled version of the module is/should be + stored (not set when the attribute would be inappropriate). + - :attr:`__path__` A list of strings specifying the search path within a package. This attribute is not set on modules. @@ -456,7 +460,8 @@ automatically. When writing to the path fails because the path is read-only - (:attr:`errno.EACCES`), do not propagate the exception. + (:attr:`errno.EACCES`/:exc:`PermissionError`), do not propagate the + exception. .. versionchanged:: 3.4 No longer raises :exc:`NotImplementedError` when called. @@ -595,8 +600,8 @@ specified by *fullname* on :data:`sys.path` or, if defined, on *path*. For each path entry that is searched, :data:`sys.path_importer_cache` is checked. If a non-false object is - found then it is used as the :term:`finder` to look for the module - being searched for. If no entry is found in + found then it is used as the :term:`path entry finder` to look for the + module being searched for. If no entry is found in :data:`sys.path_importer_cache`, then :data:`sys.path_hooks` is searched for a finder for the path entry and, if found, is stored in :data:`sys.path_importer_cache` along with being queried about the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 25 17:29:12 2013 From: python-checkins at python.org (brett.cannon) Date: Sat, 25 May 2013 17:29:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Add_a_missing_?= =?utf-8?q?parenthesis=2E?= Message-ID: <3bHpJm1BfjzRfF@mail.python.org> http://hg.python.org/cpython/rev/b29c513c4fa5 changeset: 83925:b29c513c4fa5 branch: 3.3 parent: 83923:674005847047 user: Brett Cannon date: Sat May 25 11:28:20 2013 -0400 summary: Add a missing parenthesis. files: Doc/library/unittest.mock.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -468,7 +468,7 @@ mock and unless the function returns the :data:`DEFAULT` singleton the call to the mock will then return whatever the function returns. If the function returns :data:`DEFAULT` then the mock will return its normal - value (from the :attr:`return_value`. + value (from the :attr:`return_value`). An example of a mock that raises an exception (to test exception handling of an API): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 25 17:29:13 2013 From: python-checkins at python.org (brett.cannon) Date: Sat, 25 May 2013 17:29:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3bHpJn4FSjz7LjM@mail.python.org> http://hg.python.org/cpython/rev/fbd1b092f937 changeset: 83926:fbd1b092f937 parent: 83924:eaa8f957351c parent: 83925:b29c513c4fa5 user: Brett Cannon date: Sat May 25 11:29:03 2013 -0400 summary: merge files: Doc/library/unittest.mock.rst | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -467,7 +467,7 @@ mock and unless the function returns the :data:`DEFAULT` singleton the call to the mock will then return whatever the function returns. If the function returns :data:`DEFAULT` then the mock will return its normal - value (from the :attr:`return_value`. + value (from the :attr:`return_value`). An example of a mock that raises an exception (to test exception handling of an API): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 25 17:33:21 2013 From: python-checkins at python.org (brett.cannon) Date: Sat, 25 May 2013 17:33:21 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogTWVudGlvbiBfX2Nh?= =?utf-8?q?ched=5F=5F_in_the_import_ref=2E?= Message-ID: <3bHpPY1JPqz7Llg@mail.python.org> http://hg.python.org/cpython/rev/75707db4e2e9 changeset: 83927:75707db4e2e9 branch: 3.3 parent: 83925:b29c513c4fa5 user: Brett Cannon date: Sat May 25 11:32:50 2013 -0400 summary: Mention __cached__ in the import ref. files: Doc/reference/import.rst | 6 +++++- 1 files changed, 5 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 @@ -353,7 +353,11 @@ * The loader may set the ``__file__`` attribute of the module. If set, this attribute's value must be a string. The loader may opt to leave ``__file__`` unset if it has no semantic meaning (e.g. a module loaded from - a database). + a database). If ``__file__`` is set, it may also be appropriate to set the + ``__cached__`` attribute which is the path to any compiled version of the + code (e.g. byte-compiled file). The file does not need to exist to set this + attribute; the path can simply point to whether the compiled file would + exist (see :pep:`3147`). * The loader may set the ``__name__`` attribute of the module. While not required, setting this attribute is highly recommended so that the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 25 17:33:22 2013 From: python-checkins at python.org (brett.cannon) Date: Sat, 25 May 2013 17:33:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3bHpPZ358Kz7LkX@mail.python.org> http://hg.python.org/cpython/rev/37794a002517 changeset: 83928:37794a002517 parent: 83926:fbd1b092f937 parent: 83927:75707db4e2e9 user: Brett Cannon date: Sat May 25 11:33:13 2013 -0400 summary: merge files: Doc/reference/import.rst | 6 +++++- 1 files changed, 5 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 @@ -353,7 +353,11 @@ * The loader may set the ``__file__`` attribute of the module. If set, this attribute's value must be a string. The loader may opt to leave ``__file__`` unset if it has no semantic meaning (e.g. a module loaded from - a database). + a database). If ``__file__`` is set, it may also be appropriate to set the + ``__cached__`` attribute which is the path to any compiled version of the + code (e.g. byte-compiled file). The file does not need to exist to set this + attribute; the path can simply point to whether the compiled file would + exist (see :pep:`3147`). * The loader may set the ``__name__`` attribute of the module. While not required, setting this attribute is highly recommended so that the -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 25 18:42:15 2013 From: python-checkins at python.org (lukasz.langa) Date: Sat, 25 May 2013 18:42:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fix_=2316832_-_expose_cach?= =?utf-8?q?e_validity_checking_support_in_ABCMeta?= Message-ID: <3bHqx33njMzPZ2@mail.python.org> http://hg.python.org/cpython/rev/5b17d5ca2ff1 changeset: 83929:5b17d5ca2ff1 user: ?ukasz Langa date: Sat May 25 18:41:50 2013 +0200 summary: Fix #16832 - expose cache validity checking support in ABCMeta files: Doc/library/abc.rst | 17 +++++++++++++++++ Lib/abc.py | 14 ++++++++++++++ Lib/test/test_abc.py | 3 +++ 3 files changed, 34 insertions(+), 0 deletions(-) diff --git a/Doc/library/abc.rst b/Doc/library/abc.rst --- a/Doc/library/abc.rst +++ b/Doc/library/abc.rst @@ -58,6 +58,10 @@ .. versionchanged:: 3.3 Returns the registered subclass, to allow usage as a class decorator. + .. versionchanged:: 3.4 + To detect calls to :meth:`register`, you can use the + :func:`get_cache_token` function. + You can also override this method in an abstract base class: .. method:: __subclasshook__(subclass) @@ -308,6 +312,19 @@ :func:`abstractmethod`, making this decorator redundant. +The :mod:`abc` module also provides the following functions: + +.. function:: get_cache_token() + + Returns the current abstract base class cache token. + + The token is an opaque integer identifying the current version of the + abstract base class cache for virtual subclasses. This number changes + with every call to :meth:`ABCMeta.register` on any ABC. + + .. versionadded:: 3.4 + + .. rubric:: Footnotes .. [#] C++ programmers should note that Python's virtual base class diff --git a/Lib/abc.py b/Lib/abc.py --- a/Lib/abc.py +++ b/Lib/abc.py @@ -5,6 +5,7 @@ from _weakrefset import WeakSet + def abstractmethod(funcobj): """A decorator indicating abstract methods. @@ -124,6 +125,8 @@ # A global counter that is incremented each time a class is # registered as a virtual subclass of anything. It forces the # negative cache to be cleared before its next use. + # Note: this counter is private. Use `abc.get_cache_token()` for + # external code. _abc_invalidation_counter = 0 def __new__(mcls, name, bases, namespace): @@ -227,8 +230,19 @@ cls._abc_negative_cache.add(subclass) return False + class ABC(metaclass=ABCMeta): """Helper class that provides a standard way to create an ABC using inheritance. """ pass + + +def get_cache_token(): + """Returns the current ABC cache token. + + The token is an opaque integer identifying the current version of + the ABC cache for virtual subclasses. This number changes with + every call to ``register()`` on any ABC. + """ + return ABCMeta._abc_invalidation_counter diff --git a/Lib/test/test_abc.py b/Lib/test/test_abc.py --- a/Lib/test/test_abc.py +++ b/Lib/test/test_abc.py @@ -329,7 +329,10 @@ b = B() self.assertFalse(isinstance(b, A)) self.assertFalse(isinstance(b, (A,))) + token_old = abc.get_cache_token() A.register(B) + token_new = abc.get_cache_token() + self.assertNotEqual(token_old, token_new) self.assertTrue(isinstance(b, A)) self.assertTrue(isinstance(b, (A,))) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 25 18:48:36 2013 From: python-checkins at python.org (lukasz.langa) Date: Sat, 25 May 2013 18:48:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Mention_issue_=2316832_in_?= =?utf-8?q?Misc/NEWS?= Message-ID: <3bHr4N6DhJzPdY@mail.python.org> http://hg.python.org/cpython/rev/d9828c438889 changeset: 83930:d9828c438889 user: ?ukasz Langa date: Sat May 25 18:48:16 2013 +0200 summary: Mention issue #16832 in Misc/NEWS files: Misc/NEWS | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1325,7 +1325,10 @@ - ctypes.call_commethod was removed, since its only usage was in the defunct samples directory. -- Issue #16692: Added TLSv1.1 and TLSv1.2 support for the ssl modules. +- Issue #16692: Added TLSv1.1 and TLSv1.2 support for the ssl modules. + +- Issue #16832: add abc.get_cache_token() to expose cache validity checking + support in ABCMeta. IDLE ---- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 25 20:06:04 2013 From: python-checkins at python.org (lukasz.langa) Date: Sat, 25 May 2013 20:06:04 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Document_the_=2Eregistry_attr?= =?utf-8?q?ibute?= Message-ID: <3bHsnm47LszQ6T@mail.python.org> http://hg.python.org/peps/rev/2813a160b568 changeset: 4911:2813a160b568 user: ?ukasz Langa date: Sat May 25 20:05:45 2013 +0200 summary: Document the .registry attribute files: pep-0443.txt | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-) diff --git a/pep-0443.txt b/pep-0443.txt --- a/pep-0443.txt +++ b/pep-0443.txt @@ -137,6 +137,18 @@ >>> fun.dispatch(dict) +To access all registered overloads, use the read-only ``registry`` +attribute:: + + >>> fun.registry.keys() + dict_keys([, , , + , , + ]) + >>> fun.registry[float] + + >>> fun.registry[object] + + The proposed API is intentionally limited and opinionated, as to ensure it is easy to explain and use, as well as to maintain consistency with existing members in the ``functools`` module. -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat May 25 22:06:30 2013 From: python-checkins at python.org (lukasz.langa) Date: Sat, 25 May 2013 22:06:30 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Document_that_dispatch_cachin?= =?utf-8?q?g_is_used?= Message-ID: <3bHwSk4zhYzQP0@mail.python.org> http://hg.python.org/peps/rev/90aff226351c changeset: 4912:90aff226351c user: ?ukasz Langa date: Sat May 25 22:06:02 2013 +0200 summary: Document that dispatch caching is used files: pep-0443.txt | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pep-0443.txt b/pep-0443.txt --- a/pep-0443.txt +++ b/pep-0443.txt @@ -216,10 +216,11 @@ , , ] -While this mode of operation is significantly slower, no caching is -involved because user code may ``register()`` a new class on an ABC at -any time. In such case, it is possible to create a situation with -ambiguous dispatch, for instance:: +While this mode of operation is significantly slower, all dispatch +decisions are cached. The cache is invalidated on registering new +overloads on the generic function or when user code calls ``register()`` +on an ABC to register a new virtual subclass. In the latter case, it is +possible to create a situation with ambiguous dispatch, for instance:: >>> from collections import Iterable, Container >>> class P: -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat May 25 22:49:33 2013 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 25 May 2013 22:49:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_I_was_appointed_delegate=2E?= Message-ID: <3bHxQP3y3KzPsK@mail.python.org> http://hg.python.org/peps/rev/d28b9b6add80 changeset: 4913:d28b9b6add80 user: Benjamin Peterson date: Sat May 25 13:46:47 2013 -0700 summary: I was appointed delegate. files: pep-0442.txt | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/pep-0442.txt b/pep-0442.txt --- a/pep-0442.txt +++ b/pep-0442.txt @@ -3,6 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Antoine Pitrou +BDFL-Delegate: Benjamin Peterson Status: Draft Type: Standards Track Content-Type: text/x-rst -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Sat May 25 23:48:24 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 25 May 2013 23:48:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MDYz?= =?utf-8?q?=3A_fix_some_struct_specifications_in_the_tests_for_sys=2Egetsi?= =?utf-8?b?emVvZigpLg==?= Message-ID: <3bHykJ1wTmzPtX@mail.python.org> http://hg.python.org/cpython/rev/c20b701c66fc changeset: 83931:c20b701c66fc branch: 3.3 parent: 83927:75707db4e2e9 user: Antoine Pitrou date: Sat May 25 23:47:29 2013 +0200 summary: Issue #18063: fix some struct specifications in the tests for sys.getsizeof(). files: Lib/test/test_sys.py | 10 +++++----- 1 files changed, 5 insertions(+), 5 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 @@ -703,13 +703,13 @@ class C(object): pass check(C.__dict__, size('P')) # BaseException - check(BaseException(), size('5Pi')) + check(BaseException(), size('5Pb')) # UnicodeEncodeError - check(UnicodeEncodeError("", "", 0, 0, ""), size('5Pi 2P2nP')) + check(UnicodeEncodeError("", "", 0, 0, ""), size('5Pb 2P2nP')) # UnicodeDecodeError - check(UnicodeDecodeError("", b"", 0, 0, ""), size('5Pi 2P2nP')) + check(UnicodeDecodeError("", b"", 0, 0, ""), size('5Pb 2P2nP')) # UnicodeTranslateError - check(UnicodeTranslateError("", 0, 1, ""), size('5Pi 2P2nP')) + check(UnicodeTranslateError("", 0, 1, ""), size('5Pb 2P2nP')) # ellipses check(Ellipsis, size('')) # EncodingMap @@ -851,7 +851,7 @@ samples = ['1'*100, '\xff'*50, '\u0100'*40, '\uffff'*100, '\U00010000'*30, '\U0010ffff'*100] - asciifields = "nniP" + asciifields = "nnbP" compactfields = asciifields + "nPn" unicodefields = compactfields + "P" for s in samples: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Sat May 25 23:48:25 2013 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 25 May 2013 23:48:25 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318063=3A_fix_some_struct_specifications_in_the_?= =?utf-8?q?tests_for_sys=2Egetsizeof=28=29=2E?= Message-ID: <3bHykK3jB6zQFR@mail.python.org> http://hg.python.org/cpython/rev/5c4ca109af1c changeset: 83932:5c4ca109af1c parent: 83930:d9828c438889 parent: 83931:c20b701c66fc user: Antoine Pitrou date: Sat May 25 23:48:15 2013 +0200 summary: Issue #18063: fix some struct specifications in the tests for sys.getsizeof(). files: Lib/test/test_sys.py | 10 +++++----- 1 files changed, 5 insertions(+), 5 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 @@ -735,13 +735,13 @@ class C(object): pass check(C.__dict__, size('P')) # BaseException - check(BaseException(), size('5Pi')) + check(BaseException(), size('5Pb')) # UnicodeEncodeError - check(UnicodeEncodeError("", "", 0, 0, ""), size('5Pi 2P2nP')) + check(UnicodeEncodeError("", "", 0, 0, ""), size('5Pb 2P2nP')) # UnicodeDecodeError - check(UnicodeDecodeError("", b"", 0, 0, ""), size('5Pi 2P2nP')) + check(UnicodeDecodeError("", b"", 0, 0, ""), size('5Pb 2P2nP')) # UnicodeTranslateError - check(UnicodeTranslateError("", 0, 1, ""), size('5Pi 2P2nP')) + check(UnicodeTranslateError("", 0, 1, ""), size('5Pb 2P2nP')) # ellipses check(Ellipsis, size('')) # EncodingMap @@ -883,7 +883,7 @@ samples = ['1'*100, '\xff'*50, '\u0100'*40, '\uffff'*100, '\U00010000'*30, '\U0010ffff'*100] - asciifields = "nniP" + asciifields = "nnbP" compactfields = asciifields + "nPn" unicodefields = compactfields + "P" for s in samples: -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Sun May 26 05:48:27 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 26 May 2013 05:48:27 +0200 Subject: [Python-checkins] Daily reference leaks (5c4ca109af1c): sum=0 Message-ID: results for 5c4ca109af1c on branch "default" -------------------------------------------- test_unittest leaked [-1, 2, 0] memory blocks, sum=1 test_concurrent_futures leaked [0, -2, 1] memory blocks, sum=-1 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflog2RuKdo', '-x'] From python-checkins at python.org Sun May 26 22:45:20 2013 From: python-checkins at python.org (brett.cannon) Date: Sun, 26 May 2013 22:45:20 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Move_importlib=2Eabc=2ESou?= =?utf-8?q?rceLoader=2Esource=5Fto=5Fcode=28=29_to_InspectLoader=2E?= Message-ID: <3bJYH46Tc2zPTd@mail.python.org> http://hg.python.org/cpython/rev/0a7d237c0919 changeset: 83933:0a7d237c0919 user: Brett Cannon date: Sun May 26 16:45:10 2013 -0400 summary: Move importlib.abc.SourceLoader.source_to_code() to InspectLoader. While the previous location was fine, it makes more sense to have the method higher up in the inheritance chain, especially at a point where get_source() is defined which is the earliest source_to_code() could programmatically be used in the inheritance tree in importlib.abc. files: Doc/library/importlib.rst | 22 +++--- Lib/importlib/abc.py | 7 ++ Lib/test/test_importlib/test_abc.py | 50 +++++++++++++++- Misc/NEWS | 2 +- 4 files changed, 66 insertions(+), 15 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -349,6 +349,17 @@ .. versionchanged:: 3.4 Raises :exc:`ImportError` instead of :exc:`NotImplementedError`. + .. method:: source_to_code(data, path='') + + Create a code object from Python source. + + The *data* argument can be whatever the :func:`compile` function + supports (i.e. string or bytes). The *path* argument should be + the "path" to where the source code originated from, which can be an + abstract concept (e.g. location in a zip file). + + .. versionadded:: 3.4 + .. class:: ExecutionLoader @@ -466,17 +477,6 @@ .. versionchanged:: 3.4 No longer raises :exc:`NotImplementedError` when called. - .. method:: source_to_code(data, path) - - Create a code object from Python source. - - The *data* argument can be whatever the :func:`compile` function - supports (i.e. string or bytes). The *path* argument should be - the "path" to where the source code originated from, which can be an - abstract concept (e.g. location in a zip file). - - .. versionadded:: 3.4 - .. method:: get_code(fullname) Concrete implementation of :meth:`InspectLoader.get_code`. diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py --- a/Lib/importlib/abc.py +++ b/Lib/importlib/abc.py @@ -165,6 +165,13 @@ """ raise ImportError + def source_to_code(self, data, path=''): + """Compile 'data' into a code object. + + The 'data' argument can be anything that compile() can handle. The'path' + argument should be where the data was retrieved (when applicable).""" + return compile(data, path, 'exec', dont_inherit=True) + _register(InspectLoader, machinery.BuiltinImporter, machinery.FrozenImporter, machinery.ExtensionFileLoader) diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py --- a/Lib/test/test_importlib/test_abc.py +++ b/Lib/test/test_importlib/test_abc.py @@ -12,7 +12,7 @@ from . import util -##### Inheritance +##### Inheritance ############################################################## class InheritanceTests: """Test that the specified class is a subclass/superclass of the expected @@ -81,7 +81,7 @@ subclasses = [machinery.SourceFileLoader] -##### Default semantics +##### Default return values #################################################### class MetaPathFinderSubclass(abc.MetaPathFinder): def find_module(self, fullname, path): @@ -205,7 +205,50 @@ self.ins.get_filename('blah') -##### SourceLoader +##### InspectLoader concrete methods ########################################### +class InspectLoaderConcreteMethodTests(unittest.TestCase): + + def source_to_module(self, data, path=None): + """Help with source_to_code() tests.""" + module = imp.new_module('blah') + loader = InspectLoaderSubclass() + if path is None: + code = loader.source_to_code(data) + else: + code = loader.source_to_code(data, path) + exec(code, module.__dict__) + return module + + def test_source_to_code_source(self): + # Since compile() can handle strings, so should source_to_code(). + source = 'attr = 42' + module = self.source_to_module(source) + self.assertTrue(hasattr(module, 'attr')) + self.assertEqual(module.attr, 42) + + def test_source_to_code_bytes(self): + # Since compile() can handle bytes, so should source_to_code(). + source = b'attr = 42' + module = self.source_to_module(source) + self.assertTrue(hasattr(module, 'attr')) + self.assertEqual(module.attr, 42) + + def test_source_to_code_path(self): + # Specifying a path should set it for the code object. + path = 'path/to/somewhere' + loader = InspectLoaderSubclass() + code = loader.source_to_code('', path) + self.assertEqual(code.co_filename, path) + + def test_source_to_code_no_path(self): + # Not setting a path should still work and be set to since that + # is a pre-existing practice as a default to compile(). + loader = InspectLoaderSubclass() + code = loader.source_to_code('') + self.assertEqual(code.co_filename, '') + + +##### SourceLoader concrete methods ############################################ class SourceOnlyLoaderMock(abc.SourceLoader): # Globals that should be defined for all modules. @@ -498,5 +541,6 @@ self.assertEqual(mock.get_source(name), expect) + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1111,7 +1111,7 @@ - Issue #16522: added FAIL_FAST flag to doctest. -- Issue #15627: Add the importlib.abc.SourceLoader.source_to_code() method. +- Issue #15627: Add the importlib.abc.InspectLoader.source_to_code() method. - Issue #16408: Fix file descriptors not being closed in error conditions in the zipfile module. Patch by Serhiy Storchaka. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 27 03:57:41 2013 From: python-checkins at python.org (ned.deily) Date: Mon, 27 May 2013 03:57:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Fix_typo_in_em?= =?utf-8?q?bedding_doc_and_update_examples_to_3=2E3=2E?= Message-ID: <3bJhCT62p5z7Lk1@mail.python.org> http://hg.python.org/cpython/rev/e57c8a90b2df changeset: 83934:e57c8a90b2df branch: 3.3 parent: 83931:c20b701c66fc user: Ned Deily date: Sun May 26 18:53:39 2013 -0700 summary: Fix typo in embedding doc and update examples to 3.3. files: Doc/extending/embedding.rst | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/extending/embedding.rst b/Doc/extending/embedding.rst --- a/Doc/extending/embedding.rst +++ b/Doc/extending/embedding.rst @@ -285,14 +285,14 @@ * ``pythonX.Y-config --cflags`` will give you the recommended flags when compiling:: - $ /opt/bin/python3.2-config --cflags - -I/opt/include/python3.2m -I/opt/include/python3.2m -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes + $ /opt/bin/python3.3-config --cflags + -I/opt/include/python3.3m -I/opt/include/python3.3m -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes * ``pythonX.Y-config --ldflags`` will give you the recommended flags when linking:: - $ /opt/bin/python3.2-config --ldflags - -I/opt/lib/python3.2/config-3.2m -lpthread -ldl -lutil -lm -lpython3.2m -Xlinker -export-dynamic + $ /opt/bin/python3.3-config --ldflags + -L/opt/lib/python3.3/config-3.3m -lpthread -ldl -lutil -lm -lpython3.3m -Xlinker -export-dynamic .. note:: To avoid confusion between several Python installations (and especially -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 27 03:57:43 2013 From: python-checkins at python.org (ned.deily) Date: Mon, 27 May 2013 03:57:43 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Fix_typo_in_embedding_doc_and_update_examples_to_3=2E4?= =?utf-8?q?=2E?= Message-ID: <3bJhCW0jGQz7LkD@mail.python.org> http://hg.python.org/cpython/rev/39e0be9106c1 changeset: 83935:39e0be9106c1 parent: 83933:0a7d237c0919 parent: 83934:e57c8a90b2df user: Ned Deily date: Sun May 26 18:57:00 2013 -0700 summary: Fix typo in embedding doc and update examples to 3.4. files: Doc/extending/embedding.rst | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/extending/embedding.rst b/Doc/extending/embedding.rst --- a/Doc/extending/embedding.rst +++ b/Doc/extending/embedding.rst @@ -285,14 +285,14 @@ * ``pythonX.Y-config --cflags`` will give you the recommended flags when compiling:: - $ /opt/bin/python3.2-config --cflags - -I/opt/include/python3.2m -I/opt/include/python3.2m -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes + $ /opt/bin/python3.4-config --cflags + -I/opt/include/python3.4m -I/opt/include/python3.4m -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes * ``pythonX.Y-config --ldflags`` will give you the recommended flags when linking:: - $ /opt/bin/python3.2-config --ldflags - -I/opt/lib/python3.2/config-3.2m -lpthread -ldl -lutil -lm -lpython3.2m -Xlinker -export-dynamic + $ /opt/bin/python3.4-config --ldflags + -L/opt/lib/python3.4/config-3.4m -lpthread -ldl -lutil -lm -lpython3.4m -Xlinker -export-dynamic .. note:: To avoid confusion between several Python installations (and especially -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Mon May 27 05:47:50 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 27 May 2013 05:47:50 +0200 Subject: [Python-checkins] Daily reference leaks (0a7d237c0919): sum=2 Message-ID: results for 0a7d237c0919 on branch "default" -------------------------------------------- test_concurrent_futures leaked [2, 1, -1] memory blocks, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogwTe9BY', '-x'] From python-checkins at python.org Mon May 27 13:20:34 2013 From: python-checkins at python.org (nick.coghlan) Date: Mon, 27 May 2013 13:20:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Publish_the_JSON-based_metada?= =?utf-8?q?ta_2=2E0_spec?= Message-ID: <3bJwhy01Bcz7LkD@mail.python.org> http://hg.python.org/peps/rev/6b4a11ae1c10 changeset: 4914:6b4a11ae1c10 user: Nick Coghlan date: Mon May 27 21:20:13 2013 +1000 summary: Publish the JSON-based metadata 2.0 spec files: pep-0426.txt | 3316 ++++++++++++++++++++----------------- pep-0440.txt | 995 +++++----- 2 files changed, 2304 insertions(+), 2007 deletions(-) diff --git a/pep-0426.txt b/pep-0426.txt --- a/pep-0426.txt +++ b/pep-0426.txt @@ -2,9 +2,9 @@ Title: Metadata for Python Software Packages 2.0 Version: $Revision$ Last-Modified: $Date$ -Author: Daniel Holth , - Donald Stufft , - Nick Coghlan +Author: Nick Coghlan , + Daniel Holth , + Donald Stufft BDFL-Delegate: Nick Coghlan Discussions-To: Distutils SIG Status: Draft @@ -12,15 +12,16 @@ Content-Type: text/x-rst Requires: 440 Created: 30 Aug 2012 -Post-History: 14 Nov 2012, 5 Feb 2013, 7 Feb 2013, 9 Feb 2013 +Post-History: 14 Nov 2012, 5 Feb 2013, 7 Feb 2013, 9 Feb 2013, 27-May-2013 Replaces: 345 Abstract ======== -This PEP describes a mechanism for adding metadata to Python distributions. -It includes specifics of the field names, and their semantics and +This PEP describes a mechanism for publishing and exchanging metadata +related to Python distributions. It includes specifics of the field names, +and their semantics and usage. This document specifies version 2.0 of the metadata format. @@ -28,89 +29,351 @@ Version 1.1 is specified in PEP 314. Version 1.2 is specified in PEP 345. -Version 2.0 of the metadata format adds fields designed to make -third-party packaging of Python Software easier and defines a formal -extension mechanism. It also adds support for optional features of -distributions and allows the description to be placed into a payload -section. Finally, this version addresses several issues with the -previous iteration of the standard version identification scheme. +Version 2.0 of the metadata format migrates from a custom key-value format +to a JSON-compatible in-memory representation. + +This version also adds fields designed to make third-party packaging of +Python software easier, defines a formal extension mechanism, and adds +support for optional dependencies. Finally, this version addresses +several issues with the previous iteration of the standard version +identification scheme. .. note:: - Portions of this PEP are in the process of being broken out into a - separate PEP (PEP 440). Old versions of much of that material currently - still exists in this PEP - the duplication will be eliminated in the - next major update. + "I" in this doc refers to Nick Coghlan. Daniel and Donald either wrote or + contributed to earlier versions, and have been providing feedback as this + initial draft of the JSON-based rewrite has taken shape. + + Metadata 2.0 represents a major upgrade to the Python packaging ecosystem, + and attempts to incorporate experience gained over the 15 years(!) since + distutils was first added to the standard library. Some of that is just + incorporating existing practices from setuptools/pip/etc, some of it is + copying from other distribution systems (like Linux distros or other + development language communities) and some of it is attempting to solve + problems which haven't yet been well solved by anyone (like supporting + clean conversion of Python source packages to distro policy compliant + source packages for at least Debian and Fedora, and perhaps other + platform specific distribution systems). + + There will eventually be a suite of PEPs covering various aspects of + the metadata 2.0 format and related systems: + + * this PEP, covering the core metadata format + * PEP 440, covering the versioning identification and selection scheme + * a new PEP to define v2.0 of the sdist format + * an updated wheel PEP (v1.1) to add pymeta.json + * an updated installation database PEP both for pymeta.json and to add + a linking scheme to better support runtime selection of dependencies, + as well as recording which extras are currently available + * a new static config PEP to standardise metadata generation and + creation of sdists + * PEP 439, covering a bootstrapping mechanism for ``pip`` + * a distutils upgrade PEP, adding metadata v2.0 and wheel support. + + It's going to take a while to work through all of these and make them + a reality. The main change from our last attempt at this is that we're + trying to design the different pieces so we can implement them + independently of each other, without requiring users to switch to + a whole new tool chain (although they may have to upgrade their existing + ones to start enjoying the benefits in their own work). + + Many of the inline notes in this version of the PEP are there to aid + reviewers that are familiar with the old metadata standards. Before this + version is finalised, most of that content will be moved down to the + "rationale" section at the end of the document, as it would otherwise be + an irrelevant distraction for future readers. + + +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. + +"Distributions" are deployable software components published through an index +server or otherwise made available for installation. + +"Versions" are uniquely identified snapshots of a distribution. + +"Distribution archives" are the packaged files which are used to publish +and distribute the software. + +"Source archives" require build tools to be available on the target +system. + +"Binary archives" only require that prebuilt files be moved to the correct +location on the target system. As Python is a dynamically bound +cross-platform language, many "binary" archives will contain only pure +Python source code. + +"Build tools" are automated tools intended to run on development systems, +producing source and binary distribution archives. Build tools may also be +invoked by installation tools in order to install software distributed as +source archives rather than prebuilt binary archives. + +"Index servers" are active distribution registries which publish version and +dependency metadata and place constraints on the permitted metadata. + +"Publication tools" are automated tools intended to run on development +systems and upload source and binary distribution archives to index servers. + +"Installation tools" are automated tools intended to run on production +systems, consuming source and binary distribution archives from an index +server or other designated location and deploying them to the target system. + +"Automated tools" is a collective term covering build tools, index servers, +publication tools, installation tools and any other software that produces +or consumes distribution version and dependency metadata. + +"Projects" refers to the developers that manage the creation of a particular +distribution. + +"Legacy metadata" refers to earlier versions of this metadata specification, +along with the supporting metadata file formats defined by the +``setuptools`` project. + + +Development and distribution activities +======================================= + +Making effective use of a common metadata format requires a common +understanding of the most complex development and distribution model +the format is intended to support. The metadata format described in this +PEP is based on the following activities: + +* Development: during development, a user is operating from a + source checkout (or equivalent) for the current project. Dependencies must + be available in order to build, test and create a source archive of the + distribution. + + .. note:: + As a generated file, the full distribution metadata often won't be + available in a raw source checkout or tarball. In such cases, the + relevant distribution metadata is generally obtained from another + location, such as the last published release, or by generating it + based on a command given in a standard input file. This spec + deliberately avoids handling that scenario, instead falling back on + the existing ``setup.py`` functionality. + +* Build: the build step is the process of turning a source archive into a + binary archive. Dependencies must be available in order to build and + create a binary archive of the distribution (including any documentation + that is installed on target systems). + +* Deployment: the deployment phase consists of two subphases: + + * Installation: the installation phase involves getting the distribution + and all of its runtime dependencies onto the target system. In this + phase, the distribution may already be on the system (when upgrading or + reinstalling) or else it may be a completely new installation. + + * Usage: the usage phase, also referred to as "runtime", is normal usage + of the distribution after it has been installed on the target system. + +The metadata format described in this PEP is designed to enable the +following: + +* It should be practical to have separate development systems, build systems + and deployment systems. +* It should be practical to install dependencies needed specifically to + build source archives only on development systems. +* It should be practical to install dependencies needed specifically to + build the software only on development and build systems, as well as + optionally on deployment systems if installation from source archives + is needed. +* It should be practical to install dependencies needed to run the + distribution only on development and deployment systems. +* It should be practical to install the dependencies needed to run a + distribution's test suite only on development systems, as well as + optionally on deployment systems. +* It should be practical for repackagers to separate out the build + dependencies needed to build the application itself from those required + to build its documentation (as the documentation often doesn't need to + be rebuilt when porting an application to a different platform). + +.. note:: + + This "most complex supported scenario" is almost *exactly* what has to + happen to get an upstream Python package into a Linux distribution, and + is why the current crop of automatic Python metadata -> Linux distro + metadata converters have some serious issues, at least from the point of + view of complying with distro packaging policies: the information + they need to comply with those policies isn't available from the + upstream projects, and all current formats for publishing it are + distro specific. This means either upstreams have to maintain metadata + for multiple distributions (which rarely happens) or else repackagers + have to do a lot of work manually in order to separate out these + dependencies in a way that complies with those policies. + + One thing this PEP aims to do is define a metadata format that at least + has the *potential* to provide the info repackagers need, thus allowing + upstream Python projects and Linux distro repackagers to collaborate more + effectively (and, ideally, make it possible to reliably automate + the process of converting upstream Python distributions into policy + compliant distro packages). + + Some items in this section (and the contents of this note) will likely + end up moving down to the "Rationale for changes from PEP 345" section. + + +Metadata format +=============== + +The format defined in this PEP is an in-memory representation of Python +distribution metadata as a string-keyed dictionary. Permitted values for +individual entries are strings, lists of strings, and additional +nested string-keyed dictionaries. + +Except where otherwise noted, dictionary keys in distribution metadata MUST +be valid Python identifiers in order to support attribute based metadata +access APIs. + +The individual field descriptions show examples of the key name and value +as they would be serialised as part of a JSON mapping. + +The fields identified as core metadata are required. Automated tools MUST +NOT accept distributions with missing core metadata as valid Python +distributions. + +All other fields are optional. Automated tools MUST operate correctly +if a distribution does not provide them, except for those operations +which specifically require the omitted fields. + +Automated tools MUST NOT insert dummy data for missing fields. If a valid +value is not provided for a required field then the metadata and the +associated distribution MUST be rejected as invalid. If a valid value +is not provided for an optional field, that field MUST be omitted entirely. +Automated tools MAY automatically derive valid values from other +information sources (such as a version control system). Metadata files -============== - -The syntax defined in this PEP is for use with Python distribution -metadata files. The file format is a simple UTF-8 encoded Key: value -format with case-insensitive keys and no maximum line length, optionally -followed by a blank line and a payload containing a description of the -distribution. - -This format is parseable by the ``email`` module with an appropriate -``email.policy.Policy()`` (see `Appendix A`_). When ``metadata`` is a -Unicode string, ```email.parser.Parser().parsestr(metadata)`` is a -serviceable parser. +-------------- + +The information defined in this PEP is serialised to ``pymeta.json`` +files for some use cases. As indicated by the extension, these +are JSON-encoded files. Each file consists of a single serialised mapping, +with fields as described in this PEP. There are three standard locations for these metadata files: -* the ``PKG-INFO`` file included in the base directory of Python - source distribution archives (as created by the distutils ``sdist`` - command) -* the ``{distribution}-{version}.dist-info/METADATA`` file in a ``wheel`` - binary distribution archive (as described in PEP 425, or a later version - of that specification) -* the ``{distribution}-{version}.dist-info/METADATA`` files in a local - Python installation database (as described in PEP 376, or a later version - of that specification) +* as a ``{distribution}-{version}.dist-info/pymeta.json`` file in an + ``sdist`` source distribution archive +* as a ``{distribution}-{version}.dist-info/pymeta.json`` file in a ``wheel`` + binary distribution archive +* as a ``{distribution}-{version}.dist-info/pymeta.json`` file in a local + Python installation database + +.. note:: + + These locations are to be confirmed, since they depend on the definition + of sdist 2.0 and the revised installation database standard. There will + also be a wheel 1.1 format update after this PEP is approved that + mandates 2.0+ metadata. Other tools involved in Python distribution may also use this format. - -Encoding -======== - -Metadata 2.0 files are UTF-8 with the restriction that keys must be -ASCII. Parser implementations should be aware that older versions of -the Metadata specification do not specify an encoding. - - -Metadata header fields -======================= - -This section specifies the names and semantics of each of the -supported fields in the metadata header. - -In a single Metadata 2.0 file, fields marked with "(optional)" may occur -0 or 1 times. Fields marked with "(multiple use)" may be specified -0, 1 or more times. Only "Metadata-Version", "Name", "Version", and -"Summary" must appear exactly once. - -The fields may appear in any order within the header section of the file. - - -Metadata-Version +It is expected that these metadata files will be generated by build tools +based on other input formats (such as ``setup.py``) rather than being +edited by hand. + +.. note:: + + It may be appropriate to add a "./setup.py dist_info" command to + setuptools to allow just the sdist metadata files to be generated + without having to build the full sdist archive. This would be + similar to the existing "./setup.py egg_info" command in setuptools, + which would continue to emit the legacy metadata format. + +For backwards compatibility with older installation tools, metadata 2.0 +files MAY be distributed alongside legacy metadata. + +Index servers MAY allow distributions to be uploaded and installation tools +MAY allow distributions to be installed with only legacy metadata. + + +Essential dependency resolution metadata +---------------------------------------- + +For dependency resolution purposes, it is useful to have a minimal subset +of the metadata that contains only those fields needed to identify +distributions and resolve dependencies between them. + +The essential dependency resolution metadata consists of the following +fields: + +* ``metadata_version`` +* ``name`` +* ``version`` +* ``build_label`` +* ``version_url`` +* ``extras`` +* ``requires`` +* ``may-require`` +* ``build-requires`` +* ``build-may-require`` +* ``dev-requires`` +* ``dev-may-require`` +* ``provides`` +* ``obsoleted_by`` +* ``supports_environments`` + +When serialised to a file, the name used for this metadata set SHOULD +be ``pymeta-minimal.json``. + +Abbreviated metadata +-------------------- + +Some metadata fields have the potential to contain a lot of information +that will rarely be referenced, greatly increasing storage requirements +without providing significant benefits. + +The abbreviated metadata for a distribution consists of all fields +*except* the following: + +* ``description`` +* ``contributors`` + +When serialised to a file, the name used for this metadata set SHOULD +be ``pymeta-short.json``. + + +Core metadata +============= + +This section specifies the core metadata fields that are required for every +Python distribution. + +Publication tools MUST ensure at least these fields are present when +publishing a distribution. + +Index servers MUST ensure at least these fields are present in the metadata +when distributions are uploaded. + +Installation tools MUST refuse to install distributions with one or more +of these fields missing by default, but MAY allow users to force such an +installation to occur. + + +Metadata version ---------------- -Version of the file format; "2.0" is the only legal value. - -Automated tools consuming metadata should warn if ``Metadata-Version`` is -greater than the highest version they support, and must fail if -``Metadata-Version`` has a greater major version than the highest -version they support. - -For broader compatibility, automated tools may choose to produce +Version of the file format; ``"2.0"`` is the only legal value. + +Automated tools consuming metadata SHOULD warn if ``metadata_version`` is +greater than the highest version they support, and MUST fail if +``metadata_version`` has a greater major version than the highest +version they support (as described in PEP 440, the major version is the +value before the first dot). + +For broader compatibility, build tools MAY choose to produce distribution metadata using the lowest metadata version that includes all of the needed fields. Example:: - Metadata-Version: 2.0 + "metadata_version": "2.0" Name @@ -118,1057 +381,1100 @@ The name of the distribution. +As distribution names are used as part of URLs, filenames, command line +parameters and must also interoperate with other packaging systems, the +permitted characters are constrained to: + +* ASCII letters (``[a-zA-Z]``) +* ASCII digits (``[0-9]``) +* underscores (``_``) +* hyphens (``-``) +* periods (``.``) + +Distributions named MUST start and end with an ASCII letter or digit. + +Automated tools MUST reject non-compliant names. + +All comparisons of distribution names MUST be case insensitive, and MUST +consider hyphens and underscores to be equivalent. + +Index servers MAY consider "confusable" characters (as defined by the +Unicode Consortium in `TR39: Unicode Security Mechanisms `__) to be +equivalent. + +Index servers that permit arbitrary distribution name registrations from +untrusted sources SHOULD consider confusable characters to be equivalent +when registering new distributions (and hence reject them as duplicates). + +Installation tools MUST NOT silently accept a confusable alternate +spelling as matching a requested distribution name. + +At time of writing, the characters in the ASCII subset designated as +confusables by the Unicode Consortium are: + +* ``1`` (DIGIT ONE), ``l`` (LATIN SMALL LETTER L), and ``I`` (LATIN CAPITAL + LETTER I) +* ``0`` (DIGIT ZERO), and ``O`` (LATIN CAPITAL LETTER O) + + Example:: - Name: BeagleVote + "name": "ComfyChair" + +.. note:: + + Debian doesn't actually permit underscores in names, but that seems + unduly restrictive for this spec given the common practice of using + valid Python identifiers as Python distribution names. A Debian side + policy of converting underscores to hyphens seems easy enough to + implement (and the requirement to consider hyphens and underscores as + equivalent ensures that doing so won't introduce any conflicts). + + We're deliberately *not* following Python 3 down the path of arbitrary + unicode identifiers at this time. The security implications of doing so + are substantially worse in the software distribution use case (it opens + up far more interesting attack vectors than mere code obfuscation), the + existing tooling really only works properly if you abide by the stated + restrictions and changing it would require a *lot* of work for all + the automated tools in the chain. + + PyPI has recently been updated to reject non-compliant names for newly + registered projects, but existing non-compliant names are still + tolerated when using legacy metadata formats. Affected distributions + will need to change their names (typically be replacing spaces with + hyphens) before they can migrate to the new metadata formats. + + Donald Stufft ran an analysis, and the new restrictions impact less + than 230 projects out of the ~31k already on PyPI. This isn't that + surprising given the fact that many existing tools could already + exhibit odd behaviour when attempting to deal with non-compliant + names, implicitly discouraging the use of more exotic names. + + Of those projects, ~200 have the only non-compliant character as an + internal space (e.g. "Twisted Web"). These will be automatically + migrated by replacing the spaces with hyphens (e.g. "Twisted-Web"), + which is what you have to actually type to install these distributions + with ``setuptools`` (which powers both ``easy_install`` and ``pip``). + + The remaining ~30 will be investigated manually and decided upon on a + case by case basis how to migrate them to the new naming rules (in + consultation with the maintainers of those projects where possible). Version ------- -The distribution's public version identifier. Public versions are designed -for consumption by automated tools and are strictly ordered according -to a defined scheme. See `Version scheme`_ below. +The distribution's public version identifier, as defined in PEP 440. Public +versions are designed for consumption by automated tools and support a +variety of flexible version specification mechanisms (see PEP 440 for +details). Example:: - Version: 1.0a2 - + "version": "1.0a2" + + +Additional identifying metadata +=============================== + +This section specifies fields that provide other identifying details +that are unique to this distribution. + +All of these fields are optional. Automated tools MUST operate correctly if +a distribution does not provide them, including failing cleanly when an +operation depending on one of these fields is requested. + + +Build label +----------- + +A constrained identifying text string, as defined in PEP 440. Build labels +cannot be used in ordered version comparisons, but may be used to select +an exact version (see PEP 440 for details). + + +Examples:: + + "build_label": "1.0.0-alpha.1" + + "build_label": "1.3.7+build.11.e0f985a" + + "build_label": "v1.8.1.301.ga0df26f" + + "build_label": "2013.02.17.dev123" + + +Version URL +----------- + +A string containing a full URL where this specific version of the +distribution can be downloaded. (This means that the URL can't be +something like ``"https://github.com/pypa/pip/archive/master.zip"``, but +instead must be ``"https://github.com/pypa/pip/archive/1.3.1.zip"``.) + +Some appropriate targets for a version URL are a source tarball, an sdist +archive or a direct reference to a tag or specific commit in an online +version control system. + +All version URL references SHOULD either specify a secure transport +mechanism (such as ``https``) or else include an expected hash value in the +URL for verification purposes. If an insecure transport is specified without +any hash information (or with hash information that the tool doesn't +understand), automated tools SHOULD at least emit a warning and MAY +refuse to rely on the URL. + +It is RECOMMENDED that only hashes which are unconditionally provided by +the latest version of the standard library's ``hashlib`` module be used +for source archive hashes. At time of writing, that list consists of +``'md5'``, ``'sha1'``, ``'sha224'``, ``'sha256'``, ``'sha384'``, and +``'sha512'``. + +For source archive references, an expected hash value may be specified by +including a ``=`` as part of the URL +fragment. + +For version control references, the ``VCS+protocol`` scheme SHOULD be +used to identify both the version control system and the secure transport. + +To support version control systems that do not support including commit or +tag references directly in the URL, that information may be appended to the +end of the URL using the ``@`` notation. + +Example:: + + "version_url": "https://github.com/pypa/pip/archive/1.3.1.zip" + "version_url": "http://github.com/pypa/pip/archive/1.3.1.zip#sha1=da9234ee9982d4bbb3c72346a6de940a148ea686" + "version_url": "git+https://github.com/pypa/pip.git at 1.3.1" + +.. note:: + + This was called "Download-URL" in previous versions of the metadata. It + has been renamed, since there are plenty of other download locations and + this URL is meant to be a way to get the original source for development + purposes (or to generate an SRPM or other platform specific equivalent). + + For extra fun and games, it appears that unlike "svn+ssh://", + neither "git+ssh://" nor "hg+ssh://" natively support direct linking to a + particular tag (hg does support direct links to bookmarks through the URL + fragment, but that doesn't help for git and doesn't appear to be what I + want anyway). + + However pip does have a `defined convention + `__ for + this kind of link, which effectively splits a "URL" into "@". + + The PEP simply adopts pip's existing solution to this problem. + + This field is separate from the project URLs, as it's expected to + change for each version, while the project URLs are expected to + be fairly stable. + + +Additional descriptive metadata +=============================== + +This section specifies fields that provide additional information regarding +the distribution and its contents. + +All of these fields are optional. Automated tools MUST operate correctly if +a distribution does not provide them, including failing cleanly when an +operation depending on one of these fields is requested. Summary ------- A one-line summary of what the distribution does. +Publication tools SHOULD emit a warning if this field is not provided. Index +servers MAY require that this field be present before allowing a +distribution to be uploaded. + Example:: - Summary: A module for collecting votes from beagles. - - -Private-Version (optional) --------------------------- - -An arbitrary private version label. Private version labels are intended -for internal use by a project, and cannot be used in version specifiers. -See `Compatibility with other version schemes`_ below. - -Examples:: - - Private-Version: 1.0.0-alpha.1 - Private-Version: 1.3.7+build.11.e0f985a - Private-Version: v1.8.1.301.ga0df26f - Private-Version: 2013.02.17.dev123 - - -Description (optional, deprecated) ----------------------------------- - -Starting with Metadata 2.0, the recommended place for the description is in -the payload section of the document, after the last header. The description -does not need to be reformatted when it is included in the payload. - -See `Describing the Distribution`_ for more information on the expected -contents of this field. - -Since a line separator immediately followed by another line separator -indicates the end of the headers section, any line separators in a -``Description`` header field must be suffixed by whitespace to -indicate continuation. - -It is an error to provide both a ``Description`` header and a metadata -payload. - - -Keywords (optional) -------------------- - -A list of additional whitespace separated keywords to be used to assist -searching for the distribution in a larger catalog. - -Example:: - - Keywords: dog puppy voting election - - -Home-page (optional) --------------------- - -A string containing the URL for the distribution's home page. - -Example:: - - Home-page: http://www.example.com/~cschultz/bvote/ - - -Download-URL (optional) ------------------------ - -A string containing the URL from which this version of the distribution -can be downloaded. (This means that the URL can't be something like -".../BeagleVote-latest.tgz", but instead must be ".../BeagleVote-0.45.tgz".) - - -Project-URL (multiple use) --------------------------- - -A string containing a label and a browsable URL for the project, separated -by the last occurrence of comma and space ", ". - -The label consists of any permitted header text, including commas. - -Example:: - - Bug, Issue Tracker, http://bitbucket.org/tarek/distribute/issues/ - - -Author (optional) ------------------ - -A string containing the author's name at a minimum; additional -contact information may be provided. - -Example:: - - Author: C. Schultz, Universal Features Syndicate, - Los Angeles, CA - - -Author-email (optional) ------------------------ - -A string containing the author's e-mail address. It contains a name -and e-mail address in the RFC 5322 recommended ``Address Specification`` -format. - -Example:: - - Author-email: "C. Schultz" - - -Maintainer (optional) ---------------------- - -A string containing the maintainer's name at a minimum; additional -contact information may be provided. - -Note that this field is intended for use when a project is being -maintained by someone other than the original author: it should be -omitted if it is identical to ``Author``. - -Example:: - - Maintainer: C. Schultz, Universal Features Syndicate, - Los Angeles, CA - - -Maintainer-email (optional) ---------------------------- - -A string containing the maintainer's e-mail address. It has the same -format as ``Author-email``. - -Note that this field is intended for use when a project is being -maintained by someone other than the original author: it should be -omitted if it is identical to ``Author-email``. - -Example:: - - Maintainer-email: "C. Schultz" - - -License (optional) ------------------- - -Text indicating the license covering the distribution where the license -is not a selection from the "License" Trove classifiers. See -"Classifier" below. This field may also be used to specify a -particular version of a license which is named via the ``Classifier`` -field, or to indicate a variation or exception to such a license. - -Examples:: - - License: This software may only be obtained by sending the - author a postcard, and then the user promises not - to redistribute it. - - License: GPL version 3, excluding DRM provisions - -The full text of the license would normally be included in a separate -file. - - -Classifier (multiple use) -------------------------- - -Each entry is a string giving a single classification value -for the distribution. Classifiers are described in PEP 301 [2]. - -`Environment markers`_ may be used with this field. - -Examples:: - - Classifier: Development Status :: 4 - Beta - Classifier: Environment :: Console (Text Based) - - -Provides-Dist (multiple use) ----------------------------- - -Each entry contains a string naming a requirement that is satisfied by -installing this distribution. These strings must be of the form -``Name`` or ``Name (Version)``, following the formats of the corresponding -field definitions. - -A distribution may provide additional names, e.g. to indicate that -multiple projects have been merged into and replaced by a single -distribution or to indicate that this project is a substitute for another. -For instance, distribute (a fork of setuptools) can include a -``Provides-Dist: setuptools`` entry to prevent the conflicting -package from being downloaded and installed when distribute is already -installed. A distribution that has been merged with another might -``Provides-Dist`` the obsolete name(s) to satisfy any projects that -require the obsolete distribution's name. - -A distribution may also provide a "virtual" project name, which does -not correspond to any separately-distributed project: such a name -might be used to indicate an abstract capability which could be supplied -by one of multiple projects. E.g., multiple projects might supply -RDBMS bindings for use by a given ORM: each project might declare -that it provides ``ExampleORM-somedb-bindings``, allowing other -projects to depend only on having at least one of them installed. - -A version declaration may be supplied and must follow the rules described -in `Version scheme`_. The distribution's version identifier will be implied -if none is specified. - -`Environment markers`_ may be used with this field. - -Examples:: - - Provides-Dist: AnotherProject (3.4) - Provides-Dist: virtual_package - - -Provides-Extra (multiple use) ------------------------------ - -A string containing the name of an optional feature or "extra" that may -only be available when additional dependencies have been installed. Must -be printable ASCII, not containing whitespace, comma (,), or square -brackets []. - -See `Optional Features`_ for details on the use of this field. - -Example:: - - Name: beaglevote - Provides-Extra: pdf - Requires-Dist: reportlab; extra == 'pdf' - Requires-Dist: nose; extra == 'test' - Requires-Dist: sphinx; extra == 'doc' - - -Obsoleted-By (optional) ------------------------ - -Indicates that this project is no longer being developed. The named -project provides a substitute or replacement. - -A version declaration may be supplied and must follow the rules described -in `Version specifiers`_. - -Possible uses for this field include handling project name changes and -project mergers. - -Examples:: - - Name: BadName - Obsoleted-By: AcceptableName - - Name: SeparateProject - Obsoleted-By: MergedProject (>=4.0.0) - - -Requires-Dist (multiple use) ----------------------------- - -Each entry contains a string naming some other distutils -project required by this distribution. - -The format of a requirement string is identical to that of a distribution -name (e.g., as found in the ``Name:`` field) optionally followed by a -version declaration within parentheses. - -The distribution names should correspond to names as found on the `Python -Package Index`_; often the same as, but distinct from, the module names -as accessed with ``import x``. - -`Environment markers`_ may be used with this field. - -Version declarations must follow the rules described in -`Version specifiers`_ - -Distributions may also depend on optional features of other distributions. -See `Optional Features`_ for details. - -Examples:: - - Requires-Dist: pkginfo - Requires-Dist: PasteDeploy - Requires-Dist: zope.interface (>3.5.0) - -Dependencies mentioned in ``Requires-Dist`` may be installed exclusively -at run time and are not guaranteed to be available when creating or -installing a package. If a dependency is needed during distribution -creation or installation *and* at run time, it should be listed under -both ``Requires-Dist`` and ``Setup-Requires-Dist``. - - -Setup-Requires-Dist (multiple use) ----------------------------------- - -Like ``Requires-Dist``, but names dependencies needed in order to build, -package or install the distribution -- in distutils, a dependency imported -by ``setup.py`` itself. Commonly used to bring in extra compiler support -or a package needed to generate a manifest from version control. - -Examples:: - - Setup-Requires-Dist: custom_setup_command - -Dependencies mentioned in ``Setup-Requires-Dist`` may be installed -exclusively for setup and are not guaranteed to be available at run time. -If a dependency is needed during distribution creation or installation -*and* at run time, it should be listed under both ``Requires-Dist`` and -``Setup-Requires-Dist``. - - -Requires-Python (multiple use) ------------------------------- - -This field specifies the Python version(s) that the distribution is -guaranteed to be compatible with. - -`Environment markers`_ may be used with this field. - -Version declarations must be in the format specified in -`Version specifiers`_. - -Examples:: - - Requires-Python: 3.2 - Requires-Python: >3.1 - Requires-Python: >=2.3.4 - Requires-Python: >=2.5,<2.7 - -If specified multiple times, the Python version must satisfy all such -constraints to be considered compatible. This is most useful in combination -with appropriate `Environment markers`_. - -For example, if a feature was initially introduced to Python as a -Unix-specific addition, and then Windows support was added in the -subsequent release, this could be indicated with the following pair -of entries:: - - Requires-Python: >= 3.1 - Requires-Python: >= 3.2; sys.platform == 'win32' - - -Requires-External (multiple use) --------------------------------- - -Each entry contains a string describing some dependency in the -system that the distribution is to be used. This field is intended to -serve as a hint to downstream project maintainers, and has no -semantics which are meaningful to the ``distutils`` distribution. - -The format of a requirement string is a name of an external -dependency, optionally followed by a version declaration within -parentheses. - -`Environment markers`_ may be used with this field. - -Because they refer to non-Python software releases, version identifiers -for this field are **not** required to conform to the format -described in `Version scheme`_: they should correspond to the -version scheme used by the external dependency. - -Notice that there is no particular rule on the strings to be used. - -Examples:: - - Requires-External: C - Requires-External: libpng (>=1.5) - - -Platform (multiple use) ------------------------ - -A Platform specification describing an operating system supported by -the distribution which is not listed in the "Operating System" Trove -classifiers. See `Classifier`__ above. - -__ `Classifier (multiple use)`_ - -Examples:: - - Platform: ObscureUnix - Platform: RareDOS - - -Supported-Platform (multiple use) ---------------------------------- - -Binary distributions containing a metadata file will use the -Supported-Platform field in their metadata to specify the OS and -CPU for which the binary distribution was compiled. The semantics of -the Supported-Platform field are not specified in this PEP. - -Example:: - - Supported-Platform: RedHat 7.2 - Supported-Platform: i386-win32-2791 - - -Extension (multiple use) ------------------------- - -An ASCII string, not containing whitespace or the ``/`` character, that -indicates the presence of extended metadata. The additional fields -defined by the extension are then prefixed with the name of the extension -and the ``/`` character. The additional fields are optional (0..1). - -For example:: - - Extension: Chili - Chili/Type: Poblano - Chili/Heat: Mild - Chili/json: { - "type" : "Poblano", - "heat" : "Mild" } - -The special ``{extension name}/json`` permits embedded JSON. It may be -parsed automatically by a future tool. - -Values in extension fields must still respect the general formatting -requirements for metadata headers. - -To avoid name conflicts, it is recommended that distribution names be used -to identify metadata extensions. This practice will also make it easier to -find authoritative documentation for metadata extensions. - -As the order of the metadata headers is not constrained, the -``Extension: Chili`` field may appear before or after the corresponding -extension fields ``Chili/Type:`` etc. - -A bare ``Extension: Name`` entry with no corresponding extension fields is -permitted. It may, for example, indicate the expected presence of an -additional metadata file rather than the presence of extension fields. - -An extension field with no corresponding ``Extension: Name`` entry is an -error. - - -Describing the distribution -=========================== + "summary": "A module that is more fiendish than soft cushions." + +.. note:: + + This used to be mandatory, and it's still highly recommended, but really, + nothing should break even when it's missing. + + +Description +----------- The distribution metadata should include a longer description of the distribution that may run to several paragraphs. Software that deals with metadata should not assume any maximum size for the description. -The recommended location for the description is in the metadata payload, -separated from the header fields by at least one completely blank line -(that is, two successive line separators with no other characters -between them, not even whitespace). - -Alternatively, the description may be provided in the `Description`__ -metadata header field. Providing both a ``Description`` field and a -payload is an error. - -__ `Description (optional, deprecated)`_ - The distribution description can be written using reStructuredText markup [1]_. For programs that work with the metadata, supporting markup is optional; programs may also display the contents of the field as plain text without any special formatting. This means that authors should be conservative in the markup they use. - -Version scheme -============== - -Public version identifiers must comply with the following scheme:: - - N[.N]+[{a|b|c|rc}N][.postN][.devN] - -Version identifiers which do not comply with this scheme are an error. - -Version identifiers must not include leading or trailing whitespace. - -Any given version will be a "release", "pre-release", "post-release" or -"developmental release" as defined in the following sections. +Example:: + + "description": "The ComfyChair module replaces SoftCushions.\\n\\nUse until lunchtime, but pause for a cup of coffee at eleven." .. note:: - Some hard to read version identifiers are permitted by this scheme in - order to better accommodate the wide range of versioning practices - across existing public and private Python projects, given the - constraint that the package index is not yet sophisticated enough to - allow the introduction of a simpler, backwards-incompatible scheme. - - Accordingly, some of the versioning practices which are technically - permitted by the PEP are strongly discouraged for new projects. Where - this is the case, the relevant details are noted in the following - sections. - - -Releases + The difficulty of editing this field in a raw JSON file is one of the + main reasons this metadata interchange format is NOT recommended for + use as an input format for build tools. + + +Description Format +------------------ + +A field indicating the intended format of the text in the description field. +This allows index servers to render the description field correctly and +provide feedback on rendering errors, rather than having to guess the +intended format. + +If this field is omitted, or contains an unrecognised value, the default +rendering format MUST be plain text. + +The following format names SHOULD be used for the specified markup formats: + +* ``txt``: Plain text (default handling if field is omitted) +* ``rst``: reStructured Text +* ``md``: Markdown (exact syntax variant will be implementation dependent) +* ``adoc``: AsciiDoc +* ``html``: HTML + +Automated tools MAY render one or more of the listed formats as plain +text and MAY accept other markup formats beyond those listed. + +Example:: + + "description_format": "rst" + + +Keywords -------- -A release number is a version identifier that consists solely of one or -more non-negative integer values, separated by dots:: - - N[.N]+ - -Releases within a project must be numbered in a consistently increasing -fashion. Ordering considers the numeric value of each component -in turn, with "component does not exist" sorted ahead of all numeric -values. - -Date based release numbers are explicitly excluded from compatibility with -this scheme, as they hinder automatic translation to other versioning -schemes, as well as preventing the adoption of semantic versioning without -changing the name of the project. Accordingly, a leading release component -greater than or equal to ``1980`` is an error. - -While any number of additional components after the first are permitted -under this scheme, the most common variants are to use two components -("major.minor") or three components ("major.minor.micro"). - -For example:: - - 0.9 - 0.9.1 - 0.9.2 - ... - 0.9.10 - 0.9.11 - 1.0 - 1.0.1 - 1.1 - 2.0 - 2.0.1 - -A release series is any set of release numbers that start with a common -prefix. For example, ``3.3.1``, ``3.3.5`` and ``3.3.9.45`` are all -part of the ``3.3`` release series. +A list of additional keywords to be used to assist searching for the +distribution in a larger catalog. + +Example:: + + "keywords": ["comfy", "chair", "cushions", "too silly", "monty python"] + + +License +------- + +A string indicating the license covering the distribution where the license +is not a simple selection from the "License" Trove classifiers. See +Classifiers" below. This field may also be used to specify a +particular version of a license which is named via the ``Classifier`` +field, or to indicate a variation or exception to such a license. + +Example:: + + "license": "GPL version 3, excluding DRM provisions" + + +License URL +----------- + +A specific URL referencing the full licence text for this version of the +distribution. + +Example:: + + "license_url": "https://github.com/pypa/pip/blob/1.3.1/LICENSE.txt" .. note:: - Using both ``X.Y`` and ``X.Y.0`` as distinct release numbers within the - scope of a single release series is strongly discouraged, as it makes the - version ordering ambiguous for human readers. Automated tools should - either treat this case as an error, or else interpret an ``X.Y.0`` - release as coming *after* the corresponding ``X.Y`` release. - - The recommended practice is to always use release numbers of a consistent - length (that is, always include the trailing ``.0``). An acceptable - alternative is to consistently omit the trailing ``.0``. The example - above shows both styles, always including the ``.0`` at the second - level and consistently omitting it at the third level. - - -Pre-releases + Like Version URL, this is handled separately from the project URLs + as it is important that it remain accurate for this *specific* + version of the distribution, even if the project later switches to a + different license. + + The project URLs field is intended for more stable references. + + +Classifiers +----------- + +A list of strings, with each giving a single classification value +for the distribution. Classifiers are described in PEP 301 [2]. + +Example:: + + "classifiers": [ + "Development Status :: 4 - Beta", + "Environment :: Console (Text Based)" + ] + + +Contact metadata +================ + +Contact metadata for a distribution is provided to allow users to get +access to more information about the distribution and its maintainers. + +These details are recorded as mappings with the following subfields: + +* ``name``: the name of an individual or group +* ``email``: an email address (this may be a mailing list) +* ``url``: a URL (such as a profile page on a source code hosting service) +* ``type``: one of ``"author"``, ``"maintainer"``, ``"organization"`` + or ``"individual"`` + +The ``name`` subfield is required, the other subfields are optional. + +If no specific contact type is stated, the default is ``individual``. + +The different contact types are as follows: + +* ``author``: the original creator of a distribution +* ``maintainer``: the current lead contributor for a distribution, when + they are not the original creator +* ``individual``: any other individuals involved in the creation of the + distribution +* ``organization``: indicates that these contact details are for an + organization (formal or informal) rather than for a specific individual + +.. note:: + + This is admittedly a little complicated, but it's designed to replace the + Author, Author-Email, Maintainer, Maintainer-Email fields from metadata + 1.2 in a way that allows those distinctions to be fully represented for + lossless translation, while allowing future distributions to pretty + much ignore everything other than the contact/contributor distinction + if they so choose. + +Contact metadata is optional. Automated tools MUST operate correctly if +a distribution does not provide them, including failing cleanly when an +operation depending on one of these fields is requested. + + +Contacts +-------- + +A list of contact entries giving the recommended contact points for getting +more information about the project. + +The example below would be suitable for a project that was in the process +of handing over from the original author to a new lead maintainer, while +operating as part of a larger development group. + +Example:: + + "contacts": [ + { + "name": "Python Packaging Authority/Distutils-SIG", + "type": "organization", + "email": "distutils-sig at python.org", + "url": "https://bitbucket.org/pypa/" + }, + { + "name": "Samantha C.", + "type": "maintainer", + "email": "dontblameme at example.org" + }, + { + "name": "Charlotte C.", + "type": "author", + "email": "iambecomingasketchcomedian at example.com" + } + ] + + +Contributors ------------ -Some projects use an "alpha, beta, release candidate" pre-release cycle to -support testing by their users prior to a full release. - -If used as part of a project's development cycle, these pre-releases are -indicated by a suffix appended directly to the last component of the -release number:: - - X.YaN # Alpha release - X.YbN # Beta release - X.YcN # Release candidate (alternative notation: X.YrcN) - X.Y # Full release - -The pre-release suffix consists of an alphabetical identifier for the -pre-release phase, along with a non-negative integer value. Pre-releases for -a given release are ordered first by phase (alpha, beta, release candidate) -and then by the numerical component within that phase. +A list of contact entries for other contributors not already listed as +current project points of contact. The subfields within the list elements +are the same as those for the main contact field. + +Example:: + + "contributors": [ + {"name": "John C."}, + {"name": "Erik I."}, + {"name": "Terry G."}, + {"name": "Mike P."}, + {"name": "Graeme C."}, + {"name": "Terry J."} + ] + + +Project URLs +------------ + +A mapping of arbitrary text labels to additional URLs relevant to the +project. + +While projects are free to choose their own labels and specific URLs, +it is RECOMMENDED that home page, source control, issue tracker and +documentation links be provided using the labels in the example below. + +URL labels MUST be treated as case insensitive by automated tools, but they +are not required to be valid Python identifiers. Any legal JSON string is +permitted as a URL label. + +Example:: + + "project_urls": { + "Documentation": "https://distlib.readthedocs.org" + "Home": "https://bitbucket.org/pypa/distlib" + "Source": "https://bitbucket.org/pypa/distlib/src" + "Tracker": "https://bitbucket.org/pypa/distlib/issues" + } + + +Dependency metadata +=================== + +Dependency metadata allows distributions to make use of functionality +provided by other distributions, without needing to bundle copies of those +distributions. + +Dependency management is heavily dependent on the version identification +and specification scheme defined in PEP 440. .. note:: - Using both ``c`` and ``rc`` to identify release candidates within - the scope of a single release is strongly discouraged, as it makes the - version ordering ambiguous for human readers. Automated tools should - either treat this case as an error, or else interpret all ``rc`` versions - as coming after all ``c`` versions (that is, ``rc1`` indicates a later - version than ``c2``). - - -Post-releases + This substantially changes the old two-phase setup vs runtime dependency + model in metadata 1.2 (which was in turn derived from the setuptools + dependency parameters). The translation is that ``dev_requires`` and + ``build_requires`` both map to ``Setup-Requires-Dist`` + in 1.2, while ``requires`` maps to ``Requires-Dist``. To go the other + way, ``Setup-Requires-Dist`` maps to ``build_requires`` and + ``Requires-Dist`` maps to ``requires``. + +All of these fields are optional. Automated tools MUST operate correctly if +a distribution does not provide them, by assuming that a missing field +indicates "Not applicable for this distribution". + + +Dependency specifications +------------------------- + +Individual dependencies are typically defined as strings containing a +distribution name (as found in the ``name`` field). The dependency name +may be followed by an extras specifier (enclosed in square +brackets) and by a version specification (within parentheses). + +See `Extras (optional dependencies)`_ for details on extras and PEP 440 +for details on version specifiers. + +The distribution names should correspond to names as found on the `Python +Package Index`_; while these names are often the same as the module names +as accessed with ``import x``, this is not always the case (especially +for distributions that provide multiple top level modules or packages). + +Example dependency specifications:: + + "Flask" + "Django" + "Pyramid" + "SciPy (0.12)" + "ComfyChair[warmup]" + "ComfyChair[warmup] (> 0.1)" + + +Conditional dependencies +------------------------ + +While many dependencies will be needed to use a distribution at all, others +are needed only on particular platforms or only when particular optional +features of the distribution are needed. To enable this, dependency fields +are marked as either unconditional (indicated by ``requires`` in the field +name) or conditional (indicated by ``may_require``) in the field name. + +Unconditional dependency fields are lists of dependency specifications, with +each entry indicated a required dependency. + +Conditional dependencies are lists of mappings with the following fields: + +* ``dependencies``: a list of relevant dependency specifications +* ``extra``: the name of a set of optional dependencies that are requested + and installed together. See `Extras (optional dependencies)`_ for details. +* ``environment``: an environment marker defining the environment that + needs these dependencies. See `Environment markers`_ for details. + +The ``dependencies`` field is required, as is at least one of ``extra`` and +``environment``. All three fields may be supplied, indicating that the +dependency is needed only when that particular set of additional +dependencies is requested in a particular environment. + +Note that the same extras and environment markers MAY appear in multiple +conditional dependencies. This may happen, for example, if an extra itself +only needs some of its dependencies in specific environments. + +.. note:: + + Technically, you could store the conditional and unconditional + dependencies in a single list and switch based on the entry type + (string or mapping), but the ``*requires`` vs ``*may-require`` two + list design seems easier to understand and work with. + + +Mapping dependencies to development and distribution activities +--------------------------------------------------------------- + +The different categories of dependency are based on the various distribution +and development activities identified above, and govern which dependencies +should be installed for the specified activities: + +* Deployment dependencies: + + * ``requires`` + * ``may_require`` + * Request the ``test`` extra to also install + + * ``test_requires`` + * ``test_may_require`` + +* Build dependencies: + + * ``build_requires`` + * ``build_may_require`` + +* Development dependencies: + + * ``requires`` + * ``may_require`` + * ``build_requires`` + * ``build_may_require`` + * ``test_requires`` + * ``test_may_require`` + * ``dev_requires`` + * ``dev_may_require`` + +To ease compatibility with existing two phase setup/deployment toolchains, +installation tools MAY treat ``dev_requires`` and ``dev_may_require`` as +additions to ``build_requires`` and ``build_may_require`` rather than +as separate fields. + +Installation tools SHOULD allow users to request at least the following +operations for a named distribution: + +* Install the distribution and any deployment dependencies. +* Install just the build dependencies without installing the distribution +* Install just the development dependencies without installing + the distribution + +The notation described in `Extras (optional dependencies)`_ SHOULD be used to +request additional optional dependencies when installing deployment +or build dependencies. + +Installation tools SHOULD report an error if dependencies cannot be found, +MUST at least emit a warning, and MAY allow the user to force the +installation to proceed regardless. + +.. note:: + + As an example of mapping this to Linux distro packages, assume an + example project without any extras defined is split into 2 RPMs + in a SPEC file: example and example-devel + + The ``requires`` and applicable ``may_require`` dependencies would be + mapped to the Requires dependencies for the "example" RPM (a mapping from + environment markers to SPEC file conditions would also allow those to + be handled correctly) + + The ``build_requires`` and ``build_may_require`` dependencies would be + mapped to the BuildRequires dependencies for the "example" RPM. + + All defined dependencies relevant to Linux, including those in + ``dev_requires`` and ``test_requires``, would become Requires + dependencies for the "example-devel" RPM. + + If a project defines any extras, those would be mapped to additional + virtual RPMs with appropriate BuildRequires and Requires entries based + on the details of the dependency specifications. + + A documentation toolchain dependency like Sphinx would either go in + ``build_requires`` (for example, if man pages were included in the + built distribution) or in ``dev_requires`` (for example, if the + documentation is published solely through ReadTheDocs or the + project website). This would be enough to allow an automated converter + to map it to an appropriate dependency in the spec file. + + +Requires +-------- + +A list of other distributions needed when this distribution is deployed. + +Example:: + + "requires": ["SciPy", "PasteDeploy", "zope.interface (>3.5.0)"] + + +Extras +------ + +A list of optional sets of dependencies that may be used to define +conditional dependencies in ``"may_require"`` and similar fields. See +`Extras (optional dependencies)`_ for details. + +The extra name``"test"`` is reserved for requesting the dependencies +specified in ``test_requires`` and ``test_may_require`` and is NOT +permitted in this field. + +Example:: + + "extras": ["warmup"] + + +May require +----------- + +A list of other distributions that may be needed when this distribution +is deployed, based on the extras requested and the target deployment +environment. + +Any extras referenced from this field MUST be named in the `Extras`_ field. + +Example:: + + "may_require": [ + { + "dependencies": ["pywin32 (>1.0)"], + "environment": "sys.platform == 'win32'" + }, + { + "dependencies": ["SoftCushions"], + "extra": "warmup" + } + ] + +Test requires ------------- -Some projects use post-releases to address minor errors in a release that -do not affect the distributed software (for example, correcting an error -in the release notes). - -If used as part of a project's development cycle, these post-releases are -indicated by a suffix appended directly to the last component of the -release number:: - - X.Y.postN # Post-release - -The post-release suffix consists of the string ``.post``, followed by a -non-negative integer value. Post-releases are ordered by their -numerical component, immediately following the corresponding release, -and ahead of any subsequent release. +A list of other distributions needed in order to run the automated tests +for this distribution, either during development or when running the +``test_installed_dist`` metabuild when deployed. + +Example:: + + "test_requires": ["unittest2"] + + +Test may require +---------------- + +A list of other distributions that may be needed in order to run the +automated tests for this distribution, either during development or when +running the ``test_installed_dist`` metabuild when deployed, based on the +extras requested and the target deployment environment. + +Any extras referenced from this field MUST be named in the `Extras`_ field. + +Example:: + + "test_may_require": [ + { + "dependencies": ["pywin32 (>1.0)"], + "environment": "sys.platform == 'win32'" + }, + { + "dependencies": ["CompressPadding"], + "extra": "warmup" + } + ] + + +Build requires +-------------- + +A list of other distributions needed when this distribution is being built +(creating a binary archive from a source archive). + +Note that while these are build dependencies for the distribution being +built, the installation is a *deployment* scenario for the dependencies. + +Example:: + + "build_requires": ["setuptools (>= 0.7)"] + + +Build may require +----------------- + +A list of other distributions that may be needed when this distribution +is built (creating a binary archive from a source archive), based on the +features requested and the build environment. + +Note that while these are build dependencies for the distribution being +built, the installation is a *deployment* scenario for the dependencies. + +Any extras referenced from this field MUST be named in the `Extras`_ field. + +Automated tools MAY assume that all extras are implicitly requested when +installing build dependencies. + +Example:: + + "build_may_require": [ + { + "dependencies": ["pywin32 (>1.0)"], + "environment": "sys.platform == 'win32'" + }, + { + "dependencies": ["cython"], + "extra": "c-accelerators" + } + ] + + +Dev requires +------------ + +A list of any additional distributions needed during development of this +distribution that aren't already covered by the deployment and build +dependencies. + +Additional dependencies that may be listed in this field include: + +* tools needed to create a source archive +* tools needed to generate project documentation that is published online + rather than distributed along with the rest of the software +* additional test dependencies for tests which are not executed when the + test is invoked through the ``test_installed_dist`` metabuild hook (for + example, tests that require a local database server and web server and + may not work when fully installed on a production system) + +Example:: + + "dev_requires": ["hgtools", "sphinx (>= 1.0)"] + + +Dev may require +--------------- + +A list of other distributions that may be needed during development of +this distribution, based on the features requested and the build environment. + +This should only be needed if the project's own utility scripts have +platform specific dependencies that aren't already defined as deployment +or build dependencies. + +Any extras referenced from this field MUST be named in the `Extras`_ field. + +Automated tools MAY assume that all extras are implicitly requested when +installing development dependencies. + +Example:: + + "dev_may_require": [ + { + "dependencies": ["pywin32 (>1.0)"], + "environment": "sys.platform == 'win32'" + } + ] + + +Provides +-------- + +A list of strings naming additional dependency requirements that are +satisfied by installing this distribution. These strings must be of the +form ``Name`` or ``Name (Version)``, as for the ``requires`` field. + +While dependencies are usually resolved based on distribution names and +versions, a distribution may provide additional names explicitly in the +``provides`` field. + +For example, this may be used to indicate that multiple projects have +been merged into and replaced by a single distribution or to indicate +that this project is a substitute for another. + +For instance, with distribute merged back into setuptools, the merged +project is able to include a ``"provides": ["distribute"]`` entry to +satisfy any projects that require the now obsolete distribution's name. + +A distribution may also provide a "virtual" project name, which does +not correspond to any separately distributed project: such a name +might be used to indicate an abstract capability which could be supplied +by one of multiple projects. For example, multiple projects might supply +PostgreSQL bindings for use with SQL Alchemy: each project might declare +that it provides ``sqlalchemy-postgresql-bindings``, allowing other +projects to depend only on having at least one of them installed. + +A version declaration may be supplied and must follow the rules described +in PEP 440. The distribution's version identifier will be implied +if none is specified. + +Example:: + + "provides": ["AnotherProject (3.4)", "virtual_package"] + + +Obsoleted by +------------ + +A string that indicates that this project is no longer being developed. The +named project provides a substitute or replacement. + +A version declaration may be supplied and must follow the rules described +in PEP 440. + +Possible uses for this field include handling project name changes and +project mergers. + +For instance, with distribute merging back into setuptools, a new version +of distribute may be released that depends on the new version of setuptools, +and also explicitly indicates that distribute itself is now obsolete. + +Note that without a corresponding ``provides``, there is no expectation +that the replacement project will be a "drop-in" replacement for the +obsolete project - at the very least, upgrading to the new distribution +is likely to require changes to import statements. + +Examples:: + + "name": "BadName", + "obsoleted_by": "AcceptableName" + + "name": "distribute", + "obsoleted_by": "setuptools (>= 0.7)" + + +Supports Environments +--------------------- + +A list of strings specifying the environments that the distribution +explicitly supports. An environment is considered supported if it +matches at least one of the environment markers given. + +If this field is not given in the metadata, it is assumed that the +distribution supports any platform supported by Python. + +Individual entries are environment markers, as described in +`Environment markers`_. + +Installation tools SHOULD report an error if supported platforms are +specified by the distribution and the current platform fails to match +any of them, MUST at least emit a warning, and MAY allow the user to +force the installation to proceed regardless. + +Examples:: + + "supports_environments": ["sys_platform == 'win32'"] + "supports_environments": ["sys_platform != 'win32'"] + "supports_environments": ["'linux' in sys_platform", + "'bsd' in sys_platform"] + .. note:: - The use of post-releases to publish maintenance releases containing - actual bug fixes is strongly discouraged. In general, it is better - to use a longer release number and increment the final component - for each maintenance release. - -Post-releases are also permitted for pre-releases:: - - X.YaN.postM # Post-release of an alpha release - X.YbN.postM # Post-release of a beta release - X.YcN.postM # Post-release of a release candidate - -.. note:: - - Creating post-releases of pre-releases is strongly discouraged, as - it makes the version identifier difficult to parse for human readers. - In general, it is substantially clearer to simply create a new - pre-release by incrementing the numeric component. - - -Developmental releases ----------------------- - -Some projects make regular developmental releases, and system packagers -(especially for Linux distributions) may wish to create early releases -which do not conflict with later project releases. - -If used as part of a project's development cycle, these developmental -releases are indicated by a suffix appended directly to the last -component of the release number:: - - X.Y.devN # Developmental release - -The developmental release suffix consists of the string ``.dev``, -followed by a non-negative integer value. Developmental releases are ordered -by their numerical component, immediately before the corresponding release -(and before any pre-releases), and following any previous release. - -Developmental releases are also permitted for pre-releases and -post-releases:: - - X.YaN.devM # Developmental release of an alpha release - X.YbN.devM # Developmental release of a beta release - X.YcN.devM # Developmental release of a release candidate - X.Y.postN.devM # Developmental release of a post-release - -.. note:: - - Creating developmental releases of pre-releases is strongly - discouraged, as it makes the version identifier difficult to parse for - human readers. In general, it is substantially clearer to simply create - additional pre-releases by incrementing the numeric component. - - Developmental releases of post-releases are also strongly discouraged, - but they may be appropriate for projects which use the post-release - notation for full maintenance releases which may include code changes. - - -Examples of compliant version schemes -------------------------------------- - -The standard version scheme is designed to encompass a wide range of -identification practices across public and private Python projects. In -practice, a single project attempting to use the full flexibility offered -by the scheme would create a situation where human users had difficulty -figuring out the relative order of versions, even though the rules above -ensure all compliant tools will order them consistently. - -The following examples illustrate a small selection of the different -approaches projects may choose to identify their releases, while still -ensuring that the "latest release" and the "latest stable release" can -be easily determined, both by human users and automated tools. - -Simple "major.minor" versioning:: - - 0.1 - 0.2 - 0.3 - 1.0 - 1.1 - ... - -Simple "major.minor.micro" versioning:: - - 1.1.0 - 1.1.1 - 1.1.2 - 1.2.0 - ... - -"major.minor" versioning with alpha, beta and release candidate -pre-releases:: - - 0.9 - 1.0a1 - 1.0a2 - 1.0b1 - 1.0c1 - 1.0 - 1.1a1 - ... - -"major.minor" versioning with developmental releases, release candidates -and post-releases for minor corrections:: - - 0.9 - 1.0.dev1 - 1.0.dev2 - 1.0.dev3 - 1.0.dev4 - 1.0rc1 - 1.0rc2 - 1.0 - 1.0.post1 - 1.1.dev1 - ... - - -Summary of permitted suffixes and relative ordering ---------------------------------------------------- - -.. note:: - - This section is intended primarily for authors of tools that - automatically process distribution metadata, rather than authors - of Python distributions deciding on a versioning scheme. - -The numeric release component of version identifiers should be sorted in -the same order as Python's tuple sorting when the release number is -parsed as follows:: - - tuple(map(int, release_number.split("."))) - -Within a numeric release (``1.0``, ``2.7.3``), the following suffixes -are permitted and are ordered as shown:: - - .devN, aN, bN, cN, rcN, , .postN - -Note that `rc` will always sort after `c` (regardless of the numeric -component) although they are semantically equivalent. Tools are free to -reject this case as ambiguous and remain in compliance with the PEP. - -Within an alpha (``1.0a1``), beta (``1.0b1``), or release candidate -(``1.0c1``, ``1.0rc1``), the following suffixes are permitted and are -ordered as shown:: - - .devN, , .postN - -Within a post-release (``1.0.post1``), the following suffixes are permitted -and are ordered as shown:: - - .devN, - -Note that ``devN`` and ``postN`` must always be preceded by a dot, even -when used immediately following a numeric version (e.g. ``1.0.dev456``, -``1.0.post1``). - -Within a given suffix, ordering is by the value of the numeric component. - -The following example covers many of the possible combinations:: - - 1.0.dev456 - 1.0a1 - 1.0a2.dev456 - 1.0a12.dev456 - 1.0a12 - 1.0b1.dev456 - 1.0b2 - 1.0b2.post345.dev456 - 1.0b2.post345 - 1.0c1.dev456 - 1.0c1 - 1.0 - 1.0.post456.dev34 - 1.0.post456 - 1.1.dev1 - - -Version ordering across different metadata versions ---------------------------------------------------- - -Metadata v1.0 (PEP 241) and metadata v1.1 (PEP 314) do not -specify a standard version identification or ordering scheme. This PEP does -not mandate any particular approach to handling such versions, but -acknowledges that the de facto standard for ordering them is -the scheme used by the ``pkg_resources`` component of ``setuptools``. - -Software that automatically processes distribution metadata should attempt -to normalize non-compliant version identifiers to the standard scheme, and -ignore them if normalization fails. As any normalization scheme will be -implementation specific, this means that projects using non-compliant -version identifiers may not be handled consistently across different -tools, even when correctly publishing the earlier metadata versions. - -For distributions currently using non-compliant version identifiers, these -filtering guidelines mean that it should be enough for the project to -simply switch to the use of compliant version identifiers to ensure -consistent handling by automated tools. - -Distribution users may wish to explicitly remove non-compliant versions from -any private package indexes they control. - -For metadata v1.2 (PEP 345), the version ordering described in this PEP -should be used in preference to the one defined in PEP 386. - - -Compatibility with other version schemes ----------------------------------------- - -Some projects may choose to use a version scheme which requires -translation in order to comply with the public version scheme defined in -this PEP. In such cases, the `Private-Version`__ field can be used to -record the project specific version as an arbitrary label, while the -translated public version is given in the `Version`_ field. - -__ `Private-Version (optional)`_ - -This allows automated distribution tools to provide consistently correct -ordering of published releases, while still allowing developers to use -the internal versioning scheme they prefer for their projects. - - -Semantic versioning -~~~~~~~~~~~~~~~~~~~ - -`Semantic versioning`_ is a popular version identification scheme that is -more prescriptive than this PEP regarding the significance of different -elements of a release number. Even if a project chooses not to abide by -the details of semantic versioning, the scheme is worth understanding as -it covers many of the issues that can arise when depending on other -distributions, and when publishing a distribution that others rely on. - -The "Major.Minor.Patch" (described in this PEP as "major.minor.micro") -aspects of semantic versioning (clauses 1-9 in the 2.0.0-rc-1 specification) -are fully compatible with the version scheme defined in this PEP, and abiding -by these aspects is encouraged. - -Semantic versions containing a hyphen (pre-releases - clause 10) or a -plus sign (builds - clause 11) are *not* compatible with this PEP -and are not permitted in the public `Version`_ field. - -One possible mechanism to translate such private semantic versions to -compatible public versions is to use the ``.devN`` suffix to specify the -appropriate version order. - -.. _Semantic versioning: http://semver.org/ - - -DVCS based version labels -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Many build tools integrate with distributed version control systems like -Git and Mercurial in order to add an identifying hash to the version -identifier. As hashes cannot be ordered reliably such versions are not -permitted in the public `Version`_ field. - -As with semantic versioning, the public ``.devN`` suffix may be used to -uniquely identify such releases for publication, while the private -version field is used to record the original version label. - - -Date based versions -~~~~~~~~~~~~~~~~~~~ - -As with other incompatible version schemes, date based versions can be -stored in the ``Private-Version`` field. Translating them to a compliant -public version is straightforward: the simplest approach is to subtract -the year before the first release from the major component in the release -number. - - -Version specifiers -================== - -A version specifier consists of a series of version clauses, separated by -commas. Each version clause consists of an optional comparison operator -followed by a version identifier. For example:: - - 0.9, >= 1.0, != 1.3.4, < 2.0 - -Each version identifier must be in the standard format described in -`Version scheme`_. - -The comma (",") is equivalent to a logical **and** operator. - -Whitespace between a conditional operator and the following version -identifier is optional, as is the whitespace around the commas. - - -Compatible release ------------------- - -A compatible release clause omits the comparison operator and matches any -version that is expected to be compatible with the specified version. - -For a given release identifier ``V.N``, the compatible release clause is -approximately equivalent to the pair of comparison clauses:: - - >= V.N, < V+1.dev0 - -where ``V+1`` is the next version after ``V``, as determined by -incrementing the last numeric component in ``V``. For example, -the following version clauses are approximately equivalent:: - - 2.2 - >= 2.2, < 3.dev0 - - 1.4.5 - >= 1.4.5, < 1.5.dev0 - -The difference between the two is that using a compatible release clause -does *not* count as `explicitly mentioning a pre-release`__. - -__ `Handling of pre-releases`_ - -If a pre-release, post-release or developmental release is named in a -compatible release clause as ``V.N.suffix``, then the suffix is ignored -when determining the upper limit of compatibility:: - - 2.2.post3 - >= 2.2.post3, < 3.dev0 - - 1.4.5a4 - >= 1.4.5a4, < 1.5.dev0 - - -Version comparisons -------------------- - -A version comparison clause includes a comparison operator and a version -identifier, and will match any version where the comparison is true. - -Comparison clauses are only needed to cover cases which cannot be handled -with an appropriate compatible release clause, including coping with -dependencies which do not have a robust backwards compatibility policy -and thus break the assumptions of a compatible release clause. - -The defined comparison operators are ``<``, ``>``, ``<=``, ``>=``, ``==``, -and ``!=``. - -The ordered comparison operators ``<``, ``>``, ``<=``, ``>=`` are based -on the consistent ordering defined by the standard `Version scheme`_. - -The ``==`` and ``!=`` operators are based on a kind of prefix comparison - -trailing ``0``s are implied when comparing numeric version parts of different -lengths. ``1.0 == 1 == 1.0.0``, and ``1.0a1 == ``1.0.0.0a1``. - -.. note:: - - The use of ``==`` when defining dependencies for published - distributions is strongly discouraged as it greatly complicates the - deployment of security fixes. The strict version comparison operator - is intended primarily for use when defining dependencies for repeatable - *deployments of applications* while using a shared distribution index. - - -Handling of pre-releases ------------------------- - -Pre-releases of any kind, including developmental releases, are implicitly -excluded from all version specifiers, *unless* a pre-release or developmental -release is explicitly mentioned in one of the clauses. For example, these -specifiers implicitly exclude all pre-releases and development -releases of later versions:: - - 2.2 - >= 1.0 - -While these specifiers would include at least some of them:: - - 2.2.dev0 - 2.2, != 2.3b2 - >= 1.0a1 - >= 1.0c1 - >= 1.0, != 1.0b2 - >= 1.0, < 2.0.dev123 - -Dependency resolution tools should use the above rules by default, but -should also allow users to request the following alternative behaviours: - -* accept already installed pre-releases for all version specifiers -* retrieve and install available pre-releases for all version specifiers - -Dependency resolution tools may also allow the above behaviour to be -controlled on a per-distribution basis. - -Post-releases and purely numeric releases receive no special treatment - -they are always included unless explicitly excluded. - - -Examples --------- - -* ``Requires-Dist: zope.interface (3.1)``: version 3.1 or later, but not - version 4.0 or later. Excludes pre-releases and developmental releases. -* ``Requires-Dist: zope.interface (3.1.0)``: version 3.1.0 or later, but not - version 3.2.0 or later. Excludes pre-releases and developmental releases. -* ``Requires-Dist: zope.interface (==3.1)``: any version that starts - with 3.1, excluding pre-releases and developmental releases. -* ``Requires-Dist: zope.interface (3.1.0,!=3.1.3)``: version 3.1.0 or later, - but not version 3.1.3 and not version 3.2.0 or later. Excludes pre-releases - and developmental releases. For this particular project, this means: "any - version of the 3.1 series but not 3.1.3". This is equivalent to: - ``>=3.1, !=3.1.3, <3.2``. -* ``Requires-Python: 2.6``: Any version of Python 2.6 or 2.7. It - automatically excludes Python 3 or later. -* ``Requires-Python: 3.2, < 3.3``: Specifically requires Python 3.2, - excluding pre-releases. -* ``Requires-Python: 3.3a1``: Any version of Python 3.3+, including - pre-releases like 3.4a1. - - -Depending on distributions that use non-compliant version schemes ------------------------------------------------------------------ - -A distribution using this version of the metadata standard may need to depend -on another distribution using an earlier version of the metadata standard -and a non-compliant versioning scheme. - -The normal ``Requires-Dist`` and ``Setup-Requires-Dist`` fields can be used -for such dependencies, so long as the dependency itself can be expressed -using a compliant version specifier. - -For more exotic dependencies, a metadata extension would be needed in order -to express the dependencies accurately while still obeying the restrictions -on standard version specifiers. The ``Requires-External`` field may also -be used, but would not be as amenable to automatic processing. + This field replaces the old Platform, Requires-Platform and + Requires-Python fields and has been redesigned with environment + marker based semantics that should make it possible to reliably flag, + for example, Unix specific or Windows specific distributions, as well + as Python 2 only and Python 3 only distributions. + + +Metabuild system +================ + +The ``metabuild_hooks`` field is used to define various operations that +may be invoked on a distribution in a platform independent manner. + +The metabuild system currently defines three operations as part of the +deployment of a distribution: + +* Installing to a deployment system +* Uninstalling from a deployment system +* Running the distribution's test suite on a deployment system (hence the + ``test`` runtime extra) + +Distributions may define handles for each of these operations as an +"entry point", a reference to a Python callable, with the module name +separated from the reference within the module by a colon (``:``). + +Example metabuild hooks:: + + "metabuild_hooks": { + "postinstall": "myproject.build_hooks:postinstall", + "preuininstall": "myproject.build_hooks:preuninstall", + "test_installed_dist": "some_test_harness.metabuild_hook" + } + +Build and installation tools MAY offer additional operations beyond the +core metabuild operations. These operations SHOULD be composed from the +defined metabuild operations where appropriate. + +Build and installation tools SHOULD support the legacy ``setup.py`` based +commands for metabuild operations not yet defined as metabuild hooks. + +The metabuild hooks are gathered together into a single top level +``metabuild_hooks`` field. The individual hooks are: + +* ``postinstall``: run after the distribution has been installed to a + target deployment system (or after it has been upgraded). If the hook is + not defined, it indicates no distribution specific actions are needed + following installation. +* ``preuninstall``: run before the distribution has been uninstalled from a + deployment system (or before it is upgraded). If the hook is not defined, + it indicates no distribution specific actions are needed prior to + uninstallation. +* ``test_installed_dist``: test an installed distribution is working. If the + hook is not defined, it indicates the distribution does not support + execution of the test suite after deployment. + +The expected signatures of these hooks are as follows:: + + def postinstall(current_meta, previous_meta=None): + """Run following installation or upgrade of the distribution + + *current_meta* is the distribution metadata for the version now + installed on the current system + *previous_meta* is either missing or ``None`` (indicating a fresh + install) or else the distribution metadata for the version that + was previously installed (indicating an upgrade or downgrade). + """ + + def preuninstall(current_meta, next_meta=None): + """Run prior to uninstallation or upgrade of the distribution + + *current_meta* is the distribution metadata for the version now + installed on the current system + *next_meta* is either missing or ``None`` (indicating complete + uninstallation) or else the distribution metadata for the version + that is about to be installed (indicating an upgrade or downgrade). + """ + + def test_installed_dist(current_meta): + """Check an installed distribution is working correctly + + Note that this check should always be non-destructive as it may be + invoked automatically by some tools. + + Requires that the distribution's test dependencies be installed + (indicated by the ``test`` runtime extra). + + Returns ``True`` if the check passes, ``False`` otherwise. + """ + +Metabuild hooks MUST be called with at least abbreviated metadata, and MAY +be called with full metadata. + +Where necessary, metabuild hooks check for the presence or absence of +optional dependencies defined as extras using the same techniques used +during normal operation of the distribution (for example, checking for +import failures for optional dependencies). + + +Metadata Extensions +=================== + +Extensions to the metadata may be present in a mapping under the +'extensions' key. The keys must meet the same restrictions as +distribution names, while the values may be any type natively supported +in JSON:: + + "extensions" : { + "chili" : { "type" : "Poblano", "heat" : "Mild" }, + "languages" : [ "French", "Italian", "Hebrew" ] + } + +To avoid name conflicts, it is recommended that distribution names be used +to identify metadata extensions. This practice will also make it easier to +find authoritative documentation for metadata extensions. + + +Extras (optional dependencies) +============================== + +Extras are additional dependencies that enable an optional aspect +of the distribution, generally corresponding to a ``try: import +optional_dependency ...`` block in the code. To support the use of the +distribution with or without the optional dependencies they are listed +separately from the distribution's core dependencies and must be requested +explicitly, either in the dependency specifications of another distribution, +or else when issuing a command to an installation tool. + +The names of extras MUST abide by the same restrictions as those for +distribution names. + +Example of a distribution with optional dependencies:: + + "name": "ComfyChair", + "extras": ["warmup", "c-accelerators"] + "may_require": [ + { + "dependencies": ["SoftCushions"], + "extra": "warmup" + } + ] + "build_may_require": [ + { + "dependencies": ["cython"], + "extra": "c-accelerators" + } + ] + +Other distributions require the additional dependencies by placing the +relevant extra names inside square brackets after the distribution name when +specifying the dependency. + +Extra specifications MUST support the following additional syntax: + +* Multiple features can be requested by separating them with a comma within + the brackets. +* All explicitly defined extras may be requested with the ``*`` wildcard + character. Note that this does NOT request the implicitly defined + ``test`` extra - that must always be requested explicitly when it is + desired. +* Extras may be explicitly excluded by prefixing their name with a hyphen. + +Command line based installation tools SHOULD support this same syntax to +allow extras to be requested explicitly. + +The full set of dependency requirements is then based on the top level +dependencies, along with those of any requested extras. + +Example:: + + "requires": ["ComfyChair[warmup]"] + -> requires ``ComfyChair`` and ``SoftCushions`` at run time + + "requires": ["ComfyChair[*]"] + -> requires ``ComfyChair`` and ``SoftCushions`` at run time, but + will also pick up any new optional dependencies other than those + needed solely to run the tests Environment markers =================== -An **environment marker** is a marker that can be added at the end of a -field after a semi-colon (";"), to add a condition about the execution -environment. - -Here are some example of fields using such markers:: - - Requires-Dist: pywin32 (>1.0); sys.platform == 'win32' - Requires-Dist: foo (1,!=1.3); platform.machine == 'i386' - Requires-Dist: bar; python_version == '2.4' or python_version == '2.5' - Requires-External: libxslt; 'linux' in sys.platform +An **environment marker** describes a condition about the current execution +environment. They are used to indicate when certain dependencies are only +required in particular environments, and to indicate supported platforms +for distributions with additional constraints beyond the availability of a +Python runtime. + +Here are some examples of such markers:: + + "sys_platform == 'win32'" + "platform_machine == 'i386'" + "python_version == '2.4' or python_version == '2.5'" + "'linux' in sys_platform" + +And here's an example of some conditional metadata for a distribution that +requires PyWin32 both at runtime and buildtime when using Windows:: + + "name": "ComfyChair", + "may_require": [ + { + "dependencies": ["pywin32 (>1.0)"], + "environment": "sys.platform == 'win32'" + } + ] + "build_may_require": [ + { + "dependencies": ["pywin32 (>1.0)"], + "environment": "sys.platform == 'win32'" + } + ] The micro-language behind this is a simple subset of Python: it compares only strings, with the ``==`` and ``in`` operators (and their opposites), @@ -1180,73 +1486,35 @@ MARKER: EXPR [(and|or) EXPR]* EXPR: ("(" MARKER ")") | (SUBEXPR [(in|==|!=|not in)?SUBEXPR]) -where ``SUBEXPR`` belongs to any of the following (the details after the -colon in each entry define the value represented by that subexpression): - -* ``python_version``: '%s.%s' % (sys.version_info[0], sys.version_info[1]) -* ``python_full_version``: sys.version.split()[0] -* ``os.name````: os.name -* ``sys.platform````: sys.platform -* ``platform.version``: platform.version() -* ``platform.machine``: platform.machine() -* ``platform.python_implementation``: = platform.python_implementation() -* ``extra``: (name of requested feature) or None -* ``'text'``: a free string, like ``'2.4'``, or ``'win32'`` - -Notice that ``in`` and ``not in`` are restricted to strings, meaning that it -is not possible to use other sequences like tuples or lists on the right -side. - -The fields that benefit from this marker are: - -* ``Requires-Python`` -* ``Requires-External`` -* ``Requires-Dist`` -* ``Provides-Dist`` -* ``Classifier`` - - -Optional features -================= - -Distributions may use the ``Provides-Extra`` field to declare additional -features provided through "extra" dependencies, usually corresponding to a -``try: import x ...`` block. Environment markers may be used to indicate -that particular dependencies are needed only when a particular optional -feature has been requested. - -Other distributions require the feature by placing it inside -square brackets after the distribution name when declaring the -dependency. Multiple features can be requisted by separating them with -a comma within the brackets. - -The full set of dependency requirements is then the union of the sets -created by first evaluating the `Requires-Dist` fields with `extra` -set to `None` and then to the name of each requested feature. - -Example:: - - Requires-Dist: beaglevote[pdf] - -> requires beaglevote, reportlab at run time - - Setup-Requires-Dist: beaglevote[test, doc] - -> requires beaglevote, sphinx, nose at setup time - -It is an error to request a feature name that has not been declared with -`Provides-Extra` but it is legal to specify `Provides-Extra` without -referencing it in any `Requires-Dist`. - -In the example, if ``beaglevote`` grew the ability to generate PDF -without extra dependencies, it should continue to ``Provides-Extra: -pdf`` for the benefit of dependent distributions. - -The following feature names are implicitly defined for all distributions: - -- `test`: dependencies that are needed in order to run automated tests -- `doc`: dependencies that are needed in order to generate documentation - -Listing these implicit features explicitly in a ``Provides-Extra`` field is -permitted, but not required. +where ``SUBEXPR`` is either a Python string (such as ``'2.4'``, or +``'win32'``) or one of the following marker variables: + +* ``python_version``: ``'{0.major}.{0.minor}'.format(sys.version_info)`` +* ``python_full_version``: see definition below +* ``os_name````: ``os.name`` +* ``sys_platform````: ``sys.platform`` +* ``platform_version``: ``platform.version()`` +* ``platform_machine``: ``platform.machine()`` +* ``platform_python_implementation``: ``platform.python_implementation()`` + +Note that all subexpressions are restricted to strings or one of the +marker variable names, meaning that it is not possible to use other +sequences like tuples or lists on the right side of the ``in`` and +``not in`` operators. + +Unlike Python, chaining of comparison operations is NOT permitted in +environment markers. + +The ``python_full_version`` marker variable is derived from +``sys.version_info()`` in accordance with the following algorithm:: + + def format_full_version(): + info = sys.version_info + version = '{0.major}.{0.minor}.{0.micro}'.format(info) + kind = info.releaselevel + if kind != 'final': + version += kind[0] + str(info.serial) + return version Updating the metadata specification @@ -1266,67 +1534,52 @@ * Metadata-Version is now 2.0, with semantics specified for handling version changes -* Most fields are now optional +* The increasingly complex ad hoc "Key: Value" format has been replaced by + a more structured JSON compatible format that is easily represented as + Python dictionaries, strings, lists. + +* Most fields are now optional and filling in dummy data for omitted fields + is explicitly disallowed * Explicit permission for in-place clarifications without releasing a new version of the specification -* General reformatting of the PEP to make it easier to read - -* Values are now expected to be UTF-8 - -* Changed the version scheme - - * added the new ``Private-Version`` field - * changed the top level sort position of the ``.devN`` suffix - * allowed single value version numbers - * explicit exclusion of leading or trailing whitespace - * explicit criterion for the exclusion of date based versions - * incorporated the version scheme directly into the PEP - -* Changed interpretation of version specifiers - - * implicitly exclude pre-releases unless explicitly requested - * treat post releases the same way as unqualified releases - -* Discuss ordering and dependencies across metadata versions - -* Clarify use of parentheses for grouping in environment marker - pseudo-grammar - -* Support for packaging, build and installation dependencies - - * the new ``Setup-Requires-Dist`` field - -* Optional feature mechanism - - * the new ``Provides-Extra`` field - * ``extra`` expression defined for environment markers - * optional feature support in ``Requires-Dist`` - -* Metadata extension mechanism - - * the new ``Extension`` field and extension specific fields +* The PEP now attempts to provide more of an explanation of *why* the fields + exist and how they are intended to be used, rather than being a simple + description of the permitted contents + +* Changed the version scheme to be based on PEP 440 rather than PEP 386 + +* Added the build label mechanism as described in PEP 440 + +* Support for different development, build, test and deployment dependencies + +* The "Extras" optional dependency mechanism + +* A well-defined metadata extension mechanism + +* Metabuild hook system + +* Clarify and simplify various aspects of environment markers: + + * allow use of parentheses for grouping in the pseudo-grammar + * consistently use underscores instead of periods in the variable names + * clarify that chained comparisons are not permitted + +* More flexible system for defining contact points and contributors + +* Defined a recommended set of project URLs + +* New system for defining supported environments * Updated obsolescence mechanism - * the new ``Obsoleted-By`` field - * the ``Obsoletes-Dist`` field has been removed - -* Simpler description format - - * the ``Description`` field is now deprecated - * A payload (containing the description) may appear after the headers. - -* Other changed fields: - - - ``Requires-Python`` (explicitly flagged as multiple use) - - ``Project-URL`` (commas permitted in labels) - -* Clarified fields: - - - ``Provides-Dist`` - - ``Keywords`` +* Added "License URL" field + +* Explicit declaration of description markup format + +* With all due respect to Charles Schulz and Peanuts, many of the examples + have been updated to be more `thematically appropriate`_ for Python ;) The rationale for major changes is given in the following sections. @@ -1342,8 +1595,8 @@ may include changes that are not compatible with existing tools. The major version number of the specification has been incremented -accordingly, as interpreting PEP 426 metadata in accordance with earlier -metadata specifications is unlikely to give the expected behaviour. +accordingly, as interpreting PEP 426 metadata obviously cannot be +interpreted in accordance with earlier metadata specifications. Whenever the major version number of the specification is incremented, it is expected that deployment will take some time, as either metadata @@ -1355,219 +1608,158 @@ Existing tools won't abide by this guideline until they're updated to support the new metadata standard, so the new semantics will first take effect for a hypothetical 2.x -> 3.0 transition. For the 1.x -> 2.0 -transition, it is recommended that tools continue to produce the +transition, we will use the approach where tools continue to produce the existing supplementary files (such as ``entry_points.txt``) in addition to any equivalents specified using the new features of the standard metadata format (including the formal extension mechanism). -Standard encoding and other format clarifications -------------------------------------------------- - -Several aspects of the file format, including the expected file encoding, -were underspecified in previous versions of the metadata standard. To -make it easier to develop interoperable tools, these details are now -explicitly specified. +Switching to a JSON compatible format +------------------------------------- + +The old "Key:Value" format was becoming increasingly limiting, with various +complexities like parsers needing to know which fields were permitted to +occur more than once, which fields supported the environment marker +syntax (with an optional ``";"`` to separate the value from the marker) and +eventually even the option to embed arbitrary JSON inside particular +subfields. + +The old serialisation format also wasn't amenable to easy conversion to +standard Python data structures for use in the new metabuild hook APIs, or +in future extensions to the importer APIs to allow them to provide +information for inclusion in the installation database. + +Accordingly, we've taken the step of switching to a JSON-compatible metadata +format. This works better for APIs and is much easier for tools to parse and +generate correctly. Changing the name of the metadata file also makes it +easy to distribute 1.x and 2.x metadata in parallel, greatly simplifying +several aspects of the migration to the new metadata format. Changing the version scheme --------------------------- -The new ``Private-Version`` field is intended to make it clearer that the -constraints on public version identifiers are there primarily to aid in -the creation of reliable automated dependency analysis tools. Projects -are free to use whatever versioning scheme they like internally, so long -as they are able to translate it to something the dependency analysis tools -will understand. - -The key change in the version scheme in this PEP relative to that in -PEP 386 is to sort top level developmental releases like ``X.Y.devN`` ahead -of alpha releases like ``X.Ya1``. This is a far more logical sort order, as -projects already using both development releases and alphas/betas/release -candidates do not want their developmental releases sorted in -between their release candidates and their full releases. There is no -rationale for using ``dev`` releases in that position rather than -merely creating additional release candidates. - -The updated sort order also means the sorting of ``dev`` versions is now -consistent between the metadata standard and the pre-existing behaviour -of ``pkg_resources`` (and hence the behaviour of current installation -tools). - -Making this change should make it easier for affected existing projects to -migrate to the latest version of the metadata standard. - -Another change to the version scheme is to allow single number -versions, similar to those used by non-Python projects like Mozilla -Firefox, Google Chrome and the Fedora Linux distribution. This is actually -expected to be more useful for version specifiers (allowing things like -the simple ``Requires-Python: 3`` rather than the more convoluted -``Requires-Python: >= 3.0, < 4``), but it is easier to allow it for both -version specifiers and release numbers, rather than splitting the -two definitions. - -The exclusion of leading and trailing whitespace was made explicit after -a couple of projects with version identifiers differing only in a -trailing ``\n`` character were found on PyPI. - -The exclusion of major release numbers that looks like dates was implied -by the overall text of PEP 386, but not clear in the definition of the -version scheme. This exclusion has been made clear in the definition of -the release component. - -Finally, as the version scheme in use is dependent on the metadata -version, it was deemed simpler to merge the scheme definition directly into -this PEP rather than continuing to maintain it as a separate PEP. - -`Appendix B` shows detailed results of an analysis of PyPI distribution -version information, as collected on 19th February, 2013. This analysis -compares the behaviour of the explicitly ordered version schemes defined in -this PEP and PEP 386 with the de facto standard defined by the behaviour -of setuptools. These metrics are useful, as the intent of both PEPs is to -follow existing setuptools behaviour as closely as is feasible, while -still throwing exceptions for unorderable versions (rather than trying -to guess an appropriate order as setuptools does). - -Overall, the percentage of compatible distributions improves from 97.7% -with PEP 386 to 98.7% with this PEP. While the number of projects affected -in practice was small, some of the affected projects are in widespread use -(such as Pinax and selenium). The surprising ordering discrepancy also -concerned developers and acted as an unnecessary barrier to adoption of -the new metadata standard. - -The data also shows that the pre-release sorting discrepancies are seen -only when analysing *all* versions from PyPI, rather than when analysing -public versions. This is largely due to the fact that PyPI normally reports -only the most recent version for each project (unless maintainers -explicitly configure their project to display additional versions). However, -installers that need to satisfy detailed version constraints often need -to look at all available versions, as they may need to retrieve an older -release. - -Even this PEP doesn't completely eliminate the sorting differences relative -to setuptools: - -* Sorts differently (after translations): 38 / 28194 (0.13 %) -* Sorts differently (no translations): 2 / 28194 (0.01 %) - -The two remaining sort order discrepancies picked up by the analysis are due -to a pair of projects which have PyPI releases ending with a carriage -return, alongside releases with the same version number, only *without* the -trailing carriage return. - -The sorting discrepancies after translation relate mainly to differences -in the handling of pre-releases where the standard mechanism is considered -to be an improvement. For example, the existing pkg_resources scheme will -sort "1.1beta1" *after* "1.1b2", whereas the suggested standard translation -for "1.1beta1" is "1.1b1", which sorts *before* "1.1b2". Similarly, the -pkg_resources scheme will sort "-dev-N" pre-releases differently from -"devN" pre-releases when they occur within the same release, while the -standard scheme will normalize both representations to ".devN" and sort -them by the numeric component. - - -A more opinionated description of the versioning scheme -------------------------------------------------------- - -As in PEP 386, the primary focus is on codifying existing practices to make -them more amenable to automation, rather than demanding that existing -projects make non-trivial changes to their workflow. However, the -standard scheme allows significantly more flexibility than is needed -for the vast majority of simple Python packages (which often don't even -need maintenance releases - many users are happy with needing to upgrade to a -new feature release to get bug fixes). - -For the benefit of novice developers, and for experienced developers -wishing to better understand the various use cases, the specification -now goes into much greater detail on the components of the defined -version scheme, including examples of how each component may be used -in practice. - -The PEP also explicitly guides developers in the direction of -semantic versioning (without requiring it), and discourages the use of -several aspects of the full versioning scheme that have largely been -included in order to cover esoteric corner cases in the practices of -existing projects and in repackaging software for Linux distributions. - - -Changing the interpretation of version specifiers -------------------------------------------------- - -The previous interpretation of version specifiers made it very easy to -accidentally download a pre-release version of a dependency. This in -turn made it difficult for developers to publish pre-release versions -of software to the Python Package Index, as even marking the package as -hidden wasn't enough to keep automated tools from downloading it, and also -made it harder for users to obtain the test release manually through the -main PyPI web interface. - -The previous interpretation also excluded post-releases from some version -specifiers for no adequately justified reason. - -The updated interpretation is intended to make it difficult to accidentally -accept a pre-release version as satisfying a dependency, while allowing -pre-release versions to be explicitly requested when needed. - -The "some forward compatibility assumed" default version constraint is -taken directly from the Ruby community's "pessimistic version constraint" -operator [4]_ to allow projects to take a cautious approach to forward -compatibility promises, while still easily setting a minimum required -version for their dependencies. It is made the default behaviour rather -than needing a separate operator in order to explicitly discourage -overspecification of dependencies by library developers. The explicit -comparison operators remain available to cope with dependencies with -unreliable or non-existent backwards compatibility policies. - - -Packaging, build and installation dependencies +See PEP 440 for a detailed rationale for the various changes made to the +versioning scheme. + + +Build labels +------------ + +See PEP 440 for the rationale behind the addition of this field. + + +Development, build and deployment dependencies ---------------------------------------------- -The new ``Setup-Requires-Dist`` field allows a distribution to indicate when -a dependency is needed to package, build or install the distribution, rather -than being needed to run the software after installation. - -This should allow distribution tools to effectively support a wider range of -distribution requirements. - - -Support for optional features of distributions ----------------------------------------------- - -The new ``Provides-Extra`` field allows distributions to declare optional -features, and to use environment markers to reduce their dependencies -when those features are not requested. Environment markers may also be -used to require a later version of Python when particular features are -requested. - -The ``Requires-Dist`` and ``Setup-Requires-Dist`` fields then allow -distributions to require optional features of other distributions. - -The ``test`` and ``doc`` features are implicitly defined for all -distributions, as one key motivation for this feature is to encourage -distributions to explicitly declare the dependencies needed to run -their automatic tests, or build their documentation, without demanding those -dependencies be present in order to merely install or use the software. +The separation of the ``requires``, ``build_requires`` and ``dev_requires`` +fields allow a distribution to indicate whether a dependency is needed +specifically to develop, build or deploy the distribution. + +As distribution metadata improves, this should allow much greater control +over where particular dependencies end up being installed . + + +Support for optional dependencies for distributions +--------------------------------------------------- + +The new extras system allows distributions to declare optional +features, and to use the ``may_require`` and ``build_may_require`` fields +to indicate when particular dependencies are needed only to support those +features. It is derived from the equivalent system that is already in +widespread use as part of ``setuptools`` and allows that aspect of the +legacy ``setuptools`` metadata to be accurately represented in the new +metadata format. + +The ``test`` extra is implicitly defined for all distributions, as it +ties in with the new metabuild hook offering a standard way to request +execution of a distribution's test suite. Identifying test suite +dependencies is already one of the most popular uses of the extras system +in ``setuptools``. Support for metadata extensions ------------------------------- -The new ``Extension`` field effectively allows sections of the metadata +The new extension effectively allows sections of the metadata namespace to be delegated to other distributions, while preserving a standard overal format metadata format for easy of processing by distribution tools that do not support a particular extension. -It also works well in combination with the new ``Setup-Requires-Dist`` field +It also works well in combination with the new ``build_requires`` field to allow a distribution to depend on tools which *do* know how to handle -the chosen extension, and the new optional features mechanism, allowing -support for particular extensions to be provided as optional features. +the chosen extension, and the new extras mechanism, allowing support for +particular extensions to be provided as optional features. + + +Support for metabuild hooks +--------------------------- + +The new metabuild system is designed to allow the wheel format to fully +replace direct installation on deployment targets, by allows projects like +Twisted to still execute code following installation from a wheel file. + +Falling back to invoking ``setup.py`` directly rather than using a +metabuild hook will remain an option when relying on version 1.x metadata, +and is also used as the interim solution for installation from source +archives. + +The ``test_installed_dist`` metabuild hook is included as a complement to +the ability to explicitly specify test dependencies. + + +Changes to environment markers +------------------------------ + +The changes to environment markers were just clarifications and +simplifications to make them easier to use. + +The arbitrariness of the choice of ``.`` and ``_`` in the different +variables was addressed by standardising on ``_`` (as these are predefined +variables rather than live references into the Python module namespace) + +The use of parentheses for grouping and the disallowance of chained +comparisons were added to address some underspecified behaviour in the +previous version of the specification. + + +Updated contact information +--------------------------- + +The switch to JSON made it possible to provide a more flexible +system for defining multiple contact points for a project, as well as +listing other contributors. + +The ``type`` concept allows for preservation of the distinction between +the original author of a project, and a lead maintainer that takes over +at a later date. + + +Changes to project URLs +----------------------- + +In addition to allow arbitrary strings as project URL labels, the new +metadata standard also defines a recommend set of four URL labels for +a distribution's home page, documentation, source control and issue tracker. + + +Changes to platform support +--------------------------- + +The new environment marker system makes it possible to define supported +platforms in a way that is actually amenable to automated processing. This +has been used to replace several older fields with poorly defined semantics. + +For the moment, the old ``Requires-External`` field has been removed +entirely. Possible replacements may be explored through the metadata +extension mechanism. Updated obsolescence mechanism ------------------------------ The marker to indicate when a project is obsolete and should be replaced -has been moved to the obsolete project (the new ``Obsoleted-By`` field), +has been moved to the obsolete project (the new ``obsoleted_by`` field), replacing the previous marker on the replacement project (the removed ``Obsoletes-Dist`` field). @@ -1578,19 +1770,228 @@ is not widely supported, and so removing it does not present any significant barrier to tools and projects adopting the new metadata format. - -Simpler description format +Explicit markup for description +------------------------------- + +Currently, PyPI attempts to detect the markup format by rendering it as +reStructuredText, and if that fails, treating it as plain text. Allowing +the intended format to be stated explicitly will allow this guessing to be +removed, and more informative error reports to be provided to users when +a rendering error occurs. + +This is especially necessary since PyPI applies additional restrictions to +the rendering process for security reasons, thus a description that renders +correctly on a developer's system may still fail to render on the server. + + +Deferred features +================= + +Several potentially useful features have been deliberately deferred in +order to better prioritise our efforts in migrating to the new metadata +standard. These all reflect information that may be nice to have in the +new metadata, but which can be readily added in metadata 2.1 without +breaking any use cases already supported by metadata 2.0. + +Once the ``pypi``, ``setuptools``, ``pip`` and ``distlib`` projects +support creation and consumption of metadata 2.0, then we may revisit +the creation of metadata 2.1 with these additional features. + +.. note:: + + Given the nature of this PEP as an interoperability specification, + this section will probably be removed before the PEP is accepted. + However, it's useful to have it here while discussion is ongoing. + + +String methods in environment markers +------------------------------------- + +Supporting at least ".startswith" and ".endswith" string methods in +environment markers would allow some conditions to be written more +naturally. For example, ``"sys.platform.startswith('win')"`` is a +somewhat more intuitive way to mark Windows specific dependencies, +since ``"'win' in sys.platform"`` is incorrect thanks to ``cygwin`` +and the fact that 64-bit Windows still shows up as ``win32`` is more +than a little strange. + + +Module listing +-------------- + +A top level ``"module"`` key, referencing a list of strings, with each +giving the fully qualified name of a public package or module provided +by the distribution. + +A flat list would be used in order to correctly accommodate namespace +packages (where a distribution may provide subpackages or submodules without +explicitly providing the parent namespace package). + +Example:: + + "modules": [ + "comfy.chair" + ] + +Explicitly providing a list of public module names will likely help +with enabling features in RPM like "Requires: python(requests)", as well +as providing richer static metadata for analysis from PyPI. + +However, this is just extra info that doesn't impact installing from wheels, +so it is a good candidate for postponing to metadata 2.1. + + +Additional metabuild hooks -------------------------- -Distribution descriptions are often quite long, sometimes including a -short guide to using the module. Moving them into the file payload allows -them to be formatted neatly as reStructuredText without needing to -carefully avoid the introduction of a blank line that would terminate -the header section. - -The ``Description`` header is deprecated rather than removed to support -easier conversion of existing tools and projects to the new metadata -format. +The following draft metabuild operations have been deferred for now: + +* Generating the metadata file on a development system +* Generating a source archive on a development system +* Generating a binary archive on a build system + +Metadata 2.0 deliberately focuses on wheel based installation, leaving +tarball and sdist based installation to use the existing ``setup.py`` +based ``distutils`` command interface. + +In the meantime, the above four operations will continue to be handled +through the ``distutils``/``setuptools`` command system: + +* ``python setup.py dist_info`` +* ``python setup.py sdist`` +* ``python setup.py bdist_wheel`` + +The following additional metabuild hooks may be added in metadata 2.1 to +cover these operations without relying on ``setup.py``: + +* ``make_dist_info``: generate the source archive's dist_info directory +* ``make_sdist``: construct a source archive +* ``build_wheel``: construct a binary wheel archive from an sdist source + archive + +Tentative signatures have been designed for those hooks, but they will +not be pursued further until 2.1 (note that the current signatures for +the hooks do *not* adequately handle the "extras" concept):: + + def make_dist_info(source_dir, info_dir): + """Generate the contents of dist_info for an sdist archive + + *source_dir* points to a source checkout or unpacked tarball + *info_dir* is the destination where the sdist metadata files should + be written + + Returns the distribution metadata as a dictionary. + """ + + def make_sdist(source_dir, contents_dir, info_dir): + """Generate the contents of an sdist archive + + *source_dir* points to a source checkout or unpacked tarball + *contents_dir* is the destination where the sdist contents should be + written (note that archiving the contents is the responsibility of + the metabuild tool rather than the hook function) + *info_dir* is the destination where the sdist metadata files should + be written + + Returns the distribution metadata as a dictionary. + """ + + def build_wheel(sdist_dir, contents_dir, info_dir, compatibility=None): + """Generate the contents of a wheel archive + + *source_dir* points to an unpacked source archive + *contents_dir* is the destination where the wheel contents should be + written (note that archiving the contents is the responsibility of + the metabuild tool rather than the hook function) + *info_dir* is the destination where the wheel metadata files should + be written + *compatibility* is an optional PEP 425 compatibility tag indicating + the desired target compatibility for the build. If the tag cannot + be satisfied, the hook should throw ``ValueError``. + + Returns the actual compatibility tag for the build + """ + + +Rejected Features +================= + +The following features have been explicitly considered and rejected as +introducing too much additional complexity for too small a gain in +expressiveness. + +.. note:: + + Given the nature of this PEP as an interoperability specification, + this section will probably be removed before the PEP is accepted. + However, it's useful to have it here while discussion is ongoing. + + +Detached metadata +----------------- + +Rather than allowing some large items (such as the description field) to +be distributed separately, this PEP instead defines two metadata subsets +that should support more reasonable caching and API designs (for example, +only the essential dependency resolution metadata would be distributed +through TUF, and it is entirely possible the updated sdist, wheel and +installation database specs will use the abbreviated metadata, leaving +the full metadata as the province of index servers). + + +Alternative dependencies +------------------------ + +An earlier draft of this PEP considered allowing lists in place of the +usual strings in dependency specifications to indicate that there aren +multiple ways to satisfy a dependency. + +If at least one of the individual dependencies was already available, then +the entire dependency would be considered satisfied, otherwise the first +entry would be added to the dependency set. + +Alternative dependency specification example:: + + ["Pillow", "PIL"] + ["mysql", "psycopg2 (>= 4)", "sqlite3"] + +However, neither of the given examples is particularly compelling, +since Pillow/PIL style forks aren't common, and the database driver use +case would arguably be better served by an SQL Alchemy defined "supported +database driver" metadata extension where a project depends on SQL Alchemy, +and then declares in the extension which database drivers are checked for +compatibility by the upstream project (similar to the advisory +``supports-platform`` field in the main metadata). + +We're also getting better support for "virtual provides" in this version of +the metadata standard, so this may end up being an installer and index +server problem to better track and publish those. + + +Compatible release comparisons in environment markers +----------------------------------------------------- + +PEP 440 defines a rich syntax for version comparisons that could +potentially be useful with ``python_version`` and ``python_full_version`` +in environment markers. However, allowing the full syntax would mean +environment markers are no longer a Python subset, while allowing +only some of the comparisons would introduce yet another special case +to handle. + +Given that environment markers are only used in cases where a higher level +"or" is implied by the metadata structure, it seems easier to require the +use of multiple comparisons against specific Python versions for the rare +cases where this would be useful. + + +Conditional provides +-------------------- + +Under the revised metadata design, conditional "provides" based on runtime +features or the environment would go in a separate "may_provide" field. +However, I'm not convinced there's a great use case for that, so the idea +is rejected unless someone can present a compelling use case (and even then +the idea wouldn't be reconsidered until metadata 2.1 at the earliest). References @@ -1607,145 +2008,14 @@ .. [1] reStructuredText markup: http://docutils.sourceforge.net/ -.. _`Python Package Index`: http://pypi.python.org/pypi/ +.. _Python Package Index: http://pypi.python.org/pypi/ .. [2] PEP 301: http://www.python.org/dev/peps/pep-0301/ -.. [3] Version compatibility analysis script: - http://hg.python.org/peps/file/default/pep-0426/pepsort.py - -.. [4] Pessimistic version constraint - http://docs.rubygems.org/read/chapter/16 - -Appendix A -========== - -The script used for this analysis is available at [3]_. - -Parsing and generating the Metadata 2.0 serialization format using -Python 3.3:: - - # Metadata 2.0 demo - from email.generator import Generator - from email import header - from email.parser import Parser - from email.policy import Compat32 - from email.utils import _has_surrogates - - class MetadataPolicy(Compat32): - max_line_length = 0 - continuation_whitespace = '\t' - - def _sanitize_header(self, name, value): - if not isinstance(value, str): - return value - if _has_surrogates(value): - raise NotImplementedError() - else: - return value - - def _fold(self, name, value, sanitize): - body = ((self.linesep+self.continuation_whitespace) - .join(value.splitlines())) - return ''.join((name, ': ', body, self.linesep)) - - if __name__ == "__main__": - import sys - import textwrap - - pkg_info = """\ - Metadata-Version: 2.0 - Name: package - Version: 0.1.0 - Summary: A package. - Description: Description - =========== - - A description of the package. - - """ - - m = Parser(policy=MetadataPolicy()).parsestr(pkg_info) - - m['License'] = 'GPL' - description = m['Description'] - description_lines = description.splitlines() - m.set_payload(description_lines[0] - + '\n' - + textwrap.dedent('\n'.join(description_lines[1:])) - + '\n') - del m['Description'] - - # Correct if sys.stdout.encoding == 'UTF-8': - Generator(sys.stdout, maxheaderlen=0).flatten(m) - -Appendix B -========== - -Metadata v2.0 guidelines versus setuptools:: - - $ ./pepsort.py - Comparing PEP 426 version sort to setuptools. - - Analysing release versions - Compatible: 24477 / 28194 (86.82 %) - Compatible with translation: 247 / 28194 (0.88 %) - Compatible with filtering: 84 / 28194 (0.30 %) - No compatible versions: 420 / 28194 (1.49 %) - Sorts differently (after translations): 0 / 28194 (0.00 %) - Sorts differently (no translations): 0 / 28194 (0.00 %) - No applicable versions: 2966 / 28194 (10.52 %) - - Analysing public versions - Compatible: 25600 / 28194 (90.80 %) - Compatible with translation: 1505 / 28194 (5.34 %) - Compatible with filtering: 13 / 28194 (0.05 %) - No compatible versions: 420 / 28194 (1.49 %) - Sorts differently (after translations): 0 / 28194 (0.00 %) - Sorts differently (no translations): 0 / 28194 (0.00 %) - No applicable versions: 656 / 28194 (2.33 %) - - Analysing all versions - Compatible: 24239 / 28194 (85.97 %) - Compatible with translation: 2833 / 28194 (10.05 %) - Compatible with filtering: 513 / 28194 (1.82 %) - No compatible versions: 320 / 28194 (1.13 %) - Sorts differently (after translations): 38 / 28194 (0.13 %) - Sorts differently (no translations): 2 / 28194 (0.01 %) - No applicable versions: 249 / 28194 (0.88 %) - -Metadata v1.2 guidelines versus setuptools:: - - $ ./pepsort.py 386 - Comparing PEP 386 version sort to setuptools. - - Analysing release versions - Compatible: 24244 / 28194 (85.99 %) - Compatible with translation: 247 / 28194 (0.88 %) - Compatible with filtering: 84 / 28194 (0.30 %) - No compatible versions: 648 / 28194 (2.30 %) - Sorts differently (after translations): 0 / 28194 (0.00 %) - Sorts differently (no translations): 0 / 28194 (0.00 %) - No applicable versions: 2971 / 28194 (10.54 %) - - Analysing public versions - Compatible: 25371 / 28194 (89.99 %) - Compatible with translation: 1507 / 28194 (5.35 %) - Compatible with filtering: 12 / 28194 (0.04 %) - No compatible versions: 648 / 28194 (2.30 %) - Sorts differently (after translations): 0 / 28194 (0.00 %) - Sorts differently (no translations): 0 / 28194 (0.00 %) - No applicable versions: 656 / 28194 (2.33 %) - - Analysing all versions - Compatible: 23969 / 28194 (85.01 %) - Compatible with translation: 2789 / 28194 (9.89 %) - Compatible with filtering: 530 / 28194 (1.88 %) - No compatible versions: 547 / 28194 (1.94 %) - Sorts differently (after translations): 96 / 28194 (0.34 %) - Sorts differently (no translations): 14 / 28194 (0.05 %) - No applicable versions: 249 / 28194 (0.88 %) +.. _thematically appropriate: https://www.youtube.com/watch?v=CSe38dzJYkY + +.. _TR39: http://www.unicode.org/reports/tr39/tr39-1.html#Confusable_Detection Copyright diff --git a/pep-0440.txt b/pep-0440.txt --- a/pep-0440.txt +++ b/pep-0440.txt @@ -9,82 +9,52 @@ Type: Standards Track Content-Type: text/x-rst Created: 18 Mar 2013 -Post-History: 30 Mar 2013 +Post-History: 30 Mar 2013, 27-May-2013 Replaces: 386 Abstract ======== -This PEP describes a scheme for identifying versions of Python -software distributions, and declaring dependencies on particular -versions. +This PEP describes a scheme for identifying versions of Python software +distributions, and declaring dependencies on particular versions. -This document addresses several limitations of the previous attempt at -a standardised approach to versioning, as described in PEP 345 and PEP -386. +This document addresses several limitations of the previous attempt at a +standardised approach to versioning, as described in PEP 345 and PEP 386. .. note:: - This PEP has been broken out of the metadata 2.0 specification in - PEP 426 and refers to some details that will be in the *next* - version of PEP 426. + This PEP was broken out of the metadata 2.0 specification in PEP 426. + + Unlike PEP 426, the notes that remain in this document are intended as + part of the final specification. Definitions =========== The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", -"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this +"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. -"Distributions" are deployable software components published through -an index server or otherwise made available for installation. +The following terms are to be interpreted as described in PEP 426: -"Versions" are uniquely identified snapshots of a distribution. - -"Distribution archives" are the packaged files which are used to -publish and distribute the software. "Source archives" require a -build system to be available on the target system, while "binary -archives" only require that prebuilt files be moved to the correct -location on the target system. As Python is a dynamically bound -cross-platform language, many "binary" archives will contain only pure -Python source code. - -"Build tools" are automated tools intended to run on development -systems, producing source and binary distribution archives. Build -tools may also be invoked by installation tools in order to install -software distributed as source archives rather than prebuilt binary -archives. - -"Index servers" are active distribution registries which publish -version and dependency metadata and place constraints on the permitted -metadata. - -"Publication tools" are automated tools intended to run on development -systems and upload source and binary distribution archives to index -servers. - -"Installation tools" are automated tools intended to run on production -systems, consuming source and binary distribution archives from an -index server or other designated location and deploying them to the -target system. - -"Automated tools" is a collective term covering build tools, index -servers, publication tools, installation tools and any other software -that produces or consumes distribution version and dependency -metadata. - -"Projects" refers to the developers that manage the creation of a -particular distribution. +* "Distributions" +* "Versions" +* "Build tools" +* "Index servers" +* "Publication tools" +* "Installation tools" +* "Automated tools" +* "Projects" Version scheme ============== -Distribution versions are identified by both a public version -identifier, which supports all defined version comparison operations, -and a build label, which supports only strict equality comparisons. +Distribution versions are identified by both a public version identifier, +which supports all defined version comparison operations, and a build +label, which supports only strict equality comparisons. The version scheme is used both to describe the distribution version provided by a particular distribution archive, as well as to place @@ -99,14 +69,13 @@ N[.N]+[{a|b|c|rc}N][.postN][.devN] -Public version identifiers MUST NOT include leading or trailing -whitespace. +Public version identifiers MUST NOT include leading or trailing whitespace. Public version identifiers MUST be unique within a given distribution. -Installation tools SHOULD ignore any public versions which do not -comply with this scheme. Installation tools MAY warn the user when -non-compliant or ambiguous versions are detected. +Installation tools SHOULD ignore any public versions which do not comply with +this scheme. Installation tools MAY warn the user when non-compliant +or ambiguous versions are detected. Public version identifiers are separated into up to four segments: @@ -115,22 +84,19 @@ * Post-release segment: ``.postN`` * Development release segment: ``.devN`` -Any given version will be a "release", "pre-release", "post-release" -or "developmental release" as defined in the following sections. +Any given version will be a "release", "pre-release", "post-release" or +"developmental release" as defined in the following sections. .. note:: - Some hard to read version identifiers are permitted by this scheme - in order to better accommodate the wide range of versioning - practices across existing public and private Python projects, given - the constraint that the package index is not yet sophisticated - enough to allow the introduction of a simpler, - backwards-incompatible scheme. + Some hard to read version identifiers are permitted by this scheme in + order to better accommodate the wide range of versioning practices + across existing public and private Python projects. Accordingly, some of the versioning practices which are technically - permitted by the PEP are strongly discouraged for new projects. - Where this is the case, the relevant details are noted in the - following sections. + permitted by the PEP are strongly discouraged for new projects. Where + this is the case, the relevant details are noted in the following + sections. Build labels @@ -138,42 +104,44 @@ Build labels are text strings with minimal defined semantics. -To ensure build labels can be readily incorporated in file names and -URLs, they MUST be comprised of only ASCII alphanumerics, plus signs, +To ensure build labels can be readily incorporated as part of file names +and URLs, they MUST be comprised of only ASCII alphanumerics, plus signs, periods and hyphens. In addition, build labels MUST be unique within a given distribution. +As with distribution names, all comparisons of build labels MUST be case +insensitive. + Releases -------- -A version identifier that consists solely of a release segment is -termed a "release". +A version identifier that consists solely of a release segment is termed +a "release". -The release segment consists of one or more non-negative integer -values, separated by dots:: +The release segment consists of one or more non-negative integer values, +separated by dots:: N[.N]+ Releases within a project will typically be numbered in a consistently increasing fashion. -Comparison and ordering of release segments considers the numeric -value of each component of the release segment in turn. When -comparing release segments with different numbers of components, the -shorter segment is padded out with additional zeroes as necessary. +Comparison and ordering of release segments considers the numeric value +of each component of the release segment in turn. When comparing release +segments with different numbers of components, the shorter segment is +padded out with additional zeroes as necessary. -Date based release numbers are technically compatible with this -scheme, but their use is not consistent with the expected API -versioning semantics described below. Accordingly, automated tools -SHOULD at least issue a warning when encountering a leading release -component greater than or equal to ``1980`` and MAY treat this case as -an error. +Date based release numbers are declared to be incompatible with this scheme, +as their use is not consistent with the expected API versioning semantics +described below. Accordingly, automated tools SHOULD report an error +when encountering a leading release component greater than or equal +to ``1980``. -While any number of additional components after the first are -permitted under this scheme, the most common variants are to use two -components ("major.minor") or three components ("major.minor.micro"). +While any number of additional components after the first are permitted +under this scheme, the most common variants are to use two components +("major.minor") or three components ("major.minor.micro"). For example:: @@ -189,78 +157,76 @@ 2.0 2.0.1 -A release series is any set of release numbers that start with a -common prefix. For example, ``3.3.1``, ``3.3.5`` and ``3.3.9.45`` are -all part of the ``3.3`` release series. +A release series is any set of release numbers that start with a common +prefix. For example, ``3.3.1``, ``3.3.5`` and ``3.3.9.45`` are all +part of the ``3.3`` release series. .. note:: - ``X.Y`` and ``X.Y.0`` are not considered distinct release numbers, - as the release segment comparison rules implicit expand the two - component form to ``X.Y.0`` when comparing it to any release - segment that includes three components. + ``X.Y`` and ``X.Y.0`` are not considered distinct release numbers, as + the release segment comparison rules implicit expand the two component + form to ``X.Y.0`` when comparing it to any release segment that includes + three components. Pre-releases ------------ -Some projects use an "alpha, beta, release candidate" pre-release -cycle to support testing by their users prior to a full release. +Some projects use an "alpha, beta, release candidate" pre-release cycle to +support testing by their users prior to a final release. -If used as part of a project's development cycle, these pre-releases -are indicated by including a pre-release segment in the version -identifier:: +If used as part of a project's development cycle, these pre-releases are +indicated by including a pre-release segment in the version identifier:: X.YaN # Alpha release X.YbN # Beta release - X.YcN # Release candidate (alternative notation: X.YrcN) - X.Y # Full release + X.YcN # Candidate release (alternative notation: X.YrcN) + X.Y # Final release A version identifier that consists solely of a release segment and a pre-release segment is termed a "pre-release". The pre-release segment consists of an alphabetical identifier for the -pre-release phase, along with a non-negative integer value. -Pre-releases for a given release are ordered first by phase (alpha, -beta, release candidate) and then by the numerical component within -that phase. +pre-release phase, along with a non-negative integer value. Pre-releases for +a given release are ordered first by phase (alpha, beta, release candidate) +and then by the numerical component within that phase. -Build tools, publication tools and index servers SHOULD disallow the -creation of both ``c`` and ``rc`` releases for a common release -segment, but this may need to be tolerated in order to handle some -existing legacy distributions. +Installation tools MAY accept both ``c`` and ``rc`` releases for a common +release segment in order to handle some existing legacy distributions. -Installation tools SHOULD interpret all ``rc`` versions as coming -after all ``c`` versions (that is, ``rc1`` indicates a later version -than ``c2``). Installation tools MAY warn the user when such -ambiguous versions are detected, or even reject them entirely. +Installation tools SHOULD interpret all ``rc`` versions as coming after all +``c`` versions (that is, ``rc1`` indicates a later version than ``c2``). +Installation tools MAY warn the user when such ambiguous versions are +detected, or even reject them entirely. + +Build tools, publication tools and index servers SHOULD disallow the creation +of both ``c`` and ``rc`` releases for a common release segment. Post-releases ------------- -Some projects use post-releases to address minor errors in a release -that do not affect the distributed software (for example, correcting -an error in the release notes). +Some projects use post-releases to address minor errors in a release that +do not affect the distributed software (for example, correcting an error +in the release notes). -If used as part of a project's development cycle, these post-releases -are indicated by including a post-release segment in the version -identifier:: +If used as part of a project's development cycle, these post-releases are +indicated by including a post-release segment in the version identifier:: X.Y.postN # Post-release A version identifier that includes a post-release segment without a developmental release segment is termed a "post-release". -The post-release segment consists of the string ``.post``, followed by -a non-negative integer value. Post-releases are ordered by their +The post-release segment consists of the string ``.post``, followed by a +non-negative integer value. Post-releases are ordered by their numerical component, immediately following the corresponding release, and ahead of any subsequent release. .. note:: The use of post-releases to publish maintenance releases containing - actual bug fixes is strongly discouraged. In general, it is better + actual bug fixes is strongly discouraged. In general, it is better to use a longer release number and increment the final component for each maintenance release. @@ -273,22 +239,22 @@ .. note:: Creating post-releases of pre-releases is strongly discouraged, as - it makes the version identifier difficult to parse for human - readers. In general, it is substantially clearer to simply create - a new pre-release by incrementing the numeric component. + it makes the version identifier difficult to parse for human readers. + In general, it is substantially clearer to simply create a new + pre-release by incrementing the numeric component. Developmental releases ---------------------- -Some projects make regular developmental releases, and system -packagers (especially for Linux distributions) may wish to create -early releases directly from source control which do not conflict with -later project releases. +Some projects make regular developmental releases, and system packagers +(especially for Linux distributions) may wish to create early releases +directly from source control which do not conflict with later project +releases. If used as part of a project's development cycle, these developmental -releases are indicated by including a developmental release segment in -the version identifier:: +releases are indicated by including a developmental release segment in the +version identifier:: X.Y.devN # Developmental release @@ -296,11 +262,10 @@ termed a "developmental release". The developmental release segment consists of the string ``.dev``, -followed by a non-negative integer value. Developmental releases are -ordered by their numerical component, immediately before the -corresponding release (and before any pre-releases with the same -release segment), and following any previous release (including any -post-releases). +followed by a non-negative integer value. Developmental releases are ordered +by their numerical component, immediately before the corresponding release +(and before any pre-releases with the same release segment), and following +any previous release (including any post-releases). Developmental releases are also permitted for pre-releases and post-releases:: @@ -313,27 +278,24 @@ .. note:: Creating developmental releases of pre-releases is strongly - discouraged, as it makes the version identifier difficult to parse - for human readers. In general, it is substantially clearer to - simply create additional pre-releases by incrementing the numeric - component. + discouraged, as it makes the version identifier difficult to parse for + human readers. In general, it is substantially clearer to simply create + additional pre-releases by incrementing the numeric component. - Developmental releases of post-releases are also strongly - discouraged, but they may be appropriate for projects which use the - post-release notation for full maintenance releases which may - include code changes. + Developmental releases of post-releases are also strongly discouraged, + but they may be appropriate for projects which use the post-release + notation for full maintenance releases which may include code changes. Examples of compliant version schemes ------------------------------------- The standard version scheme is designed to encompass a wide range of -identification practices across public and private Python projects. -In practice, a single project attempting to use the full flexibility -offered by the scheme would create a situation where human users had -difficulty figuring out the relative order of versions, even though -the rules above ensure all compliant tools will order them -consistently. +identification practices across public and private Python projects. In +practice, a single project attempting to use the full flexibility offered +by the scheme would create a situation where human users had difficulty +figuring out the relative order of versions, even though the rules above +ensure all compliant tools will order them consistently. The following examples illustrate a small selection of the different approaches projects may choose to identify their releases, while still @@ -357,7 +319,7 @@ 1.2.0 ... -"major.minor" versioning with alpha, beta and release candidate +"major.minor" versioning with alpha, beta and candidate pre-releases:: 0.9 @@ -369,8 +331,8 @@ 1.1a1 ... -"major.minor" versioning with developmental releases, release -candidates and post-releases for minor corrections:: +"major.minor" versioning with developmental releases, release candidates +and post-releases for minor corrections:: 0.9 1.0.dev1 @@ -394,9 +356,9 @@ automatically process distribution metadata, rather than developers of Python distributions deciding on a versioning scheme. -The release segment of version identifiers MUST be sorted in the same -order as Python's tuple sorting when the release segment is parsed as -follows:: +The release segment of version identifiers MUST be sorted in +the same order as Python's tuple sorting when the release segment is +parsed as follows:: tuple(map(int, release_segment.split("."))) @@ -409,28 +371,26 @@ .devN, aN, bN, cN, rcN, , .postN Note that `rc` will always sort after `c` (regardless of the numeric -component) although they are semantically equivalent. Tools are free -to reject this case as ambiguous and remain in compliance with the -PEP. +component) although they are semantically equivalent. Tools are free to +reject this case as ambiguous and remain in compliance with the PEP. Within an alpha (``1.0a1``), beta (``1.0b1``), or release candidate -(``1.0c1``, ``1.0rc1``), the following suffixes are permitted and MUST -be ordered as shown:: +(``1.0c1``, ``1.0rc1``), the following suffixes are permitted and MUST be +ordered as shown:: .devN, , .postN -Within a post-release (``1.0.post1``), the following suffixes are -permitted and MUST be ordered as shown:: +Within a post-release (``1.0.post1``), the following suffixes are permitted +and MUST be ordered as shown:: .devN, -Note that ``devN`` and ``postN`` MUST always be preceded by a dot, -even when used immediately following a numeric version -(e.g. ``1.0.dev456``, ``1.0.post1``). +Note that ``devN`` and ``postN`` MUST always be preceded by a dot, even +when used immediately following a numeric version (e.g. ``1.0.dev456``, +``1.0.post1``). -Within a pre-release, post-release or development release segment with -a shared prefix, ordering MUST be by the value of the numeric -component. +Within a pre-release, post-release or development release segment with a +shared prefix, ordering MUST be by the value of the numeric component. The following example covers many of the possible combinations:: @@ -454,70 +414,67 @@ Version ordering across different metadata versions --------------------------------------------------- -Metadata v1.0 (PEP 241) and metadata v1.1 (PEP 314) do not specify a -standard version identification or ordering scheme. This PEP does not -mandate any particular approach to handling such versions, but -acknowledges that the de facto standard for ordering them is the -scheme used by the ``pkg_resources`` component of ``setuptools``. +Metadata v1.0 (PEP 241) and metadata v1.1 (PEP 314) do not +specify a standard version identification or ordering scheme. This PEP does +not mandate any particular approach to handling such versions, but +acknowledges that the de facto standard for ordering them is +the scheme used by the ``pkg_resources`` component of ``setuptools``. -Software that automatically processes distribution metadata SHOULD -attempt to normalize non-compliant version identifiers to the standard -scheme, and ignore them if normalization fails. As any normalization -scheme will be implementation specific, this means that projects using -non-compliant version identifiers may not be handled consistently -across different tools, even when correctly publishing the earlier -metadata versions. +Software that automatically processes distribution metadata SHOULD attempt +to normalize non-compliant version identifiers to the standard scheme, and +ignore them if normalization fails. As any normalization scheme will be +implementation specific, this means that projects using non-compliant +version identifiers may not be handled consistently across different +tools, even when correctly publishing the earlier metadata versions. -For distributions currently using non-compliant version identifiers, -these filtering guidelines mean that it should be enough for the -project to simply switch to the use of compliant version identifiers -to ensure consistent handling by automated tools. +For distributions currently using non-compliant version identifiers, these +filtering guidelines mean that it should be enough for the project to +simply switch to the use of compliant version identifiers to ensure +consistent handling by automated tools. -Distribution users may wish to explicitly remove non-compliant -versions from any private package indexes they control. +Distribution users may wish to explicitly remove non-compliant versions from +any private package indexes they control. -For metadata v1.2 (PEP 345), the version ordering described in this -PEP SHOULD be used in preference to the one defined in PEP 386. +For metadata v1.2 (PEP 345), the version ordering described in this PEP +SHOULD be used in preference to the one defined in PEP 386. Compatibility with other version schemes ---------------------------------------- Some projects may choose to use a version scheme which requires -translation in order to comply with the public version scheme defined -in this PEP. In such cases, the build label can be used to record the -project specific version as an arbitrary label, while the translated -public version is published in the version field. +translation in order to comply with the public version scheme defined in +this PEP. In such cases, the build label can be used to +record the project specific version as an arbitrary label, while the +translated public version is published in the version field. -This allows automated distribution tools to provide consistently -correct ordering of published releases, while still allowing -developers to use the internal versioning scheme they prefer for their -projects. +This allows automated distribution tools to provide consistently correct +ordering of published releases, while still allowing developers to use +the internal versioning scheme they prefer for their projects. Semantic versioning ~~~~~~~~~~~~~~~~~~~ -`Semantic versioning`_ is a popular version identification scheme that -is more prescriptive than this PEP regarding the significance of -different elements of a release number. Even if a project chooses not -to abide by the details of semantic versioning, the scheme is worth -understanding as it covers many of the issues that can arise when -depending on other distributions, and when publishing a distribution -that others rely on. +`Semantic versioning`_ is a popular version identification scheme that is +more prescriptive than this PEP regarding the significance of different +elements of a release number. Even if a project chooses not to abide by +the details of semantic versioning, the scheme is worth understanding as +it covers many of the issues that can arise when depending on other +distributions, and when publishing a distribution that others rely on. The "Major.Minor.Patch" (described in this PEP as "major.minor.micro") -aspects of semantic versioning (clauses 1-9 in the 2.0.0-rc-1 -specification) are fully compatible with the version scheme defined in -this PEP, and abiding by these aspects is encouraged. +aspects of semantic versioning (clauses 1-9 in the 2.0.0-rc-1 specification) +are fully compatible with the version scheme defined in this PEP, and abiding +by these aspects is encouraged. Semantic versions containing a hyphen (pre-releases - clause 10) or a -plus sign (builds - clause 11) are *not* compatible with this PEP and -are not permitted in the public version field. +plus sign (builds - clause 11) are *not* compatible with this PEP +and are not permitted in the public version field. -One possible mechanism to translate such semantic versioning based -build labels to compatible public versions is to use the ``.devN`` -suffix to specify the appropriate version order. +One possible mechanism to translate such semantic versioning based build +labels to compatible public versions is to use the ``.devN`` suffix to +specify the appropriate version order. .. _Semantic versioning: http://semver.org/ @@ -525,158 +482,167 @@ DVCS based version labels ~~~~~~~~~~~~~~~~~~~~~~~~~ -Many build tools integrate with distributed version control systems -like Git and Mercurial in order to add an identifying hash to the -version identifier. As hashes cannot be ordered reliably such -versions are not permitted in the public version field. +Many build tools integrate with distributed version control systems like +Git and Mercurial in order to add an identifying hash to the version +identifier. As hashes cannot be ordered reliably such versions are not +permitted in the public version field. -As with semantic versioning, the public ``.devN`` suffix may be used -to uniquely identify such releases for publication, while the build -label is used to record the original DVCS based version label. +As with semantic versioning, the public ``.devN`` suffix may be used to +uniquely identify such releases for publication, while the build label is +used to record the original DVCS based version label. Date based versions ~~~~~~~~~~~~~~~~~~~ As with other incompatible version schemes, date based versions can be -stored in the build label field. Translating them to a compliant -public version is straightforward: use a leading "0." prefix in the -public version label, with the date based version number as the -remaining components in the release segment. +stored in the build label field. Translating them to a compliant +public version is straightforward: use a leading ``"0."`` prefix in the +public version label, with the date based version number as the remaining +components in the release segment. This has the dual benefit of allowing subsequent migration to version -numbering based on API compatibility, as well as triggering more -appropriate version comparison semantics. +numbering based on API compatibility, as well as triggering more appropriate +version comparison semantics. Version specifiers ================== -A version specifier consists of a series of version clauses, separated -by commas. For example:: +A version specifier consists of a series of version clauses, separated by +commas. For example:: - 0.9, >= 1.0, != 1.3.4.*, < 2.0 + 0.9, ~= 0.9, >= 1.0, != 1.3.4.*, < 2.0 -The comparison operator (or lack thereof) determines the kind of -version clause: +The comparison operator (or lack thereof) determines the kind of version +clause: -* No operator: `Compatible release`_ clause +* No operator: equivalent to ``~=`` +* ``~=``: `Compatible release`_ clause * ``==``: `Version matching`_ clause * ``!=``: `Version exclusion`_ clause * ``is``: `Build reference`_ clause -* ``<``, ``>``, ``<=``, ``>=``: `Ordered comparison`_ clause +* ``<=``, ``>=``: `Inclusive ordered comparison`_ clause +* ``<``, ``>``: `Exclusive ordered comparison`_ clause -The comma (",") is equivalent to a logical **and** operator: a -candidate version must match all given version clauses in order to -match the specifier as a whole. +The comma (",") is equivalent to a logical **and** operator: a candidate +version must match all given version clauses in order to match the +specifier as a whole. Whitespace between a conditional operator and the following version identifier is optional, as is the whitespace around the commas. -When multiple candidate versions match a version specifier, the -preferred version SHOULD be the latest version as determined by the -consistent ordering defined by the standard `Version scheme`_. -Whether or not pre-releases are considered as candidate versions -SHOULD be handled as described in `Handling of pre-releases`_. +When multiple candidate versions match a version specifier, the preferred +version SHOULD be the latest version as determined by the consistent +ordering defined by the standard `Version scheme`_. Whether or not +pre-releases are considered as candidate versions SHOULD be handled as +described in `Handling of pre-releases`_. Compatible release ------------------ -A compatible release clause consists solely of a version identifier -without any comparison operator. It matches any candidate version -that is expected to be compatible with the specified version. +A compatible release clause consists of either a version identifier without +any comparison operator or else the compatible release operator ``~=`` +and a version identifier. It matches any candidate version that is expected +to be compatible with the specified version. -The specified version identifier must be in the standard format -described in `Version scheme`_. +The specified version identifier must be in the standard format described in +`Version scheme`_. -For a given release identifier ``V.N``, the compatible release clause -is approximately equivalent to the pair of comparison clauses:: +For a given release identifier ``V.N``, the compatible release clause is +approximately equivalent to the pair of comparison clauses:: >= V.N, == V.* -For example, the following version clauses are equivalent:: +For example, the following groups of version clauses are equivalent:: 2.2 + ~= 2.2 >= 2.2, == 2.* 1.4.5 + ~= 1.4.5 >= 1.4.5, == 1.4.* If a pre-release, post-release or developmental release is named in a -compatible release clause as ``V.N.suffix``, then the suffix is -ignored when determining the required prefix match:: +compatible release clause as ``V.N.suffix``, then the suffix is ignored +when determining the required prefix match:: 2.2.post3 + ~= 2.2.post3 >= 2.2.post3, == 2.* 1.4.5a4 + ~= 1.4.5a4 >= 1.4.5a4, == 1.4.* -The padding rules for release segment comparisons means that the -assumed degree of forward compatibility in a compatible release clause -can be controlled by appending additional zeroes to the version -specifier:: +The padding rules for release segment comparisons means that the assumed +degree of forward compatibility in a compatible release clause can be +controlled by appending additional zeroes to the version specifier:: 2.2.0 + ~= 2.2.0 >= 2.2.0, == 2.2.* 1.4.5.0 + ~= 1.4.5.0 >= 1.4.5.0, == 1.4.5.* Version matching ---------------- -A version matching clause includes the version matching operator -``==`` and a version identifier. +A version matching clause includes the version matching operator ``==`` +and a version identifier. -The specified version identifier must be in the standard format -described in `Version scheme`_, but a trailing ``.*`` is permitted as -described below. +The specified version identifier must be in the standard format described in +`Version scheme`_, but a trailing ``.*`` is permitted as described below. -By default, the version matching operator is based on a strict -equality comparison: the specified version must be exactly the same as -the requested version. The *only* substitution performed is the zero -padding of the release segment to ensure the release segments are -compared with the same length. +By default, the version matching operator is based on a strict equality +comparison: the specified version must be exactly the same as the requested +version. The *only* substitution performed is the zero padding of the +release segment to ensure the release segments are compared with the same +length. -Prefix matching may be requested instead of strict comparison, by -appending a trailing ``.*`` to the version identifier in the version -matching clause. This means that additional trailing segments will be -ignored when determining whether or not a version identifier matches -the clause. If the version includes only a release segment, than -trailing components in the release segment are also ignored. +Prefix matching may be requested instead of strict comparison, by appending +a trailing ``.*`` to the version identifier in the version matching clause. +This means that additional trailing segments will be ignored when +determining whether or not a version identifier matches the clause. If the +version includes only a release segment, than trailing components in the +release segment are also ignored. For example, given the version ``1.1.post1``, the following clauses would -match or not as shown: +match or not as shown:: == 1.1 # Not equal, so 1.1.post1 does not match clause == 1.1.post1 # Equal, so 1.1.post1 matches clause == 1.1.* # Same prefix, so 1.1.post1 matches clause -.. note:: +The use of ``==`` (without at least the wildcard suffix) when defining +dependencies for published distributions is strongly discouraged as it +greatly complicates the deployment of security fixes. The strict version +comparison operator is intended primarily for use when defining +dependencies for repeatable *deployments of applications* while using +a shared distribution index. - The use of ``==`` when defining dependencies for published - distributions is strongly discouraged as it greatly complicates the - deployment of security fixes. The strict version comparison - operator is intended primarily for use when defining dependencies - for repeatable *deployments of applications* while using a shared - distribution index. +Publication tools and index servers SHOULD at least emit a warning when +dependencies are pinned in this fashion and MAY refuse to allow publication +of such overly specific dependencies. Version exclusion ----------------- -A version exclusion clause includes the version matching operator -``!=`` and a version identifier. +A version exclusion clause includes the version exclusion operator ``!=`` +and a version identifier. -The allowed version identifiers and comparison semantics are the same -as those of the `Version matching`_ operator, except that the sense of -any match is inverted. +The allowed version identifiers and comparison semantics are the same as +those of the `Version matching`_ operator, except that the sense of any +match is inverted. -For example, given the version ``1.1.post1``, the following clauses -would match or not as shown: +For example, given the version ``1.1.post1``, the following clauses would +match or not as shown:: != 1.1 # Not equal, so 1.1.post1 matches clause != 1.1.post1 # Equal, so 1.1.post1 does not match clause @@ -686,58 +652,113 @@ Build reference --------------- -A build reference includes the build label matching operator ``is`` and -a build reference. - -A build reference is a direct URI reference supplied to satisfy a -dependency. The exact kinds of URIs and targets supported will be -determined by the specific installation tool used. +A build reference includes the build reference operator ``is`` and +a build label or a build URL. Publication tools and public index servers SHOULD NOT permit build references in dependency specifications. -Installation tools SHOULD support the use of build references to -identify dependencies. - -Automated tools MAY support the use of build labels in build reference -clauses. They can be clearly distinguished from URI references -without ambiguity, as ``:`` and ``/`` are not permitted in build -labels. +Installation tools SHOULD support the use of build references to identify +dependencies. Build label matching works solely on strict equality comparisons: the -candidate build label must be exactly the same as the build label in -the version clause. +candidate build label must be exactly the same as the build label in the +version clause for the clause to match the candidate distribution. +For example, a build reference could be used to depend on a ``hashdist`` +generated build of ``zlib`` with the ``hashdist`` hash used as a build +label:: -Ordered comparison ------------------- + zlib (is d4jwf2sb2g6glprsdqfdpcracwpzujwq) -An ordered comparison clause includes a comparison operator and a -version identifier, and will match any version where the comparison is -correct based on the relative position of the candidate version and -the specified version given the consistent ordering defined by the -standard `Version scheme`_. +A build URL is distinguished from a build label by the presence of +``:`` and ``/`` characters in the build reference. As these characters +are not permitted in build labels, they indicate that the reference uses +a build URL. -The supported ordered comparison operators are ``<``, ``>``, ``<=``, -``>=``. +Some appropriate targets for a build URL are a binary archive, a +source tarball, an sdist archive or a direct reference to a tag or +specific commit in an online version control system. The exact URLs and +targets supported will be installation tool specific. -As with version matching, the release segment is zero padded as -necessary to ensure the release segments are compared with the same -length. +For example, a local prebuilt wheel file may be referenced directly:: -To exclude pre-releases and post-releases correctly, the comparison -clauses ``< V`` and ``> V`` MUST be interpreted as also implying the -version matching clause ``!= V.*``. + exampledist (is file:///localbuilds/exampledist-1.0-py33-none-any.whl) + +All build URL references SHOULD either specify a local file URL, a secure +transport mechanism (such as ``https``) or else include an expected hash +value in the URL for verification purposes. If an insecure network +transport is specified without any hash information (or with hash +information that the tool doesn't understand), automated tools SHOULD +at least emit a warning and MAY refuse to rely on the URL. + +It is RECOMMENDED that only hashes which are unconditionally provided by +the latest version of the standard library's ``hashlib`` module be used +for source archive hashes. At time of writing, that list consists of +``'md5'``, ``'sha1'``, ``'sha224'``, ``'sha256'``, ``'sha384'``, and +``'sha512'``. + +For binary or source archive references, an expected hash value may be +specified by including a ``=`` as part of +the URL fragment. + +For version control references, the ``VCS+protocol`` scheme SHOULD be +used to identify both the version control system and the secure transport. + +To support version control systems that do not support including commit or +tag references directly in the URL, that information may be appended to the +end of the URL using the ``@`` notation. + +The use of ``is`` when defining dependencies for published distributions +is strongly discouraged as it greatly complicates the deployment of +security fixes. The build label matching operator is intended primarily +for use when defining dependencies for repeatable *deployments of +applications* while using a shared distribution index, as well as to +reference dependencies which are not published through an index server. + + +Inclusive ordered comparison +---------------------------- + +An inclusive ordered comparison clause includes a comparison operator and a +version identifier, and will match any version where the comparison is correct +based on the relative position of the candidate version and the specified +version given the consistent ordering defined by the standard +`Version scheme`_. + +The inclusive ordered comparison operators are ``<=`` and ``>=``. + +As with version matching, the release segment is zero padded as necessary to +ensure the release segments are compared with the same length. + + +Exclusive ordered comparison +---------------------------- + +Exclusive ordered comparisons are similar to inclusive ordered comparisons, +except that the comparison operators are ``<`` and ``>`` and the clause +MUST be effectively interpreted as implying the prefix based version +exclusion clause ``!= V.*``. + +The exclusive ordered comparison ``> V`` MUST NOT match a post-release +or maintenance release of the given version. Maintenance releases can be +permitted by using the clause ``> V.0``, while both post releases and +maintenance releases can be permitted by using the inclusive ordered +comparison ``>= V.post1``. + +The exclusive ordered comparison ``< V`` MUST NOT match a pre-release of +the given version, even if acceptance of pre-releases is enabled as +described in the section below. Handling of pre-releases ------------------------ -Pre-releases of any kind, including developmental releases, are -implicitly excluded from all version specifiers, *unless* a -pre-release or developmental release is explicitly mentioned in one of -the clauses. For example, these specifiers implicitly exclude all -pre-releases and development releases of later versions:: +Pre-releases of any kind, including developmental releases, are implicitly +excluded from all version specifiers, *unless* a pre-release or developmental +release is explicitly mentioned in one of the clauses. For example, these +specifiers implicitly exclude all pre-releases and development +releases of later versions:: 2.2 >= 1.0 @@ -751,73 +772,68 @@ >= 1.0, != 1.0b2 >= 1.0, < 2.0.dev123 -Dependency resolution tools SHOULD exclude pre-releases by default, -but SHOULD also allow users to request the following alternative -behaviours: +By default, dependency resolution tools SHOULD: * accept already installed pre-releases for all version specifiers -* retrieve and install available pre-releases for all version - specifiers +* accept remotely available pre-releases for version specifiers which + include at least one version clauses that references a pre-release +* exclude all other pre-releases from consideration + +Dependency resolution tools SHOULD also allow users to request the +following alternative behaviours: + +* accepting pre-releases for all version specifiers +* excluding pre-releases for all version specifiers (reporting an error or + warning if a pre-release is already installed locally) Dependency resolution tools MAY also allow the above behaviour to be controlled on a per-distribution basis. -Post-releases and purely numeric releases receive no special treatment -- they are always included unless explicitly excluded. +Post-releases and purely numeric releases receive no special treatment in +version specifiers - they are always included unless explicitly excluded. Examples -------- -* ``3.1``: version 3.1 or later, but not version 4.0 or - later. Excludes pre-releases and developmental releases. -* ``3.1.2``: version 3.1.2 or later, but not version 3.2.0 or - later. Excludes pre-releases and developmental releases. -* ``3.1a1``: version 3.1a1 or later, but not version 4.0 or - later. Allows pre-releases like 3.2a4 and developmental releases - like 3.2.dev1. -* ``== 3.1``: specifically version 3.1 (or 3.1.0), excludes all - pre-releases, post releases, developmental releases and any 3.1.x - maintenance releases. -* ``== 3.1.*``: any version that starts with 3.1, excluding - pre-releases and developmental releases. Equivalent to the ``3.1.0`` - compatible release clause. -* ``3.1.0, != 3.1.3``: version 3.1.0 or later, but not version 3.1.3 - and not version 3.2.0 or later. Excludes pre-releases and - developmental releases. +* ``3.1``: version 3.1 or later, but not + version 4.0 or later. Excludes pre-releases and developmental releases. +* ``3.1.2``: version 3.1.2 or later, but not + version 3.2.0 or later. Excludes pre-releases and developmental releases. +* ``3.1a1``: version 3.1a1 or later, but not + version 4.0 or later. Allows pre-releases like 3.2a4 and developmental + releases like 3.2.dev1. +* ``== 3.1``: specifically version 3.1 (or 3.1.0), excludes all pre-releases, + post releases, developmental releases and any 3.1.x maintenance releases. +* ``== 3.1.*``: any version that starts with 3.1, excluding pre-releases and + developmental releases. Equivalent to the ``3.1.0`` compatible release + clause. +* ``3.1.0, != 3.1.3``: version 3.1.0 or later, but not version 3.1.3 and + not version 3.2.0 or later. Excludes pre-releases and developmental + releases. Updating the versioning specification ===================================== -The versioning specification may be updated with clarifications -without requiring a new PEP or a change to the metadata version. +The versioning specification may be updated with clarifications without +requiring a new PEP or a change to the metadata version. -Actually changing the version comparison semantics still requires a -new versioning scheme and metadata version defined in new PEPs. +Actually changing the version comparison semantics still requires a new +versioning scheme and metadata version defined in new PEPs. Open issues =========== * The new ``is`` operator seems like a reasonable way to cleanly allow - *deployments* to bring in non-published dependencies, while heavily - discouraging the practice for published libraries. However, it's a - first draft of the idea, so feedback is definitely welcome. + installation tools to bring in non-published dependencies, while heavily + discouraging the practice for published libraries. It also makes + build labels more useful by allowing them to be used to pin dependencies + in the integration use case. -* Currently, the cleanest way to specify that a project runs on Python - 2.6+ and 3.3+ is to use a clause like:: - - Requires-Python: >= 2.6, < 4.0, != 3.0.*, != 3.1.*, != 3.2.* - - It would be better if there was a cleaner way to specify "this OR - that" in a version specifier. Perhaps something like:: - - Requires-Python: (2.6) or (3.3) - - This would be a respectable increase in the complexity of the - parsing for version specifiers though, even if it was only allowed - at the top level. + However, it's an early draft of the idea, so feedback is definitely + welcome. Summary of differences from \PEP 386 @@ -825,16 +841,16 @@ * Moved the description of version specifiers into the versioning PEP -* added the "build label" concept to better handle projects that wish - to use a non-compliant versioning scheme internally, especially - those based on DVCS hashes +* added the "build label" concept to better handle projects that wish to + use a non-compliant versioning scheme internally, especially those based + on DVCS hashes * added the "compatible release" clause * added the "build reference" clause -* separated the two kinds of "version matching" clause (strict and - prefix) +* added the trailing wildcard syntax for prefix based version matching + and exclusion * changed the top level sort position of the ``.devN`` suffix @@ -857,111 +873,106 @@ ------------------- The new build label support is intended to make it clearer that the -constraints on public version identifiers are there primarily to aid -in the creation of reliable automated dependency analysis tools. -Projects are free to use whatever versioning scheme they like -internally, so long as they are able to translate it to something the -dependency analysis tools will understand. +constraints on public version identifiers are there primarily to aid in +the creation of reliable automated dependency analysis tools. Projects +are free to use whatever versioning scheme they like internally, so long +as they are able to translate it to something the dependency analysis tools +will understand. Changing the version scheme --------------------------- The key change in the version scheme in this PEP relative to that in -PEP 386 is to sort top level developmental releases like ``X.Y.devN`` -ahead of alpha releases like ``X.Ya1``. This is a far more logical -sort order, as projects already using both development releases and -alphas/betas/release candidates do not want their developmental -releases sorted in between their release candidates and their full -releases. There is no rationale for using ``dev`` releases in that -position rather than merely creating additional release candidates. +PEP 386 is to sort top level developmental releases like ``X.Y.devN`` ahead +of alpha releases like ``X.Ya1``. This is a far more logical sort order, as +projects already using both development releases and alphas/betas/release +candidates do not want their developmental releases sorted in +between their release candidates and their final releases. There is no +rationale for using ``dev`` releases in that position rather than +merely creating additional release candidates. -The updated sort order also means the sorting of ``dev`` versions is -now consistent between the metadata standard and the pre-existing -behaviour of ``pkg_resources`` (and hence the behaviour of current -installation tools). +The updated sort order also means the sorting of ``dev`` versions is now +consistent between the metadata standard and the pre-existing behaviour +of ``pkg_resources`` (and hence the behaviour of current installation +tools). -Making this change should make it easier for affected existing -projects to migrate to the latest version of the metadata standard. +Making this change should make it easier for affected existing projects to +migrate to the latest version of the metadata standard. Another change to the version scheme is to allow single number versions, similar to those used by non-Python projects like Mozilla -Firefox, Google Chrome and the Fedora Linux distribution. This is -actually expected to be more useful for version specifiers (allowing -things like the simple ``Requires-Python: 3`` rather than the more -convoluted ``Requires-Python: >= 3.0, < 4``), but it is easier to +Firefox, Google Chrome and the Fedora Linux distribution. This is actually +expected to be more useful for version specifiers, but it is easier to allow it for both version specifiers and release numbers, rather than splitting the two definitions. -The exclusion of leading and trailing whitespace was made explicit -after a couple of projects with version identifiers differing only in -a trailing ``\n`` character were found on PyPI. +The exclusion of leading and trailing whitespace was made explicit after +a couple of projects with version identifiers differing only in a +trailing ``\n`` character were found on PyPI. -The exclusion of major release numbers that looks like dates was -implied by the overall text of PEP 386, but not clear in the -definition of the version scheme. This exclusion has been made clear -in the definition of the release component. +The exclusion of major release numbers that look like dates was implied +by the overall text of PEP 386, but not clear in the definition of the +version scheme. This exclusion has been made clear in the definition of +the release component. -`Appendix A` shows detailed results of an analysis of PyPI -distribution version information, as collected on 19th February, 2013. -This analysis compares the behaviour of the explicitly ordered version -schemes defined in this PEP and PEP 386 with the de facto standard -defined by the behaviour of setuptools. These metrics are useful, as -the intent of both PEPs is to follow existing setuptools behaviour as -closely as is feasible, while still throwing exceptions for -unorderable versions (rather than trying to guess an appropriate order -as setuptools does). +`Appendix A` shows detailed results of an analysis of PyPI distribution +version information, as collected on 19th February, 2013. This analysis +compares the behaviour of the explicitly ordered version schemes defined in +this PEP and PEP 386 with the de facto standard defined by the behaviour +of setuptools. These metrics are useful, as the intent of both PEPs is to +follow existing setuptools behaviour as closely as is feasible, while +still throwing exceptions for unorderable versions (rather than trying +to guess an appropriate order as setuptools does). -Overall, the percentage of compatible distributions improves from -97.7% with PEP 386 to 98.7% with this PEP. While the number of -projects affected in practice was small, some of the affected projects -are in widespread use (such as Pinax and selenium). The surprising -ordering discrepancy also concerned developers and acted as an -unnecessary barrier to adoption of the new metadata standard, even for -projects that weren't directly affected. +Overall, the percentage of compatible distributions improves from 97.7% +with PEP 386 to 98.7% with this PEP. While the number of projects affected +in practice was small, some of the affected projects are in widespread use +(such as Pinax and selenium). The surprising ordering discrepancy also +concerned developers and acted as an unnecessary barrier to adoption of +the new metadata standard, even for projects that weren't directly affected. -The data also shows that the pre-release sorting discrepancies are -seen only when analysing *all* versions from PyPI, rather than when -analysing public versions. This is largely due to the fact that PyPI -normally reports only the most recent version for each project (unless -maintainers explicitly configure their project to display additional -versions). However, installers that need to satisfy detailed version -constraints often need to look at all available versions, as they may -need to retrieve an older release. +The data also shows that the pre-release sorting discrepancies are seen +only when analysing *all* versions from PyPI, rather than when analysing +public versions. This is largely due to the fact that PyPI normally reports +only the most recent version for each project (unless maintainers +explicitly configure their project to display additional versions). However, +installers that need to satisfy detailed version constraints often need +to look at all available versions, as they may need to retrieve an older +release. -Even this PEP doesn't completely eliminate the sorting differences -relative to setuptools: +Even this PEP doesn't completely eliminate the sorting differences relative +to setuptools: * Sorts differently (after translations): 38 / 28194 (0.13 %) * Sorts differently (no translations): 2 / 28194 (0.01 %) -The two remaining sort order discrepancies picked up by the analysis -are due to a pair of projects which have PyPI releases ending with a -carriage return, alongside releases with the same version number, only -*without* the trailing carriage return. +The two remaining sort order discrepancies picked up by the analysis are due +to a pair of projects which have PyPI releases ending with a carriage +return, alongside releases with the same version number, only *without* the +trailing carriage return. -The sorting discrepancies after translation relate mainly to -differences in the handling of pre-releases where the standard -mechanism is considered to be an improvement. For example, the -existing pkg_resources scheme will sort "1.1beta1" *after* "1.1b2", -whereas the suggested standard translation for "1.1beta1" is "1.1b1", -which sorts *before* "1.1b2". Similarly, the pkg_resources scheme -will sort "-dev-N" pre-releases differently from "devN" pre-releases -when they occur within the same release, while the scheme in this PEP -requires normalizing both representations to ".devN" and sorting them -by the numeric component. +The sorting discrepancies after translation relate mainly to differences +in the handling of pre-releases where the standard mechanism is considered +to be an improvement. For example, the existing pkg_resources scheme will +sort "1.1beta1" *after* "1.1b2", whereas the suggested standard translation +for "1.1beta1" is "1.1b1", which sorts *before* "1.1b2". Similarly, the +pkg_resources scheme will sort "-dev-N" pre-releases differently from +"devN" pre-releases when they occur within the same release, while the +scheme in this PEP requires normalizing both representations to ".devN" and +sorting them by the numeric component. A more opinionated description of the versioning scheme ------------------------------------------------------- -As in PEP 386, the primary focus is on codifying existing practices to -make them more amenable to automation, rather than demanding that -existing projects make non-trivial changes to their workflow. -However, the standard scheme allows significantly more flexibility -than is needed for the vast majority of simple Python packages (which -often don't even need maintenance releases - many users are happy with -needing to upgrade to a new feature release to get bug fixes). +As in PEP 386, the primary focus is on codifying existing practices to make +them more amenable to automation, rather than demanding that existing +projects make non-trivial changes to their workflow. However, the +standard scheme allows significantly more flexibility than is needed +for the vast majority of simple Python packages (which often don't even +need maintenance releases - many users are happy with needing to upgrade to a +new feature release to get bug fixes). For the benefit of novice developers, and for experienced developers wishing to better understand the various use cases, the specification @@ -969,57 +980,74 @@ version scheme, including examples of how each component may be used in practice. -The PEP also explicitly guides developers in the direction of semantic -versioning (without requiring it), and discourages the use of several -aspects of the full versioning scheme that have largely been included -in order to cover esoteric corner cases in the practices of existing -projects and in repackaging software for Linux distributions. +The PEP also explicitly guides developers in the direction of +semantic versioning (without requiring it), and discourages the use of +several aspects of the full versioning scheme that have largely been +included in order to cover esoteric corner cases in the practices of +existing projects and in repackaging software for Linux distributions. Describing version specifiers alongside the versioning scheme ------------------------------------------------------------- -The main reason to even have a standardised version scheme in the -first place is to make it easier to do reliable automated dependency -analysis. It makes more sense to describe the primary use case for -version identifiers alongside their definition. +The main reason to even have a standardised version scheme in the first place +is to make it easier to do reliable automated dependency analysis. It makes +more sense to describe the primary use case for version identifiers alongside +their definition. Changing the interpretation of version specifiers ------------------------------------------------- The previous interpretation of version specifiers made it very easy to -accidentally download a pre-release version of a dependency. This in +accidentally download a pre-release version of a dependency. This in turn made it difficult for developers to publish pre-release versions -of software to the Python Package Index, as even marking the package -as hidden wasn't enough to keep automated tools from downloading it, -and also made it harder for users to obtain the test release manually -through the main PyPI web interface. +of software to the Python Package Index, as even marking the package as +hidden wasn't enough to keep automated tools from downloading it, and also +made it harder for users to obtain the test release manually through the +main PyPI web interface. -The previous interpretation also excluded post-releases from some -version specifiers for no adequately justified reason. +The previous interpretation also excluded post-releases from some version +specifiers for no adequately justified reason. -The updated interpretation is intended to make it difficult to -accidentally accept a pre-release version as satisfying a dependency, -while allowing pre-release versions to be explicitly requested when -needed. +The updated interpretation is intended to make it difficult to accidentally +accept a pre-release version as satisfying a dependency, while allowing +pre-release versions to be explicitly requested when needed. The "some forward compatibility assumed" default version constraint is -taken directly from the Ruby community's "pessimistic version -constraint" operator [2]_ to allow projects to take a cautious -approach to forward compatibility promises, while still easily setting -a minimum required version for their dependencies. It is made the -default behaviour rather than needing a separate operator in order to -explicitly discourage overspecification of dependencies by library -developers. The explicit comparison operators remain available to cope -with dependencies with unreliable or non-existent backwards -compatibility policies, as well as for legitimate use cases related to -deployment of integrated applications. +taken directly from the Ruby community's "pessimistic version constraint" +operator [2]_ to allow projects to take a cautious approach to forward +compatibility promises, while still easily setting a minimum required +version for their dependencies. It is made the default behaviour rather +than needing a separate operator in order to explicitly discourage +overspecification of dependencies by library developers. The explicit +comparison operators remain available to cope with dependencies with +unreliable or non-existent backwards compatibility policies, as well +as for legitimate use cases related to deployment of integrated applications. -The two kinds of version matching (strict and prefix based) were -separated to make it possible to sensibly define the compatible -release clauses and the desired pre-release handling semantics for -``<`` and ``>`` ordered comparison clauses. +The optional explicit spelling of the compatible release clause (``~=``) is +inspired by the Ruby (``~>``) and PHP (``~``) equivalents. It is defined +in order to allow easier conversion to the legacy ``pkg_resources`` version +specifier format (which omits the parentheses, but requires a comparison +operator). + +Further improvements are also planned to the handling of parallel +installation of multiple versions of the same library, but these will +depend on updates to the installation database definition along with +improved tools for dynamic path manipulation. + +The trailing wildcard syntax to request prefix based version matching was +added to make it possible to sensibly define both compatible release clauses +and the desired pre-release handling semantics for ``<`` and ``>`` ordered +comparison clauses. + +Build references are added for two purposes. In conjunction with build +labels, they allow hash based references, such as those employed by +`hashdist `__, +or generated from version control. In conjunction with build URLs, they +allow the new metadata standard to natively support an existing feature of +``pip``, which allows arbitrary URLs like +``file:///localbuilds/exampledist-1.0-py33-none-any.whl``. References @@ -1028,18 +1056,18 @@ The initial attempt at a standardised version scheme, along with the justifications for needing such a standard can be found in PEP 386. -.. [1] Version compatibility analysis script - (http://hg.python.org/peps/file/default/pep-0426/pepsort.py) +.. [1] Version compatibility analysis script: + http://hg.python.org/peps/file/default/pep-0426/pepsort.py .. [2] Pessimistic version constraint - (http://docs.rubygems.org/read/chapter/16) + http://docs.rubygems.org/read/chapter/16 Appendix A ========== -Metadata v2.0 guidelines versus setuptools (note that this analysis -was run when this PEP was still embedded as part of PEP 426):: +Metadata v2.0 guidelines versus setuptools (note that this analysis was +run when this PEP was still embedded as part of PEP 426):: $ ./pepsort.py Comparing PEP 426 version sort to setuptools. @@ -1110,7 +1138,6 @@ This document has been placed in the public domain. - .. Local Variables: mode: indented-text -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon May 27 14:23:40 2013 From: python-checkins at python.org (lukasz.langa) Date: Mon, 27 May 2013 14:23:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Make_consistent_use_of_the_te?= =?utf-8?q?rm_=22implementation=22_versus_=22overload=22?= Message-ID: <3bJy5m1Y7mzSLQ@mail.python.org> http://hg.python.org/peps/rev/2f9702702b7c changeset: 4915:2f9702702b7c user: ?ukasz Langa date: Mon May 27 14:23:30 2013 +0200 summary: Make consistent use of the term "implementation" versus "overload" files: pep-0443.txt | 72 ++++++++++++++++++++++----------------- 1 files changed, 41 insertions(+), 31 deletions(-) diff --git a/pep-0443.txt b/pep-0443.txt --- a/pep-0443.txt +++ b/pep-0443.txt @@ -19,10 +19,11 @@ module that provides a simple form of generic programming known as single-dispatch generic functions. -A **generic function** is composed of multiple functions sharing the -same name. Which form should be used during a call is determined by the -dispatch algorithm. When the implementation is chosen based on the type -of a single argument, this is known as **single dispatch**. +A **generic function** is composed of multiple functions implementing +the same operation for different types. Which implementation should be +used during a call is determined by the dispatch algorithm. When the +implementation is chosen based on the type of a single argument, this is +known as **single dispatch**. Rationale and Goals @@ -72,8 +73,9 @@ ... print(arg) To add overloaded implementations to the function, use the -``register()`` attribute of the generic function. It takes a type -parameter:: +``register()`` attribute of the generic function. It is a decorator, +taking a type parameter and decorating a function implementing the +operation for that type:: >>> @fun.register(int) ... def _(arg, verbose=False): @@ -110,7 +112,8 @@ >>> fun_num is fun False -When called, the generic function dispatches on the first argument:: +When called, the generic function dispatches on the type of the first +argument:: >>> fun("Hello, world.") Hello, world. @@ -129,15 +132,17 @@ >>> fun(1.23) 0.615 -To get the implementation for a specific type, use the ``dispatch()`` -attribute:: +Where there is no registered implementation for a specific type, its +method resolution order is used to find a more generic implementation. +To check which implementation will the generic function choose for +a given type, use the ``dispatch()`` attribute:: >>> fun.dispatch(float) >>> fun.dispatch(dict) -To access all registered overloads, use the read-only ``registry`` +To access all registered implementations, use the read-only ``registry`` attribute:: >>> fun.registry.keys() @@ -180,9 +185,10 @@ handling of old-style classes and Zope's ExtensionClasses. More importantly, it introduces support for Abstract Base Classes (ABC). -When a generic function overload is registered for an ABC, the dispatch -algorithm switches to a mode of MRO calculation for the provided -argument which includes the relevant ABCs. The algorithm is as follows:: +When a generic function implementation is registered for an ABC, the +dispatch algorithm switches to a mode of MRO calculation for the +provided argument which includes the relevant ABCs. The algorithm is as +follows:: def _compose_mro(cls, haystack): """Calculates the MRO for a given class `cls`, including relevant @@ -218,9 +224,10 @@ While this mode of operation is significantly slower, all dispatch decisions are cached. The cache is invalidated on registering new -overloads on the generic function or when user code calls ``register()`` -on an ABC to register a new virtual subclass. In the latter case, it is -possible to create a situation with ambiguous dispatch, for instance:: +implementations on the generic function or when user code calls +``register()`` on an ABC to register a new virtual subclass. In the +latter case, it is possible to create a situation with ambiguous +dispatch, for instance:: >>> from collections import Iterable, Container >>> class P: @@ -274,24 +281,27 @@ sense that we need not expect people to randomly redefine the behavior of existing functions in unpredictable ways. To the contrary, generic function usage in actual programs tends to follow very predictable -patterns and overloads are highly-discoverable in the common case. +patterns and registered implementations are highly-discoverable in the +common case. If a module is defining a new generic operation, it will usually also -define any required overloads for existing types in the same place. -Likewise, if a module is defining a new type, then it will usually -define overloads there for any generic functions that it knows or cares -about. As a result, the vast majority of overloads can be found adjacent -to either the function being overloaded, or to a newly-defined type for -which the overload is adding support. +define any required implementations for existing types in the same +place. Likewise, if a module is defining a new type, then it will +usually define implementations there for any generic functions that it +knows or cares about. As a result, the vast majority of registered +implementations can be found adjacent to either the function being +overloaded, or to a newly-defined type for which the implementation is +adding support. -It is only in rather infrequent cases that one will have overloads in -a module that contains neither the function nor the type(s) for which -the overload is added. In the absence of incompetence or deliberate -intention to be obscure, the few overloads that are not adjacent to the -relevant type(s) or function(s), will generally not need to be -understood or known about outside the scope where those overloads are -defined. (Except in the "support modules" case, where best practice -suggests naming them accordingly.) +It is only in rather infrequent cases that one will have implementations +registered in a module that contains neither the function nor the +type(s) for which the implementation is added. In the absence of +incompetence or deliberate intention to be obscure, the few +implementations that are not registered adjacent to the relevant type(s) +or function(s), will generally not need to be understood or known about +outside the scope where those implementations are defined. (Except in +the "support modules" case, where best practice suggests naming them +accordingly.) As mentioned earlier, single-dispatch generics are already prolific throughout the standard library. A clean, standard way of doing them -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Mon May 27 19:59:10 2013 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 27 May 2013 19:59:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4MDE1?= =?utf-8?q?=3A_Fix_unpickling_of_2=2E7=2E3_and_2=2E7=2E4_namedtuples=2E?= Message-ID: <3bK5Xt6FGdz7LkV@mail.python.org> http://hg.python.org/cpython/rev/687295c6c8f2 changeset: 83936:687295c6c8f2 branch: 2.7 parent: 83906:f4981d8eb401 user: Raymond Hettinger date: Mon May 27 10:58:55 2013 -0700 summary: Issue #18015: Fix unpickling of 2.7.3 and 2.7.4 namedtuples. files: Doc/library/collections.rst | 6 +++ Lib/collections.py | 6 +++ Lib/test/test_collections.py | 44 +++++++++++++++++++++++- Misc/NEWS | 2 + 4 files changed, 57 insertions(+), 1 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -639,6 +639,12 @@ 'Return self as a plain tuple. Used by copy and pickle.' return tuple(self) + __dict__ = _property(_asdict) + + def __getstate__(self): + 'Exclude the OrderedDict from pickling' + pass + x = _property(_itemgetter(0), doc='Alias for field number 0') y = _property(_itemgetter(1), doc='Alias for field number 1') diff --git a/Lib/collections.py b/Lib/collections.py --- a/Lib/collections.py +++ b/Lib/collections.py @@ -270,6 +270,12 @@ 'Return self as a plain tuple. Used by copy and pickle.' return tuple(self) + __dict__ = _property(_asdict) + + def __getstate__(self): + 'Exclude the OrderedDict from pickling' + pass + {field_defs} ''' 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 @@ -17,6 +17,43 @@ TestNT = namedtuple('TestNT', 'x y z') # type used for pickle tests +py273_named_tuple_pickle = '''\ +ccopy_reg +_reconstructor +p0 +(ctest.test_collections +TestNT +p1 +c__builtin__ +tuple +p2 +(I10 +I20 +I30 +tp3 +tp4 +Rp5 +ccollections +OrderedDict +p6 +((lp7 +(lp8 +S'x' +p9 +aI10 +aa(lp10 +S'y' +p11 +aI20 +aa(lp12 +S'z' +p13 +aI30 +aatp14 +Rp15 +b. +''' + class TestNamedTuple(unittest.TestCase): def test_factory(self): @@ -78,12 +115,12 @@ self.assertRaises(TypeError, eval, 'Point(XXX=1, y=2)', locals()) # wrong keyword argument self.assertRaises(TypeError, eval, 'Point(x=1)', locals()) # missing keyword argument self.assertEqual(repr(p), 'Point(x=11, y=22)') - self.assertNotIn('__dict__', dir(p)) # verify instance has no dict self.assertNotIn('__weakref__', dir(p)) self.assertEqual(p, Point._make([11, 22])) # test _make classmethod self.assertEqual(p._fields, ('x', 'y')) # test _fields attribute self.assertEqual(p._replace(x=1), (1, 22)) # test _replace method self.assertEqual(p._asdict(), dict(x=11, y=22)) # test _asdict method + self.assertEqual(vars(p), p._asdict()) # verify that vars() works try: p._replace(x=1, error=2) @@ -215,6 +252,11 @@ # test __getnewargs__ self.assertEqual(t.__getnewargs__(), values) + def test_pickling_bug_18015(self): + # http://bugs.python.org/issue18015 + pt = pickle.loads(py273_named_tuple_pickle) + self.assertEqual(pt.x, 10) + class ABCTestCase(unittest.TestCase): def validate_abstract_methods(self, abc, *names): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -19,6 +19,8 @@ - Issue #17981: Closed socket on error in SysLogHandler. +- Issue #18015: Fix unpickling of 2.7.3 and 2.7.4 namedtuples. + - Issue #17754: Make ctypes.util.find_library() independent of the locale. - Fix typos in the multiprocessing module. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 27 23:46:45 2013 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 27 May 2013 23:46:45 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_don=27t_expand_the_operand?= =?utf-8?q?_to_Py=5FXINCREF/XDECREF/CLEAR/DECREF_multiple_times?= Message-ID: <3bKBbT3fmHz7LjW@mail.python.org> http://hg.python.org/cpython/rev/aff41a6421c2 changeset: 83937:aff41a6421c2 parent: 83935:39e0be9106c1 user: Benjamin Peterson date: Mon May 27 14:46:14 2013 -0700 summary: don't expand the operand to Py_XINCREF/XDECREF/CLEAR/DECREF multiple times (closes #17206) A patch from Illia Polosukhin. files: Include/object.h | 34 +++++++++++-------- Misc/ACKS | 1 + Misc/NEWS | 4 ++ Modules/_testcapimodule.c | 46 +++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 14 deletions(-) diff --git a/Include/object.h b/Include/object.h --- a/Include/object.h +++ b/Include/object.h @@ -680,12 +680,6 @@ complications in the deallocation function. (This is actually a decision that's up to the implementer of each new type so if you want, you can count such references to the type object.) - -*** WARNING*** The Py_DECREF macro must have a side-effect-free argument -since it may evaluate its argument multiple times. (The alternative -would be to mace it a proper function or assign it to a global temporary -variable first, both of which are slower; and in a multi-threaded -environment the global variable trick is not safe.) */ /* First define a pile of simple helper macros, one set per special @@ -764,15 +758,16 @@ #define Py_INCREF(op) ( \ _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \ - ((PyObject*)(op))->ob_refcnt++) + ((PyObject *)(op))->ob_refcnt++) #define Py_DECREF(op) \ do { \ + PyObject *_py_decref_tmp = (PyObject *)(op); \ if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \ - --((PyObject*)(op))->ob_refcnt != 0) \ - _Py_CHECK_REFCNT(op) \ + --(_py_decref_tmp)->ob_refcnt != 0) \ + _Py_CHECK_REFCNT(_py_decref_tmp) \ else \ - _Py_Dealloc((PyObject *)(op)); \ + _Py_Dealloc(_py_decref_tmp); \ } while (0) /* Safely decref `op` and set `op` to NULL, especially useful in tp_clear @@ -811,16 +806,27 @@ */ #define Py_CLEAR(op) \ do { \ - if (op) { \ - PyObject *_py_tmp = (PyObject *)(op); \ + PyObject *_py_tmp = (PyObject *)(op); \ + if (_py_tmp != NULL) { \ (op) = NULL; \ Py_DECREF(_py_tmp); \ } \ } while (0) /* Macros to use in case the object pointer may be NULL: */ -#define Py_XINCREF(op) do { if ((op) == NULL) ; else Py_INCREF(op); } while (0) -#define Py_XDECREF(op) do { if ((op) == NULL) ; else Py_DECREF(op); } while (0) +#define Py_XINCREF(op) \ + do { \ + PyObject *_py_xincref_tmp = (PyObject *)(op); \ + if (_py_xincref_tmp != NULL) \ + Py_INCREF(_py_xincref_tmp); \ + } while (0) + +#define Py_XDECREF(op) \ + do { \ + PyObject *_py_xdecref_tmp = (PyObject *)(op); \ + if (_py_xdecref_tmp != NULL) \ + Py_DECREF(_py_xdecref_tmp); \ + } while (0) /* These are provided as conveniences to Python runtime embedders, so that diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -983,6 +983,7 @@ Remi Pointel Ariel Poliak Guilherme Polo +Illia Polosukhin Michael Pomraning Iustin Pop Claudiu Popa diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #17206: Py_CLEAR(), Py_DECREF(), Py_XINCREF() and Py_XDECREF() now + expands their arguments once instead of multiple times. + Patch written by Illia Polosukhin. + - Issue #17937: Try harder to collect cyclic garbage at shutdown. - Issue #12370: Prevent class bodies from interfering with the __class__ diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2468,6 +2468,48 @@ return Py_BuildValue("Nl", _PyLong_FromTime_t(sec), nsec); } +static PyObject * +_test_incref(PyObject *ob) +{ + Py_INCREF(ob); + return ob; +} + +static PyObject * +test_xincref_doesnt_leak(PyObject *ob) +{ + PyObject *obj = PyLong_FromLong(0); + Py_XINCREF(_test_incref(obj)); + Py_DECREF(obj); + Py_DECREF(obj); + Py_DECREF(obj); + Py_RETURN_NONE; +} + +static PyObject * +test_incref_doesnt_leak(PyObject *ob) +{ + PyObject *obj = PyLong_FromLong(0); + Py_INCREF(_test_incref(obj)); + Py_DECREF(obj); + Py_DECREF(obj); + Py_DECREF(obj); + Py_RETURN_NONE; +} + +static PyObject * +test_xdecref_doesnt_leak(PyObject *ob) +{ + Py_XDECREF(PyLong_FromLong(0)); + Py_RETURN_NONE; +} + +static PyObject * +test_decref_doesnt_leak(PyObject *ob) +{ + Py_DECREF(PyLong_FromLong(0)); + Py_RETURN_NONE; +} static PyMethodDef TestMethods[] = { {"raise_exception", raise_exception, METH_VARARGS}, @@ -2478,6 +2520,10 @@ {"test_dict_iteration", (PyCFunction)test_dict_iteration,METH_NOARGS}, {"test_lazy_hash_inheritance", (PyCFunction)test_lazy_hash_inheritance,METH_NOARGS}, {"test_long_api", (PyCFunction)test_long_api, METH_NOARGS}, + {"test_xincref_doesnt_leak",(PyCFunction)test_xincref_doesnt_leak, METH_NOARGS}, + {"test_incref_doesnt_leak", (PyCFunction)test_incref_doesnt_leak, METH_NOARGS}, + {"test_xdecref_doesnt_leak",(PyCFunction)test_xdecref_doesnt_leak, METH_NOARGS}, + {"test_decref_doesnt_leak", (PyCFunction)test_decref_doesnt_leak, METH_NOARGS}, {"test_long_and_overflow", (PyCFunction)test_long_and_overflow, METH_NOARGS}, {"test_long_as_double", (PyCFunction)test_long_as_double,METH_NOARGS}, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Mon May 27 23:49:36 2013 From: python-checkins at python.org (benjamin.peterson) Date: Mon, 27 May 2013 23:49:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_grammar?= Message-ID: <3bKBfm53DLzMSc@mail.python.org> http://hg.python.org/cpython/rev/789f8bbf0ae7 changeset: 83938:789f8bbf0ae7 user: Benjamin Peterson date: Mon May 27 14:49:31 2013 -0700 summary: grammar files: Misc/NEWS | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,9 +10,9 @@ Core and Builtins ----------------- -- Issue #17206: Py_CLEAR(), Py_DECREF(), Py_XINCREF() and Py_XDECREF() now - expands their arguments once instead of multiple times. - Patch written by Illia Polosukhin. +- Issue #17206: Py_CLEAR(), Py_DECREF(), Py_XINCREF() and Py_XDECREF() now + expand their arguments once instead of multiple times. Patch written by Illia + Polosukhin. - Issue #17937: Try harder to collect cyclic garbage at shutdown. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 03:12:51 2013 From: python-checkins at python.org (brett.cannon) Date: Tue, 28 May 2013 03:12:51 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318072=3A_Implemen?= =?utf-8?q?t_get=5Fcode=28=29_for_importlib=2Eabc=2EInspectLoader_and?= Message-ID: <3bKH9H1M71z7Lln@mail.python.org> http://hg.python.org/cpython/rev/11510db74223 changeset: 83939:11510db74223 user: Brett Cannon date: Mon May 27 21:11:04 2013 -0400 summary: Issue #18072: Implement get_code() for importlib.abc.InspectLoader and ExecutionLoader. files: Doc/library/importlib.rst | 12 +- Lib/importlib/abc.py | 30 ++++- Lib/test/test_importlib/test_abc.py | 96 +++++++++++++++- 3 files changed, 121 insertions(+), 17 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -318,16 +318,20 @@ .. method:: get_code(fullname) - An abstract method to return the :class:`code` object for a module. - ``None`` is returned if the module does not have a code object + Return the code object for a module. + ``None`` should be returned if the module does not have a code object (e.g. built-in module). :exc:`ImportError` is raised if loader cannot find the requested module. + .. note:: + While the method has a default implementation, it is suggested that + it be overridden if possible for performance. + .. index:: single: universal newlines; importlib.abc.InspectLoader.get_source method .. versionchanged:: 3.4 - Raises :exc:`ImportError` instead of :exc:`NotImplementedError`. + No longer abstract and a concrete implementation is provided. .. method:: get_source(fullname) @@ -410,7 +414,7 @@ .. method:: get_data(path) - Returns the open, binary file for *path*. + Reads *path* as a binary file and returns the bytes from it. .. class:: SourceLoader diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py --- a/Lib/importlib/abc.py +++ b/Lib/importlib/abc.py @@ -147,14 +147,18 @@ """ raise ImportError - @abc.abstractmethod def get_code(self, fullname): - """Abstract method which when implemented should return the code object - for the module. The fullname is a str. Returns a types.CodeType. + """Method which returns the code object for the module. - Raises ImportError if the module cannot be found. + The fullname is a str. Returns a types.CodeType if possible, else + returns None if a code object does not make sense + (e.g. built-in module). Raises ImportError if the module cannot be + found. """ - raise ImportError + source = self.get_source(fullname) + if source is None: + return None + return self.source_to_code(source) @abc.abstractmethod def get_source(self, fullname): @@ -194,6 +198,22 @@ """ raise ImportError + def get_code(self, fullname): + """Method to return the code object for fullname. + + Should return None if not applicable (e.g. built-in module). + Raise ImportError if the module cannot be found. + """ + source = self.get_source(fullname) + if source is None: + return None + try: + path = self.get_filename(fullname) + except ImportError: + return self.source_to_code(source) + else: + return self.source_to_code(source, path) + class FileLoader(_bootstrap.FileLoader, ResourceLoader, ExecutionLoader): diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py --- a/Lib/test/test_importlib/test_abc.py +++ b/Lib/test/test_importlib/test_abc.py @@ -9,6 +9,7 @@ import os import sys import unittest +from unittest import mock from . import util @@ -166,9 +167,6 @@ def is_package(self, fullname): return super().is_package(fullname) - def get_code(self, fullname): - return super().get_code(fullname) - def get_source(self, fullname): return super().get_source(fullname) @@ -181,10 +179,6 @@ with self.assertRaises(ImportError): self.ins.is_package('blah') - def test_get_code(self): - with self.assertRaises(ImportError): - self.ins.get_code('blah') - def test_get_source(self): with self.assertRaises(ImportError): self.ins.get_source('blah') @@ -206,7 +200,7 @@ ##### InspectLoader concrete methods ########################################### -class InspectLoaderConcreteMethodTests(unittest.TestCase): +class InspectLoaderSourceToCodeTests(unittest.TestCase): def source_to_module(self, data, path=None): """Help with source_to_code() tests.""" @@ -248,6 +242,92 @@ self.assertEqual(code.co_filename, '') +class InspectLoaderGetCodeTests(unittest.TestCase): + + def test_get_code(self): + # Test success. + module = imp.new_module('blah') + with mock.patch.object(InspectLoaderSubclass, 'get_source') as mocked: + mocked.return_value = 'attr = 42' + loader = InspectLoaderSubclass() + code = loader.get_code('blah') + exec(code, module.__dict__) + self.assertEqual(module.attr, 42) + + def test_get_code_source_is_None(self): + # If get_source() is None then this should be None. + with mock.patch.object(InspectLoaderSubclass, 'get_source') as mocked: + mocked.return_value = None + loader = InspectLoaderSubclass() + code = loader.get_code('blah') + self.assertIsNone(code) + + def test_get_code_source_not_found(self): + # If there is no source then there is no code object. + loader = InspectLoaderSubclass() + with self.assertRaises(ImportError): + loader.get_code('blah') + + +##### ExecutionLoader concrete methods ######################################### +class ExecutionLoaderGetCodeTests(unittest.TestCase): + + def mock_methods(self, *, get_source=False, get_filename=False): + source_mock_context, filename_mock_context = None, None + if get_source: + source_mock_context = mock.patch.object(ExecutionLoaderSubclass, + 'get_source') + if get_filename: + filename_mock_context = mock.patch.object(ExecutionLoaderSubclass, + 'get_filename') + return source_mock_context, filename_mock_context + + def test_get_code(self): + path = 'blah.py' + source_mock_context, filename_mock_context = self.mock_methods( + get_source=True, get_filename=True) + with source_mock_context as source_mock, filename_mock_context as name_mock: + source_mock.return_value = 'attr = 42' + name_mock.return_value = path + loader = ExecutionLoaderSubclass() + code = loader.get_code('blah') + self.assertEqual(code.co_filename, path) + module = imp.new_module('blah') + exec(code, module.__dict__) + self.assertEqual(module.attr, 42) + + def test_get_code_source_is_None(self): + # If get_source() is None then this should be None. + source_mock_context, _ = self.mock_methods(get_source=True) + with source_mock_context as mocked: + mocked.return_value = None + loader = ExecutionLoaderSubclass() + code = loader.get_code('blah') + self.assertIsNone(code) + + def test_get_code_source_not_found(self): + # If there is no source then there is no code object. + loader = ExecutionLoaderSubclass() + with self.assertRaises(ImportError): + loader.get_code('blah') + + def test_get_code_no_path(self): + # If get_filename() raises ImportError then simply skip setting the path + # on the code object. + source_mock_context, filename_mock_context = self.mock_methods( + get_source=True, get_filename=True) + with source_mock_context as source_mock, filename_mock_context as name_mock: + source_mock.return_value = 'attr = 42' + name_mock.side_effect = ImportError + loader = ExecutionLoaderSubclass() + code = loader.get_code('blah') + self.assertEqual(code.co_filename, '') + module = imp.new_module('blah') + exec(code, module.__dict__) + self.assertEqual(module.attr, 42) + + + ##### SourceLoader concrete methods ############################################ class SourceOnlyLoaderMock(abc.SourceLoader): -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 03:12:52 2013 From: python-checkins at python.org (brett.cannon) Date: Tue, 28 May 2013 03:12:52 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_NEWS_entry_for_issue_=2318?= =?utf-8?q?072?= Message-ID: <3bKH9J3GzNz7Lln@mail.python.org> http://hg.python.org/cpython/rev/2ea849fde22b changeset: 83940:2ea849fde22b user: Brett Cannon date: Mon May 27 21:12:40 2013 -0400 summary: NEWS entry for issue #18072 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 @@ -100,6 +100,9 @@ Library ------- +- Issue #18072: Implement importlib.abc.InspectLoader.get_code() and + importlib.abc.ExecutionLoader.get_code(). + - Issue #8240: Set the SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER flag on SSL sockets. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 03:34:35 2013 From: python-checkins at python.org (terry.reedy) Date: Tue, 28 May 2013 03:34:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE1Mzky?= =?utf-8?q?=3A_Create_a_unittest_framework_for_IDLE=2E?= Message-ID: <3bKHfM1nk0z7LmQ@mail.python.org> http://hg.python.org/cpython/rev/24c3e7e08168 changeset: 83941:24c3e7e08168 branch: 3.3 parent: 83934:e57c8a90b2df user: Terry Jan Reedy date: Mon May 27 21:32:03 2013 -0400 summary: Issue #15392: Create a unittest framework for IDLE. Preliminary patch by Rajagopalasarma Jayakrishnan. files: Lib/idlelib/CallTips.py | 4 +- Lib/idlelib/PathBrowser.py | 3 +- Lib/idlelib/idle_test/@README.txt | 63 +++++++++++ Lib/idlelib/idle_test/__init__.py | 9 + Lib/idlelib/idle_test/test_calltips.py | 11 + Lib/idlelib/idle_test/test_pathbrowser.py | 12 ++ Lib/test/test_idle.py | 14 ++ Misc/ACKS | 1 + Misc/NEWS | 3 + 9 files changed, 118 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -264,4 +264,6 @@ print("%d of %d tests failed" % (num_fail, num_tests)) if __name__ == '__main__': - main() + #main() + from unittest import main + main('idlelib.idle_test.test_calltips', verbosity=2, exit=False) diff --git a/Lib/idlelib/PathBrowser.py b/Lib/idlelib/PathBrowser.py --- a/Lib/idlelib/PathBrowser.py +++ b/Lib/idlelib/PathBrowser.py @@ -95,4 +95,5 @@ mainloop() if __name__ == "__main__": - main() + from unittest import main + main('idlelib.idle_test.test_pathbrowser', verbosity=2, exit=False) diff --git a/Lib/idlelib/idle_test/@README.txt b/Lib/idlelib/idle_test/@README.txt new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/@README.txt @@ -0,0 +1,63 @@ +README FOR IDLE TESTS IN IDLELIB.IDLE_TEST + +The idle directory, idlelib, has over 60 xyz.py files. The idle_test +subdirectory should contain a test_xyy.py for each one. (For test modules, +make 'xyz' lower case.) Each should start with the following cut-paste +template, with the blanks after after '.'. 'as', and '_' filled in. +--- +import unittest +import idlelib. as + +class Test_(unittest.TestCase): + + def test_(self): + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=2) +--- +Idle tests are run with unittest; do not use regrtest's test_main. + +Once test_xyy is written, the following should go at the end of xyy.py, +with xyz (lowercased) added after 'test_'. +--- +if __name__ == "__main__": + import unittest + unittest.main('idlelib.idle_test.test_', verbosity=2, exit=False) +--- + +In Idle, pressing F5 in an editor window with either xyz.py or test_xyz.py +loaded will then run the test with the version of Python running Idle and +tracebacks will appear in the Shell window. The options are appropriate for +developers running (as opposed to importing) either type of file during +development: verbosity=2 lists all test_y methods; exit=False avoids a +spurious sys.exit traceback when running in Idle. The following command +lines also run test_xyz.py + +python -m idlelib.xyz # With the capitalization of the xyz module +python -m unittest -v idlelib.idle_test.test_xyz + +To run all idle tests either interactively ('>>>', with unittest imported) +or from a command line, use one of the following. + +>>> unittest.main('idlelib.idle_test', verbosity=2, exit=False) +python -m unittest -v idlelib.idle_test +python -m test.test_idle +python -m test test_idle + +The idle tests are 'discovered' in idlelib.idle_test.__init__.load_tests, +which is also imported into test.test_idle. Normally, neither file should be +changed when working on individual test modules. The last command runs runs +unittest indirectly through regrtest. The same happens when the entire test +suite is run with 'python -m test'. So it must work for buildbots to stay green. + +To run an individual Testcase or test method, extend the +dotted name given to unittest on the command line. + +python -m unittest -v idlelib.idle_test.text_xyz.Test_case.test_meth + +To disable test/test_idle.py, there are at least two choices. +a. Comment out 'load_tests' line, no no tests are discovered (simple and safe); +Running no tests passes, so there is no indication that nothing was run. +b.Before that line, make module an unexpected skip for regrtest with +import unittest; raise unittest.SkipTest('skip for buildbots') +When run directly with unittest, this causes a normal exit and traceback. \ No newline at end of file diff --git a/Lib/idlelib/idle_test/__init__.py b/Lib/idlelib/idle_test/__init__.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/__init__.py @@ -0,0 +1,9 @@ +from os.path import dirname + +def load_tests(loader, standard_tests, pattern): + this_dir = dirname(__file__) + top_dir = dirname(dirname(this_dir)) + package_tests = loader.discover(start_dir=this_dir, pattern='test*.py', + top_level_dir=top_dir) + standard_tests.addTests(package_tests) + return standard_tests diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -0,0 +1,11 @@ +import unittest +import idlelib.CallTips as ct + +class Test_get_entity(unittest.TestCase): + def test_bad_entity(self): + self.assertIsNone(ct.get_entity('1/0')) + def test_good_entity(self): + self.assertIs(ct.get_entity('int'), int) + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=False) diff --git a/Lib/idlelib/idle_test/test_pathbrowser.py b/Lib/idlelib/idle_test/test_pathbrowser.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/test_pathbrowser.py @@ -0,0 +1,12 @@ +import unittest +import idlelib.PathBrowser as PathBrowser + +class PathBrowserTest(unittest.TestCase): + + def test_DirBrowserTreeItem(self): + # Issue16226 - make sure that getting a sublist works + d = PathBrowser.DirBrowserTreeItem('') + d.GetSubList() + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=False) diff --git a/Lib/test/test_idle.py b/Lib/test/test_idle.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_idle.py @@ -0,0 +1,14 @@ +# Skip test if tkinter wasn't built or idlelib was deleted. +from test.support import import_module +import_module('tkinter') # discard return +itdir = import_module('idlelib.idle_test') + +# Without test_main present, regrtest.runtest_inner (line1219) +# imitates unittest.main by calling +# unittest.TestLoader().loadTestsFromModule(this_module) +# which look for load_tests and uses it if found. +load_tests = itdir.load_tests + +if __name__ == '__main__': + import unittest + unittest.main(verbosity=2, exit=False) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -575,6 +575,7 @@ Bill Janssen Thomas Jarosch Juhana Jauhiainen +Rajagopalasarma Jayakrishnan Zbigniew J?drzejewski-Szmek Julien Jehannet Drew Jenkins diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -46,6 +46,9 @@ IDLE ---- +- Issue #15392: Create a unittest framework for IDLE. + Rajagopalasarma Jayakrishnan + - Issue #14146: Highlight source line while debugging on Windows. - Issue #17532: Always include Options menu for IDLE on OS X. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 03:34:36 2013 From: python-checkins at python.org (terry.reedy) Date: Tue, 28 May 2013 03:34:36 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E3?= Message-ID: <3bKHfN4rr2z7LmQ@mail.python.org> http://hg.python.org/cpython/rev/c5d4c041ab47 changeset: 83942:c5d4c041ab47 parent: 83940:2ea849fde22b parent: 83941:24c3e7e08168 user: Terry Jan Reedy date: Mon May 27 21:33:40 2013 -0400 summary: Merge with 3.3 files: Lib/idlelib/CallTips.py | 4 +- Lib/idlelib/PathBrowser.py | 3 +- Lib/idlelib/idle_test/@README.txt | 63 +++++++++++ Lib/idlelib/idle_test/__init__.py | 9 + Lib/idlelib/idle_test/test_calltips.py | 11 + Lib/idlelib/idle_test/test_pathbrowser.py | 12 ++ Lib/test/test_idle.py | 14 ++ Misc/ACKS | 1 + Misc/NEWS | 3 + 9 files changed, 118 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -264,4 +264,6 @@ print("%d of %d tests failed" % (num_fail, num_tests)) if __name__ == '__main__': - main() + #main() + from unittest import main + main('idlelib.idle_test.test_calltips', verbosity=2, exit=False) diff --git a/Lib/idlelib/PathBrowser.py b/Lib/idlelib/PathBrowser.py --- a/Lib/idlelib/PathBrowser.py +++ b/Lib/idlelib/PathBrowser.py @@ -95,4 +95,5 @@ mainloop() if __name__ == "__main__": - main() + from unittest import main + main('idlelib.idle_test.test_pathbrowser', verbosity=2, exit=False) diff --git a/Lib/idlelib/idle_test/@README.txt b/Lib/idlelib/idle_test/@README.txt new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/@README.txt @@ -0,0 +1,63 @@ +README FOR IDLE TESTS IN IDLELIB.IDLE_TEST + +The idle directory, idlelib, has over 60 xyz.py files. The idle_test +subdirectory should contain a test_xyy.py for each one. (For test modules, +make 'xyz' lower case.) Each should start with the following cut-paste +template, with the blanks after after '.'. 'as', and '_' filled in. +--- +import unittest +import idlelib. as + +class Test_(unittest.TestCase): + + def test_(self): + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=2) +--- +Idle tests are run with unittest; do not use regrtest's test_main. + +Once test_xyy is written, the following should go at the end of xyy.py, +with xyz (lowercased) added after 'test_'. +--- +if __name__ == "__main__": + import unittest + unittest.main('idlelib.idle_test.test_', verbosity=2, exit=False) +--- + +In Idle, pressing F5 in an editor window with either xyz.py or test_xyz.py +loaded will then run the test with the version of Python running Idle and +tracebacks will appear in the Shell window. The options are appropriate for +developers running (as opposed to importing) either type of file during +development: verbosity=2 lists all test_y methods; exit=False avoids a +spurious sys.exit traceback when running in Idle. The following command +lines also run test_xyz.py + +python -m idlelib.xyz # With the capitalization of the xyz module +python -m unittest -v idlelib.idle_test.test_xyz + +To run all idle tests either interactively ('>>>', with unittest imported) +or from a command line, use one of the following. + +>>> unittest.main('idlelib.idle_test', verbosity=2, exit=False) +python -m unittest -v idlelib.idle_test +python -m test.test_idle +python -m test test_idle + +The idle tests are 'discovered' in idlelib.idle_test.__init__.load_tests, +which is also imported into test.test_idle. Normally, neither file should be +changed when working on individual test modules. The last command runs runs +unittest indirectly through regrtest. The same happens when the entire test +suite is run with 'python -m test'. So it must work for buildbots to stay green. + +To run an individual Testcase or test method, extend the +dotted name given to unittest on the command line. + +python -m unittest -v idlelib.idle_test.text_xyz.Test_case.test_meth + +To disable test/test_idle.py, there are at least two choices. +a. Comment out 'load_tests' line, no no tests are discovered (simple and safe); +Running no tests passes, so there is no indication that nothing was run. +b.Before that line, make module an unexpected skip for regrtest with +import unittest; raise unittest.SkipTest('skip for buildbots') +When run directly with unittest, this causes a normal exit and traceback. \ No newline at end of file diff --git a/Lib/idlelib/idle_test/__init__.py b/Lib/idlelib/idle_test/__init__.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/__init__.py @@ -0,0 +1,9 @@ +from os.path import dirname + +def load_tests(loader, standard_tests, pattern): + this_dir = dirname(__file__) + top_dir = dirname(dirname(this_dir)) + package_tests = loader.discover(start_dir=this_dir, pattern='test*.py', + top_level_dir=top_dir) + standard_tests.addTests(package_tests) + return standard_tests diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -0,0 +1,11 @@ +import unittest +import idlelib.CallTips as ct + +class Test_get_entity(unittest.TestCase): + def test_bad_entity(self): + self.assertIsNone(ct.get_entity('1/0')) + def test_good_entity(self): + self.assertIs(ct.get_entity('int'), int) + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=False) diff --git a/Lib/idlelib/idle_test/test_pathbrowser.py b/Lib/idlelib/idle_test/test_pathbrowser.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/test_pathbrowser.py @@ -0,0 +1,12 @@ +import unittest +import idlelib.PathBrowser as PathBrowser + +class PathBrowserTest(unittest.TestCase): + + def test_DirBrowserTreeItem(self): + # Issue16226 - make sure that getting a sublist works + d = PathBrowser.DirBrowserTreeItem('') + d.GetSubList() + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=False) diff --git a/Lib/test/test_idle.py b/Lib/test/test_idle.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_idle.py @@ -0,0 +1,14 @@ +# Skip test if tkinter wasn't built or idlelib was deleted. +from test.support import import_module +import_module('tkinter') # discard return +itdir = import_module('idlelib.idle_test') + +# Without test_main present, regrtest.runtest_inner (line1219) +# imitates unittest.main by calling +# unittest.TestLoader().loadTestsFromModule(this_module) +# which look for load_tests and uses it if found. +load_tests = itdir.load_tests + +if __name__ == '__main__': + import unittest + unittest.main(verbosity=2, exit=False) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -584,6 +584,7 @@ Bill Janssen Thomas Jarosch Juhana Jauhiainen +Rajagopalasarma Jayakrishnan Zbigniew J?drzejewski-Szmek Julien Jehannet Drew Jenkins diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,9 @@ - Issue #17206: Py_CLEAR(), Py_DECREF(), Py_XINCREF() and Py_XDECREF() now expand their arguments once instead of multiple times. Patch written by Illia Polosukhin. +- Issue #15392: Create a unittest framework for IDLE. + Rajagopalasarma Jayakrishnan + - Issue #17937: Try harder to collect cyclic garbage at shutdown. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 05:28:40 2013 From: python-checkins at python.org (jason.coombs) Date: Tue, 28 May 2013 05:28:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzEzNzcy?= =?utf-8?q?=3A_Restored_directory_detection_of_targets_in_=60os=2Esymlink?= =?utf-8?q?=60_on?= Message-ID: <3bKLB05tCRz7LmY@mail.python.org> http://hg.python.org/cpython/rev/29a2557d693e changeset: 83943:29a2557d693e branch: 3.3 parent: 83941:24c3e7e08168 user: Jason R. Coombs date: Mon May 27 23:21:28 2013 -0400 summary: Issue #13772: Restored directory detection of targets in `os.symlink` on Windows, which was temporarily removed in Python 3.2.3 due to an incomplete implementation. The implementation now works even if the symlink is created in a location other than the current directory. files: Doc/library/os.rst | 8 +- Lib/test/test_os.py | 44 ++++++++- Misc/NEWS | 5 + Modules/posixmodule.c | 129 +++++++++++++++++++++++++++++- 4 files changed, 173 insertions(+), 13 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2023,9 +2023,10 @@ Create a symbolic link pointing to *source* named *link_name*. On Windows, a symlink represents either a file or a directory, and does not - morph to the target dynamically. If *target_is_directory* is set to ``True``, - the symlink will be created as a directory symlink, otherwise as a file symlink - (the default). On non-Window platforms, *target_is_directory* is ignored. + morph to the target dynamically. If the target is present, the type of the + symlink will be created to match. Otherwise, the symlink will be created + as a directory if *target_is_directory* is ``True`` or a file symlink (the + default) otherwise. On non-Window platforms, *target_is_directory* is ignored. Symbolic link support was introduced in Windows 6.0 (Vista). :func:`symlink` will raise a :exc:`NotImplementedError` on Windows versions earlier than 6.0. @@ -2041,6 +2042,7 @@ to the administrator level. Either obtaining the privilege or running your application as an administrator are ways to successfully create symlinks. + :exc:`OSError` is raised when the function is called by an unprivileged user. diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -686,13 +686,8 @@ f.write("I'm " + path + " and proud of it. Blame test_os.\n") f.close() if support.can_symlink(): - if os.name == 'nt': - def symlink_to_dir(src, dest): - os.symlink(src, dest, True) - else: - symlink_to_dir = os.symlink - symlink_to_dir(os.path.abspath(t2_path), link_path) - symlink_to_dir('broken', broken_link_path) + os.symlink(os.path.abspath(t2_path), link_path) + symlink_to_dir('broken', broken_link_path, True) sub2_tree = (sub2_path, ["link"], ["broken_link", "tmp3"]) else: sub2_tree = (sub2_path, [], ["tmp3"]) @@ -1516,7 +1511,7 @@ os.remove(self.missing_link) def test_directory_link(self): - os.symlink(self.dirlink_target, self.dirlink, True) + os.symlink(self.dirlink_target, self.dirlink) self.assertTrue(os.path.exists(self.dirlink)) self.assertTrue(os.path.isdir(self.dirlink)) self.assertTrue(os.path.islink(self.dirlink)) @@ -1610,6 +1605,38 @@ shutil.rmtree(level1) + at support.skip_unless_symlink +class NonLocalSymlinkTests(unittest.TestCase): + + def setUp(self): + """ + Create this structure: + + base + \___ some_dir + """ + os.makedirs('base/some_dir') + + def tearDown(self): + shutil.rmtree('base') + + def test_directory_link_nonlocal(self): + """ + The symlink target should resolve relative to the link, not relative + to the current directory. + + Then, link base/some_link -> base/some_dir and ensure that some_link + is resolved as a directory. + + In issue13772, it was discovered that directory detection failed if + the symlink target was not specified relative to the current + directory, which was a defect in the implementation. + """ + src = os.path.join('base', 'some_link') + os.symlink('some_dir', src) + assert os.path.isdir(src) + + class FSEncodingTests(unittest.TestCase): def test_nop(self): self.assertEqual(os.fsencode(b'abc\xff'), b'abc\xff') @@ -2137,6 +2164,7 @@ Pep383Tests, Win32KillTests, Win32SymlinkTests, + NonLocalSymlinkTests, FSEncodingTests, DeviceEncodingTests, PidTests, diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,11 @@ Library ------- +- Issue #13772: Restored directory detection of targets in ``os.symlink`` on + Windows, which was temporarily removed in Python 3.2.3 due to an incomplete + implementation. The implementation now works even if the symlink is created + in a location other than the current directory. + - Issue #16986: ElementTree now correctly parses a string input not only when an internal XML encoding is UTF-8 or US-ASCII. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7200,6 +7200,124 @@ return (Py_CreateSymbolicLinkW && Py_CreateSymbolicLinkA); } +void _dirnameW(WCHAR *path) { + /* Remove the last portion of the path */ + + WCHAR *ptr; + + /* walk the path from the end until a backslash is encountered */ + for(ptr = path + wcslen(path); ptr != path; ptr--) + { + if(*ptr == *L"\\" || *ptr == *L"/") { + break; + } + } + *ptr = 0; +} + +void _dirnameA(char *path) { + /* Remove the last portion of the path */ + + char *ptr; + + /* walk the path from the end until a backslash is encountered */ + for(ptr = path + strlen(path); ptr != path; ptr--) + { + if(*ptr == '\\' || *ptr == '/') { + break; + } + } + *ptr = 0; +} + +int _is_absW(WCHAR *path) { + /* Is this path absolute? */ + + return path[0] == L'\\' || path[0] == L'/' || path[1] == L':'; + +} + +int _is_absA(char *path) { + /* Is this path absolute? */ + + return path[0] == '\\' || path[0] == '/' || path[1] == ':'; + +} + +void _joinW(WCHAR *dest_path, const WCHAR *root, const WCHAR *rest) { + /* join root and rest with a backslash */ + int root_len; + + if(_is_absW(rest)) { + wcscpy(dest_path, rest); + return; + } + + root_len = wcslen(root); + + wcscpy(dest_path, root); + if(root_len) { + dest_path[root_len] = *L"\\"; + root_len += 1; + } + wcscpy(dest_path+root_len, rest); +} + +void _joinA(char *dest_path, const char *root, const char *rest) { + /* join root and rest with a backslash */ + int root_len; + + if(_is_absA(rest)) { + strcpy(dest_path, rest); + return; + } + + root_len = strlen(root); + + strcpy(dest_path, root); + if(root_len) { + dest_path[root_len] = '\\'; + root_len += 1; + } + strcpy(dest_path+root_len, rest); +} + +int _check_dirW(WCHAR *src, WCHAR *dest) +{ + /* Return True if the path at src relative to dest is a directory */ + WIN32_FILE_ATTRIBUTE_DATA src_info; + WCHAR dest_parent[MAX_PATH]; + WCHAR src_resolved[MAX_PATH] = L""; + + /* dest_parent = os.path.dirname(dest) */ + wcscpy(dest_parent, dest); + _dirnameW(dest_parent); + /* src_resolved = os.path.join(dest_parent, src) */ + _joinW(src_resolved, dest_parent, src); + return ( + GetFileAttributesExW(src_resolved, GetFileExInfoStandard, &src_info) + && src_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY + ); +} + +int _check_dirA(char *src, char *dest) +{ + /* Return True if the path at src relative to dest is a directory */ + WIN32_FILE_ATTRIBUTE_DATA src_info; + char dest_parent[MAX_PATH]; + char src_resolved[MAX_PATH] = ""; + + /* dest_parent = os.path.dirname(dest) */ + strcpy(dest_parent, dest); + _dirnameW(dest_parent); + /* src_resolved = os.path.join(dest_parent, src) */ + _joinW(src_resolved, dest_parent, src); + return ( + GetFileAttributesExA(src_resolved, GetFileExInfoStandard, &src_info) + && src_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY + ); +} + #endif static PyObject * @@ -7256,13 +7374,20 @@ } #ifdef MS_WINDOWS + Py_BEGIN_ALLOW_THREADS - if (dst.wide) + if (dst.wide) { + /* if src is a directory, ensure target_is_directory==1 */ + target_is_directory |= _check_dirW(src.wide, dst.wide); result = Py_CreateSymbolicLinkW(dst.wide, src.wide, target_is_directory); - else + } + else { + /* if src is a directory, ensure target_is_directory==1 */ + target_is_directory |= _check_dirA(src.narrow, dst.narrow); result = Py_CreateSymbolicLinkA(dst.narrow, src.narrow, target_is_directory); + } Py_END_ALLOW_THREADS if (!result) { -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 05:28:42 2013 From: python-checkins at python.org (jason.coombs) Date: Tue, 28 May 2013 05:28:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E3?= Message-ID: <3bKLB2258mz7Lmb@mail.python.org> http://hg.python.org/cpython/rev/138ddf15b220 changeset: 83944:138ddf15b220 parent: 83942:c5d4c041ab47 parent: 83943:29a2557d693e user: Jason R. Coombs date: Mon May 27 23:26:36 2013 -0400 summary: Merge with 3.3 files: Doc/library/os.rst | 8 +- Lib/test/test_os.py | 44 ++++++++- Modules/posixmodule.c | 129 +++++++++++++++++++++++++++++- 3 files changed, 168 insertions(+), 13 deletions(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2024,9 +2024,10 @@ Create a symbolic link pointing to *source* named *link_name*. On Windows, a symlink represents either a file or a directory, and does not - morph to the target dynamically. If *target_is_directory* is set to ``True``, - the symlink will be created as a directory symlink, otherwise as a file symlink - (the default). On non-Window platforms, *target_is_directory* is ignored. + morph to the target dynamically. If the target is present, the type of the + symlink will be created to match. Otherwise, the symlink will be created + as a directory if *target_is_directory* is ``True`` or a file symlink (the + default) otherwise. On non-Window platforms, *target_is_directory* is ignored. Symbolic link support was introduced in Windows 6.0 (Vista). :func:`symlink` will raise a :exc:`NotImplementedError` on Windows versions earlier than 6.0. @@ -2042,6 +2043,7 @@ to the administrator level. Either obtaining the privilege or running your application as an administrator are ways to successfully create symlinks. + :exc:`OSError` is raised when the function is called by an unprivileged user. diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -686,13 +686,8 @@ f.write("I'm " + path + " and proud of it. Blame test_os.\n") f.close() if support.can_symlink(): - if os.name == 'nt': - def symlink_to_dir(src, dest): - os.symlink(src, dest, True) - else: - symlink_to_dir = os.symlink - symlink_to_dir(os.path.abspath(t2_path), link_path) - symlink_to_dir('broken', broken_link_path) + os.symlink(os.path.abspath(t2_path), link_path) + symlink_to_dir('broken', broken_link_path, True) sub2_tree = (sub2_path, ["link"], ["broken_link", "tmp3"]) else: sub2_tree = (sub2_path, [], ["tmp3"]) @@ -1516,7 +1511,7 @@ os.remove(self.missing_link) def test_directory_link(self): - os.symlink(self.dirlink_target, self.dirlink, True) + os.symlink(self.dirlink_target, self.dirlink) self.assertTrue(os.path.exists(self.dirlink)) self.assertTrue(os.path.isdir(self.dirlink)) self.assertTrue(os.path.islink(self.dirlink)) @@ -1610,6 +1605,38 @@ shutil.rmtree(level1) + at support.skip_unless_symlink +class NonLocalSymlinkTests(unittest.TestCase): + + def setUp(self): + """ + Create this structure: + + base + \___ some_dir + """ + os.makedirs('base/some_dir') + + def tearDown(self): + shutil.rmtree('base') + + def test_directory_link_nonlocal(self): + """ + The symlink target should resolve relative to the link, not relative + to the current directory. + + Then, link base/some_link -> base/some_dir and ensure that some_link + is resolved as a directory. + + In issue13772, it was discovered that directory detection failed if + the symlink target was not specified relative to the current + directory, which was a defect in the implementation. + """ + src = os.path.join('base', 'some_link') + os.symlink('some_dir', src) + assert os.path.isdir(src) + + class FSEncodingTests(unittest.TestCase): def test_nop(self): self.assertEqual(os.fsencode(b'abc\xff'), b'abc\xff') @@ -2243,6 +2270,7 @@ Pep383Tests, Win32KillTests, Win32SymlinkTests, + NonLocalSymlinkTests, FSEncodingTests, DeviceEncodingTests, PidTests, diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -6735,6 +6735,124 @@ return (Py_CreateSymbolicLinkW && Py_CreateSymbolicLinkA); } +void _dirnameW(WCHAR *path) { + /* Remove the last portion of the path */ + + WCHAR *ptr; + + /* walk the path from the end until a backslash is encountered */ + for(ptr = path + wcslen(path); ptr != path; ptr--) + { + if(*ptr == *L"\\" || *ptr == *L"/") { + break; + } + } + *ptr = 0; +} + +void _dirnameA(char *path) { + /* Remove the last portion of the path */ + + char *ptr; + + /* walk the path from the end until a backslash is encountered */ + for(ptr = path + strlen(path); ptr != path; ptr--) + { + if(*ptr == '\\' || *ptr == '/') { + break; + } + } + *ptr = 0; +} + +int _is_absW(WCHAR *path) { + /* Is this path absolute? */ + + return path[0] == L'\\' || path[0] == L'/' || path[1] == L':'; + +} + +int _is_absA(char *path) { + /* Is this path absolute? */ + + return path[0] == '\\' || path[0] == '/' || path[1] == ':'; + +} + +void _joinW(WCHAR *dest_path, const WCHAR *root, const WCHAR *rest) { + /* join root and rest with a backslash */ + int root_len; + + if(_is_absW(rest)) { + wcscpy(dest_path, rest); + return; + } + + root_len = wcslen(root); + + wcscpy(dest_path, root); + if(root_len) { + dest_path[root_len] = *L"\\"; + root_len += 1; + } + wcscpy(dest_path+root_len, rest); +} + +void _joinA(char *dest_path, const char *root, const char *rest) { + /* join root and rest with a backslash */ + int root_len; + + if(_is_absA(rest)) { + strcpy(dest_path, rest); + return; + } + + root_len = strlen(root); + + strcpy(dest_path, root); + if(root_len) { + dest_path[root_len] = '\\'; + root_len += 1; + } + strcpy(dest_path+root_len, rest); +} + +int _check_dirW(WCHAR *src, WCHAR *dest) +{ + /* Return True if the path at src relative to dest is a directory */ + WIN32_FILE_ATTRIBUTE_DATA src_info; + WCHAR dest_parent[MAX_PATH]; + WCHAR src_resolved[MAX_PATH] = L""; + + /* dest_parent = os.path.dirname(dest) */ + wcscpy(dest_parent, dest); + _dirnameW(dest_parent); + /* src_resolved = os.path.join(dest_parent, src) */ + _joinW(src_resolved, dest_parent, src); + return ( + GetFileAttributesExW(src_resolved, GetFileExInfoStandard, &src_info) + && src_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY + ); +} + +int _check_dirA(char *src, char *dest) +{ + /* Return True if the path at src relative to dest is a directory */ + WIN32_FILE_ATTRIBUTE_DATA src_info; + char dest_parent[MAX_PATH]; + char src_resolved[MAX_PATH] = ""; + + /* dest_parent = os.path.dirname(dest) */ + strcpy(dest_parent, dest); + _dirnameW(dest_parent); + /* src_resolved = os.path.join(dest_parent, src) */ + _joinW(src_resolved, dest_parent, src); + return ( + GetFileAttributesExA(src_resolved, GetFileExInfoStandard, &src_info) + && src_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY + ); +} + #endif static PyObject * @@ -6793,13 +6911,20 @@ } #ifdef MS_WINDOWS + Py_BEGIN_ALLOW_THREADS - if (dst.wide) + if (dst.wide) { + /* if src is a directory, ensure target_is_directory==1 */ + target_is_directory |= _check_dirW(src.wide, dst.wide); result = Py_CreateSymbolicLinkW(dst.wide, src.wide, target_is_directory); - else + } + else { + /* if src is a directory, ensure target_is_directory==1 */ + target_is_directory |= _check_dirA(src.narrow, dst.narrow); result = Py_CreateSymbolicLinkA(dst.narrow, src.narrow, target_is_directory); + } Py_END_ALLOW_THREADS if (!result) { -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Tue May 28 05:49:28 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 28 May 2013 05:49:28 +0200 Subject: [Python-checkins] Daily reference leaks (2ea849fde22b): sum=1 Message-ID: results for 2ea849fde22b on branch "default" -------------------------------------------- test_unittest leaked [0, -1, 2] memory blocks, sum=1 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogufxu2q', '-x'] From python-checkins at python.org Tue May 28 05:53:15 2013 From: python-checkins at python.org (jason.coombs) Date: Tue, 28 May 2013 05:53:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Use_simple_cal?= =?utf-8?q?l_to_os=2Esymlink_for_broken_link_=28intended_for_previous_comm?= =?utf-8?b?aXQp?= Message-ID: <3bKLkM2L4dz7Lln@mail.python.org> http://hg.python.org/cpython/rev/8cebe8d537a4 changeset: 83945:8cebe8d537a4 branch: 3.3 parent: 83943:29a2557d693e user: Jason R. Coombs date: Mon May 27 23:52:43 2013 -0400 summary: Use simple call to os.symlink for broken link (intended for previous commit) files: Lib/test/test_os.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -687,7 +687,7 @@ f.close() if support.can_symlink(): os.symlink(os.path.abspath(t2_path), link_path) - symlink_to_dir('broken', broken_link_path, True) + os.symlink('broken', broken_link_path, True) sub2_tree = (sub2_path, ["link"], ["broken_link", "tmp3"]) else: sub2_tree = (sub2_path, [], ["tmp3"]) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 05:53:16 2013 From: python-checkins at python.org (jason.coombs) Date: Tue, 28 May 2013 05:53:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E3?= Message-ID: <3bKLkN4Kwsz7Lms@mail.python.org> http://hg.python.org/cpython/rev/eb1025b107c5 changeset: 83946:eb1025b107c5 parent: 83944:138ddf15b220 parent: 83945:8cebe8d537a4 user: Jason R. Coombs date: Mon May 27 23:53:02 2013 -0400 summary: Merge with 3.3 files: Lib/test/test_os.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -687,7 +687,7 @@ f.close() if support.can_symlink(): os.symlink(os.path.abspath(t2_path), link_path) - symlink_to_dir('broken', broken_link_path, True) + os.symlink('broken', broken_link_path, True) sub2_tree = (sub2_path, ["link"], ["broken_link", "tmp3"]) else: sub2_tree = (sub2_path, [], ["tmp3"]) -- Repository URL: http://hg.python.org/cpython From benjamin at python.org Tue May 28 08:14:03 2013 From: benjamin at python.org (Benjamin Peterson) Date: Mon, 27 May 2013 23:14:03 -0700 Subject: [Python-checkins] cpython (merge 3.3 -> default): Merge with 3.3 In-Reply-To: <3bKHfN4rr2z7LmQ@mail.python.org> References: <3bKHfN4rr2z7LmQ@mail.python.org> Message-ID: 2013/5/27 terry.reedy : > http://hg.python.org/cpython/rev/c5d4c041ab47 > changeset: 83942:c5d4c041ab47 > parent: 83940:2ea849fde22b > parent: 83941:24c3e7e08168 > user: Terry Jan Reedy > date: Mon May 27 21:33:40 2013 -0400 > summary: > Merge with 3.3 > > files: > Lib/idlelib/CallTips.py | 4 +- > Lib/idlelib/PathBrowser.py | 3 +- > Lib/idlelib/idle_test/@README.txt | 63 +++++++++++ Is @README really the intended name of this file? Would README-TEST or something similar be better? -- Regards, Benjamin From python-checkins at python.org Tue May 28 11:53:28 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 28 May 2013 11:53:28 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MDc5?= =?utf-8?q?=3A_Fix_a_typo_in_the_tutorial=2E?= Message-ID: <3bKVk02yjpzPbb@mail.python.org> http://hg.python.org/cpython/rev/bde91dddbcbc changeset: 83947:bde91dddbcbc branch: 3.3 parent: 83945:8cebe8d537a4 user: Serhiy Storchaka date: Tue May 28 12:49:34 2013 +0300 summary: Issue #18079: Fix a typo in the tutorial. files: Doc/tutorial/introduction.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -447,9 +447,9 @@ >>> x = [a, n] >>> x [['a', 'b', 'c'], [1, 2, 3]] - >>> p[0] + >>> x[0] ['a', 'b', 'c'] - >>> p[0][1] + >>> x[0][1] 'b' .. _tut-firststeps: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 11:53:29 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 28 May 2013 11:53:29 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318079=3A_Fix_a_typo_in_the_tutorial=2E?= Message-ID: <3bKVk14mvWzQD5@mail.python.org> http://hg.python.org/cpython/rev/09b88b5bebd0 changeset: 83948:09b88b5bebd0 parent: 83946:eb1025b107c5 parent: 83947:bde91dddbcbc user: Serhiy Storchaka date: Tue May 28 12:50:54 2013 +0300 summary: Issue #18079: Fix a typo in the tutorial. files: Doc/tutorial/introduction.rst | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -447,9 +447,9 @@ >>> x = [a, n] >>> x [['a', 'b', 'c'], [1, 2, 3]] - >>> p[0] + >>> x[0] ['a', 'b', 'c'] - >>> p[0][1] + >>> x[0][1] 'b' .. _tut-firststeps: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 14:35:30 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 28 May 2013 14:35:30 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MDEx?= =?utf-8?q?=3A_base64=2Eb32decode=28=29_now_raises_a_binascii=2EError_if_t?= =?utf-8?q?here_are?= Message-ID: <3bKZJy5w4vzRfN@mail.python.org> http://hg.python.org/cpython/rev/0b9bcb2ac145 changeset: 83949:0b9bcb2ac145 branch: 3.3 parent: 83947:bde91dddbcbc user: Serhiy Storchaka date: Tue May 28 15:27:29 2013 +0300 summary: Issue #18011: base64.b32decode() now raises a binascii.Error if there are non-alphabet characters present in the input string to conform a docstring. Updated the module documentation. files: Doc/library/base64.rst | 2 +- Lib/base64.py | 2 +- Lib/test/test_base64.py | 8 +++++--- Misc/NEWS | 4 ++++ 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Doc/library/base64.rst b/Doc/library/base64.rst --- a/Doc/library/base64.rst +++ b/Doc/library/base64.rst @@ -103,7 +103,7 @@ digit 0 is always mapped to the letter O). For security purposes the default is ``None``, so that 0 and 1 are not allowed in the input. - The decoded byte string is returned. A :exc:`TypeError` is raised if *s* were + The decoded byte string is returned. A :exc:`binascii.Error` is raised if *s* were incorrectly padded or if there are non-alphabet characters present in the string. diff --git a/Lib/base64.py b/Lib/base64.py --- a/Lib/base64.py +++ b/Lib/base64.py @@ -245,7 +245,7 @@ for c in s: val = _b32rev.get(c) if val is None: - raise TypeError('Non-base32 digit found') + raise binascii.Error('Non-base32 digit found') acc += _b32rev[c] << shift shift -= 5 if shift < 0: diff --git a/Lib/test/test_base64.py b/Lib/test/test_base64.py --- a/Lib/test/test_base64.py +++ b/Lib/test/test_base64.py @@ -244,8 +244,8 @@ eq(base64.b32decode(data, True), res) eq(base64.b32decode(data.decode('ascii'), True), res) - self.assertRaises(TypeError, base64.b32decode, b'me======') - self.assertRaises(TypeError, base64.b32decode, 'me======') + self.assertRaises(binascii.Error, base64.b32decode, b'me======') + self.assertRaises(binascii.Error, base64.b32decode, 'me======') # Mapping zero and one eq(base64.b32decode(b'MLO23456'), b'b\xdd\xad\xf3\xbe') @@ -262,9 +262,11 @@ eq(base64.b32decode(data_str, map01=map01), res) eq(base64.b32decode(data, map01=map01_str), res) eq(base64.b32decode(data_str, map01=map01_str), res) + self.assertRaises(binascii.Error, base64.b32decode, data) + self.assertRaises(binascii.Error, base64.b32decode, data_str) def test_b32decode_error(self): - for data in [b'abc', b'ABCDEF==']: + for data in [b'abc', b'ABCDEF==', b'==ABCDEF']: with self.assertRaises(binascii.Error): base64.b32decode(data) with self.assertRaises(binascii.Error): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,10 @@ Library ------- +- Issue #18011: base64.b32decode() now raises a binascii.Error if there are + non-alphabet characters present in the input string to conform a docstring. + Updated the module documentation. + - Issue #13772: Restored directory detection of targets in ``os.symlink`` on Windows, which was temporarily removed in Python 3.2.3 due to an incomplete implementation. The implementation now works even if the symlink is created -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 14:35:32 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 28 May 2013 14:35:32 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318011=3A_base64=2Eb32decode=28=29_now_raises_a_?= =?utf-8?q?binascii=2EError_if_there_are?= Message-ID: <3bKZK00zrVzRKN@mail.python.org> http://hg.python.org/cpython/rev/7446f53ba2d2 changeset: 83950:7446f53ba2d2 parent: 83948:09b88b5bebd0 parent: 83949:0b9bcb2ac145 user: Serhiy Storchaka date: Tue May 28 15:30:38 2013 +0300 summary: Issue #18011: base64.b32decode() now raises a binascii.Error if there are non-alphabet characters present in the input string to conform a docstring. Updated the module documentation. files: Doc/library/base64.rst | 2 +- Lib/base64.py | 2 +- Lib/test/test_base64.py | 8 +++++--- Misc/NEWS | 4 ++++ 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Doc/library/base64.rst b/Doc/library/base64.rst --- a/Doc/library/base64.rst +++ b/Doc/library/base64.rst @@ -103,7 +103,7 @@ digit 0 is always mapped to the letter O). For security purposes the default is ``None``, so that 0 and 1 are not allowed in the input. - The decoded byte string is returned. A :exc:`TypeError` is raised if *s* were + The decoded byte string is returned. A :exc:`binascii.Error` is raised if *s* were incorrectly padded or if there are non-alphabet characters present in the string. diff --git a/Lib/base64.py b/Lib/base64.py --- a/Lib/base64.py +++ b/Lib/base64.py @@ -222,7 +222,7 @@ for c in quanta: acc = (acc << 5) + b32rev[c] except KeyError: - raise TypeError('Non-base32 digit found') + raise binascii.Error('Non-base32 digit found') decoded += acc.to_bytes(5, 'big') # Process the last, partial quanta if padchars: diff --git a/Lib/test/test_base64.py b/Lib/test/test_base64.py --- a/Lib/test/test_base64.py +++ b/Lib/test/test_base64.py @@ -244,8 +244,8 @@ eq(base64.b32decode(data, True), res) eq(base64.b32decode(data.decode('ascii'), True), res) - self.assertRaises(TypeError, base64.b32decode, b'me======') - self.assertRaises(TypeError, base64.b32decode, 'me======') + self.assertRaises(binascii.Error, base64.b32decode, b'me======') + self.assertRaises(binascii.Error, base64.b32decode, 'me======') # Mapping zero and one eq(base64.b32decode(b'MLO23456'), b'b\xdd\xad\xf3\xbe') @@ -262,9 +262,11 @@ eq(base64.b32decode(data_str, map01=map01), res) eq(base64.b32decode(data, map01=map01_str), res) eq(base64.b32decode(data_str, map01=map01_str), res) + self.assertRaises(binascii.Error, base64.b32decode, data) + self.assertRaises(binascii.Error, base64.b32decode, data_str) def test_b32decode_error(self): - for data in [b'abc', b'ABCDEF==']: + for data in [b'abc', b'ABCDEF==', b'==ABCDEF']: with self.assertRaises(binascii.Error): base64.b32decode(data) with self.assertRaises(binascii.Error): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -103,6 +103,10 @@ Library ------- +- Issue #18011: base64.b32decode() now raises a binascii.Error if there are + non-alphabet characters present in the input string to conform a docstring. + Updated the module documentation. + - Issue #18072: Implement importlib.abc.InspectLoader.get_code() and importlib.abc.ExecutionLoader.get_code(). -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 14:35:33 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 28 May 2013 14:35:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Move_some_Misc/NEWS_entrie?= =?utf-8?q?s_to_correct_place=2E?= Message-ID: <3bKZK13QwxzRW6@mail.python.org> http://hg.python.org/cpython/rev/54f4f9cd686c changeset: 83951:54f4f9cd686c user: Serhiy Storchaka date: Tue May 28 15:34:16 2013 +0300 summary: Move some Misc/NEWS entries to correct place. files: Misc/NEWS | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,13 +10,6 @@ Core and Builtins ----------------- -- Issue #17206: Py_CLEAR(), Py_DECREF(), Py_XINCREF() and Py_XDECREF() now - expand their arguments once instead of multiple times. Patch written by Illia - Polosukhin. -- Issue #15392: Create a unittest framework for IDLE. - Rajagopalasarma Jayakrishnan - - - Issue #17937: Try harder to collect cyclic garbage at shutdown. - Issue #12370: Prevent class bodies from interfering with the __class__ @@ -309,6 +302,9 @@ Tests ----- +- Issue #15392: Create a unittest framework for IDLE. + Rajagopalasarma Jayakrishnan + - Issue #17992: Add timeouts to asyncore and asynchat tests so that they won't accidentally hang. @@ -373,6 +369,10 @@ C-API ----- +- Issue #17206: Py_CLEAR(), Py_DECREF(), Py_XINCREF() and Py_XDECREF() now + expand their arguments once instead of multiple times. Patch written by Illia + Polosukhin. + - Issue #17522: Add the PyGILState_Check() API. - Issue #17327: Add PyDict_SetDefault. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 14:43:16 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 28 May 2013 14:43:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318011=3A_Silence_?= =?utf-8?q?an_unrelated_noise_introduced_in_changeset_1b5ef05d6ced=2E?= Message-ID: <3bKZTw4nLzzP9n@mail.python.org> http://hg.python.org/cpython/rev/29a823f31465 changeset: 83952:29a823f31465 user: Serhiy Storchaka date: Tue May 28 15:42:34 2013 +0300 summary: Issue #18011: Silence an unrelated noise introduced in changeset 1b5ef05d6ced. files: Lib/base64.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/base64.py b/Lib/base64.py --- a/Lib/base64.py +++ b/Lib/base64.py @@ -222,7 +222,7 @@ for c in quanta: acc = (acc << 5) + b32rev[c] except KeyError: - raise binascii.Error('Non-base32 digit found') + raise binascii.Error('Non-base32 digit found') from None decoded += acc.to_bytes(5, 'big') # Process the last, partial quanta if padchars: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 14:56:33 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 28 May 2013 14:56:33 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3NzQ2?= =?utf-8?q?=3A_Skip_test=5Fshutil=2Etest=5Fnon=5Fmatching=5Fmode_when_run_?= =?utf-8?q?as_root_or?= Message-ID: <3bKZnF0hG6zR2r@mail.python.org> http://hg.python.org/cpython/rev/b98380a1d979 changeset: 83953:b98380a1d979 branch: 3.3 parent: 83949:0b9bcb2ac145 user: Serhiy Storchaka date: Tue May 28 15:50:15 2013 +0300 summary: Issue #17746: Skip test_shutil.test_non_matching_mode when run as root or on unsuitable platform/environment. files: Lib/test/test_shutil.py | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -1327,9 +1327,13 @@ # Other platforms: shouldn't match in the current directory. self.assertIsNone(rv) + @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0, + 'non-root user required') def test_non_matching_mode(self): # Set the file read-only and ask for writeable files. os.chmod(self.temp_file.name, stat.S_IREAD) + if os.access(self.temp_file.name, os.W_OK): + self.skipTest("can't set the file read-only") rv = shutil.which(self.file, path=self.dir, mode=os.W_OK) self.assertIsNone(rv) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 14:56:34 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 28 May 2013 14:56:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2317746=3A_Skip_test=5Fshutil=2Etest=5Fnon=5Fmatc?= =?utf-8?q?hing=5Fmode_when_run_as_root_or?= Message-ID: <3bKZnG2RWqzR5x@mail.python.org> http://hg.python.org/cpython/rev/96e543ba96a4 changeset: 83954:96e543ba96a4 parent: 83952:29a823f31465 parent: 83953:b98380a1d979 user: Serhiy Storchaka date: Tue May 28 15:53:46 2013 +0300 summary: Issue #17746: Skip test_shutil.test_non_matching_mode when run as root or on unsuitable platform/environment. files: Lib/test/test_shutil.py | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -1338,9 +1338,13 @@ # Other platforms: shouldn't match in the current directory. self.assertIsNone(rv) + @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0, + 'non-root user required') def test_non_matching_mode(self): # Set the file read-only and ask for writeable files. os.chmod(self.temp_file.name, stat.S_IREAD) + if os.access(self.temp_file.name, os.W_OK): + self.skipTest("can't set the file read-only") rv = shutil.which(self.file, path=self.dir, mode=os.W_OK) self.assertIsNone(rv) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 15:28:14 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 28 May 2013 15:28:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MDI1?= =?utf-8?q?=3A_Fixed_a_segfault_in_io=2EBufferedIOBase=2Ereadinto=28=29_wh?= =?utf-8?q?en_raw?= Message-ID: <3bKbTp3bV6zSVs@mail.python.org> http://hg.python.org/cpython/rev/b864f4056b78 changeset: 83955:b864f4056b78 branch: 3.3 parent: 83953:b98380a1d979 user: Serhiy Storchaka date: Tue May 28 16:24:45 2013 +0300 summary: Issue #18025: Fixed a segfault in io.BufferedIOBase.readinto() when raw stream's read() returns more bytes than requested. files: Lib/test/test_io.py | 9 +++++++++ Misc/NEWS | 3 +++ Modules/_io/bufferedio.c | 8 ++++++++ 3 files changed, 20 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 @@ -3019,6 +3019,15 @@ class CMiscIOTest(MiscIOTest): io = io + def test_readinto_buffer_overflow(self): + # Issue #18025 + class BadReader(self.io.BufferedIOBase): + def read(self, n=-1): + return b'x' * 10**6 + bufio = BadReader() + b = bytearray(2) + self.assertRaises(ValueError, bufio.readinto, b) + class PyMiscIOTest(MiscIOTest): io = pyio diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,9 @@ Library ------- +- Issue #18025: Fixed a segfault in io.BufferedIOBase.readinto() when raw + stream's read() returns more bytes than requested. + - Issue #18011: base64.b32decode() now raises a binascii.Error if there are non-alphabet characters present in the input string to conform a docstring. Updated the module documentation. diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -69,6 +69,14 @@ } len = Py_SIZE(data); + if (len > buf.len) { + PyErr_Format(PyExc_ValueError, + "read() returned too much data: " + "%zd bytes requested, %zd returned", + buf.len, len); + Py_DECREF(data); + goto error; + } memcpy(buf.buf, PyBytes_AS_STRING(data), len); PyBuffer_Release(&buf); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 15:28:15 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 28 May 2013 15:28:15 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318025=3A_Fixed_a_segfault_in_io=2EBufferedIOBas?= =?utf-8?q?e=2Ereadinto=28=29_when_raw?= Message-ID: <3bKbTq5znBzSYs@mail.python.org> http://hg.python.org/cpython/rev/ad56dff3602f changeset: 83956:ad56dff3602f parent: 83954:96e543ba96a4 parent: 83955:b864f4056b78 user: Serhiy Storchaka date: Tue May 28 16:27:08 2013 +0300 summary: Issue #18025: Fixed a segfault in io.BufferedIOBase.readinto() when raw stream's read() returns more bytes than requested. files: Lib/test/test_io.py | 9 +++++++++ Misc/NEWS | 3 +++ Modules/_io/bufferedio.c | 8 ++++++++ 3 files changed, 20 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 @@ -3027,6 +3027,15 @@ class CMiscIOTest(MiscIOTest): io = io + def test_readinto_buffer_overflow(self): + # Issue #18025 + class BadReader(self.io.BufferedIOBase): + def read(self, n=-1): + return b'x' * 10**6 + bufio = BadReader() + b = bytearray(2) + self.assertRaises(ValueError, bufio.readinto, b) + class PyMiscIOTest(MiscIOTest): io = pyio diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -96,6 +96,9 @@ Library ------- +- Issue #18025: Fixed a segfault in io.BufferedIOBase.readinto() when raw + stream's read() returns more bytes than requested. + - Issue #18011: base64.b32decode() now raises a binascii.Error if there are non-alphabet characters present in the input string to conform a docstring. Updated the module documentation. diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -69,6 +69,14 @@ } len = Py_SIZE(data); + if (len > buf.len) { + PyErr_Format(PyExc_ValueError, + "read() returned too much data: " + "%zd bytes requested, %zd returned", + buf.len, len); + Py_DECREF(data); + goto error; + } memcpy(buf.buf, PyBytes_AS_STRING(data), len); PyBuffer_Release(&buf); -- Repository URL: http://hg.python.org/cpython From tjreedy at udel.edu Tue May 28 21:06:39 2013 From: tjreedy at udel.edu (Terry Reedy) Date: Tue, 28 May 2013 15:06:39 -0400 Subject: [Python-checkins] cpython (merge 3.3 -> default): Merge with 3.3 In-Reply-To: References: <3bKHfN4rr2z7LmQ@mail.python.org> Message-ID: <51A5003F.3010603@udel.edu> On 5/28/2013 2:14 AM, Benjamin Peterson wrote: > 2013/5/27 terry.reedy : >> http://hg.python.org/cpython/rev/c5d4c041ab47 >> changeset: 83942:c5d4c041ab47 >> parent: 83940:2ea849fde22b >> parent: 83941:24c3e7e08168 >> user: Terry Jan Reedy >> date: Mon May 27 21:33:40 2013 -0400 >> summary: >> Merge with 3.3 >> >> files: >> Lib/idlelib/CallTips.py | 4 +- >> Lib/idlelib/PathBrowser.py | 3 +- >> Lib/idlelib/idle_test/@README.txt | 63 +++++++++++ > Is @README really the intended name of this file? Yes, Nick suggested README instead of what I had. I want a prefix to keep it near the top of a directory listing even when other non 'test_xxx' files are added. I thing '_' wold be better though. If I can find how to rename in hg, I will do this with today's touchup commit. > Would README-TEST or something similar be better? > Not to me. Terry From python-checkins at python.org Tue May 28 21:48:08 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 28 May 2013 21:48:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MDg1?= =?utf-8?q?=3A_Fix_PyObject=5FCallMethodObjArgs=28=29=27s_entry_in_refcoun?= =?utf-8?q?ts=2Edat=2E?= Message-ID: <3bKlw81sNgz7Lq8@mail.python.org> http://hg.python.org/cpython/rev/0889ab0d0da1 changeset: 83957:0889ab0d0da1 branch: 3.3 parent: 83955:b864f4056b78 user: Serhiy Storchaka date: Tue May 28 22:46:15 2013 +0300 summary: Issue #18085: Fix PyObject_CallMethodObjArgs()'s entry in refcounts.dat. files: Doc/data/refcounts.dat | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -927,7 +927,7 @@ PyObject_CallMethodObjArgs:PyObject*::+1: PyObject_CallMethodObjArgs:PyObject*:o:0: -PyObject_CallMethodObjArgs:char*:name:: +PyObject_CallMethodObjArgs:PyObject*:name:0: PyObject_CallMethodObjArgs::...:: PyObject_CallObject:PyObject*::+1: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 21:48:09 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 28 May 2013 21:48:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4MDg1?= =?utf-8?q?=3A_Fix_PyObject=5FCallMethodObjArgs=28=29=27s_entry_in_refcoun?= =?utf-8?q?ts=2Edat=2E?= Message-ID: <3bKlw93nMKz7LqK@mail.python.org> http://hg.python.org/cpython/rev/ef9d42b98a3d changeset: 83958:ef9d42b98a3d branch: 2.7 parent: 83936:687295c6c8f2 user: Serhiy Storchaka date: Tue May 28 22:46:51 2013 +0300 summary: Issue #18085: Fix PyObject_CallMethodObjArgs()'s entry in refcounts.dat. files: Doc/data/refcounts.dat | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -932,7 +932,7 @@ PyObject_CallMethodObjArgs:PyObject*::+1: PyObject_CallMethodObjArgs:PyObject*:o:0: -PyObject_CallMethodObjArgs:char*:name:: +PyObject_CallMethodObjArgs:PyObject*:name:0: PyObject_CallMethodObjArgs::...:: PyObject_CallObject:PyObject*::+1: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 21:48:10 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Tue, 28 May 2013 21:48:10 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318085=3A_Fix_PyObject=5FCallMethodObjArgs=28=29?= =?utf-8?q?=27s_entry_in_refcounts=2Edat=2E?= Message-ID: <3bKlwB5Zj3z7LqV@mail.python.org> http://hg.python.org/cpython/rev/6d0fd113a2e4 changeset: 83959:6d0fd113a2e4 parent: 83956:ad56dff3602f parent: 83957:0889ab0d0da1 user: Serhiy Storchaka date: Tue May 28 22:47:36 2013 +0300 summary: Issue #18085: Fix PyObject_CallMethodObjArgs()'s entry in refcounts.dat. files: Doc/data/refcounts.dat | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -932,7 +932,7 @@ PyObject_CallMethodObjArgs:PyObject*::+1: PyObject_CallMethodObjArgs:PyObject*:o:0: -PyObject_CallMethodObjArgs:char*:name:: +PyObject_CallMethodObjArgs:PyObject*:name:0: PyObject_CallMethodObjArgs::...:: PyObject_CallObject:PyObject*::+1: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 23:29:46 2013 From: python-checkins at python.org (brett.cannon) Date: Tue, 28 May 2013 23:29:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Introduce_importlib=2Eutil?= =?utf-8?q?=2EModuleManager_which_is_a_context_manager_to?= Message-ID: <3bKp9Q5tqHz7LkF@mail.python.org> http://hg.python.org/cpython/rev/3a1976680717 changeset: 83960:3a1976680717 user: Brett Cannon date: Tue May 28 17:29:34 2013 -0400 summary: Introduce importlib.util.ModuleManager which is a context manager to handle providing (and cleaning up if needed) the module to be loaded. A future commit will use the context manager in Lib/importlib/_bootstrap.py and thus why the code is placed there instead of in Lib/importlib/util.py. files: Doc/library/importlib.rst | 13 + Lib/importlib/_bootstrap.py | 38 +- Lib/importlib/util.py | 1 + Lib/test/test_importlib/test_util.py | 50 + Misc/NEWS | 3 + Python/importlib.h | 6748 +++++++------ 6 files changed, 3510 insertions(+), 3343 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -789,6 +789,15 @@ .. versionadded:: 3.3 +.. class:: ModuleManager(name) + + A :term:`context manager` which provides the module to load. The module will + either come from :attr:`sys.modules` in the case of reloading or a fresh + module if loading a new module. Proper cleanup of :attr:`sys.modules` occurs + if the module was new and an exception was raised. + + .. versionadded:: 3.4 + .. decorator:: module_for_loader A :term:`decorator` for a :term:`loader` method, @@ -818,6 +827,10 @@ Use of this decorator handles all the details of which module object a loader should initialize as specified by :pep:`302` as best as possible. + .. note:: + :class:`ModuleManager` subsumes the module management aspect of this + decorator. + .. versionchanged:: 3.3 :attr:`__loader__` and :attr:`__package__` are automatically set (when possible). diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -9,7 +9,7 @@ # # IMPORTANT: Whenever making changes to this module, be sure to run # a top-level make in order to get the frozen version of the module -# update. Not doing so, will result in the Makefile to fail for +# update. Not doing so will result in the Makefile to fail for # all others who don't have a ./python around to freeze the module # in the early stages of compilation. # @@ -20,10 +20,6 @@ # reference any injected objects! This includes not only global code but also # anything specified at the class level. -# XXX Make sure all public names have no single leading underscore and all -# others do. - - # Bootstrap-related code ###################################################### _CASE_INSENSITIVE_PLATFORMS = 'win', 'cygwin', 'darwin' @@ -498,6 +494,38 @@ print(message.format(*args), file=sys.stderr) +class ModuleManager: + + """Context manager which returns the module to be loaded. + + Does the proper unloading from sys.modules upon failure. + + """ + + def __init__(self, name): + self._name = name + + def __enter__(self): + self._module = sys.modules.get(self._name) + self._is_reload = self._module is not None + if not self._is_reload: + # This must be done before open() is called as the 'io' module + # implicitly imports 'locale' and would otherwise trigger an + # infinite loop. + self._module = new_module(self._name) + # This must be done before putting the module in sys.modules + # (otherwise an optimization shortcut in import.c becomes wrong) + self._module.__initializing__ = True + sys.modules[self._name] = self._module + return self._module + + def __exit__(self, *args): + self._module.__initializing__ = False + del self._module + if any(arg is not None for arg in args) and not self._is_reload: + del sys.modules[self._name] + + def set_package(fxn): """Set __package__ on the returned module.""" def set_package_wrapper(*args, **kwargs): diff --git a/Lib/importlib/util.py b/Lib/importlib/util.py --- a/Lib/importlib/util.py +++ b/Lib/importlib/util.py @@ -1,5 +1,6 @@ """Utility code for constructing importers, etc.""" +from ._bootstrap import ModuleManager from ._bootstrap import module_for_loader from ._bootstrap import set_loader from ._bootstrap import set_package diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py --- a/Lib/test/test_importlib/test_util.py +++ b/Lib/test/test_importlib/test_util.py @@ -2,10 +2,60 @@ from . import util as test_util import imp import sys +from test import support import types import unittest +class ModuleManagerTests(unittest.TestCase): + + module_name = 'ModuleManagerTest_module' + + def setUp(self): + support.unload(self.module_name) + self.addCleanup(support.unload, self.module_name) + + def test_new_module(self): + # Test a new module is created, inserted into sys.modules, has + # __initializing__ set to True after entering the context manager, + # and __initializing__ set to False after exiting. + with util.ModuleManager(self.module_name) as module: + self.assertIn(self.module_name, sys.modules) + self.assertIs(sys.modules[self.module_name], module) + self.assertTrue(module.__initializing__) + self.assertFalse(module.__initializing__) + + def test_new_module_failed(self): + # Test the module is removed from sys.modules. + try: + with util.ModuleManager(self.module_name) as module: + self.assertIn(self.module_name, sys.modules) + raise exception + except Exception: + self.assertNotIn(self.module_name, sys.modules) + else: + self.fail('importlib.util.ModuleManager swallowed an exception') + + def test_reload(self): + # Test that the same module is in sys.modules. + created_module = imp.new_module(self.module_name) + sys.modules[self.module_name] = created_module + with util.ModuleManager(self.module_name) as module: + self.assertIs(module, created_module) + + def test_reload_failed(self): + # Test that the module was left in sys.modules. + created_module = imp.new_module(self.module_name) + sys.modules[self.module_name] = created_module + try: + with util.ModuleManager(self.module_name) as module: + raise Exception + except Exception: + self.assertIn(self.module_name, sys.modules) + else: + self.fail('importlib.util.ModuleManager swallowed an exception') + + class ModuleForLoaderTests(unittest.TestCase): """Tests for importlib.util.module_for_loader.""" diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -96,6 +96,9 @@ Library ------- +- Add importlib.util.ModuleManager as a context manager to provide the proper + module object to load. + - Issue #18025: Fixed a segfault in io.BufferedIOBase.readinto() when raw stream's read() returns more bytes than requested. diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 23:50:22 2013 From: python-checkins at python.org (brett.cannon) Date: Tue, 28 May 2013 23:50:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Update_importlib=2Eh?= Message-ID: <3bKpdB2W4gz7LjX@mail.python.org> http://hg.python.org/cpython/rev/a49c22a1bfbd changeset: 83961:a49c22a1bfbd user: Brett Cannon date: Tue May 28 17:50:04 2013 -0400 summary: Update importlib.h files: Python/importlib.h | 5369 +++++++++++++++---------------- 1 files changed, 2684 insertions(+), 2685 deletions(-) diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Tue May 28 23:50:23 2013 From: python-checkins at python.org (brett.cannon) Date: Tue, 28 May 2013 23:50:23 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Clarify_some_documentation?= Message-ID: <3bKpdC5Q29z7LjX@mail.python.org> http://hg.python.org/cpython/rev/8483ff12c3e5 changeset: 83962:8483ff12c3e5 user: Brett Cannon date: Tue May 28 17:50:14 2013 -0400 summary: Clarify some documentation files: Doc/library/importlib.rst | 48 +++++++++----------------- 1 files changed, 17 insertions(+), 31 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -800,7 +800,7 @@ .. decorator:: module_for_loader - A :term:`decorator` for a :term:`loader` method, + A :term:`decorator` for :meth:`importlib.abc.Loader.load_module` to handle selecting the proper module object to load with. The decorated method is expected to have a call signature taking two positional arguments @@ -813,20 +813,16 @@ as expected for a :term:`loader`. If the module is not found in :data:`sys.modules` then a new one is constructed with its :attr:`__name__` attribute set to **name**, :attr:`__loader__` set to - **self**, and :attr:`__package__` set if - :meth:`importlib.abc.InspectLoader.is_package` is defined for **self** and - does not raise :exc:`ImportError` for **name**. If a new module is not - needed then the module found in :data:`sys.modules` will be passed into the - method. + **self**, and :attr:`__package__` set based on what + :meth:`importlib.abc.InspectLoader.is_package` returns (if available). If a + new module is not needed then the module found in :data:`sys.modules` will + be passed into the method. If an exception is raised by the decorated method and a module was added to :data:`sys.modules` it will be removed to prevent a partially initialized module from being in left in :data:`sys.modules`. If the module was already in :data:`sys.modules` then it is left alone. - Use of this decorator handles all the details of which module object a - loader should initialize as specified by :pep:`302` as best as possible. - .. note:: :class:`ModuleManager` subsumes the module management aspect of this decorator. @@ -837,16 +833,16 @@ .. decorator:: set_loader - A :term:`decorator` for a :term:`loader` method, - to set the :attr:`__loader__` - attribute on loaded modules. If the attribute is already set the decorator - does nothing. It is assumed that the first positional argument to the - wrapped method (i.e. ``self``) is what :attr:`__loader__` should be set to. + A :term:`decorator` for :meth:`importlib.abc.Loader.load_module` + to set the :attr:`__loader__` + attribute on the returned module. If the attribute is already set the + decorator does nothing. It is assumed that the first positional argument to + the wrapped method (i.e. ``self``) is what :attr:`__loader__` should be set + to. .. note:: - - It is recommended that :func:`module_for_loader` be used over this - decorator as it subsumes this functionality. + As this decorator sets :attr:`__loader__` after loading the module, it is + recommended to use :func:`module_for_loader` instead when appropriate. .. versionchanged:: 3.4 Set ``__loader__`` if set to ``None``, as if the attribute does not @@ -855,19 +851,9 @@ .. decorator:: set_package - A :term:`decorator` for a :term:`loader` to set the :attr:`__package__` - attribute on the module returned by the loader. If :attr:`__package__` is - set and has a value other than ``None`` it will not be changed. - Note that the module returned by the loader is what has the attribute - set on and not the module found in :data:`sys.modules`. - - Reliance on this decorator is discouraged when it is possible to set - :attr:`__package__` before importing. By - setting it beforehand the code for the module is executed with the - attribute set and thus can be used by global level code during - initialization. + A :term:`decorator` for :meth:`importlib.abc.Loader.load_module` to set the :attr:`__package__` attribute on the returned module. If :attr:`__package__` + is set and has a value other than ``None`` it will not be changed. .. note:: - - It is recommended that :func:`module_for_loader` be used over this - decorator as it subsumes this functionality. + As this decorator sets :attr:`__package__` after loading the module, it is + recommended to use :func:`module_for_loader` instead when appropriate. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 00:36:06 2013 From: python-checkins at python.org (brett.cannon) Date: Wed, 29 May 2013 00:36:06 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318070=3A_importli?= =?utf-8?b?Yi51dGlsLm1vZHVsZV9mb3JfbG9hZGVyKCkgbm93IHNldHMgX19sb2FkZXJf?= =?utf-8?q?=5F?= Message-ID: <3bKqdy0Cplz7Lk5@mail.python.org> http://hg.python.org/cpython/rev/185a0e649fb8 changeset: 83963:185a0e649fb8 user: Brett Cannon date: Tue May 28 18:35:54 2013 -0400 summary: Issue #18070: importlib.util.module_for_loader() now sets __loader__ and __package__ unconditionally in order to do the right thing for reloading. files: Doc/library/importlib.rst | 22 +- Doc/whatsnew/3.4.rst | 7 +- Lib/importlib/_bootstrap.py | 35 +- Lib/test/test_importlib/test_util.py | 13 +- Misc/NEWS | 3 + Python/importlib.h | 6879 ++++++------- 6 files changed, 3468 insertions(+), 3491 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -811,12 +811,11 @@ The decorated method will take in the **name** of the module to be loaded as expected for a :term:`loader`. If the module is not found in - :data:`sys.modules` then a new one is constructed with its - :attr:`__name__` attribute set to **name**, :attr:`__loader__` set to - **self**, and :attr:`__package__` set based on what - :meth:`importlib.abc.InspectLoader.is_package` returns (if available). If a - new module is not needed then the module found in :data:`sys.modules` will - be passed into the method. + :data:`sys.modules` then a new one is constructed. Regardless of where the + module came from, :attr:`__loader__` set to **self** and :attr:`__package__` + is set based on what :meth:`importlib.abc.InspectLoader.is_package` returns + (if available). These attributes are set unconditionally to support + reloading. If an exception is raised by the decorated method and a module was added to :data:`sys.modules` it will be removed to prevent a partially initialized @@ -831,6 +830,10 @@ :attr:`__loader__` and :attr:`__package__` are automatically set (when possible). + .. versionchanged:: 3.4 + Set :attr:`__loader__` :attr:`__package__` unconditionally to support + reloading. + .. decorator:: set_loader A :term:`decorator` for :meth:`importlib.abc.Loader.load_module` @@ -843,12 +846,13 @@ .. note:: As this decorator sets :attr:`__loader__` after loading the module, it is recommended to use :func:`module_for_loader` instead when appropriate. + This decorator is also redundant as of Python 3.3 as import itself will + set these attributes post-import if necessary. .. versionchanged:: 3.4 Set ``__loader__`` if set to ``None``, as if the attribute does not exist. - .. decorator:: set_package A :term:`decorator` for :meth:`importlib.abc.Loader.load_module` to set the :attr:`__package__` attribute on the returned module. If :attr:`__package__` @@ -856,4 +860,6 @@ .. note:: As this decorator sets :attr:`__package__` after loading the module, it is - recommended to use :func:`module_for_loader` instead when appropriate. + recommended to use :func:`module_for_loader` instead when appropriate. As + of Python 3.3 this decorator is also redundant as import will set + :attr:`__package__` post-import if necessary. 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 @@ -250,4 +250,9 @@ * The module type now initializes the :attr:`__package__` and :attr:`__loader__` attributes to ``None`` by default. To determine if these attributes were set in a backwards-compatible fashion, use e.g. - ``getattr(module, '__loader__', None) is not None``. \ No newline at end of file + ``getattr(module, '__loader__', None) is not None``. + +* :meth:`importlib.util.module_for_loader` now sets ``__loader__`` and + ``__package__`` unconditionally to properly support reloading. If this is not + desired then you will need to set these attributes manually. You can use + :class:`importlib.util.ModuleManager` for module management. diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -37,23 +37,13 @@ return _relax_case -# TODO: Expose from marshal def _w_long(x): - """Convert a 32-bit integer to little-endian. - - XXX Temporary until marshal's long functions are exposed. - - """ + """Convert a 32-bit integer to little-endian.""" return (int(x) & 0xFFFFFFFF).to_bytes(4, 'little') -# TODO: Expose from marshal def _r_long(int_bytes): - """Convert 4 bytes in little-endian to an integer. - - XXX Temporary until marshal's long function are exposed. - - """ + """Convert 4 bytes in little-endian to an integer.""" return int.from_bytes(int_bytes, 'little') @@ -569,17 +559,7 @@ """ def module_for_loader_wrapper(self, fullname, *args, **kwargs): - module = sys.modules.get(fullname) - is_reload = module is not None - if not is_reload: - # This must be done before open() is called as the 'io' module - # implicitly imports 'locale' and would otherwise trigger an - # infinite loop. - module = new_module(fullname) - # This must be done before putting the module in sys.modules - # (otherwise an optimization shortcut in import.c becomes wrong) - module.__initializing__ = True - sys.modules[fullname] = module + with ModuleManager(fullname) as module: module.__loader__ = self try: is_package = self.is_package(fullname) @@ -590,17 +570,8 @@ module.__package__ = fullname else: module.__package__ = fullname.rpartition('.')[0] - else: - module.__initializing__ = True - try: # If __package__ was not set above, __import__() will do it later. return fxn(self, module, *args, **kwargs) - except: - if not is_reload: - del sys.modules[fullname] - raise - finally: - module.__initializing__ = False _wrap(module_for_loader_wrapper, fxn) return module_for_loader_wrapper diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py --- a/Lib/test/test_importlib/test_util.py +++ b/Lib/test/test_importlib/test_util.py @@ -85,12 +85,23 @@ def test_reload(self): # Test that a module is reused if already in sys.modules. + class FakeLoader: + def is_package(self, name): + return True + @util.module_for_loader + def load_module(self, module): + return module name = 'a.b.c' module = imp.new_module('a.b.c') + module.__loader__ = 42 + module.__package__ = 42 with test_util.uncache(name): sys.modules[name] = module - returned_module = self.return_module(name) + loader = FakeLoader() + returned_module = loader.load_module(name) self.assertIs(returned_module, sys.modules[name]) + self.assertEqual(module.__loader__, loader) + self.assertEqual(module.__package__, name) def test_new_module_failure(self): # Test that a module is removed from sys.modules if added but an diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -96,6 +96,9 @@ Library ------- +- Issue #18070: Have importlib.util.module_for_loader() set attributes + unconditionally in order to properly support reloading. + - Add importlib.util.ModuleManager as a context manager to provide the proper module object to load. diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 00:40:40 2013 From: python-checkins at python.org (brett.cannon) Date: Wed, 29 May 2013 00:40:40 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Undo_a_recommendation_as_l?= =?utf-8?q?oad=5Fmodule=28=29_methods_might_be_called_directly?= Message-ID: <3bKqlD2bVdz7Lk5@mail.python.org> http://hg.python.org/cpython/rev/e50571f10755 changeset: 83964:e50571f10755 user: Brett Cannon date: Tue May 28 18:40:31 2013 -0400 summary: Undo a recommendation as load_module() methods might be called directly files: Doc/library/importlib.rst | 6 +----- 1 files changed, 1 insertions(+), 5 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -846,8 +846,6 @@ .. note:: As this decorator sets :attr:`__loader__` after loading the module, it is recommended to use :func:`module_for_loader` instead when appropriate. - This decorator is also redundant as of Python 3.3 as import itself will - set these attributes post-import if necessary. .. versionchanged:: 3.4 Set ``__loader__`` if set to ``None``, as if the attribute does not @@ -860,6 +858,4 @@ .. note:: As this decorator sets :attr:`__package__` after loading the module, it is - recommended to use :func:`module_for_loader` instead when appropriate. As - of Python 3.3 this decorator is also redundant as import will set - :attr:`__package__` post-import if necessary. + recommended to use :func:`module_for_loader` instead when appropriate. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 01:45:41 2013 From: python-checkins at python.org (ned.deily) Date: Wed, 29 May 2013 01:45:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4MDgw?= =?utf-8?q?=3A_When_building_a_C_extension_module_on_OS_X=2C_if_the_compil?= =?utf-8?q?er?= Message-ID: <3bKsBF1pJ2z7Ljf@mail.python.org> http://hg.python.org/cpython/rev/ca24bc6a5a4b changeset: 83965:ca24bc6a5a4b branch: 2.7 parent: 83958:ef9d42b98a3d user: Ned Deily date: Tue May 28 16:31:45 2013 -0700 summary: Issue #18080: When building a C extension module on OS X, if the compiler is overriden with the CC environment variable, use the new compiler as the default for linking if LDSHARED is not also overriden. This restores Distutils behavior introduced in 2.7.3 and inadvertently dropped in 2.7.4. files: Lib/distutils/sysconfig.py | 10 ++- Lib/distutils/tests/test_unixccompiler.py | 34 ++++++++++- Misc/NEWS | 5 + 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -175,9 +175,15 @@ 'CCSHARED', 'LDSHARED', 'SO', 'AR', 'ARFLAGS') - newcc = None if 'CC' in os.environ: - cc = os.environ['CC'] + newcc = os.environ['CC'] + if (sys.platform == 'darwin' + and 'LDSHARED' not in os.environ + and ldshared.startswith(cc)): + # On OS X, if CC is overridden, use that as the default + # command for LDSHARED as well + ldshared = newcc + ldshared[len(cc):] + cc = newcc if 'CXX' in os.environ: cxx = os.environ['CXX'] if 'LDSHARED' in os.environ: diff --git a/Lib/distutils/tests/test_unixccompiler.py b/Lib/distutils/tests/test_unixccompiler.py --- a/Lib/distutils/tests/test_unixccompiler.py +++ b/Lib/distutils/tests/test_unixccompiler.py @@ -1,7 +1,8 @@ """Tests for distutils.unixccompiler.""" +import os import sys import unittest -from test.test_support import run_unittest +from test.test_support import EnvironmentVarGuard, run_unittest from distutils import sysconfig from distutils.unixccompiler import UnixCCompiler @@ -122,6 +123,37 @@ sysconfig.get_config_var = gcv self.assertEqual(self.cc.rpath_foo(), '-R/foo') + @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for OS X') + def test_osx_cc_overrides_ldshared(self): + # Issue #18080: + # ensure that setting CC env variable also changes default linker + def gcv(v): + if v == 'LDSHARED': + return 'gcc-4.2 -bundle -undefined dynamic_lookup ' + return 'gcc-4.2' + sysconfig.get_config_var = gcv + with EnvironmentVarGuard() as env: + env['CC'] = 'my_cc' + del env['LDSHARED'] + sysconfig.customize_compiler(self.cc) + self.assertEqual(self.cc.linker_so[0], 'my_cc') + + @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for OS X') + def test_osx_explict_ldshared(self): + # Issue #18080: + # ensure that setting CC env variable does not change + # explicit LDSHARED setting for linker + def gcv(v): + if v == 'LDSHARED': + return 'gcc-4.2 -bundle -undefined dynamic_lookup ' + return 'gcc-4.2' + sysconfig.get_config_var = gcv + with EnvironmentVarGuard() as env: + env['CC'] = 'my_cc' + env['LDSHARED'] = 'my_ld -bundle -dynamic' + sysconfig.customize_compiler(self.cc) + self.assertEqual(self.cc.linker_so[0], 'my_ld') + def test_suite(): return unittest.makeSuite(UnixCCompilerTestCase) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -28,6 +28,11 @@ - Issue #17269: Workaround for socket.getaddrinfo crash on MacOS X with port None or "0" and flags AI_NUMERICSERV. +- Issue #18080: When building a C extension module on OS X, if the compiler + is overriden with the CC environment variable, use the new compiler as + the default for linking if LDSHARED is not also overriden. This restores + Distutils behavior introduced in 2.7.3 and inadvertently dropped in 2.7.4. + IDLE ---- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 01:45:42 2013 From: python-checkins at python.org (ned.deily) Date: Wed, 29 May 2013 01:45:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MDgw?= =?utf-8?q?=3A_When_building_a_C_extension_module_on_OS_X=2C_if_the_compil?= =?utf-8?q?er?= Message-ID: <3bKsBG4wxVz7Ljf@mail.python.org> http://hg.python.org/cpython/rev/75432fb6b9af changeset: 83966:75432fb6b9af branch: 3.3 parent: 83957:0889ab0d0da1 user: Ned Deily date: Tue May 28 16:35:30 2013 -0700 summary: Issue #18080: When building a C extension module on OS X, if the compiler is overriden with the CC environment variable, use the new compiler as the default for linking if LDSHARED is not also overriden. This restores Distutils behavior introduced in 3.2.3 and inadvertently dropped in 3.3.0. files: Lib/distutils/sysconfig.py | 10 ++- Lib/distutils/tests/test_unixccompiler.py | 36 ++++++++++- Misc/NEWS | 5 + 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -195,9 +195,15 @@ get_config_vars('CC', 'CXX', 'OPT', 'CFLAGS', 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS') - newcc = None if 'CC' in os.environ: - cc = os.environ['CC'] + newcc = os.environ['CC'] + if (sys.platform == 'darwin' + and 'LDSHARED' not in os.environ + and ldshared.startswith(cc)): + # On OS X, if CC is overridden, use that as the default + # command for LDSHARED as well + ldshared = newcc + ldshared[len(cc):] + cc = newcc if 'CXX' in os.environ: cxx = os.environ['CXX'] if 'LDSHARED' in os.environ: diff --git a/Lib/distutils/tests/test_unixccompiler.py b/Lib/distutils/tests/test_unixccompiler.py --- a/Lib/distutils/tests/test_unixccompiler.py +++ b/Lib/distutils/tests/test_unixccompiler.py @@ -1,7 +1,8 @@ """Tests for distutils.unixccompiler.""" +import os import sys import unittest -from test.support import run_unittest +from test.support import EnvironmentVarGuard, run_unittest from distutils import sysconfig from distutils.unixccompiler import UnixCCompiler @@ -94,7 +95,6 @@ sysconfig.get_config_var = gcv self.assertEqual(self.cc.rpath_foo(), '-Wl,--enable-new-dtags,-R/foo') - # non-GCC GNULD sys.platform = 'bar' def gcv(v): @@ -115,6 +115,38 @@ sysconfig.get_config_var = gcv self.assertEqual(self.cc.rpath_foo(), '-R/foo') + @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for OS X') + def test_osx_cc_overrides_ldshared(self): + # Issue #18080: + # ensure that setting CC env variable also changes default linker + def gcv(v): + if v == 'LDSHARED': + return 'gcc-4.2 -bundle -undefined dynamic_lookup ' + return 'gcc-4.2' + sysconfig.get_config_var = gcv + with EnvironmentVarGuard() as env: + env['CC'] = 'my_cc' + del env['LDSHARED'] + sysconfig.customize_compiler(self.cc) + self.assertEqual(self.cc.linker_so[0], 'my_cc') + + @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for OS X') + def test_osx_explict_ldshared(self): + # Issue #18080: + # ensure that setting CC env variable does not change + # explicit LDSHARED setting for linker + def gcv(v): + if v == 'LDSHARED': + return 'gcc-4.2 -bundle -undefined dynamic_lookup ' + return 'gcc-4.2' + sysconfig.get_config_var = gcv + with EnvironmentVarGuard() as env: + env['CC'] = 'my_cc' + env['LDSHARED'] = 'my_ld -bundle -dynamic' + sysconfig.customize_compiler(self.cc) + self.assertEqual(self.cc.linker_so[0], 'my_ld') + + def test_suite(): return unittest.makeSuite(UnixCCompilerTestCase) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -55,6 +55,11 @@ - Issue #17269: Workaround for socket.getaddrinfo crash on MacOS X with port None or "0" and flags AI_NUMERICSERV. +- Issue #18080: When building a C extension module on OS X, if the compiler + is overriden with the CC environment variable, use the new compiler as + the default for linking if LDSHARED is not also overriden. This restores + Distutils behavior introduced in 3.2.3 and inadvertently dropped in 3.3.0. + IDLE ---- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 01:45:44 2013 From: python-checkins at python.org (ned.deily) Date: Wed, 29 May 2013 01:45:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318080=3A_merge_from_3=2E3?= Message-ID: <3bKsBJ0qvyz7LkX@mail.python.org> http://hg.python.org/cpython/rev/0512bb1b5b8a changeset: 83967:0512bb1b5b8a parent: 83964:e50571f10755 parent: 83966:75432fb6b9af user: Ned Deily date: Tue May 28 16:45:06 2013 -0700 summary: Issue #18080: merge from 3.3 files: Lib/distutils/sysconfig.py | 10 ++- Lib/distutils/tests/test_unixccompiler.py | 36 ++++++++++- Misc/NEWS | 5 + 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -188,9 +188,15 @@ get_config_vars('CC', 'CXX', 'OPT', 'CFLAGS', 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS') - newcc = None if 'CC' in os.environ: - cc = os.environ['CC'] + newcc = os.environ['CC'] + if (sys.platform == 'darwin' + and 'LDSHARED' not in os.environ + and ldshared.startswith(cc)): + # On OS X, if CC is overridden, use that as the default + # command for LDSHARED as well + ldshared = newcc + ldshared[len(cc):] + cc = newcc if 'CXX' in os.environ: cxx = os.environ['CXX'] if 'LDSHARED' in os.environ: diff --git a/Lib/distutils/tests/test_unixccompiler.py b/Lib/distutils/tests/test_unixccompiler.py --- a/Lib/distutils/tests/test_unixccompiler.py +++ b/Lib/distutils/tests/test_unixccompiler.py @@ -1,7 +1,8 @@ """Tests for distutils.unixccompiler.""" +import os import sys import unittest -from test.support import run_unittest +from test.support import EnvironmentVarGuard, run_unittest from distutils import sysconfig from distutils.unixccompiler import UnixCCompiler @@ -94,7 +95,6 @@ sysconfig.get_config_var = gcv self.assertEqual(self.cc.rpath_foo(), '-Wl,--enable-new-dtags,-R/foo') - # non-GCC GNULD sys.platform = 'bar' def gcv(v): @@ -115,6 +115,38 @@ sysconfig.get_config_var = gcv self.assertEqual(self.cc.rpath_foo(), '-R/foo') + @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for OS X') + def test_osx_cc_overrides_ldshared(self): + # Issue #18080: + # ensure that setting CC env variable also changes default linker + def gcv(v): + if v == 'LDSHARED': + return 'gcc-4.2 -bundle -undefined dynamic_lookup ' + return 'gcc-4.2' + sysconfig.get_config_var = gcv + with EnvironmentVarGuard() as env: + env['CC'] = 'my_cc' + del env['LDSHARED'] + sysconfig.customize_compiler(self.cc) + self.assertEqual(self.cc.linker_so[0], 'my_cc') + + @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for OS X') + def test_osx_explict_ldshared(self): + # Issue #18080: + # ensure that setting CC env variable does not change + # explicit LDSHARED setting for linker + def gcv(v): + if v == 'LDSHARED': + return 'gcc-4.2 -bundle -undefined dynamic_lookup ' + return 'gcc-4.2' + sysconfig.get_config_var = gcv + with EnvironmentVarGuard() as env: + env['CC'] = 'my_cc' + env['LDSHARED'] = 'my_ld -bundle -dynamic' + sysconfig.customize_compiler(self.cc) + self.assertEqual(self.cc.linker_so[0], 'my_ld') + + def test_suite(): return unittest.makeSuite(UnixCCompilerTestCase) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -308,6 +308,11 @@ - Issue #17032: The "global" in the "NameError: global name 'x' is not defined" error message has been removed. Patch by Ram Rachum. +- Issue #18080: When building a C extension module on OS X, if the compiler + is overriden with the CC environment variable, use the new compiler as + the default for linking if LDSHARED is not also overriden. This restores + Distutils behavior introduced in 3.2.3 and inadvertently dropped in 3.3.0. + Tests ----- -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 03:48:44 2013 From: python-checkins at python.org (andrew.kuchling) Date: Wed, 29 May 2013 03:48:44 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_=231554133=3A_Document_PyO?= =?utf-8?q?S=5FInputHook=2C_PyOS=5FReadlineFunctionPointer?= Message-ID: <3bKvwD3xh1z7LkV@mail.python.org> http://hg.python.org/cpython/rev/672614d809a1 changeset: 83968:672614d809a1 user: Andrew Kuchling date: Tue May 28 21:48:28 2013 -0400 summary: #1554133: Document PyOS_InputHook, PyOS_ReadlineFunctionPointer files: Doc/c-api/veryhigh.rst | 24 +++++++++++++++++++++++- 1 files changed, 23 insertions(+), 1 deletions(-) diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -144,6 +144,29 @@ (:func:`sys.getfilesystemencoding`). Returns ``0`` at EOF. +.. c:var:: int (*PyOS_InputHook)(void) + + Can be set to point to a function with the prototype + ``int func(void)``. The function will be called when Python's + interpreter prompt is about to become idle and wait for user input + from the terminal. The return value is ignored. Overriding this + hook can be used to integrate the interpreter's prompt with other + event loops, as done in the :file:`Modules/_tkinter.c` in the + Python source code. + + +.. c:var:: char* (*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, char *) + + Can be set to point to a function with the prototype + ``char *func(FILE *stdin, FILE *stdout, char *prompt)``, + overriding the default function used to read a single line of input + at the interpreter's prompt. The function is expected to output + the string *prompt* if it's not *NULL*, and then read a line of + input from the provided standard input file, returning the + resulting string. For example, The :mod:`readline` module sets + this hook to provide line-editing and tab-completion features. + + .. c:function:: struct _node* PyParser_SimpleParseString(const char *str, int start) This is a simplified interface to @@ -338,4 +361,3 @@ This bit can be set in *flags* to cause division operator ``/`` to be interpreted as "true division" according to :pep:`238`. - -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 04:22:54 2013 From: python-checkins at python.org (terry.reedy) Date: Wed, 29 May 2013 04:22:54 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE1Mzky?= =?utf-8?q?=3A_Do_not_run_tests_if_threading/=5Fthread_not_available=2E_Ot?= =?utf-8?q?herwise?= Message-ID: <3bKwgf65wsz7LlZ@mail.python.org> http://hg.python.org/cpython/rev/968f6094788b changeset: 83969:968f6094788b branch: 3.3 parent: 83966:75432fb6b9af user: Terry Jan Reedy date: Tue May 28 22:21:53 2013 -0400 summary: Issue #15392: Do not run tests if threading/_thread not available. Otherwise touchup test_idle. Rename README.txt. files: Lib/idlelib/idle_test/@README.txt | 0 Lib/test/test_idle.py | 16 ++++++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Lib/idlelib/idle_test/@README.txt b/Lib/idlelib/idle_test/README.txt rename from Lib/idlelib/idle_test/@README.txt rename to Lib/idlelib/idle_test/README.txt diff --git a/Lib/test/test_idle.py b/Lib/test/test_idle.py --- a/Lib/test/test_idle.py +++ b/Lib/test/test_idle.py @@ -1,13 +1,13 @@ -# Skip test if tkinter wasn't built or idlelib was deleted. +# Skip test if _tkinter or _thread wasn't built or idlelib was deleted. from test.support import import_module -import_module('tkinter') # discard return -itdir = import_module('idlelib.idle_test') +import_module('tkinter') +import_module('threading') # imported by PyShell, imports _thread +idletest = import_module('idlelib.idle_test') -# Without test_main present, regrtest.runtest_inner (line1219) -# imitates unittest.main by calling -# unittest.TestLoader().loadTestsFromModule(this_module) -# which look for load_tests and uses it if found. -load_tests = itdir.load_tests +# Without test_main present, regrtest.runtest_inner (line1219) calls +# unittest.TestLoader().loadTestsFromModule(this_module) which calls +# load_tests() if it finds it. (Unittest.main does the same.) +load_tests = idletest.load_tests if __name__ == '__main__': import unittest -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 04:22:56 2013 From: python-checkins at python.org (terry.reedy) Date: Wed, 29 May 2013 04:22:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Merge_with_3=2E3?= Message-ID: <3bKwgh0qhQzSNH@mail.python.org> http://hg.python.org/cpython/rev/7a6a8a003553 changeset: 83970:7a6a8a003553 parent: 83968:672614d809a1 parent: 83969:968f6094788b user: Terry Jan Reedy date: Tue May 28 22:22:14 2013 -0400 summary: Merge with 3.3 files: Lib/idlelib/idle_test/@README.txt | 0 Lib/test/test_idle.py | 16 ++++++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Lib/idlelib/idle_test/@README.txt b/Lib/idlelib/idle_test/README.txt rename from Lib/idlelib/idle_test/@README.txt rename to Lib/idlelib/idle_test/README.txt diff --git a/Lib/test/test_idle.py b/Lib/test/test_idle.py --- a/Lib/test/test_idle.py +++ b/Lib/test/test_idle.py @@ -1,13 +1,13 @@ -# Skip test if tkinter wasn't built or idlelib was deleted. +# Skip test if _tkinter or _thread wasn't built or idlelib was deleted. from test.support import import_module -import_module('tkinter') # discard return -itdir = import_module('idlelib.idle_test') +import_module('tkinter') +import_module('threading') # imported by PyShell, imports _thread +idletest = import_module('idlelib.idle_test') -# Without test_main present, regrtest.runtest_inner (line1219) -# imitates unittest.main by calling -# unittest.TestLoader().loadTestsFromModule(this_module) -# which look for load_tests and uses it if found. -load_tests = itdir.load_tests +# Without test_main present, regrtest.runtest_inner (line1219) calls +# unittest.TestLoader().loadTestsFromModule(this_module) which calls +# load_tests() if it finds it. (Unittest.main does the same.) +load_tests = idletest.load_tests if __name__ == '__main__': import unittest -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Wed May 29 05:47:32 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 29 May 2013 05:47:32 +0200 Subject: [Python-checkins] Daily reference leaks (0512bb1b5b8a): sum=2 Message-ID: results for 0512bb1b5b8a on branch "default" -------------------------------------------- test_unittest leaked [-1, 1, 2] memory blocks, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogHN_mr8', '-x'] From python-checkins at python.org Wed May 29 14:59:12 2013 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 29 May 2013 14:59:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogIzE3NDAzOiB1cmxs?= =?utf-8?q?ib=2Eparse=2Erobotparser_normalizes_the_urls_before_adding_to_r?= =?utf-8?q?uleline=2E?= Message-ID: <3bLBnr0DyfzQ0w@mail.python.org> http://hg.python.org/cpython/rev/30128355f53b changeset: 83971:30128355f53b branch: 3.3 parent: 83969:968f6094788b user: Senthil Kumaran date: Wed May 29 05:54:31 2013 -0700 summary: #17403: urllib.parse.robotparser normalizes the urls before adding to ruleline. This helps in handling certain types invalid urls in a conservative manner. files: Lib/test/test_robotparser.py | 12 ++++++++++++ Lib/urllib/robotparser.py | 1 + Misc/NEWS | 4 ++++ 3 files changed, 17 insertions(+), 0 deletions(-) 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 @@ -234,6 +234,18 @@ RobotTest(15, doc, good, bad) +# 16. Empty query (issue #17403). Normalizing the url first. +doc = """ +User-agent: * +Allow: /some/path? +Disallow: /another/path? +""" + +good = ['/some/path?'] +bad = ['/another/path?'] + +RobotTest(16, doc, good, bad) + class NetworkTestCase(unittest.TestCase): diff --git a/Lib/urllib/robotparser.py b/Lib/urllib/robotparser.py --- a/Lib/urllib/robotparser.py +++ b/Lib/urllib/robotparser.py @@ -157,6 +157,7 @@ if path == '' and not allowance: # an empty value means allow all allowance = True + path = urllib.parse.urlunparse(urllib.parse.urlparse(path)) self.path = urllib.parse.quote(path) self.allowance = allowance diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -24,6 +24,10 @@ Library ------- +- Issue #17403: urllib.parse.robotparser normalizes the urls before adding to + ruleline. This helps in handling certain types invalid urls in a conservative + manner. + - Issue #18025: Fixed a segfault in io.BufferedIOBase.readinto() when raw stream's read() returns more bytes than requested. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 14:59:13 2013 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 29 May 2013 14:59:13 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge_from_3=2E3?= Message-ID: <3bLBns2CJYzQ2R@mail.python.org> http://hg.python.org/cpython/rev/e954d7a3bb8a changeset: 83972:e954d7a3bb8a parent: 83970:7a6a8a003553 parent: 83971:30128355f53b user: Senthil Kumaran date: Wed May 29 05:57:21 2013 -0700 summary: merge from 3.3 #17403: urllib.parse.robotparser normalizes the urls before adding to ruleline. This helps in handling certain types invalid urls in a conservative manner. Patch contributed by Mher Movsisyan. files: Lib/test/test_robotparser.py | 12 ++++++++++++ Lib/urllib/robotparser.py | 1 + Misc/NEWS | 4 ++++ 3 files changed, 17 insertions(+), 0 deletions(-) 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 @@ -234,6 +234,18 @@ RobotTest(15, doc, good, bad) +# 16. Empty query (issue #17403). Normalizing the url first. +doc = """ +User-agent: * +Allow: /some/path? +Disallow: /another/path? +""" + +good = ['/some/path?'] +bad = ['/another/path?'] + +RobotTest(16, doc, good, bad) + class NetworkTestCase(unittest.TestCase): diff --git a/Lib/urllib/robotparser.py b/Lib/urllib/robotparser.py --- a/Lib/urllib/robotparser.py +++ b/Lib/urllib/robotparser.py @@ -157,6 +157,7 @@ if path == '' and not allowance: # an empty value means allow all allowance = True + path = urllib.parse.urlunparse(urllib.parse.urlparse(path)) self.path = urllib.parse.quote(path) self.allowance = allowance diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -96,6 +96,10 @@ Library ------- +- Issue #17403: urllib.parse.robotparser normalizes the urls before adding to + ruleline. This helps in handling certain types invalid urls in a conservative + manner. Patch contributed by Mher Movsisyan. + - Issue #18070: Have importlib.util.module_for_loader() set attributes unconditionally in order to properly support reloading. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 14:59:14 2013 From: python-checkins at python.org (senthil.kumaran) Date: Wed, 29 May 2013 14:59:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogIzE3NDAzOiB1cmxs?= =?utf-8?q?ib=2Eparse=2Erobotparser_normalizes_the_urls_before_adding_to_r?= =?utf-8?q?uleline=2E?= Message-ID: <3bLBnt4FVgzQDf@mail.python.org> http://hg.python.org/cpython/rev/bcbad715c2ce changeset: 83973:bcbad715c2ce branch: 2.7 parent: 83965:ca24bc6a5a4b user: Senthil Kumaran date: Wed May 29 05:58:47 2013 -0700 summary: #17403: urllib.parse.robotparser normalizes the urls before adding to ruleline. This helps in handling certain types invalid urls in a conservative manner. files: Lib/robotparser.py | 1 + Lib/test/test_robotparser.py | 12 ++++++++++++ Misc/NEWS | 4 ++++ 3 files changed, 17 insertions(+), 0 deletions(-) diff --git a/Lib/robotparser.py b/Lib/robotparser.py --- a/Lib/robotparser.py +++ b/Lib/robotparser.py @@ -160,6 +160,7 @@ if path == '' and not allowance: # an empty value means allow all allowance = True + path = urlparse.urlunparse(urlparse.urlparse(path)) self.path = urllib.quote(path) self.allowance = allowance 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 @@ -228,6 +228,18 @@ RobotTest(15, doc, good, bad) +# 16. Empty query (issue #17403). Normalizing the url first. +doc = """ +User-agent: * +Allow: /some/path? +Disallow: /another/path? +""" + +good = ['/some/path?'] +bad = ['/another/path?'] + +RobotTest(16, doc, good, bad) + class NetworkTestCase(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -15,6 +15,10 @@ Library ------- +- Issue #17403: urllib.parse.robotparser normalizes the urls before adding to + ruleline. This helps in handling certain types invalid urls in a conservative + manner. Patch contributed by Mher Movsisyan. + - Implement inequality on weakref.WeakSet. - Issue #17981: Closed socket on error in SysLogHandler. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 15:48:41 2013 From: python-checkins at python.org (stefan.krah) Date: Wed, 29 May 2013 15:48:41 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE3NzY4?= =?utf-8?q?=3A_Support_newline_fill_character_in_decimal=2Epy_and_NUL_fill?= Message-ID: <3bLCtx23wCzPNt@mail.python.org> http://hg.python.org/cpython/rev/9156c663d6aa changeset: 83974:9156c663d6aa branch: 3.3 parent: 83971:30128355f53b user: Stefan Krah date: Wed May 29 15:45:38 2013 +0200 summary: Issue #17768: Support newline fill character in decimal.py and NUL fill character in _decimal.c. files: Lib/decimal.py | 2 +- Lib/test/test_decimal.py | 4 + Modules/_decimal/_decimal.c | 64 ++++++++++++- Modules/_decimal/tests/deccheck.py | 4 +- Modules/_decimal/tests/formathelper.py | 6 +- 5 files changed, 64 insertions(+), 16 deletions(-) diff --git a/Lib/decimal.py b/Lib/decimal.py --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -6140,7 +6140,7 @@ (?:\.(?P0|(?!0)\d+))? (?P[eEfFgGn%])? \Z -""", re.VERBOSE) +""", re.VERBOSE|re.DOTALL) del re diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -1021,6 +1021,10 @@ ('/=10', '-45.6', '-/////45.6'), ('/=+10', '45.6', '+/////45.6'), ('/= 10', '45.6', ' /////45.6'), + ('\x00=10', '-inf', '-\x00Infinity'), + ('\x00^16', '-inf', '\x00\x00\x00-Infinity\x00\x00\x00\x00'), + ('\x00>10', '1.2345', '\x00\x00\x00\x001.2345'), + ('\x00<10', '1.2345', '1.2345\x00\x00\x00\x00'), # thousands separator (',', '1234567', '1,234,567'), diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -3096,6 +3096,29 @@ return res; } +/* Return a duplicate of src, copy embedded null characters. */ +static char * +dec_strdup(const char *src, Py_ssize_t size) +{ + char *dest = PyMem_Malloc(size+1); + if (dest == NULL) { + return NULL; + } + + memcpy(dest, src, size); + dest[size] = '\0'; + return dest; +} + +static void +dec_replace_fillchar(char *dest) +{ + while (*dest != '\0') { + if (*dest == '\xff') *dest = '\0'; + dest++; + } +} + /* Convert decimal_point or thousands_sep, which may be multibyte or in the range [128, 255], to a UTF8 string. */ static PyObject * @@ -3131,13 +3154,14 @@ PyObject *dot = NULL; PyObject *sep = NULL; PyObject *grouping = NULL; - PyObject *fmt = NULL; PyObject *fmtarg; PyObject *context; mpd_spec_t spec; - char *decstring= NULL; + char *fmt; + char *decstring = NULL; uint32_t status = 0; - size_t n; + int replace_fillchar = 0; + Py_ssize_t size; CURRENT_CONTEXT(context); @@ -3146,10 +3170,20 @@ } if (PyUnicode_Check(fmtarg)) { - fmt = PyUnicode_AsUTF8String(fmtarg); + fmt = PyUnicode_AsUTF8AndSize(fmtarg, &size); if (fmt == NULL) { return NULL; } + if (size > 0 && fmt[0] == '\0') { + /* NUL fill character: must be replaced with a valid UTF-8 char + before calling mpd_parse_fmt_str(). */ + replace_fillchar = 1; + fmt = dec_strdup(fmt, size); + if (fmt == NULL) { + return NULL; + } + fmt[0] = '_'; + } } else { PyErr_SetString(PyExc_TypeError, @@ -3157,12 +3191,19 @@ return NULL; } - if (!mpd_parse_fmt_str(&spec, PyBytes_AS_STRING(fmt), - CtxCaps(context))) { + if (!mpd_parse_fmt_str(&spec, fmt, CtxCaps(context))) { PyErr_SetString(PyExc_ValueError, "invalid format string"); goto finish; } + if (replace_fillchar) { + /* In order to avoid clobbering parts of UTF-8 thousands separators or + decimal points when the substitution is reversed later, the actual + placeholder must be an invalid UTF-8 byte. */ + spec.fill[0] = '\xff'; + spec.fill[1] = '\0'; + } + if (override) { /* Values for decimal_point, thousands_sep and grouping can be explicitly specified in the override dict. These values @@ -3199,7 +3240,7 @@ } } else { - n = strlen(spec.dot); + size_t n = strlen(spec.dot); if (n > 1 || (n == 1 && !isascii((uchar)spec.dot[0]))) { /* fix locale dependent non-ascii characters */ dot = dotsep_as_utf8(spec.dot); @@ -3231,14 +3272,19 @@ } goto finish; } - result = PyUnicode_DecodeUTF8(decstring, strlen(decstring), NULL); + size = strlen(decstring); + if (replace_fillchar) { + dec_replace_fillchar(decstring); + } + + result = PyUnicode_DecodeUTF8(decstring, size, NULL); finish: Py_XDECREF(grouping); Py_XDECREF(sep); Py_XDECREF(dot); - Py_XDECREF(fmt); + if (replace_fillchar) PyMem_Free(fmt); if (decstring) mpd_free(decstring); return result; } diff --git a/Modules/_decimal/tests/deccheck.py b/Modules/_decimal/tests/deccheck.py --- a/Modules/_decimal/tests/deccheck.py +++ b/Modules/_decimal/tests/deccheck.py @@ -891,7 +891,7 @@ def test_format(method, prec, exp_range, restricted_range, itr, stat): """Iterate the __format__ method through many test cases.""" for op in all_unary(prec, exp_range, itr): - fmt1 = rand_format(chr(random.randrange(32, 128)), 'EeGgn') + fmt1 = rand_format(chr(random.randrange(0, 128)), 'EeGgn') fmt2 = rand_locale() for fmt in (fmt1, fmt2): fmtop = (op[0], fmt) @@ -904,7 +904,7 @@ except VerifyError as err: log(err) for op in all_unary(prec, 9999, itr): - fmt1 = rand_format(chr(random.randrange(32, 128)), 'Ff%') + fmt1 = rand_format(chr(random.randrange(0, 128)), 'Ff%') fmt2 = rand_locale() for fmt in (fmt1, fmt2): fmtop = (op[0], fmt) diff --git a/Modules/_decimal/tests/formathelper.py b/Modules/_decimal/tests/formathelper.py --- a/Modules/_decimal/tests/formathelper.py +++ b/Modules/_decimal/tests/formathelper.py @@ -215,8 +215,6 @@ c = chr(i) c.encode('utf-8').decode() format(P.Decimal(0), c + '<19g') - if c in ("'", '"', '\\'): - return None return c except: return None @@ -224,14 +222,14 @@ # Generate all unicode characters that are accepted as # fill characters by decimal.py. def all_fillchars(): - for i in range(32, 0x110002): + for i in range(0, 0x110002): c = check_fillchar(i) if c: yield c # Return random fill character. def rand_fillchar(): while 1: - i = random.randrange(32, 0x110002) + i = random.randrange(0, 0x110002) c = check_fillchar(i) if c: return c -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 15:48:42 2013 From: python-checkins at python.org (stefan.krah) Date: Wed, 29 May 2013 15:48:42 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy4zLg==?= Message-ID: <3bLCty5DzXzSTD@mail.python.org> http://hg.python.org/cpython/rev/148000544c3f changeset: 83975:148000544c3f parent: 83972:e954d7a3bb8a parent: 83974:9156c663d6aa user: Stefan Krah date: Wed May 29 15:47:24 2013 +0200 summary: Merge 3.3. files: Lib/decimal.py | 2 +- Lib/test/test_decimal.py | 4 + Modules/_decimal/_decimal.c | 64 ++++++++++++- Modules/_decimal/tests/deccheck.py | 4 +- Modules/_decimal/tests/formathelper.py | 6 +- 5 files changed, 64 insertions(+), 16 deletions(-) diff --git a/Lib/decimal.py b/Lib/decimal.py --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -6138,7 +6138,7 @@ (?:\.(?P0|(?!0)\d+))? (?P[eEfFgGn%])? \Z -""", re.VERBOSE) +""", re.VERBOSE|re.DOTALL) del re diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -1020,6 +1020,10 @@ ('/=10', '-45.6', '-/////45.6'), ('/=+10', '45.6', '+/////45.6'), ('/= 10', '45.6', ' /////45.6'), + ('\x00=10', '-inf', '-\x00Infinity'), + ('\x00^16', '-inf', '\x00\x00\x00-Infinity\x00\x00\x00\x00'), + ('\x00>10', '1.2345', '\x00\x00\x00\x001.2345'), + ('\x00<10', '1.2345', '1.2345\x00\x00\x00\x00'), # thousands separator (',', '1234567', '1,234,567'), diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -3096,6 +3096,29 @@ return res; } +/* Return a duplicate of src, copy embedded null characters. */ +static char * +dec_strdup(const char *src, Py_ssize_t size) +{ + char *dest = PyMem_Malloc(size+1); + if (dest == NULL) { + return NULL; + } + + memcpy(dest, src, size); + dest[size] = '\0'; + return dest; +} + +static void +dec_replace_fillchar(char *dest) +{ + while (*dest != '\0') { + if (*dest == '\xff') *dest = '\0'; + dest++; + } +} + /* Convert decimal_point or thousands_sep, which may be multibyte or in the range [128, 255], to a UTF8 string. */ static PyObject * @@ -3131,13 +3154,14 @@ PyObject *dot = NULL; PyObject *sep = NULL; PyObject *grouping = NULL; - PyObject *fmt = NULL; PyObject *fmtarg; PyObject *context; mpd_spec_t spec; - char *decstring= NULL; + char *fmt; + char *decstring = NULL; uint32_t status = 0; - size_t n; + int replace_fillchar = 0; + Py_ssize_t size; CURRENT_CONTEXT(context); @@ -3146,10 +3170,20 @@ } if (PyUnicode_Check(fmtarg)) { - fmt = PyUnicode_AsUTF8String(fmtarg); + fmt = PyUnicode_AsUTF8AndSize(fmtarg, &size); if (fmt == NULL) { return NULL; } + if (size > 0 && fmt[0] == '\0') { + /* NUL fill character: must be replaced with a valid UTF-8 char + before calling mpd_parse_fmt_str(). */ + replace_fillchar = 1; + fmt = dec_strdup(fmt, size); + if (fmt == NULL) { + return NULL; + } + fmt[0] = '_'; + } } else { PyErr_SetString(PyExc_TypeError, @@ -3157,12 +3191,19 @@ return NULL; } - if (!mpd_parse_fmt_str(&spec, PyBytes_AS_STRING(fmt), - CtxCaps(context))) { + if (!mpd_parse_fmt_str(&spec, fmt, CtxCaps(context))) { PyErr_SetString(PyExc_ValueError, "invalid format string"); goto finish; } + if (replace_fillchar) { + /* In order to avoid clobbering parts of UTF-8 thousands separators or + decimal points when the substitution is reversed later, the actual + placeholder must be an invalid UTF-8 byte. */ + spec.fill[0] = '\xff'; + spec.fill[1] = '\0'; + } + if (override) { /* Values for decimal_point, thousands_sep and grouping can be explicitly specified in the override dict. These values @@ -3199,7 +3240,7 @@ } } else { - n = strlen(spec.dot); + size_t n = strlen(spec.dot); if (n > 1 || (n == 1 && !isascii((uchar)spec.dot[0]))) { /* fix locale dependent non-ascii characters */ dot = dotsep_as_utf8(spec.dot); @@ -3231,14 +3272,19 @@ } goto finish; } - result = PyUnicode_DecodeUTF8(decstring, strlen(decstring), NULL); + size = strlen(decstring); + if (replace_fillchar) { + dec_replace_fillchar(decstring); + } + + result = PyUnicode_DecodeUTF8(decstring, size, NULL); finish: Py_XDECREF(grouping); Py_XDECREF(sep); Py_XDECREF(dot); - Py_XDECREF(fmt); + if (replace_fillchar) PyMem_Free(fmt); if (decstring) mpd_free(decstring); return result; } diff --git a/Modules/_decimal/tests/deccheck.py b/Modules/_decimal/tests/deccheck.py --- a/Modules/_decimal/tests/deccheck.py +++ b/Modules/_decimal/tests/deccheck.py @@ -891,7 +891,7 @@ def test_format(method, prec, exp_range, restricted_range, itr, stat): """Iterate the __format__ method through many test cases.""" for op in all_unary(prec, exp_range, itr): - fmt1 = rand_format(chr(random.randrange(32, 128)), 'EeGgn') + fmt1 = rand_format(chr(random.randrange(0, 128)), 'EeGgn') fmt2 = rand_locale() for fmt in (fmt1, fmt2): fmtop = (op[0], fmt) @@ -904,7 +904,7 @@ except VerifyError as err: log(err) for op in all_unary(prec, 9999, itr): - fmt1 = rand_format(chr(random.randrange(32, 128)), 'Ff%') + fmt1 = rand_format(chr(random.randrange(0, 128)), 'Ff%') fmt2 = rand_locale() for fmt in (fmt1, fmt2): fmtop = (op[0], fmt) diff --git a/Modules/_decimal/tests/formathelper.py b/Modules/_decimal/tests/formathelper.py --- a/Modules/_decimal/tests/formathelper.py +++ b/Modules/_decimal/tests/formathelper.py @@ -215,8 +215,6 @@ c = chr(i) c.encode('utf-8').decode() format(P.Decimal(0), c + '<19g') - if c in ("'", '"', '\\'): - return None return c except: return None @@ -224,14 +222,14 @@ # Generate all unicode characters that are accepted as # fill characters by decimal.py. def all_fillchars(): - for i in range(32, 0x110002): + for i in range(0, 0x110002): c = check_fillchar(i) if c: yield c # Return random fill character. def rand_fillchar(): while 1: - i = random.randrange(32, 0x110002) + i = random.randrange(0, 0x110002) c = check_fillchar(i) if c: return c -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 16:15:39 2013 From: python-checkins at python.org (nick.coghlan) Date: Wed, 29 May 2013 16:15:39 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Update_based_on_distutils-sig?= =?utf-8?q?_feedback?= Message-ID: <3bLDV346j0z7LjS@mail.python.org> http://hg.python.org/peps/rev/a561f851473c changeset: 4916:a561f851473c user: Nick Coghlan date: Thu May 30 00:15:30 2013 +1000 summary: Update based on distutils-sig feedback files: pep-0426.txt | 232 ++++++++++++++++++++++++-------------- pep-0440.txt | 110 +++++++---------- 2 files changed, 192 insertions(+), 150 deletions(-) diff --git a/pep-0426.txt b/pep-0426.txt --- a/pep-0426.txt +++ b/pep-0426.txt @@ -310,11 +310,11 @@ * ``version_url`` * ``extras`` * ``requires`` -* ``may-require`` -* ``build-requires`` -* ``build-may-require`` -* ``dev-requires`` -* ``dev-may-require`` +* ``may_require`` +* ``build_requires`` +* ``build_may_require`` +* ``dev_requires`` +* ``dev_may_require`` * ``provides`` * ``obsoleted_by`` * ``supports_environments`` @@ -474,49 +474,49 @@ "version": "1.0a2" -Additional identifying metadata -=============================== - -This section specifies fields that provide other identifying details -that are unique to this distribution. +Source code metadata +==================== + +This section specifies fields that provide identifying details for the +source code used to produce this distribution. All of these fields are optional. Automated tools MUST operate correctly if a distribution does not provide them, including failing cleanly when an operation depending on one of these fields is requested. -Build label ------------ - -A constrained identifying text string, as defined in PEP 440. Build labels +Source label +------------ + +A constrained identifying text string, as defined in PEP 440. Source labels cannot be used in ordered version comparisons, but may be used to select an exact version (see PEP 440 for details). Examples:: - "build_label": "1.0.0-alpha.1" - - "build_label": "1.3.7+build.11.e0f985a" - - "build_label": "v1.8.1.301.ga0df26f" - - "build_label": "2013.02.17.dev123" - - -Version URL ------------ - -A string containing a full URL where this specific version of the -distribution can be downloaded. (This means that the URL can't be + "source_label": "1.0.0-alpha.1" + + "source_label": "1.3.7+build.11.e0f985a" + + "source_label": "v1.8.1.301.ga0df26f" + + "source_label": "2013.02.17.dev123" + + +Source URL +---------- + +A string containing a full URL where the source for this specific version of +the distribution can be downloaded. (This means that the URL can't be something like ``"https://github.com/pypa/pip/archive/master.zip"``, but instead must be ``"https://github.com/pypa/pip/archive/1.3.1.zip"``.) -Some appropriate targets for a version URL are a source tarball, an sdist +Some appropriate targets for a source URL are a source tarball, an sdist archive or a direct reference to a tag or specific commit in an online version control system. -All version URL references SHOULD either specify a secure transport +All source URL references SHOULD either specify a secure transport mechanism (such as ``https``) or else include an expected hash value in the URL for verification purposes. If an insecure transport is specified without any hash information (or with hash information that the tool doesn't @@ -542,9 +542,9 @@ Example:: - "version_url": "https://github.com/pypa/pip/archive/1.3.1.zip" - "version_url": "http://github.com/pypa/pip/archive/1.3.1.zip#sha1=da9234ee9982d4bbb3c72346a6de940a148ea686" - "version_url": "git+https://github.com/pypa/pip.git at 1.3.1" + "source_url": "https://github.com/pypa/pip/archive/1.3.1.zip" + "source_url": "http://github.com/pypa/pip/archive/1.3.1.zip#sha1=da9234ee9982d4bbb3c72346a6de940a148ea686" + "source_url": "git+https://github.com/pypa/pip.git at 1.3.1" .. note:: @@ -709,10 +709,10 @@ ] -Contact metadata -================ - -Contact metadata for a distribution is provided to allow users to get +Contributor metadata +==================== + +Contributor metadata for a distribution is provided to allow users to get access to more information about the distribution and its maintainers. These details are recorded as mappings with the following subfields: @@ -720,42 +720,39 @@ * ``name``: the name of an individual or group * ``email``: an email address (this may be a mailing list) * ``url``: a URL (such as a profile page on a source code hosting service) -* ``type``: one of ``"author"``, ``"maintainer"``, ``"organization"`` - or ``"individual"`` +* ``role``: one of ``"author"``, ``"maintainer"`` or ``"contributor"`` The ``name`` subfield is required, the other subfields are optional. -If no specific contact type is stated, the default is ``individual``. - -The different contact types are as follows: +If no specific role is stated, the default is ``contributor``. + +The defined contributor roles are as follows: * ``author``: the original creator of a distribution * ``maintainer``: the current lead contributor for a distribution, when they are not the original creator -* ``individual``: any other individuals involved in the creation of the - distribution -* ``organization``: indicates that these contact details are for an - organization (formal or informal) rather than for a specific individual +* ``contributor``: any other individuals or organizations involved in the + creation of the distribution .. note:: - This is admittedly a little complicated, but it's designed to replace the + The contributor role field is included primarily to replace the Author, Author-Email, Maintainer, Maintainer-Email fields from metadata 1.2 in a way that allows those distinctions to be fully represented for lossless translation, while allowing future distributions to pretty much ignore everything other than the contact/contributor distinction if they so choose. -Contact metadata is optional. Automated tools MUST operate correctly if -a distribution does not provide them, including failing cleanly when an -operation depending on one of these fields is requested. +Contact and contributor metadata is optional. Automated tools MUST operate +correctly if a distribution does not provide it, including failing cleanly +when an operation depending on one of these fields is requested. Contacts -------- -A list of contact entries giving the recommended contact points for getting -more information about the project. +A list of contributor entries giving the recommended contact points for +getting more information about the project. The example below would be suitable for a project that was in the process of handing over from the original author to a new lead maintainer, while @@ -766,18 +763,17 @@ "contacts": [ { "name": "Python Packaging Authority/Distutils-SIG", - "type": "organization", "email": "distutils-sig at python.org", "url": "https://bitbucket.org/pypa/" }, { "name": "Samantha C.", - "type": "maintainer", + "role": "maintainer", "email": "dontblameme at example.org" }, { "name": "Charlotte C.", - "type": "author", + "role": "author", "email": "iambecomingasketchcomedian at example.com" } ] @@ -786,7 +782,7 @@ Contributors ------------ -A list of contact entries for other contributors not already listed as +A list of contributor entries for other contributors not already listed as current project points of contact. The subfields within the list elements are the same as those for the main contact field. @@ -821,7 +817,7 @@ "project_urls": { "Documentation": "https://distlib.readthedocs.org" "Home": "https://bitbucket.org/pypa/distlib" - "Source": "https://bitbucket.org/pypa/distlib/src" + "Repository": "https://bitbucket.org/pypa/distlib/src" "Tracker": "https://bitbucket.org/pypa/distlib/issues" } @@ -842,9 +838,10 @@ model in metadata 1.2 (which was in turn derived from the setuptools dependency parameters). The translation is that ``dev_requires`` and ``build_requires`` both map to ``Setup-Requires-Dist`` - in 1.2, while ``requires`` maps to ``Requires-Dist``. To go the other - way, ``Setup-Requires-Dist`` maps to ``build_requires`` and - ``Requires-Dist`` maps to ``requires``. + in 1.2, while ``requires`` and ``distributes`` map to ``Requires-Dist``. + To go the other way, ``Setup-Requires-Dist`` maps to ``build_requires`` + and ``Requires-Dist`` maps to ``distributes`` (for exact comparisons) + and ``requires`` (for all other version specifiers). All of these fields are optional. Automated tools MUST operate correctly if a distribution does not provide them, by assuming that a missing field @@ -923,6 +920,7 @@ * Deployment dependencies: + * ``distributes`` * ``requires`` * ``may_require`` * Request the ``test`` extra to also install @@ -937,6 +935,7 @@ * Development dependencies: + * ``distributes`` * ``requires`` * ``may_require`` * ``build_requires`` @@ -946,6 +945,7 @@ * ``dev_requires`` * ``dev_may_require`` + To ease compatibility with existing two phase setup/deployment toolchains, installation tools MAY treat ``dev_requires`` and ``dev_may_require`` as additions to ``build_requires`` and ``build_may_require`` rather than @@ -958,6 +958,8 @@ * Install just the build dependencies without installing the distribution * Install just the development dependencies without installing the distribution +* Install just the development dependencies without installing + the distribution or any dependencies listed in ``distributes`` The notation described in `Extras (optional dependencies)`_ SHOULD be used to request additional optional dependencies when installing deployment @@ -973,10 +975,10 @@ example project without any extras defined is split into 2 RPMs in a SPEC file: example and example-devel - The ``requires`` and applicable ``may_require`` dependencies would be - mapped to the Requires dependencies for the "example" RPM (a mapping from - environment markers to SPEC file conditions would also allow those to - be handled correctly) + The ``distributes``, ``requires`` and applicable ``may_require`` + dependencies would be mapped to the Requires dependencies for the + "example" RPM (a mapping from environment markers to SPEC file + conditions would also allow those to be handled correctly) The ``build_requires`` and ``build_may_require`` dependencies would be mapped to the BuildRequires dependencies for the "example" RPM. @@ -997,11 +999,29 @@ to map it to an appropriate dependency in the spec file. +Distributes +----------- + +A list of subdistributions that can easily be installed and used together +by depending on this metadistribution. + +Automated tools MUST allow strict version matching and source reference +clauses in this field and MUST NOT allow more permissive version specifiers. + +Example:: + + "distributes": ["ComfyUpholstery (== 1.0a2)", + "ComfySeatCushion (== 1.0a2)"] + + Requires -------- A list of other distributions needed when this distribution is deployed. +Automated tools MAY disallow strict version matching clauses and source +references in this field and SHOULD at least emit a warning for such clauses. + Example:: "requires": ["SciPy", "PasteDeploy", "zope.interface (>3.5.0)"] @@ -1032,6 +1052,9 @@ Any extras referenced from this field MUST be named in the `Extras`_ field. +Automated tools MAY disallow strict version matching clauses and source +references in this field and SHOULD at least emit a warning for such clauses. + Example:: "may_require": [ @@ -1052,6 +1075,9 @@ for this distribution, either during development or when running the ``test_installed_dist`` metabuild when deployed. +Automated tools MAY disallow strict version matching clauses and source +references in this field and SHOULD at least emit a warning for such clauses. + Example:: "test_requires": ["unittest2"] @@ -1067,6 +1093,9 @@ Any extras referenced from this field MUST be named in the `Extras`_ field. +Automated tools MAY disallow strict version matching clauses and source +references in this field and SHOULD at least emit a warning for such clauses. + Example:: "test_may_require": [ @@ -1090,6 +1119,9 @@ Note that while these are build dependencies for the distribution being built, the installation is a *deployment* scenario for the dependencies. +Automated tools MAY disallow strict version matching clauses and source +references in this field and SHOULD at least emit a warning for such clauses. + Example:: "build_requires": ["setuptools (>= 0.7)"] @@ -1110,6 +1142,9 @@ Automated tools MAY assume that all extras are implicitly requested when installing build dependencies. +Automated tools MAY disallow strict version matching clauses and source +references in this field and SHOULD at least emit a warning for such clauses. + Example:: "build_may_require": [ @@ -1141,6 +1176,9 @@ example, tests that require a local database server and web server and may not work when fully installed on a production system) +Automated tools MAY disallow strict version matching clauses and source +references in this field and SHOULD at least emit a warning for such clauses. + Example:: "dev_requires": ["hgtools", "sphinx (>= 1.0)"] @@ -1161,6 +1199,9 @@ Automated tools MAY assume that all extras are implicitly requested when installing development dependencies. +Automated tools MAY disallow strict version matching clauses and source +references in this field and SHOULD at least emit a warning for such clauses. + Example:: "dev_may_require": [ @@ -1295,7 +1336,7 @@ "metabuild_hooks": { "postinstall": "myproject.build_hooks:postinstall", "preuininstall": "myproject.build_hooks:preuninstall", - "test_installed_dist": "some_test_harness.metabuild_hook" + "test_installed_dist": "some_test_harness:metabuild_hook" } Build and installation tools MAY offer additional operations beyond the @@ -1484,7 +1525,8 @@ The pseudo-grammar is :: MARKER: EXPR [(and|or) EXPR]* - EXPR: ("(" MARKER ")") | (SUBEXPR [(in|==|!=|not in)?SUBEXPR]) + EXPR: ("(" MARKER ")") | (SUBEXPR [CMPOP?SUBEXPR]) + CMPOP: (==|!=|<|>|<=|>=|in|not in) where ``SUBEXPR`` is either a Python string (such as ``'2.4'``, or ``'win32'``) or one of the following marker variables: @@ -1493,17 +1535,18 @@ * ``python_full_version``: see definition below * ``os_name````: ``os.name`` * ``sys_platform````: ``sys.platform`` +* ``platform_release``: ``platform.release()`` * ``platform_version``: ``platform.version()`` * ``platform_machine``: ``platform.machine()`` * ``platform_python_implementation``: ``platform.python_implementation()`` Note that all subexpressions are restricted to strings or one of the -marker variable names, meaning that it is not possible to use other -sequences like tuples or lists on the right side of the ``in`` and -``not in`` operators. - -Unlike Python, chaining of comparison operations is NOT permitted in -environment markers. +marker variable names (which refer to string values), meaning that it is +not possible to use other sequences like tuples or lists on the right +side of the ``in`` and ``not in`` operators. + +Chaining of comparison operations is permitted using the normal Python +semantics of an implied ``and``. The ``python_full_version`` marker variable is derived from ``sys.version_info()`` in accordance with the following algorithm:: @@ -1516,7 +1559,6 @@ version += kind[0] + str(info.serial) return version - Updating the metadata specification =================================== @@ -1653,7 +1695,7 @@ ---------------------------------------------- The separation of the ``requires``, ``build_requires`` and ``dev_requires`` -fields allow a distribution to indicate whether a dependency is needed +fields allows a distribution to indicate whether a dependency is needed specifically to develop, build or deploy the distribution. As distribution metadata improves, this should allow much greater control @@ -1696,7 +1738,7 @@ --------------------------- The new metabuild system is designed to allow the wheel format to fully -replace direct installation on deployment targets, by allows projects like +replace direct installation on deployment targets, by allowing projects like Twisted to still execute code following installation from a wheel file. Falling back to invoking ``setup.py`` directly rather than using a @@ -1704,23 +1746,35 @@ and is also used as the interim solution for installation from source archives. -The ``test_installed_dist`` metabuild hook is included as a complement to -the ability to explicitly specify test dependencies. +The ``test_installed_dist`` metabuild hook is included in order to integrate +with build systems that can automatically invoke test suites, and as +a complement to the ability to explicitly specify test dependencies. Changes to environment markers ------------------------------ -The changes to environment markers were just clarifications and +There are three substantive changes to environment markers in this version:: + +* ``platform_release`` was added, as it provides more useful information + than ``platform_version`` on at least Linux and Mac OS X (specifically, + it provides details of the running kernel version) +* ordered comparison of strings is allowed, as this is more useful for + setting minimum and maximum versions where conditional dependencies + are needed or where a platform is supported +* comparison chaining is explicitly allowed, as this becomes useful in the + presence of ordered comparisons + +The other changes to environment markers are just clarifications and simplifications to make them easier to use. The arbitrariness of the choice of ``.`` and ``_`` in the different -variables was addressed by standardising on ``_`` (as these are predefined -variables rather than live references into the Python module namespace) - -The use of parentheses for grouping and the disallowance of chained -comparisons were added to address some underspecified behaviour in the -previous version of the specification. +variables was addressed by standardising on ``_`` (as these are all +predefined variables rather than live references into the Python module +namespace) + +The use of parentheses for grouping was explicitly noted to address some +underspecified behaviour in the previous version of the specification. Updated contact information @@ -1854,7 +1908,7 @@ tarball and sdist based installation to use the existing ``setup.py`` based ``distutils`` command interface. -In the meantime, the above four operations will continue to be handled +In the meantime, the above three operations will continue to be handled through the ``distutils``/``setuptools`` command system: * ``python setup.py dist_info`` @@ -1870,8 +1924,7 @@ archive Tentative signatures have been designed for those hooks, but they will -not be pursued further until 2.1 (note that the current signatures for -the hooks do *not* adequately handle the "extras" concept):: +not be pursued further until 2.1:: def make_dist_info(source_dir, info_dir): """Generate the contents of dist_info for an sdist archive @@ -1912,6 +1965,11 @@ Returns the actual compatibility tag for the build """ +As with the existing metabuild hooks, checking for extras would be done +using the same import based checks as are used for runtime extras. That +way it doesn't matter if the additional dependencies were requested +explicitly or just happen to be available on the system. + Rejected Features ================= diff --git a/pep-0440.txt b/pep-0440.txt --- a/pep-0440.txt +++ b/pep-0440.txt @@ -99,18 +99,18 @@ sections. -Build labels ------------- +Source labels +------------- -Build labels are text strings with minimal defined semantics. +Source labels are text strings with minimal defined semantics. -To ensure build labels can be readily incorporated as part of file names +To ensure source labels can be readily incorporated as part of file names and URLs, they MUST be comprised of only ASCII alphanumerics, plus signs, periods and hyphens. -In addition, build labels MUST be unique within a given distribution. +In addition, source labels MUST be unique within a given distribution. -As with distribution names, all comparisons of build labels MUST be case +As with distribution names, all comparisons of source labels MUST be case insensitive. @@ -444,7 +444,7 @@ Some projects may choose to use a version scheme which requires translation in order to comply with the public version scheme defined in -this PEP. In such cases, the build label can be used to +this PEP. In such cases, the source label can be used to record the project specific version as an arbitrary label, while the translated public version is published in the version field. @@ -488,7 +488,7 @@ permitted in the public version field. As with semantic versioning, the public ``.devN`` suffix may be used to -uniquely identify such releases for publication, while the build label is +uniquely identify such releases for publication, while the source label is used to record the original DVCS based version label. @@ -496,7 +496,7 @@ ~~~~~~~~~~~~~~~~~~~ As with other incompatible version schemes, date based versions can be -stored in the build label field. Translating them to a compliant +stored in the source label field. Translating them to a compliant public version is straightforward: use a leading ``"0."`` prefix in the public version label, with the date based version number as the remaining components in the release segment. @@ -521,7 +521,7 @@ * ``~=``: `Compatible release`_ clause * ``==``: `Version matching`_ clause * ``!=``: `Version exclusion`_ clause -* ``is``: `Build reference`_ clause +* ``is``: `Source reference`_ clause * ``<=``, ``>=``: `Inclusive ordered comparison`_ clause * ``<``, ``>``: `Exclusive ordered comparison`_ clause @@ -626,10 +626,6 @@ dependencies for repeatable *deployments of applications* while using a shared distribution index. -Publication tools and index servers SHOULD at least emit a warning when -dependencies are pinned in this fashion and MAY refuse to allow publication -of such overly specific dependencies. - Version exclusion ----------------- @@ -649,43 +645,44 @@ != 1.1.* # Same prefix, so 1.1.post1 does not match clause -Build reference ---------------- +Source reference +---------------- -A build reference includes the build reference operator ``is`` and -a build label or a build URL. +A source reference includes the source reference operator ``is`` and +a source label or a source URL. -Publication tools and public index servers SHOULD NOT permit build -references in dependency specifications. +Installation tools MAY also permit direct references to a platform +appropriate binary archive in a source reference clause. -Installation tools SHOULD support the use of build references to identify -dependencies. +Publication tools and public index servers SHOULD NOT permit direct +references to a platform appropriate binary archive in a source +reference clause. -Build label matching works solely on strict equality comparisons: the -candidate build label must be exactly the same as the build label in the +Source label matching works solely on strict equality comparisons: the +candidate source label must be exactly the same as the source label in the version clause for the clause to match the candidate distribution. -For example, a build reference could be used to depend on a ``hashdist`` -generated build of ``zlib`` with the ``hashdist`` hash used as a build -label:: +For example, a source reference could be used to depend directly on a +version control hash based identifier rather than the translated public +version:: - zlib (is d4jwf2sb2g6glprsdqfdpcracwpzujwq) + exact-dependency (is 1.3.7+build.11.e0f985a) -A build URL is distinguished from a build label by the presence of -``:`` and ``/`` characters in the build reference. As these characters -are not permitted in build labels, they indicate that the reference uses -a build URL. +A source URL is distinguished from a source label by the presence of +``:`` and ``/`` characters in the source reference. As these characters +are not permitted in source labels, they indicate that the reference uses +a source URL. -Some appropriate targets for a build URL are a binary archive, a -source tarball, an sdist archive or a direct reference to a tag or -specific commit in an online version control system. The exact URLs and +Some appropriate targets for a source URL are a source tarball, an sdist +archive or a direct reference to a tag or specific commit in an online +version control system. The exact URLs and targets supported will be installation tool specific. -For example, a local prebuilt wheel file may be referenced directly:: +For example, a local source archive may be referenced directly:: - exampledist (is file:///localbuilds/exampledist-1.0-py33-none-any.whl) + pip (is file:///localbuilds/pip-1.3.1.zip) -All build URL references SHOULD either specify a local file URL, a secure +All source URL references SHOULD either specify a local file URL, a secure transport mechanism (such as ``https``) or else include an expected hash value in the URL for verification purposes. If an insecure network transport is specified without any hash information (or with hash @@ -698,7 +695,7 @@ ``'md5'``, ``'sha1'``, ``'sha224'``, ``'sha256'``, ``'sha384'``, and ``'sha512'``. -For binary or source archive references, an expected hash value may be +For source archive references, an expected hash value may be specified by including a ``=`` as part of the URL fragment. @@ -711,7 +708,7 @@ The use of ``is`` when defining dependencies for published distributions is strongly discouraged as it greatly complicates the deployment of -security fixes. The build label matching operator is intended primarily +security fixes. The source label matching operator is intended primarily for use when defining dependencies for repeatable *deployments of applications* while using a shared distribution index, as well as to reference dependencies which are not published through an index server. @@ -823,31 +820,18 @@ versioning scheme and metadata version defined in new PEPs. -Open issues -=========== - -* The new ``is`` operator seems like a reasonable way to cleanly allow - installation tools to bring in non-published dependencies, while heavily - discouraging the practice for published libraries. It also makes - build labels more useful by allowing them to be used to pin dependencies - in the integration use case. - - However, it's an early draft of the idea, so feedback is definitely - welcome. - - Summary of differences from \PEP 386 ==================================== * Moved the description of version specifiers into the versioning PEP -* added the "build label" concept to better handle projects that wish to +* added the "source label" concept to better handle projects that wish to use a non-compliant versioning scheme internally, especially those based on DVCS hashes * added the "compatible release" clause -* added the "build reference" clause +* added the "source reference" clause * added the trailing wildcard syntax for prefix based version matching and exclusion @@ -869,10 +853,10 @@ The rationale for major changes is given in the following sections. -Adding build labels +Adding source labels ------------------- -The new build label support is intended to make it clearer that the +The new source label support is intended to make it clearer that the constraints on public version identifiers are there primarily to aid in the creation of reliable automated dependency analysis tools. Projects are free to use whatever versioning scheme they like internally, so long @@ -1041,12 +1025,12 @@ and the desired pre-release handling semantics for ``<`` and ``>`` ordered comparison clauses. -Build references are added for two purposes. In conjunction with build -labels, they allow hash based references, such as those employed by -`hashdist `__, -or generated from version control. In conjunction with build URLs, they -allow the new metadata standard to natively support an existing feature of -``pip``, which allows arbitrary URLs like +Source references are added for two purposes. In conjunction with source +labels, they allow hash based references to exact versions that aren't +compliant with the fully ordered public version scheme, such as those +generated from version control. In combination with source URLs, they +also allow the new metadata standard to natively support an existing +feature of ``pip``, which allows arbitrary URLs like ``file:///localbuilds/exampledist-1.0-py33-none-any.whl``. -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed May 29 16:17:37 2013 From: python-checkins at python.org (nick.coghlan) Date: Wed, 29 May 2013 16:17:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Markup_fixes?= Message-ID: <3bLDXK1qyTzShn@mail.python.org> http://hg.python.org/peps/rev/1d2c0597e55c changeset: 4917:1d2c0597e55c user: Nick Coghlan date: Thu May 30 00:17:27 2013 +1000 summary: Markup fixes files: pep-0426.txt | 2 +- pep-0440.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pep-0426.txt b/pep-0426.txt --- a/pep-0426.txt +++ b/pep-0426.txt @@ -1754,7 +1754,7 @@ Changes to environment markers ------------------------------ -There are three substantive changes to environment markers in this version:: +There are three substantive changes to environment markers in this version: * ``platform_release`` was added, as it provides more useful information than ``platform_version`` on at least Linux and Mac OS X (specifically, diff --git a/pep-0440.txt b/pep-0440.txt --- a/pep-0440.txt +++ b/pep-0440.txt @@ -854,7 +854,7 @@ Adding source labels -------------------- +-------------------- The new source label support is intended to make it clearer that the constraints on public version identifiers are there primarily to aid in -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Wed May 29 17:51:19 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 29 May 2013 17:51:19 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=239369=3A_The_types?= =?utf-8?q?_of_=60char*=60_arguments_of_PyObject=5FCallFunction=28=29_and?= Message-ID: <3bLGcR0fGJz7LjR@mail.python.org> http://hg.python.org/cpython/rev/0a45896a7cde changeset: 83976:0a45896a7cde user: Serhiy Storchaka date: Wed May 29 18:50:54 2013 +0300 summary: Issue #9369: The types of `char*` arguments of PyObject_CallFunction() and PyObject_CallMethod() now changed to `const char*`. Based on patches by J?rg M?ller and Lars Buitinck. files: Doc/c-api/object.rst | 10 ++++++++-- Doc/data/refcounts.dat | 8 ++++---- Include/abstract.h | 23 ++++++++++++++--------- Misc/ACKS | 2 ++ Misc/NEWS | 4 ++++ Objects/abstract.c | 17 ++++++++++------- 6 files changed, 42 insertions(+), 22 deletions(-) diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -240,7 +240,7 @@ of the Python expression ``callable_object(*args)``. -.. c:function:: PyObject* PyObject_CallFunction(PyObject *callable, char *format, ...) +.. c:function:: PyObject* PyObject_CallFunction(PyObject *callable, const char *format, ...) Call a callable Python object *callable*, with a variable number of C arguments. The C arguments are described using a :c:func:`Py_BuildValue` style format @@ -250,8 +250,11 @@ pass :c:type:`PyObject \*` args, :c:func:`PyObject_CallFunctionObjArgs` is a faster alternative. + .. versionchanged:: 3.4 + The type of *format* was changed from ``char *``. -.. c:function:: PyObject* PyObject_CallMethod(PyObject *o, char *method, char *format, ...) + +.. c:function:: PyObject* PyObject_CallMethod(PyObject *o, const char *method, const char *format, ...) Call the method named *method* of object *o* with a variable number of C arguments. The C arguments are described by a :c:func:`Py_BuildValue` format @@ -261,6 +264,9 @@ Note that if you only pass :c:type:`PyObject \*` args, :c:func:`PyObject_CallMethodObjArgs` is a faster alternative. + .. versionchanged:: 3.4 + The types of *method* and *format* were changed from ``char *``. + .. c:function:: PyObject* PyObject_CallFunctionObjArgs(PyObject *callable, ..., NULL) diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -218,7 +218,7 @@ PyDict_GetItemString:PyObject*::0: PyDict_GetItemString:PyObject*:p:0: -PyDict_GetItemString:char*:key:: +PyDict_GetItemString:const char*:key:: PyDict_SetDefault:PyObject*::0: PyDict_SetDefault:PyObject*:p:0: @@ -917,7 +917,7 @@ PyObject_CallFunction:PyObject*::+1: PyObject_CallFunction:PyObject*:callable_object:0: -PyObject_CallFunction:char*:format:: +PyObject_CallFunction:const char*:format:: PyObject_CallFunction::...:: PyObject_CallFunctionObjArgs:PyObject*::+1: @@ -926,8 +926,8 @@ PyObject_CallMethod:PyObject*::+1: PyObject_CallMethod:PyObject*:o:0: -PyObject_CallMethod:char*:m:: -PyObject_CallMethod:char*:format:: +PyObject_CallMethod:const char*:m:: +PyObject_CallMethod:const char*:format:: PyObject_CallMethod::...:: PyObject_CallMethodObjArgs:PyObject*::+1: diff --git a/Include/abstract.h b/Include/abstract.h --- a/Include/abstract.h +++ b/Include/abstract.h @@ -284,7 +284,7 @@ */ PyAPI_FUNC(PyObject *) PyObject_CallFunction(PyObject *callable_object, - char *format, ...); + const char *format, ...); /* Call a callable Python object, callable_object, with a @@ -296,8 +296,9 @@ */ - PyAPI_FUNC(PyObject *) PyObject_CallMethod(PyObject *o, char *method, - char *format, ...); + PyAPI_FUNC(PyObject *) PyObject_CallMethod(PyObject *o, + const char *method, + const char *format, ...); /* Call the method named m of object o with a variable number of @@ -308,8 +309,9 @@ Python expression: o.method(args). */ - PyAPI_FUNC(PyObject *) _PyObject_CallMethodId(PyObject *o, _Py_Identifier *method, - char *format, ...); + PyAPI_FUNC(PyObject *) _PyObject_CallMethodId(PyObject *o, + _Py_Identifier *method, + const char *format, ...); /* Like PyObject_CallMethod, but expect a _Py_Identifier* as the @@ -317,13 +319,16 @@ */ PyAPI_FUNC(PyObject *) _PyObject_CallFunction_SizeT(PyObject *callable, - char *format, ...); + const char *format, + ...); PyAPI_FUNC(PyObject *) _PyObject_CallMethod_SizeT(PyObject *o, - char *name, - char *format, ...); + const char *name, + const char *format, + ...); PyAPI_FUNC(PyObject *) _PyObject_CallMethodId_SizeT(PyObject *o, _Py_Identifier *name, - char *format, ...); + const char *format, + ...); PyAPI_FUNC(PyObject *) PyObject_CallFunctionObjArgs(PyObject *callable, ...); diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -174,6 +174,7 @@ Stan Bubrouski Erik de Bueger Jan-Hein B?hrman +Lars Buitinck Dick Bulterman Bill Bumgarner Jimmy Burgett @@ -872,6 +873,7 @@ Louis Munro R. David Murray Matti M?ki +J?rg M?ller Dale Nagata John Nagle Takahiro Nakayama diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -387,6 +387,10 @@ C-API ----- +- Issue #9369: The types of `char*` arguments of PyObject_CallFunction() and + PyObject_CallMethod() now changed to `const char*`. Based on patches by + J?rg M?ller and Lars Buitinck. + - Issue #17206: Py_CLEAR(), Py_DECREF(), Py_XINCREF() and Py_XDECREF() now expand their arguments once instead of multiple times. Patch written by Illia Polosukhin. diff --git a/Objects/abstract.c b/Objects/abstract.c --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2142,7 +2142,7 @@ } PyObject * -PyObject_CallFunction(PyObject *callable, char *format, ...) +PyObject_CallFunction(PyObject *callable, const char *format, ...) { va_list va; PyObject *args; @@ -2162,7 +2162,7 @@ } PyObject * -_PyObject_CallFunction_SizeT(PyObject *callable, char *format, ...) +_PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) { va_list va; PyObject *args; @@ -2182,7 +2182,7 @@ } static PyObject* -callmethod(PyObject* func, char *format, va_list va, int is_size_t) +callmethod(PyObject* func, const char *format, va_list va, int is_size_t) { PyObject *retval = NULL; PyObject *args; @@ -2211,7 +2211,7 @@ } PyObject * -PyObject_CallMethod(PyObject *o, char *name, char *format, ...) +PyObject_CallMethod(PyObject *o, const char *name, const char *format, ...) { va_list va; PyObject *func = NULL; @@ -2232,7 +2232,8 @@ } PyObject * -_PyObject_CallMethodId(PyObject *o, _Py_Identifier *name, char *format, ...) +_PyObject_CallMethodId(PyObject *o, _Py_Identifier *name, + const char *format, ...) { va_list va; PyObject *func = NULL; @@ -2253,7 +2254,8 @@ } PyObject * -_PyObject_CallMethod_SizeT(PyObject *o, char *name, char *format, ...) +_PyObject_CallMethod_SizeT(PyObject *o, const char *name, + const char *format, ...) { va_list va; PyObject *func = NULL; @@ -2273,7 +2275,8 @@ } PyObject * -_PyObject_CallMethodId_SizeT(PyObject *o, _Py_Identifier *name, char *format, ...) +_PyObject_CallMethodId_SizeT(PyObject *o, _Py_Identifier *name, + const char *format, ...) { va_list va; PyObject *func = NULL; -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 18:51:03 2013 From: python-checkins at python.org (stefan.krah) Date: Wed, 29 May 2013 18:51:03 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_test=5Fdecimal=3A_add_=5F?= =?utf-8?q?=5Fsizeof=5F=5F=28=29_tests_for_code_coverage=2E?= Message-ID: <3bLHxM4msNz7Lkp@mail.python.org> http://hg.python.org/cpython/rev/bcaaaa00425b changeset: 83977:bcaaaa00425b user: Stefan Krah date: Wed May 29 18:50:06 2013 +0200 summary: test_decimal: add __sizeof__() tests for code coverage. files: Lib/test/test_decimal.py | 13 +++++++++++++ 1 files changed, 13 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -5372,6 +5372,19 @@ x = (1, (0, 1), "N") self.assertEqual(str(Decimal(x)), '-sNaN1') + def test_sizeof(self): + Decimal = C.Decimal + HAVE_CONFIG_64 = (C.MAX_PREC > 425000000) + + self.assertGreater(Decimal(0).__sizeof__(), 0) + if HAVE_CONFIG_64: + x = Decimal(10**(19*24)).__sizeof__() + y = Decimal(10**(19*25)).__sizeof__() + self.assertEqual(y, x+8) + else: + x = Decimal(10**(9*24)).__sizeof__() + y = Decimal(10**(9*25)).__sizeof__() + self.assertEqual(y, x+4) all_tests = [ CExplicitConstructionTest, PyExplicitConstructionTest, -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 19:09:50 2013 From: python-checkins at python.org (stefan.krah) Date: Wed, 29 May 2013 19:09:50 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Mark_untestable_lines_for_?= =?utf-8?q?gcov=2E?= Message-ID: <3bLJM235FjzNKx@mail.python.org> http://hg.python.org/cpython/rev/bff16086f03b changeset: 83978:bff16086f03b user: Stefan Krah date: Wed May 29 19:08:34 2013 +0200 summary: Mark untestable lines for gcov. files: Modules/_decimal/_decimal.c | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -4469,10 +4469,10 @@ goto malloc_error; } else { - PyErr_SetString(PyExc_RuntimeError, - "dec_hash: internal error: please report"); + PyErr_SetString(PyExc_RuntimeError, /* GCOV_NOT_REACHED */ + "dec_hash: internal error: please report"); /* GCOV_NOT_REACHED */ } - result = -1; + result = -1; /* GCOV_NOT_REACHED */ } @@ -5623,7 +5623,7 @@ } if (base == NULL) { - goto error; + goto error; /* GCOV_NOT_REACHED */ } ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname, base, NULL)); @@ -5655,7 +5655,7 @@ base = PyTuple_Pack(1, signal_map[0].ex); } if (base == NULL) { - goto error; + goto error; /* GCOV_NOT_REACHED */ } ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname, base, NULL)); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 19:16:08 2013 From: python-checkins at python.org (stefan.krah) Date: Wed, 29 May 2013 19:16:08 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Backport_bff16?= =?utf-8?q?086f03b_and_bcaaaa00425b=2E?= Message-ID: <3bLJVJ1Y4lz7LlM@mail.python.org> http://hg.python.org/cpython/rev/8a77d7019559 changeset: 83979:8a77d7019559 branch: 3.3 parent: 83974:9156c663d6aa user: Stefan Krah date: Wed May 29 19:14:17 2013 +0200 summary: Backport bff16086f03b and bcaaaa00425b. files: Lib/test/test_decimal.py | 13 +++++++++++++ Modules/_decimal/_decimal.c | 10 +++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -5373,6 +5373,19 @@ x = (1, (0, 1), "N") self.assertEqual(str(Decimal(x)), '-sNaN1') + def test_sizeof(self): + Decimal = C.Decimal + HAVE_CONFIG_64 = (C.MAX_PREC > 425000000) + + self.assertGreater(Decimal(0).__sizeof__(), 0) + if HAVE_CONFIG_64: + x = Decimal(10**(19*24)).__sizeof__() + y = Decimal(10**(19*25)).__sizeof__() + self.assertEqual(y, x+8) + else: + x = Decimal(10**(9*24)).__sizeof__() + y = Decimal(10**(9*25)).__sizeof__() + self.assertEqual(y, x+4) all_tests = [ CExplicitConstructionTest, PyExplicitConstructionTest, diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -4469,10 +4469,10 @@ goto malloc_error; } else { - PyErr_SetString(PyExc_RuntimeError, - "dec_hash: internal error: please report"); + PyErr_SetString(PyExc_RuntimeError, /* GCOV_NOT_REACHED */ + "dec_hash: internal error: please report"); /* GCOV_NOT_REACHED */ } - result = -1; + result = -1; /* GCOV_NOT_REACHED */ } @@ -5623,7 +5623,7 @@ } if (base == NULL) { - goto error; + goto error; /* GCOV_NOT_REACHED */ } ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname, base, NULL)); @@ -5655,7 +5655,7 @@ base = PyTuple_Pack(1, signal_map[0].ex); } if (base == NULL) { - goto error; + goto error; /* GCOV_NOT_REACHED */ } ASSIGN_PTR(cm->ex, PyErr_NewException((char *)cm->fqname, base, NULL)); -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 19:16:09 2013 From: python-checkins at python.org (stefan.krah) Date: Wed, 29 May 2013 19:16:09 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Null_merge=2E?= Message-ID: <3bLJVK6mJQz7LkF@mail.python.org> http://hg.python.org/cpython/rev/3e0284efa9fd changeset: 83980:3e0284efa9fd parent: 83978:bff16086f03b parent: 83979:8a77d7019559 user: Stefan Krah date: Wed May 29 19:15:28 2013 +0200 summary: Null merge. files: -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 21:13:37 2013 From: python-checkins at python.org (stefan.krah) Date: Wed, 29 May 2013 21:13:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=283=2E3=29=3A_Support_multia?= =?utf-8?q?rch_build_in_tests=2E?= Message-ID: <3bLM5s2v0jzSqF@mail.python.org> http://hg.python.org/cpython/rev/280303da5b30 changeset: 83981:280303da5b30 branch: 3.3 parent: 83979:8a77d7019559 user: Stefan Krah date: Wed May 29 20:58:19 2013 +0200 summary: Support multiarch build in tests. files: Modules/_decimal/tests/runall-memorydebugger.sh | 15 +++++---- 1 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Modules/_decimal/tests/runall-memorydebugger.sh b/Modules/_decimal/tests/runall-memorydebugger.sh --- a/Modules/_decimal/tests/runall-memorydebugger.sh +++ b/Modules/_decimal/tests/runall-memorydebugger.sh @@ -9,8 +9,9 @@ # Requirements: valgrind # -# Set additional CFLAGS for ./configure +# Set additional CFLAGS and LDFLAGS for ./configure ADD_CFLAGS= +ADD_LDFLAGS= CONFIGS_64="x64 uint128 ansi64 universal" @@ -74,7 +75,7 @@ cd ../../ $GMAKE distclean > /dev/null 2>&1 - ./configure CFLAGS="$ADD_CFLAGS" --with-pydebug $args > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" LDFLAGS="$ADD_LDFLAGS" --with-pydebug $args > /dev/null 2>&1 $GMAKE | grep _decimal printf "\n\n# ======================== refleak tests ===========================\n\n" @@ -86,7 +87,7 @@ printf "\nbuilding python ...\n\n" $GMAKE distclean > /dev/null 2>&1 - ./configure CFLAGS="$ADD_CFLAGS" $args > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" LDFLAGS="$ADD_LDFLAGS" $args > /dev/null 2>&1 $GMAKE | grep _decimal printf "\n\n# ======================== regular tests ===========================\n\n" @@ -106,7 +107,7 @@ print_config "valgrind tests: config=$config" $args printf "\nbuilding python ...\n\n" $GMAKE distclean > /dev/null 2>&1 - ./configure CFLAGS="$ADD_CFLAGS" --without-pymalloc $args > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" LDFLAGS="$ADD_LDFLAGS" --without-pymalloc $args > /dev/null 2>&1 $GMAKE | grep _decimal printf "\n\n# ======================== valgrind tests ===========================\n\n" @@ -132,7 +133,7 @@ printf "\nbuilding python ...\n\n" $GMAKE distclean > /dev/null 2>&1 - ./configure CFLAGS="$ADD_CFLAGS" --with-pydebug $args > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" LDFLAGS="$ADD_LDFLAGS" --with-pydebug $args > /dev/null 2>&1 $GMAKE | grep _decimal printf "\n\n# ========================== debug ===========================\n\n" @@ -143,7 +144,7 @@ printf "\nbuilding python ...\n\n" $GMAKE distclean > /dev/null 2>&1 - ./configure CFLAGS="$ADD_CFLAGS" $args > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" LDFLAGS="$ADD_LDFLAGS" $args > /dev/null 2>&1 $GMAKE | grep _decimal printf "\n\n# ======================== regular ===========================\n\n" @@ -163,7 +164,7 @@ printf "\nbuilding python ...\n\n" $GMAKE distclean > /dev/null 2>&1 - ./configure CFLAGS="$ADD_CFLAGS" --without-pymalloc $args > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" LDFLAGS="$ADD_LDFLAGS" --without-pymalloc $args > /dev/null 2>&1 $GMAKE | grep _decimal printf "\n\n# ======================== valgrind ==========================\n\n" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 21:13:38 2013 From: python-checkins at python.org (stefan.krah) Date: Wed, 29 May 2013 21:13:38 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?b?KTogTWVyZ2UgMy4zLg==?= Message-ID: <3bLM5t4nTKzSqF@mail.python.org> http://hg.python.org/cpython/rev/4585804b44a1 changeset: 83982:4585804b44a1 parent: 83980:3e0284efa9fd parent: 83981:280303da5b30 user: Stefan Krah date: Wed May 29 21:12:46 2013 +0200 summary: Merge 3.3. files: Modules/_decimal/tests/runall-memorydebugger.sh | 15 +++++---- 1 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Modules/_decimal/tests/runall-memorydebugger.sh b/Modules/_decimal/tests/runall-memorydebugger.sh --- a/Modules/_decimal/tests/runall-memorydebugger.sh +++ b/Modules/_decimal/tests/runall-memorydebugger.sh @@ -9,8 +9,9 @@ # Requirements: valgrind # -# Set additional CFLAGS for ./configure +# Set additional CFLAGS and LDFLAGS for ./configure ADD_CFLAGS= +ADD_LDFLAGS= CONFIGS_64="x64 uint128 ansi64 universal" @@ -74,7 +75,7 @@ cd ../../ $GMAKE distclean > /dev/null 2>&1 - ./configure CFLAGS="$ADD_CFLAGS" --with-pydebug $args > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" LDFLAGS="$ADD_LDFLAGS" --with-pydebug $args > /dev/null 2>&1 $GMAKE | grep _decimal printf "\n\n# ======================== refleak tests ===========================\n\n" @@ -86,7 +87,7 @@ printf "\nbuilding python ...\n\n" $GMAKE distclean > /dev/null 2>&1 - ./configure CFLAGS="$ADD_CFLAGS" $args > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" LDFLAGS="$ADD_LDFLAGS" $args > /dev/null 2>&1 $GMAKE | grep _decimal printf "\n\n# ======================== regular tests ===========================\n\n" @@ -106,7 +107,7 @@ print_config "valgrind tests: config=$config" $args printf "\nbuilding python ...\n\n" $GMAKE distclean > /dev/null 2>&1 - ./configure CFLAGS="$ADD_CFLAGS" --without-pymalloc $args > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" LDFLAGS="$ADD_LDFLAGS" --without-pymalloc $args > /dev/null 2>&1 $GMAKE | grep _decimal printf "\n\n# ======================== valgrind tests ===========================\n\n" @@ -132,7 +133,7 @@ printf "\nbuilding python ...\n\n" $GMAKE distclean > /dev/null 2>&1 - ./configure CFLAGS="$ADD_CFLAGS" --with-pydebug $args > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" LDFLAGS="$ADD_LDFLAGS" --with-pydebug $args > /dev/null 2>&1 $GMAKE | grep _decimal printf "\n\n# ========================== debug ===========================\n\n" @@ -143,7 +144,7 @@ printf "\nbuilding python ...\n\n" $GMAKE distclean > /dev/null 2>&1 - ./configure CFLAGS="$ADD_CFLAGS" $args > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" LDFLAGS="$ADD_LDFLAGS" $args > /dev/null 2>&1 $GMAKE | grep _decimal printf "\n\n# ======================== regular ===========================\n\n" @@ -163,7 +164,7 @@ printf "\nbuilding python ...\n\n" $GMAKE distclean > /dev/null 2>&1 - ./configure CFLAGS="$ADD_CFLAGS" --without-pymalloc $args > /dev/null 2>&1 + ./configure CFLAGS="$ADD_CFLAGS" LDFLAGS="$ADD_LDFLAGS" --without-pymalloc $args > /dev/null 2>&1 $GMAKE | grep _decimal printf "\n\n# ======================== valgrind ==========================\n\n" -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 22:45:22 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 29 May 2013 22:45:22 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Issue_=2318084=3A_Use_sys?= =?utf-8?q?=2Ebyteorder_in_wave=2Epy=2E?= Message-ID: <3bLP7k5BH9z7LkH@mail.python.org> http://hg.python.org/cpython/rev/ccffce2dde49 changeset: 83983:ccffce2dde49 parent: 83977:bcaaaa00425b user: Serhiy Storchaka date: Wed May 29 23:38:00 2013 +0300 summary: Issue #18084: Use sys.byteorder in wave.py. Original patch by Hideaki Takahashi. files: Lib/wave.py | 11 +++-------- Misc/ACKS | 1 + 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Lib/wave.py b/Lib/wave.py --- a/Lib/wave.py +++ b/Lib/wave.py @@ -82,13 +82,8 @@ _array_fmts = None, 'b', 'h', None, 'l' -# Determine endian-ness import struct -if struct.pack("h", 1) == b"\000\001": - big_endian = 1 -else: - big_endian = 0 - +import sys from chunk import Chunk from collections import namedtuple @@ -235,7 +230,7 @@ self._data_seek_needed = 0 if nframes == 0: return b'' - if self._sampwidth > 1 and big_endian: + if self._sampwidth > 1 and sys.byteorder == 'big': # unfortunately the fromfile() method does not take # something that only looks like a file object, so # we have to reach into the innards of the chunk object @@ -422,7 +417,7 @@ nframes = len(data) // (self._sampwidth * self._nchannels) if self._convert: data = self._convert(data) - if self._sampwidth > 1 and big_endian: + if self._sampwidth > 1 and sys.byteorder == 'big': import array data = array.array(_array_fmts[self._sampwidth], data) data.byteswap() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1222,6 +1222,7 @@ P?ter Szab? Amir Szekely Arfrever Frehtes Taifersar Arahesis +Hideaki Takahashi Neil Tallim Geoff Talvola Musashi Tamura -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Wed May 29 22:45:24 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Wed, 29 May 2013 22:45:24 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_heads?= Message-ID: <3bLP7m02xCz7LkV@mail.python.org> http://hg.python.org/cpython/rev/18ef35afc55d changeset: 83984:18ef35afc55d parent: 83982:4585804b44a1 parent: 83983:ccffce2dde49 user: Serhiy Storchaka date: Wed May 29 23:45:05 2013 +0300 summary: Merge heads files: Lib/wave.py | 11 +++-------- Misc/ACKS | 1 + 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Lib/wave.py b/Lib/wave.py --- a/Lib/wave.py +++ b/Lib/wave.py @@ -82,13 +82,8 @@ _array_fmts = None, 'b', 'h', None, 'l' -# Determine endian-ness import struct -if struct.pack("h", 1) == b"\000\001": - big_endian = 1 -else: - big_endian = 0 - +import sys from chunk import Chunk from collections import namedtuple @@ -235,7 +230,7 @@ self._data_seek_needed = 0 if nframes == 0: return b'' - if self._sampwidth > 1 and big_endian: + if self._sampwidth > 1 and sys.byteorder == 'big': # unfortunately the fromfile() method does not take # something that only looks like a file object, so # we have to reach into the innards of the chunk object @@ -422,7 +417,7 @@ nframes = len(data) // (self._sampwidth * self._nchannels) if self._convert: data = self._convert(data) - if self._sampwidth > 1 and big_endian: + if self._sampwidth > 1 and sys.byteorder == 'big': import array data = array.array(_array_fmts[self._sampwidth], data) data.byteswap() diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1222,6 +1222,7 @@ P?ter Szab? Amir Szekely Arfrever Frehtes Taifersar Arahesis +Hideaki Takahashi Neil Tallim Geoff Talvola Musashi Tamura -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 30 00:33:57 2013 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 30 May 2013 00:33:57 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Minor_clarifications=2E?= Message-ID: <3bLRY11gPDz7LkH@mail.python.org> http://hg.python.org/peps/rev/a33c5941269a changeset: 4918:a33c5941269a user: Guido van Rossum date: Wed May 29 15:33:55 2013 -0700 summary: Minor clarifications. files: pep-3156.txt | 30 ++++++++++++++++++------------ 1 files changed, 18 insertions(+), 12 deletions(-) diff --git a/pep-3156.txt b/pep-3156.txt --- a/pep-3156.txt +++ b/pep-3156.txt @@ -846,6 +846,12 @@ convention from the section "Callback Style" below) is always called with a single argument, the Future object. +- ``remove_done_callback(fn)``. Remove the argument from the list of + callbacks. This method is not defined by PEP 3148. The argument + must be equal (using ``==``) to the argument passed to + ``add_done_callback()``. Returns the number of times the callback + was removed. + - ``set_result(result)``. The Future must not be done (nor cancelled) already. This makes the Future done and schedules the callbacks. Difference with PEP 3148: This is a public API. @@ -1302,25 +1308,25 @@ - ``FIRST_EXCEPTION``: Wait until at least one Future is done (not cancelled) with an exception set. (The exclusion of cancelled - Futures from the filter is surprising, but PEP 3148 does it this - way.) + Futures from the condition is surprising, but PEP 3148 does it + this way.) - ``tulip.as_completed(fs, timeout=None)``. Returns an iterator whose - values are Futures; waiting for successive values waits until the - next Future or coroutine from the set ``fs`` completes, and returns - its result (or raises its exception). The optional argument - ``timeout`` has the same meaning and default as it does for - ``concurrent.futures.wait()``: when the timeout occurs, the next - Future returned by the iterator will raise ``TimeoutError`` when - waited for. Example of use:: + values are Futures or coroutines; waiting for successive values + waits until the next Future or coroutine from the set ``fs`` + completes, and returns its result (or raises its exception). The + optional argument ``timeout`` has the same meaning and default as it + does for ``concurrent.futures.wait()``: when the timeout occurs, the + next Future returned by the iterator will raise ``TimeoutError`` + when waited for. Example of use:: for f in as_completed(fs): result = yield from f # May raise an exception. # Use result. - Note: if you do not wait for the futures as they are produced by the - iterator, your ``for`` loop may not make progress (since you are not - allowing other tasks to run). + Note: if you do not wait for the values produced by the iterator, + your ``for`` loop may not make progress (since you are not allowing + other tasks to run). Sleeping -------- -- Repository URL: http://hg.python.org/peps From solipsis at pitrou.net Thu May 30 05:48:37 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 30 May 2013 05:48:37 +0200 Subject: [Python-checkins] Daily reference leaks (18ef35afc55d): sum=0 Message-ID: results for 18ef35afc55d on branch "default" -------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogV5krA0', '-x'] From python-checkins at python.org Thu May 30 09:15:00 2013 From: python-checkins at python.org (ned.deily) Date: Thu, 30 May 2013 09:15:00 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4MDk4?= =?utf-8?q?=3A_The_deprecated_OS_X_Build_Applet=2Eapp_fails_to_build_on?= Message-ID: <3bLg6D1HkRz7LnC@mail.python.org> http://hg.python.org/cpython/rev/cfdb4598c935 changeset: 83985:cfdb4598c935 branch: 2.7 parent: 83973:bcbad715c2ce user: Ned Deily date: Thu May 30 00:14:29 2013 -0700 summary: Issue #18098: The deprecated OS X Build Applet.app fails to build on OS X 10.8 systems because the Apple-deprecated QuickDraw headers have been removed from Xcode 4. Skip building it in this case. files: Lib/plat-mac/EasyDialogs.py | 9 ++++++++- Mac/Makefile.in | 25 ++++++++++++++++--------- Mac/README | 8 +++++--- Misc/NEWS | 7 +++++++ configure | 2 +- configure.ac | 2 +- 6 files changed, 38 insertions(+), 15 deletions(-) diff --git a/Lib/plat-mac/EasyDialogs.py b/Lib/plat-mac/EasyDialogs.py --- a/Lib/plat-mac/EasyDialogs.py +++ b/Lib/plat-mac/EasyDialogs.py @@ -243,8 +243,15 @@ +# The deprecated Carbon QuickDraw APIs are no longer available as of +# OS X 10.8. Raise an ImportError here in that case so that callers +# of EasyDialogs, like BuildApplet, will do the right thing. -screenbounds = Qd.GetQDGlobalsScreenBits().bounds +try: + screenbounds = Qd.GetQDGlobalsScreenBits().bounds +except AttributeError: + raise ImportError("QuickDraw APIs not available") + screenbounds = screenbounds[0]+4, screenbounds[1]+4, \ screenbounds[2]-4, screenbounds[3]-4 diff --git a/Mac/Makefile.in b/Mac/Makefile.in --- a/Mac/Makefile.in +++ b/Mac/Makefile.in @@ -202,15 +202,22 @@ cd IDLE && make install install_BuildApplet: - $(RUNSHARED) @ARCH_RUN_32BIT@ $(BUILDPYTHON) $(srcdir)/scripts/BuildApplet.py \ - --destroot "$(DESTDIR)" \ - --python=$(prefix)/Resources/Python.app/Contents/MacOS/Python \ - --output "$(DESTDIR)$(PYTHONAPPSDIR)/Build Applet.app" \ - $(srcdir)/scripts/BuildApplet.py -ifneq ($(LIPO_32BIT_FLAGS),) - rm "$(DESTDIR)$(PYTHONAPPSDIR)/Build Applet.app/Contents/MacOS/Python" - lipo $(LIPO_32BIT_FLAGS) -output "$(DESTDIR)$(PYTHONAPPSDIR)/Build Applet.app/Contents/MacOS/Python" $(BUILDPYTHON) -endif + if ! $(RUNSHARED) @ARCH_RUN_32BIT@ $(BUILDPYTHON) \ + -c 'import EasyDialogs' 2>/dev/null ; then \ + echo "EasyDialogs not available in this Python - skipping Build Applet.app" ; \ + else \ + $(RUNSHARED) @ARCH_RUN_32BIT@ $(BUILDPYTHON) $(srcdir)/scripts/BuildApplet.py \ + --destroot "$(DESTDIR)" \ + --python=$(prefix)/Resources/Python.app/Contents/MacOS/Python \ + --output "$(DESTDIR)$(PYTHONAPPSDIR)/Build Applet.app" \ + $(srcdir)/scripts/BuildApplet.py && \ + if [ -n "$(LIPO_32BIT_FLAGS)" ] ; then \ + rm "$(DESTDIR)$(PYTHONAPPSDIR)/Build Applet.app/Contents/MacOS/Python" && \ + lipo $(LIPO_32BIT_FLAGS) \ + -output "$(DESTDIR)$(PYTHONAPPSDIR)/Build Applet.app/Contents/MacOS/Python" \ + $(BUILDPYTHON) ; \ + fi \ + fi MACLIBDEST=$(LIBDEST)/plat-mac MACTOOLSDEST=$(prefix)/Mac/Tools diff --git a/Mac/README b/Mac/README --- a/Mac/README +++ b/Mac/README @@ -209,9 +209,11 @@ through PythonLauncher's preferences dialog. "BuildApplet.app" creates an applet from a Python script. Drop the script on it -and out comes a full-featured MacOS application. There is much more to this, -to be supplied later. Some useful (but outdated) info can be found in -Mac/Demo. +and out comes a full-featured MacOS application. BuildApplet.app is now +deprecated and has been removed in Python 3. As of OS X 10.8, Xcode 4 no +longer supplies the headers for the deprecated QuickDraw APIs used by +the EasyDialogs module making BuildApplet unusable as an app. It will +not be built by the Mac/Makefile in this case. The commandline scripts /usr/local/bin/python and pythonw can be used to run non-GUI and GUI python scripts from the command line, respectively. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,6 +37,13 @@ the default for linking if LDSHARED is not also overriden. This restores Distutils behavior introduced in 2.7.3 and inadvertently dropped in 2.7.4. +Build +----- + +- Issue #18098: The deprecated OS X Build Applet.app fails to build on + OS X 10.8 systems because the Apple-deprecated QuickDraw headers have + been removed from Xcode 4. Skip building it in this case. + IDLE ---- diff --git a/configure b/configure --- a/configure +++ b/configure @@ -2981,6 +2981,7 @@ +ARCH_RUN_32BIT="" UNIVERSAL_ARCHS="32-bit" @@ -7996,7 +7997,6 @@ esac -ARCH_RUN_32BIT="" case $ac_sys_system/$ac_sys_release in Darwin/[01567]\..*) diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -145,6 +145,7 @@ AC_SUBST(UNIVERSALSDK) AC_SUBST(ARCH_RUN_32BIT) +ARCH_RUN_32BIT="" UNIVERSAL_ARCHS="32-bit" AC_SUBST(LIPO_32BIT_FLAGS) @@ -1801,7 +1802,6 @@ esac -ARCH_RUN_32BIT="" AC_SUBST(LIBTOOL_CRUFT) case $ac_sys_system/$ac_sys_release in Darwin/@<:@01567@:>@\..*) -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 30 20:48:14 2013 From: python-checkins at python.org (terry.reedy) Date: Thu, 30 May 2013 20:48:14 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1Mzky?= =?utf-8?q?=3A_Create_a_unittest_framework_for_IDLE=2C_2=2E7_version=2E?= Message-ID: <3bLyV63RPgz7Lsm@mail.python.org> http://hg.python.org/cpython/rev/93eb15779050 changeset: 83986:93eb15779050 branch: 2.7 user: Terry Jan Reedy date: Thu May 30 14:47:33 2013 -0400 summary: Issue #15392: Create a unittest framework for IDLE, 2.7 version. Preliminary patch by Rajagopalasarma Jayakrishnan. files: Lib/idlelib/CallTips.py | 4 +- Lib/idlelib/PathBrowser.py | 3 +- Lib/idlelib/idle_test/README.txt | 63 +++++++++++ Lib/idlelib/idle_test/__init__.py | 9 + Lib/idlelib/idle_test/test_calltips.py | 14 ++ Lib/idlelib/idle_test/test_pathbrowser.py | 12 ++ Lib/test/test_idle.py | 17 ++ Misc/ACKS | 1 + Misc/NEWS | 3 + 9 files changed, 124 insertions(+), 2 deletions(-) diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py --- a/Lib/idlelib/CallTips.py +++ b/Lib/idlelib/CallTips.py @@ -223,4 +223,6 @@ tests = (t1, t2, t3, t4, t5, t6, t7, TC, tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6, tc.t7) - test(tests) + # test(tests) + from unittest import main + main('idlelib.idle_test.test_calltips', verbosity=2, exit=False) diff --git a/Lib/idlelib/PathBrowser.py b/Lib/idlelib/PathBrowser.py --- a/Lib/idlelib/PathBrowser.py +++ b/Lib/idlelib/PathBrowser.py @@ -92,4 +92,5 @@ mainloop() if __name__ == "__main__": - main() + from unittest import main + main('idlelib.idle_test.test_pathbrowser', verbosity=2, exit=False) diff --git a/Lib/idlelib/idle_test/README.txt b/Lib/idlelib/idle_test/README.txt new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/README.txt @@ -0,0 +1,63 @@ +README FOR IDLE TESTS IN IDLELIB.IDLE_TEST + +The idle directory, idlelib, has over 60 xyz.py files. The idle_test +subdirectory should contain a test_xyy.py for each one. (For test modules, +make 'xyz' lower case.) Each should start with the following cut-paste +template, with the blanks after after '.'. 'as', and '_' filled in. +--- +import unittest +import idlelib. as + +class Test_(unittest.TestCase): + + def test_(self): + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=2) +--- +Idle tests are run with unittest; do not use regrtest's test_main. + +Once test_xyy is written, the following should go at the end of xyy.py, +with xyz (lowercased) added after 'test_'. +--- +if __name__ == "__main__": + import unittest + unittest.main('idlelib.idle_test.test_', verbosity=2, exit=False) +--- + +In Idle, pressing F5 in an editor window with either xyz.py or test_xyz.py +loaded will then run the test with the version of Python running Idle and +tracebacks will appear in the Shell window. The options are appropriate for +developers running (as opposed to importing) either type of file during +development: verbosity=2 lists all test_y methods; exit=False avoids a +spurious sys.exit traceback when running in Idle. The following command +lines also run test_xyz.py + +python -m idlelib.xyz # With the capitalization of the xyz module +python -m unittest -v idlelib.idle_test.test_xyz + +To run all idle tests either interactively ('>>>', with unittest imported) +or from a command line, use one of the following. + +>>> unittest.main('idlelib.idle_test', verbosity=2, exit=False) +python -m unittest -v idlelib.idle_test +python -m test.test_idle +python -m test test_idle + +The idle tests are 'discovered' in idlelib.idle_test.__init__.load_tests, +which is also imported into test.test_idle. Normally, neither file should be +changed when working on individual test modules. The last command runs runs +unittest indirectly through regrtest. The same happens when the entire test +suite is run with 'python -m test'. So it must work for buildbots to stay green. + +To run an individual Testcase or test method, extend the +dotted name given to unittest on the command line. + +python -m unittest -v idlelib.idle_test.text_xyz.Test_case.test_meth + +To disable test/test_idle.py, there are at least two choices. +a. Comment out 'load_tests' line, no no tests are discovered (simple and safe); +Running no tests passes, so there is no indication that nothing was run. +b.Before that line, make module an unexpected skip for regrtest with +import unittest; raise unittest.SkipTest('skip for buildbots') +When run directly with unittest, this causes a normal exit and traceback. \ No newline at end of file diff --git a/Lib/idlelib/idle_test/__init__.py b/Lib/idlelib/idle_test/__init__.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/__init__.py @@ -0,0 +1,9 @@ +from os.path import dirname + +def load_tests(loader, standard_tests, pattern): + this_dir = dirname(__file__) + top_dir = dirname(dirname(this_dir)) + package_tests = loader.discover(start_dir=this_dir, pattern='test*.py', + top_level_dir=top_dir) + standard_tests.addTests(package_tests) + return standard_tests diff --git a/Lib/idlelib/idle_test/test_calltips.py b/Lib/idlelib/idle_test/test_calltips.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/test_calltips.py @@ -0,0 +1,14 @@ +import unittest +import idlelib.CallTips as ct +CTi = ct.CallTips() + +class Test_get_entity(unittest.TestCase): + # In 3.x, get_entity changed from 'instance method' to module function + # since 'self' not used. Use dummy instance until change 2.7 also. + def test_bad_entity(self): + self.assertIsNone(CTi.get_entity('1/0')) + def test_good_entity(self): + self.assertIs(CTi.get_entity('int'), int) + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=False) diff --git a/Lib/idlelib/idle_test/test_pathbrowser.py b/Lib/idlelib/idle_test/test_pathbrowser.py new file mode 100644 --- /dev/null +++ b/Lib/idlelib/idle_test/test_pathbrowser.py @@ -0,0 +1,12 @@ +import unittest +import idlelib.PathBrowser as PathBrowser + +class PathBrowserTest(unittest.TestCase): + + def test_DirBrowserTreeItem(self): + # Issue16226 - make sure that getting a sublist works + d = PathBrowser.DirBrowserTreeItem('') + d.GetSubList() + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=False) diff --git a/Lib/test/test_idle.py b/Lib/test/test_idle.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_idle.py @@ -0,0 +1,17 @@ +# Skip test if _tkinter or _thread wasn't built or idlelib was deleted. +try: + import Tkinter + import threading # imported by PyShell, imports _thread + import idlelib.idle_test as idletest +except ImportError: + import unittest + raise unittest.SkipTest + +# Without test_main present, regrtest.runtest_inner (line1219) calls +# unittest.TestLoader().loadTestsFromModule(this_module) which calls +# load_tests() if it finds it. (Unittest.main does the same.) +load_tests = idletest.load_tests + +if __name__ == '__main__': + import unittest + unittest.main(verbosity=2, exit=False) diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -478,6 +478,7 @@ Jack Jansen Bill Janssen Thomas Jarosch +Rajagopalasarma Jayakrishnan Drew Jenkins Flemming Kj?r Jensen Philip H. Jensen diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -47,6 +47,9 @@ IDLE ---- +- Issue #15392: Create a unittest framework for IDLE. + Preliminary patch by Rajagopalasarma Jayakrishnan + - Issue #14146: Highlight source line while debugging on Windows. - Issue #17532: Always include Options menu for IDLE on OS X. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 30 21:02:30 2013 From: python-checkins at python.org (lukasz.langa) Date: Thu, 30 May 2013 21:02:30 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Fixed_=2318075_-_Infinite_?= =?utf-8?q?recursion_tests_triggering_a_segfault_on_Mac_OS_X?= Message-ID: <3bLypZ1p5Dz7LsC@mail.python.org> http://hg.python.org/cpython/rev/b07ad4b5e349 changeset: 83987:b07ad4b5e349 parent: 83984:18ef35afc55d user: ?ukasz Langa date: Thu May 30 20:58:53 2013 +0200 summary: Fixed #18075 - Infinite recursion tests triggering a segfault on Mac OS X Patch by Ronald Oussoren files: configure | 6 ++++++ configure.ac | 6 ++++++ 2 files changed, 12 insertions(+), 0 deletions(-) diff --git a/configure b/configure --- a/configure +++ b/configure @@ -8614,6 +8614,12 @@ # -u libsys_s pulls in all symbols in libsys Darwin/*) LINKFORSHARED="$extra_undefs -framework CoreFoundation" + + # Issue #18075: the default maximum stack size (8MBytes) is too + # small for the default recursion limit. Increase the stack size + # to ensure that tests don't crash + LINKFORSHARED="-Wl,-stack_size,1000000 $LINKFORSHARED" + if test "$enable_framework" then LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -2114,6 +2114,12 @@ # -u libsys_s pulls in all symbols in libsys Darwin/*) LINKFORSHARED="$extra_undefs -framework CoreFoundation" + + # Issue #18075: the default maximum stack size (8MBytes) is too + # small for the default recursion limit. Increase the stack size + # to ensure that tests don't crash + LINKFORSHARED="-Wl,-stack_size,1000000 $LINKFORSHARED" + if test "$enable_framework" then LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Thu May 30 23:31:56 2013 From: python-checkins at python.org (brett.cannon) Date: Thu, 30 May 2013 23:31:56 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Rename_importlib=2Eutil=2E?= =?utf-8?q?ModuleManager_to_module=5Fto=5Fload_so_that_the_name?= Message-ID: <3bM2703Cjpz7LvV@mail.python.org> http://hg.python.org/cpython/rev/6ace4133c1c0 changeset: 83988:6ace4133c1c0 user: Brett Cannon date: Thu May 30 17:31:47 2013 -0400 summary: Rename importlib.util.ModuleManager to module_to_load so that the name explains better what the context manager is providing. files: Doc/library/importlib.rst | 13 +- Lib/importlib/_bootstrap.py | 11 +- Lib/importlib/util.py | 2 +- Lib/test/test_importlib/test_util.py | 14 +- Misc/NEWS | 4 +- Python/importlib.h | 7035 +++++++------ 6 files changed, 3550 insertions(+), 3529 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -789,12 +789,13 @@ .. versionadded:: 3.3 -.. class:: ModuleManager(name) +.. function:: module_to_load(name) - A :term:`context manager` which provides the module to load. The module will - either come from :attr:`sys.modules` in the case of reloading or a fresh - module if loading a new module. Proper cleanup of :attr:`sys.modules` occurs - if the module was new and an exception was raised. + Returns a :term:`context manager` which provides the module to load. The + module will either come from :attr:`sys.modules` in the case of reloading or + a fresh module if loading a new module. Proper cleanup of + :attr:`sys.modules` occurs if the module was new and an exception was + raised. .. versionadded:: 3.4 @@ -823,7 +824,7 @@ in :data:`sys.modules` then it is left alone. .. note:: - :class:`ModuleManager` subsumes the module management aspect of this + :func:`module_to_load` subsumes the module management aspect of this decorator. .. versionchanged:: 3.3 diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -484,7 +484,8 @@ print(message.format(*args), file=sys.stderr) -class ModuleManager: +# Written as a class only because contextlib is not available. +class _ModuleManager: """Context manager which returns the module to be loaded. @@ -516,6 +517,12 @@ del sys.modules[self._name] +def module_to_load(name): + """Return a context manager which provides the module object to load.""" + # Hiding _ModuleManager behind a function for better naming. + return _ModuleManager(name) + + def set_package(fxn): """Set __package__ on the returned module.""" def set_package_wrapper(*args, **kwargs): @@ -559,7 +566,7 @@ """ def module_for_loader_wrapper(self, fullname, *args, **kwargs): - with ModuleManager(fullname) as module: + with module_to_load(fullname) as module: module.__loader__ = self try: is_package = self.is_package(fullname) diff --git a/Lib/importlib/util.py b/Lib/importlib/util.py --- a/Lib/importlib/util.py +++ b/Lib/importlib/util.py @@ -1,6 +1,6 @@ """Utility code for constructing importers, etc.""" -from ._bootstrap import ModuleManager +from ._bootstrap import module_to_load from ._bootstrap import module_for_loader from ._bootstrap import set_loader from ._bootstrap import set_package diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py --- a/Lib/test/test_importlib/test_util.py +++ b/Lib/test/test_importlib/test_util.py @@ -7,7 +7,7 @@ import unittest -class ModuleManagerTests(unittest.TestCase): +class ModuleToLoadTests(unittest.TestCase): module_name = 'ModuleManagerTest_module' @@ -19,7 +19,7 @@ # Test a new module is created, inserted into sys.modules, has # __initializing__ set to True after entering the context manager, # and __initializing__ set to False after exiting. - with util.ModuleManager(self.module_name) as module: + with util.module_to_load(self.module_name) as module: self.assertIn(self.module_name, sys.modules) self.assertIs(sys.modules[self.module_name], module) self.assertTrue(module.__initializing__) @@ -28,19 +28,19 @@ def test_new_module_failed(self): # Test the module is removed from sys.modules. try: - with util.ModuleManager(self.module_name) as module: + with util.module_to_load(self.module_name) as module: self.assertIn(self.module_name, sys.modules) raise exception except Exception: self.assertNotIn(self.module_name, sys.modules) else: - self.fail('importlib.util.ModuleManager swallowed an exception') + self.fail('importlib.util.module_to_load swallowed an exception') def test_reload(self): # Test that the same module is in sys.modules. created_module = imp.new_module(self.module_name) sys.modules[self.module_name] = created_module - with util.ModuleManager(self.module_name) as module: + with util.module_to_load(self.module_name) as module: self.assertIs(module, created_module) def test_reload_failed(self): @@ -48,12 +48,12 @@ created_module = imp.new_module(self.module_name) sys.modules[self.module_name] = created_module try: - with util.ModuleManager(self.module_name) as module: + with util.module_to_load(self.module_name) as module: raise Exception except Exception: self.assertIn(self.module_name, sys.modules) else: - self.fail('importlib.util.ModuleManager swallowed an exception') + self.fail('importlib.util.module_to_load swallowed an exception') class ModuleForLoaderTests(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -103,8 +103,8 @@ - Issue #18070: Have importlib.util.module_for_loader() set attributes unconditionally in order to properly support reloading. -- Add importlib.util.ModuleManager as a context manager to provide the proper - module object to load. +- Add importlib.util.module_to_load to return a context manager to provide the + proper module object to load. - Issue #18025: Fixed a segfault in io.BufferedIOBase.readinto() when raw stream's read() returns more bytes than requested. diff --git a/Python/importlib.h b/Python/importlib.h --- a/Python/importlib.h +++ b/Python/importlib.h [stripped] -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 31 00:25:12 2013 From: python-checkins at python.org (terry.reedy) Date: Fri, 31 May 2013 00:25:12 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE1Mzky?= =?utf-8?q?=3A_Use_test=2Etest=5Fsupport=2C_as_used_test=2Esupport_in_3=2E?= =?utf-8?q?x=2E?= Message-ID: <3bM3JS48mtz7Ltj@mail.python.org> http://hg.python.org/cpython/rev/6159916c712e changeset: 83989:6159916c712e branch: 2.7 parent: 83986:93eb15779050 user: Terry Jan Reedy date: Thu May 30 18:24:28 2013 -0400 summary: Issue #15392: Use test.test_support, as used test.support in 3.x. files: Lib/test/test_idle.py | 11 ++++------- 1 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_idle.py b/Lib/test/test_idle.py --- a/Lib/test/test_idle.py +++ b/Lib/test/test_idle.py @@ -1,11 +1,8 @@ # Skip test if _tkinter or _thread wasn't built or idlelib was deleted. -try: - import Tkinter - import threading # imported by PyShell, imports _thread - import idlelib.idle_test as idletest -except ImportError: - import unittest - raise unittest.SkipTest +from test.test_support import import_module +import_module('Tkinter') +import_module('threading') # imported by PyShell, imports _thread +idletest = import_module('idlelib.idle_test') # Without test_main present, regrtest.runtest_inner (line1219) calls # unittest.TestLoader().loadTestsFromModule(this_module) which calls -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 31 03:06:35 2013 From: python-checkins at python.org (terry.reedy) Date: Fri, 31 May 2013 03:06:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE1Mzky?= =?utf-8?q?=3A_Finish_news_entry=2E?= Message-ID: <3bM6tg5Wn1z7LwD@mail.python.org> http://hg.python.org/cpython/rev/16fea8b0f8c4 changeset: 83990:16fea8b0f8c4 branch: 3.3 parent: 83981:280303da5b30 user: Terry Jan Reedy date: Thu May 30 20:55:52 2013 -0400 summary: Issue #15392: Finish news entry. files: Misc/NEWS | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -68,7 +68,7 @@ ---- - Issue #15392: Create a unittest framework for IDLE. - Rajagopalasarma Jayakrishnan + Initial patch by Rajagopalasarma Jayakrishnan. - Issue #14146: Highlight source line while debugging on Windows. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 31 03:06:37 2013 From: python-checkins at python.org (terry.reedy) Date: Fri, 31 May 2013 03:06:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_merge?= Message-ID: <3bM6tj0RRtz7Lvs@mail.python.org> http://hg.python.org/cpython/rev/26cf22140cca changeset: 83991:26cf22140cca parent: 83988:6ace4133c1c0 parent: 83990:16fea8b0f8c4 user: Terry Jan Reedy date: Thu May 30 21:05:53 2013 -0400 summary: merge 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 @@ -402,6 +402,9 @@ IDLE ---- +- Issue #15392: Create a unittest framework for IDLE. + Initial patch by Rajagopalasarma Jayakrishnan. + - Issue #14146: Highlight source line while debugging on Windows. - Issue #17838: Allow sys.stdin to be reassigned. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 31 03:09:27 2013 From: python-checkins at python.org (terry.reedy) Date: Fri, 31 May 2013 03:09:27 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython=3A_Remove_duplicate_entry_due?= =?utf-8?q?_to_mismerge_and_incomplete_resolution=2E?= Message-ID: <3bM6xz1tKzz7Lph@mail.python.org> http://hg.python.org/cpython/rev/0ebc9005cb00 changeset: 83992:0ebc9005cb00 user: Terry Jan Reedy date: Thu May 30 21:08:49 2013 -0400 summary: Remove duplicate entry due to mismerge and incomplete resolution. files: Misc/NEWS | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -320,9 +320,6 @@ Tests ----- -- Issue #15392: Create a unittest framework for IDLE. - Rajagopalasarma Jayakrishnan - - Issue #17992: Add timeouts to asyncore and asynchat tests so that they won't accidentally hang. -- Repository URL: http://hg.python.org/cpython From solipsis at pitrou.net Fri May 31 05:50:00 2013 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 31 May 2013 05:50:00 +0200 Subject: [Python-checkins] Daily reference leaks (0ebc9005cb00): sum=2 Message-ID: results for 0ebc9005cb00 on branch "default" -------------------------------------------- test_concurrent_futures leaked [-2, 3, 1] memory blocks, sum=2 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/cpython/refleaks/reflogiuKHdR', '-x'] From python-checkins at python.org Fri May 31 11:34:16 2013 From: python-checkins at python.org (lukasz.langa) Date: Fri, 31 May 2013 11:34:16 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_reference_the_final_posting_o?= =?utf-8?q?n_python-dev?= Message-ID: <3bML8S3WV3z7Lml@mail.python.org> http://hg.python.org/peps/rev/92816a630302 changeset: 4919:92816a630302 user: ?ukasz Langa date: Fri May 31 11:34:10 2013 +0200 summary: reference the final posting on python-dev files: pep-0443.txt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/pep-0443.txt b/pep-0443.txt --- a/pep-0443.txt +++ b/pep-0443.txt @@ -8,7 +8,7 @@ Type: Standards Track Content-Type: text/x-rst Created: 22-May-2013 -Post-History: 22-May-2013, 25-May-2013 +Post-History: 22-May-2013, 25-May-2013, 31-May-2013 Replaces: 245, 246, 3124 -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri May 31 12:31:46 2013 From: python-checkins at python.org (lukasz.langa) Date: Fri, 31 May 2013 12:31:46 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?peps=3A_Explicitly_state_that_the_def?= =?utf-8?q?ault_implementation_is_registered_for_=60object=60?= Message-ID: <3bMMQp4Hbmz7Lwm@mail.python.org> http://hg.python.org/peps/rev/4d6c827944c4 changeset: 4920:4d6c827944c4 user: ?ukasz Langa date: Fri May 31 12:31:11 2013 +0200 summary: Explicitly state that the default implementation is registered for `object` Thanks to Gustavo Carneiro for the suggestion. files: pep-0443.txt | 10 +++++++--- 1 files changed, 7 insertions(+), 3 deletions(-) diff --git a/pep-0443.txt b/pep-0443.txt --- a/pep-0443.txt +++ b/pep-0443.txt @@ -134,13 +134,17 @@ Where there is no registered implementation for a specific type, its method resolution order is used to find a more generic implementation. +The original function decorated with ``@singledispatch`` is registered +for the base ``object`` type, which means it is used if no better +implementation is found. + To check which implementation will the generic function choose for a given type, use the ``dispatch()`` attribute:: >>> fun.dispatch(float) - >>> fun.dispatch(dict) - + >>> fun.dispatch(dict) # note: default implementation + To access all registered implementations, use the read-only ``registry`` attribute:: @@ -152,7 +156,7 @@ >>> fun.registry[float] >>> fun.registry[object] - + The proposed API is intentionally limited and opinionated, as to ensure it is easy to explain and use, as well as to maintain consistency with -- Repository URL: http://hg.python.org/peps From python-checkins at python.org Fri May 31 21:32:28 2013 From: python-checkins at python.org (phillip.eby) Date: Fri, 31 May 2013 21:32:28 +0200 (CEST) Subject: [Python-checkins] r88998 - sandbox/branches/setuptools-0.6/setuptools/ssl_support.py Message-ID: <3bMbQh0Zftz7Lmf@mail.python.org> Author: phillip.eby Date: Fri May 31 21:32:27 2013 New Revision: 88998 Log: Fix missing import Modified: sandbox/branches/setuptools-0.6/setuptools/ssl_support.py Modified: sandbox/branches/setuptools-0.6/setuptools/ssl_support.py ============================================================================== --- sandbox/branches/setuptools-0.6/setuptools/ssl_support.py (original) +++ sandbox/branches/setuptools-0.6/setuptools/ssl_support.py Fri May 31 21:32:27 2013 @@ -1,5 +1,5 @@ -import sys, os, socket, urllib2, atexit, re -from pkg_resources import ResolutionError, ExtractionError +import sys, os, socket, urllib2, atexit +from pkg_resources import ResolutionError, ExtractionError, resource_filename try: import ssl @@ -236,7 +236,7 @@ if os.path.isfile(cert_path): return cert_path try: - return pkg_resources.resource_filename('certifi', 'cacert.pem') + return resource_filename('certifi', 'cacert.pem') except (ImportError, ResolutionError, ExtractionError): return None From python-checkins at python.org Fri May 31 21:32:43 2013 From: python-checkins at python.org (phillip.eby) Date: Fri, 31 May 2013 21:32:43 +0200 (CEST) Subject: [Python-checkins] r88999 - sandbox/trunk/setuptools/setuptools/ssl_support.py Message-ID: <3bMbQz3fZvz7Lmf@mail.python.org> Author: phillip.eby Date: Fri May 31 21:32:43 2013 New Revision: 88999 Log: Fix missing import Modified: sandbox/trunk/setuptools/setuptools/ssl_support.py Modified: sandbox/trunk/setuptools/setuptools/ssl_support.py ============================================================================== --- sandbox/trunk/setuptools/setuptools/ssl_support.py (original) +++ sandbox/trunk/setuptools/setuptools/ssl_support.py Fri May 31 21:32:43 2013 @@ -1,5 +1,5 @@ -import sys, os, socket, urllib2, atexit, re -from pkg_resources import ResolutionError, ExtractionError +import sys, os, socket, urllib2, atexit +from pkg_resources import ResolutionError, ExtractionError, resource_filename try: import ssl @@ -236,7 +236,7 @@ if os.path.isfile(cert_path): return cert_path try: - return pkg_resources.resource_filename('certifi', 'cacert.pem') + return resource_filename('certifi', 'cacert.pem') except (ImportError, ResolutionError, ExtractionError): return None From python-checkins at python.org Fri May 31 21:35:34 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 31 May 2013 21:35:34 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMy4zKTogSXNzdWUgIzE4MDk0?= =?utf-8?q?=3A_test=5Fuuid_no_more_reports_skipped_tests_as_passed=2E?= Message-ID: <3bMbVG3bXBzNGX@mail.python.org> http://hg.python.org/cpython/rev/81c02d2c830d changeset: 83993:81c02d2c830d branch: 3.3 parent: 83990:16fea8b0f8c4 user: Serhiy Storchaka date: Fri May 31 22:31:02 2013 +0300 summary: Issue #18094: test_uuid no more reports skipped tests as passed. files: Lib/test/test_uuid.py | 78 ++++++++++-------------------- Misc/NEWS | 2 + 2 files changed, 29 insertions(+), 51 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 @@ -1,6 +1,6 @@ -from unittest import TestCase -from test import support +import unittest import builtins +import os import uuid def importable(name): @@ -10,7 +10,7 @@ except: return False -class TestUUID(TestCase): +class TestUUID(unittest.TestCase): last_node = None source2node = {} @@ -310,24 +310,22 @@ else: TestUUID.last_node = node + @unittest.skipUnless(os.name == 'posix', 'requires Posix') def test_ifconfig_getnode(self): - import sys - import os - if os.name == 'posix': - node = uuid._ifconfig_getnode() - if node is not None: - self.check_node(node, 'ifconfig') + node = uuid._ifconfig_getnode() + if node is not None: + self.check_node(node, 'ifconfig') + @unittest.skipUnless(os.name == 'nt', 'requires Windows') def test_ipconfig_getnode(self): - import os - if os.name == 'nt': - node = uuid._ipconfig_getnode() - if node is not None: - self.check_node(node, 'ipconfig') + node = uuid._ipconfig_getnode() + if node is not None: + self.check_node(node, 'ipconfig') + @unittest.skipUnless(importable('win32wnet'), 'requires win32wnet') + @unittest.skipUnless(importable('netbios'), 'requires netbios') def test_netbios_getnode(self): - if importable('win32wnet') and importable('netbios'): - self.check_node(uuid._netbios_getnode(), 'netbios') + self.check_node(uuid._netbios_getnode(), 'netbios') def test_random_getnode(self): node = uuid._random_getnode() @@ -335,22 +333,20 @@ self.assertTrue(node & 0x010000000000) self.assertTrue(node < (1 << 48)) + @unittest.skipUnless(os.name == 'posix', 'requires Posix') + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') def test_unixdll_getnode(self): - import sys - import os - if importable('ctypes') and os.name == 'posix': - try: # Issues 1481, 3581: _uuid_generate_time() might be None. - self.check_node(uuid._unixdll_getnode(), 'unixdll') - except TypeError: - pass + try: # Issues 1481, 3581: _uuid_generate_time() might be None. + self.check_node(uuid._unixdll_getnode(), 'unixdll') + except TypeError: + pass + @unittest.skipUnless(os.name == 'nt', 'requires Windows') + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') def test_windll_getnode(self): - import os - if importable('ctypes') and os.name == 'nt': - self.check_node(uuid._windll_getnode(), 'windll') + self.check_node(uuid._windll_getnode(), 'windll') def test_getnode(self): - import sys node1 = uuid.getnode() self.check_node(node1, "getnode1") @@ -360,13 +356,8 @@ self.assertEqual(node1, node2) + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') def test_uuid1(self): - # uuid1 requires ctypes. - try: - import ctypes - except ImportError: - return - equal = self.assertEqual # Make sure uuid1() generates UUIDs that are actually version 1. @@ -419,13 +410,8 @@ equal(u, uuid.UUID(v)) equal(str(u), v) + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') def test_uuid4(self): - # uuid4 requires ctypes. - try: - import ctypes - except ImportError: - return - equal = self.assertEqual # Make sure uuid4() generates UUIDs that are actually version 4. @@ -457,12 +443,8 @@ equal(u, uuid.UUID(v)) equal(str(u), v) + @unittest.skipUnless(os.name == 'posix', 'requires Posix') def testIssue8621(self): - import os - import sys - if os.name != 'posix': - return - # On at least some versions of OSX uuid.uuid4 generates # the same sequence of UUIDs in the parent and any # children started using fork. @@ -483,11 +465,5 @@ self.assertNotEqual(parent_value, child_value) - - - -def test_main(): - support.run_unittest(TestUUID) - if __name__ == '__main__': - test_main() + unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -78,6 +78,8 @@ Tests ----- +- Issue #18094: test_uuid no more reports skipped tests as passed. + - Issue #11995: test_pydoc doesn't import all sys.path modules anymore. Documentation -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 31 21:35:35 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 31 May 2013 21:35:35 +0200 (CEST) Subject: [Python-checkins] =?utf-8?q?cpython_=28merge_3=2E3_-=3E_default?= =?utf-8?q?=29=3A_Issue_=2318094=3A_test=5Fuuid_no_more_reports_skipped_te?= =?utf-8?q?sts_as_passed=2E?= Message-ID: <3bMbVH6ftcz7LnZ@mail.python.org> http://hg.python.org/cpython/rev/ebd11a19d830 changeset: 83994:ebd11a19d830 parent: 83992:0ebc9005cb00 parent: 83993:81c02d2c830d user: Serhiy Storchaka date: Fri May 31 22:34:00 2013 +0300 summary: Issue #18094: test_uuid no more reports skipped tests as passed. files: Lib/test/test_uuid.py | 78 ++++++++++-------------------- Misc/NEWS | 3 + 2 files changed, 30 insertions(+), 51 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 @@ -1,6 +1,6 @@ -from unittest import TestCase -from test import support +import unittest import builtins +import os import uuid def importable(name): @@ -10,7 +10,7 @@ except: return False -class TestUUID(TestCase): +class TestUUID(unittest.TestCase): last_node = None source2node = {} @@ -310,24 +310,22 @@ else: TestUUID.last_node = node + @unittest.skipUnless(os.name == 'posix', 'requires Posix') def test_ifconfig_getnode(self): - import sys - import os - if os.name == 'posix': - node = uuid._ifconfig_getnode() - if node is not None: - self.check_node(node, 'ifconfig') + node = uuid._ifconfig_getnode() + if node is not None: + self.check_node(node, 'ifconfig') + @unittest.skipUnless(os.name == 'nt', 'requires Windows') def test_ipconfig_getnode(self): - import os - if os.name == 'nt': - node = uuid._ipconfig_getnode() - if node is not None: - self.check_node(node, 'ipconfig') + node = uuid._ipconfig_getnode() + if node is not None: + self.check_node(node, 'ipconfig') + @unittest.skipUnless(importable('win32wnet'), 'requires win32wnet') + @unittest.skipUnless(importable('netbios'), 'requires netbios') def test_netbios_getnode(self): - if importable('win32wnet') and importable('netbios'): - self.check_node(uuid._netbios_getnode(), 'netbios') + self.check_node(uuid._netbios_getnode(), 'netbios') def test_random_getnode(self): node = uuid._random_getnode() @@ -335,22 +333,20 @@ self.assertTrue(node & 0x010000000000) self.assertTrue(node < (1 << 48)) + @unittest.skipUnless(os.name == 'posix', 'requires Posix') + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') def test_unixdll_getnode(self): - import sys - import os - if importable('ctypes') and os.name == 'posix': - try: # Issues 1481, 3581: _uuid_generate_time() might be None. - self.check_node(uuid._unixdll_getnode(), 'unixdll') - except TypeError: - pass + try: # Issues 1481, 3581: _uuid_generate_time() might be None. + self.check_node(uuid._unixdll_getnode(), 'unixdll') + except TypeError: + pass + @unittest.skipUnless(os.name == 'nt', 'requires Windows') + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') def test_windll_getnode(self): - import os - if importable('ctypes') and os.name == 'nt': - self.check_node(uuid._windll_getnode(), 'windll') + self.check_node(uuid._windll_getnode(), 'windll') def test_getnode(self): - import sys node1 = uuid.getnode() self.check_node(node1, "getnode1") @@ -360,13 +356,8 @@ self.assertEqual(node1, node2) + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') def test_uuid1(self): - # uuid1 requires ctypes. - try: - import ctypes - except ImportError: - return - equal = self.assertEqual # Make sure uuid1() generates UUIDs that are actually version 1. @@ -419,13 +410,8 @@ equal(u, uuid.UUID(v)) equal(str(u), v) + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') def test_uuid4(self): - # uuid4 requires ctypes. - try: - import ctypes - except ImportError: - return - equal = self.assertEqual # Make sure uuid4() generates UUIDs that are actually version 4. @@ -457,12 +443,8 @@ equal(u, uuid.UUID(v)) equal(str(u), v) + @unittest.skipUnless(os.name == 'posix', 'requires Posix') def testIssue8621(self): - import os - import sys - if os.name != 'posix': - return - # On at least some versions of OSX uuid.uuid4 generates # the same sequence of UUIDs in the parent and any # children started using fork. @@ -483,11 +465,5 @@ self.assertNotEqual(parent_value, child_value) - - - -def test_main(): - support.run_unittest(TestUUID) - if __name__ == '__main__': - test_main() + unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -80,6 +80,7 @@ - Issue #14439: Python now prints the traceback on runpy failure at startup. + - Issue #17469: Fix _Py_GetAllocatedBlocks() and sys.getallocatedblocks() when running on valgrind. @@ -320,6 +321,8 @@ Tests ----- +- Issue #18094: test_uuid no more reports skipped tests as passed. + - Issue #17992: Add timeouts to asyncore and asynchat tests so that they won't accidentally hang. -- Repository URL: http://hg.python.org/cpython From python-checkins at python.org Fri May 31 21:35:37 2013 From: python-checkins at python.org (serhiy.storchaka) Date: Fri, 31 May 2013 21:35:37 +0200 (CEST) Subject: [Python-checkins] =?utf-8?b?Y3B5dGhvbiAoMi43KTogSXNzdWUgIzE4MDk0?= =?utf-8?q?=3A_test=5Fuuid_no_more_reports_skipped_tests_as_passed=2E?= Message-ID: <3bMbVK2bTJz7LpC@mail.python.org> http://hg.python.org/cpython/rev/6ceb5bf24da8 changeset: 83995:6ceb5bf24da8 branch: 2.7 parent: 83989:6159916c712e user: Serhiy Storchaka date: Fri May 31 22:34:53 2013 +0300 summary: Issue #18094: test_uuid no more reports skipped tests as passed. files: Lib/test/test_uuid.py | 69 +++++++++++------------------- Misc/NEWS | 2 + 2 files changed, 28 insertions(+), 43 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 @@ -1,5 +1,6 @@ -from unittest import TestCase +import unittest from test import test_support +import os import uuid def importable(name): @@ -9,7 +10,7 @@ except: return False -class TestUUID(TestCase): +class TestUUID(unittest.TestCase): last_node = None source2node = {} @@ -299,24 +300,22 @@ else: TestUUID.last_node = node + @unittest.skipUnless(os.name == 'posix', 'requires Posix') def test_ifconfig_getnode(self): - import sys - import os - if os.name == 'posix': - node = uuid._ifconfig_getnode() - if node is not None: - self.check_node(node, 'ifconfig') + node = uuid._ifconfig_getnode() + if node is not None: + self.check_node(node, 'ifconfig') + @unittest.skipUnless(os.name == 'nt', 'requires Windows') def test_ipconfig_getnode(self): - import os - if os.name == 'nt': - node = uuid._ipconfig_getnode() - if node is not None: - self.check_node(node, 'ipconfig') + node = uuid._ipconfig_getnode() + if node is not None: + self.check_node(node, 'ipconfig') + @unittest.skipUnless(importable('win32wnet'), 'requires win32wnet') + @unittest.skipUnless(importable('netbios'), 'requires netbios') def test_netbios_getnode(self): - if importable('win32wnet') and importable('netbios'): - self.check_node(uuid._netbios_getnode(), 'netbios') + self.check_node(uuid._netbios_getnode(), 'netbios') def test_random_getnode(self): node = uuid._random_getnode() @@ -324,22 +323,20 @@ self.assertTrue(node & 0x010000000000) self.assertTrue(node < (1L << 48)) + @unittest.skipUnless(os.name == 'posix', 'requires Posix') + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') def test_unixdll_getnode(self): - import sys - import os - if importable('ctypes') and os.name == 'posix': - try: # Issues 1481, 3581: _uuid_generate_time() might be None. - self.check_node(uuid._unixdll_getnode(), 'unixdll') - except TypeError: - pass + try: # Issues 1481, 3581: _uuid_generate_time() might be None. + self.check_node(uuid._unixdll_getnode(), 'unixdll') + except TypeError: + pass + @unittest.skipUnless(os.name == 'nt', 'requires Windows') + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') def test_windll_getnode(self): - import os - if importable('ctypes') and os.name == 'nt': - self.check_node(uuid._windll_getnode(), 'windll') + self.check_node(uuid._windll_getnode(), 'windll') def test_getnode(self): - import sys node1 = uuid.getnode() self.check_node(node1, "getnode1") @@ -349,13 +346,8 @@ self.assertEqual(node1, node2) + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') def test_uuid1(self): - # uuid1 requires ctypes. - try: - import ctypes - except ImportError: - return - equal = self.assertEqual # Make sure uuid1() generates UUIDs that are actually version 1. @@ -408,13 +400,8 @@ equal(u, uuid.UUID(v)) equal(str(u), v) + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') def test_uuid4(self): - # uuid4 requires ctypes. - try: - import ctypes - except ImportError: - return - equal = self.assertEqual # Make sure uuid4() generates UUIDs that are actually version 4. @@ -446,12 +433,8 @@ equal(u, uuid.UUID(v)) equal(str(u), v) + @unittest.skipUnless(os.name == 'posix', 'requires Posix') def testIssue8621(self): - import os - import sys - if os.name != 'posix': - return - # On at least some versions of OSX uuid.uuid4 generates # the same sequence of UUIDs in the parent and any # children started using fork. diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -58,6 +58,8 @@ Tests ----- +- Issue #18094: test_uuid no more reports skipped tests as passed. + - Issue #11995: test_pydoc doesn't import all sys.path modules anymore. Documentation -- Repository URL: http://hg.python.org/cpython